[libvirt] [RFC PATCH] Add Qemu Network Helper

rmarwah at linux.vnet.ibm.com rmarwah at linux.vnet.ibm.com
Thu May 10 15:15:17 UTC 2012


From: Richa Marwaha <rmarwah at linux.vnet.ibm.com>

QEMU has a new feature which allows QEMU to execute under an unprivileged user ID and still be able to add a tap device to a Linux network bridge. Below is
the link to the QEMU patches for the bridge helper feature:

http://lists.gnu.org/archive/html/qemu-devel/2012-01/msg03562.html

The existing libvirt tap network device support for adding a tap device to a bridge (-netdev tap) works only when connected to a libvirtd instance running
as the privileged system account 'root'.  When connected to a libvirtd instance running as an unprivileged user (ie. using the session URI) creation of
the tap device fails as follows:

error: Failed to start domain F14_64 error: Unable to create tap device vnet%d: Operation not permitted

With this support, creating a tap device in the above scenario will be possible.  Additionally, hot attaching a tap device to a bridge while running when
connected to a libvirtd instance running as an unprivileged user will be possible.

Signed-off-by: Richa Marwaha <rmarwah at linux.vnet.ibm.com>
Signed-off-by: Corey Bryant<coreyb at linux.vnet.ibm.com>
---
 src/qemu/qemu_command.c |   38 +++++++++++++++++++++++++-------------
 src/qemu/qemu_command.h |    1 +
 src/qemu/qemu_hotplug.c |   19 +++++++++++--------
 3 files changed, 37 insertions(+), 21 deletions(-)

diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 117542f..daa5381 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -2745,6 +2745,7 @@ error:
 
 char *
 qemuBuildHostNetStr(virDomainNetDefPtr net,
+                    struct qemud_driver *driver,
                     char type_sep,
                     int vlan,
                     const char *tapfd,
@@ -2753,6 +2754,7 @@ qemuBuildHostNetStr(virDomainNetDefPtr net,
     bool is_tap = false;
     virBuffer buf = VIR_BUFFER_INITIALIZER;
     enum virDomainNetType netType = virDomainNetGetActualType(net);
+    const char *brname = NULL;
 
     if (net->script && netType != VIR_DOMAIN_NET_TYPE_ETHERNET) {
         qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
@@ -2762,8 +2764,15 @@ qemuBuildHostNetStr(virDomainNetDefPtr net,
     }
 
     switch (netType) {
-    case VIR_DOMAIN_NET_TYPE_NETWORK:
     case VIR_DOMAIN_NET_TYPE_BRIDGE:
+        if (!driver->privileged) {
+            brname = virDomainNetGetActualBridgeName(net);
+            virBufferAsprintf(&buf, "bridge%cbr=%s", type_sep, brname);
+            type_sep = ',';
+            is_tap = true;
+            break;
+        }
+    case VIR_DOMAIN_NET_TYPE_NETWORK:
     case VIR_DOMAIN_NET_TYPE_DIRECT:
         virBufferAsprintf(&buf, "tap%cfd=%s", type_sep, tapfd);
         type_sep = ',';
@@ -4865,7 +4874,7 @@ qemuBuildCommandLine(virConnectPtr conn,
         for (i = 0 ; i < def->nnets ; i++) {
             virDomainNetDefPtr net = def->nets[i];
             char *nic, *host;
-            char tapfd_name[50];
+            char tapfd_name[50] = "";
             char vhostfd_name[50] = "";
             int vlan;
             int bootindex = bootNet;
@@ -4902,17 +4911,20 @@ qemuBuildCommandLine(virConnectPtr conn,
 
             if (actualType == VIR_DOMAIN_NET_TYPE_NETWORK ||
                 actualType == VIR_DOMAIN_NET_TYPE_BRIDGE) {
-                int tapfd = qemuNetworkIfaceConnect(def, conn, driver, net,
-                                                    qemuCaps);
-                if (tapfd < 0)
-                    goto error;
+                if (actualType == VIR_DOMAIN_NET_TYPE_NETWORK ||
+                    driver->privileged) {
+                    int tapfd = qemuNetworkIfaceConnect(def, conn, driver, net,
+                                                        qemuCaps);
+                    if (tapfd < 0)
+                        goto error;
 
-                last_good_net = i;
-                virCommandTransferFD(cmd, tapfd);
+                    last_good_net = i;
+                    virCommandTransferFD(cmd, tapfd);
 
-                if (snprintf(tapfd_name, sizeof(tapfd_name), "%d",
-                             tapfd) >= sizeof(tapfd_name))
-                    goto no_memory;
+                    if (snprintf(tapfd_name, sizeof(tapfd_name), "%d",
+                                 tapfd) >= sizeof(tapfd_name))
+                        goto no_memory;
+                }
             } else if (actualType == VIR_DOMAIN_NET_TYPE_DIRECT) {
                 int tapfd = qemuPhysIfaceConnect(def, driver, net,
                                                  qemuCaps, vmop);
@@ -4955,7 +4967,7 @@ qemuBuildCommandLine(virConnectPtr conn,
             if (qemuCapsGet(qemuCaps, QEMU_CAPS_NETDEV) &&
                 qemuCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) {
                 virCommandAddArg(cmd, "-netdev");
-                if (!(host = qemuBuildHostNetStr(net, ',', vlan,
+                if (!(host = qemuBuildHostNetStr(net, driver, ',', vlan,
                                                  tapfd_name, vhostfd_name)))
                     goto error;
                 virCommandAddArg(cmd, host);
@@ -4978,7 +4990,7 @@ qemuBuildCommandLine(virConnectPtr conn,
             if (!(qemuCapsGet(qemuCaps, QEMU_CAPS_NETDEV) &&
                   qemuCapsGet(qemuCaps, QEMU_CAPS_DEVICE))) {
                 virCommandAddArg(cmd, "-net");
-                if (!(host = qemuBuildHostNetStr(net, ',', vlan,
+                if (!(host = qemuBuildHostNetStr(net, driver, ',', vlan,
                                                  tapfd_name, vhostfd_name)))
                     goto error;
                 virCommandAddArg(cmd, host);
diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h
index 1eafeb3..04240bc 100644
--- a/src/qemu/qemu_command.h
+++ b/src/qemu/qemu_command.h
@@ -62,6 +62,7 @@ qemuBuildChrDeviceStr (virDomainChrDefPtr serial,
 
 /* With vlan == -1, use netdev syntax, else old hostnet */
 char * qemuBuildHostNetStr(virDomainNetDefPtr net,
+                           struct qemud_driver *driver,
                            char type_sep,
                            int vlan,
                            const char *tapfd,
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index ad31eba..7f8b1e4 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -699,12 +699,15 @@ int qemuDomainAttachNetDevice(virConnectPtr conn,
 
     if (actualType == VIR_DOMAIN_NET_TYPE_BRIDGE ||
         actualType == VIR_DOMAIN_NET_TYPE_NETWORK) {
-        if ((tapfd = qemuNetworkIfaceConnect(vm->def, conn, driver, net,
-                                             priv->qemuCaps)) < 0)
-            goto cleanup;
-        iface_connected = true;
-        if (qemuOpenVhostNet(vm->def, net, priv->qemuCaps, &vhostfd) < 0)
-            goto cleanup;
+        if (actualType == VIR_DOMAIN_NET_TYPE_NETWORK ||
+            driver->privileged) {
+            if ((tapfd = qemuNetworkIfaceConnect(vm->def, conn, driver, net,
+                                                 priv->qemuCaps)) < 0)
+                goto cleanup;
+            iface_connected = true;
+            if (qemuOpenVhostNet(vm->def, net, priv->qemuCaps, &vhostfd) < 0)
+                goto cleanup;
+        }
     } else if (actualType == VIR_DOMAIN_NET_TYPE_DIRECT) {
         if ((tapfd = qemuPhysIfaceConnect(vm->def, driver, net,
                                           priv->qemuCaps,
@@ -752,11 +755,11 @@ int qemuDomainAttachNetDevice(virConnectPtr conn,
 
     if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_NETDEV) &&
         qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) {
-        if (!(netstr = qemuBuildHostNetStr(net, ',',
+        if (!(netstr = qemuBuildHostNetStr(net, driver, ',',
                                            -1, tapfd_name, vhostfd_name)))
             goto cleanup;
     } else {
-        if (!(netstr = qemuBuildHostNetStr(net, ' ',
+        if (!(netstr = qemuBuildHostNetStr(net, driver, ' ',
                                            vlan, tapfd_name, vhostfd_name)))
             goto cleanup;
     }
-- 
1.7.1




More information about the libvir-list mailing list