[libvirt] [PATCH 6/6] conf: parse/format type='hostdev' network interfaces

Laine Stump laine at laine.org
Mon Feb 20 17:10:18 UTC 2012


This is the new interface type that sets up a PCI/USB network device
to be assigned to the guest with PCI/USB passthrough after
initializing some network device-specific things from the config
(e.g. MAC address, virtualport profile parameters). Here is an example
of the syntax:

  <interface type='hostdev' managed='yes'>
    <source>
      <address type='pci' domain='0' bus='0' slot='4' function='0'/>
    </source>
    <mac address='00:11:22:33:44:55'/>
    <address type='pci' domain='0' bus='0' slot='7' function='0'/>
  </interface>

This would assign the PCI card from bus 0 slot 4 function 0 on the
host, to bus 0 slot 7 function 0 on the guest, but would first set the
MAC address of the card to 00:11:22:33:44:55.

Although it's not expected to be used very much, usb network hostdevs
are also supported for completeness. <source> syntax is identical to
that for plain <hostdev> devices, except that the <address> element
should have "type='usb'" added if it's specified:

  <interface type='hostdev'>
    <source>
      <address type='usb' bus='0' device='4'/>
    </source>
    <mac address='00:11:22:33:44:55'/>
  </interface>

If the vendor/product form of usb specification is used, type='usb'
is implied:

  <interface type='hostdev'>
    <source>
      <vendor id='0x0012'/>
      <product id='0x24dd'/>
    </source>
    <mac address='00:11:22:33:44:55'/>
  </interface>
---
 docs/formatdomain.html.in                          |   41 +++++
 docs/schemas/domaincommon.rng                      |   50 ++++++
 src/conf/domain_conf.c                             |  158 ++++++++++++++++++--
 src/conf/domain_conf.h                             |   10 ++
 src/libvirt_private.syms                           |    1 +
 src/qemu/qemu_command.c                            |    1 +
 src/uml/uml_conf.c                                 |    5 +
 src/xenxs/xen_sxpr.c                               |    1 +
 .../qemuxml2argvdata/qemuxml2argv-net-hostdev.xml  |   48 ++++++
 tests/qemuxml2xmltest.c                            |    1 +
 10 files changed, 301 insertions(+), 15 deletions(-)
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-net-hostdev.xml

diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index 5305f82..535b56d 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -2295,6 +2295,47 @@
   ...
   </pre>
 
+
+    <h5><a name="elementsNICSHostdev">PCI/USB Passthrough</a></h5>
+
+    <p>
+      A PCI or USB network device (specified by the <source>
+      element) is directly assigned to the guest using generic device
+      passthrough, after first optionally setting the device's MAC
+      address to the configured value, and associating the device with
+      a VEPA or 802.1Qgh capable switch using an optionally specified
+      %lt;virtualport%gt; element (see the examples of virtualport
+      given above for type='direct' network devices).
+      <span class="since">Since 0.9.11</span>
+    </p>
+
+    <p>
+      Note that this "intelligent passthrough" of network devices is
+      very similar to the functionality of a standard <hostdev>
+      device, the difference being that this method allows specifying
+      a MAC address and <virtualport> for the passed-through
+      device. If these capabilities are not required, of if you are
+      using a version of libvirt older than 0.9.11, you should use
+      standard <hostdev> to assign the device to the guest
+      instead of <interface type='hostdev'/>.
+    </p>
+
+<pre>
+  ...
+  <devices>
+    <interface type='hostdev'>
+      <source>
+        <address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/>
+      </source>
+      <mac address='52:54:00:6d:90:02'>
+      <virtualport type='802.1Qbh'>
+        <parameters profileid='finance'/>
+      </virtualport>
+    </interface>
+  </devices>
+  ...</pre>
+
+
     <h5><a name="elementsNICSMulticast">Multicast tunnel</a></h5>
 
     <p>
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index e276a92..f52f8e3 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -1414,6 +1414,56 @@
             </optional>
           </interleave>
         </group>
+        <group>
+          <attribute name="type">
+            <value>hostdev</value>
+          </attribute>
+          <optional>
+            <attribute name="managed">
+              <choice>
+                <value>yes</value>
+                <value>no</value>
+              </choice>
+            </attribute>
+          </optional>
+          <interleave>
+            <element name="source">
+              <choice>
+                <group>
+                  <ref name="usbproduct"/>
+                  <optional>
+                    <ref name="usbaddress"/>
+                  </optional>
+                </group>
+                <element name="address">
+                  <choice>
+                    <group>
+                      <attribute name="type">
+                        <value>pci</value>
+                      </attribute>
+                      <ref name="pciaddress"/>
+                    </group>
+                    <group>
+                      <attribute name="type">
+                        <value>usb</value>
+                      </attribute>
+                      <attribute name="bus">
+                        <ref name="usbAddr"/>
+                      </attribute>
+                      <attribute name="device">
+                        <ref name="usbPort"/>
+                      </attribute>
+                    </group>
+                  </choice>
+                </element>
+              </choice>
+            </element>
+            <optional>
+              <ref name="virtualPortProfile"/>
+            </optional>
+            <ref name="interface-options"/>
+          </interleave>
+        </group>
       </choice>
     </element>
   </define>
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 12d48fb..c0503f4 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -281,7 +281,8 @@ VIR_ENUM_IMPL(virDomainNet, VIR_DOMAIN_NET_TYPE_LAST,
               "network",
               "bridge",
               "internal",
-              "direct")
+              "direct",
+              "hostdev")
 
 VIR_ENUM_IMPL(virDomainNetBackend, VIR_DOMAIN_NET_BACKEND_TYPE_LAST,
               "default",
@@ -966,6 +967,12 @@ virDomainActualNetDefFree(virDomainActualNetDefPtr def)
         VIR_FREE(def->data.direct.linkdev);
         VIR_FREE(def->data.direct.virtPortProfile);
         break;
+    case VIR_DOMAIN_NET_TYPE_HOSTDEV:
+        /* currently there is nothing in a virDomainHostdevDef
+         * that requires freeing.
+         */
+        VIR_FREE(def->data.hostdev.virtPortProfile);
+        break;
     default:
         break;
     }
@@ -1016,6 +1023,13 @@ void virDomainNetDefFree(virDomainNetDefPtr def)
         VIR_FREE(def->data.direct.virtPortProfile);
         break;
 
+    case VIR_DOMAIN_NET_TYPE_HOSTDEV:
+        /* currently there is nothing in a virDomainHostdevDef
+         * that requires freeing.
+         */
+        VIR_FREE(def->data.hostdev.virtPortProfile);
+        break;
+
     case VIR_DOMAIN_NET_TYPE_USER:
     case VIR_DOMAIN_NET_TYPE_LAST:
         break;
@@ -4018,7 +4032,9 @@ cleanup:
 static int
 virDomainActualNetDefParseXML(xmlNodePtr node,
                               xmlXPathContextPtr ctxt,
-                              virDomainActualNetDefPtr *def)
+                              virDomainNetDefPtr parent,
+                              virDomainActualNetDefPtr *def,
+                              unsigned int flags)
 {
     virDomainActualNetDefPtr actual = NULL;
     int ret = -1;
@@ -4026,6 +4042,7 @@ virDomainActualNetDefParseXML(xmlNodePtr node,
     xmlNodePtr bandwidth_node = NULL;
     char *type = NULL;
     char *mode = NULL;
+    char *addrtype = NULL;
 
     if (VIR_ALLOC(actual) < 0) {
         virReportOOMError();
@@ -4047,6 +4064,7 @@ virDomainActualNetDefParseXML(xmlNodePtr node,
     }
     if (actual->type != VIR_DOMAIN_NET_TYPE_BRIDGE &&
         actual->type != VIR_DOMAIN_NET_TYPE_DIRECT &&
+        actual->type != VIR_DOMAIN_NET_TYPE_HOSTDEV &&
         actual->type != VIR_DOMAIN_NET_TYPE_NETWORK) {
         virDomainReportError(VIR_ERR_INTERNAL_ERROR,
                              _("unsupported type '%s' in interface's <actual> element"),
@@ -4082,6 +4100,31 @@ virDomainActualNetDefParseXML(xmlNodePtr node,
             (!(actual->data.direct.virtPortProfile =
                virNetDevVPortProfileParse(virtPortNode))))
             goto error;
+    } else if (actual->type == VIR_DOMAIN_NET_TYPE_HOSTDEV) {
+        xmlNodePtr virtPortNode = virXPathNode("./virtualport", ctxt);
+        virDomainHostdevDefPtr hostdev = &actual->data.hostdev.def;
+
+        hostdev->parent.type = VIR_DOMAIN_DEVICE_NET;
+        hostdev->parent.data.net = parent;
+        hostdev->info = &parent->info;
+        /* The helper function expects type to already be found and
+         * passed in as a string, since it is in a different place in
+         * NetDef vs HostdevDef.
+         */
+        addrtype = virXPathString("string(./source/address/@type)", ctxt);
+        if ((!addrtype) && virXPathNode("./source/vendor", ctxt))
+           addrtype = strdup("usb"); /* source/vendor implies usb device */
+
+        if (virDomainHostdevPartsParse(node, ctxt, NULL, addrtype,
+                                       hostdev, flags) < 0) {
+            goto error;
+        }
+
+        if (virtPortNode &&
+            (!(actual->data.hostdev.virtPortProfile =
+               virNetDevVPortProfileParse(virtPortNode)))) {
+            goto error;
+        }
     }
 
     bandwidth_node = virXPathNode("./bandwidth", ctxt);
@@ -4095,6 +4138,7 @@ virDomainActualNetDefParseXML(xmlNodePtr node,
 error:
     VIR_FREE(type);
     VIR_FREE(mode);
+    VIR_FREE(addrtype);
     virDomainActualNetDefFree(actual);
 
     ctxt->node = save_ctxt;
@@ -4116,6 +4160,7 @@ virDomainNetDefParseXML(virCapsPtr caps,
                         unsigned int flags)
 {
     virDomainNetDefPtr def;
+    virDomainHostdevDefPtr hostdev;
     xmlNodePtr cur;
     char *macaddr = NULL;
     char *type = NULL;
@@ -4137,6 +4182,7 @@ virDomainNetDefParseXML(virCapsPtr caps,
     char *devaddr = NULL;
     char *mode = NULL;
     char *linkstate = NULL;
+    char *addrtype = NULL;
     virNWFilterHashTablePtr filterparams = NULL;
     virNetDevVPortProfilePtr virtPort = NULL;
     virDomainActualNetDefPtr actual = NULL;
@@ -4189,7 +4235,8 @@ virDomainNetDefParseXML(virCapsPtr caps,
             } else if ((virtPort == NULL) &&
                        ((def->type == VIR_DOMAIN_NET_TYPE_DIRECT) ||
                         (def->type == VIR_DOMAIN_NET_TYPE_NETWORK) ||
-                        (def->type == VIR_DOMAIN_NET_TYPE_BRIDGE)) &&
+                        (def->type == VIR_DOMAIN_NET_TYPE_BRIDGE) ||
+                        (def->type == VIR_DOMAIN_NET_TYPE_HOSTDEV)) &&
                        xmlStrEqual(cur->name, BAD_CAST "virtualport")) {
                 if (!(virtPort = virNetDevVPortProfileParse(cur)))
                     goto error;
@@ -4241,8 +4288,10 @@ virDomainNetDefParseXML(virCapsPtr caps,
                        (flags & VIR_DOMAIN_XML_INTERNAL_ACTUAL_NET) &&
                        (def->type == VIR_DOMAIN_NET_TYPE_NETWORK) &&
                        xmlStrEqual(cur->name, BAD_CAST "actual")) {
-                if (virDomainActualNetDefParseXML(cur, ctxt, &actual) < 0)
+                if (virDomainActualNetDefParseXML(cur, ctxt, def,
+                                                  &actual, flags) < 0) {
                     goto error;
+                }
             } else if (xmlStrEqual(cur->name, BAD_CAST "bandwidth")) {
                 if (!(def->bandwidth = virNetDevBandwidthParse(cur)))
                     goto error;
@@ -4397,6 +4446,27 @@ virDomainNetDefParseXML(virCapsPtr caps,
 
         break;
 
+    case VIR_DOMAIN_NET_TYPE_HOSTDEV:
+        hostdev = &def->data.hostdev.def;
+        hostdev->parent.type = VIR_DOMAIN_DEVICE_NET;
+        hostdev->parent.data.net = def;
+        hostdev->info = &def->info;
+        /* The helper function expects type to already be found and
+         * passed in as a string, since it is in a different place in
+         * NetDef vs HostdevDef.
+         */
+        addrtype = virXPathString("string(./source/address/@type)", ctxt);
+        if ((!addrtype) && virXPathNode("./source/vendor", ctxt))
+           addrtype = strdup("usb"); /* source/vendor implies usb device */
+
+        if (virDomainHostdevPartsParse(node, ctxt, NULL, addrtype,
+                                       hostdev, flags) < 0) {
+            goto error;
+        }
+        def->data.hostdev.virtPortProfile = virtPort;
+        virtPort = NULL;
+        break;
+
     case VIR_DOMAIN_NET_TYPE_USER:
     case VIR_DOMAIN_NET_TYPE_LAST:
         break;
@@ -4532,6 +4602,7 @@ cleanup:
     VIR_FREE(devaddr);
     VIR_FREE(mode);
     VIR_FREE(linkstate);
+    VIR_FREE(addrtype);
     virNWFilterHashTableFree(filterparams);
 
     return def;
@@ -10525,7 +10596,8 @@ virDomainHostdevSourceFormat(virBufferPtr buf,
 
 static int
 virDomainActualNetDefFormat(virBufferPtr buf,
-                            virDomainActualNetDefPtr def)
+                            virDomainActualNetDefPtr def,
+                            unsigned int flags)
 {
     int ret = -1;
     const char *type;
@@ -10541,14 +10613,12 @@ virDomainActualNetDefFormat(virBufferPtr buf,
         return ret;
     }
 
-    if (def->type != VIR_DOMAIN_NET_TYPE_BRIDGE &&
-        def->type != VIR_DOMAIN_NET_TYPE_DIRECT &&
-        def->type != VIR_DOMAIN_NET_TYPE_NETWORK) {
-        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
-                             _("unexpected net type %s"), type);
-        goto error;
+    virBufferAsprintf(buf, "      <actual type='%s'", type);
+    if ((def->type == VIR_DOMAIN_NET_TYPE_HOSTDEV) &&
+        def->data.hostdev.def.managed) {
+        virBufferAddLit(buf, " managed='yes'");
     }
-    virBufferAsprintf(buf, "      <actual type='%s'>\n", type);
+    virBufferAddLit(buf, ">\n");
 
     switch (def->type) {
     case VIR_DOMAIN_NET_TYPE_BRIDGE:
@@ -10581,8 +10651,31 @@ virDomainActualNetDefFormat(virBufferPtr buf,
             goto error;
         virBufferAdjustIndent(buf, -8);
         break;
-    default:
+
+    case VIR_DOMAIN_NET_TYPE_HOSTDEV:
+        virBufferAdjustIndent(buf, 8);
+        if (virDomainHostdevSourceFormat(buf, &def->data.hostdev.def,
+                                         flags, true) < 0) {
+            return -1;
+        }
+        if (virNetDevVPortProfileFormat(def->data.hostdev.virtPortProfile,
+                                        buf) < 0) {
+            return -1;
+        }
+        virBufferAdjustIndent(buf, -8);
+        break;
+
+
+        if (virNetDevVPortProfileFormat(def->data.hostdev.virtPortProfile, buf) < 0)
+            goto error;
+        virBufferAdjustIndent(buf, -8);
+        break;
+    case VIR_DOMAIN_NET_TYPE_NETWORK:
         break;
+    default:
+        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+                             _("unexpected net type %s"), type);
+        goto error;
     }
 
     virBufferAdjustIndent(buf, 8);
@@ -10610,7 +10703,12 @@ virDomainNetDefFormat(virBufferPtr buf,
         return -1;
     }
 
-    virBufferAsprintf(buf, "    <interface type='%s'>\n", type);
+    virBufferAsprintf(buf, "    <interface type='%s'", type);
+    if ((def->type == VIR_DOMAIN_NET_TYPE_HOSTDEV) &&
+        def->data.hostdev.def.managed) {
+        virBufferAddLit(buf, " managed='yes'");
+    }
+    virBufferAddLit(buf, ">\n");
 
     virBufferAsprintf(buf,
                       "      <mac address='%02x:%02x:%02x:%02x:%02x:%02x'/>\n",
@@ -10629,7 +10727,7 @@ virDomainNetDefFormat(virBufferPtr buf,
             return -1;
         virBufferAdjustIndent(buf, -6);
         if ((flags & VIR_DOMAIN_XML_INTERNAL_ACTUAL_NET) &&
-            (virDomainActualNetDefFormat(buf, def->data.network.actual) < 0))
+            (virDomainActualNetDefFormat(buf, def->data.network.actual, flags) < 0))
             return -1;
         break;
 
@@ -10683,6 +10781,19 @@ virDomainNetDefFormat(virBufferPtr buf,
         virBufferAdjustIndent(buf, -6);
         break;
 
+    case VIR_DOMAIN_NET_TYPE_HOSTDEV:
+        virBufferAdjustIndent(buf, 6);
+        if (virDomainHostdevSourceFormat(buf, &def->data.hostdev.def,
+                                         flags, true) < 0) {
+            return -1;
+        }
+        if (virNetDevVPortProfileFormat(def->data.hostdev.virtPortProfile,
+                                        buf) < 0) {
+            return -1;
+        }
+        virBufferAdjustIndent(buf, -6);
+        break;
+
     case VIR_DOMAIN_NET_TYPE_USER:
     case VIR_DOMAIN_NET_TYPE_LAST:
         break;
@@ -13936,6 +14047,19 @@ virDomainNetGetActualDirectMode(virDomainNetDefPtr iface)
     return iface->data.network.actual->data.direct.mode;
 }
 
+virDomainHostdevDefPtr
+virDomainNetGetActualHostdev(virDomainNetDefPtr iface)
+{
+    if (iface->type == VIR_DOMAIN_NET_TYPE_HOSTDEV)
+        return &iface->data.hostdev.def;
+    else if ((iface->type == VIR_DOMAIN_NET_TYPE_NETWORK) &&
+             (iface->data.network.actual->type
+              == VIR_DOMAIN_NET_TYPE_HOSTDEV)) {
+        return &iface->data.network.actual->data.hostdev.def;
+    }
+    return NULL;
+}
+
 virNetDevVPortProfilePtr
 virDomainNetGetActualVirtPortProfile(virDomainNetDefPtr iface)
 {
@@ -13944,6 +14068,8 @@ virDomainNetGetActualVirtPortProfile(virDomainNetDefPtr iface)
         return iface->data.direct.virtPortProfile;
     case VIR_DOMAIN_NET_TYPE_BRIDGE:
         return iface->data.bridge.virtPortProfile;
+    case VIR_DOMAIN_NET_TYPE_HOSTDEV:
+        return iface->data.hostdev.virtPortProfile;
     case VIR_DOMAIN_NET_TYPE_NETWORK:
         if (!iface->data.network.actual)
             return NULL;
@@ -13952,6 +14078,8 @@ virDomainNetGetActualVirtPortProfile(virDomainNetDefPtr iface)
             return iface->data.network.actual->data.direct.virtPortProfile;
         case VIR_DOMAIN_NET_TYPE_BRIDGE:
             return iface->data.network.actual->data.bridge.virtPortProfile;
+        case VIR_DOMAIN_NET_TYPE_HOSTDEV:
+            return iface->data.network.actual->data.hostdev.virtPortProfile;
         default:
             return NULL;
         }
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 924c7ec..42c9517 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -681,6 +681,7 @@ enum virDomainNetType {
     VIR_DOMAIN_NET_TYPE_BRIDGE,
     VIR_DOMAIN_NET_TYPE_INTERNAL,
     VIR_DOMAIN_NET_TYPE_DIRECT,
+    VIR_DOMAIN_NET_TYPE_HOSTDEV,
 
     VIR_DOMAIN_NET_TYPE_LAST,
 };
@@ -731,6 +732,10 @@ struct _virDomainActualNetDef {
             int mode; /* enum virMacvtapMode from util/macvtap.h */
             virNetDevVPortProfilePtr virtPortProfile;
         } direct;
+        struct {
+            virDomainHostdevDef def;
+            virNetDevVPortProfilePtr virtPortProfile;
+        } hostdev;
     } data;
     virNetDevBandwidthPtr bandwidth;
 };
@@ -786,6 +791,10 @@ struct _virDomainNetDef {
             int mode; /* enum virMacvtapMode from util/macvtap.h */
             virNetDevVPortProfilePtr virtPortProfile;
         } direct;
+        struct {
+            virDomainHostdevDef def;
+            virNetDevVPortProfilePtr virtPortProfile;
+        } hostdev;
     } data;
     struct {
         bool sndbuf_specified;
@@ -1921,6 +1930,7 @@ int virDomainNetGetActualType(virDomainNetDefPtr iface);
 const char *virDomainNetGetActualBridgeName(virDomainNetDefPtr iface);
 const char *virDomainNetGetActualDirectDev(virDomainNetDefPtr iface);
 int virDomainNetGetActualDirectMode(virDomainNetDefPtr iface);
+virDomainHostdevDefPtr virDomainNetGetActualHostdev(virDomainNetDefPtr iface);
 virNetDevVPortProfilePtr
 virDomainNetGetActualVirtPortProfile(virDomainNetDefPtr iface);
 virNetDevBandwidthPtr
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index dc55f7b..00b085c 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -379,6 +379,7 @@ virDomainNetGetActualBandwidth;
 virDomainNetGetActualBridgeName;
 virDomainNetGetActualDirectDev;
 virDomainNetGetActualDirectMode;
+virDomainNetGetActualHostdev;
 virDomainNetGetActualType;
 virDomainNetGetActualVirtPortProfile;
 virDomainNetIndexByMac;
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index dffb6d4..a5a0054 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -2606,6 +2606,7 @@ qemuBuildHostNetStr(virDomainNetDefPtr net,
         case VIR_DOMAIN_NET_TYPE_BRIDGE:
         case VIR_DOMAIN_NET_TYPE_INTERNAL:
         case VIR_DOMAIN_NET_TYPE_DIRECT:
+        case VIR_DOMAIN_NET_TYPE_HOSTDEV:
         case VIR_DOMAIN_NET_TYPE_LAST:
             break;
         }
diff --git a/src/uml/uml_conf.c b/src/uml/uml_conf.c
index dbbbfda..0e281ff 100644
--- a/src/uml/uml_conf.c
+++ b/src/uml/uml_conf.c
@@ -257,6 +257,11 @@ umlBuildCommandLineNet(virConnectPtr conn,
                        _("direct networking type not supported"));
         goto error;
 
+    case VIR_DOMAIN_NET_TYPE_HOSTDEV:
+        umlReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("hostdev networking type not supported"));
+        goto error;
+
     case VIR_DOMAIN_NET_TYPE_LAST:
         break;
     }
diff --git a/src/xenxs/xen_sxpr.c b/src/xenxs/xen_sxpr.c
index 81fc0af..b0e1b36 100644
--- a/src/xenxs/xen_sxpr.c
+++ b/src/xenxs/xen_sxpr.c
@@ -1955,6 +1955,7 @@ xenFormatSxprNet(virConnectPtr conn,
     case VIR_DOMAIN_NET_TYPE_MCAST:
     case VIR_DOMAIN_NET_TYPE_INTERNAL:
     case VIR_DOMAIN_NET_TYPE_DIRECT:
+    case VIR_DOMAIN_NET_TYPE_HOSTDEV:
     case VIR_DOMAIN_NET_TYPE_LAST:
         break;
     }
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-net-hostdev.xml b/tests/qemuxml2argvdata/qemuxml2argv-net-hostdev.xml
new file mode 100644
index 0000000..73cb1d9
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-net-hostdev.xml
@@ -0,0 +1,48 @@
+<domain type='qemu'>
+  <name>QEMUGuest1</name>
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+  <memory>219136</memory>
+  <currentMemory>219136</currentMemory>
+  <vcpu>1</vcpu>
+  <os>
+    <type arch='i686' machine='pc'>hvm</type>
+    <boot dev='hd'/>
+  </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>
+    <disk type='block' device='disk'>
+      <source dev='/dev/HostVG/QEMUGuest1'/>
+      <target dev='hda' bus='ide'/>
+      <address type='drive' controller='0' bus='0' unit='0'/>
+    </disk>
+    <controller type='usb' index='0'/>
+    <controller type='ide' index='0'/>
+    <interface type='hostdev' managed='yes'>
+      <mac address='00:11:22:33:44:55'/>
+      <source>
+        <address type='pci' domain='0x0002' bus='0x03' slot='0x07' function='0x1'/>
+      </source>
+      <virtualport type='802.1Qbg'>
+        <parameters managerid='11' typeid='1193047' typeidversion='2' instanceid='09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f'/>
+      </virtualport>
+    </interface>
+    <interface type='hostdev'>
+      <mac address='11:11:22:33:44:55'/>
+      <source>
+        <address type='usb' bus='0' device='2'/>
+      </source>
+    </interface>
+    <interface type='hostdev'>
+      <mac address='22:11:22:33:44:55'/>
+      <source>
+        <vendor id='0x0012'/>
+        <product id='0x24dd'/>
+      </source>
+    </interface>
+    <memballoon model='virtio'/>
+  </devices>
+</domain>
diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c
index c1b2b14..9869c79 100644
--- a/tests/qemuxml2xmltest.c
+++ b/tests/qemuxml2xmltest.c
@@ -170,6 +170,7 @@ mymain(void)
     DO_TEST("net-eth");
     DO_TEST("net-eth-ifname");
     DO_TEST("net-virtio-network-portgroup");
+    DO_TEST("net-hostdev");
     DO_TEST("sound");
     DO_TEST("net-bandwidth");
 
-- 
1.7.7.6




More information about the libvir-list mailing list