[libvirt] [PATCH] Add XML config switch to enable/disable vhost-net support

Laine Stump laine at laine.org
Thu Jan 13 06:45:28 UTC 2011


This patch is in response to

  https://bugzilla.redhat.com/show_bug.cgi?id=643050

The existing libvirt support for the vhost-net backend to the virtio
network driver happens automatically - if the vhost-net device is
available, it is always enabled, otherwise the standard userland
virtio backend is used.

This patch makes it possible to force whether or not vhost-net is used
with a bit of XML. Adding a <driver> element to the interface XML, eg:

     <interface type="network">
       <model type="virtio"/>
       <driver name="vhost"/>

will force use of vhost-net (if it's not available, the domain will
fail to start). if driver name="qemu", vhost-net will not be used even
if it is available.

If there is no <driver name='xxx'/> in the config, libvirt will revert
to the pre-existing automatic behavior - use vhost-net if it's
available, and userland backend if vhost-net isn't available.
---

Note that I don't really like the "name='vhost|qemu'" nomenclature,
but am including it here just to get the patches on the list. I could
live with it this way, or with any of the following (anyone have a
strong opinion?) (note that in all cases, nothing specified means "try
to use vhost, but fallback to userland if necessary")

   vhost='on|off'
   vhost='required|disabled'
   mode='vhost|qemu'
   mode='kernel|user'
   backend='kernel|user'

(So far the strongest opinion has been for the current "name='vhost|qemu'")

Oh, and also - sorry Eric, but I didn't have the brain cells left
tonight to add this new bit to the documentation, and I really want to
get the patch up/in now, so that will have to wait for a followup next
week :-)

 docs/schemas/domain.rng |   13 ++++++++
 src/conf/domain_conf.c  |   27 +++++++++++++++++-
 src/conf/domain_conf.h  |   10 ++++++
 src/qemu/qemu_command.c |   71 +++++++++++++++++++++++++++++++++++++++--------
 src/qemu/qemu_command.h |    3 --
 5 files changed, 108 insertions(+), 16 deletions(-)

diff --git a/docs/schemas/domain.rng b/docs/schemas/domain.rng
index a524e4b..6d0654d 100644
--- a/docs/schemas/domain.rng
+++ b/docs/schemas/domain.rng
@@ -1005,6 +1005,19 @@
         </element>
       </optional>
       <optional>
+        <element name="driver">
+          <optional>
+            <attribute name="name">
+              <choice>
+                <value>qemu</value>
+                <value>vhost</value>
+              </choice>
+            </attribute>
+          </optional>
+          <empty/>
+        </element>
+      </optional>
+      <optional>
         <ref name="address"/>
       </optional>
       <optional>
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index b4df38c..04ed502 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -184,6 +184,10 @@ VIR_ENUM_IMPL(virDomainNet, VIR_DOMAIN_NET_TYPE_LAST,
               "internal",
               "direct")
 
+VIR_ENUM_IMPL(virDomainNetBackend, VIR_DOMAIN_NET_BACKEND_TYPE_LAST,
+              "qemu",
+              "vhost")
+
 VIR_ENUM_IMPL(virDomainChrChannelTarget,
               VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_LAST,
               "guestfwd",
@@ -2289,6 +2293,7 @@ virDomainNetDefParseXML(virCapsPtr caps,
     char *address = NULL;
     char *port = NULL;
     char *model = NULL;
+    char *backend = NULL;
     char *filter = NULL;
     char *internal = NULL;
     char *devaddr = NULL;
@@ -2371,6 +2376,8 @@ virDomainNetDefParseXML(virCapsPtr caps,
                 script = virXMLPropString(cur, "path");
             } else if (xmlStrEqual (cur->name, BAD_CAST "model")) {
                 model = virXMLPropString(cur, "type");
+            } else if (xmlStrEqual (cur->name, BAD_CAST "driver")) {
+                backend = virXMLPropString(cur, "name");
             } else if (xmlStrEqual (cur->name, BAD_CAST "filterref")) {
                 filter = virXMLPropString(cur, "filter");
                 VIR_FREE(filterparams);
@@ -2558,6 +2565,18 @@ virDomainNetDefParseXML(virCapsPtr caps,
         model = NULL;
     }
 
+    if ((backend != NULL) &&
+        (def->model && STREQ(def->model, "virtio"))) {
+        int b;
+        if ((b = virDomainNetBackendTypeFromString(backend)) < 0) {
+            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+                                 _("Unkown interface <driver name='%s'> has been specified"),
+                                 backend);
+            goto error;
+        }
+        def->backend = b;
+        def->backend_specified = 1;
+    }
     if (filter != NULL) {
         switch (def->type) {
         case VIR_DOMAIN_NET_TYPE_ETHERNET:
@@ -2584,6 +2603,7 @@ cleanup:
     VIR_FREE(script);
     VIR_FREE(bridge);
     VIR_FREE(model);
+    VIR_FREE(backend);
     VIR_FREE(filter);
     VIR_FREE(type);
     VIR_FREE(internal);
@@ -6275,9 +6295,14 @@ virDomainNetDefFormat(virBufferPtr buf,
     if (def->ifname)
         virBufferEscapeString(buf, "      <target dev='%s'/>\n",
                               def->ifname);
-    if (def->model)
+    if (def->model) {
         virBufferEscapeString(buf, "      <model type='%s'/>\n",
                               def->model);
+        if (STREQ(def->model, "virtio") && def->backend_specified) {
+            virBufferVSprintf(buf, "      <driver name='%s'/>\n",
+                              virDomainNetBackendTypeToString(def->backend));
+        }
+    }
     if (def->filter) {
         virBufferEscapeString(buf, "      <filterref filter='%s'",
                               def->filter);
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index a459a22..451ccad 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -292,6 +292,13 @@ enum virDomainNetType {
     VIR_DOMAIN_NET_TYPE_LAST,
 };
 
+/* the backend driver used for virtio interfaces */
+enum virDomainNetBackendType {
+    VIR_DOMAIN_NET_BACKEND_TYPE_QEMU,         /* userland */
+    VIR_DOMAIN_NET_BACKEND_TYPE_VHOST,        /* kernel */
+
+    VIR_DOMAIN_NET_BACKEND_TYPE_LAST,
+};
 
 /* the mode type for macvtap devices */
 enum virDomainNetdevMacvtapType {
@@ -310,6 +317,8 @@ struct _virDomainNetDef {
     enum virDomainNetType type;
     unsigned char mac[VIR_MAC_BUFLEN];
     char *model;
+    enum virDomainNetBackendType backend;
+    int backend_specified : 1;
     union {
         struct {
             char *dev;
@@ -1264,6 +1273,7 @@ VIR_ENUM_DECL(virDomainControllerModel)
 VIR_ENUM_DECL(virDomainFS)
 VIR_ENUM_DECL(virDomainFSAccessMode)
 VIR_ENUM_DECL(virDomainNet)
+VIR_ENUM_DECL(virDomainNetBackend)
 VIR_ENUM_DECL(virDomainChrDevice)
 VIR_ENUM_DECL(virDomainChrChannelTarget)
 VIR_ENUM_DECL(virDomainChrConsoleTarget)
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 86c5bb5..9eb54a1 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -302,24 +302,61 @@ cleanup:
 }
 
 
-int
+static int
 qemuOpenVhostNet(virDomainNetDefPtr net,
-                 unsigned long long qemuCmdFlags)
+                 unsigned long long qemuCmdFlags,
+                 int *vhostfd)
 {
 
-    /* If qemu supports vhost-net mode (including the -netdev command
-     * option), the nic model is virtio, and we can open
-     * /dev/vhost_net, assume that vhost-net mode is available and
-     * return the fd to /dev/vhost_net. Otherwise, return -1.
-     */
+    *vhostfd = -1;   /* assume we won't use vhost */
 
+    /* If the config says explicitly to not use vhost, return now */
+    if (net->backend_specified &&
+        (net->backend == VIR_DOMAIN_NET_BACKEND_TYPE_QEMU)) {
+       return 0;
+    }
+
+    /* If qemu doesn't support vhost-net mode (including the -netdev command
+     * option), don't try to open the device.
+     */
     if (!(qemuCmdFlags & QEMUD_CMD_FLAG_VNET_HOST &&
           qemuCmdFlags & QEMUD_CMD_FLAG_NETDEV &&
-          qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE &&
-          net->model && STREQ(net->model, "virtio")))
-        return -1;
+          qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
+        if (net->backend_specified &&
+            (net->backend == VIR_DOMAIN_NET_BACKEND_TYPE_VHOST)) {
+            qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                            "%s", _("vhost-net is not supported with "
+                                    "this QEMU binary"));
+            return -1;
+        }
+        return 0;
+    }
 
-    return open("/dev/vhost-net", O_RDWR, 0);
+    /* If the nic model isn't virtio, don't try to open. */
+    if (!(net->model && STREQ(net->model, "virtio"))) {
+        if (net->backend_specified &&
+            (net->backend == VIR_DOMAIN_NET_BACKEND_TYPE_VHOST)) {
+            qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                            "%s", _("vhost-net is only supported for "
+                                    "virtio network interfaces"));
+            return -1;
+        }
+        return 0;
+    }
+
+    *vhostfd = open("/dev/vhost-net", O_RDWR, 0);
+
+    /* If the config says explicitly to use vhost and we couldn't open it,
+     * report an error.
+     */
+    if ((*vhostfd < 0) && net->backend_specified &&
+        (net->backend == VIR_DOMAIN_NET_BACKEND_TYPE_VHOST)) {
+        qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                        "%s", _("vhost-net was requested for an interface, "
+                                "but is unavailable"));
+        return -1;
+    }
+    return 0;
 }
 
 
@@ -3278,7 +3315,10 @@ qemuBuildCommandLine(virConnectPtr conn,
                 net->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
                 /* Attempt to use vhost-net mode for these types of
                    network device */
-                int vhostfd = qemuOpenVhostNet(net, qemuCmdFlags);
+                int vhostfd;
+
+                if (qemuOpenVhostNet(net, qemuCmdFlags, &vhostfd) < 0)
+                    goto error;
                 if (vhostfd >= 0) {
                     virCommandTransferFD(cmd, vhostfd);
 
@@ -4618,6 +4658,13 @@ qemuParseCommandLineNet(virCapsPtr caps,
         } else if (STREQ(keywords[i], "model")) {
             def->model = values[i];
             values[i] = NULL;
+        } else if (STREQ(keywords[i], "vhost")) {
+            if ((values[i] == NULL) || STREQ(values[i], "on")) {
+                def->backend = VIR_DOMAIN_NET_BACKEND_TYPE_VHOST;
+            } else if (STREQ(keywords[i], "off")) {
+                def->backend = VIR_DOMAIN_NET_BACKEND_TYPE_QEMU;
+            }
+            def->backend_specified = 1;
         }
     }
 
diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h
index 4c42a10..5439184 100644
--- a/src/qemu/qemu_command.h
+++ b/src/qemu/qemu_command.h
@@ -116,9 +116,6 @@ int qemuNetworkIfaceConnect(virConnectPtr conn,
                             unsigned long long qemCmdFlags)
     ATTRIBUTE_NONNULL(1);
 
-int qemuOpenVhostNet(virDomainNetDefPtr net,
-                     unsigned long long qemuCmdFlags);
-
 int qemuPhysIfaceConnect(virConnectPtr conn,
                          struct qemud_driver *driver,
                          virDomainNetDefPtr net,
-- 
1.7.3.4




More information about the libvir-list mailing list