summaryrefslogtreecommitdiffstats
path: root/src/main/java/org/openslx/libvirt/domain/device/HostdevPciDeviceAddress.java
blob: 928150092cfc12f3b89210a4b68e0ccf27265849 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
package org.openslx.libvirt.domain.device;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Representation of a slot address from a PCI device.
 * 
 * @author Manuel Bentele
 * @version 1.0
 */
public class HostdevPciDeviceAddress
{
	/**
	 * Regular expression to parse a PCI device address from a {@link String}.
	 * <p>
	 * The regular expression matches a PCI device address if its textual PCI device address is
	 * well-formed according to the following examples:
	 * 
	 * <pre>
	 *   0000:00:02.3
	 *   0000:01:00.0
	 *   0000:00:1f.3
	 * </pre>
	 */
	private static final String DEVICE_ADDRESS_REGEX = "^([a-f0-9]{4}):([a-f0-9]{2}):([a-f0-9]{2})\\.([0-7]{1})$";

	/**
	 * Minimum value for a valid PCI device address component number.
	 */
	private static final int DEVICE_ADDRESS_MIN_VALUE = 0;

	/**
	 * Maximum value for a valid PCI device domain number.
	 */
	private static final int DEVICE_ADDRESS_DOMAIN_MAX_VALUE = 0xffff;

	/**
	 * Maximum value for a valid PCI device bus number.
	 */
	private static final int DEVICE_ADDRESS_BUS_MAX_VALUE = 0xff;

	/**
	 * Maximum value for a valid PCI device device number.
	 */
	private static final int DEVICE_ADDRESS_DEVICE_MAX_VALUE = 0x1f;

	/**
	 * Maximum value for a valid PCI device function number.
	 */
	private static final int DEVICE_ADDRESS_FUNCTION_MAX_VALUE = 0x7;

	/**
	 * Domain number of the PCI device address.
	 */
	final int pciDomain;

	/**
	 * Bus number of the PCI device address.
	 */
	final int pciBus;

	/**
	 * Device number of the PCI device address.
	 */
	final int pciDevice;

	/**
	 * Function number of the PCI device address.
	 */
	final int pciFunction;

	/**
	 * Creates a new PCI device address and sets the address information to the default
	 * address {@code 0000:00:00.0}.
	 */
	public HostdevPciDeviceAddress()
	{
		this( 0, 0, 0, 0 );
	}

	/**
	 * Creates a new PCI device address consisting of a specified PCI bus, device, and function.
	 * <p>
	 * The domain of the PCI device address is set to the default number {@code 0000}.
	 * 
	 * @param pciBus number of the PCI bus.
	 * @param pciDevice number of the PCI device.
	 * @param pciFunction number of the PCI function.
	 * 
	 * @throws IllegalArgumentException failed to validate the PCI bus, device and function.
	 */
	public HostdevPciDeviceAddress( int pciBus, int pciDevice, int pciFunction ) throws IllegalArgumentException
	{
		this( 0, pciBus, pciDevice, pciFunction );
	}

	/**
	 * Creates a new PCI device address consisting of a specified PCI domain, bus, device, and
	 * function.
	 * 
	 * @param pciDomain number of the PCI domain.
	 * @param pciBus number of the PCI bus.
	 * @param pciDevice number of the PCI device.
	 * @param pciFunction number of the PCI function.
	 * 
	 * @throws IllegalArgumentException failed to validate the PCI domain, bus, device and function.
	 */
	public HostdevPciDeviceAddress( int pciDomain, int pciBus, int pciDevice, int pciFunction )
			throws IllegalArgumentException
	{
		HostdevPciDeviceAddress.validatePciDeviceAddress( pciDomain, "PCI domain",
				HostdevPciDeviceAddress.DEVICE_ADDRESS_DOMAIN_MAX_VALUE );
		HostdevPciDeviceAddress.validatePciDeviceAddress( pciBus, "PCI bus",
				HostdevPciDeviceAddress.DEVICE_ADDRESS_BUS_MAX_VALUE );
		HostdevPciDeviceAddress.validatePciDeviceAddress( pciDevice, "PCI device",
				HostdevPciDeviceAddress.DEVICE_ADDRESS_DEVICE_MAX_VALUE );
		HostdevPciDeviceAddress.validatePciDeviceAddress( pciFunction, "PCI function",
				HostdevPciDeviceAddress.DEVICE_ADDRESS_FUNCTION_MAX_VALUE );

		this.pciDomain = pciDomain;
		this.pciBus = pciBus;
		this.pciDevice = pciDevice;
		this.pciFunction = pciFunction;
	}

	/**
	 * Validates a specified PCI address component (PCI domain, bus, device or function).
	 * 
	 * @param address value of the PCI address component.
	 * @param addressName name of the PCI address component.
	 * @param upperLimit maximum value for the PCI address component
	 * 
	 * @throws IllegalArgumentException
	 */
	private static void validatePciDeviceAddress( final int address, final String addressName, final int upperLimit )
			throws IllegalArgumentException
	{
		if ( address < HostdevPciDeviceAddress.DEVICE_ADDRESS_MIN_VALUE ) {
			throw new IllegalArgumentException(
					"The " + addressName + " address must be larger or equal than "
							+ HostdevPciDeviceAddress.DEVICE_ADDRESS_MIN_VALUE );
		} else if ( address > upperLimit ) {
			throw new IllegalArgumentException(
					"The " + addressName + " address must be smaller or equal than " + upperLimit );
		}
	}

	/**
	 * Returns the PCI domain.
	 * 
	 * @return PCI domain.
	 */
	public int getPciDomain()
	{
		return this.pciDomain;
	}

	/**
	 * Returns the PCI domain as {@link String}.
	 * 
	 * @return PCI domain as {@link String}.
	 */
	public String getPciDomainAsString()
	{
		return String.format( "%04x", HostdevPciDeviceAddress.DEVICE_ADDRESS_DOMAIN_MAX_VALUE & this.getPciDomain() );
	}

	/**
	 * Returns the PCI bus.
	 * 
	 * @return PCI bus.
	 */
	public int getPciBus()
	{
		return this.pciBus;
	}

	/**
	 * Returns the PCI bus as {@link String}.
	 * 
	 * @return PCI bus as {@link String}.
	 */
	public String getPciBusAsString()
	{
		return String.format( "%02x", HostdevPciDeviceAddress.DEVICE_ADDRESS_BUS_MAX_VALUE & this.getPciBus() );
	}

	/**
	 * Returns the PCI device.
	 * 
	 * @return PCI device.
	 */
	public int getPciDevice()
	{
		return this.pciDevice;
	}

	/**
	 * Returns the PCI device as {@link String}.
	 * 
	 * @return PCI device as {@link String}.
	 */
	public String getPciDeviceAsString()
	{
		return String.format( "%02x", HostdevPciDeviceAddress.DEVICE_ADDRESS_DEVICE_MAX_VALUE & this.getPciDevice() );
	}

	/**
	 * Returns the PCI function.
	 * 
	 * @return PCI function.
	 */
	public int getPciFunction()
	{
		return this.pciFunction;
	}

	/**
	 * Returns the PCI function as {@link String}.
	 * 
	 * @return PCI function as {@link String}.
	 */
	public String getPciFunctionAsString()
	{
		return String.format( "%01x", HostdevPciDeviceAddress.DEVICE_ADDRESS_FUNCTION_MAX_VALUE & this.getPciFunction() );
	}

	/**
	 * Creates a new PCI device address parsed from a {@link String}.
	 * <p>
	 * The PCI device address consists of a PCI domain, bus, device and function parsed from the
	 * specified {@link String}.
	 * 
	 * @param pciDeviceAddress textual information containing a PCI device address as {@link String}.
	 *           The textual PCI device address should be well-formed according to the defined
	 *           regular expression {@link #DEVICE_ADDRESS_REGEX}.
	 * 
	 * @return PCI device address instance.
	 */
	public static HostdevPciDeviceAddress valueOf( String pciDeviceAddress )
	{
		HostdevPciDeviceAddress parsedPciDeviceAddress;

		if ( pciDeviceAddress == null || pciDeviceAddress.isEmpty() ) {
			parsedPciDeviceAddress = null;
		} else {
			final Pattern pciDeviceAddressPattern = Pattern.compile( HostdevPciDeviceAddress.DEVICE_ADDRESS_REGEX );
			final Matcher pciDeviceAddressMatcher = pciDeviceAddressPattern.matcher( pciDeviceAddress.toLowerCase() );

			if ( pciDeviceAddressMatcher.find() ) {
				final int pciDomain = Integer.valueOf( pciDeviceAddressMatcher.group( 1 ), 16 );
				final int pciBus = Integer.valueOf( pciDeviceAddressMatcher.group( 2 ), 16 );
				final int pciDevice = Integer.valueOf( pciDeviceAddressMatcher.group( 3 ), 16 );
				final int pciFunction = Integer.valueOf( pciDeviceAddressMatcher.group( 4 ), 16 );

				try {
					parsedPciDeviceAddress = new HostdevPciDeviceAddress( pciDomain, pciBus, pciDevice, pciFunction );
				} catch ( IllegalArgumentException e ) {
					parsedPciDeviceAddress = null;
				}
			} else {
				parsedPciDeviceAddress = null;
			}
		}

		return parsedPciDeviceAddress;
	}

	@Override
	public boolean equals( Object obj )
	{
		if ( obj == null ) {
			return false;
		} else if ( this.getClass() != obj.getClass() ) {
			return false;
		} else {
			// check if PCI domain, bus, device and function are equal
			final HostdevPciDeviceAddress other = HostdevPciDeviceAddress.class.cast( obj );
			if ( this.getPciDomain() == other.getPciDomain() && this.getPciBus() == other.getPciBus()
					&& this.getPciDevice() == other.getPciDevice() && this.getPciFunction() == other.getPciFunction() ) {
				return true;
			} else {
				return false;
			}
		}
	}

	@Override
	public String toString()
	{
		return this.getPciDomainAsString() + ":" + this.getPciBusAsString() + ":" + this.getPciDeviceAsString() + "."
				+ this.getPciFunctionAsString();
	}
}