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 41cc0151b3SMaxime Coquelin /* with below features, vhost kernel does not need to do the checksum and TSO, 42cc0151b3SMaxime Coquelin * these info will be passed to virtio_user through virtio net header. 43cc0151b3SMaxime Coquelin */ 44cc0151b3SMaxime Coquelin #define VHOST_KERNEL_GUEST_OFFLOADS_MASK \ 45cc0151b3SMaxime Coquelin ((1ULL << VIRTIO_NET_F_GUEST_CSUM) | \ 46cc0151b3SMaxime Coquelin (1ULL << VIRTIO_NET_F_GUEST_TSO4) | \ 47cc0151b3SMaxime Coquelin (1ULL << VIRTIO_NET_F_GUEST_TSO6) | \ 48cc0151b3SMaxime Coquelin (1ULL << VIRTIO_NET_F_GUEST_ECN) | \ 49cc0151b3SMaxime Coquelin (1ULL << VIRTIO_NET_F_GUEST_UFO)) 50cc0151b3SMaxime Coquelin 51cc0151b3SMaxime Coquelin /* with below features, when flows from virtio_user to vhost kernel 52cc0151b3SMaxime Coquelin * (1) if flows goes up through the kernel networking stack, it does not need 53cc0151b3SMaxime Coquelin * to verify checksum, which can save CPU cycles; 54cc0151b3SMaxime Coquelin * (2) if flows goes through a Linux bridge and outside from an interface 55cc0151b3SMaxime Coquelin * (kernel driver), checksum and TSO will be done by GSO in kernel or even 56cc0151b3SMaxime Coquelin * offloaded into real physical device. 57cc0151b3SMaxime Coquelin */ 58cc0151b3SMaxime Coquelin #define VHOST_KERNEL_HOST_OFFLOADS_MASK \ 59cc0151b3SMaxime Coquelin ((1ULL << VIRTIO_NET_F_HOST_TSO4) | \ 60cc0151b3SMaxime Coquelin (1ULL << VIRTIO_NET_F_HOST_TSO6) | \ 61cc0151b3SMaxime Coquelin (1ULL << VIRTIO_NET_F_CSUM)) 62cc0151b3SMaxime 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 102cc0151b3SMaxime Coquelin static int 103cc0151b3SMaxime Coquelin vhost_kernel_get_features(struct virtio_user_dev *dev, uint64_t *features) 104cc0151b3SMaxime Coquelin { 105cc0151b3SMaxime Coquelin int ret; 106cc0151b3SMaxime Coquelin unsigned int tap_features; 107cc0151b3SMaxime Coquelin 108cc0151b3SMaxime Coquelin ret = vhost_kernel_ioctl(dev->vhostfds[0], VHOST_GET_FEATURES, features); 109cc0151b3SMaxime Coquelin if (ret < 0) { 110cc0151b3SMaxime Coquelin PMD_DRV_LOG(ERR, "Failed to get features"); 111cc0151b3SMaxime Coquelin return -1; 112cc0151b3SMaxime Coquelin } 113cc0151b3SMaxime Coquelin 114cc0151b3SMaxime Coquelin ret = tap_support_features(&tap_features); 115cc0151b3SMaxime Coquelin if (ret < 0) { 116cc0151b3SMaxime Coquelin PMD_DRV_LOG(ERR, "Failed to get TAP features"); 117cc0151b3SMaxime Coquelin return -1; 118cc0151b3SMaxime Coquelin } 119cc0151b3SMaxime Coquelin 120cc0151b3SMaxime Coquelin /* with tap as the backend, all these features are supported 121cc0151b3SMaxime Coquelin * but not claimed by vhost-net, so we add them back when 122cc0151b3SMaxime Coquelin * reporting to upper layer. 123cc0151b3SMaxime Coquelin */ 124cc0151b3SMaxime Coquelin if (tap_features & IFF_VNET_HDR) { 125cc0151b3SMaxime Coquelin *features |= VHOST_KERNEL_GUEST_OFFLOADS_MASK; 126cc0151b3SMaxime Coquelin *features |= VHOST_KERNEL_HOST_OFFLOADS_MASK; 127cc0151b3SMaxime Coquelin } 128cc0151b3SMaxime Coquelin 129cc0151b3SMaxime Coquelin /* vhost_kernel will not declare this feature, but it does 130cc0151b3SMaxime Coquelin * support multi-queue. 131cc0151b3SMaxime Coquelin */ 132cc0151b3SMaxime Coquelin if (tap_features & IFF_MULTI_QUEUE) 133cc0151b3SMaxime Coquelin *features |= (1ull << VIRTIO_NET_F_MQ); 134cc0151b3SMaxime Coquelin 135cc0151b3SMaxime Coquelin return 0; 136cc0151b3SMaxime Coquelin } 137cc0151b3SMaxime Coquelin 138cc0151b3SMaxime Coquelin static int 139cc0151b3SMaxime Coquelin vhost_kernel_set_features(struct virtio_user_dev *dev, uint64_t features) 140cc0151b3SMaxime Coquelin { 141cc0151b3SMaxime Coquelin /* We don't need memory protection here */ 142cc0151b3SMaxime Coquelin features &= ~(1ULL << VIRTIO_F_IOMMU_PLATFORM); 143cc0151b3SMaxime Coquelin /* VHOST kernel does not know about below flags */ 144cc0151b3SMaxime Coquelin features &= ~VHOST_KERNEL_GUEST_OFFLOADS_MASK; 145cc0151b3SMaxime Coquelin features &= ~VHOST_KERNEL_HOST_OFFLOADS_MASK; 146cc0151b3SMaxime Coquelin features &= ~(1ULL << VIRTIO_NET_F_MQ); 147cc0151b3SMaxime Coquelin 148cc0151b3SMaxime Coquelin return vhost_kernel_ioctl(dev->vhostfds[0], VHOST_SET_FEATURES, &features); 149cc0151b3SMaxime Coquelin } 150cc0151b3SMaxime Coquelin 151746c346dSAnatoly Burakov static int 15275728654STiwei Bie add_memseg_list(const struct rte_memseg_list *msl, void *arg) 153746c346dSAnatoly Burakov { 15475728654STiwei Bie struct vhost_memory_kernel *vm = arg; 155746c346dSAnatoly Burakov struct vhost_memory_region *mr; 156746c346dSAnatoly Burakov void *start_addr; 15775728654STiwei Bie uint64_t len; 158746c346dSAnatoly Burakov 1595282bb1cSAnatoly Burakov if (msl->external) 1605282bb1cSAnatoly Burakov return 0; 1615282bb1cSAnatoly Burakov 16275728654STiwei Bie if (vm->nregions >= max_regions) 163746c346dSAnatoly Burakov return -1; 164746c346dSAnatoly Burakov 16575728654STiwei Bie start_addr = msl->base_va; 16675728654STiwei Bie len = msl->page_sz * msl->memseg_arr.len; 16775728654STiwei Bie 16875728654STiwei Bie mr = &vm->regions[vm->nregions++]; 169746c346dSAnatoly Burakov 170746c346dSAnatoly Burakov mr->guest_phys_addr = (uint64_t)(uintptr_t)start_addr; 171746c346dSAnatoly Burakov mr->userspace_addr = (uint64_t)(uintptr_t)start_addr; 172746c346dSAnatoly Burakov mr->memory_size = len; 17375728654STiwei Bie mr->mmap_offset = 0; /* flags_padding */ 17475728654STiwei Bie 17575728654STiwei Bie PMD_DRV_LOG(DEBUG, "index=%u addr=%p len=%" PRIu64, 17675728654STiwei Bie vm->nregions - 1, start_addr, len); 177746c346dSAnatoly Burakov 178746c346dSAnatoly Burakov return 0; 179746c346dSAnatoly Burakov } 180746c346dSAnatoly Burakov 18175728654STiwei Bie /* By default, vhost kernel module allows 64 regions, but DPDK may 18275728654STiwei Bie * have much more memory regions. Below function will treat each 18375728654STiwei Bie * contiguous memory space reserved by DPDK as one region. 184e3b43481SJianfeng Tan */ 185*539d910cSMaxime Coquelin static int 186*539d910cSMaxime Coquelin vhost_kernel_set_memory_table(struct virtio_user_dev *dev) 187e3b43481SJianfeng Tan { 188e3b43481SJianfeng Tan struct vhost_memory_kernel *vm; 189*539d910cSMaxime Coquelin int ret; 190e3b43481SJianfeng Tan 191e3b43481SJianfeng Tan vm = malloc(sizeof(struct vhost_memory_kernel) + 192e3b43481SJianfeng Tan max_regions * 193e3b43481SJianfeng Tan sizeof(struct vhost_memory_region)); 1941e9057a9SJianfeng Tan if (!vm) 195*539d910cSMaxime Coquelin goto err; 196e3b43481SJianfeng Tan 19775728654STiwei Bie vm->nregions = 0; 19875728654STiwei Bie vm->padding = 0; 199e3b43481SJianfeng Tan 2007ff26957STiwei Bie /* 2017ff26957STiwei Bie * The memory lock has already been taken by memory subsystem 2027ff26957STiwei Bie * or virtio_user_start_device(). 2037ff26957STiwei Bie */ 204*539d910cSMaxime Coquelin ret = rte_memseg_list_walk_thread_unsafe(add_memseg_list, vm); 205*539d910cSMaxime Coquelin if (ret < 0) 206*539d910cSMaxime Coquelin goto err_free; 207*539d910cSMaxime Coquelin 208*539d910cSMaxime Coquelin ret = vhost_kernel_ioctl(dev->vhostfds[0], VHOST_SET_MEM_TABLE, vm); 209*539d910cSMaxime Coquelin if (ret < 0) 210*539d910cSMaxime Coquelin goto err_free; 211*539d910cSMaxime Coquelin 212e3b43481SJianfeng Tan free(vm); 213*539d910cSMaxime Coquelin 214*539d910cSMaxime Coquelin return 0; 215*539d910cSMaxime Coquelin err_free: 216*539d910cSMaxime Coquelin free(vm); 217*539d910cSMaxime Coquelin err: 218*539d910cSMaxime Coquelin PMD_DRV_LOG(ERR, "Failed to set memory table"); 219*539d910cSMaxime Coquelin return -1; 220e3b43481SJianfeng Tan } 221e3b43481SJianfeng Tan 222*539d910cSMaxime Coquelin static uint64_t vhost_req_user_to_kernel[] = { 223*539d910cSMaxime Coquelin [VHOST_USER_RESET_OWNER] = VHOST_RESET_OWNER, 224*539d910cSMaxime Coquelin [VHOST_USER_SET_VRING_CALL] = VHOST_SET_VRING_CALL, 225*539d910cSMaxime Coquelin [VHOST_USER_SET_VRING_NUM] = VHOST_SET_VRING_NUM, 226*539d910cSMaxime Coquelin [VHOST_USER_SET_VRING_BASE] = VHOST_SET_VRING_BASE, 227*539d910cSMaxime Coquelin [VHOST_USER_GET_VRING_BASE] = VHOST_GET_VRING_BASE, 228*539d910cSMaxime Coquelin [VHOST_USER_SET_VRING_ADDR] = VHOST_SET_VRING_ADDR, 229*539d910cSMaxime Coquelin [VHOST_USER_SET_VRING_KICK] = VHOST_SET_VRING_KICK, 230*539d910cSMaxime Coquelin }; 231e3b43481SJianfeng Tan 232be7a4707SJianfeng Tan static int 23306856cabSMaxime Coquelin vhost_kernel_send_request(struct virtio_user_dev *dev, 234e3b43481SJianfeng Tan enum vhost_user_request req, 235e3b43481SJianfeng Tan void *arg) 236e3b43481SJianfeng Tan { 237e3b43481SJianfeng Tan int ret = -1; 238e3b43481SJianfeng Tan unsigned int i; 239e3b43481SJianfeng Tan uint64_t req_kernel; 240be7a4707SJianfeng Tan int vhostfd; 241be7a4707SJianfeng Tan unsigned int queue_sel; 242e3b43481SJianfeng Tan 243e3b43481SJianfeng Tan PMD_DRV_LOG(INFO, "%s", vhost_msg_strings[req]); 244e3b43481SJianfeng Tan 245e3b43481SJianfeng Tan req_kernel = vhost_req_user_to_kernel[req]; 246e3b43481SJianfeng Tan 247be7a4707SJianfeng Tan switch (req_kernel) { 248be7a4707SJianfeng Tan case VHOST_SET_VRING_NUM: 249be7a4707SJianfeng Tan case VHOST_SET_VRING_ADDR: 250be7a4707SJianfeng Tan case VHOST_SET_VRING_BASE: 251be7a4707SJianfeng Tan case VHOST_GET_VRING_BASE: 252be7a4707SJianfeng Tan case VHOST_SET_VRING_KICK: 253be7a4707SJianfeng Tan case VHOST_SET_VRING_CALL: 254be7a4707SJianfeng Tan queue_sel = *(unsigned int *)arg; 255be7a4707SJianfeng Tan vhostfd = dev->vhostfds[queue_sel / 2]; 256be7a4707SJianfeng Tan *(unsigned int *)arg = queue_sel % 2; 257be7a4707SJianfeng Tan PMD_DRV_LOG(DEBUG, "vhostfd=%d, index=%u", 258be7a4707SJianfeng Tan vhostfd, *(unsigned int *)arg); 259be7a4707SJianfeng Tan break; 260be7a4707SJianfeng Tan default: 261be7a4707SJianfeng Tan vhostfd = -1; 262be7a4707SJianfeng Tan } 263be7a4707SJianfeng Tan if (vhostfd == -1) { 264e3b43481SJianfeng Tan for (i = 0; i < dev->max_queue_pairs; ++i) { 265e3b43481SJianfeng Tan if (dev->vhostfds[i] < 0) 266e3b43481SJianfeng Tan continue; 267e3b43481SJianfeng Tan 268e3b43481SJianfeng Tan ret = ioctl(dev->vhostfds[i], req_kernel, arg); 269e3b43481SJianfeng Tan if (ret < 0) 270e3b43481SJianfeng Tan break; 271e3b43481SJianfeng Tan } 272be7a4707SJianfeng Tan } else { 273be7a4707SJianfeng Tan ret = ioctl(vhostfd, req_kernel, arg); 274be7a4707SJianfeng Tan } 275e3b43481SJianfeng Tan 276e3b43481SJianfeng Tan if (ret < 0) 277e3b43481SJianfeng Tan PMD_DRV_LOG(ERR, "%s failed: %s", 278e3b43481SJianfeng Tan vhost_msg_strings[req], strerror(errno)); 279e3b43481SJianfeng Tan 280e3b43481SJianfeng Tan return ret; 281e3b43481SJianfeng Tan } 282e3b43481SJianfeng Tan 283e3b43481SJianfeng Tan /** 284e3b43481SJianfeng Tan * Set up environment to talk with a vhost kernel backend. 285e3b43481SJianfeng Tan * 286e3b43481SJianfeng Tan * @return 287e3b43481SJianfeng Tan * - (-1) if fail to set up; 288e3b43481SJianfeng Tan * - (>=0) if successful. 289e3b43481SJianfeng Tan */ 290e3b43481SJianfeng Tan static int 291e3b43481SJianfeng Tan vhost_kernel_setup(struct virtio_user_dev *dev) 292e3b43481SJianfeng Tan { 293e3b43481SJianfeng Tan int vhostfd; 294e3b43481SJianfeng Tan uint32_t i; 295e3b43481SJianfeng Tan 296e3b43481SJianfeng Tan get_vhost_kernel_max_regions(); 297e3b43481SJianfeng Tan 298e3b43481SJianfeng Tan for (i = 0; i < dev->max_queue_pairs; ++i) { 299e3b43481SJianfeng Tan vhostfd = open(dev->path, O_RDWR); 300e3b43481SJianfeng Tan if (vhostfd < 0) { 301e3b43481SJianfeng Tan PMD_DRV_LOG(ERR, "fail to open %s, %s", 302e3b43481SJianfeng Tan dev->path, strerror(errno)); 303e3b43481SJianfeng Tan return -1; 304e3b43481SJianfeng Tan } 305e3b43481SJianfeng Tan 306e3b43481SJianfeng Tan dev->vhostfds[i] = vhostfd; 307e3b43481SJianfeng Tan } 308e3b43481SJianfeng Tan 309e3b43481SJianfeng Tan return 0; 310e3b43481SJianfeng Tan } 311e3b43481SJianfeng Tan 312e3b43481SJianfeng Tan static int 313e3b43481SJianfeng Tan vhost_kernel_set_backend(int vhostfd, int tapfd) 314e3b43481SJianfeng Tan { 315e3b43481SJianfeng Tan struct vhost_vring_file f; 316e3b43481SJianfeng Tan 317e3b43481SJianfeng Tan f.fd = tapfd; 318e3b43481SJianfeng Tan f.index = 0; 319e3b43481SJianfeng Tan if (ioctl(vhostfd, VHOST_NET_SET_BACKEND, &f) < 0) { 320e3b43481SJianfeng Tan PMD_DRV_LOG(ERR, "VHOST_NET_SET_BACKEND fails, %s", 321e3b43481SJianfeng Tan strerror(errno)); 322e3b43481SJianfeng Tan return -1; 323e3b43481SJianfeng Tan } 324e3b43481SJianfeng Tan 325e3b43481SJianfeng Tan f.index = 1; 326e3b43481SJianfeng Tan if (ioctl(vhostfd, VHOST_NET_SET_BACKEND, &f) < 0) { 327e3b43481SJianfeng Tan PMD_DRV_LOG(ERR, "VHOST_NET_SET_BACKEND fails, %s", 328e3b43481SJianfeng Tan strerror(errno)); 329e3b43481SJianfeng Tan return -1; 330e3b43481SJianfeng Tan } 331e3b43481SJianfeng Tan 332e3b43481SJianfeng Tan return 0; 333e3b43481SJianfeng Tan } 334e3b43481SJianfeng Tan 335e3b43481SJianfeng Tan static int 336e3b43481SJianfeng Tan vhost_kernel_enable_queue_pair(struct virtio_user_dev *dev, 337e3b43481SJianfeng Tan uint16_t pair_idx, 338e3b43481SJianfeng Tan int enable) 339e3b43481SJianfeng Tan { 340e3b43481SJianfeng Tan int hdr_size; 341e3b43481SJianfeng Tan int vhostfd; 342e3b43481SJianfeng Tan int tapfd; 343be7a4707SJianfeng Tan int req_mq = (dev->max_queue_pairs > 1); 344e3b43481SJianfeng Tan 345e3b43481SJianfeng Tan vhostfd = dev->vhostfds[pair_idx]; 346e3b43481SJianfeng Tan 34747ac9661STiwei Bie if (dev->qp_enabled[pair_idx] == enable) 348e3b43481SJianfeng Tan return 0; 34947ac9661STiwei Bie 35047ac9661STiwei Bie if (!enable) { 35147ac9661STiwei Bie tapfd = dev->tapfds[pair_idx]; 35247ac9661STiwei Bie if (vhost_kernel_set_backend(vhostfd, -1) < 0) { 35347ac9661STiwei Bie PMD_DRV_LOG(ERR, "fail to set backend for vhost kernel"); 35447ac9661STiwei Bie return -1; 35547ac9661STiwei Bie } 35647ac9661STiwei Bie if (req_mq && vhost_kernel_tap_set_queue(tapfd, false) < 0) { 35747ac9661STiwei Bie PMD_DRV_LOG(ERR, "fail to disable tap for vhost kernel"); 35847ac9661STiwei Bie return -1; 35947ac9661STiwei Bie } 36047ac9661STiwei Bie dev->qp_enabled[pair_idx] = false; 36147ac9661STiwei Bie return 0; 36247ac9661STiwei Bie } 36347ac9661STiwei Bie 36447ac9661STiwei Bie if (dev->tapfds[pair_idx] >= 0) { 36547ac9661STiwei Bie tapfd = dev->tapfds[pair_idx]; 36647ac9661STiwei Bie if (vhost_kernel_tap_set_offload(tapfd, dev->features) == -1) 36747ac9661STiwei Bie return -1; 36847ac9661STiwei Bie if (req_mq && vhost_kernel_tap_set_queue(tapfd, true) < 0) { 36947ac9661STiwei Bie PMD_DRV_LOG(ERR, "fail to enable tap for vhost kernel"); 37047ac9661STiwei Bie return -1; 37147ac9661STiwei Bie } 37247ac9661STiwei Bie goto set_backend; 373e3b43481SJianfeng Tan } 374e3b43481SJianfeng Tan 375e3b43481SJianfeng Tan if ((dev->features & (1ULL << VIRTIO_NET_F_MRG_RXBUF)) || 376e3b43481SJianfeng Tan (dev->features & (1ULL << VIRTIO_F_VERSION_1))) 377e3b43481SJianfeng Tan hdr_size = sizeof(struct virtio_net_hdr_mrg_rxbuf); 378e3b43481SJianfeng Tan else 379e3b43481SJianfeng Tan hdr_size = sizeof(struct virtio_net_hdr); 380e3b43481SJianfeng Tan 381791b43e0SNing Li tapfd = vhost_kernel_open_tap(&dev->ifname, hdr_size, req_mq, 3821db4d233SEric Zhang (char *)dev->mac_addr, dev->features); 383e3b43481SJianfeng Tan if (tapfd < 0) { 384e3b43481SJianfeng Tan PMD_DRV_LOG(ERR, "fail to open tap for vhost kernel"); 385e3b43481SJianfeng Tan return -1; 386e3b43481SJianfeng Tan } 387e3b43481SJianfeng Tan 38847ac9661STiwei Bie dev->tapfds[pair_idx] = tapfd; 38947ac9661STiwei Bie 39047ac9661STiwei Bie set_backend: 391e3b43481SJianfeng Tan if (vhost_kernel_set_backend(vhostfd, tapfd) < 0) { 392e3b43481SJianfeng Tan PMD_DRV_LOG(ERR, "fail to set backend for vhost kernel"); 393e3b43481SJianfeng Tan return -1; 394e3b43481SJianfeng Tan } 395e3b43481SJianfeng Tan 39647ac9661STiwei Bie dev->qp_enabled[pair_idx] = true; 397e3b43481SJianfeng Tan return 0; 398e3b43481SJianfeng Tan } 399e3b43481SJianfeng Tan 400520dd992SFerruh Yigit struct virtio_user_backend_ops virtio_ops_kernel = { 401e3b43481SJianfeng Tan .setup = vhost_kernel_setup, 40206856cabSMaxime Coquelin .set_owner = vhost_kernel_set_owner, 403cc0151b3SMaxime Coquelin .get_features = vhost_kernel_get_features, 404cc0151b3SMaxime Coquelin .set_features = vhost_kernel_set_features, 405*539d910cSMaxime Coquelin .set_memory_table = vhost_kernel_set_memory_table, 40606856cabSMaxime Coquelin .send_request = vhost_kernel_send_request, 407e3b43481SJianfeng Tan .enable_qp = vhost_kernel_enable_queue_pair 408e3b43481SJianfeng Tan }; 409