[libvirt] [PATCH 1/3] Add serials to USB hostdevs in domain XML

Ján Tomko jtomko at redhat.com
Thu Jun 5 18:59:42 UTC 2014


From: David Waring <davidjw at rd.bbc.co.uk>

This patch adds the ability to include a serial element in a
hostdev/source to select a device with a particular serial number.

Signed-off-by: Ján Tomko <jtomko at redhat.com>
---
 docs/formatdomain.html.in                          | 22 +++++++-----
 docs/schemas/domaincommon.rng                      |  8 +++++
 src/conf/domain_conf.c                             | 31 +++++++++++++---
 src/conf/domain_conf.h                             |  1 +
 .../qemuxml2argvdata/qemuxml2argv-usb-hostdev.xml  | 42 ++++++++++++++++++++++
 tests/qemuxml2xmltest.c                            |  2 ++
 6 files changed, 92 insertions(+), 14 deletions(-)
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb-hostdev.xml

diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index 691a451..5bb2531 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -2711,6 +2711,7 @@
       <source startupPolicy='optional'>
         <vendor id='0x1234'/>
         <product id='0xbeef'/>
+        <serial>SERIAL123456</serial>
       </source>
       <boot order='2'/>
     </hostdev>
@@ -2773,10 +2774,11 @@
       </dd>
       <dt><code>source</code></dt>
       <dd>The source element describes the device as seen from the host.
-      The USB device can either be addressed by vendor / product id using the
-      <code>vendor</code> and <code>product</code> elements or by the device's
-      address on the hosts using the <code>address</code> element. PCI devices
-      on the other hand can only be described by their <code>address</code>.
+      The USB device can either be addressed by vendor / product id and optional
+      serial number using the <code>vendor</code>, <code>product</code> and
+      <code>serial</code> elements or by the device's address on the hosts using
+      the <code>address</code> element. PCI devices on the other hand can only
+      be described by their <code>address</code>.
       SCSI devices are described by both the <code>adapter</code> and
       <code>address</code> elements.
 
@@ -2800,11 +2802,13 @@
           </tr>
         </table>
       </dd>
-      <dt><code>vendor</code>, <code>product</code></dt>
-      <dd>The <code>vendor</code> and <code>product</code> elements each have an
-      <code>id</code> attribute that specifies the USB vendor and product id.
-      The ids can be given in decimal, hexadecimal (starting with 0x) or
-      octal (starting with 0) form.</dd>
+      <dt><code>vendor</code>, <code>product</code>, <code>serial</code></dt>
+      <dd>The <code>vendor</code>, <code>product</code> and <code>serial</code>
+      elements each have an <code>id</code> attribute that specifies the USB
+      vendor, product and device serial id. The ids can be given in decimal,
+      hexadecimal (starting with 0x) or octal (starting with 0) form for
+      vendor and product. The serial number is a string that matches the serial
+      number of the device.</dd>
       <dt><code>boot</code></dt>
       <dd>Specifies that the device is bootable. The <code>order</code>
       attribute determines the order in which devices will be tried during
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index af67123..8595771 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -3546,6 +3546,14 @@
         <ref name="usbId"/>
       </attribute>
     </element>
+    <optional>
+      <element name="serial">
+        <choice>
+          <text/>
+          <empty/>
+        </choice>
+      </element>
+    </optional>
   </define>
   <define name="usbaddress">
     <element name="address">
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index fe06921..4c1d02e 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -1719,8 +1719,14 @@ void virDomainHostdevDefClear(virDomainHostdevDefPtr def)
         }
         break;
     case VIR_DOMAIN_HOSTDEV_MODE_SUBSYS:
-        if (def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI)
+        switch (def->source.subsys.type) {
+        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
+            VIR_FREE(def->source.subsys.u.usb.serial);
+            break;
+        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI:
             VIR_FREE(def->source.subsys.u.scsi.adapter);
+            break;
+        }
         break;
     }
 }
@@ -3852,6 +3858,18 @@ virDomainHostdevSubsysUSBDefParseXML(xmlNodePtr node,
                                    "%s", _("usb product needs id"));
                     goto out;
                 }
+            } else if (xmlStrEqual(cur->name, BAD_CAST "serial")) {
+                char *serial;
+
+                if (VIR_STRDUP(serial, (const char *)xmlNodeGetContent(cur)) < 0)
+                    goto out;
+
+                if (!serial) {
+                    virReportError(VIR_ERR_INTERNAL_ERROR,
+                                   "%s", _("usb serial needs id"));
+                    goto out;
+                }
+                def->source.subsys.u.usb.serial = serial;
             } else if (xmlStrEqual(cur->name, BAD_CAST "address")) {
                 char *bus, *device;
 
@@ -3903,12 +3921,12 @@ virDomainHostdevSubsysUSBDefParseXML(xmlNodePtr node,
         goto out;
     }
 
-    if (!got_vendor && got_product) {
+    if (!got_vendor && (got_product || def->source.subsys.u.usb.serial)) {
         virReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("missing vendor"));
         goto out;
     }
-    if (got_vendor && !got_product) {
+    if ((got_vendor || def->source.subsys.u.usb.serial) && !got_product) {
         virReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("missing product"));
         goto out;
@@ -10095,9 +10113,10 @@ virDomainHostdevMatchSubsysUSB(virDomainHostdevDefPtr a,
             a->source.subsys.u.usb.device == b->source.subsys.u.usb.device)
             return 1;
     } else {
-        /* specified by product & vendor id */
+        /* specified by product, vendor id and optionally serial number */
         if (a->source.subsys.u.usb.product == b->source.subsys.u.usb.product &&
-            a->source.subsys.u.usb.vendor == b->source.subsys.u.usb.vendor)
+            a->source.subsys.u.usb.vendor == b->source.subsys.u.usb.vendor &&
+            STREQ_NULLABLE(a->source.subsys.u.usb.serial, b->source.subsys.u.usb.serial))
             return 1;
     }
     return 0;
@@ -15479,6 +15498,8 @@ virDomainHostdevDefFormatSubsys(virBufferPtr buf,
                               def->source.subsys.u.usb.vendor);
             virBufferAsprintf(buf, "<product id='0x%.4x'/>\n",
                               def->source.subsys.u.usb.product);
+            virBufferEscapeString(buf, "<serial>%s</serial>\n",
+                                  def->source.subsys.u.usb.serial);
         }
         if (def->source.subsys.u.usb.bus ||
             def->source.subsys.u.usb.device) {
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 2de807d..cba3733 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -403,6 +403,7 @@ struct _virDomainHostdevSubsys {
 
             unsigned vendor;
             unsigned product;
+            char *serial;
         } usb;
         struct {
             virDevicePCIAddress addr; /* host address */
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-usb-hostdev.xml b/tests/qemuxml2argvdata/qemuxml2argv-usb-hostdev.xml
new file mode 100644
index 0000000..10c4bbf
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-usb-hostdev.xml
@@ -0,0 +1,42 @@
+<domain type='qemu'>
+  <name>QEMUGuest1</name>
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+  <memory unit='KiB'>219136</memory>
+  <currentMemory unit='KiB'>219136</currentMemory>
+  <vcpu placement='static'>1</vcpu>
+  <os>
+    <type arch='i686' machine='pc'>hvm</type>
+  </os>
+  <clock offset='utc'/>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>destroy</on_crash>
+  <devices>
+    <emulator>/usr/bin/qemu</emulator>
+    <controller type='usb' index='0' model='ich9-ehci1'>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x7'/>
+    </controller>
+    <controller type='usb' index='0' model='ich9-uhci1'>
+      <master startport='0'/>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0' multifunction='on'/>
+    </controller>
+    <controller type='usb' index='0' model='ich9-uhci2'>
+      <master startport='2'/>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x1'/>
+    </controller>
+    <controller type='usb' index='0' model='ich9-uhci3'>
+      <master startport='4'/>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x2'/>
+    </controller>
+    <controller type='pci' index='0' model='pci-root'/>
+    <hostdev mode='subsystem' type='usb' managed='no'>
+      <source startupPolicy='optional'>
+        <vendor id='0x1234'/>
+        <product id='0xbeef'/>
+        <serial>S123456</serial>
+      </source>
+      <boot order='1'/>
+    </hostdev>
+    <memballoon model='virtio'/>
+  </devices>
+</domain>
diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c
index da528da..a130034 100644
--- a/tests/qemuxml2xmltest.c
+++ b/tests/qemuxml2xmltest.c
@@ -364,6 +364,8 @@ mymain(void)
 
     DO_TEST("chardev-label");
 
+    DO_TEST("usb-hostdev");
+
     virObjectUnref(driver.caps);
     virObjectUnref(driver.xmlopt);
 
-- 
1.8.3.2




More information about the libvir-list mailing list