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>
This commit is contained in:
Jason Wang 2013-01-30 19:12:31 +08:00 committed by Anthony Liguori
parent 5193e5fbb5
commit 94fdc6d030
6 changed files with 97 additions and 0 deletions

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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 */