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 */ 185539d910cSMaxime Coquelin static int 186539d910cSMaxime Coquelin vhost_kernel_set_memory_table(struct virtio_user_dev *dev) 187e3b43481SJianfeng Tan { 188e3b43481SJianfeng Tan struct vhost_memory_kernel *vm; 189539d910cSMaxime 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) 195539d910cSMaxime 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 */ 204539d910cSMaxime Coquelin ret = rte_memseg_list_walk_thread_unsafe(add_memseg_list, vm); 205539d910cSMaxime Coquelin if (ret < 0) 206539d910cSMaxime Coquelin goto err_free; 207539d910cSMaxime Coquelin 208539d910cSMaxime Coquelin ret = vhost_kernel_ioctl(dev->vhostfds[0], VHOST_SET_MEM_TABLE, vm); 209539d910cSMaxime Coquelin if (ret < 0) 210539d910cSMaxime Coquelin goto err_free; 211539d910cSMaxime Coquelin 212e3b43481SJianfeng Tan free(vm); 213539d910cSMaxime Coquelin 214539d910cSMaxime Coquelin return 0; 215539d910cSMaxime Coquelin err_free: 216539d910cSMaxime Coquelin free(vm); 217539d910cSMaxime Coquelin err: 218539d910cSMaxime Coquelin PMD_DRV_LOG(ERR, "Failed to set memory table"); 219539d910cSMaxime Coquelin return -1; 220e3b43481SJianfeng Tan } 221e3b43481SJianfeng Tan 222ab9098d2SMaxime Coquelin static int 223ab9098d2SMaxime Coquelin vhost_kernel_set_vring(struct virtio_user_dev *dev, uint64_t req, struct vhost_vring_state *state) 224ab9098d2SMaxime Coquelin { 225ab9098d2SMaxime Coquelin int ret, fd; 226ab9098d2SMaxime Coquelin unsigned int index = state->index; 227ab9098d2SMaxime Coquelin 228ab9098d2SMaxime Coquelin /* Convert from queue index to queue-pair & offset */ 229ab9098d2SMaxime Coquelin fd = dev->vhostfds[state->index / 2]; 230ab9098d2SMaxime Coquelin state->index %= 2; 231ab9098d2SMaxime Coquelin 232ab9098d2SMaxime Coquelin ret = vhost_kernel_ioctl(fd, req, state); 233ab9098d2SMaxime Coquelin if (ret < 0) { 234ab9098d2SMaxime Coquelin PMD_DRV_LOG(ERR, "Failed to set vring (request %" PRIu64 ")", req); 235ab9098d2SMaxime Coquelin return -1; 236ab9098d2SMaxime Coquelin } 237ab9098d2SMaxime Coquelin 238ab9098d2SMaxime Coquelin /* restore index back to queue index */ 239ab9098d2SMaxime Coquelin state->index = index; 240ab9098d2SMaxime Coquelin 241ab9098d2SMaxime Coquelin return 0; 242ab9098d2SMaxime Coquelin } 243ab9098d2SMaxime Coquelin 244ab9098d2SMaxime Coquelin static int 245ab9098d2SMaxime Coquelin vhost_kernel_set_vring_num(struct virtio_user_dev *dev, struct vhost_vring_state *state) 246ab9098d2SMaxime Coquelin { 247ab9098d2SMaxime Coquelin return vhost_kernel_set_vring(dev, VHOST_SET_VRING_NUM, state); 248ab9098d2SMaxime Coquelin } 249ab9098d2SMaxime Coquelin 250ab9098d2SMaxime Coquelin static int 251ab9098d2SMaxime Coquelin vhost_kernel_set_vring_base(struct virtio_user_dev *dev, struct vhost_vring_state *state) 252ab9098d2SMaxime Coquelin { 253ab9098d2SMaxime Coquelin return vhost_kernel_set_vring(dev, VHOST_SET_VRING_BASE, state); 254ab9098d2SMaxime Coquelin } 255ab9098d2SMaxime Coquelin 256ab9098d2SMaxime Coquelin static int 257ab9098d2SMaxime Coquelin vhost_kernel_get_vring_base(struct virtio_user_dev *dev, struct vhost_vring_state *state) 258ab9098d2SMaxime Coquelin { 259ab9098d2SMaxime Coquelin return vhost_kernel_set_vring(dev, VHOST_GET_VRING_BASE, state); 260ab9098d2SMaxime Coquelin } 261ab9098d2SMaxime Coquelin 262ce399c36SMaxime Coquelin static int 263ce399c36SMaxime Coquelin vhost_kernel_set_vring_file(struct virtio_user_dev *dev, uint64_t req, 264ce399c36SMaxime Coquelin struct vhost_vring_file *file) 265ce399c36SMaxime Coquelin { 266ce399c36SMaxime Coquelin int ret, fd; 267ce399c36SMaxime Coquelin unsigned int index = file->index; 268ce399c36SMaxime Coquelin 269ce399c36SMaxime Coquelin /* Convert from queue index to queue-pair & offset */ 270ce399c36SMaxime Coquelin fd = dev->vhostfds[file->index / 2]; 271ce399c36SMaxime Coquelin file->index %= 2; 272ce399c36SMaxime Coquelin 273ce399c36SMaxime Coquelin ret = vhost_kernel_ioctl(fd, req, file); 274ce399c36SMaxime Coquelin if (ret < 0) { 275ce399c36SMaxime Coquelin PMD_DRV_LOG(ERR, "Failed to set vring file (request %" PRIu64 ")", req); 276ce399c36SMaxime Coquelin return -1; 277ce399c36SMaxime Coquelin } 278ce399c36SMaxime Coquelin 279ce399c36SMaxime Coquelin /* restore index back to queue index */ 280ce399c36SMaxime Coquelin file->index = index; 281ce399c36SMaxime Coquelin 282ce399c36SMaxime Coquelin return 0; 283ce399c36SMaxime Coquelin } 284ce399c36SMaxime Coquelin 285ce399c36SMaxime Coquelin static int 286ce399c36SMaxime Coquelin vhost_kernel_set_vring_kick(struct virtio_user_dev *dev, struct vhost_vring_file *file) 287ce399c36SMaxime Coquelin { 288ce399c36SMaxime Coquelin return vhost_kernel_set_vring_file(dev, VHOST_SET_VRING_KICK, file); 289ce399c36SMaxime Coquelin } 290ce399c36SMaxime Coquelin 291ce399c36SMaxime Coquelin static int 292ce399c36SMaxime Coquelin vhost_kernel_set_vring_call(struct virtio_user_dev *dev, struct vhost_vring_file *file) 293ce399c36SMaxime Coquelin { 294ce399c36SMaxime Coquelin return vhost_kernel_set_vring_file(dev, VHOST_SET_VRING_CALL, file); 295ce399c36SMaxime Coquelin } 296ce399c36SMaxime Coquelin 297dc65db73SMaxime Coquelin static int 298dc65db73SMaxime Coquelin vhost_kernel_set_vring_addr(struct virtio_user_dev *dev, struct vhost_vring_addr *addr) 299dc65db73SMaxime Coquelin { 300dc65db73SMaxime Coquelin int ret, fd; 301dc65db73SMaxime Coquelin unsigned int index = addr->index; 302dc65db73SMaxime Coquelin 303dc65db73SMaxime Coquelin /* Convert from queue index to queue-pair & offset */ 304dc65db73SMaxime Coquelin fd = dev->vhostfds[addr->index / 2]; 305dc65db73SMaxime Coquelin addr->index %= 2; 306dc65db73SMaxime Coquelin 307dc65db73SMaxime Coquelin ret = vhost_kernel_ioctl(fd, VHOST_SET_VRING_ADDR, addr); 308dc65db73SMaxime Coquelin if (ret < 0) { 309dc65db73SMaxime Coquelin PMD_DRV_LOG(ERR, "Failed to set vring address"); 310dc65db73SMaxime Coquelin return -1; 311dc65db73SMaxime Coquelin } 312dc65db73SMaxime Coquelin 313dc65db73SMaxime Coquelin /* restore index back to queue index */ 314dc65db73SMaxime Coquelin addr->index = index; 315dc65db73SMaxime Coquelin 316dc65db73SMaxime Coquelin return 0; 317dc65db73SMaxime Coquelin } 318dc65db73SMaxime Coquelin 3198723c894SMaxime Coquelin static int 3208723c894SMaxime Coquelin vhost_kernel_get_status(struct virtio_user_dev *dev __rte_unused, uint8_t *status __rte_unused) 3218723c894SMaxime Coquelin { 3228723c894SMaxime Coquelin return -ENOTSUP; 3238723c894SMaxime Coquelin } 3248723c894SMaxime Coquelin 3258723c894SMaxime Coquelin static int 3268723c894SMaxime Coquelin vhost_kernel_set_status(struct virtio_user_dev *dev __rte_unused, uint8_t status __rte_unused) 3278723c894SMaxime Coquelin { 3288723c894SMaxime Coquelin return -ENOTSUP; 3298723c894SMaxime Coquelin } 3308723c894SMaxime Coquelin 331e3b43481SJianfeng Tan /** 332e3b43481SJianfeng Tan * Set up environment to talk with a vhost kernel backend. 333e3b43481SJianfeng Tan * 334e3b43481SJianfeng Tan * @return 335e3b43481SJianfeng Tan * - (-1) if fail to set up; 336e3b43481SJianfeng Tan * - (>=0) if successful. 337e3b43481SJianfeng Tan */ 338e3b43481SJianfeng Tan static int 339e3b43481SJianfeng Tan vhost_kernel_setup(struct virtio_user_dev *dev) 340e3b43481SJianfeng Tan { 341e3b43481SJianfeng Tan int vhostfd; 342e3b43481SJianfeng Tan uint32_t i; 343e3b43481SJianfeng Tan 344e3b43481SJianfeng Tan get_vhost_kernel_max_regions(); 345e3b43481SJianfeng Tan 346e3b43481SJianfeng Tan for (i = 0; i < dev->max_queue_pairs; ++i) { 347e3b43481SJianfeng Tan vhostfd = open(dev->path, O_RDWR); 348e3b43481SJianfeng Tan if (vhostfd < 0) { 349e3b43481SJianfeng Tan PMD_DRV_LOG(ERR, "fail to open %s, %s", 350e3b43481SJianfeng Tan dev->path, strerror(errno)); 351e3b43481SJianfeng Tan return -1; 352e3b43481SJianfeng Tan } 353e3b43481SJianfeng Tan 354e3b43481SJianfeng Tan dev->vhostfds[i] = vhostfd; 355e3b43481SJianfeng Tan } 356e3b43481SJianfeng Tan 357e3b43481SJianfeng Tan return 0; 358e3b43481SJianfeng Tan } 359e3b43481SJianfeng Tan 360e3b43481SJianfeng Tan static int 361*748e5ea5SMaxime Coquelin vhost_kernel_destroy(struct virtio_user_dev *dev __rte_unused) 362*748e5ea5SMaxime Coquelin { 363*748e5ea5SMaxime Coquelin return 0; 364*748e5ea5SMaxime Coquelin } 365*748e5ea5SMaxime Coquelin 366*748e5ea5SMaxime Coquelin static int 367e3b43481SJianfeng Tan vhost_kernel_set_backend(int vhostfd, int tapfd) 368e3b43481SJianfeng Tan { 369e3b43481SJianfeng Tan struct vhost_vring_file f; 370e3b43481SJianfeng Tan 371e3b43481SJianfeng Tan f.fd = tapfd; 372e3b43481SJianfeng Tan f.index = 0; 373e3b43481SJianfeng Tan if (ioctl(vhostfd, VHOST_NET_SET_BACKEND, &f) < 0) { 374e3b43481SJianfeng Tan PMD_DRV_LOG(ERR, "VHOST_NET_SET_BACKEND fails, %s", 375e3b43481SJianfeng Tan strerror(errno)); 376e3b43481SJianfeng Tan return -1; 377e3b43481SJianfeng Tan } 378e3b43481SJianfeng Tan 379e3b43481SJianfeng Tan f.index = 1; 380e3b43481SJianfeng Tan if (ioctl(vhostfd, VHOST_NET_SET_BACKEND, &f) < 0) { 381e3b43481SJianfeng Tan PMD_DRV_LOG(ERR, "VHOST_NET_SET_BACKEND fails, %s", 382e3b43481SJianfeng Tan strerror(errno)); 383e3b43481SJianfeng Tan return -1; 384e3b43481SJianfeng Tan } 385e3b43481SJianfeng Tan 386e3b43481SJianfeng Tan return 0; 387e3b43481SJianfeng Tan } 388e3b43481SJianfeng Tan 389e3b43481SJianfeng Tan static int 390e3b43481SJianfeng Tan vhost_kernel_enable_queue_pair(struct virtio_user_dev *dev, 391e3b43481SJianfeng Tan uint16_t pair_idx, 392e3b43481SJianfeng Tan int enable) 393e3b43481SJianfeng Tan { 394e3b43481SJianfeng Tan int hdr_size; 395e3b43481SJianfeng Tan int vhostfd; 396e3b43481SJianfeng Tan int tapfd; 397be7a4707SJianfeng Tan int req_mq = (dev->max_queue_pairs > 1); 398e3b43481SJianfeng Tan 399e3b43481SJianfeng Tan vhostfd = dev->vhostfds[pair_idx]; 400e3b43481SJianfeng Tan 40147ac9661STiwei Bie if (dev->qp_enabled[pair_idx] == enable) 402e3b43481SJianfeng Tan return 0; 40347ac9661STiwei Bie 40447ac9661STiwei Bie if (!enable) { 40547ac9661STiwei Bie tapfd = dev->tapfds[pair_idx]; 40647ac9661STiwei Bie if (vhost_kernel_set_backend(vhostfd, -1) < 0) { 40747ac9661STiwei Bie PMD_DRV_LOG(ERR, "fail to set backend for vhost kernel"); 40847ac9661STiwei Bie return -1; 40947ac9661STiwei Bie } 41047ac9661STiwei Bie if (req_mq && vhost_kernel_tap_set_queue(tapfd, false) < 0) { 41147ac9661STiwei Bie PMD_DRV_LOG(ERR, "fail to disable tap for vhost kernel"); 41247ac9661STiwei Bie return -1; 41347ac9661STiwei Bie } 41447ac9661STiwei Bie dev->qp_enabled[pair_idx] = false; 41547ac9661STiwei Bie return 0; 41647ac9661STiwei Bie } 41747ac9661STiwei Bie 41847ac9661STiwei Bie if (dev->tapfds[pair_idx] >= 0) { 41947ac9661STiwei Bie tapfd = dev->tapfds[pair_idx]; 42047ac9661STiwei Bie if (vhost_kernel_tap_set_offload(tapfd, dev->features) == -1) 42147ac9661STiwei Bie return -1; 42247ac9661STiwei Bie if (req_mq && vhost_kernel_tap_set_queue(tapfd, true) < 0) { 42347ac9661STiwei Bie PMD_DRV_LOG(ERR, "fail to enable tap for vhost kernel"); 42447ac9661STiwei Bie return -1; 42547ac9661STiwei Bie } 42647ac9661STiwei Bie goto set_backend; 427e3b43481SJianfeng Tan } 428e3b43481SJianfeng Tan 429e3b43481SJianfeng Tan if ((dev->features & (1ULL << VIRTIO_NET_F_MRG_RXBUF)) || 430e3b43481SJianfeng Tan (dev->features & (1ULL << VIRTIO_F_VERSION_1))) 431e3b43481SJianfeng Tan hdr_size = sizeof(struct virtio_net_hdr_mrg_rxbuf); 432e3b43481SJianfeng Tan else 433e3b43481SJianfeng Tan hdr_size = sizeof(struct virtio_net_hdr); 434e3b43481SJianfeng Tan 435791b43e0SNing Li tapfd = vhost_kernel_open_tap(&dev->ifname, hdr_size, req_mq, 4361db4d233SEric Zhang (char *)dev->mac_addr, dev->features); 437e3b43481SJianfeng Tan if (tapfd < 0) { 438e3b43481SJianfeng Tan PMD_DRV_LOG(ERR, "fail to open tap for vhost kernel"); 439e3b43481SJianfeng Tan return -1; 440e3b43481SJianfeng Tan } 441e3b43481SJianfeng Tan 44247ac9661STiwei Bie dev->tapfds[pair_idx] = tapfd; 44347ac9661STiwei Bie 44447ac9661STiwei Bie set_backend: 445e3b43481SJianfeng Tan if (vhost_kernel_set_backend(vhostfd, tapfd) < 0) { 446e3b43481SJianfeng Tan PMD_DRV_LOG(ERR, "fail to set backend for vhost kernel"); 447e3b43481SJianfeng Tan return -1; 448e3b43481SJianfeng Tan } 449e3b43481SJianfeng Tan 45047ac9661STiwei Bie dev->qp_enabled[pair_idx] = true; 451e3b43481SJianfeng Tan return 0; 452e3b43481SJianfeng Tan } 453e3b43481SJianfeng Tan 4545b75b63cSMaxime Coquelin static int 4555b75b63cSMaxime Coquelin vhost_kernel_get_backend_features(uint64_t *features) 4565b75b63cSMaxime Coquelin { 4575b75b63cSMaxime Coquelin *features = 0; 4585b75b63cSMaxime Coquelin 4595b75b63cSMaxime Coquelin return 0; 4605b75b63cSMaxime Coquelin } 4615b75b63cSMaxime Coquelin 462520dd992SFerruh Yigit struct virtio_user_backend_ops virtio_ops_kernel = { 463e3b43481SJianfeng Tan .setup = vhost_kernel_setup, 464*748e5ea5SMaxime Coquelin .destroy = vhost_kernel_destroy, 4655b75b63cSMaxime Coquelin .get_backend_features = vhost_kernel_get_backend_features, 46606856cabSMaxime Coquelin .set_owner = vhost_kernel_set_owner, 467cc0151b3SMaxime Coquelin .get_features = vhost_kernel_get_features, 468cc0151b3SMaxime Coquelin .set_features = vhost_kernel_set_features, 469539d910cSMaxime Coquelin .set_memory_table = vhost_kernel_set_memory_table, 470ab9098d2SMaxime Coquelin .set_vring_num = vhost_kernel_set_vring_num, 471ab9098d2SMaxime Coquelin .set_vring_base = vhost_kernel_set_vring_base, 472ab9098d2SMaxime Coquelin .get_vring_base = vhost_kernel_get_vring_base, 473ce399c36SMaxime Coquelin .set_vring_call = vhost_kernel_set_vring_call, 474ce399c36SMaxime Coquelin .set_vring_kick = vhost_kernel_set_vring_kick, 475dc65db73SMaxime Coquelin .set_vring_addr = vhost_kernel_set_vring_addr, 4768723c894SMaxime Coquelin .get_status = vhost_kernel_get_status, 4778723c894SMaxime Coquelin .set_status = vhost_kernel_set_status, 478e3b43481SJianfeng Tan .enable_qp = vhost_kernel_enable_queue_pair 479e3b43481SJianfeng Tan }; 480