Patchwork [V4,12/22] tap: add Linux multiqueue support

login
register
mail settings
Submitter Jason Wang
Date Jan. 30, 2013, 11:12 a.m.
Message ID <1359544361-5089-13-git-send-email-jasowang@redhat.com>
Download mbox | patch
Permalink /patch/216867/
State New
Headers show

Comments

Jason Wang - Jan. 30, 2013, 11:12 a.m.
This patch add basic multiqueue support for Linux. When multiqueue is needed, we
will first check whether kernel support multiqueue tap before creating more
queues. Two new functions tap_fd_enable() and tap_fd_disable() were introduced
to enable and disable a specific queue. Since the multiqueue is only supported
in Linux, return error on other platforms.

Signed-off-by: Jason Wang <jasowang@redhat.com>
---
 net/tap-aix.c     |   10 ++++++++++
 net/tap-bsd.c     |   11 +++++++++++
 net/tap-haiku.c   |   11 +++++++++++
 net/tap-linux.c   |   52 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 net/tap-solaris.c |   11 +++++++++++
 net/tap_int.h     |    2 ++
 6 files changed, 97 insertions(+), 0 deletions(-)

Patch

diff --git a/net/tap-aix.c b/net/tap-aix.c
index aff6c52..66e0574 100644
--- a/net/tap-aix.c
+++ b/net/tap-aix.c
@@ -59,3 +59,13 @@  void tap_fd_set_offload(int fd, int csum, int tso4,
                         int tso6, int ecn, int ufo)
 {
 }
+
+int tap_fd_enable(int fd)
+{
+    return -1;
+}
+
+int tap_fd_disable(int fd)
+{
+    return -1;
+}
diff --git a/net/tap-bsd.c b/net/tap-bsd.c
index 01c705b..cfc7a28 100644
--- a/net/tap-bsd.c
+++ b/net/tap-bsd.c
@@ -145,3 +145,14 @@  void tap_fd_set_offload(int fd, int csum, int tso4,
                         int tso6, int ecn, int ufo)
 {
 }
+
+int tap_fd_enable(int fd)
+{
+    return -1;
+}
+
+int tap_fd_disable(int fd)
+{
+    return -1;
+}
+
diff --git a/net/tap-haiku.c b/net/tap-haiku.c
index 08cc034..664d40f 100644
--- a/net/tap-haiku.c
+++ b/net/tap-haiku.c
@@ -59,3 +59,14 @@  void tap_fd_set_offload(int fd, int csum, int tso4,
                         int tso6, int ecn, int ufo)
 {
 }
+
+int tap_fd_enable(int fd)
+{
+    return -1;
+}
+
+int tap_fd_disable(int fd)
+{
+    return -1;
+}
+
diff --git a/net/tap-linux.c b/net/tap-linux.c
index 0a6acc7..bdb0a79 100644
--- a/net/tap-linux.c
+++ b/net/tap-linux.c
@@ -41,6 +41,7 @@  int tap_open(char *ifname, int ifname_size, int *vnet_hdr, int vnet_hdr_required
     struct ifreq ifr;
     int fd, ret;
     int len = sizeof(struct virtio_net_hdr);
+    int mq_required = 0;
 
     TFR(fd = open(PATH_NET_TUN, O_RDWR));
     if (fd < 0) {
@@ -76,6 +77,20 @@  int tap_open(char *ifname, int ifname_size, int *vnet_hdr, int vnet_hdr_required
         ioctl(fd, TUNSETVNETHDRSZ, &len);
     }
 
+    if (mq_required) {
+        unsigned int features;
+
+        if ((ioctl(fd, TUNGETFEATURES, &features) != 0) ||
+            !(features & IFF_MULTI_QUEUE)) {
+            error_report("multiqueue required, but no kernel "
+                         "support for IFF_MULTI_QUEUE available");
+            close(fd);
+            return -1;
+        } else {
+            ifr.ifr_flags |= IFF_MULTI_QUEUE;
+        }
+    }
+
     if (ifname[0] != '\0')
         pstrcpy(ifr.ifr_name, IFNAMSIZ, ifname);
     else
@@ -209,3 +224,40 @@  void tap_fd_set_offload(int fd, int csum, int tso4,
         }
     }
 }
+
+/* Enable a specific queue of tap. */
+int tap_fd_enable(int fd)
+{
+    struct ifreq ifr;
+    int ret;
+
+    memset(&ifr, 0, sizeof(ifr));
+
+    ifr.ifr_flags = IFF_ATTACH_QUEUE;
+    ret = ioctl(fd, TUNSETQUEUE, (void *) &ifr);
+
+    if (ret != 0) {
+        error_report("could not enable queue");
+    }
+
+    return ret;
+}
+
+/* Disable a specific queue of tap/ */
+int tap_fd_disable(int fd)
+{
+    struct ifreq ifr;
+    int ret;
+
+    memset(&ifr, 0, sizeof(ifr));
+
+    ifr.ifr_flags = IFF_DETACH_QUEUE;
+    ret = ioctl(fd, TUNSETQUEUE, (void *) &ifr);
+
+    if (ret != 0) {
+        error_report("could not disable queue");
+    }
+
+    return ret;
+}
+
diff --git a/net/tap-solaris.c b/net/tap-solaris.c
index 486a7ea..12cc392 100644
--- a/net/tap-solaris.c
+++ b/net/tap-solaris.c
@@ -225,3 +225,14 @@  void tap_fd_set_offload(int fd, int csum, int tso4,
                         int tso6, int ecn, int ufo)
 {
 }
+
+int tap_fd_enable(int fd)
+{
+    return -1;
+}
+
+int tap_fd_disable(int fd)
+{
+    return -1;
+}
+
diff --git a/net/tap_int.h b/net/tap_int.h
index 1dffe12..ca1c21b 100644
--- a/net/tap_int.h
+++ b/net/tap_int.h
@@ -42,5 +42,7 @@  int tap_probe_vnet_hdr_len(int fd, int len);
 int tap_probe_has_ufo(int fd);
 void tap_fd_set_offload(int fd, int csum, int tso4, int tso6, int ecn, int ufo);
 void tap_fd_set_vnet_hdr_len(int fd, int len);
+int tap_fd_enable(int fd);
+int tap_fd_disable(int fd);
 
 #endif /* QEMU_TAP_H */