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 -- Libvir-list mailing list Libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list