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

Michal Privoznik mprivozn at redhat.com
Mon Apr 22 14:25:51 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     | 105 ++++++++++++++++++++++++--------------------
 src/util/virnetdevtap.h     |   2 +
 5 files changed, 66 insertions(+), 50 deletions(-)

diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
index 27dd230..7118702 100644
--- a/src/network/bridge_driver.c
+++ b/src/network/bridge_driver.c
@@ -2424,7 +2424,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 b5374e0..f5d11ad 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -272,7 +272,7 @@ qemuNetworkIfaceConnect(virDomainDefPtr def,
     }
 
     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 4fa7927..4816f06 100644
--- a/src/uml/uml_conf.c
+++ b/src/uml/uml_conf.c
@@ -110,6 +110,7 @@ umlConnectTapDevice(virConnectPtr conn,
                     const char *bridge)
 {
     bool template_ifname = false;
+    int tapfd;
 
     if (!net->ifname ||
         STRPREFIX(net->ifname, VIR_NET_GENERATED_PREFIX) ||
@@ -122,7 +123,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 |
@@ -140,11 +141,13 @@ umlConnectTapDevice(virConnectPtr conn,
         }
     }
 
+    VIR_FORCE_CLOSE(tapfd);
     return 0;
 
 no_memory:
     virReportOOMError();
 error:
+    VIR_FORCE_CLOSE(tapfd);
     return -1;
 }
 
diff --git a/src/util/virnetdevtap.c b/src/util/virnetdevtap.c
index e4ce223..cdf6bd3 100644
--- a/src/util/virnetdevtap.c
+++ b/src/util/virnetdevtap.c
@@ -106,7 +106,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
@@ -114,76 +115,83 @@ 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;
+
+        if ((fd = open("/dev/net/tun", O_RDWR)) < 0) {
+            virReportSystemError(errno, "%s",
+                                 _("Unable to open /dev/net/tun, is tun module loaded?"));
+            goto cleanup;
+        }
 
-    ifr.ifr_flags = IFF_TAP|IFF_NO_PI;
+        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 ((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;
     }
 
     VIR_FREE(*ifname);
-    if (!(*ifname = strdup(ifr.ifr_name))) {
+    if (ifr.ifr_name && !(*ifname = strdup(ifr.ifr_name))) {
         virReportOOMError();
         goto cleanup;
     }
-    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;
 }
@@ -232,6 +240,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",
@@ -252,7 +261,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:
 
@@ -280,6 +290,7 @@ int virNetDevTapCreateInBridgePort(const char *brname,
                                    const virMacAddrPtr macaddr,
                                    const unsigned char *vmuuid,
                                    int *tapfd,
+                                   int tapfdSize,
                                    virNetDevVPortProfilePtr virtPortProfile,
                                    virNetDevVlanPtr virtVlan,
                                    unsigned int flags)
@@ -287,7 +298,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
@@ -338,9 +349,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 980db61..6e46ac8 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;
 
@@ -52,6 +53,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.1.5




More information about the libvir-list mailing list