15566a3e3SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause 25566a3e3SBruce Richardson * Copyright(c) 2016 Intel Corporation 3e3b43481SJianfeng Tan */ 4e3b43481SJianfeng Tan 5e3b43481SJianfeng Tan #include <sys/types.h> 6e3b43481SJianfeng Tan #include <sys/stat.h> 7e3b43481SJianfeng Tan #include <fcntl.h> 8e3b43481SJianfeng Tan #include <unistd.h> 906856cabSMaxime Coquelin #include <errno.h> 10e3b43481SJianfeng Tan 11e3b43481SJianfeng Tan #include <rte_memory.h> 12e3b43481SJianfeng Tan 13e3b43481SJianfeng Tan #include "vhost.h" 14e3b43481SJianfeng Tan #include "virtio_user_dev.h" 15e3b43481SJianfeng Tan #include "vhost_kernel_tap.h" 16e3b43481SJianfeng Tan 17e3b43481SJianfeng Tan struct vhost_memory_kernel { 18e3b43481SJianfeng Tan uint32_t nregions; 19e3b43481SJianfeng Tan uint32_t padding; 20e3b43481SJianfeng Tan struct vhost_memory_region regions[0]; 21e3b43481SJianfeng Tan }; 22e3b43481SJianfeng Tan 23e3b43481SJianfeng Tan /* vhost kernel ioctls */ 24e3b43481SJianfeng Tan #define VHOST_VIRTIO 0xAF 25e3b43481SJianfeng Tan #define VHOST_GET_FEATURES _IOR(VHOST_VIRTIO, 0x00, __u64) 26e3b43481SJianfeng Tan #define VHOST_SET_FEATURES _IOW(VHOST_VIRTIO, 0x00, __u64) 27e3b43481SJianfeng Tan #define VHOST_SET_OWNER _IO(VHOST_VIRTIO, 0x01) 28e3b43481SJianfeng Tan #define VHOST_RESET_OWNER _IO(VHOST_VIRTIO, 0x02) 29e3b43481SJianfeng Tan #define VHOST_SET_MEM_TABLE _IOW(VHOST_VIRTIO, 0x03, struct vhost_memory_kernel) 30e3b43481SJianfeng Tan #define VHOST_SET_LOG_BASE _IOW(VHOST_VIRTIO, 0x04, __u64) 31e3b43481SJianfeng Tan #define VHOST_SET_LOG_FD _IOW(VHOST_VIRTIO, 0x07, int) 32e3b43481SJianfeng Tan #define VHOST_SET_VRING_NUM _IOW(VHOST_VIRTIO, 0x10, struct vhost_vring_state) 33e3b43481SJianfeng Tan #define VHOST_SET_VRING_ADDR _IOW(VHOST_VIRTIO, 0x11, struct vhost_vring_addr) 34e3b43481SJianfeng Tan #define VHOST_SET_VRING_BASE _IOW(VHOST_VIRTIO, 0x12, struct vhost_vring_state) 35e3b43481SJianfeng Tan #define VHOST_GET_VRING_BASE _IOWR(VHOST_VIRTIO, 0x12, struct vhost_vring_state) 36e3b43481SJianfeng Tan #define VHOST_SET_VRING_KICK _IOW(VHOST_VIRTIO, 0x20, struct vhost_vring_file) 37e3b43481SJianfeng Tan #define VHOST_SET_VRING_CALL _IOW(VHOST_VIRTIO, 0x21, struct vhost_vring_file) 38e3b43481SJianfeng Tan #define VHOST_SET_VRING_ERR _IOW(VHOST_VIRTIO, 0x22, struct vhost_vring_file) 39e3b43481SJianfeng Tan #define VHOST_NET_SET_BACKEND _IOW(VHOST_VIRTIO, 0x30, struct vhost_vring_file) 40e3b43481SJianfeng Tan 41*cc0151b3SMaxime Coquelin /* with below features, vhost kernel does not need to do the checksum and TSO, 42*cc0151b3SMaxime Coquelin * these info will be passed to virtio_user through virtio net header. 43*cc0151b3SMaxime Coquelin */ 44*cc0151b3SMaxime Coquelin #define VHOST_KERNEL_GUEST_OFFLOADS_MASK \ 45*cc0151b3SMaxime Coquelin ((1ULL << VIRTIO_NET_F_GUEST_CSUM) | \ 46*cc0151b3SMaxime Coquelin (1ULL << VIRTIO_NET_F_GUEST_TSO4) | \ 47*cc0151b3SMaxime Coquelin (1ULL << VIRTIO_NET_F_GUEST_TSO6) | \ 48*cc0151b3SMaxime Coquelin (1ULL << VIRTIO_NET_F_GUEST_ECN) | \ 49*cc0151b3SMaxime Coquelin (1ULL << VIRTIO_NET_F_GUEST_UFO)) 50*cc0151b3SMaxime Coquelin 51*cc0151b3SMaxime Coquelin /* with below features, when flows from virtio_user to vhost kernel 52*cc0151b3SMaxime Coquelin * (1) if flows goes up through the kernel networking stack, it does not need 53*cc0151b3SMaxime Coquelin * to verify checksum, which can save CPU cycles; 54*cc0151b3SMaxime Coquelin * (2) if flows goes through a Linux bridge and outside from an interface 55*cc0151b3SMaxime Coquelin * (kernel driver), checksum and TSO will be done by GSO in kernel or even 56*cc0151b3SMaxime Coquelin * offloaded into real physical device. 57*cc0151b3SMaxime Coquelin */ 58*cc0151b3SMaxime Coquelin #define VHOST_KERNEL_HOST_OFFLOADS_MASK \ 59*cc0151b3SMaxime Coquelin ((1ULL << VIRTIO_NET_F_HOST_TSO4) | \ 60*cc0151b3SMaxime Coquelin (1ULL << VIRTIO_NET_F_HOST_TSO6) | \ 61*cc0151b3SMaxime Coquelin (1ULL << VIRTIO_NET_F_CSUM)) 62*cc0151b3SMaxime Coquelin 63e3b43481SJianfeng Tan static uint64_t max_regions = 64; 64e3b43481SJianfeng Tan 65e3b43481SJianfeng Tan static void 66e3b43481SJianfeng Tan get_vhost_kernel_max_regions(void) 67e3b43481SJianfeng Tan { 68e3b43481SJianfeng Tan int fd; 69e3b43481SJianfeng Tan char buf[20] = {'\0'}; 70e3b43481SJianfeng Tan 71e3b43481SJianfeng Tan fd = open("/sys/module/vhost/parameters/max_mem_regions", O_RDONLY); 72e3b43481SJianfeng Tan if (fd < 0) 73e3b43481SJianfeng Tan return; 74e3b43481SJianfeng Tan 75e3b43481SJianfeng Tan if (read(fd, buf, sizeof(buf) - 1) > 0) 76e3b43481SJianfeng Tan max_regions = strtoull(buf, NULL, 10); 77e3b43481SJianfeng Tan 78e3b43481SJianfeng Tan close(fd); 79e3b43481SJianfeng Tan } 80e3b43481SJianfeng Tan 8106856cabSMaxime Coquelin static int 8206856cabSMaxime Coquelin vhost_kernel_ioctl(int fd, uint64_t request, void *arg) 8306856cabSMaxime Coquelin { 8406856cabSMaxime Coquelin int ret; 8506856cabSMaxime Coquelin 8606856cabSMaxime Coquelin ret = ioctl(fd, request, arg); 8706856cabSMaxime Coquelin if (ret) { 8806856cabSMaxime Coquelin PMD_DRV_LOG(ERR, "Vhost-kernel ioctl %"PRIu64" failed (%s)", 8906856cabSMaxime Coquelin request, strerror(errno)); 9006856cabSMaxime Coquelin return -1; 9106856cabSMaxime Coquelin } 9206856cabSMaxime Coquelin 9306856cabSMaxime Coquelin return 0; 9406856cabSMaxime Coquelin } 9506856cabSMaxime Coquelin 9606856cabSMaxime Coquelin static int 9706856cabSMaxime Coquelin vhost_kernel_set_owner(struct virtio_user_dev *dev) 9806856cabSMaxime Coquelin { 9906856cabSMaxime Coquelin return vhost_kernel_ioctl(dev->vhostfds[0], VHOST_SET_OWNER, NULL); 10006856cabSMaxime Coquelin } 10106856cabSMaxime Coquelin 102*cc0151b3SMaxime Coquelin static int 103*cc0151b3SMaxime Coquelin vhost_kernel_get_features(struct virtio_user_dev *dev, uint64_t *features) 104*cc0151b3SMaxime Coquelin { 105*cc0151b3SMaxime Coquelin int ret; 106*cc0151b3SMaxime Coquelin unsigned int tap_features; 107*cc0151b3SMaxime Coquelin 108*cc0151b3SMaxime Coquelin ret = vhost_kernel_ioctl(dev->vhostfds[0], VHOST_GET_FEATURES, features); 109*cc0151b3SMaxime Coquelin if (ret < 0) { 110*cc0151b3SMaxime Coquelin PMD_DRV_LOG(ERR, "Failed to get features"); 111*cc0151b3SMaxime Coquelin return -1; 112*cc0151b3SMaxime Coquelin } 113*cc0151b3SMaxime Coquelin 114*cc0151b3SMaxime Coquelin ret = tap_support_features(&tap_features); 115*cc0151b3SMaxime Coquelin if (ret < 0) { 116*cc0151b3SMaxime Coquelin PMD_DRV_LOG(ERR, "Failed to get TAP features"); 117*cc0151b3SMaxime Coquelin return -1; 118*cc0151b3SMaxime Coquelin } 119*cc0151b3SMaxime Coquelin 120*cc0151b3SMaxime Coquelin /* with tap as the backend, all these features are supported 121*cc0151b3SMaxime Coquelin * but not claimed by vhost-net, so we add them back when 122*cc0151b3SMaxime Coquelin * reporting to upper layer. 123*cc0151b3SMaxime Coquelin */ 124*cc0151b3SMaxime Coquelin if (tap_features & IFF_VNET_HDR) { 125*cc0151b3SMaxime Coquelin *features |= VHOST_KERNEL_GUEST_OFFLOADS_MASK; 126*cc0151b3SMaxime Coquelin *features |= VHOST_KERNEL_HOST_OFFLOADS_MASK; 127*cc0151b3SMaxime Coquelin } 128*cc0151b3SMaxime Coquelin 129*cc0151b3SMaxime Coquelin /* vhost_kernel will not declare this feature, but it does 130*cc0151b3SMaxime Coquelin * support multi-queue. 131*cc0151b3SMaxime Coquelin */ 132*cc0151b3SMaxime Coquelin if (tap_features & IFF_MULTI_QUEUE) 133*cc0151b3SMaxime Coquelin *features |= (1ull << VIRTIO_NET_F_MQ); 134*cc0151b3SMaxime Coquelin 135*cc0151b3SMaxime Coquelin return 0; 136*cc0151b3SMaxime Coquelin } 137*cc0151b3SMaxime Coquelin 138*cc0151b3SMaxime Coquelin static int 139*cc0151b3SMaxime Coquelin vhost_kernel_set_features(struct virtio_user_dev *dev, uint64_t features) 140*cc0151b3SMaxime Coquelin { 141*cc0151b3SMaxime Coquelin /* We don't need memory protection here */ 142*cc0151b3SMaxime Coquelin features &= ~(1ULL << VIRTIO_F_IOMMU_PLATFORM); 143*cc0151b3SMaxime Coquelin /* VHOST kernel does not know about below flags */ 144*cc0151b3SMaxime Coquelin features &= ~VHOST_KERNEL_GUEST_OFFLOADS_MASK; 145*cc0151b3SMaxime Coquelin features &= ~VHOST_KERNEL_HOST_OFFLOADS_MASK; 146*cc0151b3SMaxime Coquelin features &= ~(1ULL << VIRTIO_NET_F_MQ); 147*cc0151b3SMaxime Coquelin 148*cc0151b3SMaxime Coquelin return vhost_kernel_ioctl(dev->vhostfds[0], VHOST_SET_FEATURES, &features); 149*cc0151b3SMaxime Coquelin } 150*cc0151b3SMaxime Coquelin 151e3b43481SJianfeng Tan static uint64_t vhost_req_user_to_kernel[] = { 152e3b43481SJianfeng Tan [VHOST_USER_RESET_OWNER] = VHOST_RESET_OWNER, 153e3b43481SJianfeng Tan [VHOST_USER_SET_VRING_CALL] = VHOST_SET_VRING_CALL, 154e3b43481SJianfeng Tan [VHOST_USER_SET_VRING_NUM] = VHOST_SET_VRING_NUM, 155e3b43481SJianfeng Tan [VHOST_USER_SET_VRING_BASE] = VHOST_SET_VRING_BASE, 156e3b43481SJianfeng Tan [VHOST_USER_GET_VRING_BASE] = VHOST_GET_VRING_BASE, 157e3b43481SJianfeng Tan [VHOST_USER_SET_VRING_ADDR] = VHOST_SET_VRING_ADDR, 158e3b43481SJianfeng Tan [VHOST_USER_SET_VRING_KICK] = VHOST_SET_VRING_KICK, 159e3b43481SJianfeng Tan [VHOST_USER_SET_MEM_TABLE] = VHOST_SET_MEM_TABLE, 160e3b43481SJianfeng Tan }; 161e3b43481SJianfeng Tan 162746c346dSAnatoly Burakov static int 16375728654STiwei Bie add_memseg_list(const struct rte_memseg_list *msl, void *arg) 164746c346dSAnatoly Burakov { 16575728654STiwei Bie struct vhost_memory_kernel *vm = arg; 166746c346dSAnatoly Burakov struct vhost_memory_region *mr; 167746c346dSAnatoly Burakov void *start_addr; 16875728654STiwei Bie uint64_t len; 169746c346dSAnatoly Burakov 1705282bb1cSAnatoly Burakov if (msl->external) 1715282bb1cSAnatoly Burakov return 0; 1725282bb1cSAnatoly Burakov 17375728654STiwei Bie if (vm->nregions >= max_regions) 174746c346dSAnatoly Burakov return -1; 175746c346dSAnatoly Burakov 17675728654STiwei Bie start_addr = msl->base_va; 17775728654STiwei Bie len = msl->page_sz * msl->memseg_arr.len; 17875728654STiwei Bie 17975728654STiwei Bie mr = &vm->regions[vm->nregions++]; 180746c346dSAnatoly Burakov 181746c346dSAnatoly Burakov mr->guest_phys_addr = (uint64_t)(uintptr_t)start_addr; 182746c346dSAnatoly Burakov mr->userspace_addr = (uint64_t)(uintptr_t)start_addr; 183746c346dSAnatoly Burakov mr->memory_size = len; 18475728654STiwei Bie mr->mmap_offset = 0; /* flags_padding */ 18575728654STiwei Bie 18675728654STiwei Bie PMD_DRV_LOG(DEBUG, "index=%u addr=%p len=%" PRIu64, 18775728654STiwei Bie vm->nregions - 1, start_addr, len); 188746c346dSAnatoly Burakov 189746c346dSAnatoly Burakov return 0; 190746c346dSAnatoly Burakov } 191746c346dSAnatoly Burakov 19275728654STiwei Bie /* By default, vhost kernel module allows 64 regions, but DPDK may 19375728654STiwei Bie * have much more memory regions. Below function will treat each 19475728654STiwei Bie * contiguous memory space reserved by DPDK as one region. 195e3b43481SJianfeng Tan */ 196e3b43481SJianfeng Tan static struct vhost_memory_kernel * 197e3b43481SJianfeng Tan prepare_vhost_memory_kernel(void) 198e3b43481SJianfeng Tan { 199e3b43481SJianfeng Tan struct vhost_memory_kernel *vm; 200e3b43481SJianfeng Tan 201e3b43481SJianfeng Tan vm = malloc(sizeof(struct vhost_memory_kernel) + 202e3b43481SJianfeng Tan max_regions * 203e3b43481SJianfeng Tan sizeof(struct vhost_memory_region)); 2041e9057a9SJianfeng Tan if (!vm) 2051e9057a9SJianfeng Tan return NULL; 206e3b43481SJianfeng Tan 20775728654STiwei Bie vm->nregions = 0; 20875728654STiwei Bie vm->padding = 0; 209e3b43481SJianfeng Tan 2107ff26957STiwei Bie /* 2117ff26957STiwei Bie * The memory lock has already been taken by memory subsystem 2127ff26957STiwei Bie * or virtio_user_start_device(). 2137ff26957STiwei Bie */ 21475728654STiwei Bie if (rte_memseg_list_walk_thread_unsafe(add_memseg_list, vm) < 0) { 215e3b43481SJianfeng Tan free(vm); 216e3b43481SJianfeng Tan return NULL; 217e3b43481SJianfeng Tan } 218e3b43481SJianfeng Tan 219e3b43481SJianfeng Tan return vm; 220e3b43481SJianfeng Tan } 221e3b43481SJianfeng Tan 222be7a4707SJianfeng Tan static int 22306856cabSMaxime Coquelin vhost_kernel_send_request(struct virtio_user_dev *dev, 224e3b43481SJianfeng Tan enum vhost_user_request req, 225e3b43481SJianfeng Tan void *arg) 226e3b43481SJianfeng Tan { 227e3b43481SJianfeng Tan int ret = -1; 228e3b43481SJianfeng Tan unsigned int i; 229e3b43481SJianfeng Tan uint64_t req_kernel; 230e3b43481SJianfeng Tan struct vhost_memory_kernel *vm = NULL; 231be7a4707SJianfeng Tan int vhostfd; 232be7a4707SJianfeng Tan unsigned int queue_sel; 233e3b43481SJianfeng Tan 234e3b43481SJianfeng Tan PMD_DRV_LOG(INFO, "%s", vhost_msg_strings[req]); 235e3b43481SJianfeng Tan 236e3b43481SJianfeng Tan req_kernel = vhost_req_user_to_kernel[req]; 237e3b43481SJianfeng Tan 238e3b43481SJianfeng Tan if (req_kernel == VHOST_SET_MEM_TABLE) { 239e3b43481SJianfeng Tan vm = prepare_vhost_memory_kernel(); 240e3b43481SJianfeng Tan if (!vm) 241e3b43481SJianfeng Tan return -1; 242e3b43481SJianfeng Tan arg = (void *)vm; 243e3b43481SJianfeng Tan } 244e3b43481SJianfeng Tan 245be7a4707SJianfeng Tan switch (req_kernel) { 246be7a4707SJianfeng Tan case VHOST_SET_VRING_NUM: 247be7a4707SJianfeng Tan case VHOST_SET_VRING_ADDR: 248be7a4707SJianfeng Tan case VHOST_SET_VRING_BASE: 249be7a4707SJianfeng Tan case VHOST_GET_VRING_BASE: 250be7a4707SJianfeng Tan case VHOST_SET_VRING_KICK: 251be7a4707SJianfeng Tan case VHOST_SET_VRING_CALL: 252be7a4707SJianfeng Tan queue_sel = *(unsigned int *)arg; 253be7a4707SJianfeng Tan vhostfd = dev->vhostfds[queue_sel / 2]; 254be7a4707SJianfeng Tan *(unsigned int *)arg = queue_sel % 2; 255be7a4707SJianfeng Tan PMD_DRV_LOG(DEBUG, "vhostfd=%d, index=%u", 256be7a4707SJianfeng Tan vhostfd, *(unsigned int *)arg); 257be7a4707SJianfeng Tan break; 258be7a4707SJianfeng Tan default: 259be7a4707SJianfeng Tan vhostfd = -1; 260be7a4707SJianfeng Tan } 261be7a4707SJianfeng Tan if (vhostfd == -1) { 262e3b43481SJianfeng Tan for (i = 0; i < dev->max_queue_pairs; ++i) { 263e3b43481SJianfeng Tan if (dev->vhostfds[i] < 0) 264e3b43481SJianfeng Tan continue; 265e3b43481SJianfeng Tan 266e3b43481SJianfeng Tan ret = ioctl(dev->vhostfds[i], req_kernel, arg); 267e3b43481SJianfeng Tan if (ret < 0) 268e3b43481SJianfeng Tan break; 269e3b43481SJianfeng Tan } 270be7a4707SJianfeng Tan } else { 271be7a4707SJianfeng Tan ret = ioctl(vhostfd, req_kernel, arg); 272be7a4707SJianfeng Tan } 273e3b43481SJianfeng Tan 274e3b43481SJianfeng Tan if (vm) 275e3b43481SJianfeng Tan free(vm); 276e3b43481SJianfeng Tan 277e3b43481SJianfeng Tan if (ret < 0) 278e3b43481SJianfeng Tan PMD_DRV_LOG(ERR, "%s failed: %s", 279e3b43481SJianfeng Tan vhost_msg_strings[req], strerror(errno)); 280e3b43481SJianfeng Tan 281e3b43481SJianfeng Tan return ret; 282e3b43481SJianfeng Tan } 283e3b43481SJianfeng Tan 284e3b43481SJianfeng Tan /** 285e3b43481SJianfeng Tan * Set up environment to talk with a vhost kernel backend. 286e3b43481SJianfeng Tan * 287e3b43481SJianfeng Tan * @return 288e3b43481SJianfeng Tan * - (-1) if fail to set up; 289e3b43481SJianfeng Tan * - (>=0) if successful. 290e3b43481SJianfeng Tan */ 291e3b43481SJianfeng Tan static int 292e3b43481SJianfeng Tan vhost_kernel_setup(struct virtio_user_dev *dev) 293e3b43481SJianfeng Tan { 294e3b43481SJianfeng Tan int vhostfd; 295e3b43481SJianfeng Tan uint32_t i; 296e3b43481SJianfeng Tan 297e3b43481SJianfeng Tan get_vhost_kernel_max_regions(); 298e3b43481SJianfeng Tan 299e3b43481SJianfeng Tan for (i = 0; i < dev->max_queue_pairs; ++i) { 300e3b43481SJianfeng Tan vhostfd = open(dev->path, O_RDWR); 301e3b43481SJianfeng Tan if (vhostfd < 0) { 302e3b43481SJianfeng Tan PMD_DRV_LOG(ERR, "fail to open %s, %s", 303e3b43481SJianfeng Tan dev->path, strerror(errno)); 304e3b43481SJianfeng Tan return -1; 305e3b43481SJianfeng Tan } 306e3b43481SJianfeng Tan 307e3b43481SJianfeng Tan dev->vhostfds[i] = vhostfd; 308e3b43481SJianfeng Tan } 309e3b43481SJianfeng Tan 310e3b43481SJianfeng Tan return 0; 311e3b43481SJianfeng Tan } 312e3b43481SJianfeng Tan 313e3b43481SJianfeng Tan static int 314e3b43481SJianfeng Tan vhost_kernel_set_backend(int vhostfd, int tapfd) 315e3b43481SJianfeng Tan { 316e3b43481SJianfeng Tan struct vhost_vring_file f; 317e3b43481SJianfeng Tan 318e3b43481SJianfeng Tan f.fd = tapfd; 319e3b43481SJianfeng Tan f.index = 0; 320e3b43481SJianfeng Tan if (ioctl(vhostfd, VHOST_NET_SET_BACKEND, &f) < 0) { 321e3b43481SJianfeng Tan PMD_DRV_LOG(ERR, "VHOST_NET_SET_BACKEND fails, %s", 322e3b43481SJianfeng Tan strerror(errno)); 323e3b43481SJianfeng Tan return -1; 324e3b43481SJianfeng Tan } 325e3b43481SJianfeng Tan 326e3b43481SJianfeng Tan f.index = 1; 327e3b43481SJianfeng Tan if (ioctl(vhostfd, VHOST_NET_SET_BACKEND, &f) < 0) { 328e3b43481SJianfeng Tan PMD_DRV_LOG(ERR, "VHOST_NET_SET_BACKEND fails, %s", 329e3b43481SJianfeng Tan strerror(errno)); 330e3b43481SJianfeng Tan return -1; 331e3b43481SJianfeng Tan } 332e3b43481SJianfeng Tan 333e3b43481SJianfeng Tan return 0; 334e3b43481SJianfeng Tan } 335e3b43481SJianfeng Tan 336e3b43481SJianfeng Tan static int 337e3b43481SJianfeng Tan vhost_kernel_enable_queue_pair(struct virtio_user_dev *dev, 338e3b43481SJianfeng Tan uint16_t pair_idx, 339e3b43481SJianfeng Tan int enable) 340e3b43481SJianfeng Tan { 341e3b43481SJianfeng Tan int hdr_size; 342e3b43481SJianfeng Tan int vhostfd; 343e3b43481SJianfeng Tan int tapfd; 344be7a4707SJianfeng Tan int req_mq = (dev->max_queue_pairs > 1); 345e3b43481SJianfeng Tan 346e3b43481SJianfeng Tan vhostfd = dev->vhostfds[pair_idx]; 347e3b43481SJianfeng Tan 34847ac9661STiwei Bie if (dev->qp_enabled[pair_idx] == enable) 349e3b43481SJianfeng Tan return 0; 35047ac9661STiwei Bie 35147ac9661STiwei Bie if (!enable) { 35247ac9661STiwei Bie tapfd = dev->tapfds[pair_idx]; 35347ac9661STiwei Bie if (vhost_kernel_set_backend(vhostfd, -1) < 0) { 35447ac9661STiwei Bie PMD_DRV_LOG(ERR, "fail to set backend for vhost kernel"); 35547ac9661STiwei Bie return -1; 35647ac9661STiwei Bie } 35747ac9661STiwei Bie if (req_mq && vhost_kernel_tap_set_queue(tapfd, false) < 0) { 35847ac9661STiwei Bie PMD_DRV_LOG(ERR, "fail to disable tap for vhost kernel"); 35947ac9661STiwei Bie return -1; 36047ac9661STiwei Bie } 36147ac9661STiwei Bie dev->qp_enabled[pair_idx] = false; 36247ac9661STiwei Bie return 0; 36347ac9661STiwei Bie } 36447ac9661STiwei Bie 36547ac9661STiwei Bie if (dev->tapfds[pair_idx] >= 0) { 36647ac9661STiwei Bie tapfd = dev->tapfds[pair_idx]; 36747ac9661STiwei Bie if (vhost_kernel_tap_set_offload(tapfd, dev->features) == -1) 36847ac9661STiwei Bie return -1; 36947ac9661STiwei Bie if (req_mq && vhost_kernel_tap_set_queue(tapfd, true) < 0) { 37047ac9661STiwei Bie PMD_DRV_LOG(ERR, "fail to enable tap for vhost kernel"); 37147ac9661STiwei Bie return -1; 37247ac9661STiwei Bie } 37347ac9661STiwei Bie goto set_backend; 374e3b43481SJianfeng Tan } 375e3b43481SJianfeng Tan 376e3b43481SJianfeng Tan if ((dev->features & (1ULL << VIRTIO_NET_F_MRG_RXBUF)) || 377e3b43481SJianfeng Tan (dev->features & (1ULL << VIRTIO_F_VERSION_1))) 378e3b43481SJianfeng Tan hdr_size = sizeof(struct virtio_net_hdr_mrg_rxbuf); 379e3b43481SJianfeng Tan else 380e3b43481SJianfeng Tan hdr_size = sizeof(struct virtio_net_hdr); 381e3b43481SJianfeng Tan 382791b43e0SNing Li tapfd = vhost_kernel_open_tap(&dev->ifname, hdr_size, req_mq, 3831db4d233SEric Zhang (char *)dev->mac_addr, dev->features); 384e3b43481SJianfeng Tan if (tapfd < 0) { 385e3b43481SJianfeng Tan PMD_DRV_LOG(ERR, "fail to open tap for vhost kernel"); 386e3b43481SJianfeng Tan return -1; 387e3b43481SJianfeng Tan } 388e3b43481SJianfeng Tan 38947ac9661STiwei Bie dev->tapfds[pair_idx] = tapfd; 39047ac9661STiwei Bie 39147ac9661STiwei Bie set_backend: 392e3b43481SJianfeng Tan if (vhost_kernel_set_backend(vhostfd, tapfd) < 0) { 393e3b43481SJianfeng Tan PMD_DRV_LOG(ERR, "fail to set backend for vhost kernel"); 394e3b43481SJianfeng Tan return -1; 395e3b43481SJianfeng Tan } 396e3b43481SJianfeng Tan 39747ac9661STiwei Bie dev->qp_enabled[pair_idx] = true; 398e3b43481SJianfeng Tan return 0; 399e3b43481SJianfeng Tan } 400e3b43481SJianfeng Tan 401520dd992SFerruh Yigit struct virtio_user_backend_ops virtio_ops_kernel = { 402e3b43481SJianfeng Tan .setup = vhost_kernel_setup, 40306856cabSMaxime Coquelin .set_owner = vhost_kernel_set_owner, 404*cc0151b3SMaxime Coquelin .get_features = vhost_kernel_get_features, 405*cc0151b3SMaxime Coquelin .set_features = vhost_kernel_set_features, 40606856cabSMaxime Coquelin .send_request = vhost_kernel_send_request, 407e3b43481SJianfeng Tan .enable_qp = vhost_kernel_enable_queue_pair 408e3b43481SJianfeng Tan }; 409