Introduce a new structure
struct _virDomainDeviceUSBAddress {
unsigned int bus;
unsigned int dev;
};
and plug that into virDomainDeviceAddress. Convert the
host device USB config to use this new address struct.
XML looks like
<address type='usb' bus='007' dev='003'/>
---
src/conf/domain_conf.c | 93 ++++++++++++++++++++++++++++++++++++--
src/conf/domain_conf.h | 15 +++++-
src/libvirt_private.syms | 2 +
src/qemu/qemu_conf.c | 12 +++---
src/qemu/qemu_driver.c | 13 +++---
src/security/security_selinux.c | 26 ++++++-----
6 files changed, 130 insertions(+), 31 deletions(-)
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 975b62b..0e88362 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -90,7 +90,8 @@ VIR_ENUM_IMPL(virDomainDevice, VIR_DOMAIN_DEVICE_LAST,
VIR_ENUM_IMPL(virDomainDeviceAddress, VIR_DOMAIN_DEVICE_ADDRESS_TYPE_LAST,
"none",
- "pci")
+ "pci",
+ "usb");
VIR_ENUM_IMPL(virDomainDeviceAddressMode, VIR_DOMAIN_DEVICE_ADDRESS_MODE_LAST,
"dynamic",
@@ -746,6 +747,9 @@ int virDomainDeviceAddressIsValid(virDomainDeviceAddressPtr addr,
switch (addr->type) {
case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI:
return virDomainDevicePCIAddressIsValid(&addr->data.pci);
+
+ case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB:
+ return virDomainDeviceUSBAddressIsValid(&addr->data.usb);
}
return 0;
@@ -758,6 +762,12 @@ int virDomainDevicePCIAddressIsValid(virDomainDevicePCIAddressPtr
addr)
}
+int virDomainDeviceUSBAddressIsValid(virDomainDeviceUSBAddressPtr addr)
+{
+ return addr->bus || addr->dev;
+}
+
+
void virDomainDeviceAddressClear(virDomainDeviceAddressPtr addr)
{
memset(addr, 0, sizeof(addr));
@@ -801,6 +811,12 @@ static int virDomainDeviceAddressFormat(virBufferPtr buf,
addr->data.pci.function);
break;
+ case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB:
+ virBufferVSprintf(buf, " bus='%.3d' dev='%.3d'",
+ addr->data.usb.bus,
+ addr->data.usb.dev);
+ break;
+
default:
virDomainReportError(NULL, VIR_ERR_INTERNAL_ERROR,
_("unknown address type '%d'"),
addr->type);
@@ -827,6 +843,9 @@ int virDomainDeviceAddressEqual(virDomainDeviceAddressPtr a,
case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI:
return virDomainDevicePCIAddressEqual(&a->data.pci,
&b->data.pci);
+ case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB:
+ return virDomainDeviceUSBAddressEqual(&a->data.usb,
+ &b->data.usb);
}
return 0;
@@ -846,6 +865,17 @@ int virDomainDevicePCIAddressEqual(virDomainDevicePCIAddressPtr a,
}
+int virDomainDeviceUSBAddressEqual(virDomainDeviceUSBAddressPtr a,
+ virDomainDeviceUSBAddressPtr b)
+{
+ if (a->bus == b->bus &&
+ a->dev == b->dev)
+ return 1;
+
+ return 0;
+}
+
+
static int
virDomainDevicePCIAddressParseXML(virConnectPtr conn,
xmlNodePtr node,
@@ -905,6 +935,47 @@ cleanup:
return ret;
}
+static int
+virDomainDeviceUSBAddressParseXML(virConnectPtr conn,
+ xmlNodePtr node,
+ virDomainDeviceUSBAddressPtr addr)
+{
+ char *bus, *dev;
+ int ret = -1;
+
+ memset(addr, 0, sizeof(*addr));
+
+ bus = virXMLPropString(node, "bus");
+ dev = virXMLPropString(node, "dev");
+
+ if (bus &&
+ virStrToLong_ui(bus, NULL, 10, &addr->bus) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Cannot parse <address> 'bus'
attribute"));
+ goto cleanup;
+ }
+
+ if (dev &&
+ virStrToLong_ui(dev, NULL, 10, &addr->dev) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Cannot parse <address> 'dev'
attribute"));
+ goto cleanup;
+ }
+
+ if (!virDomainDeviceUSBAddressIsValid(addr)) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Insufficient specification for USB address"));
+ goto cleanup;
+ }
+
+ ret = 0;
+
+cleanup:
+ VIR_FREE(bus);
+ VIR_FREE(dev);
+ return ret;
+}
+
/* Parse the XML definition for a device address
* @param node XML nodeset to parse for device address definition
@@ -960,6 +1031,11 @@ virDomainDeviceAddressParseXML(virConnectPtr conn,
goto cleanup;
break;
+ case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB:
+ if (virDomainDeviceUSBAddressParseXML(conn, node, &addr->data.usb) <
0)
+ goto cleanup;
+ break;
+
default:
/* Should not happen */
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
@@ -2518,7 +2594,7 @@ virDomainHostdevSubsysUsbDefParseXML(virConnectPtr conn,
bus = virXMLPropString(cur, "bus");
if (bus) {
if (virStrToLong_ui(bus, NULL, 0,
- &def->source.subsys.u.usb.bus) < 0) {
+ &def->source.subsys.u.usb.addr.bus) <
0) {
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
_("cannot parse bus %s"), bus);
VIR_FREE(bus);
@@ -2534,7 +2610,7 @@ virDomainHostdevSubsysUsbDefParseXML(virConnectPtr conn,
device = virXMLPropString(cur, "device");
if (device) {
if (virStrToLong_ui(device, NULL, 0,
- &def->source.subsys.u.usb.device) < 0)
{
+ &def->source.subsys.u.usb.addr.dev) <
0) {
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
_("cannot parse device %s"),
device);
@@ -2710,6 +2786,13 @@ virDomainHostdevDefParseXML(virConnectPtr conn,
goto error;
}
break;
+ case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
+ if (def->addr.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s",
+ _("USB host devices must use 'usb'
address type"));
+ goto error;
+ }
+ break;
}
}
@@ -4721,8 +4804,8 @@ virDomainHostdevDefFormat(virConnectPtr conn,
def->source.subsys.u.usb.product);
} else {
virBufferVSprintf(buf, " <address bus='%d'
device='%d'/>\n",
- def->source.subsys.u.usb.bus,
- def->source.subsys.u.usb.device);
+ def->source.subsys.u.usb.addr.bus,
+ def->source.subsys.u.usb.addr.dev);
}
} else if (def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) {
virBufferVSprintf(buf, " <address domain='0x%.4x'
bus='0x%.2x' slot='0x%.2x' function='0x%.1x'/>\n",
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 31a2f9d..1ae63bd 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -66,6 +66,7 @@ enum virDomainVirtType {
enum virDomainDeviceAddressType {
VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE,
VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI,
+ VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB,
VIR_DOMAIN_DEVICE_ADDRESS_TYPE_LAST
};
@@ -86,6 +87,13 @@ struct _virDomainDevicePCIAddress {
unsigned int function;
};
+typedef struct _virDomainDeviceUSBAddress virDomainDeviceUSBAddress;
+typedef virDomainDeviceUSBAddress *virDomainDeviceUSBAddressPtr;
+struct _virDomainDeviceUSBAddress {
+ unsigned int bus;
+ unsigned int dev;
+};
+
typedef struct _virDomainDeviceAddress virDomainDeviceAddress;
typedef virDomainDeviceAddress *virDomainDeviceAddressPtr;
struct _virDomainDeviceAddress {
@@ -93,6 +101,7 @@ struct _virDomainDeviceAddress {
int mode;
union {
virDomainDevicePCIAddress pci;
+ virDomainDeviceUSBAddress usb;
} data;
};
@@ -449,8 +458,7 @@ struct _virDomainHostdevDef {
int type; /* enum virDomainHostdevBusType */
union {
struct {
- unsigned bus;
- unsigned device;
+ virDomainDeviceUSBAddress addr;
unsigned vendor;
unsigned product;
@@ -695,9 +703,12 @@ int virDomainDeviceAddressEqual(virDomainDeviceAddressPtr a,
virDomainDeviceAddressPtr b);
int virDomainDevicePCIAddressEqual(virDomainDevicePCIAddressPtr a,
virDomainDevicePCIAddressPtr b);
+int virDomainDeviceUSBAddressEqual(virDomainDeviceUSBAddressPtr a,
+ virDomainDeviceUSBAddressPtr b);
int virDomainDeviceAddressIsValid(virDomainDeviceAddressPtr addr,
int type);
int virDomainDevicePCIAddressIsValid(virDomainDevicePCIAddressPtr addr);
+int virDomainDeviceUSBAddressIsValid(virDomainDeviceUSBAddressPtr addr);
void virDomainDeviceAddressClear(virDomainDeviceAddressPtr addr);
void virDomainDefFree(virDomainDefPtr vm);
void virDomainObjRef(virDomainObjPtr vm);
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 963206b..49df15c 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -156,8 +156,10 @@ virDomainObjRef;
virDomainObjUnref;
virDomainDeviceAddressEqual;
virDomainDevicePCIAddressEqual;
+virDomainDeviceUSBAddressEqual;
virDomainDeviceAddressIsValid;
virDomainDevicePCIAddressIsValid;
+virDomainDeviceUSBAddressIsValid;
virDomainDeviceAddressClear;
diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
index 7d41b5d..39d9314 100644
--- a/src/qemu/qemu_conf.c
+++ b/src/qemu/qemu_conf.c
@@ -2466,15 +2466,15 @@ int qemudBuildCommandLine(virConnectPtr conn,
/* USB */
if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) {
- if(hostdev->source.subsys.u.usb.vendor) {
- ret = virAsprintf(&usbdev, "host:%.4x:%.4x",
+ if
(!virDomainDeviceUSBAddressIsValid(&hostdev->source.subsys.u.usb.addr)) {
+ ret = virAsprintf(&usbdev, "host:%.4x:%.4x",
hostdev->source.subsys.u.usb.vendor,
hostdev->source.subsys.u.usb.product);
} else {
ret = virAsprintf(&usbdev, "host:%.3d.%.3d",
- hostdev->source.subsys.u.usb.bus,
- hostdev->source.subsys.u.usb.device);
+ hostdev->source.subsys.u.usb.addr.bus,
+ hostdev->source.subsys.u.usb.addr.dev);
}
if (ret < 0)
goto error;
@@ -3189,8 +3189,8 @@ qemuParseCommandLineUSB(virConnectPtr conn,
def->managed = 0;
def->source.subsys.type = VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB;
if (*end == '.') {
- def->source.subsys.u.usb.bus = first;
- def->source.subsys.u.usb.device = second;
+ def->source.subsys.u.usb.addr.bus = first;
+ def->source.subsys.u.usb.addr.dev = second;
} else {
def->source.subsys.u.usb.vendor = first;
def->source.subsys.u.usb.product = second;
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 5920ab3..da4fae7 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -2019,13 +2019,12 @@ static int qemuDomainSetHostdevUSBOwnership(virConnectPtr conn,
int ret = -1;
/* XXX what todo for USB devs assigned based on product/vendor ? Doom :-( */
- if (!def->source.subsys.u.usb.bus ||
- !def->source.subsys.u.usb.device)
+ if (!virDomainDeviceUSBAddressIsValid(&def->source.subsys.u.usb.addr))
return 0;
usbDevice *dev = usbGetDevice(conn,
- def->source.subsys.u.usb.bus,
- def->source.subsys.u.usb.device);
+ def->source.subsys.u.usb.addr.bus,
+ def->source.subsys.u.usb.addr.dev);
if (!dev)
goto cleanup;
@@ -5199,14 +5198,14 @@ static int qemudDomainAttachHostUsbDevice(virConnectPtr conn,
}
qemuDomainObjEnterMonitorWithDriver(driver, vm);
- if (dev->data.hostdev->source.subsys.u.usb.vendor) {
+ if
(!virDomainDeviceUSBAddressIsValid(&dev->data.hostdev->source.subsys.u.usb.addr))
{
ret = qemuMonitorAddUSBDeviceMatch(priv->mon,
dev->data.hostdev->source.subsys.u.usb.vendor,
dev->data.hostdev->source.subsys.u.usb.product);
} else {
ret = qemuMonitorAddUSBDeviceExact(priv->mon,
-
dev->data.hostdev->source.subsys.u.usb.bus,
-
dev->data.hostdev->source.subsys.u.usb.device);
+
dev->data.hostdev->source.subsys.u.usb.addr.bus,
+
dev->data.hostdev->source.subsys.u.usb.addr.dev);
}
qemuDomainObjExitMonitorWithDriver(driver, vm);
diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c
index 255ba53..1710651 100644
--- a/src/security/security_selinux.c
+++ b/src/security/security_selinux.c
@@ -481,10 +481,10 @@ SELinuxSetSecurityHostdevLabel(virConnectPtr conn,
switch (dev->source.subsys.type) {
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: {
- if (dev->source.subsys.u.usb.bus &&
dev->source.subsys.u.usb.device) {
+ if (virDomainDeviceUSBAddressIsValid(&dev->source.subsys.u.usb.addr)) {
usbDevice *usb = usbGetDevice(conn,
- dev->source.subsys.u.usb.bus,
- dev->source.subsys.u.usb.device);
+ dev->source.subsys.u.usb.addr.bus,
+ dev->source.subsys.u.usb.addr.dev);
if (!usb)
goto done;
@@ -554,16 +554,20 @@ SELinuxRestoreSecurityHostdevLabel(virConnectPtr conn,
switch (dev->source.subsys.type) {
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: {
- usbDevice *usb = usbGetDevice(conn,
- dev->source.subsys.u.usb.bus,
- dev->source.subsys.u.usb.device);
-
- if (!usb)
- goto done;
+ if (virDomainDeviceUSBAddressIsValid(&dev->source.subsys.u.usb.addr)) {
+ usbDevice *usb = usbGetDevice(conn,
+ dev->source.subsys.u.usb.addr.bus,
+ dev->source.subsys.u.usb.addr.dev);
- ret = usbDeviceFileIterate(conn, usb, SELinuxRestoreSecurityUSBLabel, NULL);
- usbFreeDevice(conn, usb);
+ if (!usb)
+ goto done;
+ ret = usbDeviceFileIterate(conn, usb, SELinuxRestoreSecurityUSBLabel, NULL);
+ usbFreeDevice(conn, usb);
+ } else {
+ /* XXX deal with product/vendor better */
+ ret = 0;
+ }
break;
}
--
1.6.5.2