X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fvirtio%2Fvirtio_user%2Fvhost_kernel.c;h=202a8cdee1ca91a42659af628dcfd40b812c1acb;hb=1dfb92a529722c87b251eaaf673c48b13d1a54cc;hp=2047d41a500318ed0ecaa26dcf162d5a4e41023c;hpb=5b75b63c324a7a3b0101b4cf1e245b8b8a0f22bd;p=dpdk.git diff --git a/drivers/net/virtio/virtio_user/vhost_kernel.c b/drivers/net/virtio/virtio_user/vhost_kernel.c index 2047d41a50..202a8cdee1 100644 --- a/drivers/net/virtio/virtio_user/vhost_kernel.c +++ b/drivers/net/virtio/virtio_user/vhost_kernel.c @@ -14,6 +14,11 @@ #include "virtio_user_dev.h" #include "vhost_kernel_tap.h" +struct vhost_kernel_data { + int *vhostfds; + int *tapfds; +}; + struct vhost_memory_kernel { uint32_t nregions; uint32_t padding; @@ -96,22 +101,36 @@ vhost_kernel_ioctl(int fd, uint64_t request, void *arg) static int vhost_kernel_set_owner(struct virtio_user_dev *dev) { - return vhost_kernel_ioctl(dev->vhostfds[0], VHOST_SET_OWNER, NULL); + int ret; + uint32_t i; + struct vhost_kernel_data *data = dev->backend_data; + + for (i = 0; i < dev->max_queue_pairs; ++i) { + if (data->vhostfds[i] < 0) + continue; + + ret = vhost_kernel_ioctl(data->vhostfds[i], VHOST_SET_OWNER, NULL); + if (ret < 0) + return ret; + } + + return 0; } static int vhost_kernel_get_features(struct virtio_user_dev *dev, uint64_t *features) { + struct vhost_kernel_data *data = dev->backend_data; + unsigned int tap_flags; int ret; - unsigned int tap_features; - ret = vhost_kernel_ioctl(dev->vhostfds[0], VHOST_GET_FEATURES, features); + ret = vhost_kernel_ioctl(data->vhostfds[0], VHOST_GET_FEATURES, features); if (ret < 0) { PMD_DRV_LOG(ERR, "Failed to get features"); return -1; } - ret = tap_support_features(&tap_features); + ret = tap_get_flags(data->tapfds[0], &tap_flags); if (ret < 0) { PMD_DRV_LOG(ERR, "Failed to get TAP features"); return -1; @@ -121,7 +140,7 @@ vhost_kernel_get_features(struct virtio_user_dev *dev, uint64_t *features) * but not claimed by vhost-net, so we add them back when * reporting to upper layer. */ - if (tap_features & IFF_VNET_HDR) { + if (tap_flags & IFF_VNET_HDR) { *features |= VHOST_KERNEL_GUEST_OFFLOADS_MASK; *features |= VHOST_KERNEL_HOST_OFFLOADS_MASK; } @@ -129,7 +148,7 @@ vhost_kernel_get_features(struct virtio_user_dev *dev, uint64_t *features) /* vhost_kernel will not declare this feature, but it does * support multi-queue. */ - if (tap_features & IFF_MULTI_QUEUE) + if (tap_flags & IFF_MULTI_QUEUE) *features |= (1ull << VIRTIO_NET_F_MQ); return 0; @@ -138,6 +157,10 @@ vhost_kernel_get_features(struct virtio_user_dev *dev, uint64_t *features) static int vhost_kernel_set_features(struct virtio_user_dev *dev, uint64_t features) { + struct vhost_kernel_data *data = dev->backend_data; + uint32_t i; + int ret; + /* We don't need memory protection here */ features &= ~(1ULL << VIRTIO_F_IOMMU_PLATFORM); /* VHOST kernel does not know about below flags */ @@ -145,7 +168,16 @@ vhost_kernel_set_features(struct virtio_user_dev *dev, uint64_t features) features &= ~VHOST_KERNEL_HOST_OFFLOADS_MASK; features &= ~(1ULL << VIRTIO_NET_F_MQ); - return vhost_kernel_ioctl(dev->vhostfds[0], VHOST_SET_FEATURES, &features); + for (i = 0; i < dev->max_queue_pairs; ++i) { + if (data->vhostfds[i] < 0) + continue; + + ret = vhost_kernel_ioctl(data->vhostfds[i], VHOST_SET_FEATURES, &features); + if (ret < 0) + return ret; + } + + return 0; } static int @@ -185,6 +217,8 @@ add_memseg_list(const struct rte_memseg_list *msl, void *arg) static int vhost_kernel_set_memory_table(struct virtio_user_dev *dev) { + uint32_t i; + struct vhost_kernel_data *data = dev->backend_data; struct vhost_memory_kernel *vm; int ret; @@ -205,9 +239,14 @@ vhost_kernel_set_memory_table(struct virtio_user_dev *dev) if (ret < 0) goto err_free; - ret = vhost_kernel_ioctl(dev->vhostfds[0], VHOST_SET_MEM_TABLE, vm); - if (ret < 0) - goto err_free; + for (i = 0; i < dev->max_queue_pairs; ++i) { + if (data->vhostfds[i] < 0) + continue; + + ret = vhost_kernel_ioctl(data->vhostfds[i], VHOST_SET_MEM_TABLE, vm); + if (ret < 0) + goto err_free; + } free(vm); @@ -224,9 +263,10 @@ vhost_kernel_set_vring(struct virtio_user_dev *dev, uint64_t req, struct vhost_v { int ret, fd; unsigned int index = state->index; + struct vhost_kernel_data *data = dev->backend_data; /* Convert from queue index to queue-pair & offset */ - fd = dev->vhostfds[state->index / 2]; + fd = data->vhostfds[state->index / 2]; state->index %= 2; ret = vhost_kernel_ioctl(fd, req, state); @@ -265,9 +305,10 @@ vhost_kernel_set_vring_file(struct virtio_user_dev *dev, uint64_t req, { int ret, fd; unsigned int index = file->index; + struct vhost_kernel_data *data = dev->backend_data; /* Convert from queue index to queue-pair & offset */ - fd = dev->vhostfds[file->index / 2]; + fd = data->vhostfds[file->index / 2]; file->index %= 2; ret = vhost_kernel_ioctl(fd, req, file); @@ -299,9 +340,10 @@ vhost_kernel_set_vring_addr(struct virtio_user_dev *dev, struct vhost_vring_addr { int ret, fd; unsigned int index = addr->index; + struct vhost_kernel_data *data = dev->backend_data; /* Convert from queue index to queue-pair & offset */ - fd = dev->vhostfds[addr->index / 2]; + fd = data->vhostfds[addr->index / 2]; addr->index %= 2; ret = vhost_kernel_ioctl(fd, VHOST_SET_VRING_ADDR, addr); @@ -338,22 +380,119 @@ vhost_kernel_set_status(struct virtio_user_dev *dev __rte_unused, uint8_t status static int vhost_kernel_setup(struct virtio_user_dev *dev) { + struct vhost_kernel_data *data; + unsigned int tap_features; + unsigned int tap_flags; + const char *ifname; + uint32_t q, i; int vhostfd; - uint32_t i; + + if (tap_support_features(&tap_features) < 0) + return -1; + + if ((tap_features & IFF_VNET_HDR) == 0) { + PMD_INIT_LOG(ERR, "TAP does not support IFF_VNET_HDR"); + return -1; + } + + data = malloc(sizeof(*data)); + if (!data) { + PMD_INIT_LOG(ERR, "(%s) Failed to allocate Vhost-kernel data", dev->path); + return -1; + } + + data->vhostfds = malloc(dev->max_queue_pairs * sizeof(int)); + if (!data->vhostfds) { + PMD_INIT_LOG(ERR, "(%s) Failed to allocate Vhost FDs", dev->path); + goto err_data; + } + data->tapfds = malloc(dev->max_queue_pairs * sizeof(int)); + if (!data->tapfds) { + PMD_INIT_LOG(ERR, "(%s) Failed to allocate TAP FDs", dev->path); + goto err_vhostfds; + } + + for (q = 0; q < dev->max_queue_pairs; ++q) { + data->vhostfds[q] = -1; + data->tapfds[q] = -1; + } get_vhost_kernel_max_regions(); for (i = 0; i < dev->max_queue_pairs; ++i) { vhostfd = open(dev->path, O_RDWR); if (vhostfd < 0) { - PMD_DRV_LOG(ERR, "fail to open %s, %s", - dev->path, strerror(errno)); - return -1; + PMD_DRV_LOG(ERR, "fail to open %s, %s", dev->path, strerror(errno)); + goto err_tapfds; } + data->vhostfds[i] = vhostfd; + } - dev->vhostfds[i] = vhostfd; + ifname = dev->ifname != NULL ? dev->ifname : "tap%d"; + data->tapfds[0] = tap_open(ifname, (tap_features & IFF_MULTI_QUEUE) != 0); + if (data->tapfds[0] < 0) + goto err_tapfds; + if (dev->ifname == NULL && tap_get_name(data->tapfds[0], &dev->ifname) < 0) { + PMD_DRV_LOG(ERR, "fail to get tap name (%d)", data->tapfds[0]); + goto err_tapfds; + } + if (tap_get_flags(data->tapfds[0], &tap_flags) < 0) { + PMD_DRV_LOG(ERR, "fail to get tap flags for tap %s", dev->ifname); + goto err_tapfds; + } + if ((tap_flags & IFF_MULTI_QUEUE) == 0 && dev->max_queue_pairs > 1) { + PMD_DRV_LOG(ERR, "tap %s does not support multi queue", dev->ifname); + goto err_tapfds; } + for (i = 1; i < dev->max_queue_pairs; i++) { + data->tapfds[i] = tap_open(dev->ifname, true); + if (data->tapfds[i] < 0) + goto err_tapfds; + } + + dev->backend_data = data; + + return 0; + +err_tapfds: + for (i = 0; i < dev->max_queue_pairs; i++) { + if (data->vhostfds[i] >= 0) + close(data->vhostfds[i]); + if (data->tapfds[i] >= 0) + close(data->tapfds[i]); + } + + free(data->tapfds); +err_vhostfds: + free(data->vhostfds); +err_data: + free(data); + + return -1; +} + +static int +vhost_kernel_destroy(struct virtio_user_dev *dev) +{ + struct vhost_kernel_data *data = dev->backend_data; + uint32_t i; + + if (!data) + return 0; + + for (i = 0; i < dev->max_queue_pairs; ++i) { + if (data->vhostfds[i] >= 0) + close(data->vhostfds[i]); + if (data->tapfds[i] >= 0) + close(data->tapfds[i]); + } + + free(data->vhostfds); + free(data->tapfds); + free(data); + dev->backend_data = NULL; + return 0; } @@ -385,57 +524,42 @@ vhost_kernel_enable_queue_pair(struct virtio_user_dev *dev, uint16_t pair_idx, int enable) { + struct vhost_kernel_data *data = dev->backend_data; int hdr_size; int vhostfd; int tapfd; - int req_mq = (dev->max_queue_pairs > 1); - - vhostfd = dev->vhostfds[pair_idx]; if (dev->qp_enabled[pair_idx] == enable) return 0; + vhostfd = data->vhostfds[pair_idx]; + tapfd = data->tapfds[pair_idx]; + if (!enable) { - tapfd = dev->tapfds[pair_idx]; if (vhost_kernel_set_backend(vhostfd, -1) < 0) { PMD_DRV_LOG(ERR, "fail to set backend for vhost kernel"); return -1; } - if (req_mq && vhost_kernel_tap_set_queue(tapfd, false) < 0) { - PMD_DRV_LOG(ERR, "fail to disable tap for vhost kernel"); - return -1; - } dev->qp_enabled[pair_idx] = false; return 0; } - if (dev->tapfds[pair_idx] >= 0) { - tapfd = dev->tapfds[pair_idx]; - if (vhost_kernel_tap_set_offload(tapfd, dev->features) == -1) - return -1; - if (req_mq && vhost_kernel_tap_set_queue(tapfd, true) < 0) { - PMD_DRV_LOG(ERR, "fail to enable tap for vhost kernel"); - return -1; - } - goto set_backend; - } - if ((dev->features & (1ULL << VIRTIO_NET_F_MRG_RXBUF)) || (dev->features & (1ULL << VIRTIO_F_VERSION_1))) hdr_size = sizeof(struct virtio_net_hdr_mrg_rxbuf); else hdr_size = sizeof(struct virtio_net_hdr); - tapfd = vhost_kernel_open_tap(&dev->ifname, hdr_size, req_mq, - (char *)dev->mac_addr, dev->features); - if (tapfd < 0) { - PMD_DRV_LOG(ERR, "fail to open tap for vhost kernel"); + /* Set mac on tap only once when starting */ + if (!dev->started && pair_idx == 0 && + tap_set_mac(data->tapfds[pair_idx], dev->mac_addr) < 0) return -1; - } - dev->tapfds[pair_idx] = tapfd; + if (vhost_kernel_tap_setup(tapfd, hdr_size, dev->features) < 0) { + PMD_DRV_LOG(ERR, "fail to setup tap for vhost kernel"); + return -1; + } -set_backend: if (vhost_kernel_set_backend(vhostfd, tapfd) < 0) { PMD_DRV_LOG(ERR, "fail to set backend for vhost kernel"); return -1; @@ -453,8 +577,23 @@ vhost_kernel_get_backend_features(uint64_t *features) return 0; } +static int +vhost_kernel_update_link_state(struct virtio_user_dev *dev __rte_unused) +{ + /* Nothing to update (Maybe get TAP interface link state?) */ + return 0; +} + +static int +vhost_kernel_get_intr_fd(struct virtio_user_dev *dev __rte_unused) +{ + /* No link state interrupt with Vhost-kernel */ + return -1; +} + struct virtio_user_backend_ops virtio_ops_kernel = { .setup = vhost_kernel_setup, + .destroy = vhost_kernel_destroy, .get_backend_features = vhost_kernel_get_backend_features, .set_owner = vhost_kernel_set_owner, .get_features = vhost_kernel_get_features, @@ -468,5 +607,7 @@ struct virtio_user_backend_ops virtio_ops_kernel = { .set_vring_addr = vhost_kernel_set_vring_addr, .get_status = vhost_kernel_get_status, .set_status = vhost_kernel_set_status, - .enable_qp = vhost_kernel_enable_queue_pair + .enable_qp = vhost_kernel_enable_queue_pair, + .update_link_state = vhost_kernel_update_link_state, + .get_intr_fd = vhost_kernel_get_intr_fd, };