From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mga06.intel.com (mga06.intel.com [134.134.136.31]) by dpdk.org (Postfix) with ESMTP id 7773CFA37 for ; Fri, 2 Dec 2016 15:30:42 +0100 (CET) Received: from fmsmga002.fm.intel.com ([10.253.24.26]) by orsmga104.jf.intel.com with ESMTP; 02 Dec 2016 06:30:41 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.33,287,1477983600"; d="scan'208";a="1093688013" Received: from dpdk06.sh.intel.com ([10.239.129.195]) by fmsmga002.fm.intel.com with ESMTP; 02 Dec 2016 06:30:39 -0800 From: Jianfeng Tan To: dev@dpdk.org Cc: yuanhan.liu@linux.intel.com, ferruh.yigit@intel.com, cunming.liang@intel.com, Jianfeng Tan Date: Fri, 2 Dec 2016 14:31:13 +0000 Message-Id: <1480689075-66977-2-git-send-email-jianfeng.tan@intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1480689075-66977-1-git-send-email-jianfeng.tan@intel.com> References: <1480689075-66977-1-git-send-email-jianfeng.tan@intel.com> Subject: [dpdk-dev] [PATCH 1/3] net/virtio_user: add vhost layer X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 02 Dec 2016 14:30:43 -0000 To support vhost kernel as the backend of net_virtio_user in comming patches, we abstract a vhost layer to hide all vhost_user functions. - Move vhost_user specific structs and macros into vhost_user.c, and only keep common definitions in vhost.h; - Add a struct vhost_internal, and an array to store vhost_user and vhost_kernel backends; in multiqueue case, vhost_user has only one vhost FD, but vhost_kernel would have multiple FDs (equal to # of queues), so we turn to use an id to index the backend info; - Add a struct vhost_ops depending on different type of backends. Signed-off-by: Jianfeng Tan --- drivers/net/virtio/Makefile | 1 + drivers/net/virtio/virtio_user/vhost.c | 162 +++++++++++++++++++++++ drivers/net/virtio/virtio_user/vhost.h | 68 +++++----- drivers/net/virtio/virtio_user/vhost_user.c | 81 ++++++++---- drivers/net/virtio/virtio_user/virtio_user_dev.c | 47 +++---- drivers/net/virtio/virtio_user/virtio_user_dev.h | 2 +- 6 files changed, 266 insertions(+), 95 deletions(-) create mode 100644 drivers/net/virtio/virtio_user/vhost.c diff --git a/drivers/net/virtio/Makefile b/drivers/net/virtio/Makefile index 97972a6..17f7129 100644 --- a/drivers/net/virtio/Makefile +++ b/drivers/net/virtio/Makefile @@ -59,6 +59,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_VIRTIO_PMD) += virtio_rxtx_simple_neon.c endif ifeq ($(CONFIG_RTE_VIRTIO_USER),y) +SRCS-$(CONFIG_RTE_LIBRTE_VIRTIO_PMD) += virtio_user/vhost.c SRCS-$(CONFIG_RTE_LIBRTE_VIRTIO_PMD) += virtio_user/vhost_user.c SRCS-$(CONFIG_RTE_LIBRTE_VIRTIO_PMD) += virtio_user/virtio_user_dev.c SRCS-$(CONFIG_RTE_LIBRTE_VIRTIO_PMD) += virtio_user_ethdev.c diff --git a/drivers/net/virtio/virtio_user/vhost.c b/drivers/net/virtio/virtio_user/vhost.c new file mode 100644 index 0000000..09e2e92 --- /dev/null +++ b/drivers/net/virtio/virtio_user/vhost.c @@ -0,0 +1,162 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2016 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include + +#include "vhost.h" + +#define VHOST_MAX_DEVICES 8 + +static struct vhost_internal internals[VHOST_MAX_DEVICES]; + +static inline int +vhost_internal_valid_vid(int vid) +{ + if (vid < 0 || vid >= VHOST_MAX_DEVICES) + return 0; + + if (!internals[vid].ops) + return 0; + + return 1; +} + +static int +vhost_internal_alloc(void) +{ + int i; + + for (i = 0; i < VHOST_MAX_DEVICES; ++i) + if (internals[i].ops == NULL) + break; + + if (i >= VHOST_MAX_DEVICES) + return -1; + + internals[i].features = 0; + + internals[i].vhostfd = -1; + + return 0; +} + +static void +vhost_internal_free(int id) +{ + internals[id].ops = NULL; + + if (internals[id].vhostfd >= 0) + close(internals[id].vhostfd); +} + + +static int +is_vhost_user_by_type(const char *path) +{ + struct stat sb; + + if (stat(path, &sb) == -1) + return 0; + + return S_ISSOCK(sb.st_mode); +} + +int +vhost_setup(const char *path) +{ + int ret = -1; + int vid = vhost_internal_alloc(); + + if (vid < 0) { + PMD_DRV_LOG(ERR, "exceeding %d devices", VHOST_MAX_DEVICES); + return -1; + } + + if (is_vhost_user_by_type(path)) { + ret = vhost_ops_user.setup(&internals[vid], path); + internals[vid].ops = &vhost_ops_user; + } + + if (ret < 0) + vhost_internal_free(vid); + + return vid; +} + +static const char * const vhost_msg_strings[] = { + [VHOST_USER_SET_OWNER] = "VHOST_USER_SET_OWNER", + [VHOST_USER_RESET_OWNER] = "VHOST_USER_RESET_OWNER", + [VHOST_USER_SET_FEATURES] = "VHOST_USER_SET_FEATURES", + [VHOST_USER_GET_FEATURES] = "VHOST_USER_GET_FEATURES", + [VHOST_USER_SET_VRING_CALL] = "VHOST_USER_SET_VRING_CALL", + [VHOST_USER_SET_VRING_NUM] = "VHOST_USER_SET_VRING_NUM", + [VHOST_USER_SET_VRING_BASE] = "VHOST_USER_SET_VRING_BASE", + [VHOST_USER_GET_VRING_BASE] = "VHOST_USER_GET_VRING_BASE", + [VHOST_USER_SET_VRING_ADDR] = "VHOST_USER_SET_VRING_ADDR", + [VHOST_USER_SET_VRING_KICK] = "VHOST_USER_SET_VRING_KICK", + [VHOST_USER_SET_MEM_TABLE] = "VHOST_USER_SET_MEM_TABLE", + [VHOST_USER_SET_VRING_ENABLE] = "VHOST_USER_SET_VRING_ENABLE", + NULL, +}; + +int +vhost_call(int vid, enum vhost_user_request req, void *arg) +{ + RTE_SET_USED(vhost_msg_strings); + PMD_DRV_LOG(INFO, "%s", vhost_msg_strings[req]); + + if (!vhost_internal_valid_vid(vid)) + return -1; + + return internals[vid].ops->control(&internals[vid], req, arg); +} + +int +vhost_enable_queue_pair(int vid, uint16_t pair_idx, int enable) +{ + if (!vhost_internal_valid_vid(vid)) + return -1; + + return internals[vid].ops->enable_qp(&internals[vid], pair_idx, enable); +} + +void +vhost_close(int vid) +{ + if (!vhost_internal_valid_vid(vid)) + return; + + vhost_internal_free(vid); +} diff --git a/drivers/net/virtio/virtio_user/vhost.h b/drivers/net/virtio/virtio_user/vhost.h index 7adb55f..b476ecc 100644 --- a/drivers/net/virtio/virtio_user/vhost.h +++ b/drivers/net/virtio/virtio_user/vhost.h @@ -42,8 +42,6 @@ #include "../virtio_logs.h" #include "../virtqueue.h" -#define VHOST_MEMORY_MAX_NREGIONS 8 - struct vhost_vring_state { unsigned int index; unsigned int num; @@ -105,42 +103,38 @@ struct vhost_memory_region { uint64_t mmap_offset; }; -struct vhost_memory { - uint32_t nregions; - uint32_t padding; - struct vhost_memory_region regions[VHOST_MEMORY_MAX_NREGIONS]; +struct vhost_ops; + +struct vhost_internal { + /* for both vhost-user and vhost-kernel */ + uint64_t features; + struct vhost_ops *ops; + + /* for vhost-user */ + int vhostfd; + + /* for vhost-kernel */ +}; + +typedef int (*vhost_setup_t)(struct vhost_internal *internal, + const char *path); +typedef int (*vhost_control_t)(struct vhost_internal *internal, + enum vhost_user_request req, + void *arg); +typedef int (*vhost_enable_qp_t)(struct vhost_internal *internal, + uint16_t pair_idx, + int enable); + +struct vhost_ops { + vhost_setup_t setup; + vhost_control_t control; + vhost_enable_qp_t enable_qp; }; -struct vhost_user_msg { - enum vhost_user_request request; - -#define VHOST_USER_VERSION_MASK 0x3 -#define VHOST_USER_REPLY_MASK (0x1 << 2) - uint32_t flags; - uint32_t size; /* the following payload size */ - union { -#define VHOST_USER_VRING_IDX_MASK 0xff -#define VHOST_USER_VRING_NOFD_MASK (0x1 << 8) - uint64_t u64; - struct vhost_vring_state state; - struct vhost_vring_addr addr; - struct vhost_memory memory; - } payload; - int fds[VHOST_MEMORY_MAX_NREGIONS]; -} __attribute((packed)); - -#define VHOST_USER_HDR_SIZE offsetof(struct vhost_user_msg, payload.u64) -#define VHOST_USER_PAYLOAD_SIZE \ - (sizeof(struct vhost_user_msg) - VHOST_USER_HDR_SIZE) - -/* The version of the protocol we support */ -#define VHOST_USER_VERSION 0x1 - -#define VHOST_USER_F_PROTOCOL_FEATURES 30 -#define VHOST_USER_MQ (1ULL << VHOST_USER_F_PROTOCOL_FEATURES) - -int vhost_user_sock(int vhostfd, enum vhost_user_request req, void *arg); -int vhost_user_setup(const char *path); -int vhost_user_enable_queue_pair(int vhostfd, uint16_t pair_idx, int enable); +struct vhost_ops vhost_ops_user; +int vhost_setup(const char *path); +int vhost_call(int vid, enum vhost_user_request req, void *arg); +int vhost_enable_queue_pair(int vid, uint16_t pair_idx, int enable); +void vhost_close(int vid); #endif diff --git a/drivers/net/virtio/virtio_user/vhost_user.c b/drivers/net/virtio/virtio_user/vhost_user.c index 082e821..afd18ec 100644 --- a/drivers/net/virtio/virtio_user/vhost_user.c +++ b/drivers/net/virtio/virtio_user/vhost_user.c @@ -42,6 +42,38 @@ #include "vhost.h" +/* The version of the protocol we support */ +#define VHOST_USER_VERSION 0x1 +#define VHOST_MEMORY_MAX_NREGIONS 8 + +struct vhost_memory { + uint32_t nregions; + uint32_t padding; + struct vhost_memory_region regions[VHOST_MEMORY_MAX_NREGIONS]; +}; + +struct vhost_user_msg { + enum vhost_user_request request; + +#define VHOST_USER_VERSION_MASK 0x3 +#define VHOST_USER_REPLY_MASK (0x1 << 2) + uint32_t flags; + uint32_t size; /* the following payload size */ + union { +#define VHOST_USER_VRING_IDX_MASK 0xff +#define VHOST_USER_VRING_NOFD_MASK (0x1 << 8) + uint64_t u64; + struct vhost_vring_state state; + struct vhost_vring_addr addr; + struct vhost_memory memory; + } payload; + int fds[VHOST_MEMORY_MAX_NREGIONS]; +} __attribute((packed)); + +#define VHOST_USER_HDR_SIZE offsetof(struct vhost_user_msg, payload.u64) +#define VHOST_USER_PAYLOAD_SIZE \ + (sizeof(struct vhost_user_msg) - VHOST_USER_HDR_SIZE) + static int vhost_user_write(int fd, void *buf, int len, int *fds, int fd_num) { @@ -223,24 +255,10 @@ prepare_vhost_memory_user(struct vhost_user_msg *msg, int fds[]) static struct vhost_user_msg m; -static const char * const vhost_msg_strings[] = { - [VHOST_USER_SET_OWNER] = "VHOST_USER_SET_OWNER", - [VHOST_USER_RESET_OWNER] = "VHOST_USER_RESET_OWNER", - [VHOST_USER_SET_FEATURES] = "VHOST_USER_SET_FEATURES", - [VHOST_USER_GET_FEATURES] = "VHOST_USER_GET_FEATURES", - [VHOST_USER_SET_VRING_CALL] = "VHOST_USER_SET_VRING_CALL", - [VHOST_USER_SET_VRING_NUM] = "VHOST_USER_SET_VRING_NUM", - [VHOST_USER_SET_VRING_BASE] = "VHOST_USER_SET_VRING_BASE", - [VHOST_USER_GET_VRING_BASE] = "VHOST_USER_GET_VRING_BASE", - [VHOST_USER_SET_VRING_ADDR] = "VHOST_USER_SET_VRING_ADDR", - [VHOST_USER_SET_VRING_KICK] = "VHOST_USER_SET_VRING_KICK", - [VHOST_USER_SET_MEM_TABLE] = "VHOST_USER_SET_MEM_TABLE", - [VHOST_USER_SET_VRING_ENABLE] = "VHOST_USER_SET_VRING_ENABLE", - NULL, -}; - -int -vhost_user_sock(int vhostfd, enum vhost_user_request req, void *arg) +static int +vhost_user_sock(struct vhost_internal *internal, + enum vhost_user_request req, + void *arg) { struct vhost_user_msg msg; struct vhost_vring_file *file = 0; @@ -248,11 +266,9 @@ vhost_user_sock(int vhostfd, enum vhost_user_request req, void *arg) int fds[VHOST_MEMORY_MAX_NREGIONS]; int fd_num = 0; int i, len; + int vhostfd = internal->vhostfd; RTE_SET_USED(m); - RTE_SET_USED(vhost_msg_strings); - - PMD_DRV_LOG(INFO, "%s", vhost_msg_strings[req]); msg.request = req; msg.flags = VHOST_USER_VERSION; @@ -323,8 +339,8 @@ vhost_user_sock(int vhostfd, enum vhost_user_request req, void *arg) len = VHOST_USER_HDR_SIZE + msg.size; if (vhost_user_write(vhostfd, &msg, len, fds, fd_num) < 0) { - PMD_DRV_LOG(ERR, "%s failed: %s", - vhost_msg_strings[req], strerror(errno)); + PMD_DRV_LOG(ERR, "fail to write vhost user msg: %s", + strerror(errno)); return -1; } @@ -378,8 +394,8 @@ vhost_user_sock(int vhostfd, enum vhost_user_request req, void *arg) * - (-1) if fail to set up; * - (>=0) if successful, and it is the fd to vhostfd. */ -int -vhost_user_setup(const char *path) +static int +vhost_user_setup(struct vhost_internal *internal, const char *path) { int fd; int flag; @@ -404,11 +420,14 @@ vhost_user_setup(const char *path) return -1; } + internal->vhostfd = fd; + return fd; } -int -vhost_user_enable_queue_pair(int vhostfd, uint16_t pair_idx, int enable) +static int +vhost_user_enable_queue_pair(struct vhost_internal *internal, + uint16_t pair_idx, int enable) { int i; @@ -418,10 +437,16 @@ vhost_user_enable_queue_pair(int vhostfd, uint16_t pair_idx, int enable) .num = enable, }; - if (vhost_user_sock(vhostfd, + if (vhost_user_sock(internal, VHOST_USER_SET_VRING_ENABLE, &state)) return -1; } return 0; } + +struct vhost_ops vhost_ops_user = { + .setup = vhost_user_setup, + .control = vhost_user_sock, + .enable_qp = vhost_user_enable_queue_pair +}; diff --git a/drivers/net/virtio/virtio_user/virtio_user_dev.c b/drivers/net/virtio/virtio_user/virtio_user_dev.c index e239e0e..3aef5f6 100644 --- a/drivers/net/virtio/virtio_user/virtio_user_dev.c +++ b/drivers/net/virtio/virtio_user/virtio_user_dev.c @@ -64,7 +64,7 @@ virtio_user_create_queue(struct virtio_user_dev *dev, uint32_t queue_sel) } file.index = queue_sel; file.fd = callfd; - vhost_user_sock(dev->vhostfd, VHOST_USER_SET_VRING_CALL, &file); + vhost_call(dev->vid, VHOST_USER_SET_VRING_CALL, &file); dev->callfds[queue_sel] = callfd; return 0; @@ -88,12 +88,12 @@ virtio_user_kick_queue(struct virtio_user_dev *dev, uint32_t queue_sel) state.index = queue_sel; state.num = vring->num; - vhost_user_sock(dev->vhostfd, VHOST_USER_SET_VRING_NUM, &state); + vhost_call(dev->vid, VHOST_USER_SET_VRING_NUM, &state); state.num = 0; /* no reservation */ - vhost_user_sock(dev->vhostfd, VHOST_USER_SET_VRING_BASE, &state); + vhost_call(dev->vid, VHOST_USER_SET_VRING_BASE, &state); - vhost_user_sock(dev->vhostfd, VHOST_USER_SET_VRING_ADDR, &addr); + vhost_call(dev->vid, VHOST_USER_SET_VRING_ADDR, &addr); /* Of all per virtqueue MSGs, make sure VHOST_USER_SET_VRING_KICK comes * lastly because vhost depends on this msg to judge if @@ -106,7 +106,7 @@ virtio_user_kick_queue(struct virtio_user_dev *dev, uint32_t queue_sel) } file.index = queue_sel; file.fd = kickfd; - vhost_user_sock(dev->vhostfd, VHOST_USER_SET_VRING_KICK, &file); + vhost_call(dev->vid, VHOST_USER_SET_VRING_KICK, &file); dev->kickfds[queue_sel] = kickfd; return 0; @@ -146,21 +146,18 @@ virtio_user_start_device(struct virtio_user_dev *dev) if (virtio_user_queue_setup(dev, virtio_user_create_queue) < 0) goto error; - /* Step 1: set features - * Make sure VHOST_USER_F_PROTOCOL_FEATURES is added if mq is enabled, - * and VIRTIO_NET_F_MAC is stripped. + /* Step 1: set feature + * Strip VIRTIO_NET_F_MAC, as MAC address is handled in vdev init. */ features = dev->features; - if (dev->max_queue_pairs > 1) - features |= VHOST_USER_MQ; features &= ~(1ull << VIRTIO_NET_F_MAC); - ret = vhost_user_sock(dev->vhostfd, VHOST_USER_SET_FEATURES, &features); + ret = vhost_call(dev->vid, VHOST_USER_SET_FEATURES, &features); if (ret < 0) goto error; PMD_DRV_LOG(INFO, "set features: %" PRIx64, features); /* Step 2: share memory regions */ - ret = vhost_user_sock(dev->vhostfd, VHOST_USER_SET_MEM_TABLE, NULL); + ret = vhost_call(dev->vid, VHOST_USER_SET_MEM_TABLE, NULL); if (ret < 0) goto error; @@ -171,7 +168,7 @@ virtio_user_start_device(struct virtio_user_dev *dev) /* Step 4: enable queues * we enable the 1st queue pair by default. */ - vhost_user_enable_queue_pair(dev->vhostfd, 0, 1); + vhost_enable_queue_pair(dev->vid, 0, 1); return 0; error: @@ -181,7 +178,7 @@ virtio_user_start_device(struct virtio_user_dev *dev) int virtio_user_stop_device(struct virtio_user_dev *dev) { - return vhost_user_sock(dev->vhostfd, VHOST_USER_RESET_OWNER, NULL); + return vhost_call(dev->vid, VHOST_USER_RESET_OWNER, NULL); } static inline void @@ -215,19 +212,18 @@ virtio_user_dev_init(struct virtio_user_dev *dev, char *path, int queues, dev->queue_size = queue_size; dev->mac_specified = 0; parse_mac(dev, mac); - dev->vhostfd = -1; - dev->vhostfd = vhost_user_setup(dev->path); - if (dev->vhostfd < 0) { + dev->vid = vhost_setup(dev->path); + if (dev->vid < 0) { PMD_INIT_LOG(ERR, "backend set up fails"); return -1; } - if (vhost_user_sock(dev->vhostfd, VHOST_USER_SET_OWNER, NULL) < 0) { + if (vhost_call(dev->vid, VHOST_USER_SET_OWNER, NULL) < 0) { PMD_INIT_LOG(ERR, "set_owner fails: %s", strerror(errno)); return -1; } - if (vhost_user_sock(dev->vhostfd, VHOST_USER_GET_FEATURES, + if (vhost_call(dev->vid, VHOST_USER_GET_FEATURES, &dev->features) < 0) { PMD_INIT_LOG(ERR, "get_features failed: %s", strerror(errno)); return -1; @@ -253,13 +249,6 @@ virtio_user_dev_init(struct virtio_user_dev *dev, char *path, int queues, PMD_INIT_LOG(INFO, "vhost does not support ctrl-q"); } - if (dev->max_queue_pairs > 1) { - if (!(dev->features & VHOST_USER_MQ)) { - PMD_INIT_LOG(ERR, "MQ not supported by the backend"); - return -1; - } - } - return 0; } @@ -273,7 +262,7 @@ virtio_user_dev_uninit(struct virtio_user_dev *dev) close(dev->kickfds[i]); } - close(dev->vhostfd); + vhost_close(dev->vid); } static uint8_t @@ -289,9 +278,9 @@ virtio_user_handle_mq(struct virtio_user_dev *dev, uint16_t q_pairs) } for (i = 0; i < q_pairs; ++i) - ret |= vhost_user_enable_queue_pair(dev->vhostfd, i, 1); + ret |= vhost_enable_queue_pair(dev->vid, i, 1); for (i = q_pairs; i < dev->max_queue_pairs; ++i) - ret |= vhost_user_enable_queue_pair(dev->vhostfd, i, 0); + ret |= vhost_enable_queue_pair(dev->vid, i, 0); dev->queue_pairs = q_pairs; diff --git a/drivers/net/virtio/virtio_user/virtio_user_dev.h b/drivers/net/virtio/virtio_user/virtio_user_dev.h index 33690b5..80efb6e 100644 --- a/drivers/net/virtio/virtio_user/virtio_user_dev.h +++ b/drivers/net/virtio/virtio_user/virtio_user_dev.h @@ -39,7 +39,7 @@ #include "../virtio_ring.h" struct virtio_user_dev { - int vhostfd; + int vid; int callfds[VIRTIO_MAX_VIRTQUEUES * 2 + 1]; int kickfds[VIRTIO_MAX_VIRTQUEUES * 2 + 1]; int mac_specified; -- 2.7.4