[libvirt] [PATCH v2 06/12] util: Learn virNetDevTapCreate multiqueue network

Michal Privoznik mprivozn at redhat.com
Mon May 13 17:23:03 UTC 2013


Currently, the function knows how to open a TAP device for a single
time. However, in case of multiqueue network we need to open it multiple
times. Moreover, when doing TUNSETIFF ioctl, the IFF_MULTI_QUEUE flag
shall be requested. This commit changes a behaviour slightly as well.
Till now it was possible to pass NULL as an @fd address by which caller
didn't care about returned FD. While this was used only in UML driver,
the appropriate UML code snippets has been changed as well.
---
 src/network/bridge_driver.c |   2 +-
 src/qemu/qemu_command.c     |   2 +-
 src/uml/uml_conf.c          |   5 +-
 src/util/virnetdevtap.c     | 115 ++++++++++++++++++++++++--------------------
 src/util/virnetdevtap.h     |   2 +
 5 files changed, 72 insertions(+), 54 deletions(-)

diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
index 99c1316..f81e925 100644
--- a/src/network/bridge_driver.c
+++ b/src/network/bridge_driver.c
@@ -2444,7 +2444,7 @@ networkStartNetworkVirtual(struct network_driver *driver,
         /* Keep tun fd open and interface up to allow for IPv6 DAD to happen */
         if (virNetDevTapCreateInBridgePort(network->def->bridge,
                                            &macTapIfName, &network->def->mac,
-                                           NULL, &tapfd, NULL, NULL,
+                                           NULL, &tapfd, 1, NULL, NULL,
                                            VIR_NETDEV_TAP_CREATE_USE_MAC_FOR_BRIDGE |
                                            VIR_NETDEV_TAP_CREATE_IFUP |
                                            VIR_NETDEV_TAP_CREATE_PERSIST) < 0) {
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index ec061d1..e4bb2b7 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -355,7 +355,7 @@ qemuNetworkIfaceConnect(virDomainDefPtr def,
 
     if (cfg->privileged)
         err = virNetDevTapCreateInBridgePort(brname, &net->ifname, &net->mac,
-                                             def->uuid, &tapfd,
+                                             def->uuid, &tapfd, 1,
                                              virDomainNetGetActualVirtPortProfile(net),
                                              virDomainNetGetActualVlan(net),
                                              tap_create_flags);
diff --git a/src/uml/uml_conf.c b/src/uml/uml_conf.c
index 52b705c..3fda7e4 100644
--- a/src/uml/uml_conf.c
+++ b/src/uml/uml_conf.c
@@ -109,6 +109,7 @@ umlConnectTapDevice(virConnectPtr conn,
                     const char *bridge)
 {
     bool template_ifname = false;
+    int tapfd;
 
     if (!net->ifname ||
         STRPREFIX(net->ifname, VIR_NET_GENERATED_PREFIX) ||
@@ -121,7 +122,7 @@ umlConnectTapDevice(virConnectPtr conn,
     }
 
     if (virNetDevTapCreateInBridgePort(bridge, &net->ifname, &net->mac,
-                                       vm->uuid, NULL,
+                                       vm->uuid, &tapfd, 1,
                                        virDomainNetGetActualVirtPortProfile(net),
                                        virDomainNetGetActualVlan(net),
                                        VIR_NETDEV_TAP_CREATE_IFUP |
@@ -139,9 +140,11 @@ umlConnectTapDevice(virConnectPtr conn,
         }
     }
 
+    VIR_FORCE_CLOSE(tapfd);
     return 0;
 
 error:
+    VIR_FORCE_CLOSE(tapfd);
     return -1;
 }
 
diff --git a/src/util/virnetdevtap.c b/src/util/virnetdevtap.c
index 75599db..ee839e3 100644
--- a/src/util/virnetdevtap.c
+++ b/src/util/virnetdevtap.c
@@ -140,7 +140,8 @@ virNetDevProbeVnetHdr(int tapfd)
 /**
  * virNetDevTapCreate:
  * @ifname: the interface name
- * @tapfd: file descriptor return value for the new tap device
+ * @tapfds: file descriptor return value for the new tap device
+ * @tapfdSize: size of @tapfd
  * @flags: OR of virNetDevTapCreateFlags. Only one flag is recognized:
  *
  *   VIR_NETDEV_TAP_CREATE_VNET_HDR
@@ -148,76 +149,85 @@ virNetDevProbeVnetHdr(int tapfd)
  *   VIR_NETDEV_TAP_CREATE_PERSIST
  *     - The device will persist after the file descriptor is closed
  *
- * Creates a tap interface.
- * If the @tapfd parameter is supplied, the open tap device file descriptor
- * will be returned, otherwise the TAP device will be closed. The caller must
- * use virNetDevTapDelete to remove a persistent TAP device when it is no
- * longer needed.
+ * Creates a tap interface. The caller must use virNetDevTapDelete to
+ * remove a persistent TAP device when it is no longer needed. In case
+ * @tapfdSize is greater than one, multiqueue extension is requested
+ * from kernel.
  *
  * Returns 0 in case of success or -1 on failure.
  */
 int virNetDevTapCreate(char **ifname,
                        int *tapfd,
+                       int tapfdSize,
                        unsigned int flags)
 {
-    int fd;
+    int i;
     struct ifreq ifr;
     int ret = -1;
 
-    if ((fd = open("/dev/net/tun", O_RDWR)) < 0) {
-        virReportSystemError(errno, "%s",
-                             _("Unable to open /dev/net/tun, is tun module loaded?"));
-        return -1;
-    }
-
     memset(&ifr, 0, sizeof(ifr));
+    for (i = 0; i < tapfdSize; i++) {
+        int fd;
 
-    ifr.ifr_flags = IFF_TAP|IFF_NO_PI;
+        if ((fd = open("/dev/net/tun", O_RDWR)) < 0) {
+            virReportSystemError(errno, "%s",
+                                 _("Unable to open /dev/net/tun, is tun module loaded?"));
+            goto cleanup;
+        }
+
+        memset(&ifr, 0, sizeof(ifr));
+
+        ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+        /* If tapfdSize is greater than one, request multiqueue */
+        if (tapfdSize > 1)
+            ifr.ifr_flags |= IFF_MULTI_QUEUE;
 
 # ifdef IFF_VNET_HDR
-    if ((flags &  VIR_NETDEV_TAP_CREATE_VNET_HDR) &&
-        virNetDevProbeVnetHdr(fd))
-        ifr.ifr_flags |= IFF_VNET_HDR;
+        if ((flags &  VIR_NETDEV_TAP_CREATE_VNET_HDR) &&
+            virNetDevProbeVnetHdr(fd))
+            ifr.ifr_flags |= IFF_VNET_HDR;
 # endif
 
-    if (virStrcpyStatic(ifr.ifr_name, *ifname) == NULL) {
-        virReportSystemError(ERANGE,
-                             _("Network interface name '%s' is too long"),
-                             *ifname);
-        goto cleanup;
+        if (virStrcpyStatic(ifr.ifr_name, *ifname) == NULL) {
+            virReportSystemError(ERANGE,
+                                 _("Network interface name '%s' is too long"),
+                                 *ifname);
+            goto cleanup;
 
-    }
+        }
 
-    if (ioctl(fd, TUNSETIFF, &ifr) < 0) {
-        virReportSystemError(errno,
-                             _("Unable to create tap device %s"),
-                             NULLSTR(*ifname));
-        goto cleanup;
-    }
+        if (ioctl(fd, TUNSETIFF, &ifr) < 0) {
+            virReportSystemError(errno,
+                                 _("Unable to create tap device %s"),
+                                 NULLSTR(*ifname));
+            goto cleanup;
+        }
 
-    if ((flags & VIR_NETDEV_TAP_CREATE_PERSIST) &&
-        (errno = ioctl(fd, TUNSETPERSIST, 1))) {
-        virReportSystemError(errno,
-                             _("Unable to set tap device %s to persistent"),
-                             NULLSTR(*ifname));
-        goto cleanup;
-    }
+        if (i == 0) {
+            /* In case we are looping more than once, set other
+             * TAPs to have the same name */
+            VIR_FREE(*ifname);
+            if (ifr.ifr_name && VIR_STRDUP(*ifname, ifr.ifr_name) < 0)
+                goto cleanup;
+        }
 
-    VIR_FREE(*ifname);
-    if (!(*ifname = strdup(ifr.ifr_name))) {
-        virReportOOMError();
-        goto cleanup;
+        if ((flags & VIR_NETDEV_TAP_CREATE_PERSIST) &&
+            (errno = ioctl(fd, TUNSETPERSIST, 1))) {
+            virReportSystemError(errno,
+                                 _("Unable to set tap device %s to persistent"),
+                                 NULLSTR(*ifname));
+            goto cleanup;
+        }
+        tapfd[i] = fd;
     }
-    if (tapfd)
-        *tapfd = fd;
-    else
-        VIR_FORCE_CLOSE(fd);
 
     ret = 0;
 
 cleanup:
-    if (ret < 0)
-        VIR_FORCE_CLOSE(fd);
+    if (ret < 0) {
+        for (i = 0; i < tapfdSize; i++)
+            VIR_FORCE_CLOSE(tapfd[i]);
+    }
 
     return ret;
 }
@@ -266,6 +276,7 @@ cleanup:
 #else /* ! TUNSETIFF */
 int virNetDevTapCreate(char **ifname ATTRIBUTE_UNUSED,
                        int *tapfd ATTRIBUTE_UNUSED,
+                       int tapfdSize ATTRIBUTE_UNUSED,
                        unsigned int flags ATTRIBUTE_UNUSED)
 {
     virReportSystemError(ENOSYS, "%s",
@@ -286,7 +297,8 @@ int virNetDevTapDelete(const char *ifname ATTRIBUTE_UNUSED)
  * @brname: the bridge name
  * @ifname: the interface name (or name template)
  * @macaddr: desired MAC address
- * @tapfd: file descriptor return value for the new tap device
+ * @tapfd: array of file descriptor return value for the new tap device
+ * @tapfdSize: size of @tapfd
  * @virtPortProfile: bridge/port specific configuration
  * @flags: OR of virNetDevTapCreateFlags:
 
@@ -314,6 +326,7 @@ int virNetDevTapCreateInBridgePort(const char *brname,
                                    const virMacAddrPtr macaddr,
                                    const unsigned char *vmuuid,
                                    int *tapfd,
+                                   int tapfdSize,
                                    virNetDevVPortProfilePtr virtPortProfile,
                                    virNetDevVlanPtr virtVlan,
                                    unsigned int flags)
@@ -321,7 +334,7 @@ int virNetDevTapCreateInBridgePort(const char *brname,
     virMacAddr tapmac;
     char macaddrstr[VIR_MAC_STRING_BUFLEN];
 
-    if (virNetDevTapCreate(ifname, tapfd, flags) < 0)
+    if (virNetDevTapCreate(ifname, tapfd, tapfdSize, flags) < 0)
         return -1;
 
     /* We need to set the interface MAC before adding it
@@ -372,9 +385,9 @@ int virNetDevTapCreateInBridgePort(const char *brname,
 
     return 0;
 
- error:
-    if (tapfd)
-        VIR_FORCE_CLOSE(*tapfd);
+error:
+    while (tapfdSize)
+        VIR_FORCE_CLOSE(tapfd[--tapfdSize]);
 
     return -1;
 }
diff --git a/src/util/virnetdevtap.h b/src/util/virnetdevtap.h
index 6bfc80c..cb6c284 100644
--- a/src/util/virnetdevtap.h
+++ b/src/util/virnetdevtap.h
@@ -29,6 +29,7 @@
 
 int virNetDevTapCreate(char **ifname,
                        int *tapfd,
+                       int tapfdSize,
                        unsigned int flags)
     ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
 
@@ -55,6 +56,7 @@ int virNetDevTapCreateInBridgePort(const char *brname,
                                    const virMacAddrPtr macaddr,
                                    const unsigned char *vmuuid,
                                    int *tapfd,
+                                   int tapfdSize,
                                    virNetDevVPortProfilePtr virtPortProfile,
                                    virNetDevVlanPtr virtVlan,
                                    unsigned int flags)
-- 
1.8.2.1




More information about the libvir-list mailing list