1 /*- 2 * BSD LICENSE 3 * 4 * Copyright(c) 2016 Intel Corporation. All rights reserved. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of Intel Corporation nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include <unistd.h> 35 #include <sys/types.h> 36 #include <sys/stat.h> 37 #include <fcntl.h> 38 #include <net/if.h> 39 #include <errno.h> 40 #include <string.h> 41 #include <limits.h> 42 43 #include "vhost_kernel_tap.h" 44 #include "../virtio_logs.h" 45 46 int 47 vhost_kernel_open_tap(char **p_ifname, int hdr_size, int req_mq) 48 { 49 unsigned int tap_features; 50 int sndbuf = INT_MAX; 51 struct ifreq ifr; 52 int tapfd; 53 unsigned int offload = 54 TUN_F_CSUM | 55 TUN_F_TSO4 | 56 TUN_F_TSO6 | 57 TUN_F_TSO_ECN | 58 TUN_F_UFO; 59 60 /* TODO: 61 * 1. verify we can get/set vnet_hdr_len, tap_probe_vnet_hdr_len 62 * 2. get number of memory regions from vhost module parameter 63 * max_mem_regions, supported in newer version linux kernel 64 */ 65 tapfd = open(PATH_NET_TUN, O_RDWR); 66 if (tapfd < 0) { 67 PMD_DRV_LOG(ERR, "fail to open %s: %s", 68 PATH_NET_TUN, strerror(errno)); 69 return -1; 70 } 71 72 /* Construct ifr */ 73 memset(&ifr, 0, sizeof(ifr)); 74 ifr.ifr_flags = IFF_TAP | IFF_NO_PI; 75 76 if (ioctl(tapfd, TUNGETFEATURES, &tap_features) == -1) { 77 PMD_DRV_LOG(ERR, "TUNGETFEATURES failed: %s", strerror(errno)); 78 goto error; 79 } 80 if (tap_features & IFF_ONE_QUEUE) 81 ifr.ifr_flags |= IFF_ONE_QUEUE; 82 83 /* Let tap instead of vhost-net handle vnet header, as the latter does 84 * not support offloading. And in this case, we should not set feature 85 * bit VHOST_NET_F_VIRTIO_NET_HDR. 86 */ 87 if (tap_features & IFF_VNET_HDR) { 88 ifr.ifr_flags |= IFF_VNET_HDR; 89 } else { 90 PMD_DRV_LOG(ERR, "TAP does not support IFF_VNET_HDR"); 91 goto error; 92 } 93 94 if (req_mq) 95 ifr.ifr_flags |= IFF_MULTI_QUEUE; 96 97 if (*p_ifname) 98 strncpy(ifr.ifr_name, *p_ifname, IFNAMSIZ); 99 else 100 strncpy(ifr.ifr_name, "tap%d", IFNAMSIZ); 101 if (ioctl(tapfd, TUNSETIFF, (void *)&ifr) == -1) { 102 PMD_DRV_LOG(ERR, "TUNSETIFF failed: %s", strerror(errno)); 103 goto error; 104 } 105 106 fcntl(tapfd, F_SETFL, O_NONBLOCK); 107 108 if (ioctl(tapfd, TUNSETVNETHDRSZ, &hdr_size) < 0) { 109 PMD_DRV_LOG(ERR, "TUNSETVNETHDRSZ failed: %s", strerror(errno)); 110 goto error; 111 } 112 113 if (ioctl(tapfd, TUNSETSNDBUF, &sndbuf) < 0) { 114 PMD_DRV_LOG(ERR, "TUNSETSNDBUF failed: %s", strerror(errno)); 115 goto error; 116 } 117 118 /* TODO: before set the offload capabilities, we'd better (1) check 119 * negotiated features to see if necessary to offload; (2) query tap 120 * to see if it supports the offload capabilities. 121 */ 122 if (ioctl(tapfd, TUNSETOFFLOAD, offload) != 0) 123 PMD_DRV_LOG(ERR, "TUNSETOFFLOAD ioctl() failed: %s", 124 strerror(errno)); 125 126 if (!(*p_ifname)) 127 *p_ifname = strdup(ifr.ifr_name); 128 129 return tapfd; 130 error: 131 close(tapfd); 132 return -1; 133 } 134