net/virtio-user: check negotiated features before set

This patch checks negotiated features to see if necessary to offload
before set the tap device offload capabilities. It also checks if kernel
support the TUNSETOFFLOAD operation.

Fixes: 5e97e4202563 ("net/virtio-user: enable offloading")
Cc: stable@dpdk.org

Signed-off-by: Eric Zhang <eric.zhang@windriver.com>
Reviewed-by: Tiwei Bie <tiwei.bie@intel.com>
This commit is contained in:
Eric Zhang 2018-08-29 11:55:21 -04:00 committed by Ferruh Yigit
parent 28925156d9
commit 1db4d2330b
3 changed files with 54 additions and 22 deletions

@ -147,8 +147,8 @@ prepare_vhost_memory_kernel(void)
(1ULL << VIRTIO_NET_F_HOST_TSO6) | \ (1ULL << VIRTIO_NET_F_HOST_TSO6) | \
(1ULL << VIRTIO_NET_F_CSUM)) (1ULL << VIRTIO_NET_F_CSUM))
static int static unsigned int
tap_supporte_mq(void) tap_support_features(void)
{ {
int tapfd; int tapfd;
unsigned int tap_features; unsigned int tap_features;
@ -167,7 +167,7 @@ tap_supporte_mq(void)
} }
close(tapfd); close(tapfd);
return tap_features & IFF_MULTI_QUEUE; return tap_features;
} }
static int static int
@ -181,6 +181,7 @@ vhost_kernel_ioctl(struct virtio_user_dev *dev,
struct vhost_memory_kernel *vm = NULL; struct vhost_memory_kernel *vm = NULL;
int vhostfd; int vhostfd;
unsigned int queue_sel; unsigned int queue_sel;
unsigned int features;
PMD_DRV_LOG(INFO, "%s", vhost_msg_strings[req]); PMD_DRV_LOG(INFO, "%s", vhost_msg_strings[req]);
@ -234,17 +235,20 @@ vhost_kernel_ioctl(struct virtio_user_dev *dev,
} }
if (!ret && req_kernel == VHOST_GET_FEATURES) { if (!ret && req_kernel == VHOST_GET_FEATURES) {
features = tap_support_features();
/* with tap as the backend, all these features are supported /* with tap as the backend, all these features are supported
* but not claimed by vhost-net, so we add them back when * but not claimed by vhost-net, so we add them back when
* reporting to upper layer. * reporting to upper layer.
*/ */
*((uint64_t *)arg) |= VHOST_KERNEL_GUEST_OFFLOADS_MASK; if (features & IFF_VNET_HDR) {
*((uint64_t *)arg) |= VHOST_KERNEL_HOST_OFFLOADS_MASK; *((uint64_t *)arg) |= VHOST_KERNEL_GUEST_OFFLOADS_MASK;
*((uint64_t *)arg) |= VHOST_KERNEL_HOST_OFFLOADS_MASK;
}
/* vhost_kernel will not declare this feature, but it does /* vhost_kernel will not declare this feature, but it does
* support multi-queue. * support multi-queue.
*/ */
if (tap_supporte_mq()) if (features & IFF_MULTI_QUEUE)
*(uint64_t *)arg |= (1ull << VIRTIO_NET_F_MQ); *(uint64_t *)arg |= (1ull << VIRTIO_NET_F_MQ);
} }
@ -339,7 +343,7 @@ vhost_kernel_enable_queue_pair(struct virtio_user_dev *dev,
hdr_size = sizeof(struct virtio_net_hdr); hdr_size = sizeof(struct virtio_net_hdr);
tapfd = vhost_kernel_open_tap(&dev->ifname, hdr_size, req_mq, tapfd = vhost_kernel_open_tap(&dev->ifname, hdr_size, req_mq,
(char *)dev->mac_addr); (char *)dev->mac_addr, dev->features);
if (tapfd < 0) { if (tapfd < 0) {
PMD_DRV_LOG(ERR, "fail to open tap for vhost kernel"); PMD_DRV_LOG(ERR, "fail to open tap for vhost kernel");
return -1; return -1;

@ -16,21 +16,55 @@
#include "vhost_kernel_tap.h" #include "vhost_kernel_tap.h"
#include "../virtio_logs.h" #include "../virtio_logs.h"
#include "../virtio_pci.h"
static int
vhost_kernel_tap_set_offload(int fd, uint64_t features)
{
unsigned int offload = 0;
if (features & (1ULL << VIRTIO_NET_F_GUEST_CSUM)) {
offload |= TUN_F_CSUM;
if (features & (1ULL << VIRTIO_NET_F_GUEST_TSO4))
offload |= TUN_F_TSO4;
if (features & (1ULL << VIRTIO_NET_F_GUEST_TSO6))
offload |= TUN_F_TSO6;
if (features & ((1ULL << VIRTIO_NET_F_GUEST_TSO4) |
(1ULL << VIRTIO_NET_F_GUEST_TSO6)) &&
(features & (1ULL << VIRTIO_NET_F_GUEST_ECN)))
offload |= TUN_F_TSO_ECN;
if (features & (1ULL << VIRTIO_NET_F_GUEST_UFO))
offload |= TUN_F_UFO;
}
if (offload != 0) {
/* Check if our kernel supports TUNSETOFFLOAD */
if (ioctl(fd, TUNSETOFFLOAD, 0) != 0 && errno == EINVAL) {
PMD_DRV_LOG(ERR, "Kernel does't support TUNSETOFFLOAD\n");
return -ENOTSUP;
}
if (ioctl(fd, TUNSETOFFLOAD, offload) != 0) {
offload &= ~TUN_F_UFO;
if (ioctl(fd, TUNSETOFFLOAD, offload) != 0) {
PMD_DRV_LOG(ERR, "TUNSETOFFLOAD ioctl() failed: %s\n",
strerror(errno));
return -1;
}
}
}
return 0;
}
int int
vhost_kernel_open_tap(char **p_ifname, int hdr_size, int req_mq, vhost_kernel_open_tap(char **p_ifname, int hdr_size, int req_mq,
const char *mac) const char *mac, uint64_t features)
{ {
unsigned int tap_features; unsigned int tap_features;
int sndbuf = INT_MAX; int sndbuf = INT_MAX;
struct ifreq ifr; struct ifreq ifr;
int tapfd; int tapfd;
unsigned int offload =
TUN_F_CSUM |
TUN_F_TSO4 |
TUN_F_TSO6 |
TUN_F_TSO_ECN |
TUN_F_UFO;
/* TODO: /* TODO:
* 1. verify we can get/set vnet_hdr_len, tap_probe_vnet_hdr_len * 1. verify we can get/set vnet_hdr_len, tap_probe_vnet_hdr_len
@ -90,13 +124,7 @@ vhost_kernel_open_tap(char **p_ifname, int hdr_size, int req_mq,
goto error; goto error;
} }
/* TODO: before set the offload capabilities, we'd better (1) check vhost_kernel_tap_set_offload(tapfd, features);
* negotiated features to see if necessary to offload; (2) query tap
* to see if it supports the offload capabilities.
*/
if (ioctl(tapfd, TUNSETOFFLOAD, offload) != 0)
PMD_DRV_LOG(ERR, "TUNSETOFFLOAD ioctl() failed: %s",
strerror(errno));
memset(&ifr, 0, sizeof(ifr)); memset(&ifr, 0, sizeof(ifr));
ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER; ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;

@ -36,4 +36,4 @@
#define PATH_NET_TUN "/dev/net/tun" #define PATH_NET_TUN "/dev/net/tun"
int vhost_kernel_open_tap(char **p_ifname, int hdr_size, int req_mq, int vhost_kernel_open_tap(char **p_ifname, int hdr_size, int req_mq,
const char *mac); const char *mac, uint64_t features);