net/virtio-user: enable offloading
authorJianfeng Tan <jianfeng.tan@intel.com>
Fri, 13 Jan 2017 12:18:39 +0000 (12:18 +0000)
committerYuanhan Liu <yuanhan.liu@linux.intel.com>
Tue, 17 Jan 2017 08:24:56 +0000 (09:24 +0100)
When used with vhost kernel backend, we can offload at both directions.
  - From vhost kernel to virtio_user, the offload is enabled so that
    DPDK app can trust the flow is checksum-correct; and if DPDK app
    sends it through another port, the checksum needs to be
    recalculated or offloaded. It also applies to TSO.
  - From virtio_user to vhost_kernel, the offload is enabled so that
    kernel can trust the flow is L4-checksum-correct, no need to verify
    it; if kernel will consume it, DPDK app should make sure the
    l3-checksum is correctly set.

Signed-off-by: Jianfeng Tan <jianfeng.tan@intel.com>
Acked-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
drivers/net/virtio/virtio_user/vhost_kernel.c
drivers/net/virtio/virtio_user/vhost_kernel_tap.c
drivers/net/virtio/virtio_user/vhost_kernel_tap.h

index d3cbdbd..aeb5075 100644 (file)
@@ -165,6 +165,28 @@ prepare_vhost_memory_kernel(void)
        return vm;
 }
 
+/* with below features, vhost kernel does not need to do the checksum and TSO,
+ * these info will be passed to virtio_user through virtio net header.
+ */
+#define VHOST_KERNEL_GUEST_OFFLOADS_MASK       \
+       ((1ULL << VIRTIO_NET_F_GUEST_CSUM) |    \
+        (1ULL << VIRTIO_NET_F_GUEST_TSO4) |    \
+        (1ULL << VIRTIO_NET_F_GUEST_TSO6) |    \
+        (1ULL << VIRTIO_NET_F_GUEST_ECN)  |    \
+        (1ULL << VIRTIO_NET_F_GUEST_UFO))
+
+/* with below features, when flows from virtio_user to vhost kernel
+ * (1) if flows goes up through the kernel networking stack, it does not need
+ * to verify checksum, which can save CPU cycles;
+ * (2) if flows goes through a Linux bridge and outside from an interface
+ * (kernel driver), checksum and TSO will be done by GSO in kernel or even
+ * offloaded into real physical device.
+ */
+#define VHOST_KERNEL_HOST_OFFLOADS_MASK                \
+       ((1ULL << VIRTIO_NET_F_HOST_TSO4) |     \
+        (1ULL << VIRTIO_NET_F_HOST_TSO6) |     \
+        (1ULL << VIRTIO_NET_F_CSUM))
+
 static int
 vhost_kernel_ioctl(struct virtio_user_dev *dev,
                   enum vhost_user_request req,
@@ -186,10 +208,15 @@ vhost_kernel_ioctl(struct virtio_user_dev *dev,
                arg = (void *)vm;
        }
 
-       /* We don't need memory protection here */
-       if (req_kernel == VHOST_SET_FEATURES)
+       if (req_kernel == VHOST_SET_FEATURES) {
+               /* We don't need memory protection here */
                *(uint64_t *)arg &= ~(1ULL << VIRTIO_F_IOMMU_PLATFORM);
 
+               /* VHOST kernel does not know about below flags */
+               *(uint64_t *)arg &= ~VHOST_KERNEL_GUEST_OFFLOADS_MASK;
+               *(uint64_t *)arg &= ~VHOST_KERNEL_HOST_OFFLOADS_MASK;
+       }
+
        for (i = 0; i < dev->max_queue_pairs; ++i) {
                if (dev->vhostfds[i] < 0)
                        continue;
@@ -199,6 +226,15 @@ vhost_kernel_ioctl(struct virtio_user_dev *dev,
                        break;
        }
 
+       if (!ret && req_kernel == VHOST_GET_FEATURES) {
+               /* with tap as the backend, all these features are supported
+                * but not claimed by vhost-net, so we add them back when
+                * reporting to upper layer.
+                */
+               *((uint64_t *)arg) |= VHOST_KERNEL_GUEST_OFFLOADS_MASK;
+               *((uint64_t *)arg) |= VHOST_KERNEL_HOST_OFFLOADS_MASK;
+       }
+
        if (vm)
                free(vm);
 
index 797713b..cdb5c3c 100644 (file)
@@ -50,6 +50,12 @@ vhost_kernel_open_tap(char **p_ifname, int hdr_size)
        int sndbuf = INT_MAX;
        struct ifreq ifr;
        int tapfd;
+       unsigned int offload =
+                       TUN_F_CSUM |
+                       TUN_F_TSO4 |
+                       TUN_F_TSO6 |
+                       TUN_F_TSO_ECN |
+                       TUN_F_UFO;
 
        /* TODO:
         * 1. verify we can get/set vnet_hdr_len, tap_probe_vnet_hdr_len
@@ -106,6 +112,14 @@ vhost_kernel_open_tap(char **p_ifname, int hdr_size)
                goto error;
        }
 
+       /* TODO: before set the offload capabilities, we'd better (1) check
+        * 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));
+
        if (!(*p_ifname))
                *p_ifname = strdup(ifr.ifr_name);
 
index 1fc58ff..8535116 100644 (file)
 #define IFF_ATTACH_QUEUE 0x0200
 #define IFF_DETACH_QUEUE 0x0400
 
+/* Features for GSO (TUNSETOFFLOAD). */
+#define TUN_F_CSUM     0x01    /* You can hand me unchecksummed packets. */
+#define TUN_F_TSO4     0x02    /* I can handle TSO for IPv4 packets */
+#define TUN_F_TSO6     0x04    /* I can handle TSO for IPv6 packets */
+#define TUN_F_TSO_ECN  0x08    /* I can handle TSO with ECN bits. */
+#define TUN_F_UFO      0x10    /* I can handle UFO packets */
+
 /* Constants */
 #define PATH_NET_TUN   "/dev/net/tun"