aboutsummaryrefslogtreecommitdiff
path: root/net/tap-linux.c
diff options
context:
space:
mode:
authorJason Wang <jasowang@redhat.com>2013-01-30 19:12:31 +0800
committerAnthony Liguori <aliguori@us.ibm.com>2013-02-01 11:03:01 -0600
commit94fdc6d03034f594c53d5413590e23fcb7ffc268 (patch)
treecc87baf580b144ee06f8fab9f44963105966ea43 /net/tap-linux.c
parent5193e5fbb52a33f1f684b0d42d29a452dfd29e4a (diff)
tap: add Linux multiqueue support
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> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
Diffstat (limited to 'net/tap-linux.c')
-rw-r--r--net/tap-linux.c52
1 files changed, 52 insertions, 0 deletions
diff --git a/net/tap-linux.c b/net/tap-linux.c
index 0a6acc7d5a..bdb0a790c8 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;
+}
+