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=bdef4365952640c77b4ed985e3d2a5c523b2c641;hpb=ce399c36b4fd090b49bc444b520500c85ba55f2e;p=dpdk.git diff --git a/drivers/net/virtio/virtio_user/vhost_kernel.c b/drivers/net/virtio/virtio_user/vhost_kernel.c index bdef436595..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); @@ -294,55 +335,39 @@ vhost_kernel_set_vring_call(struct virtio_user_dev *dev, struct vhost_vring_file return vhost_kernel_set_vring_file(dev, VHOST_SET_VRING_CALL, file); } -static uint64_t vhost_req_user_to_kernel[] = { - [VHOST_USER_RESET_OWNER] = VHOST_RESET_OWNER, - [VHOST_USER_SET_VRING_ADDR] = VHOST_SET_VRING_ADDR, -}; - static int -vhost_kernel_send_request(struct virtio_user_dev *dev, - enum vhost_user_request req, - void *arg) +vhost_kernel_set_vring_addr(struct virtio_user_dev *dev, struct vhost_vring_addr *addr) { - int ret = -1; - unsigned int i; - uint64_t req_kernel; - int vhostfd; - unsigned int queue_sel; - - PMD_DRV_LOG(INFO, "%s", vhost_msg_strings[req]); - - req_kernel = vhost_req_user_to_kernel[req]; - - switch (req_kernel) { - case VHOST_SET_VRING_ADDR: - queue_sel = *(unsigned int *)arg; - vhostfd = dev->vhostfds[queue_sel / 2]; - *(unsigned int *)arg = queue_sel % 2; - PMD_DRV_LOG(DEBUG, "vhostfd=%d, index=%u", - vhostfd, *(unsigned int *)arg); - break; - default: - vhostfd = -1; - } - if (vhostfd == -1) { - for (i = 0; i < dev->max_queue_pairs; ++i) { - if (dev->vhostfds[i] < 0) - continue; - - ret = ioctl(dev->vhostfds[i], req_kernel, arg); - if (ret < 0) - break; - } - } else { - ret = ioctl(vhostfd, req_kernel, arg); + 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 = data->vhostfds[addr->index / 2]; + addr->index %= 2; + + ret = vhost_kernel_ioctl(fd, VHOST_SET_VRING_ADDR, addr); + if (ret < 0) { + PMD_DRV_LOG(ERR, "Failed to set vring address"); + return -1; } - if (ret < 0) - PMD_DRV_LOG(ERR, "%s failed: %s", - vhost_msg_strings[req], strerror(errno)); + /* restore index back to queue index */ + addr->index = index; - return ret; + return 0; +} + +static int +vhost_kernel_get_status(struct virtio_user_dev *dev __rte_unused, uint8_t *status __rte_unused) +{ + return -ENOTSUP; +} + +static int +vhost_kernel_set_status(struct virtio_user_dev *dev __rte_unused, uint8_t status __rte_unused) +{ + return -ENOTSUP; } /** @@ -355,22 +380,119 @@ vhost_kernel_send_request(struct virtio_user_dev *dev, 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; + } + + 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; - dev->vhostfds[i] = vhostfd; +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; } @@ -402,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; @@ -462,8 +569,32 @@ set_backend: return 0; } +static int +vhost_kernel_get_backend_features(uint64_t *features) +{ + *features = 0; + + 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, .set_features = vhost_kernel_set_features, @@ -473,6 +604,10 @@ struct virtio_user_backend_ops virtio_ops_kernel = { .get_vring_base = vhost_kernel_get_vring_base, .set_vring_call = vhost_kernel_set_vring_call, .set_vring_kick = vhost_kernel_set_vring_kick, - .send_request = vhost_kernel_send_request, - .enable_qp = vhost_kernel_enable_queue_pair + .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, + .update_link_state = vhost_kernel_update_link_state, + .get_intr_fd = vhost_kernel_get_intr_fd, };