[libvirt] [PATCH 02/12] Extend the virDomainDeviceAddress struture to allow USB addresses

Daniel P. Berrange berrange at redhat.com
Thu Dec 10 22:22:22 UTC 2009


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




More information about the libvir-list mailing list