X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fvirtio%2Fvirtio_user%2Fvhost_kernel_tap.c;h=2aac4028bb298b81ae957e6dc07844816feb41b9;hb=6c31a8c20a5af8f8b7929d7637a6a9d414ccfb31;hp=cdb5c3c180b1db1451502e51f0aee2ddb290f657;hpb=5e97e42025635e03ff5c256275d7d7650fff4dbc;p=dpdk.git diff --git a/drivers/net/virtio/virtio_user/vhost_kernel_tap.c b/drivers/net/virtio/virtio_user/vhost_kernel_tap.c index cdb5c3c180..2aac4028bb 100644 --- a/drivers/net/virtio/virtio_user/vhost_kernel_tap.c +++ b/drivers/net/virtio/virtio_user/vhost_kernel_tap.c @@ -1,34 +1,5 @@ -/*- - * BSD LICENSE - * - * Copyright(c) 2016 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2016 Intel Corporation */ #include @@ -36,32 +7,23 @@ #include #include #include +#include #include #include #include +#include + #include "vhost_kernel_tap.h" #include "../virtio_logs.h" +#include "../virtio.h" + int -vhost_kernel_open_tap(char **p_ifname, int hdr_size) +tap_support_features(unsigned int *tap_features) { - unsigned int tap_features; - 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 - * 2. get number of memory regions from vhost module parameter - * max_mem_regions, supported in newer version linux kernel - */ tapfd = open(PATH_NET_TUN, O_RDWR); if (tapfd < 0) { PMD_DRV_LOG(ERR, "fail to open %s: %s", @@ -69,62 +31,161 @@ vhost_kernel_open_tap(char **p_ifname, int hdr_size) return -1; } - /* Construct ifr */ - memset(&ifr, 0, sizeof(ifr)); - ifr.ifr_flags = IFF_TAP | IFF_NO_PI; - - if (ioctl(tapfd, TUNGETFEATURES, &tap_features) == -1) { + if (ioctl(tapfd, TUNGETFEATURES, tap_features) == -1) { PMD_DRV_LOG(ERR, "TUNGETFEATURES failed: %s", strerror(errno)); - goto error; + close(tapfd); + return -1; } - if (tap_features & IFF_ONE_QUEUE) - ifr.ifr_flags |= IFF_ONE_QUEUE; - /* Let tap instead of vhost-net handle vnet header, as the latter does - * not support offloading. And in this case, we should not set feature - * bit VHOST_NET_F_VIRTIO_NET_HDR. - */ - if (tap_features & IFF_VNET_HDR) { - ifr.ifr_flags |= IFF_VNET_HDR; - } else { - PMD_DRV_LOG(ERR, "TAP does not support IFF_VNET_HDR"); - goto error; + close(tapfd); + return 0; +} + +int +tap_open(const char *ifname, bool multi_queue) +{ + struct ifreq ifr; + int tapfd; + + tapfd = open(PATH_NET_TUN, O_RDWR); + if (tapfd < 0) { + PMD_DRV_LOG(ERR, "fail to open %s: %s", PATH_NET_TUN, strerror(errno)); + return -1; + } + if (fcntl(tapfd, F_SETFL, O_NONBLOCK) < 0) { + PMD_DRV_LOG(ERR, "fcntl tapfd failed: %s", strerror(errno)); + close(tapfd); + return -1; } - if (*p_ifname) - strncpy(ifr.ifr_name, *p_ifname, IFNAMSIZ); - else - strncpy(ifr.ifr_name, "tap%d", IFNAMSIZ); +retry_mono_q: + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1); + ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_VNET_HDR; + if (multi_queue) + ifr.ifr_flags |= IFF_MULTI_QUEUE; if (ioctl(tapfd, TUNSETIFF, (void *)&ifr) == -1) { + if (multi_queue) { + PMD_DRV_LOG(DEBUG, + "TUNSETIFF failed (will retry without IFF_MULTI_QUEUE): %s", + strerror(errno)); + multi_queue = false; + goto retry_mono_q; + } + PMD_DRV_LOG(ERR, "TUNSETIFF failed: %s", strerror(errno)); - goto error; + close(tapfd); + tapfd = -1; + } + return tapfd; +} + +int +tap_get_name(int tapfd, char **name) +{ + struct ifreq ifr; + int ret; + + memset(&ifr, 0, sizeof(ifr)); + if (ioctl(tapfd, TUNGETIFF, (void *)&ifr) == -1) { + PMD_DRV_LOG(ERR, "TUNGETIFF failed: %s", strerror(errno)); + return -1; + } + ret = asprintf(name, "%s", ifr.ifr_name); + if (ret != -1) + ret = 0; + return ret; +} + +int +tap_get_flags(int tapfd, unsigned int *tap_flags) +{ + struct ifreq ifr; + + memset(&ifr, 0, sizeof(ifr)); + if (ioctl(tapfd, TUNGETIFF, (void *)&ifr) == -1) { + PMD_DRV_LOG(ERR, "TUNGETIFF failed: %s", strerror(errno)); + return -1; } + *tap_flags = ifr.ifr_flags; + return 0; +} + +int +tap_set_mac(int tapfd, uint8_t *mac) +{ + struct ifreq ifr; - fcntl(tapfd, F_SETFL, O_NONBLOCK); + memset(&ifr, 0, sizeof(ifr)); + ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER; + memcpy(ifr.ifr_hwaddr.sa_data, mac, RTE_ETHER_ADDR_LEN); + if (ioctl(tapfd, SIOCSIFHWADDR, (void *)&ifr) == -1) { + PMD_DRV_LOG(ERR, "SIOCSIFHWADDR failed: %s", strerror(errno)); + return -1; + } + return 0; +} + +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; + } + + /* Check if our kernel supports TUNSETOFFLOAD */ + if (ioctl(fd, TUNSETOFFLOAD, 0) != 0 && errno == EINVAL) { + PMD_DRV_LOG(ERR, "Kernel doesn't support TUNSETOFFLOAD"); + 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", + strerror(errno)); + return -1; + } + } + + return 0; +} + +int +vhost_kernel_tap_setup(int tapfd, int hdr_size, uint64_t features) +{ + int sndbuf = INT_MAX; + int ret; + + /* TODO: + * 1. verify we can get/set vnet_hdr_len, tap_probe_vnet_hdr_len + * 2. get number of memory regions from vhost module parameter + * max_mem_regions, supported in newer version linux kernel + */ if (ioctl(tapfd, TUNSETVNETHDRSZ, &hdr_size) < 0) { PMD_DRV_LOG(ERR, "TUNSETVNETHDRSZ failed: %s", strerror(errno)); - goto error; + return -1; } if (ioctl(tapfd, TUNSETSNDBUF, &sndbuf) < 0) { PMD_DRV_LOG(ERR, "TUNSETSNDBUF failed: %s", strerror(errno)); - goto error; + return -1; } - /* 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); - - return tapfd; -error: - close(tapfd); - return -1; + ret = vhost_kernel_tap_set_offload(tapfd, features); + if (ret == -ENOTSUP) + ret = 0; + return ret; }