summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorManuel Bentele2021-06-10 10:47:50 +0200
committerManuel Bentele2021-06-10 10:49:50 +0200
commit9cda192f9f5ee9ffb5d8d6962651d950a7b0fd76 (patch)
tree04fb49f4724a39f0e4a318102f1c11c30ee9310c
parentAdd test Libvirt capabilities XML file with old QEMU machine versions (diff)
downloadmaster-sync-shared-9cda192f9f5ee9ffb5d8d6962651d950a7b0fd76.tar.gz
master-sync-shared-9cda192f9f5ee9ffb5d8d6962651d950a7b0fd76.tar.xz
master-sync-shared-9cda192f9f5ee9ffb5d8d6962651d950a7b0fd76.zip
Add Libvirt PCI, shared memory and hypervisor features for GPU passthrough
-rw-r--r--src/main/java/org/openslx/libvirt/domain/Domain.java130
-rw-r--r--src/main/java/org/openslx/libvirt/domain/device/Device.java7
-rw-r--r--src/main/java/org/openslx/libvirt/domain/device/GraphicsSpice.java2
-rw-r--r--src/main/java/org/openslx/libvirt/domain/device/Hostdev.java33
-rw-r--r--src/main/java/org/openslx/libvirt/domain/device/HostdevAddressableSource.java26
-rw-r--r--src/main/java/org/openslx/libvirt/domain/device/HostdevAddressableTarget.java26
-rw-r--r--src/main/java/org/openslx/libvirt/domain/device/HostdevPci.java70
-rw-r--r--src/main/java/org/openslx/libvirt/domain/device/HostdevPciDeviceAddress.java295
-rw-r--r--src/main/java/org/openslx/libvirt/domain/device/HostdevPciDeviceDescription.java186
-rw-r--r--src/main/java/org/openslx/libvirt/domain/device/HostdevUsb.java41
-rw-r--r--src/main/java/org/openslx/libvirt/domain/device/HostdevUsbDeviceAddress.java141
-rw-r--r--src/main/java/org/openslx/libvirt/domain/device/HostdevUsbDeviceDescription.java190
-rw-r--r--src/main/java/org/openslx/libvirt/domain/device/HostdevUtils.java32
-rw-r--r--src/main/java/org/openslx/libvirt/domain/device/Shmem.java178
-rw-r--r--src/main/java/org/openslx/libvirt/domain/device/Video.java13
-rw-r--r--src/main/java/org/openslx/libvirt/xml/LibvirtXmlEditable.java66
-rw-r--r--src/main/java/org/openslx/libvirt/xml/LibvirtXmlNode.java17
-rw-r--r--src/test/java/org/openslx/libvirt/domain/device/HostdevPciDeviceAddressTest.java79
-rw-r--r--src/test/java/org/openslx/libvirt/domain/device/HostdevPciDeviceDescriptionTest.java75
19 files changed, 1561 insertions, 46 deletions
diff --git a/src/main/java/org/openslx/libvirt/domain/Domain.java b/src/main/java/org/openslx/libvirt/domain/Domain.java
index 50d0811..e0a90e5 100644
--- a/src/main/java/org/openslx/libvirt/domain/Domain.java
+++ b/src/main/java/org/openslx/libvirt/domain/Domain.java
@@ -26,11 +26,14 @@ import org.openslx.libvirt.domain.device.GraphicsSdl;
import org.openslx.libvirt.domain.device.GraphicsSpice;
import org.openslx.libvirt.domain.device.GraphicsVnc;
import org.openslx.libvirt.domain.device.Hostdev;
+import org.openslx.libvirt.domain.device.HostdevPci;
+import org.openslx.libvirt.domain.device.HostdevUsb;
import org.openslx.libvirt.domain.device.Interface;
import org.openslx.libvirt.domain.device.InterfaceBridge;
import org.openslx.libvirt.domain.device.InterfaceNetwork;
import org.openslx.libvirt.domain.device.Parallel;
import org.openslx.libvirt.domain.device.Serial;
+import org.openslx.libvirt.domain.device.Shmem;
import org.openslx.libvirt.domain.device.Sound;
import org.openslx.libvirt.domain.device.Video;
import org.openslx.libvirt.xml.LibvirtXmlDocument;
@@ -272,6 +275,66 @@ public class Domain extends LibvirtXmlDocument
}
/**
+ * Returns the state of the Hyper-V vendor identifier feature.
+ *
+ * @return state of the Hyper-V vendor identifier feature.
+ */
+ public boolean isFeatureHypervVendorIdStateOn()
+ {
+ return this.getRootXmlNode().getXmlElementAttributeValueAsBool( "features/hyperv/vendor_id", "state" );
+ }
+
+ /**
+ * Sets the state of the Hyper-V vendor identifier feature.
+ *
+ * @param on state for the Hyper-V vendor identifier feature.
+ */
+ public void setFeatureHypervVendorIdState( boolean on )
+ {
+ this.getRootXmlNode().setXmlElementAttributeValueOnOff( "features/hyperv/vendor_id", "state", on );
+ }
+
+ /**
+ * Returns the value of the Hyper-V vendor identifier feature.
+ *
+ * @return value of the Hyper-V vendor identifier feature.
+ */
+ public String getFeatureHypervVendorIdValue()
+ {
+ return this.getRootXmlNode().getXmlElementAttributeValue( "features/hyperv/vendor_id", "value" );
+ }
+
+ /**
+ * Sets the value of the Hyper-V vendor identifier feature.
+ *
+ * @param value value for the Hyper-V vendor identifier feature.
+ */
+ public void setFeatureHypervVendorIdValue( String value )
+ {
+ this.getRootXmlNode().setXmlElementAttributeValue( "features/hyperv/vendor_id", "value", value );
+ }
+
+ /**
+ * Returns the state of the KVM hidden feature.
+ *
+ * @return state of the KVM hidden feature.
+ */
+ public boolean isFeatureKvmHiddenStateOn()
+ {
+ return this.getRootXmlNode().getXmlElementAttributeValueAsBool( "features/kvm/hidden", "state" );
+ }
+
+ /**
+ * Sets the state of the KVM hidden feature.
+ *
+ * @param on state for the KVM hidden feature.
+ */
+ public void setFeatureKvmHiddenState( boolean on )
+ {
+ this.getRootXmlNode().setXmlElementAttributeValueOnOff( "features/kvm/hidden", "state", on );
+ }
+
+ /**
* Returns virtual machine UUID defined in the Libvirt domain XML document.
*
* @return UUID of virtual machine.
@@ -860,6 +923,28 @@ public class Domain extends LibvirtXmlDocument
}
/**
+ * Returns list of virtual machine PCI hostdev devices specified in the Libvirt domain XML
+ * document.
+ *
+ * @return list of virtual machine PCI hostdev devices.
+ */
+ public ArrayList<HostdevPci> getHostdevPciDevices()
+ {
+ return Domain.filterDevices( HostdevPci.class, this.getDevices() );
+ }
+
+ /**
+ * Returns list of virtual machine USB hostdev devices specified in the Libvirt domain XML
+ * document.
+ *
+ * @return list of virtual machine USB hostdev devices.
+ */
+ public ArrayList<HostdevUsb> getHostdevUsbDevices()
+ {
+ return Domain.filterDevices( HostdevUsb.class, this.getDevices() );
+ }
+
+ /**
* Returns list of virtual machine network interface devices specified in the Libvirt domain XML
* document.
*
@@ -903,6 +988,17 @@ public class Domain extends LibvirtXmlDocument
}
/**
+ * Returns list of virtual machine shared memory devices specified in the Libvirt domain XML
+ * document.
+ *
+ * @return list of virtual machine shared memory devices.
+ */
+ public ArrayList<Shmem> getShmemDevices()
+ {
+ return Domain.filterDevices( Shmem.class, this.getDevices() );
+ }
+
+ /**
* Returns list of virtual machine sound devices specified in the Libvirt domain XML document.
*
* @return list of virtual machine sound devices.
@@ -1066,9 +1162,9 @@ public class Domain extends LibvirtXmlDocument
}
/**
- * Adds a virtual machine disk device to the Libvirt domain XML document.
+ * Adds a virtual machine hostdev device to the Libvirt domain XML document.
*
- * @return reference to the added disk device if creation was successful.
+ * @return reference to the added hostdev device if creation was successful.
*/
public Hostdev addHostdevDevice()
{
@@ -1076,6 +1172,26 @@ public class Domain extends LibvirtXmlDocument
}
/**
+ * Adds a virtual machine PCI hostdev device to the Libvirt domain XML document.
+ *
+ * @return reference to the added PCI hostdev device if creation was successful.
+ */
+ public HostdevPci addHostdevPciDevice()
+ {
+ return HostdevPci.class.cast( this.addDevice( new HostdevPci() ) );
+ }
+
+ /**
+ * Adds a virtual machine USB hostdev device to the Libvirt domain XML document.
+ *
+ * @return reference to the added USB hostdev device if creation was successful.
+ */
+ public HostdevUsb addHostdevUsbDevice()
+ {
+ return HostdevUsb.class.cast( this.addDevice( new HostdevUsb() ) );
+ }
+
+ /**
* Adds a virtual machine network device to the Libvirt domain XML document.
*
* @return reference to the added network device if creation was successful.
@@ -1166,6 +1282,16 @@ public class Domain extends LibvirtXmlDocument
}
/**
+ * Adds a virtual machine shared memory device to the Libvirt domain XML document.
+ *
+ * @return reference to the added shared memory device if creation was successful.
+ */
+ public Shmem addShmemDevice()
+ {
+ return Shmem.class.cast( this.addDevice( new Shmem() ) );
+ }
+
+ /**
* Adds a virtual machine sound device to the Libvirt domain XML document.
*
* @return reference to the added sound device if creation was successful.
diff --git a/src/main/java/org/openslx/libvirt/domain/device/Device.java b/src/main/java/org/openslx/libvirt/domain/device/Device.java
index c252793..1e0e031 100644
--- a/src/main/java/org/openslx/libvirt/domain/device/Device.java
+++ b/src/main/java/org/openslx/libvirt/domain/device/Device.java
@@ -95,6 +95,9 @@ public class Device extends LibvirtXmlNode
} else if ( device instanceof Serial ) {
LibvirtXmlNode xmlNode = Device.createDeviceElement( xmlParentNode, Type.SERIAL );
createdDevice = Serial.createInstance( xmlNode );
+ } else if ( device instanceof Shmem ) {
+ LibvirtXmlNode xmlNode = Device.createDeviceElement( xmlParentNode, Type.SHMEM );
+ createdDevice = Shmem.createInstance( xmlNode );
} else if ( device instanceof Sound ) {
LibvirtXmlNode xmlNode = Device.createDeviceElement( xmlParentNode, Type.SOUND );
createdDevice = Sound.createInstance( xmlNode );
@@ -152,6 +155,9 @@ public class Device extends LibvirtXmlNode
case SERIAL:
device = Serial.newInstance( xmlNode );
break;
+ case SHMEM:
+ device = Shmem.newInstance( xmlNode );
+ break;
case SOUND:
device = Sound.newInstance( xmlNode );
break;
@@ -181,6 +187,7 @@ public class Device extends LibvirtXmlNode
GRAPHICS ( "graphics" ),
PARALLEL ( "parallel" ),
SERIAL ( "serial" ),
+ SHMEM ( "shmem" ),
SOUND ( "sound" ),
VIDEO ( "video" );
// @formatter:on
diff --git a/src/main/java/org/openslx/libvirt/domain/device/GraphicsSpice.java b/src/main/java/org/openslx/libvirt/domain/device/GraphicsSpice.java
index f087296..4d06f78 100644
--- a/src/main/java/org/openslx/libvirt/domain/device/GraphicsSpice.java
+++ b/src/main/java/org/openslx/libvirt/domain/device/GraphicsSpice.java
@@ -46,7 +46,7 @@ public class GraphicsSpice extends Graphics
*/
public void setOpenGl( boolean enabled )
{
- this.setXmlElementAttributeValue( "gl", "enable", enabled );
+ this.setXmlElementAttributeValueYesNo( "gl", "enable", enabled );
}
/**
diff --git a/src/main/java/org/openslx/libvirt/domain/device/Hostdev.java b/src/main/java/org/openslx/libvirt/domain/device/Hostdev.java
index cb09099..4c6775e 100644
--- a/src/main/java/org/openslx/libvirt/domain/device/Hostdev.java
+++ b/src/main/java/org/openslx/libvirt/domain/device/Hostdev.java
@@ -29,6 +29,33 @@ public class Hostdev extends Device
}
/**
+ * Checks if hostdev device is managed.
+ *
+ * If {@link #isManaged()} returns <code>true</code> the hostdev device is detached from the
+ * host before being passed on to the guest and reattached to the host after the guest exits.
+ *
+ * @return state whether hostdev device is managed.
+ */
+ public boolean isManaged()
+ {
+ return this.getXmlElementAttributeValueAsBool( "managed" );
+ }
+
+ /**
+ * Sets state whether hostdev device is managed.
+ *
+ * If the <code>managed</code> parameter is set to <code>true</code> the hostdev device is
+ * detached from the host before being passed on to the guest and reattached to the host after
+ * the guest exits.
+ *
+ * @param managed state whether hostdev device is managed or not.
+ */
+ public void setManaged( boolean managed )
+ {
+ this.setXmlElementAttributeValueYesNo( "managed", managed );
+ }
+
+ /**
* Removes boot oder entry of the hostdev device.
*/
public void removeBootOrder()
@@ -47,11 +74,13 @@ public class Hostdev extends Device
{
Hostdev addedHostdev = null;
+ xmlNode.setXmlElementAttributeValue( "mode", "subsystem" );
+
if ( hostdev instanceof HostdevPci ) {
- xmlNode.setXmlElementAttributeValue( "device", Type.PCI.toString() );
+ xmlNode.setXmlElementAttributeValue( "type", Type.PCI.toString() );
addedHostdev = HostdevPci.createInstance( xmlNode );
} else if ( hostdev instanceof HostdevUsb ) {
- xmlNode.setXmlElementAttributeValue( "device", Type.USB.toString() );
+ xmlNode.setXmlElementAttributeValue( "type", Type.USB.toString() );
addedHostdev = HostdevUsb.createInstance( xmlNode );
}
diff --git a/src/main/java/org/openslx/libvirt/domain/device/HostdevAddressableSource.java b/src/main/java/org/openslx/libvirt/domain/device/HostdevAddressableSource.java
new file mode 100644
index 0000000..9377421
--- /dev/null
+++ b/src/main/java/org/openslx/libvirt/domain/device/HostdevAddressableSource.java
@@ -0,0 +1,26 @@
+package org.openslx.libvirt.domain.device;
+
+/**
+ * Addressable source operations for a hostdev device.
+ *
+ * @author Manuel Bentele
+ * @version 1.0
+ *
+ * @param <T> type of the source.
+ */
+public abstract interface HostdevAddressableSource<T>
+{
+ /**
+ * Returns the source of the source device (on the Libvirt host).
+ *
+ * @return source of the source device (on the Libvirt host).
+ */
+ public T getSource();
+
+ /**
+ * Sets the source for the source device (on the Libvirt host).
+ *
+ * @param source source for the source device (on the Libvirt host).
+ */
+ public void setSource( T source );
+}
diff --git a/src/main/java/org/openslx/libvirt/domain/device/HostdevAddressableTarget.java b/src/main/java/org/openslx/libvirt/domain/device/HostdevAddressableTarget.java
new file mode 100644
index 0000000..8a6f9a1
--- /dev/null
+++ b/src/main/java/org/openslx/libvirt/domain/device/HostdevAddressableTarget.java
@@ -0,0 +1,26 @@
+package org.openslx.libvirt.domain.device;
+
+/**
+ * Addressable target operations for a hostdev device.
+ *
+ * @author Manuel Bentele
+ * @version 1.0
+ *
+ * @param <T> type of the target.
+ */
+public abstract interface HostdevAddressableTarget<T>
+{
+ /**
+ * Returns the target of the target device (in the virtual machine).
+ *
+ * @return target of the target device (in the virtual machine).
+ */
+ public T getTarget();
+
+ /**
+ * Sets the target for the target device (in the virtual machine).
+ *
+ * @param target target for the target device (in the virtual machine).
+ */
+ public void setTarget( T target );
+}
diff --git a/src/main/java/org/openslx/libvirt/domain/device/HostdevPci.java b/src/main/java/org/openslx/libvirt/domain/device/HostdevPci.java
index a0563f2..d2be2d6 100644
--- a/src/main/java/org/openslx/libvirt/domain/device/HostdevPci.java
+++ b/src/main/java/org/openslx/libvirt/domain/device/HostdevPci.java
@@ -8,7 +8,8 @@ import org.openslx.libvirt.xml.LibvirtXmlNode;
* @author Manuel Bentele
* @version 1.0
*/
-public class HostdevPci extends Hostdev
+public class HostdevPci extends Hostdev implements HostdevAddressableSource<HostdevPciDeviceAddress>,
+ HostdevAddressableTarget<HostdevPciDeviceAddress>
{
/**
* Creates an empty hostdev PCI device.
@@ -29,30 +30,67 @@ public class HostdevPci extends Hostdev
}
/**
- * Checks if PCI hostdev device is managed.
+ * Returns the PCI device address from an address XML element selected by a XPath expression.
*
- * If {@link #isManaged()} returns <code>true</code> the hostdev PCI device is detached from the
- * host before being passed on to the guest and reattached to the host after the guest exits.
- *
- * @return state whether PCI hostdev device is managed.
+ * @param expression XPath expression to select the XML address element.
+ * @return PCI device address from the selected XML address element.
*/
- public boolean isManaged()
+ private HostdevPciDeviceAddress getPciAddress( final String expression )
{
- return this.getXmlElementAttributeValueAsBool( "managed" );
+ String pciDomain = this.getXmlElementAttributeValue( expression, "domain" );
+ String pciBus = this.getXmlElementAttributeValue( expression, "bus" );
+ String pciDevice = this.getXmlElementAttributeValue( expression, "slot" );
+ String pciFunction = this.getXmlElementAttributeValue( expression, "function" );
+
+ pciDomain = HostdevUtils.removeHexPrefix( pciDomain );
+ pciBus = HostdevUtils.removeHexPrefix( pciBus );
+ pciDevice = HostdevUtils.removeHexPrefix( pciDevice );
+ pciFunction = HostdevUtils.removeHexPrefix( pciFunction );
+
+ return HostdevPciDeviceAddress.valueOf( pciDomain + ":" + pciBus + ":" + pciDevice + "." + pciFunction );
}
/**
- * Sets state whether PCI hostdev device is managed.
+ * Sets the PCI device address for an XML address element selected by a XPath expression.
*
- * If the <code>managed</code> parameter is set to <code>true</code> the PCI hostdev device is
- * detached from the host before being passed on to the guest and reattached to the host after
- * the guest exits.
- *
- * @param managed state whether PCI hostdev device is managed or not.
+ * @param expression XPath expression to select the XML address element.
+ * @param address PCI device address for the selected XML address element.
*/
- public void setManaged( boolean managed )
+ private void setPciAddress( final String expression, final HostdevPciDeviceAddress address )
+ {
+ final String pciDomain = HostdevUtils.appendHexPrefix( address.getPciDomainAsString() );
+ final String pciBus = HostdevUtils.appendHexPrefix( address.getPciBusAsString() );
+ final String pciDevice = HostdevUtils.appendHexPrefix( address.getPciDeviceAsString() );
+ final String pciFunction = HostdevUtils.appendHexPrefix( address.getPciFunctionAsString() );
+
+ this.setXmlElementAttributeValue( expression, "domain", pciDomain );
+ this.setXmlElementAttributeValue( expression, "bus", pciBus );
+ this.setXmlElementAttributeValue( expression, "slot", pciDevice );
+ this.setXmlElementAttributeValue( expression, "function", pciFunction );
+ }
+
+ @Override
+ public HostdevPciDeviceAddress getSource()
+ {
+ return this.getPciAddress( "source/address" );
+ }
+
+ @Override
+ public void setSource( HostdevPciDeviceAddress address )
+ {
+ this.setPciAddress( "source/address", address );
+ }
+
+ @Override
+ public HostdevPciDeviceAddress getTarget()
+ {
+ return this.getPciAddress( "address" );
+ }
+
+ @Override
+ public void setTarget( HostdevPciDeviceAddress address )
{
- this.setXmlElementAttributeValue( "managed", managed );
+ this.setPciAddress( "address", address );
}
/**
diff --git a/src/main/java/org/openslx/libvirt/domain/device/HostdevPciDeviceAddress.java b/src/main/java/org/openslx/libvirt/domain/device/HostdevPciDeviceAddress.java
new file mode 100644
index 0000000..9281500
--- /dev/null
+++ b/src/main/java/org/openslx/libvirt/domain/device/HostdevPciDeviceAddress.java
@@ -0,0 +1,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();
+ }
+}
diff --git a/src/main/java/org/openslx/libvirt/domain/device/HostdevPciDeviceDescription.java b/src/main/java/org/openslx/libvirt/domain/device/HostdevPciDeviceDescription.java
new file mode 100644
index 0000000..25c29f2
--- /dev/null
+++ b/src/main/java/org/openslx/libvirt/domain/device/HostdevPciDeviceDescription.java
@@ -0,0 +1,186 @@
+package org.openslx.libvirt.domain.device;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Representation of a PCI device description.
+ *
+ * @author Manuel Bentele
+ * @version 1.0
+ */
+public class HostdevPciDeviceDescription extends Hostdev
+{
+ /**
+ * Regular expression to parse a PCI vendor and device identifier from a {@link String}.
+ * <p>
+ * The regular expression matches a PCI device description if its textual PCI device description
+ * is well-formed according to the following examples:
+ *
+ * <pre>
+ * 8086:a170
+ * 10ec:8168
+ * 8086:15b7
+ * </pre>
+ */
+ private static final String DEVICE_DESCRIPTION_REGEX = "^([a-f0-9]{4}):([a-f0-9]{4})$";
+
+ /**
+ * Minimum value of a valid identifier from a PCI device description.
+ */
+ private static final int DEVICE_DESCRIPTION_ID_MIN_VALUE = 0x0000;
+
+ /**
+ * Maximum value of a valid identifier from a PCI device description.
+ */
+ private static final int DEVICE_DESCRIPTION_ID_MAX_VALUE = 0xffff;
+
+ /**
+ * Vendor identifier of the PCI device.
+ */
+ final int vendorId;
+
+ /**
+ * Device identifier of the PCI device.
+ */
+ final int deviceId;
+
+ /**
+ * Creates a new PCI device description consisting of a PCI vendor and device identifier.
+ *
+ * @param vendorId vendor identifier of the PCI device.
+ * @param deviceId device identifier of the PCI device.
+ *
+ * @throws throws IllegalArgumentException failed to validate the PCI device description
+ * identifiers.
+ */
+ public HostdevPciDeviceDescription( int vendorId, int deviceId ) throws IllegalArgumentException
+ {
+ HostdevPciDeviceDescription.validatePciDeviceDescriptionId( "PCI vendor ID", vendorId );
+ HostdevPciDeviceDescription.validatePciDeviceDescriptionId( "PCI device ID", deviceId );
+
+ this.vendorId = vendorId;
+ this.deviceId = deviceId;
+ }
+
+ /**
+ * Validates a PCI device description ID (a PCI vendor or device ID).
+ *
+ * @param idName name of the PCI device description identifier.
+ * @param id value of the PCI device description identifier that should be validated.
+ *
+ * @throws IllegalArgumentException failed to validate the PCI device description identifier.
+ */
+ private static void validatePciDeviceDescriptionId( final String idName, final int id )
+ throws IllegalArgumentException
+ {
+ if ( id < HostdevPciDeviceDescription.DEVICE_DESCRIPTION_ID_MIN_VALUE ) {
+ throw new IllegalArgumentException(
+ "The " + idName + "must be larger or equal than "
+ + HostdevPciDeviceDescription.DEVICE_DESCRIPTION_ID_MIN_VALUE );
+ } else if ( id > HostdevPciDeviceDescription.DEVICE_DESCRIPTION_ID_MAX_VALUE ) {
+ throw new IllegalArgumentException(
+ "The " + idName + "must be smaller or equal than "
+ + HostdevPciDeviceDescription.DEVICE_DESCRIPTION_ID_MAX_VALUE );
+ }
+ }
+
+ /**
+ * Returns the PCI vendor identifier.
+ *
+ * @return PCI vendor identifier.
+ */
+ public int getVendorId()
+ {
+ return this.vendorId;
+ }
+
+ /**
+ * Returns the PCI vendor identifier as {@link String}.
+ *
+ * @return PCI vendor identifier as {@link String}.
+ */
+ public String getVendorIdAsString()
+ {
+ return String.format( "%04x", HostdevPciDeviceDescription.DEVICE_DESCRIPTION_ID_MAX_VALUE & this.getVendorId() );
+ }
+
+ /**
+ * Returns the PCI device identifier.
+ *
+ * @return PCI device identifier.
+ */
+ public int getDeviceId()
+ {
+ return this.deviceId;
+ }
+
+ /**
+ * Returns the PCI device identifier as {@link String}.
+ *
+ * @return PCI device identifier as {@link String}.
+ */
+ public String getDeviceIdAsString()
+ {
+ return String.format( "%04x", HostdevPciDeviceDescription.DEVICE_DESCRIPTION_ID_MAX_VALUE & this.getDeviceId() );
+ }
+
+ /**
+ * Creates a new PCI device description parsed from a {@link String}.
+ * <p>
+ * The PCI device description consists of a PCI vendor and device identifier parsed from the
+ * specified {@link String}.
+ *
+ * @param vendorDeviceId textual information containing a PCI device description as
+ * {@link String}. The textual PCI device description should be well-formed according
+ * to the defined regular expression {@link #DEVICE_DESCRIPTION_REGEX}.
+ *
+ * @return PCI device description instance.
+ */
+ public static HostdevPciDeviceDescription valueOf( String vendorDeviceId )
+ {
+ final HostdevPciDeviceDescription pciDeviceDescription;
+
+ if ( vendorDeviceId == null || vendorDeviceId.isEmpty() ) {
+ pciDeviceDescription = null;
+ } else {
+ final Pattern pciDeviceDescPattern = Pattern.compile( HostdevPciDeviceDescription.DEVICE_DESCRIPTION_REGEX );
+ final Matcher pciDeviceDescMatcher = pciDeviceDescPattern.matcher( vendorDeviceId.toLowerCase() );
+
+ if ( pciDeviceDescMatcher.find() ) {
+ final int vendorId = Integer.valueOf( pciDeviceDescMatcher.group( 1 ), 16 );
+ final int deviceId = Integer.valueOf( pciDeviceDescMatcher.group( 2 ), 16 );
+
+ pciDeviceDescription = new HostdevPciDeviceDescription( vendorId, deviceId );
+ } else {
+ pciDeviceDescription = null;
+ }
+ }
+
+ return pciDeviceDescription;
+ }
+
+ @Override
+ public boolean equals( Object obj )
+ {
+ if ( obj == null ) {
+ return false;
+ } else if ( this.getClass() != obj.getClass() ) {
+ return false;
+ } else {
+ // check if vendor and device ID are equal
+ final HostdevPciDeviceDescription other = HostdevPciDeviceDescription.class.cast( obj );
+ if ( this.getVendorId() == other.getVendorId() && this.getDeviceId() == other.getDeviceId() ) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }
+
+ @Override
+ public String toString()
+ {
+ return this.getVendorIdAsString() + ":" + this.getDeviceIdAsString();
+ }
+}
diff --git a/src/main/java/org/openslx/libvirt/domain/device/HostdevUsb.java b/src/main/java/org/openslx/libvirt/domain/device/HostdevUsb.java
index e1fcc0c..a9d7f89 100644
--- a/src/main/java/org/openslx/libvirt/domain/device/HostdevUsb.java
+++ b/src/main/java/org/openslx/libvirt/domain/device/HostdevUsb.java
@@ -8,7 +8,8 @@ import org.openslx.libvirt.xml.LibvirtXmlNode;
* @author Manuel Bentele
* @version 1.0
*/
-public class HostdevUsb extends Hostdev
+public class HostdevUsb extends Hostdev implements HostdevAddressableSource<HostdevUsbDeviceDescription>,
+ HostdevAddressableTarget<HostdevUsbDeviceAddress>
{
/**
* Creates an empty hostdev USB device.
@@ -28,6 +29,44 @@ public class HostdevUsb extends Hostdev
super( xmlNode );
}
+ @Override
+ public HostdevUsbDeviceDescription getSource()
+ {
+ String vendorId = this.getXmlElementAttributeValue( "source/address/vendor", "id" );
+ String productId = this.getXmlElementAttributeValue( "source/address/product", "id" );
+
+ vendorId = HostdevUtils.removeHexPrefix( vendorId );
+ productId = HostdevUtils.removeHexPrefix( productId );
+
+ return HostdevUsbDeviceDescription.valueOf( vendorId + ":" + productId );
+ }
+
+ @Override
+ public void setSource( HostdevUsbDeviceDescription description )
+ {
+ final String vendorId = HostdevUtils.appendHexPrefix( description.getVendorIdAsString() );
+ final String productId = HostdevUtils.appendHexPrefix( description.getProductIdAsString() );
+
+ this.setXmlElementAttributeValue( "source/address/vendor", "id", vendorId );
+ this.setXmlElementAttributeValue( "source/address/product", "id", productId );
+ }
+
+ @Override
+ public HostdevUsbDeviceAddress getTarget()
+ {
+ final String usbBus = this.getXmlElementAttributeValue( "address", "bus" );
+ final String usbPort = this.getXmlElementAttributeValue( "address", "port" );
+
+ return HostdevUsbDeviceAddress.valueOf( usbBus, usbPort );
+ }
+
+ @Override
+ public void setTarget( HostdevUsbDeviceAddress address )
+ {
+ this.setXmlElementAttributeValue( "address", "bus", Integer.toString( address.getUsbBus() ) );
+ this.setXmlElementAttributeValue( "address", "port", Integer.toString( address.getUsbPort() ) );
+ }
+
/**
* Creates a non-existent hostdev USB device as Libvirt XML device element.
*
diff --git a/src/main/java/org/openslx/libvirt/domain/device/HostdevUsbDeviceAddress.java b/src/main/java/org/openslx/libvirt/domain/device/HostdevUsbDeviceAddress.java
new file mode 100644
index 0000000..02961a1
--- /dev/null
+++ b/src/main/java/org/openslx/libvirt/domain/device/HostdevUsbDeviceAddress.java
@@ -0,0 +1,141 @@
+package org.openslx.libvirt.domain.device;
+
+/**
+ * Representation of an address from an USB device.
+ *
+ * @author Manuel Bentele
+ * @version 1.0
+ */
+public class HostdevUsbDeviceAddress
+{
+ /**
+ * Minimum value for a valid USB device address component number.
+ */
+ private static final int DEVICE_ADDRESS_MIN_VALUE = 0;
+
+ /**
+ * Maximum value for a valid USB device bus number.
+ */
+ static final int DEVICE_BUS_MAX_VALUE = 127;
+
+ /**
+ * Maximum value for a valid USB device port number.
+ */
+ static final int DEVICE_PORT_MAX_VALUE = 127;
+
+ /**
+ * USB bus of the USB device.
+ */
+ final int usbBus;
+
+ /**
+ * USB port of the USB device.
+ */
+ final int usbPort;
+
+ public HostdevUsbDeviceAddress( int usbBus, int usbPort ) throws IllegalArgumentException
+ {
+ HostdevUsbDeviceAddress.validateUsbDeviceAddress( usbBus, "USB bus",
+ HostdevUsbDeviceAddress.DEVICE_BUS_MAX_VALUE );
+ HostdevUsbDeviceAddress.validateUsbDeviceAddress( usbPort, "USB port",
+ HostdevUsbDeviceAddress.DEVICE_PORT_MAX_VALUE );
+
+ this.usbBus = usbBus;
+ this.usbPort = usbPort;
+ }
+
+ /**
+ * Validates a specified USB device address component (USB bus or port).
+ *
+ * @param address value of the USB address component.
+ * @param addressName name of the USB address component.
+ * @param upperLimit maximum value for the USB address component
+ *
+ * @throws IllegalArgumentException
+ */
+ private static void validateUsbDeviceAddress( final int address, final String addressName, final int upperLimit )
+ throws IllegalArgumentException
+ {
+ if ( address < HostdevUsbDeviceAddress.DEVICE_ADDRESS_MIN_VALUE ) {
+ throw new IllegalArgumentException(
+ "The " + addressName + " must be larger or equal than "
+ + HostdevUsbDeviceAddress.DEVICE_ADDRESS_MIN_VALUE );
+ } else if ( address > upperLimit ) {
+ throw new IllegalArgumentException(
+ "The " + addressName + " must be smaller or equal than " + upperLimit );
+ }
+ }
+
+ /**
+ * Returns the USB bus number.
+ *
+ * @return USB bus number.
+ */
+ public int getUsbBus()
+ {
+ return this.usbBus;
+ }
+
+ /**
+ * Returns the USB port number.
+ *
+ * @return USB port number.
+ */
+ public int getUsbPort()
+ {
+ return this.usbPort;
+ }
+
+ /**
+ * Creates a new USB device address parsed from {@link String}s.
+ *
+ * @param usbBus textual information containing a decimal USB device bus number as
+ * {@link String}.
+ * @param usbPort textual information containing a decimal USB device port number as
+ * {@link String}.
+ * @return USB device address instance.
+ */
+ public static HostdevUsbDeviceAddress valueOf( String usbBus, String usbPort )
+ {
+ HostdevUsbDeviceAddress usbDeviceAddress;
+
+ if ( usbBus == null || usbBus.isEmpty() || usbPort == null || usbPort.isEmpty() ) {
+ usbDeviceAddress = null;
+ } else {
+ try {
+ final int parsedUsbBus = Integer.valueOf( usbBus );
+ final int parsedUsbPort = Integer.valueOf( usbPort );
+ usbDeviceAddress = new HostdevUsbDeviceAddress( parsedUsbBus, parsedUsbPort );
+ } catch ( IllegalArgumentException e ) {
+ usbDeviceAddress = null;
+ }
+ }
+
+ return usbDeviceAddress;
+
+ }
+
+ @Override
+ public boolean equals( Object obj )
+ {
+ if ( obj == null ) {
+ return false;
+ } else if ( this.getClass() != obj.getClass() ) {
+ return false;
+ } else {
+ // check if USB bus and port are equal
+ final HostdevUsbDeviceAddress other = HostdevUsbDeviceAddress.class.cast( obj );
+ if ( this.getUsbBus() == other.getUsbBus() && this.getUsbPort() == other.getUsbPort() ) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }
+
+ @Override
+ public String toString()
+ {
+ return this.getUsbBus() + ":" + this.getUsbPort();
+ }
+}
diff --git a/src/main/java/org/openslx/libvirt/domain/device/HostdevUsbDeviceDescription.java b/src/main/java/org/openslx/libvirt/domain/device/HostdevUsbDeviceDescription.java
new file mode 100644
index 0000000..d1c546f
--- /dev/null
+++ b/src/main/java/org/openslx/libvirt/domain/device/HostdevUsbDeviceDescription.java
@@ -0,0 +1,190 @@
+package org.openslx.libvirt.domain.device;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Representation of an USB device description.
+ *
+ * @author Manuel Bentele
+ * @version 1.0
+ */
+public class HostdevUsbDeviceDescription
+{
+ /**
+ * Regular expression to parse an USB device vendor and product identifier from a {@link String}.
+ * <p>
+ * The regular expression matches an USB device description if its textual USB device description
+ * is well-formed according to the following examples:
+ *
+ * <pre>
+ * 1d6b:0002
+ * 0461:4d22
+ * 046d:c312
+ * </pre>
+ */
+ private static final String DEVICE_DESCRIPTION_REGEX = "^([a-f0-9]{4}):([a-f0-9]{4})$";
+
+ /**
+ * Minimum value of a valid identifier from an USB device description.
+ */
+ private static final int DEVICE_DESCRIPTION_ID_MIN_VALUE = 0x0000;
+
+ /**
+ * Maximum value of a valid identifier from an USB device description.
+ */
+ private static final int DEVICE_DESCRIPTION_ID_MAX_VALUE = 0xffff;
+
+ /**
+ * Vendor identifier of the USB device.
+ */
+ final int vendorId;
+
+ /**
+ * Product identifier of the USB device.
+ */
+ final int productId;
+
+ /**
+ * Creates a new USB device description consisting of a USB vendor and product identifier.
+ *
+ * @param vendorId vendor identifier of the USB device.
+ * @param productId product identifier of the USB device.
+ *
+ * @throws throws IllegalArgumentException failed to validate the USB device description
+ * identifiers.
+ */
+ public HostdevUsbDeviceDescription( int vendorId, int productId ) throws IllegalArgumentException
+ {
+ HostdevUsbDeviceDescription.validateUsbDeviceDescriptionId( "PCI vendor ID", vendorId );
+ HostdevUsbDeviceDescription.validateUsbDeviceDescriptionId( "PCI device ID", productId );
+
+ this.vendorId = vendorId;
+ this.productId = productId;
+ }
+
+ /**
+ * Validates an USB device description ID (an USB vendor or product ID).
+ *
+ * @param idName name of the USB device description identifier.
+ * @param id value of the USB device description identifier that should be validated.
+ *
+ * @throws IllegalArgumentException failed to validate the USB device description identifier.
+ */
+ private static void validateUsbDeviceDescriptionId( final String idName, final int id )
+ throws IllegalArgumentException
+ {
+ if ( id < HostdevUsbDeviceDescription.DEVICE_DESCRIPTION_ID_MIN_VALUE ) {
+ throw new IllegalArgumentException(
+ "The " + idName + "must be larger or equal than "
+ + HostdevUsbDeviceDescription.DEVICE_DESCRIPTION_ID_MIN_VALUE );
+ } else if ( id > HostdevUsbDeviceDescription.DEVICE_DESCRIPTION_ID_MAX_VALUE ) {
+ throw new IllegalArgumentException(
+ "The " + idName + "must be smaller or equal than "
+ + HostdevUsbDeviceDescription.DEVICE_DESCRIPTION_ID_MAX_VALUE );
+ }
+ }
+
+ /**
+ * Returns the USB device vendor identifier.
+ *
+ * @return USB device vendor identifier.
+ */
+ public int getVendorId()
+ {
+ return this.vendorId;
+ }
+
+ /**
+ * Returns the USB vendor identifier as {@link String}.
+ *
+ * @return USB vendor identifier as {@link String}.
+ */
+ public String getVendorIdAsString()
+ {
+ return String.format( "%04x", HostdevUsbDeviceDescription.DEVICE_DESCRIPTION_ID_MAX_VALUE & this.getVendorId() );
+ }
+
+ /**
+ * Returns the USB device product identifier.
+ *
+ * @return USB device product identifier.
+ */
+ public int getProductId()
+ {
+ return this.productId;
+ }
+
+ /**
+ * Returns the USB device product identifier as {@link String}.
+ *
+ * @return USB device product identifier as {@link String}.
+ */
+ public String getProductIdAsString()
+ {
+ return String.format( "%04x", HostdevUsbDeviceDescription.DEVICE_DESCRIPTION_ID_MAX_VALUE & this.getProductId() );
+ }
+
+ /**
+ * Creates a new USB device description parsed from a {@link String}.
+ * <p>
+ * The USB device description consists of an USB vendor and product identifier parsed from the
+ * specified {@link String}.
+ *
+ * @param vendorProductId textual information containing an USB device description as
+ * {@link String}. The textual USB device description should be well-formed according
+ * to the defined regular expression {@link #DEVICE_DESCRIPTION_REGEX}.
+ *
+ * @return USB device description instance.
+ */
+ public static HostdevUsbDeviceDescription valueOf( String vendorProductId )
+ {
+ HostdevUsbDeviceDescription usbDeviceDescription;
+
+ if ( vendorProductId == null || vendorProductId.isEmpty() ) {
+ usbDeviceDescription = null;
+ } else {
+ final Pattern usbDeviceDescPattern = Pattern.compile( HostdevUsbDeviceDescription.DEVICE_DESCRIPTION_REGEX );
+ final Matcher usbDeviceDescMatcher = usbDeviceDescPattern.matcher( vendorProductId.toLowerCase() );
+
+ if ( usbDeviceDescMatcher.find() ) {
+ final int vendorId = Integer.valueOf( usbDeviceDescMatcher.group( 1 ), 16 );
+ final int productId = Integer.valueOf( usbDeviceDescMatcher.group( 2 ), 16 );
+
+ try {
+ usbDeviceDescription = new HostdevUsbDeviceDescription( vendorId, productId );
+ } catch ( IllegalArgumentException e ) {
+ usbDeviceDescription = null;
+ }
+ } else {
+ usbDeviceDescription = null;
+ }
+ }
+
+ return usbDeviceDescription;
+ }
+
+ @Override
+ public boolean equals( Object obj )
+ {
+ if ( obj == null ) {
+ return false;
+ } else if ( this.getClass() != obj.getClass() ) {
+ return false;
+ } else {
+ // check if vendor and product ID are equal
+ final HostdevUsbDeviceDescription other = HostdevUsbDeviceDescription.class.cast( obj );
+ if ( this.getVendorId() == other.getVendorId() && this.getProductId() == other.getProductId() ) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }
+
+ @Override
+ public String toString()
+ {
+ return this.getVendorIdAsString() + ":" + this.getProductIdAsString();
+ }
+}
diff --git a/src/main/java/org/openslx/libvirt/domain/device/HostdevUtils.java b/src/main/java/org/openslx/libvirt/domain/device/HostdevUtils.java
new file mode 100644
index 0000000..204bea9
--- /dev/null
+++ b/src/main/java/org/openslx/libvirt/domain/device/HostdevUtils.java
@@ -0,0 +1,32 @@
+package org.openslx.libvirt.domain.device;
+
+/**
+ * Collection of helper methods to maintain a Libvirt related hostdev XML element.
+ *
+ * @author Manuel Bentele
+ * @version 1.0
+ */
+public class HostdevUtils
+{
+ /**
+ * Appends the HEX prefix to a specified hostdev address component without any HEX prefix.
+ *
+ * @param component address component without any HEX prefix.
+ * @return address component with the HEX prefix.
+ */
+ public static String appendHexPrefix( String component )
+ {
+ return "0x" + component;
+ }
+
+ /**
+ * Removes a possible HEX prefix of a specified hostdev address component.
+ *
+ * @param component address component with possible HEX prefix.
+ * @return address component without any HEX prefix.
+ */
+ public static String removeHexPrefix( String component )
+ {
+ return component.replaceFirst( "0x", "" );
+ }
+}
diff --git a/src/main/java/org/openslx/libvirt/domain/device/Shmem.java b/src/main/java/org/openslx/libvirt/domain/device/Shmem.java
new file mode 100644
index 0000000..3c48c95
--- /dev/null
+++ b/src/main/java/org/openslx/libvirt/domain/device/Shmem.java
@@ -0,0 +1,178 @@
+package org.openslx.libvirt.domain.device;
+
+import java.math.BigInteger;
+
+import org.openslx.libvirt.domain.DomainUtils;
+import org.openslx.libvirt.xml.LibvirtXmlNode;
+
+/**
+ * A shared memory device node in a Libvirt domain XML document.
+ *
+ * @author Manuel Bentele
+ * @version 1.0
+ */
+public class Shmem extends Device
+{
+ /**
+ * Creates an empty sound device.
+ */
+ public Shmem()
+ {
+ super();
+ }
+
+ /**
+ * Creates a shared memory device representing an existing Libvirt XML shared memory device
+ * element.
+ *
+ * @param xmlNode existing Libvirt XML shared memory device element.
+ */
+ public Shmem( LibvirtXmlNode xmlNode )
+ {
+ super( xmlNode );
+ }
+
+ /**
+ * Returns the model of the shared memory device.
+ *
+ * @return model of the shared memory device.
+ */
+ public Model getModel()
+ {
+ String model = this.getXmlElementAttributeValue( "model", "type" );
+ return Model.fromString( model );
+ }
+
+ /**
+ * Sets the model for the shared memory device.
+ *
+ * @param model model for the shared memory device.
+ */
+ public void setModel( Model model )
+ {
+ this.setXmlElementAttributeValue( "model", "type", model.toString() );
+ }
+
+ /**
+ * Returns the name of the shared memory device.
+ *
+ * @return name of the shared memory device.
+ */
+ public String getName()
+ {
+ return this.getXmlElementAttributeValue( "name" );
+ }
+
+ /**
+ * Sets the name for the shared memory device.
+ *
+ * @param name name for the shared memory device.
+ */
+ public void setName( String name )
+ {
+ this.setXmlElementAttributeValue( "name", name );
+ }
+
+ /**
+ * Returns the memory size of the shared memory device.
+ *
+ * @return memory size of the shared memory device in bytes.
+ */
+ public BigInteger getSize()
+ {
+ final String unit = this.getXmlElementAttributeValue( "size", "unit" );
+ final String size = this.getXmlElementValue( "size" );
+
+ return DomainUtils.decodeMemory( size, unit );
+ }
+
+ /**
+ * Sets the memory size for the shared memory device.
+ *
+ * @param size memory size for the shared memory device in bytes.
+ */
+ public void setSize( BigInteger memory )
+ {
+ final String unit = "M";
+ final String size = DomainUtils.encodeMemory( memory, unit );
+
+ this.setXmlElementAttributeValue( "size", "unit", unit );
+ this.setXmlElementValue( "size", size );
+ }
+
+ /**
+ * Creates a non-existent shared memory device as Libvirt XML device element.
+ *
+ * @param xmlNode Libvirt XML node of the Libvirt XML device that is created.
+ * @return created shared memory device instance.
+ */
+ public static Shmem createInstance( LibvirtXmlNode xmlNode )
+ {
+ return Shmem.newInstance( xmlNode );
+ }
+
+ /**
+ * Creates a shared memory device representing an existing Libvirt XML shared memory device
+ * element.
+ *
+ * @param xmlNode existing Libvirt XML shared memory device element.
+ * @return shared memory device instance.
+ */
+ public static Shmem newInstance( LibvirtXmlNode xmlNode )
+ {
+ return new Shmem( xmlNode );
+ }
+
+ /**
+ * Model of shared memory device.
+ *
+ * @author Manuel Bentele
+ * @version 1.0
+ */
+ public enum Model
+ {
+ // @formatter:off
+ IVSHMEM ( "ivshmem" ),
+ IVSHMEM_PLAIN ( "ivshmem-plain" ),
+ IVSHMEM_DOORBELL( "ivshmem-doorbell" );
+ // @formatter:on
+
+ /**
+ * Name of the shared memory device model.
+ */
+ private String model;
+
+ /**
+ * Creates shared memory device model.
+ *
+ * @param type valid name of the shared memory device model in a Libvirt domain XML document.
+ */
+ Model( String model )
+ {
+ this.model = model;
+ }
+
+ @Override
+ public String toString()
+ {
+ return this.model;
+ }
+
+ /**
+ * Creates shared memory device model from its name with error check.
+ *
+ * @param model name of the shared memory device model in a Libvirt domain XML document.
+ * @return valid shared memory device model.
+ */
+ public static Model fromString( String model )
+ {
+ for ( Model m : Model.values() ) {
+ if ( m.model.equalsIgnoreCase( model ) ) {
+ return m;
+ }
+ }
+
+ return null;
+ }
+ }
+}
diff --git a/src/main/java/org/openslx/libvirt/domain/device/Video.java b/src/main/java/org/openslx/libvirt/domain/device/Video.java
index 0f8861f..f3ee13f 100644
--- a/src/main/java/org/openslx/libvirt/domain/device/Video.java
+++ b/src/main/java/org/openslx/libvirt/domain/device/Video.java
@@ -71,7 +71,7 @@ public class Video extends Device
if ( model != null ) {
if ( model == Model.VIRTIO ) {
// only set acceleration on supported Virtio GPUs
- this.setXmlElementAttributeValue( "model/acceleration", "accel2d", acceleration );
+ this.setXmlElementAttributeValueYesNo( "model/acceleration", "accel2d", acceleration );
} else {
String errorMsg = new String(
"Video card model '" + model.toString() + "' does not support enabled 2D hardware acceleration." );
@@ -101,7 +101,7 @@ public class Video extends Device
if ( model == Model.VIRTIO ) {
// only set acceleration on supported Virtio GPUs
- this.setXmlElementAttributeValue( "model/acceleration", "accel3d", acceleration );
+ this.setXmlElementAttributeValueYesNo( "model/acceleration", "accel3d", acceleration );
} else {
String errorMsg = new String(
"Video card model '" + model.toString() + "' does not support enabled 3D hardware acceleration." );
@@ -110,6 +110,15 @@ public class Video extends Device
}
/**
+ * Disables the video device by setting the model to {@link Model#NONE}.
+ */
+ public void disable()
+ {
+ this.removeXmlElementChilds();
+ this.setModel( Model.NONE );
+ }
+
+ /**
* Creates a non-existent video device as Libvirt XML device element.
*
* @param xmlNode Libvirt XML node of the Libvirt XML device that is created.
diff --git a/src/main/java/org/openslx/libvirt/xml/LibvirtXmlEditable.java b/src/main/java/org/openslx/libvirt/xml/LibvirtXmlEditable.java
index 40d7b86..5834e58 100644
--- a/src/main/java/org/openslx/libvirt/xml/LibvirtXmlEditable.java
+++ b/src/main/java/org/openslx/libvirt/xml/LibvirtXmlEditable.java
@@ -93,6 +93,14 @@ public interface LibvirtXmlEditable
public void removeXmlElement( String expression );
/**
+ * Removes all child elements of the current XML root element.
+ */
+ public default void removeXmlElementChilds()
+ {
+ this.removeXmlElementChilds( null );
+ }
+
+ /**
* Removes all child elements of a XML element selected by a XPath expression.
*
* @param expression XPath expression to select XML element.
@@ -114,9 +122,9 @@ public interface LibvirtXmlEditable
/**
* Returns the binary choice of a XML attribute from the current XML root element.
*
- * If the text value of the XML attribute equals to <i>yes</i>, the returned {@link boolean}
- * value is set to <i>true</i>. Otherwise, if the text value of the XML attribute equals to
- * <i>no</i>, the returned {@link boolean} value is set to <i>false</i>.
+ * If the text value of the XML attribute equals to <i>yes</i> or <i>on</i>, the returned
+ * {@link boolean} value is set to <i>true</i>. Otherwise, if the text value of the XML attribute
+ * equals to <i>no</i> or <i>off</i>, the returned {@link boolean} value is set to <i>false</i>.
*
* @param attributeName name to select XML attribute of the current XML root element.
* @return attribute value of the XML attribute from the current XML root element as
@@ -124,16 +132,17 @@ public interface LibvirtXmlEditable
*/
public default boolean getXmlElementAttributeValueAsBool( String attributeName )
{
- return "yes".equals( this.getXmlElementAttributeValue( attributeName ) );
+ final String attributeValue = this.getXmlElementAttributeValue( attributeName );
+ return "yes".equals( attributeValue ) || "on".equals( attributeValue );
}
/**
* Returns the binary choice of a XML attribute from a XML element selected by a XPath
* expression.
*
- * If the text value of the XML attribute equals to <i>yes</i>, the returned {@link boolean}
- * value is set to <i>true</i>. Otherwise, if the text value of the XML attribute equals to
- * <i>no</i>, the returned {@link boolean} value is set to <i>false</i>.
+ * If the text value of the XML attribute equals to <i>yes</i> or <i>on</i>, the returned
+ * {@link boolean} value is set to <i>true</i>. Otherwise, if the text value of the XML attribute
+ * equals to <i>no</i> or <i>off</i>, the returned {@link boolean} value is set to <i>false</i>.
*
* @param expression XPath expression to select XML element.
* @param attributeName name to select XML attribute of the current XML root element.
@@ -142,7 +151,8 @@ public interface LibvirtXmlEditable
*/
public default boolean getXmlElementAttributeValueAsBool( String expression, String attributeName )
{
- return "yes".equals( this.getXmlElementAttributeValue( expression, attributeName ) );
+ final String attributeValue = this.getXmlElementAttributeValue( expression, attributeName );
+ return "yes".equals( attributeValue ) || "on".equals( attributeValue );
}
/**
@@ -177,7 +187,7 @@ public interface LibvirtXmlEditable
* @param attributeName name to select XML attribute of the selected XML element.
* @param value binary choice value for the selected XML attribute from the selected XML element.
*/
- public default void setXmlElementAttributeValue( String attributeName, boolean value )
+ public default void setXmlElementAttributeValueYesNo( String attributeName, boolean value )
{
final String valueYesNo = value ? "yes" : "no";
this.setXmlElementAttributeValue( attributeName, valueYesNo );
@@ -196,13 +206,49 @@ public interface LibvirtXmlEditable
* @param attributeName name to select XML attribute of the selected XML element.
* @param value binary choice value for the selected XML attribute from the selected XML element.
*/
- public default void setXmlElementAttributeValue( String expression, String attributeName, boolean value )
+ public default void setXmlElementAttributeValueYesNo( String expression, String attributeName, boolean value )
{
final String valueYesNo = value ? "yes" : "no";
this.setXmlElementAttributeValue( expression, attributeName, valueYesNo );
}
/**
+ * Sets the binary choice value of a XML attribute from the current XML root element.
+ *
+ * If the binary choice value for the XML attribute equals to <i>true</i>, the text value of the
+ * selected XML attribute is set to <i>on</i>. Otherwise, if the binary choice value for the
+ * selected XML attribute equals to <i>false</i>, the text value of the selected XML attribute is
+ * set to <i>off</i>.
+ *
+ * @param attributeName name to select XML attribute of the selected XML element.
+ * @param value binary choice value for the selected XML attribute from the selected XML element.
+ */
+ public default void setXmlElementAttributeValueOnOff( String attributeName, boolean value )
+ {
+ final String valueOnOff = value ? "on" : "off";
+ this.setXmlElementAttributeValue( attributeName, valueOnOff );
+ }
+
+ /**
+ * Sets the binary choice value of a XML attribute from a XML element selected by a XPath
+ * expression.
+ *
+ * If the binary choice value for the XML attribute equals to <i>true</i>, the text value of the
+ * selected XML attribute is set to <i>on</i>. Otherwise, if the binary choice value for the
+ * selected XML attribute equals to <i>false</i>, the text value of the selected XML attribute is
+ * set to <i>off</i>.
+ *
+ * @param expression XPath expression to select XML element.
+ * @param attributeName name to select XML attribute of the selected XML element.
+ * @param value binary choice value for the selected XML attribute from the selected XML element.
+ */
+ public default void setXmlElementAttributeValueOnOff( String expression, String attributeName, boolean value )
+ {
+ final String valueOnOff = value ? "on" : "off";
+ this.setXmlElementAttributeValue( expression, attributeName, valueOnOff );
+ }
+
+ /**
* Sets the text value of a XML attribute from a XML element selected by a XPath expression.
*
* @param expression XPath expression to select XML element.
diff --git a/src/main/java/org/openslx/libvirt/xml/LibvirtXmlNode.java b/src/main/java/org/openslx/libvirt/xml/LibvirtXmlNode.java
index 6d00271..2110f7a 100644
--- a/src/main/java/org/openslx/libvirt/xml/LibvirtXmlNode.java
+++ b/src/main/java/org/openslx/libvirt/xml/LibvirtXmlNode.java
@@ -184,9 +184,7 @@ public class LibvirtXmlNode implements LibvirtXmlCreatable, LibvirtXmlEditable
{
String completeExpression = null;
- if ( expression == null ) {
- completeExpression = XPATH_EXPRESSION_CURRENT_NODE;
- } else if ( expression.isEmpty() ) {
+ if ( expression == null || expression.isEmpty() ) {
completeExpression = XPATH_EXPRESSION_CURRENT_NODE;
} else {
completeExpression = XPATH_EXPRESSION_CURRENT_NODE + XPATH_EXPRESSION_SEPARATOR + expression;
@@ -271,8 +269,9 @@ public class LibvirtXmlNode implements LibvirtXmlCreatable, LibvirtXmlEditable
Node node = this.getXmlElement( expression );
if ( node != null ) {
- for ( int i = 0; i < node.getChildNodes().getLength(); i++ ) {
- Node child = node.getChildNodes().item( 0 );
+ final NodeList childs = node.getChildNodes();
+ while ( childs.getLength() > 0 ) {
+ Node child = childs.item( 0 );
node.removeChild( child );
}
}
@@ -281,13 +280,7 @@ public class LibvirtXmlNode implements LibvirtXmlCreatable, LibvirtXmlEditable
@Override
public String getXmlElementAttributeValue( String expression, String attributeName )
{
- Node node = null;
-
- if ( expression != null && !expression.isEmpty() ) {
- node = this.getXmlElement( expression );
- } else {
- node = this.xmlBaseNode;
- }
+ Node node = this.getXmlElement( expression );
if ( node == null ) {
return null;
diff --git a/src/test/java/org/openslx/libvirt/domain/device/HostdevPciDeviceAddressTest.java b/src/test/java/org/openslx/libvirt/domain/device/HostdevPciDeviceAddressTest.java
new file mode 100644
index 0000000..377e126
--- /dev/null
+++ b/src/test/java/org/openslx/libvirt/domain/device/HostdevPciDeviceAddressTest.java
@@ -0,0 +1,79 @@
+package org.openslx.libvirt.domain.device;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+public class HostdevPciDeviceAddressTest
+{
+ @Test
+ @DisplayName( "Test that a PCI device address instance is not created if invalid values are specified" )
+ public void testHostdevPciDeviceAddressInstanceInvalid()
+ {
+ assertThrows( IllegalArgumentException.class,
+ () -> new HostdevPciDeviceAddress( Integer.MIN_VALUE, 0x03, 0x0a, 0x7 ) );
+ assertThrows( IllegalArgumentException.class,
+ () -> new HostdevPciDeviceAddress( 0x72ab, 0x0c, 0x1a, Integer.MAX_VALUE ) );
+ }
+
+ @Test
+ @DisplayName( "Test that a PCI device address instance is parsed from a valid String" )
+ public void testHostdevPciDeviceAddressValueOfValid()
+ {
+ final HostdevPciDeviceAddress pciDeviceAddr = HostdevPciDeviceAddress.valueOf( "002b:2a:1f.1" );
+
+ assertNotNull( pciDeviceAddr );
+ assertEquals( 0x002b, pciDeviceAddr.getPciDomain() );
+ assertEquals( "002b", pciDeviceAddr.getPciDomainAsString() );
+ assertEquals( 0x2a, pciDeviceAddr.getPciBus() );
+ assertEquals( "2a", pciDeviceAddr.getPciBusAsString() );
+ assertEquals( 0x1f, pciDeviceAddr.getPciDevice() );
+ assertEquals( "1f", pciDeviceAddr.getPciDeviceAsString() );
+ assertEquals( 0x1, pciDeviceAddr.getPciFunction() );
+ assertEquals( "1", pciDeviceAddr.getPciFunctionAsString() );
+ }
+
+ @Test
+ @DisplayName( "Test that no PCI device address instance is parsed from an invalid String" )
+ public void testHostdevPciDeviceAddressValueOfInvalid()
+ {
+ final HostdevPciDeviceAddress pciDeviceAddr = HostdevPciDeviceAddress.valueOf( "0000b2ac1f31" );
+
+ assertNull( pciDeviceAddr );
+ }
+
+ @Test
+ @DisplayName( "Test that two PCI device address instances are equal" )
+ public void testHostdevPciDeviceAddressEquals()
+ {
+ final HostdevPciDeviceAddress pciDeviceAddr1 = new HostdevPciDeviceAddress( 0x0000, 0x2a, 0x1f, 0x1 );
+ final HostdevPciDeviceAddress pciDeviceAddr2 = new HostdevPciDeviceAddress( 0x0000, 0x2a, 0x1f, 0x1 );
+
+ assertTrue( pciDeviceAddr1.equals( pciDeviceAddr2 ) );
+ }
+
+ @Test
+ @DisplayName( "Test that two PCI device address instances are not equal" )
+ public void testHostdevPciDeviceAddressNotEquals()
+ {
+ final HostdevPciDeviceAddress pciDeviceAddr1 = new HostdevPciDeviceAddress( 0x0000, 0x2a, 0x1f, 0x1 );
+ final HostdevPciDeviceAddress pciDeviceAddr2 = new HostdevPciDeviceAddress( 0x0000, 0x2a, 0x1f, 0x2 );
+
+ assertFalse( pciDeviceAddr1.equals( pciDeviceAddr2 ) );
+ }
+
+ @Test
+ @DisplayName( "Test that a PCI device address can be dumped to a String" )
+ public void testHostdevPciDeviceAddressToString()
+ {
+ final HostdevPciDeviceAddress pciDeviceAddr = new HostdevPciDeviceAddress( 0x0000, 0x2a, 0x1f, 0x1 );
+
+ assertEquals( "0000:2a:1f.1", pciDeviceAddr.toString() );
+ }
+}
diff --git a/src/test/java/org/openslx/libvirt/domain/device/HostdevPciDeviceDescriptionTest.java b/src/test/java/org/openslx/libvirt/domain/device/HostdevPciDeviceDescriptionTest.java
new file mode 100644
index 0000000..7a740ac
--- /dev/null
+++ b/src/test/java/org/openslx/libvirt/domain/device/HostdevPciDeviceDescriptionTest.java
@@ -0,0 +1,75 @@
+package org.openslx.libvirt.domain.device;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+public class HostdevPciDeviceDescriptionTest
+{
+ @Test
+ @DisplayName( "Test that a PCI device description instance is not created if invalid values are specified" )
+ public void testHostdevPciDeviceDescriptionInstanceInvalid()
+ {
+ assertThrows( IllegalArgumentException.class,
+ () -> new HostdevPciDeviceDescription( Integer.MIN_VALUE, 0x293a ) );
+ assertThrows( IllegalArgumentException.class,
+ () -> new HostdevPciDeviceDescription( 0x8086, Integer.MAX_VALUE ) );
+ }
+
+ @Test
+ @DisplayName( "Test that a PCI device description instance is parsed from a valid String" )
+ public void testHostdevPciDeviceDescriptionValueOfValid()
+ {
+ final HostdevPciDeviceDescription pciDeviceDesc = HostdevPciDeviceDescription.valueOf( "8086:293a" );
+
+ assertNotNull( pciDeviceDesc );
+ assertEquals( 0x8086, pciDeviceDesc.getVendorId() );
+ assertEquals( "8086", pciDeviceDesc.getVendorIdAsString() );
+ assertEquals( 0x293a, pciDeviceDesc.getDeviceId() );
+ assertEquals( "293a", pciDeviceDesc.getDeviceIdAsString() );
+ }
+
+ @Test
+ @DisplayName( "Test that no PCI device description instance is parsed from an invalid String" )
+ public void testHostdevPciDeviceDescriptionValueOfInvalid()
+ {
+ final HostdevPciDeviceDescription pciDeviceDesc = HostdevPciDeviceDescription.valueOf( "bba93e215" );
+
+ assertNull( pciDeviceDesc );
+ }
+
+ @Test
+ @DisplayName( "Test that two PCI device description instances are equal" )
+ public void testHostdevPciDeviceDescriptionEquals()
+ {
+ final HostdevPciDeviceDescription pciDeviceDesc1 = new HostdevPciDeviceDescription( 0x8086, 0x293a );
+ final HostdevPciDeviceDescription pciDeviceDesc2 = new HostdevPciDeviceDescription( 0x8086, 0x293a );
+
+ assertTrue( pciDeviceDesc1.equals( pciDeviceDesc2 ) );
+ }
+
+ @Test
+ @DisplayName( "Test that two PCI device description instances are not equal" )
+ public void testHostdevPciDeviceDescriptionNotEquals()
+ {
+ final HostdevPciDeviceDescription pciDeviceDesc1 = new HostdevPciDeviceDescription( 0x8086, 0x293a );
+ final HostdevPciDeviceDescription pciDeviceDesc2 = new HostdevPciDeviceDescription( 0x293a, 0x8086 );
+
+ assertFalse( pciDeviceDesc1.equals( pciDeviceDesc2 ) );
+ }
+
+ @Test
+ @DisplayName( "Test that a PCI device description can be dumped to a String" )
+ public void testHostdevPciDeviceDescriptionToString()
+ {
+ final HostdevPciDeviceDescription pciDeviceDesc = new HostdevPciDeviceDescription( 0x00b1, 0x293a );
+
+ assertEquals( "00b1:293a", pciDeviceDesc.toString() );
+ }
+}