get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/15788/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 15788,
    "url": "http://patches.dpdk.org/api/patches/15788/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/1473855300-3066-1-git-send-email-changpeng.liu@intel.com/",
    "project": {
        "id": 1,
        "url": "http://patches.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<1473855300-3066-1-git-send-email-changpeng.liu@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1473855300-3066-1-git-send-email-changpeng.liu@intel.com",
    "date": "2016-09-14T12:15:00",
    "name": "[dpdk-dev] vhost: change the vhost library to a common framework which can support more VIRTIO devices",
    "commit_ref": null,
    "pull_url": null,
    "state": "rejected",
    "archived": true,
    "hash": "a47a8ac5bca8f992309c92ece8fd3bb4a4e7c6e2",
    "submitter": {
        "id": 565,
        "url": "http://patches.dpdk.org/api/people/565/?format=api",
        "name": "Liu, Changpeng",
        "email": "changpeng.liu@intel.com"
    },
    "delegate": {
        "id": 355,
        "url": "http://patches.dpdk.org/api/users/355/?format=api",
        "username": "yliu",
        "first_name": "Yuanhan",
        "last_name": "Liu",
        "email": "yuanhan.liu@linux.intel.com"
    },
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/1473855300-3066-1-git-send-email-changpeng.liu@intel.com/mbox/",
    "series": [],
    "comments": "http://patches.dpdk.org/api/patches/15788/comments/",
    "check": "pending",
    "checks": "http://patches.dpdk.org/api/patches/15788/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@dpdk.org",
        "Delivered-To": "patchwork@dpdk.org",
        "Received": [
            "from [92.243.14.124] (localhost [IPv6:::1])\n\tby dpdk.org (Postfix) with ESMTP id A2AE76CC2;\n\tTue, 13 Sep 2016 14:07:05 +0200 (CEST)",
            "from mga07.intel.com (mga07.intel.com [134.134.136.100])\n\tby dpdk.org (Postfix) with ESMTP id 927AB6CC1\n\tfor <dev@dpdk.org>; Tue, 13 Sep 2016 14:07:03 +0200 (CEST)",
            "from fmsmga004.fm.intel.com ([10.253.24.48])\n\tby orsmga105.jf.intel.com with ESMTP; 13 Sep 2016 05:07:02 -0700",
            "from fedora.sh.intel.com ([10.239.67.161])\n\tby fmsmga004.fm.intel.com with ESMTP; 13 Sep 2016 05:07:01 -0700"
        ],
        "X-ExtLoop1": "1",
        "X-IronPort-AV": "E=Sophos;i=\"5.30,328,1470726000\"; d=\"scan'208\";a=\"167625749\"",
        "From": "Changpeng Liu <changpeng.liu@intel.com>",
        "To": "dev@dpdk.org",
        "Cc": "yuanhan.liu@intel.com, james.r.harris@intel.com, changpeng.liu@intel.com",
        "Date": "Wed, 14 Sep 2016 20:15:00 +0800",
        "Message-Id": "<1473855300-3066-1-git-send-email-changpeng.liu@intel.com>",
        "X-Mailer": "git-send-email 1.9.3",
        "Subject": "[dpdk-dev] [PATCH] vhost: change the vhost library to a common\n\tframework which can support more VIRTIO devices",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "patches and discussions about DPDK <dev.dpdk.org>",
        "List-Unsubscribe": "<http://dpdk.org/ml/options/dev>,\n\t<mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://dpdk.org/ml/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<http://dpdk.org/ml/listinfo/dev>,\n\t<mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "For storage virtualization use cases, vhost-scsi becomes a more popular\nsolution to support VMs. However a user space vhost-scsi-user solution\ndoes not exist currently. SPDK(Storage Performance Development Kit,\nhttps://github.com/spdk/spdk) will provide a user space vhost-scsi target\nto support multiple VMs through Qemu. Originally SPDK is built on top\nof DPDK libraries, so we would like to use DPDK vhost library as the\ncommunication channel between Qemu and vhost-scsi target application.\n\nCurrently DPDK vhost library can only support VIRTIO_ID_NET device type,\nwe would like to extend the library to support VIRTIO_ID_SCSI and\nVIRTIO_ID_BLK. Most of DPDK vhost library can be reused only several\ndifferences:\n1. VIRTIO SCSI device has different vring queues compared with VIRTIO NET\ndevice, at least 3 vring queues needed for SCSI device type;\n2. VIRTIO SCSI will need several extra message operation code, such as\nSCSI_SET_ENDPIONT/SCSI_CLEAR_ENDPOINT;\n\nFirst, we would like to extend DPDK vhost library as a common framework\nwhich be friendly to add other VIRTIO device types, to implement this feature,\nwe add a new data structure virtio_dev, which can deliver socket messages\nto different VIRTIO devices, each specific VIRTIO device will register\ncallback to virtio_dev.\n\nSecondly, we would to upstream a patch to Qemu community to add vhost-scsi\nspecific operation command such as SCSI_SET_ENDPOINT and SCSI_CLEAR_ENDOINT,\nand user space feature bits.\n\nFinally, after the Qemu patch set was merged, we will add VIRTIO_ID_SCSI\nsupport to DPDK vhost library and an example vhost-scsi target which can\nadd a SCSI device to VM through this example application.\n\nThis patch set changed the vhost library as a common framework which\ncan add other VIRTIO device type in future.\n\nSigned-off-by: Changpeng Liu <changpeng.liu@intel.com>\n---\n lib/librte_vhost/Makefile         |   4 +-\n lib/librte_vhost/rte_virtio_dev.h | 140 ++++++++\n lib/librte_vhost/rte_virtio_net.h |  97 +-----\n lib/librte_vhost/socket.c         |   6 +-\n lib/librte_vhost/vhost.c          | 421 ------------------------\n lib/librte_vhost/vhost.h          | 288 -----------------\n lib/librte_vhost/vhost_device.h   | 230 +++++++++++++\n lib/librte_vhost/vhost_net.c      | 659 ++++++++++++++++++++++++++++++++++++++\n lib/librte_vhost/vhost_net.h      | 126 ++++++++\n lib/librte_vhost/vhost_user.c     | 451 +++++++++++++-------------\n lib/librte_vhost/vhost_user.h     |  17 +-\n lib/librte_vhost/virtio_net.c     |  37 ++-\n 12 files changed, 1426 insertions(+), 1050 deletions(-)\n create mode 100644 lib/librte_vhost/rte_virtio_dev.h\n delete mode 100644 lib/librte_vhost/vhost.c\n delete mode 100644 lib/librte_vhost/vhost.h\n create mode 100644 lib/librte_vhost/vhost_device.h\n create mode 100644 lib/librte_vhost/vhost_net.c\n create mode 100644 lib/librte_vhost/vhost_net.h",
    "diff": "diff --git a/lib/librte_vhost/Makefile b/lib/librte_vhost/Makefile\nindex 415ffc6..af30491 100644\n--- a/lib/librte_vhost/Makefile\n+++ b/lib/librte_vhost/Makefile\n@@ -47,11 +47,11 @@ LDLIBS += -lnuma\n endif\n \n # all source are stored in SRCS-y\n-SRCS-$(CONFIG_RTE_LIBRTE_VHOST) := fd_man.c socket.c vhost.c vhost_user.c \\\n+SRCS-$(CONFIG_RTE_LIBRTE_VHOST) := fd_man.c socket.c vhost_net.c vhost_user.c \\\n \t\t\t\t   virtio_net.c\n \n # install includes\n-SYMLINK-$(CONFIG_RTE_LIBRTE_VHOST)-include += rte_virtio_net.h\n+SYMLINK-$(CONFIG_RTE_LIBRTE_VHOST)-include += rte_virtio_net.h rte_virtio_dev.h\n \n # dependencies\n DEPDIRS-$(CONFIG_RTE_LIBRTE_VHOST) += lib/librte_eal\ndiff --git a/lib/librte_vhost/rte_virtio_dev.h b/lib/librte_vhost/rte_virtio_dev.h\nnew file mode 100644\nindex 0000000..e3c857a\n--- /dev/null\n+++ b/lib/librte_vhost/rte_virtio_dev.h\n@@ -0,0 +1,140 @@\n+/*-\n+ *   BSD LICENSE\n+ *\n+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.\n+ *   All rights reserved.\n+ *\n+ *   Redistribution and use in source and binary forms, with or without\n+ *   modification, are permitted provided that the following conditions\n+ *   are met:\n+ *\n+ *     * Redistributions of source code must retain the above copyright\n+ *       notice, this list of conditions and the following disclaimer.\n+ *     * Redistributions in binary form must reproduce the above copyright\n+ *       notice, this list of conditions and the following disclaimer in\n+ *       the documentation and/or other materials provided with the\n+ *       distribution.\n+ *     * Neither the name of Intel Corporation nor the names of its\n+ *       contributors may be used to endorse or promote products derived\n+ *       from this software without specific prior written permission.\n+ *\n+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n+ *   \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+ */\n+\n+#ifndef _VIRTIO_DEV_H_\n+#define _VIRTIO_DEV_H_\n+\n+/* Device types and capabilities flag */\n+#define RTE_VHOST_USER_CLIENT\t\t(1ULL << 0)\n+#define RTE_VHOST_USER_NO_RECONNECT\t(1ULL << 1)\n+#define RTE_VHOST_USER_TX_ZERO_COPY\t(1ULL << 2)\n+\n+#define RTE_VHOST_USER_DEV_NET\t\t(1ULL << 32)\n+\n+/**\n+ * Device and vring operations.\n+ *\n+ * Make sure to set VIRTIO_DEV_RUNNING to the device flags in new_device and\n+ * remove it in destroy_device.\n+ *\n+ */\n+struct virtio_net_device_ops {\n+\tint (*new_device)(int vid);\t\t/**< Add device. */\n+\tvoid (*destroy_device)(int vid);\t/**< Remove device. */\n+\n+\tint (*vring_state_changed)(int vid, uint16_t queue_id, int enable);\t/**< triggered when a vring is enabled or disabled */\n+\n+\tvoid *reserved[5]; /**< Reserved for future extension */\n+};\n+\n+/**\n+ *  Disable features in feature_mask. Returns 0 on success.\n+ */\n+int rte_vhost_feature_disable(uint64_t feature_mask);\n+\n+/**\n+ *  Enable features in feature_mask. Returns 0 on success.\n+ */\n+int rte_vhost_feature_enable(uint64_t feature_mask);\n+\n+/* Returns currently supported vhost features */\n+uint64_t rte_vhost_feature_get(void);\n+\n+int rte_vhost_enable_guest_notification(int vid, uint16_t queue_id, int enable);\n+\n+/**\n+ * Register vhost driver. path could be different for multiple\n+ * instance support.\n+ */\n+int rte_vhost_driver_register(const char *path, uint64_t flags);\n+\n+/* Unregister vhost driver. This is only meaningful to vhost user. */\n+int rte_vhost_driver_unregister(const char *path);\n+\n+/* Start vhost driver session blocking loop. */\n+int rte_vhost_driver_session_start(void);\n+\n+/**\n+ * Get the numa node from which the virtio net device's memory\n+ * is allocated.\n+ *\n+ * @param vid\n+ *  virtio-net device ID\n+ *\n+ * @return\n+ *  The numa node, -1 on failure\n+ */\n+int rte_vhost_get_numa_node(int vid);\n+\n+/**\n+ * Get the number of queues the device supports.\n+ *\n+ * @param vid\n+ *  virtio-net device ID\n+ *\n+ * @return\n+ *  The number of queues, 0 on failure\n+ */\n+uint32_t rte_vhost_get_queue_num(int vid);\n+\n+/**\n+ * Get how many avail entries are left in the queue\n+ *\n+ * @param vid\n+ *  virtio-net device ID\n+ * @param queue_id\n+ *  virtio queue index\n+ *\n+ * @return\n+ *  num of avail entires left\n+ */\n+uint16_t rte_vhost_avail_entries(int vid, uint16_t queue_id);\n+\n+/**\n+ * Get the virtio net device's ifname. For vhost-cuse, ifname is the\n+ * path of the char device. For vhost-user, ifname is the vhost-user\n+ * socket file path.\n+ *\n+ * @param vid\n+ *  virtio-net device ID\n+ * @param buf\n+ *  The buffer to stored the queried ifname\n+ * @param len\n+ *  The length of buf\n+ *\n+ * @return\n+ *  0 on success, -1 on failure\n+ */\n+int rte_vhost_get_ifname(int vid, char *buf, size_t len);\n+\n+#endif /* _VIRTIO_DEV_H_ */\n\\ No newline at end of file\ndiff --git a/lib/librte_vhost/rte_virtio_net.h b/lib/librte_vhost/rte_virtio_net.h\nindex 3ddc9ca..86ede8a 100644\n--- a/lib/librte_vhost/rte_virtio_net.h\n+++ b/lib/librte_vhost/rte_virtio_net.h\n@@ -50,107 +50,14 @@\n #include <rte_memory.h>\n #include <rte_mempool.h>\n #include <rte_ether.h>\n-\n-#define RTE_VHOST_USER_CLIENT\t\t(1ULL << 0)\n-#define RTE_VHOST_USER_NO_RECONNECT\t(1ULL << 1)\n-#define RTE_VHOST_USER_TX_ZERO_COPY\t(1ULL << 2)\n+#include <rte_virtio_dev.h>\n \n /* Enum for virtqueue management. */\n enum {VIRTIO_RXQ, VIRTIO_TXQ, VIRTIO_QNUM};\n \n-/**\n- * Device and vring operations.\n- */\n-struct virtio_net_device_ops {\n-\tint (*new_device)(int vid);\t\t/**< Add device. */\n-\tvoid (*destroy_device)(int vid);\t/**< Remove device. */\n-\n-\tint (*vring_state_changed)(int vid, uint16_t queue_id, int enable);\t/**< triggered when a vring is enabled or disabled */\n-\n-\tvoid *reserved[5]; /**< Reserved for future extension */\n-};\n-\n-/**\n- *  Disable features in feature_mask. Returns 0 on success.\n- */\n-int rte_vhost_feature_disable(uint64_t feature_mask);\n-\n-/**\n- *  Enable features in feature_mask. Returns 0 on success.\n- */\n-int rte_vhost_feature_enable(uint64_t feature_mask);\n-\n-/* Returns currently supported vhost features */\n-uint64_t rte_vhost_feature_get(void);\n-\n-int rte_vhost_enable_guest_notification(int vid, uint16_t queue_id, int enable);\n-\n-/**\n- * Register vhost driver. path could be different for multiple\n- * instance support.\n- */\n-int rte_vhost_driver_register(const char *path, uint64_t flags);\n-\n-/* Unregister vhost driver. This is only meaningful to vhost user. */\n-int rte_vhost_driver_unregister(const char *path);\n-\n /* Register callbacks. */\n int rte_vhost_driver_callback_register(struct virtio_net_device_ops const * const);\n-/* Start vhost driver session blocking loop. */\n-int rte_vhost_driver_session_start(void);\n-\n-/**\n- * Get the numa node from which the virtio net device's memory\n- * is allocated.\n- *\n- * @param vid\n- *  virtio-net device ID\n- *\n- * @return\n- *  The numa node, -1 on failure\n- */\n-int rte_vhost_get_numa_node(int vid);\n \n-/**\n- * Get the number of queues the device supports.\n- *\n- * @param vid\n- *  virtio-net device ID\n- *\n- * @return\n- *  The number of queues, 0 on failure\n- */\n-uint32_t rte_vhost_get_queue_num(int vid);\n-\n-/**\n- * Get the virtio net device's ifname. For vhost-cuse, ifname is the\n- * path of the char device. For vhost-user, ifname is the vhost-user\n- * socket file path.\n- *\n- * @param vid\n- *  virtio-net device ID\n- * @param buf\n- *  The buffer to stored the queried ifname\n- * @param len\n- *  The length of buf\n- *\n- * @return\n- *  0 on success, -1 on failure\n- */\n-int rte_vhost_get_ifname(int vid, char *buf, size_t len);\n-\n-/**\n- * Get how many avail entries are left in the queue\n- *\n- * @param vid\n- *  virtio-net device ID\n- * @param queue_id\n- *  virtio queue index\n- *\n- * @return\n- *  num of avail entires left\n- */\n-uint16_t rte_vhost_avail_entries(int vid, uint16_t queue_id);\n \n /**\n  * This function adds buffers to the virtio devices RX virtqueue. Buffers can\n@@ -191,4 +98,4 @@ uint16_t rte_vhost_enqueue_burst(int vid, uint16_t queue_id,\n uint16_t rte_vhost_dequeue_burst(int vid, uint16_t queue_id,\n \tstruct rte_mempool *mbuf_pool, struct rte_mbuf **pkts, uint16_t count);\n \n-#endif /* _VIRTIO_NET_H_ */\n+#endif /* _VIRTIO_NET_H_ */\n\\ No newline at end of file\ndiff --git a/lib/librte_vhost/socket.c b/lib/librte_vhost/socket.c\nindex 5c3962d..1474c98 100644\n--- a/lib/librte_vhost/socket.c\n+++ b/lib/librte_vhost/socket.c\n@@ -49,7 +49,7 @@\n #include <rte_log.h>\n \n #include \"fd_man.h\"\n-#include \"vhost.h\"\n+#include \"vhost_device.h\"\n #include \"vhost_user.h\"\n \n /*\n@@ -62,6 +62,7 @@ struct vhost_user_socket {\n \tint connfd;\n \tbool is_server;\n \tbool reconnect;\n+\tint type;\n \tbool tx_zero_copy;\n };\n \n@@ -194,7 +195,7 @@ vhost_user_add_connection(int fd, struct vhost_user_socket *vsocket)\n \t\treturn;\n \t}\n \n-\tvid = vhost_new_device();\n+\tvid = vhost_new_device(vsocket->type);\n \tif (vid == -1) {\n \t\tclose(fd);\n \t\tfree(conn);\n@@ -525,6 +526,7 @@ rte_vhost_driver_register(const char *path, uint64_t flags)\n \t\tgoto out;\n \t}\n \n+\tvsocket->type = VIRTIO_ID_NET;\n \tvhost_user.vsockets[vhost_user.vsocket_cnt++] = vsocket;\n \n out:\ndiff --git a/lib/librte_vhost/vhost.c b/lib/librte_vhost/vhost.c\ndeleted file mode 100644\nindex 5461e5b..0000000\n--- a/lib/librte_vhost/vhost.c\n+++ /dev/null\n@@ -1,421 +0,0 @@\n-/*-\n- *   BSD LICENSE\n- *\n- *   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.\n- *   All rights reserved.\n- *\n- *   Redistribution and use in source and binary forms, with or without\n- *   modification, are permitted provided that the following conditions\n- *   are met:\n- *\n- *     * Redistributions of source code must retain the above copyright\n- *       notice, this list of conditions and the following disclaimer.\n- *     * Redistributions in binary form must reproduce the above copyright\n- *       notice, this list of conditions and the following disclaimer in\n- *       the documentation and/or other materials provided with the\n- *       distribution.\n- *     * Neither the name of Intel Corporation nor the names of its\n- *       contributors may be used to endorse or promote products derived\n- *       from this software without specific prior written permission.\n- *\n- *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n- *   \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n- *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n- *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n- *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n- *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n- *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n- *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n- *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n- *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n- *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n- */\n-\n-#include <linux/vhost.h>\n-#include <linux/virtio_net.h>\n-#include <stddef.h>\n-#include <stdint.h>\n-#include <stdlib.h>\n-#ifdef RTE_LIBRTE_VHOST_NUMA\n-#include <numaif.h>\n-#endif\n-\n-#include <rte_ethdev.h>\n-#include <rte_log.h>\n-#include <rte_string_fns.h>\n-#include <rte_memory.h>\n-#include <rte_malloc.h>\n-#include <rte_virtio_net.h>\n-\n-#include \"vhost.h\"\n-\n-#define VHOST_USER_F_PROTOCOL_FEATURES\t30\n-\n-/* Features supported by this lib. */\n-#define VHOST_SUPPORTED_FEATURES ((1ULL << VIRTIO_NET_F_MRG_RXBUF) | \\\n-\t\t\t\t(1ULL << VIRTIO_NET_F_CTRL_VQ) | \\\n-\t\t\t\t(1ULL << VIRTIO_NET_F_CTRL_RX) | \\\n-\t\t\t\t(1ULL << VIRTIO_NET_F_GUEST_ANNOUNCE) | \\\n-\t\t\t\t(VHOST_SUPPORTS_MQ)            | \\\n-\t\t\t\t(1ULL << VIRTIO_F_VERSION_1)   | \\\n-\t\t\t\t(1ULL << VHOST_F_LOG_ALL)      | \\\n-\t\t\t\t(1ULL << VHOST_USER_F_PROTOCOL_FEATURES) | \\\n-\t\t\t\t(1ULL << VIRTIO_NET_F_HOST_TSO4) | \\\n-\t\t\t\t(1ULL << VIRTIO_NET_F_HOST_TSO6) | \\\n-\t\t\t\t(1ULL << VIRTIO_NET_F_CSUM)    | \\\n-\t\t\t\t(1ULL << VIRTIO_NET_F_GUEST_CSUM) | \\\n-\t\t\t\t(1ULL << VIRTIO_NET_F_GUEST_TSO4) | \\\n-\t\t\t\t(1ULL << VIRTIO_NET_F_GUEST_TSO6))\n-\n-uint64_t VHOST_FEATURES = VHOST_SUPPORTED_FEATURES;\n-\n-struct virtio_net *vhost_devices[MAX_VHOST_DEVICE];\n-\n-/* device ops to add/remove device to/from data core. */\n-struct virtio_net_device_ops const *notify_ops;\n-\n-struct virtio_net *\n-get_device(int vid)\n-{\n-\tstruct virtio_net *dev = vhost_devices[vid];\n-\n-\tif (unlikely(!dev)) {\n-\t\tRTE_LOG(ERR, VHOST_CONFIG,\n-\t\t\t\"(%d) device not found.\\n\", vid);\n-\t}\n-\n-\treturn dev;\n-}\n-\n-static void\n-cleanup_vq(struct vhost_virtqueue *vq, int destroy)\n-{\n-\tif ((vq->callfd >= 0) && (destroy != 0))\n-\t\tclose(vq->callfd);\n-\tif (vq->kickfd >= 0)\n-\t\tclose(vq->kickfd);\n-}\n-\n-/*\n- * Unmap any memory, close any file descriptors and\n- * free any memory owned by a device.\n- */\n-void\n-cleanup_device(struct virtio_net *dev, int destroy)\n-{\n-\tuint32_t i;\n-\n-\tvhost_backend_cleanup(dev);\n-\n-\tfor (i = 0; i < dev->virt_qp_nb; i++) {\n-\t\tcleanup_vq(dev->virtqueue[i * VIRTIO_QNUM + VIRTIO_RXQ], destroy);\n-\t\tcleanup_vq(dev->virtqueue[i * VIRTIO_QNUM + VIRTIO_TXQ], destroy);\n-\t}\n-}\n-\n-/*\n- * Release virtqueues and device memory.\n- */\n-static void\n-free_device(struct virtio_net *dev)\n-{\n-\tuint32_t i;\n-\n-\tfor (i = 0; i < dev->virt_qp_nb; i++)\n-\t\trte_free(dev->virtqueue[i * VIRTIO_QNUM]);\n-\n-\trte_free(dev);\n-}\n-\n-static void\n-init_vring_queue(struct vhost_virtqueue *vq, int qp_idx)\n-{\n-\tmemset(vq, 0, sizeof(struct vhost_virtqueue));\n-\n-\tvq->kickfd = VIRTIO_UNINITIALIZED_EVENTFD;\n-\tvq->callfd = VIRTIO_UNINITIALIZED_EVENTFD;\n-\n-\t/* Backends are set to -1 indicating an inactive device. */\n-\tvq->backend = -1;\n-\n-\t/* always set the default vq pair to enabled */\n-\tif (qp_idx == 0)\n-\t\tvq->enabled = 1;\n-\n-\tTAILQ_INIT(&vq->zmbuf_list);\n-}\n-\n-static void\n-init_vring_queue_pair(struct virtio_net *dev, uint32_t qp_idx)\n-{\n-\tuint32_t base_idx = qp_idx * VIRTIO_QNUM;\n-\n-\tinit_vring_queue(dev->virtqueue[base_idx + VIRTIO_RXQ], qp_idx);\n-\tinit_vring_queue(dev->virtqueue[base_idx + VIRTIO_TXQ], qp_idx);\n-}\n-\n-static void\n-reset_vring_queue(struct vhost_virtqueue *vq, int qp_idx)\n-{\n-\tint callfd;\n-\n-\tcallfd = vq->callfd;\n-\tinit_vring_queue(vq, qp_idx);\n-\tvq->callfd = callfd;\n-}\n-\n-static void\n-reset_vring_queue_pair(struct virtio_net *dev, uint32_t qp_idx)\n-{\n-\tuint32_t base_idx = qp_idx * VIRTIO_QNUM;\n-\n-\treset_vring_queue(dev->virtqueue[base_idx + VIRTIO_RXQ], qp_idx);\n-\treset_vring_queue(dev->virtqueue[base_idx + VIRTIO_TXQ], qp_idx);\n-}\n-\n-int\n-alloc_vring_queue_pair(struct virtio_net *dev, uint32_t qp_idx)\n-{\n-\tstruct vhost_virtqueue *virtqueue = NULL;\n-\tuint32_t virt_rx_q_idx = qp_idx * VIRTIO_QNUM + VIRTIO_RXQ;\n-\tuint32_t virt_tx_q_idx = qp_idx * VIRTIO_QNUM + VIRTIO_TXQ;\n-\n-\tvirtqueue = rte_malloc(NULL,\n-\t\t\t       sizeof(struct vhost_virtqueue) * VIRTIO_QNUM, 0);\n-\tif (virtqueue == NULL) {\n-\t\tRTE_LOG(ERR, VHOST_CONFIG,\n-\t\t\t\"Failed to allocate memory for virt qp:%d.\\n\", qp_idx);\n-\t\treturn -1;\n-\t}\n-\n-\tdev->virtqueue[virt_rx_q_idx] = virtqueue;\n-\tdev->virtqueue[virt_tx_q_idx] = virtqueue + VIRTIO_TXQ;\n-\n-\tinit_vring_queue_pair(dev, qp_idx);\n-\n-\tdev->virt_qp_nb += 1;\n-\n-\treturn 0;\n-}\n-\n-/*\n- * Reset some variables in device structure, while keeping few\n- * others untouched, such as vid, ifname, virt_qp_nb: they\n- * should be same unless the device is removed.\n- */\n-void\n-reset_device(struct virtio_net *dev)\n-{\n-\tuint32_t i;\n-\n-\tdev->features = 0;\n-\tdev->protocol_features = 0;\n-\tdev->flags = 0;\n-\n-\tfor (i = 0; i < dev->virt_qp_nb; i++)\n-\t\treset_vring_queue_pair(dev, i);\n-}\n-\n-/*\n- * Function is called from the CUSE open function. The device structure is\n- * initialised and a new entry is added to the device configuration linked\n- * list.\n- */\n-int\n-vhost_new_device(void)\n-{\n-\tstruct virtio_net *dev;\n-\tint i;\n-\n-\tdev = rte_zmalloc(NULL, sizeof(struct virtio_net), 0);\n-\tif (dev == NULL) {\n-\t\tRTE_LOG(ERR, VHOST_CONFIG,\n-\t\t\t\"Failed to allocate memory for new dev.\\n\");\n-\t\treturn -1;\n-\t}\n-\n-\tfor (i = 0; i < MAX_VHOST_DEVICE; i++) {\n-\t\tif (vhost_devices[i] == NULL)\n-\t\t\tbreak;\n-\t}\n-\tif (i == MAX_VHOST_DEVICE) {\n-\t\tRTE_LOG(ERR, VHOST_CONFIG,\n-\t\t\t\"Failed to find a free slot for new device.\\n\");\n-\t\treturn -1;\n-\t}\n-\n-\tvhost_devices[i] = dev;\n-\tdev->vid = i;\n-\n-\treturn i;\n-}\n-\n-/*\n- * Function is called from the CUSE release function. This function will\n- * cleanup the device and remove it from device configuration linked list.\n- */\n-void\n-vhost_destroy_device(int vid)\n-{\n-\tstruct virtio_net *dev = get_device(vid);\n-\n-\tif (dev == NULL)\n-\t\treturn;\n-\n-\tif (dev->flags & VIRTIO_DEV_RUNNING) {\n-\t\tdev->flags &= ~VIRTIO_DEV_RUNNING;\n-\t\tnotify_ops->destroy_device(vid);\n-\t}\n-\n-\tcleanup_device(dev, 1);\n-\tfree_device(dev);\n-\n-\tvhost_devices[vid] = NULL;\n-}\n-\n-void\n-vhost_set_ifname(int vid, const char *if_name, unsigned int if_len)\n-{\n-\tstruct virtio_net *dev;\n-\tunsigned int len;\n-\n-\tdev = get_device(vid);\n-\tif (dev == NULL)\n-\t\treturn;\n-\n-\tlen = if_len > sizeof(dev->ifname) ?\n-\t\tsizeof(dev->ifname) : if_len;\n-\n-\tstrncpy(dev->ifname, if_name, len);\n-\tdev->ifname[sizeof(dev->ifname) - 1] = '\\0';\n-}\n-\n-void\n-vhost_enable_tx_zero_copy(int vid)\n-{\n-\tstruct virtio_net *dev = get_device(vid);\n-\n-\tif (dev == NULL)\n-\t\treturn;\n-\n-\tdev->tx_zero_copy = 1;\n-}\n-\n-int\n-rte_vhost_get_numa_node(int vid)\n-{\n-#ifdef RTE_LIBRTE_VHOST_NUMA\n-\tstruct virtio_net *dev = get_device(vid);\n-\tint numa_node;\n-\tint ret;\n-\n-\tif (dev == NULL)\n-\t\treturn -1;\n-\n-\tret = get_mempolicy(&numa_node, NULL, 0, dev,\n-\t\t\t    MPOL_F_NODE | MPOL_F_ADDR);\n-\tif (ret < 0) {\n-\t\tRTE_LOG(ERR, VHOST_CONFIG,\n-\t\t\t\"(%d) failed to query numa node: %d\\n\", vid, ret);\n-\t\treturn -1;\n-\t}\n-\n-\treturn numa_node;\n-#else\n-\tRTE_SET_USED(vid);\n-\treturn -1;\n-#endif\n-}\n-\n-uint32_t\n-rte_vhost_get_queue_num(int vid)\n-{\n-\tstruct virtio_net *dev = get_device(vid);\n-\n-\tif (dev == NULL)\n-\t\treturn 0;\n-\n-\treturn dev->virt_qp_nb;\n-}\n-\n-int\n-rte_vhost_get_ifname(int vid, char *buf, size_t len)\n-{\n-\tstruct virtio_net *dev = get_device(vid);\n-\n-\tif (dev == NULL)\n-\t\treturn -1;\n-\n-\tlen = RTE_MIN(len, sizeof(dev->ifname));\n-\n-\tstrncpy(buf, dev->ifname, len);\n-\tbuf[len - 1] = '\\0';\n-\n-\treturn 0;\n-}\n-\n-uint16_t\n-rte_vhost_avail_entries(int vid, uint16_t queue_id)\n-{\n-\tstruct virtio_net *dev;\n-\tstruct vhost_virtqueue *vq;\n-\n-\tdev = get_device(vid);\n-\tif (!dev)\n-\t\treturn 0;\n-\n-\tvq = dev->virtqueue[queue_id];\n-\tif (!vq->enabled)\n-\t\treturn 0;\n-\n-\treturn *(volatile uint16_t *)&vq->avail->idx - vq->last_used_idx;\n-}\n-\n-int\n-rte_vhost_enable_guest_notification(int vid, uint16_t queue_id, int enable)\n-{\n-\tstruct virtio_net *dev = get_device(vid);\n-\n-\tif (dev == NULL)\n-\t\treturn -1;\n-\n-\tif (enable) {\n-\t\tRTE_LOG(ERR, VHOST_CONFIG,\n-\t\t\t\"guest notification isn't supported.\\n\");\n-\t\treturn -1;\n-\t}\n-\n-\tdev->virtqueue[queue_id]->used->flags = VRING_USED_F_NO_NOTIFY;\n-\treturn 0;\n-}\n-\n-uint64_t rte_vhost_feature_get(void)\n-{\n-\treturn VHOST_FEATURES;\n-}\n-\n-int rte_vhost_feature_disable(uint64_t feature_mask)\n-{\n-\tVHOST_FEATURES = VHOST_FEATURES & ~feature_mask;\n-\treturn 0;\n-}\n-\n-int rte_vhost_feature_enable(uint64_t feature_mask)\n-{\n-\tif ((feature_mask & VHOST_SUPPORTED_FEATURES) == feature_mask) {\n-\t\tVHOST_FEATURES = VHOST_FEATURES | feature_mask;\n-\t\treturn 0;\n-\t}\n-\treturn -1;\n-}\n-\n-/*\n- * Register ops so that we can add/remove device to data core.\n- */\n-int\n-rte_vhost_driver_callback_register(struct virtio_net_device_ops const * const ops)\n-{\n-\tnotify_ops = ops;\n-\n-\treturn 0;\n-}\ndiff --git a/lib/librte_vhost/vhost.h b/lib/librte_vhost/vhost.h\ndeleted file mode 100644\nindex 7e4a15e..0000000\n--- a/lib/librte_vhost/vhost.h\n+++ /dev/null\n@@ -1,288 +0,0 @@\n-/*-\n- *   BSD LICENSE\n- *\n- *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.\n- *   All rights reserved.\n- *\n- *   Redistribution and use in source and binary forms, with or without\n- *   modification, are permitted provided that the following conditions\n- *   are met:\n- *\n- *     * Redistributions of source code must retain the above copyright\n- *       notice, this list of conditions and the following disclaimer.\n- *     * Redistributions in binary form must reproduce the above copyright\n- *       notice, this list of conditions and the following disclaimer in\n- *       the documentation and/or other materials provided with the\n- *       distribution.\n- *     * Neither the name of Intel Corporation nor the names of its\n- *       contributors may be used to endorse or promote products derived\n- *       from this software without specific prior written permission.\n- *\n- *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n- *   \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n- *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n- *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n- *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n- *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n- *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n- *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n- *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n- *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n- *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n- */\n-\n-#ifndef _VHOST_NET_CDEV_H_\n-#define _VHOST_NET_CDEV_H_\n-#include <stdint.h>\n-#include <stdio.h>\n-#include <sys/types.h>\n-#include <sys/queue.h>\n-#include <unistd.h>\n-#include <linux/vhost.h>\n-\n-#include <rte_log.h>\n-\n-#include \"rte_virtio_net.h\"\n-\n-/* Used to indicate that the device is running on a data core */\n-#define VIRTIO_DEV_RUNNING 1\n-\n-/* Backend value set by guest. */\n-#define VIRTIO_DEV_STOPPED -1\n-\n-#define BUF_VECTOR_MAX 256\n-\n-/**\n- * Structure contains buffer address, length and descriptor index\n- * from vring to do scatter RX.\n- */\n-struct buf_vector {\n-\tuint64_t buf_addr;\n-\tuint32_t buf_len;\n-\tuint32_t desc_idx;\n-};\n-\n-/*\n- * A structure to hold some fields needed in zero copy code path,\n- * mainly for associating an mbuf with the right desc_idx.\n- */\n-struct zcopy_mbuf {\n-\tstruct rte_mbuf *mbuf;\n-\tuint32_t desc_idx;\n-\tuint16_t in_use;\n-\n-\tTAILQ_ENTRY(zcopy_mbuf) next;\n-};\n-TAILQ_HEAD(zcopy_mbuf_list, zcopy_mbuf);\n-\n-/**\n- * Structure contains variables relevant to RX/TX virtqueues.\n- */\n-struct vhost_virtqueue {\n-\tstruct vring_desc\t*desc;\n-\tstruct vring_avail\t*avail;\n-\tstruct vring_used\t*used;\n-\tuint32_t\t\tsize;\n-\n-\tuint16_t\t\tlast_avail_idx;\n-\tvolatile uint16_t\tlast_used_idx;\n-#define VIRTIO_INVALID_EVENTFD\t\t(-1)\n-#define VIRTIO_UNINITIALIZED_EVENTFD\t(-2)\n-\n-\t/* Backend value to determine if device should started/stopped */\n-\tint\t\t\tbackend;\n-\t/* Used to notify the guest (trigger interrupt) */\n-\tint\t\t\tcallfd;\n-\t/* Currently unused as polling mode is enabled */\n-\tint\t\t\tkickfd;\n-\tint\t\t\tenabled;\n-\n-\t/* Physical address of used ring, for logging */\n-\tuint64_t\t\tlog_guest_addr;\n-\n-\tuint16_t\t\tnr_zmbuf;\n-\tuint16_t\t\tzmbuf_size;\n-\tuint16_t\t\tlast_zmbuf_idx;\n-\tstruct zcopy_mbuf\t*zmbufs;\n-\tstruct zcopy_mbuf_list\tzmbuf_list;\n-} __rte_cache_aligned;\n-\n-/* Old kernels have no such macro defined */\n-#ifndef VIRTIO_NET_F_GUEST_ANNOUNCE\n- #define VIRTIO_NET_F_GUEST_ANNOUNCE 21\n-#endif\n-\n-\n-/*\n- * Make an extra wrapper for VIRTIO_NET_F_MQ and\n- * VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX as they are\n- * introduced since kernel v3.8. This makes our\n- * code buildable for older kernel.\n- */\n-#ifdef VIRTIO_NET_F_MQ\n- #define VHOST_MAX_QUEUE_PAIRS\tVIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX\n- #define VHOST_SUPPORTS_MQ\t(1ULL << VIRTIO_NET_F_MQ)\n-#else\n- #define VHOST_MAX_QUEUE_PAIRS\t1\n- #define VHOST_SUPPORTS_MQ\t0\n-#endif\n-\n-/*\n- * Define virtio 1.0 for older kernels\n- */\n-#ifndef VIRTIO_F_VERSION_1\n- #define VIRTIO_F_VERSION_1 32\n-#endif\n-\n-struct guest_page {\n-\tuint64_t guest_phys_addr;\n-\tuint64_t host_phys_addr;\n-\tuint64_t size;\n-};\n-\n-/**\n- * Device structure contains all configuration information relating\n- * to the device.\n- */\n-struct virtio_net {\n-\t/* Frontend (QEMU) memory and memory region information */\n-\tstruct virtio_memory\t*mem;\n-\tuint64_t\t\tfeatures;\n-\tuint64_t\t\tprotocol_features;\n-\tint\t\t\tvid;\n-\tuint32_t\t\tflags;\n-\tuint16_t\t\tvhost_hlen;\n-\t/* to tell if we need broadcast rarp packet */\n-\trte_atomic16_t\t\tbroadcast_rarp;\n-\tuint32_t\t\tvirt_qp_nb;\n-\tint\t\t\ttx_zero_copy;\n-\tstruct vhost_virtqueue\t*virtqueue[VHOST_MAX_QUEUE_PAIRS * 2];\n-#define IF_NAME_SZ (PATH_MAX > IFNAMSIZ ? PATH_MAX : IFNAMSIZ)\n-\tchar\t\t\tifname[IF_NAME_SZ];\n-\tuint64_t\t\tlog_size;\n-\tuint64_t\t\tlog_base;\n-\tuint64_t\t\tlog_addr;\n-\tstruct ether_addr\tmac;\n-\n-\tuint32_t\t\tnr_guest_pages;\n-\tuint32_t\t\tmax_guest_pages;\n-\tstruct guest_page       *guest_pages;\n-} __rte_cache_aligned;\n-\n-/**\n- * Information relating to memory regions including offsets to\n- * addresses in QEMUs memory file.\n- */\n-struct virtio_memory_region {\n-\tuint64_t guest_phys_addr;\n-\tuint64_t guest_user_addr;\n-\tuint64_t host_user_addr;\n-\tuint64_t size;\n-\tvoid\t *mmap_addr;\n-\tuint64_t mmap_size;\n-\tint fd;\n-};\n-\n-\n-/**\n- * Memory structure includes region and mapping information.\n- */\n-struct virtio_memory {\n-\tuint32_t nregions;\n-\tstruct virtio_memory_region regions[0];\n-};\n-\n-\n-/* Macros for printing using RTE_LOG */\n-#define RTE_LOGTYPE_VHOST_CONFIG RTE_LOGTYPE_USER1\n-#define RTE_LOGTYPE_VHOST_DATA   RTE_LOGTYPE_USER1\n-\n-#ifdef RTE_LIBRTE_VHOST_DEBUG\n-#define VHOST_MAX_PRINT_BUFF 6072\n-#define LOG_LEVEL RTE_LOG_DEBUG\n-#define LOG_DEBUG(log_type, fmt, args...) RTE_LOG(DEBUG, log_type, fmt, ##args)\n-#define PRINT_PACKET(device, addr, size, header) do { \\\n-\tchar *pkt_addr = (char *)(addr); \\\n-\tunsigned int index; \\\n-\tchar packet[VHOST_MAX_PRINT_BUFF]; \\\n-\t\\\n-\tif ((header)) \\\n-\t\tsnprintf(packet, VHOST_MAX_PRINT_BUFF, \"(%d) Header size %d: \", (device->vid), (size)); \\\n-\telse \\\n-\t\tsnprintf(packet, VHOST_MAX_PRINT_BUFF, \"(%d) Packet size %d: \", (device->vid), (size)); \\\n-\tfor (index = 0; index < (size); index++) { \\\n-\t\tsnprintf(packet + strnlen(packet, VHOST_MAX_PRINT_BUFF), VHOST_MAX_PRINT_BUFF - strnlen(packet, VHOST_MAX_PRINT_BUFF), \\\n-\t\t\t\"%02hhx \", pkt_addr[index]); \\\n-\t} \\\n-\tsnprintf(packet + strnlen(packet, VHOST_MAX_PRINT_BUFF), VHOST_MAX_PRINT_BUFF - strnlen(packet, VHOST_MAX_PRINT_BUFF), \"\\n\"); \\\n-\t\\\n-\tLOG_DEBUG(VHOST_DATA, \"%s\", packet); \\\n-} while (0)\n-#else\n-#define LOG_LEVEL RTE_LOG_INFO\n-#define LOG_DEBUG(log_type, fmt, args...) do {} while (0)\n-#define PRINT_PACKET(device, addr, size, header) do {} while (0)\n-#endif\n-\n-extern uint64_t VHOST_FEATURES;\n-#define MAX_VHOST_DEVICE\t1024\n-extern struct virtio_net *vhost_devices[MAX_VHOST_DEVICE];\n-\n-/* Convert guest physical Address to host virtual address */\n-static inline uint64_t __attribute__((always_inline))\n-gpa_to_vva(struct virtio_net *dev, uint64_t gpa)\n-{\n-\tstruct virtio_memory_region *reg;\n-\tuint32_t i;\n-\n-\tfor (i = 0; i < dev->mem->nregions; i++) {\n-\t\treg = &dev->mem->regions[i];\n-\t\tif (gpa >= reg->guest_phys_addr &&\n-\t\t    gpa <  reg->guest_phys_addr + reg->size) {\n-\t\t\treturn gpa - reg->guest_phys_addr +\n-\t\t\t       reg->host_user_addr;\n-\t\t}\n-\t}\n-\n-\treturn 0;\n-}\n-\n-/* Convert guest physical address to host physical address */\n-static inline phys_addr_t __attribute__((always_inline))\n-gpa_to_hpa(struct virtio_net *dev, uint64_t gpa, uint64_t size)\n-{\n-\tuint32_t i;\n-\tstruct guest_page *page;\n-\n-\tfor (i = 0; i < dev->nr_guest_pages; i++) {\n-\t\tpage = &dev->guest_pages[i];\n-\n-\t\tif (gpa >= page->guest_phys_addr &&\n-\t\t    gpa + size < page->guest_phys_addr + page->size) {\n-\t\t\treturn gpa - page->guest_phys_addr +\n-\t\t\t       page->host_phys_addr;\n-\t\t}\n-\t}\n-\n-\treturn 0;\n-}\n-\n-struct virtio_net_device_ops const *notify_ops;\n-struct virtio_net *get_device(int vid);\n-\n-int vhost_new_device(void);\n-void cleanup_device(struct virtio_net *dev, int destroy);\n-void reset_device(struct virtio_net *dev);\n-void vhost_destroy_device(int);\n-\n-int alloc_vring_queue_pair(struct virtio_net *dev, uint32_t qp_idx);\n-\n-void vhost_set_ifname(int, const char *if_name, unsigned int if_len);\n-void vhost_enable_tx_zero_copy(int vid);\n-\n-/*\n- * Backend-specific cleanup. Defined by vhost-cuse and vhost-user.\n- */\n-void vhost_backend_cleanup(struct virtio_net *dev);\n-\n-#endif /* _VHOST_NET_CDEV_H_ */\ndiff --git a/lib/librte_vhost/vhost_device.h b/lib/librte_vhost/vhost_device.h\nnew file mode 100644\nindex 0000000..7101bb0\n--- /dev/null\n+++ b/lib/librte_vhost/vhost_device.h\n@@ -0,0 +1,230 @@\n+/*-\n+ *   BSD LICENSE\n+ *\n+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.\n+ *   All rights reserved.\n+ *\n+ *   Redistribution and use in source and binary forms, with or without\n+ *   modification, are permitted provided that the following conditions\n+ *   are met:\n+ *\n+ *     * Redistributions of source code must retain the above copyright\n+ *       notice, this list of conditions and the following disclaimer.\n+ *     * Redistributions in binary form must reproduce the above copyright\n+ *       notice, this list of conditions and the following disclaimer in\n+ *       the documentation and/or other materials provided with the\n+ *       distribution.\n+ *     * Neither the name of Intel Corporation nor the names of its\n+ *       contributors may be used to endorse or promote products derived\n+ *       from this software without specific prior written permission.\n+ *\n+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n+ *   \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+ */\n+\n+#ifndef _VHOST_DEVICE_H_\n+#define _VHOST_DEVICE_H_\n+\n+#include <linux/virtio_ids.h>\n+\n+#include \"vhost_net.h\"\n+#include \"vhost_user.h\"\n+\n+/* Used to indicate that the device is running on a data core */\n+#define VIRTIO_DEV_RUNNING 1\n+\n+/* Backend value set by guest. */\n+#define VIRTIO_DEV_STOPPED -1\n+\n+/**\n+ * Structure contains variables relevant to RX/TX virtqueues.\n+ */\n+struct vhost_virtqueue {\n+\tstruct vring_desc\t*desc;\n+\tstruct vring_avail\t*avail;\n+\tstruct vring_used\t*used;\n+\tuint32_t\t\tsize;\n+\n+\tuint16_t\t\tlast_avail_idx;\n+\tvolatile uint16_t\tlast_used_idx;\n+#define VIRTIO_INVALID_EVENTFD\t\t(-1)\n+#define VIRTIO_UNINITIALIZED_EVENTFD\t(-2)\n+\n+\t/* Backend value to determine if device should started/stopped */\n+\tint\t\t\tbackend;\n+\t/* Used to notify the guest (trigger interrupt) */\n+\tint\t\t\tcallfd;\n+\t/* Currently unused as polling mode is enabled */\n+\tint\t\t\tkickfd;\n+\tint\t\t\tenabled;\n+\n+\t/* Physical address of used ring, for logging */\n+\tuint64_t\t\tlog_guest_addr;\n+\n+\tuint16_t\t\tnr_zmbuf;\n+\tuint16_t\t\tzmbuf_size;\n+\tuint16_t\t\tlast_zmbuf_idx;\n+\tstruct zcopy_mbuf\t*zmbufs;\n+\tstruct zcopy_mbuf_list\tzmbuf_list;\n+} __rte_cache_aligned;\n+\n+struct virtio_dev;\n+\n+struct virtio_dev_table {\n+\tint (*vhost_dev_ready)(struct virtio_dev *dev);\n+\tstruct vhost_virtqueue* (*vhost_dev_get_queues)(struct virtio_dev *dev, uint16_t queue_id);\n+\tvoid (*vhost_dev_cleanup)(struct virtio_dev *dev, int destroy);\n+\tvoid (*vhost_dev_free)(struct virtio_dev *dev);\n+\tvoid (*vhost_dev_reset)(struct virtio_dev *dev);\n+\tuint64_t (*vhost_dev_get_features)(struct virtio_dev *dev);\n+\tint (*vhost_dev_set_features)(struct virtio_dev *dev, uint64_t features);\n+\tuint64_t (*vhost_dev_get_protocol_features)(struct virtio_dev *dev);\n+\tint (*vhost_dev_set_protocol_features)(struct virtio_dev *dev, uint64_t features);\n+\tuint32_t (*vhost_dev_get_default_queue_num)(struct virtio_dev *dev);\n+\tuint32_t (*vhost_dev_get_queue_num)(struct virtio_dev *dev);\n+\tuint16_t (*vhost_dev_get_avail_entries)(struct virtio_dev *dev, uint16_t queue_id);\n+\tint (*vhost_dev_get_vring_base)(struct virtio_dev *dev, struct vhost_virtqueue *vq);\n+\tint (*vhost_dev_set_vring_num)(struct virtio_dev *dev, struct vhost_virtqueue *vq);\n+\tint (*vhost_dev_set_vring_call)(struct virtio_dev *dev, struct vhost_vring_file *file);\n+\tint (*vhost_dev_set_log_base)(struct virtio_dev *dev, int fd, uint64_t size, uint64_t off);\n+};\n+\n+struct virtio_dev {\n+\t/* Frontend (QEMU) memory and memory region information */\n+\tstruct virtio_memory\t*mem;\n+\tint\t\t\tvid;\n+\tuint32_t\t\tflags;\n+\t#define IF_NAME_SZ (PATH_MAX > IFNAMSIZ ? PATH_MAX : IFNAMSIZ)\n+\tchar\t\t\tifname[IF_NAME_SZ];\n+\n+\tuint32_t\t\tdev_type;\n+\tunion {\n+\t\tstruct virtio_net\tnet_dev;\n+\t} dev;\n+\n+\tuint32_t\t\tnr_guest_pages;\n+\tuint32_t\t\tmax_guest_pages;\n+\tstruct guest_page       *guest_pages;\n+\n+\tconst struct virtio_net_device_ops\t*notify_ops;\n+\tstruct virtio_dev_table fn_table;\n+} __rte_cache_aligned;\n+\n+extern struct virtio_net_device_ops const *notify_ops;\n+\n+/*\n+ * Define virtio 1.0 for older kernels\n+ */\n+#ifndef VIRTIO_F_VERSION_1\n+ #define VIRTIO_F_VERSION_1 32\n+#endif\n+\n+struct guest_page {\n+\tuint64_t guest_phys_addr;\n+\tuint64_t host_phys_addr;\n+\tuint64_t size;\n+};\n+\n+/**\n+ * Information relating to memory regions including offsets to\n+ * addresses in QEMUs memory file.\n+ */\n+struct virtio_memory_region {\n+\tuint64_t guest_phys_addr;\n+\tuint64_t guest_user_addr;\n+\tuint64_t host_user_addr;\n+\tuint64_t size;\n+\tvoid\t *mmap_addr;\n+\tuint64_t mmap_size;\n+\tint fd;\n+};\n+\n+/**\n+ * Memory structure includes region and mapping information.\n+ */\n+struct virtio_memory {\n+\tuint32_t nregions;\n+\tstruct virtio_memory_region regions[0];\n+};\n+\n+\n+/* Macros for printing using RTE_LOG */\n+#define RTE_LOGTYPE_VHOST_CONFIG RTE_LOGTYPE_USER1\n+#define RTE_LOGTYPE_VHOST_DATA   RTE_LOGTYPE_USER1\n+\n+#ifdef RTE_LIBRTE_VHOST_DEBUG\n+#define VHOST_MAX_PRINT_BUFF 6072\n+#define LOG_LEVEL RTE_LOG_DEBUG\n+#define LOG_DEBUG(log_type, fmt, args...) RTE_LOG(DEBUG, log_type, fmt, ##args)\n+#define PRINT_PACKET(device, addr, size, header) do { \\\n+\tchar *pkt_addr = (char *)(addr); \\\n+\tunsigned int index; \\\n+\tchar packet[VHOST_MAX_PRINT_BUFF]; \\\n+\t\\\n+\tif ((header)) \\\n+\t\tsnprintf(packet, VHOST_MAX_PRINT_BUFF, \"(%d) Header size %d: \", (device->vid), (size)); \\\n+\telse \\\n+\t\tsnprintf(packet, VHOST_MAX_PRINT_BUFF, \"(%d) Packet size %d: \", (device->vid), (size)); \\\n+\tfor (index = 0; index < (size); index++) { \\\n+\t\tsnprintf(packet + strnlen(packet, VHOST_MAX_PRINT_BUFF), VHOST_MAX_PRINT_BUFF - strnlen(packet, VHOST_MAX_PRINT_BUFF), \\\n+\t\t\t\"%02hhx \", pkt_addr[index]); \\\n+\t} \\\n+\tsnprintf(packet + strnlen(packet, VHOST_MAX_PRINT_BUFF), VHOST_MAX_PRINT_BUFF - strnlen(packet, VHOST_MAX_PRINT_BUFF), \"\\n\"); \\\n+\t\\\n+\tLOG_DEBUG(VHOST_DATA, \"%s\", packet); \\\n+} while (0)\n+#else\n+#define LOG_LEVEL RTE_LOG_INFO\n+#define LOG_DEBUG(log_type, fmt, args...) do {} while (0)\n+#define PRINT_PACKET(device, addr, size, header) do {} while (0)\n+#endif\n+\n+/* Convert guest physical Address to host virtual address */\n+static inline uint64_t __attribute__((always_inline))\n+gpa_to_vva(struct virtio_dev *dev, uint64_t gpa)\n+{\n+\tstruct virtio_memory_region *reg;\n+\tuint32_t i;\n+\n+\tfor (i = 0; i < dev->mem->nregions; i++) {\n+\t\treg = &dev->mem->regions[i];\n+\t\tif (gpa >= reg->guest_phys_addr &&\n+\t\t    gpa <  reg->guest_phys_addr + reg->size) {\n+\t\t\treturn gpa - reg->guest_phys_addr +\n+\t\t\t       reg->host_user_addr;\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n+/* Convert guest physical address to host physical address */\n+static inline phys_addr_t __attribute__((always_inline))\n+gpa_to_hpa(struct virtio_dev *dev, uint64_t gpa, uint64_t size)\n+{\n+\tuint32_t i;\n+\tstruct guest_page *page;\n+\n+\tfor (i = 0; i < dev->nr_guest_pages; i++) {\n+\t\tpage = &dev->guest_pages[i];\n+\n+\t\tif (gpa >= page->guest_phys_addr &&\n+\t\t    gpa + size < page->guest_phys_addr + page->size) {\n+\t\t\treturn gpa - page->guest_phys_addr +\n+\t\t\t       page->host_phys_addr;\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n+#endif\n\\ No newline at end of file\ndiff --git a/lib/librte_vhost/vhost_net.c b/lib/librte_vhost/vhost_net.c\nnew file mode 100644\nindex 0000000..f141b32\n--- /dev/null\n+++ b/lib/librte_vhost/vhost_net.c\n@@ -0,0 +1,659 @@\n+/*-\n+ *   BSD LICENSE\n+ *\n+ *   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.\n+ *   All rights reserved.\n+ *\n+ *   Redistribution and use in source and binary forms, with or without\n+ *   modification, are permitted provided that the following conditions\n+ *   are met:\n+ *\n+ *     * Redistributions of source code must retain the above copyright\n+ *       notice, this list of conditions and the following disclaimer.\n+ *     * Redistributions in binary form must reproduce the above copyright\n+ *       notice, this list of conditions and the following disclaimer in\n+ *       the documentation and/or other materials provided with the\n+ *       distribution.\n+ *     * Neither the name of Intel Corporation nor the names of its\n+ *       contributors may be used to endorse or promote products derived\n+ *       from this software without specific prior written permission.\n+ *\n+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n+ *   \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+ */\n+\n+#include <linux/vhost.h>\n+#include <linux/virtio_net.h>\n+#include <stddef.h>\n+#include <stdint.h>\n+#include <stdlib.h>\n+#include <assert.h>\n+#ifdef RTE_LIBRTE_VHOST_NUMA\n+#include <numaif.h>\n+#endif\n+#include <sys/mman.h>\n+\n+#include <rte_ethdev.h>\n+#include <rte_log.h>\n+#include <rte_string_fns.h>\n+#include <rte_memory.h>\n+#include <rte_malloc.h>\n+#include <rte_virtio_net.h>\n+\n+#include \"vhost_net.h\"\n+#include \"vhost_device.h\"\n+\n+#define VHOST_USER_F_PROTOCOL_FEATURES\t30\n+\n+/* Features supported by this lib. */\n+#define VHOST_SUPPORTED_FEATURES ((1ULL << VIRTIO_NET_F_MRG_RXBUF) | \\\n+\t\t\t\t(1ULL << VIRTIO_NET_F_CTRL_VQ) | \\\n+\t\t\t\t(1ULL << VIRTIO_NET_F_CTRL_RX) | \\\n+\t\t\t\t(1ULL << VIRTIO_NET_F_GUEST_ANNOUNCE) | \\\n+\t\t\t\t(VHOST_SUPPORTS_MQ)            | \\\n+\t\t\t\t(1ULL << VIRTIO_F_VERSION_1)   | \\\n+\t\t\t\t(1ULL << VHOST_F_LOG_ALL)      | \\\n+\t\t\t\t(1ULL << VHOST_USER_F_PROTOCOL_FEATURES) | \\\n+\t\t\t\t(1ULL << VIRTIO_NET_F_HOST_TSO4) | \\\n+\t\t\t\t(1ULL << VIRTIO_NET_F_HOST_TSO6) | \\\n+\t\t\t\t(1ULL << VIRTIO_NET_F_CSUM)    | \\\n+\t\t\t\t(1ULL << VIRTIO_NET_F_GUEST_CSUM) | \\\n+\t\t\t\t(1ULL << VIRTIO_NET_F_GUEST_TSO4) | \\\n+\t\t\t\t(1ULL << VIRTIO_NET_F_GUEST_TSO6))\n+\n+uint64_t VHOST_FEATURES = VHOST_SUPPORTED_FEATURES;\n+\n+/* device ops to add/remove device to/from data core. */\n+struct virtio_net_device_ops const *notify_ops = NULL;\n+\n+struct virtio_net *\n+get_net_device(struct virtio_dev *dev)\n+{\n+\tif (!dev)\n+\t\treturn NULL;\n+ \n+\treturn &dev->dev.net_dev;\n+}\n+\n+static void\n+cleanup_vq(struct vhost_virtqueue *vq, int destroy)\n+{\n+\tif ((vq->callfd >= 0) && (destroy != 0))\n+\t\tclose(vq->callfd);\n+\tif (vq->kickfd >= 0)\n+\t\tclose(vq->kickfd);\n+}\n+\n+/*\n+ * Unmap any memory, close any file descriptors and\n+ * free any memory owned by a device.\n+ */\n+static void\n+cleanup_device(struct virtio_dev *device, int destroy)\n+{\n+\tstruct virtio_net *dev = get_net_device(device);\n+\tuint32_t i;\n+\n+\tdev->features = 0;\n+\tdev->protocol_features = 0;\n+\n+\tfor (i = 0; i < dev->virt_qp_nb; i++) {\n+\t\tcleanup_vq(dev->virtqueue[i * VIRTIO_QNUM + VIRTIO_RXQ], destroy);\n+\t\tcleanup_vq(dev->virtqueue[i * VIRTIO_QNUM + VIRTIO_TXQ], destroy);\n+\t}\n+\n+\tif (dev->log_addr) {\n+\t\tmunmap((void *)(uintptr_t)dev->log_addr, dev->log_size);\n+\t\tdev->log_addr = 0;\n+\t}\n+}\n+\n+/*\n+ * Release virtqueues and device memory.\n+ */\n+static void\n+free_device(struct virtio_dev *device)\n+{\n+\tstruct virtio_net *dev = get_net_device(device);\n+\tuint32_t i;\n+\n+\tfor (i = 0; i < dev->virt_qp_nb; i++)\n+\t\trte_free(dev->virtqueue[i * VIRTIO_QNUM]);\n+\n+\trte_free(dev);\n+}\n+\n+static void\n+init_vring_queue(struct vhost_virtqueue *vq, int qp_idx)\n+{\n+\tmemset(vq, 0, sizeof(struct vhost_virtqueue));\n+\n+\tvq->kickfd = VIRTIO_UNINITIALIZED_EVENTFD;\n+\tvq->callfd = VIRTIO_UNINITIALIZED_EVENTFD;\n+\n+\t/* Backends are set to -1 indicating an inactive device. */\n+\tvq->backend = -1;\n+\n+\t/* always set the default vq pair to enabled */\n+\tif (qp_idx == 0)\n+\t\tvq->enabled = 1;\n+\n+\tTAILQ_INIT(&vq->zmbuf_list);\n+}\n+\n+static void\n+init_vring_queue_pair(struct virtio_net *dev, uint32_t qp_idx)\n+{\n+\tuint32_t base_idx = qp_idx * VIRTIO_QNUM;\n+\n+\tinit_vring_queue(dev->virtqueue[base_idx + VIRTIO_RXQ], qp_idx);\n+\tinit_vring_queue(dev->virtqueue[base_idx + VIRTIO_TXQ], qp_idx);\n+}\n+\n+static void\n+reset_vring_queue(struct vhost_virtqueue *vq, int qp_idx)\n+{\n+\tint callfd;\n+\n+\tcallfd = vq->callfd;\n+\tinit_vring_queue(vq, qp_idx);\n+\tvq->callfd = callfd;\n+}\n+\n+static void\n+reset_vring_queue_pair(struct virtio_net *dev, uint32_t qp_idx)\n+{\n+\tuint32_t base_idx = qp_idx * VIRTIO_QNUM;\n+\n+\treset_vring_queue(dev->virtqueue[base_idx + VIRTIO_RXQ], qp_idx);\n+\treset_vring_queue(dev->virtqueue[base_idx + VIRTIO_TXQ], qp_idx);\n+}\n+\n+static int\n+alloc_vring_queue_pair(struct virtio_net *dev, uint32_t qp_idx)\n+{\n+\tstruct vhost_virtqueue *virtqueue = NULL;\n+\tuint32_t virt_rx_q_idx = qp_idx * VIRTIO_QNUM + VIRTIO_RXQ;\n+\tuint32_t virt_tx_q_idx = qp_idx * VIRTIO_QNUM + VIRTIO_TXQ;\n+\n+\tvirtqueue = rte_malloc(NULL,\n+\t\t\t       sizeof(struct vhost_virtqueue) * VIRTIO_QNUM, 0);\n+\tif (virtqueue == NULL) {\n+\t\tRTE_LOG(ERR, VHOST_CONFIG,\n+\t\t\t\"Failed to allocate memory for virt qp:%d.\\n\", qp_idx);\n+\t\treturn -1;\n+\t}\n+\n+\tdev->virtqueue[virt_rx_q_idx] = virtqueue;\n+\tdev->virtqueue[virt_tx_q_idx] = virtqueue + VIRTIO_TXQ;\n+\n+\tinit_vring_queue_pair(dev, qp_idx);\n+\n+\tdev->virt_qp_nb += 1;\n+\n+\treturn 0;\n+}\n+\n+/*\n+ * Reset some variables in device structure, while keeping few\n+ * others untouched, such as vid, ifname, virt_qp_nb: they\n+ * should be same unless the device is removed.\n+ */\n+static void\n+reset_device(struct virtio_dev *device)\n+{\n+\tstruct virtio_net *dev = get_net_device(device);\n+\tuint32_t i;\n+\n+\tfor (i = 0; i < dev->virt_qp_nb; i++)\n+\t\treset_vring_queue_pair(dev, i);\n+}\n+\n+static uint64_t\n+vhost_dev_get_features(struct virtio_dev *dev)\n+{\n+\tif (dev == NULL)\n+\t\treturn 0;\n+\n+\treturn VHOST_FEATURES;\t\n+}\n+\n+static int\n+vhost_dev_set_features(struct virtio_dev *device, uint64_t features)\n+{\n+\tstruct virtio_net *dev = get_net_device(device);\n+\n+\tif (features & ~VHOST_FEATURES)\n+\t\treturn -1;\n+\n+\tdev->features = features;\n+\tif (dev->features &\n+\t\t((1 << VIRTIO_NET_F_MRG_RXBUF) | (1ULL << VIRTIO_F_VERSION_1))) {\n+\t\tdev->vhost_hlen = sizeof(struct virtio_net_hdr_mrg_rxbuf);\n+\t} else {\n+\t\tdev->vhost_hlen = sizeof(struct virtio_net_hdr);\n+\t}\n+\tLOG_DEBUG(VHOST_CONFIG,\n+\t\t\"(%d) mergeable RX buffers %s, virtio 1 %s\\n\",\n+\t\tdevice->vid,\n+\t\t(dev->features & (1 << VIRTIO_NET_F_MRG_RXBUF)) ? \"on\" : \"off\",\n+\t\t(dev->features & (1ULL << VIRTIO_F_VERSION_1)) ? \"on\" : \"off\");\n+\n+\treturn 0;\n+}\n+\n+static int\n+vhost_dev_set_vring_num(struct virtio_dev *device,\n+\t\t\t struct vhost_virtqueue *vq)\n+{\n+\tstruct virtio_net *dev = get_net_device(device);\n+\n+\tif (dev->tx_zero_copy) {\n+\t\tvq->nr_zmbuf = 0;\n+\t\tvq->last_zmbuf_idx = 0;\n+\t\tvq->zmbuf_size = vq->size;\n+\t\tvq->zmbufs = rte_zmalloc(NULL, vq->zmbuf_size *\n+\t\t\t\t\t sizeof(struct zcopy_mbuf), 0);\n+\t\tif (vq->zmbufs == NULL) {\n+\t\t\tRTE_LOG(WARNING, VHOST_CONFIG,\n+\t\t\t\t\"failed to allocate mem for zero copy; \"\n+\t\t\t\t\"zero copy is force disabled\\n\");\n+\t\t\tdev->tx_zero_copy = 0;\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int\n+vq_is_ready(struct vhost_virtqueue *vq)\n+{\n+\treturn vq && vq->desc   &&\n+\t       vq->kickfd != VIRTIO_UNINITIALIZED_EVENTFD &&\n+\t       vq->callfd != VIRTIO_UNINITIALIZED_EVENTFD;\n+}\n+\n+static int\n+vhost_dev_is_ready(struct virtio_dev *device)\n+{\n+\tstruct virtio_net *dev = get_net_device(device);\n+\tstruct vhost_virtqueue *rvq, *tvq;\n+\tuint32_t i;\n+\n+\tfor (i = 0; i < dev->virt_qp_nb; i++) {\n+\t\trvq = dev->virtqueue[i * VIRTIO_QNUM + VIRTIO_RXQ];\n+\t\ttvq = dev->virtqueue[i * VIRTIO_QNUM + VIRTIO_TXQ];\n+\n+\t\tif (!vq_is_ready(rvq) || !vq_is_ready(tvq)) {\n+\t\t\tRTE_LOG(INFO, VHOST_CONFIG,\n+\t\t\t\t\"virtio is not ready for processing.\\n\");\n+\t\t\treturn 0;\n+\t\t}\n+\t}\n+\n+\tRTE_LOG(INFO, VHOST_CONFIG,\n+\t\t\"virtio is now ready for processing.\\n\");\n+\treturn 1;\n+}\n+\n+static int\n+vhost_dev_set_vring_call(struct virtio_dev *device, struct vhost_vring_file *file)\n+{\n+\tstruct virtio_net *dev = get_net_device(device);\n+\tstruct vhost_virtqueue *vq;\n+\tuint32_t cur_qp_idx;\n+\n+\t/*\n+\t * FIXME: VHOST_SET_VRING_CALL is the first per-vring message\n+\t * we get, so we do vring queue pair allocation here.\n+\t */\n+\tcur_qp_idx = file->index / VIRTIO_QNUM;\n+\tif (cur_qp_idx + 1 > dev->virt_qp_nb) {\n+\t\tif (alloc_vring_queue_pair(dev, cur_qp_idx) < 0)\n+\t\t\treturn -1;\n+\t}\n+\n+\tvq = dev->virtqueue[file->index];\n+\tassert(vq != NULL);\n+\n+\tif (vq->callfd >= 0)\n+\t\tclose(vq->callfd);\n+\n+\tvq->callfd = file->fd;\n+\treturn 0;\n+}\n+\n+static int\n+vhost_dev_set_protocol_features(struct virtio_dev *device,\n+\t\t\t\t uint64_t protocol_features)\n+{\n+\tstruct virtio_net *dev = get_net_device(device);\n+\n+\tif (protocol_features & ~VHOST_USER_PROTOCOL_FEATURES)\n+\t\treturn -1;\n+\n+\tdev->protocol_features = protocol_features;\n+\treturn 0;\n+}\n+\n+static uint64_t\n+vhost_dev_get_protocol_features(struct virtio_dev *dev)\n+{\n+\tif (dev == NULL)\n+\t\treturn 0;\n+\n+\treturn VHOST_USER_PROTOCOL_FEATURES;\n+}\n+\n+static uint32_t\n+vhost_dev_get_default_queue_num(struct virtio_dev *dev)\n+{\n+\tif (dev == NULL)\n+\t\treturn 0;\n+\n+\treturn VHOST_MAX_QUEUE_PAIRS;\n+}\n+\n+static uint32_t\n+vhost_dev_get_queue_num(struct virtio_dev *device)\n+{\n+\tstruct virtio_net *dev;\n+\tif (device == NULL)\n+\t\treturn 0;\n+\n+\tdev = get_net_device(device);\n+\treturn dev->virt_qp_nb;\n+}\n+\n+static uint16_t\n+vhost_dev_get_avail_entries(struct virtio_dev *device, uint16_t queue_id)\n+{\n+\tstruct virtio_net *dev = get_net_device(device);\n+\tstruct vhost_virtqueue *vq;\n+\n+\tvq = dev->virtqueue[queue_id];\n+\tif (!vq->enabled)\n+\t\treturn 0;\n+\n+\treturn *(volatile uint16_t *)&vq->avail->idx - vq->last_used_idx;\n+}\n+\n+void\n+vhost_enable_tx_zero_copy(int vid)\n+{\n+\tstruct virtio_dev *device = get_device(vid);\n+\tstruct virtio_net *dev;\n+\n+\tif (device == NULL)\n+\t\treturn;\n+\n+\tdev = get_net_device(device);\n+\tdev->tx_zero_copy = 1;\n+}\n+\n+static void\n+free_zmbufs(struct vhost_virtqueue *vq)\n+{\n+\tstruct zcopy_mbuf *zmbuf, *next;\n+\n+\tfor (zmbuf = TAILQ_FIRST(&vq->zmbuf_list);\n+\t     zmbuf != NULL; zmbuf = next) {\n+\t\tnext = TAILQ_NEXT(zmbuf, next);\n+\n+\t\trte_pktmbuf_free(zmbuf->mbuf);\n+\t\tTAILQ_REMOVE(&vq->zmbuf_list, zmbuf, next);\n+\t}\n+\n+\trte_free(vq->zmbufs);\n+}\n+\n+static int\n+vhost_dev_get_vring_base(struct virtio_dev *device, struct vhost_virtqueue *vq)\n+{\n+\tstruct virtio_net *dev = get_net_device(device);\n+\n+\t/*\n+\t * Based on current qemu vhost-user implementation, this message is\n+\t * sent and only sent in vhost_vring_stop.\n+\t * TODO: cleanup the vring, it isn't usable since here.\n+\t */\n+\tif (vq->kickfd >= 0)\n+\t\tclose(vq->kickfd);\n+\n+\tvq->kickfd = VIRTIO_UNINITIALIZED_EVENTFD;\n+\n+\tif (dev->tx_zero_copy)\n+\t\tfree_zmbufs(vq);\n+\n+\treturn 0;\n+}\n+\n+static int\n+vhost_dev_set_log_base(struct virtio_dev *device, int fd, uint64_t size, uint64_t off)\n+{\n+\tvoid *addr;\n+\tstruct virtio_net *dev = get_net_device(device);\n+\n+\t/*\n+\t * mmap from 0 to workaround a hugepage mmap bug: mmap will\n+\t * fail when offset is not page size aligned.\n+\t */\n+\taddr = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);\n+\tclose(fd);\n+\tif (addr == MAP_FAILED) {\n+\t\tRTE_LOG(ERR, VHOST_CONFIG, \"mmap log base failed!\\n\");\n+\t\treturn -1;\n+\t}\n+\n+\t/*\n+\t * Free previously mapped log memory on occasionally\n+\t * multiple VHOST_USER_SET_LOG_BASE.\n+\t */\n+\tif (dev->log_addr) {\n+\t\tmunmap((void *)(uintptr_t)dev->log_addr, dev->log_size);\n+\t}\n+\tdev->log_addr = (uint64_t)(uintptr_t)addr;\n+\tdev->log_base = dev->log_addr + off;\n+\tdev->log_size = size;\n+\n+\treturn 0;\n+}\n+\n+/*\n+ * An rarp packet is constructed and broadcasted to notify switches about\n+ * the new location of the migrated VM, so that packets from outside will\n+ * not be lost after migration.\n+ *\n+ * However, we don't actually \"send\" a rarp packet here, instead, we set\n+ * a flag 'broadcast_rarp' to let rte_vhost_dequeue_burst() inject it.\n+ */\n+int\n+vhost_user_send_rarp(struct virtio_dev *device, struct VhostUserMsg *msg)\n+{\n+\tstruct virtio_net *dev = get_net_device(device);\n+\tuint8_t *mac = (uint8_t *)&msg->payload.u64;\n+\n+\tRTE_LOG(DEBUG, VHOST_CONFIG,\n+\t\t\":: mac: %02x:%02x:%02x:%02x:%02x:%02x\\n\",\n+\t\tmac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);\n+\tmemcpy(dev->mac.addr_bytes, mac, 6);\n+\n+\t/*\n+\t * Set the flag to inject a RARP broadcast packet at\n+\t * rte_vhost_dequeue_burst().\n+\t *\n+\t * rte_smp_wmb() is for making sure the mac is copied\n+\t * before the flag is set.\n+\t */\n+\trte_smp_wmb();\n+\trte_atomic16_set(&dev->broadcast_rarp, 1);\n+\n+\treturn 0;\n+}\n+\n+static struct vhost_virtqueue *\n+vhost_dev_get_queues(struct virtio_dev *device, uint16_t queue_id)\n+{\n+\tstruct virtio_net *dev = get_net_device(device);\n+\tstruct vhost_virtqueue *vq;\n+\n+\tvq = dev->virtqueue[queue_id];\n+\n+\treturn vq;\n+}\n+\n+void\n+vhost_net_device_init(struct virtio_dev *device)\n+{\n+\tstruct virtio_net *dev = get_net_device(device);\n+\n+\tdevice->fn_table.vhost_dev_ready  = vhost_dev_is_ready;\n+\tdevice->fn_table.vhost_dev_get_queues  = vhost_dev_get_queues;\n+\tdevice->fn_table.vhost_dev_cleanup = cleanup_device;\n+\tdevice->fn_table.vhost_dev_free  = free_device;\n+\tdevice->fn_table.vhost_dev_reset  = reset_device;\n+\tdevice->fn_table.vhost_dev_get_features  = vhost_dev_get_features;\n+\tdevice->fn_table.vhost_dev_set_features  = vhost_dev_set_features;\n+\tdevice->fn_table.vhost_dev_get_protocol_features  = vhost_dev_get_protocol_features;\n+\tdevice->fn_table.vhost_dev_set_protocol_features  = vhost_dev_set_protocol_features;\n+\tdevice->fn_table.vhost_dev_get_default_queue_num  = vhost_dev_get_default_queue_num;\n+\tdevice->fn_table.vhost_dev_get_queue_num  = vhost_dev_get_queue_num;\n+\tdevice->fn_table.vhost_dev_get_avail_entries  = vhost_dev_get_avail_entries;\n+\tdevice->fn_table.vhost_dev_get_vring_base  = vhost_dev_get_vring_base;\n+\tdevice->fn_table.vhost_dev_set_vring_num = vhost_dev_set_vring_num;\n+\tdevice->fn_table.vhost_dev_set_vring_call  = vhost_dev_set_vring_call;\n+\tdevice->fn_table.vhost_dev_set_log_base = vhost_dev_set_log_base;\n+\n+\tdev->device = device;\n+}\n+\n+uint64_t rte_vhost_feature_get(void)\n+{\n+\treturn VHOST_FEATURES;\n+}\n+\n+int rte_vhost_feature_disable(uint64_t feature_mask)\n+{\n+\tVHOST_FEATURES = VHOST_FEATURES & ~feature_mask;\n+\treturn 0;\n+}\n+\n+int rte_vhost_feature_enable(uint64_t feature_mask)\n+{\n+\tif ((feature_mask & VHOST_SUPPORTED_FEATURES) == feature_mask) {\n+\t\tVHOST_FEATURES = VHOST_FEATURES | feature_mask;\n+\t\treturn 0;\n+\t}\n+\treturn -1;\n+}\n+\n+int\n+rte_vhost_get_numa_node(int vid)\n+{\n+#ifdef RTE_LIBRTE_VHOST_NUMA\n+\tstruct virtio_dev *dev = get_device(vid);\n+\tint numa_node;\n+\tint ret;\n+\n+\tif (dev == NULL)\n+\t\treturn -1;\n+\n+\tret = get_mempolicy(&numa_node, NULL, 0, dev,\n+\t\t\t    MPOL_F_NODE | MPOL_F_ADDR);\n+\tif (ret < 0) {\n+\t\tRTE_LOG(ERR, VHOST_CONFIG,\n+\t\t\t\"(%d) failed to query numa node: %d\\n\", vid, ret);\n+\t\treturn -1;\n+\t}\n+\n+\treturn numa_node;\n+#else\n+\tRTE_SET_USED(vid);\n+\treturn -1;\n+#endif\n+}\n+\n+uint32_t\n+rte_vhost_get_queue_num(int vid)\n+{\n+\tstruct virtio_dev *device = get_device(vid);\n+\n+\tif (device == NULL)\n+\t\treturn 0;\n+\n+\tif (device->fn_table.vhost_dev_get_queue_num)\n+\t\treturn device->fn_table.vhost_dev_get_queue_num(device);\n+\n+\treturn 0;\n+}\n+\n+int\n+rte_vhost_get_ifname(int vid, char *buf, size_t len)\n+{\n+\tstruct virtio_dev *dev = get_device(vid);\n+\n+\tif (dev == NULL)\n+\t\treturn -1;\n+\n+\tlen = RTE_MIN(len, sizeof(dev->ifname));\n+\n+\tstrncpy(buf, dev->ifname, len);\n+\tbuf[len - 1] = '\\0';\n+\n+\treturn 0;\n+}\n+\n+uint16_t\n+rte_vhost_avail_entries(int vid, uint16_t queue_id)\n+{\n+\tstruct virtio_dev *device;\n+\n+\tdevice = get_device(vid);\n+\tif (!device)\n+\t\treturn 0;\n+\n+\tif (device->fn_table.vhost_dev_get_avail_entries)\n+\t\treturn device->fn_table.vhost_dev_get_avail_entries(device, queue_id);\n+\n+\treturn 0;\n+}\n+\n+int\n+rte_vhost_enable_guest_notification(int vid, uint16_t queue_id, int enable)\n+{\n+\tstruct virtio_dev *device = get_device(vid);\n+\tstruct vhost_virtqueue *vq;\n+\n+\tif (device == NULL)\n+\t\treturn -1;\n+\n+\tvq = device->fn_table.vhost_dev_get_queues(device, queue_id);\n+\tif (enable) {\n+\t\tRTE_LOG(ERR, VHOST_CONFIG,\n+\t\t\t\"guest notification isn't supported.\\n\");\n+\t\treturn -1;\n+\t}\n+\n+\tvq->used->flags = VRING_USED_F_NO_NOTIFY;\n+\treturn 0;\n+}\n+\n+/*\n+ * Register ops so that we can add/remove device to data core.\n+ */\n+int\n+rte_vhost_driver_callback_register(struct virtio_net_device_ops const * const ops)\n+{\n+\tnotify_ops = ops;\n+\n+\treturn 0;\n+}\n\\ No newline at end of file\ndiff --git a/lib/librte_vhost/vhost_net.h b/lib/librte_vhost/vhost_net.h\nnew file mode 100644\nindex 0000000..53b6b16\n--- /dev/null\n+++ b/lib/librte_vhost/vhost_net.h\n@@ -0,0 +1,126 @@\n+/*-\n+ *   BSD LICENSE\n+ *\n+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.\n+ *   All rights reserved.\n+ *\n+ *   Redistribution and use in source and binary forms, with or without\n+ *   modification, are permitted provided that the following conditions\n+ *   are met:\n+ *\n+ *     * Redistributions of source code must retain the above copyright\n+ *       notice, this list of conditions and the following disclaimer.\n+ *     * Redistributions in binary form must reproduce the above copyright\n+ *       notice, this list of conditions and the following disclaimer in\n+ *       the documentation and/or other materials provided with the\n+ *       distribution.\n+ *     * Neither the name of Intel Corporation nor the names of its\n+ *       contributors may be used to endorse or promote products derived\n+ *       from this software without specific prior written permission.\n+ *\n+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n+ *   \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+ */\n+\n+#ifndef _VHOST_NET_H_\n+#define _VHOST_NET_H_\n+#include <stdint.h>\n+#include <stdio.h>\n+#include <sys/types.h>\n+#include <sys/queue.h>\n+#include <unistd.h>\n+#include <linux/vhost.h>\n+\n+#include <rte_log.h>\n+\n+#include \"rte_virtio_net.h\"\n+#include \"vhost_user.h\"\n+\n+#define VHOST_USER_PROTOCOL_F_MQ\t0\n+#define VHOST_USER_PROTOCOL_F_LOG_SHMFD\t1\n+#define VHOST_USER_PROTOCOL_F_RARP\t2\n+\n+#define VHOST_USER_PROTOCOL_FEATURES\t((1ULL << VHOST_USER_PROTOCOL_F_MQ) | \\\n+\t\t\t\t\t (1ULL << VHOST_USER_PROTOCOL_F_LOG_SHMFD) |\\\n+\t\t\t\t\t (1ULL << VHOST_USER_PROTOCOL_F_RARP))\n+\n+#define BUF_VECTOR_MAX 256\n+\n+/**\n+ * Structure contains buffer address, length and descriptor index\n+ * from vring to do scatter RX.\n+ */\n+struct buf_vector {\n+\tuint64_t buf_addr;\n+\tuint32_t buf_len;\n+\tuint32_t desc_idx;\n+};\n+\n+/*\n+ * A structure to hold some fields needed in zero copy code path,\n+ * mainly for associating an mbuf with the right desc_idx.\n+ */\n+struct zcopy_mbuf {\n+\tstruct rte_mbuf *mbuf;\n+\tuint32_t desc_idx;\n+\tuint16_t in_use;\n+\n+\tTAILQ_ENTRY(zcopy_mbuf) next;\n+};\n+TAILQ_HEAD(zcopy_mbuf_list, zcopy_mbuf);\n+\n+/* Old kernels have no such macro defined */\n+#ifndef VIRTIO_NET_F_GUEST_ANNOUNCE\n+ #define VIRTIO_NET_F_GUEST_ANNOUNCE 21\n+#endif\n+\n+/*\n+ * Make an extra wrapper for VIRTIO_NET_F_MQ and\n+ * VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX as they are\n+ * introduced since kernel v3.8. This makes our\n+ * code buildable for older kernel.\n+ */\n+#ifdef VIRTIO_NET_F_MQ\n+ #define VHOST_MAX_QUEUE_PAIRS\tVIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX\n+ #define VHOST_SUPPORTS_MQ\t(1ULL << VIRTIO_NET_F_MQ)\n+#else\n+ #define VHOST_MAX_QUEUE_PAIRS\t1\n+ #define VHOST_SUPPORTS_MQ\t0\n+#endif\n+\n+/**\n+ * Device structure contains all configuration information relating\n+ * to the device.\n+ */\n+struct virtio_net {\n+\tuint64_t\t\tfeatures;\n+\tuint64_t\t\tprotocol_features;\n+\tuint16_t\t\tvhost_hlen;\n+\tuint64_t\t\tlog_size;\n+\tuint64_t\t\tlog_base;\n+\tuint64_t\t\tlog_addr;\n+\t/* to tell if we need broadcast rarp packet */\n+\trte_atomic16_t\t\tbroadcast_rarp;\n+\tuint32_t\t\tvirt_qp_nb;\n+\tint\t\t\ttx_zero_copy;\n+\tstruct vhost_virtqueue\t*virtqueue[VHOST_MAX_QUEUE_PAIRS * 2];\n+\tstruct ether_addr\tmac;\n+\t/* transport layer device context */\n+\tstruct virtio_dev\t*device;\n+} __rte_cache_aligned;\n+\n+void vhost_enable_tx_zero_copy(int vid);\n+int vhost_user_send_rarp(struct virtio_dev *device, struct VhostUserMsg *msg);\n+void vhost_net_device_init(struct virtio_dev *device);\n+struct virtio_net *get_net_device(struct virtio_dev *dev);\n+\n+#endif /* _VHOST_NET_H_ */\n\\ No newline at end of file\ndiff --git a/lib/librte_vhost/vhost_user.c b/lib/librte_vhost/vhost_user.c\nindex ff995d5..90c4b03 100644\n--- a/lib/librte_vhost/vhost_user.c\n+++ b/lib/librte_vhost/vhost_user.c\n@@ -48,9 +48,13 @@\n #include <rte_malloc.h>\n #include <rte_log.h>\n \n-#include \"vhost.h\"\n+#include \"vhost_device.h\"\n+#include \"vhost_net.h\"\n #include \"vhost_user.h\"\n \n+#define MAX_VHOST_DEVICE        1024\n+struct virtio_dev *vhost_devices[MAX_VHOST_DEVICE];\n+\n static const char *vhost_message_str[VHOST_USER_MAX] = {\n \t[VHOST_USER_NONE] = \"VHOST_USER_NONE\",\n \t[VHOST_USER_GET_FEATURES] = \"VHOST_USER_GET_FEATURES\",\n@@ -85,7 +89,7 @@ get_blk_size(int fd)\n }\n \n static void\n-free_mem_region(struct virtio_net *dev)\n+free_mem_region(struct virtio_dev *dev)\n {\n \tuint32_t i;\n \tstruct virtio_memory_region *reg;\n@@ -102,18 +106,99 @@ free_mem_region(struct virtio_net *dev)\n \t}\n }\n \n-void\n-vhost_backend_cleanup(struct virtio_net *dev)\n+static void\n+vhost_backend_cleanup(struct virtio_dev *dev)\n {\n \tif (dev->mem) {\n \t\tfree_mem_region(dev);\n-\t\trte_free(dev->mem);\n+\t\tfree(dev->mem);\n \t\tdev->mem = NULL;\n \t}\n-\tif (dev->log_addr) {\n-\t\tmunmap((void *)(uintptr_t)dev->log_addr, dev->log_size);\n-\t\tdev->log_addr = 0;\n+}\n+\n+struct virtio_dev *\n+get_device(int vid)\n+{\n+\tstruct virtio_dev *dev = vhost_devices[vid];\n+\n+\tif (unlikely(!dev)) {\n+\t\tRTE_LOG(ERR, VHOST_CONFIG,\n+\t\t\t\"(%d) device not found.\\n\", vid);\n+\t}\n+\n+\treturn dev;\n+}\n+\n+/*\n+ * Function is called from the CUSE open function. The device structure is\n+ * initialised and a new entry is added to the device configuration linked\n+ * list.\n+ */\n+int\n+vhost_new_device(int type)\n+{\n+\tstruct virtio_dev *dev;\n+\tint i;\n+\n+\tdev = rte_zmalloc(NULL, sizeof(struct virtio_dev), 0);\n+\tif (dev == NULL) {\n+\t\tRTE_LOG(ERR, VHOST_CONFIG,\n+\t\t\t\"Failed to allocate memory for new dev.\\n\");\n+\t\treturn -1;\n+\t}\n+\n+\tfor (i = 0; i < MAX_VHOST_DEVICE; i++) {\n+\t\tif (vhost_devices[i] == NULL)\n+\t\t\tbreak;\n+\t}\n+\tif (i == MAX_VHOST_DEVICE) {\n+\t\tRTE_LOG(ERR, VHOST_CONFIG,\n+\t\t\t\"Failed to find a free slot for new device.\\n\");\n+\t\treturn -1;\n+\t}\n+\n+\tswitch(type) {\n+\t\tcase VIRTIO_ID_NET:\n+\t\t\tdev->notify_ops = notify_ops;\n+\t\t\tvhost_net_device_init(dev);\n+\t\t\tassert(notify_ops != NULL);\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\treturn -1;\n+\t}\n+\n+\tvhost_devices[i] = dev;\n+\tdev->vid = i;\n+\tdev->dev_type = type;\n+\tassert(dev->fn_table.vhost_dev_get_queues != NULL);\n+\n+\treturn i;\n+}\n+\n+/*\n+ * Function is called from the CUSE release function. This function will\n+ * cleanup the device and remove it from device configuration linked list.\n+ */\n+void\n+vhost_destroy_device(int vid)\n+{\n+\tstruct virtio_dev *dev = get_device(vid);\n+\n+\tif (dev == NULL)\n+\t\treturn;\n+\n+\tif (dev->flags & VIRTIO_DEV_RUNNING) {\n+\t\tdev->flags &= ~VIRTIO_DEV_RUNNING;\n+\t\tdev->notify_ops->destroy_device(vid);\n \t}\n+\n+\tvhost_backend_cleanup(dev);\n+\tif (dev->fn_table.vhost_dev_cleanup)\n+\t\tdev->fn_table.vhost_dev_cleanup(dev, 1);\n+\tif (dev->fn_table.vhost_dev_free)\n+\t\tdev->fn_table.vhost_dev_free(dev);\n+\n+\tvhost_devices[vid] = NULL;\n }\n \n /*\n@@ -126,16 +211,28 @@ vhost_user_set_owner(void)\n \treturn 0;\n }\n \n+/*\n+ * Called from CUSE IOCTL: VHOST_RESET_OWNER\n+ */\n static int\n-vhost_user_reset_owner(struct virtio_net *dev)\n+vhost_user_reset_owner(struct virtio_dev *dev)\n {\n+\tif (dev == NULL)\n+\t\treturn -1;\n+\n \tif (dev->flags & VIRTIO_DEV_RUNNING) {\n \t\tdev->flags &= ~VIRTIO_DEV_RUNNING;\n-\t\tnotify_ops->destroy_device(dev->vid);\n+\t\tdev->notify_ops->destroy_device(dev->vid);\n \t}\n \n-\tcleanup_device(dev, 0);\n-\treset_device(dev);\n+\tdev->flags = 0;\n+\n+\tvhost_backend_cleanup(dev);\n+\tif (dev->fn_table.vhost_dev_cleanup)\n+\t\tdev->fn_table.vhost_dev_cleanup(dev, 0);\n+\tif (dev->fn_table.vhost_dev_reset)\n+\t\tdev->fn_table.vhost_dev_reset(dev);\n+\n \treturn 0;\n }\n \n@@ -143,61 +240,61 @@ vhost_user_reset_owner(struct virtio_net *dev)\n  * The features that we support are requested.\n  */\n static uint64_t\n-vhost_user_get_features(void)\n+vhost_user_get_features(struct virtio_dev *dev)\n {\n-\treturn VHOST_FEATURES;\n+\tif (dev == NULL)\n+\t\treturn 0;\n+\n+\tif (dev->fn_table.vhost_dev_get_features)\n+\t\treturn dev->fn_table.vhost_dev_get_features(dev);\n+\n+\treturn 0;\n }\n \n /*\n  * We receive the negotiated features supported by us and the virtio device.\n  */\n static int\n-vhost_user_set_features(struct virtio_net *dev, uint64_t features)\n+vhost_user_set_features(struct virtio_dev *dev, uint64_t pu)\n {\n-\tif (features & ~VHOST_FEATURES)\n-\t\treturn -1;\n+\tint ret = 0;\n \n-\tdev->features = features;\n-\tif (dev->features &\n-\t\t((1 << VIRTIO_NET_F_MRG_RXBUF) | (1ULL << VIRTIO_F_VERSION_1))) {\n-\t\tdev->vhost_hlen = sizeof(struct virtio_net_hdr_mrg_rxbuf);\n-\t} else {\n-\t\tdev->vhost_hlen = sizeof(struct virtio_net_hdr);\n-\t}\n-\tLOG_DEBUG(VHOST_CONFIG,\n-\t\t\"(%d) mergeable RX buffers %s, virtio 1 %s\\n\",\n-\t\tdev->vid,\n-\t\t(dev->features & (1 << VIRTIO_NET_F_MRG_RXBUF)) ? \"on\" : \"off\",\n-\t\t(dev->features & (1ULL << VIRTIO_F_VERSION_1)) ? \"on\" : \"off\");\n+\tif (dev->fn_table.vhost_dev_set_features)\n+\t\tret = dev->fn_table.vhost_dev_set_features(dev, pu);\n \n-\treturn 0;\n+\treturn ret;\n+}\n+\n+void\n+vhost_set_ifname(int vid, const char *if_name, unsigned int if_len)\n+{\n+\tstruct virtio_dev *dev;\n+\tunsigned int len;\n+\n+\tdev = get_device(vid);\n+\tif (dev == NULL)\n+\t\treturn;\n+\n+\tlen = if_len > sizeof(dev->ifname) ?\n+\t\tsizeof(dev->ifname) : if_len;\n+\n+\tstrncpy(dev->ifname, if_name, len);\n+\tdev->ifname[sizeof(dev->ifname) - 1] = '\\0';\n }\n \n /*\n  * The virtio device sends us the size of the descriptor ring.\n  */\n static int\n-vhost_user_set_vring_num(struct virtio_net *dev,\n-\t\t\t struct vhost_vring_state *state)\n+vhost_user_set_vring_num(struct virtio_dev *dev, struct vhost_vring_state *state)\n {\n-\tstruct vhost_virtqueue *vq = dev->virtqueue[state->index];\n+\tstruct vhost_virtqueue *vq;\n \n+\tvq = dev->fn_table.vhost_dev_get_queues(dev, state->index);\n \tvq->size = state->num;\n \n-\tif (dev->tx_zero_copy) {\n-\t\tvq->nr_zmbuf = 0;\n-\t\tvq->last_zmbuf_idx = 0;\n-\t\tvq->zmbuf_size = vq->size;\n-\t\tvq->zmbufs = rte_zmalloc(NULL, vq->zmbuf_size *\n-\t\t\t\t\t sizeof(struct zcopy_mbuf), 0);\n-\t\tif (vq->zmbufs == NULL) {\n-\t\t\tRTE_LOG(WARNING, VHOST_CONFIG,\n-\t\t\t\t\"failed to allocate mem for zero copy; \"\n-\t\t\t\t\"zero copy is force disabled\\n\");\n-\t\t\tdev->tx_zero_copy = 0;\n-\t\t}\n-\t}\n-\n+\tif (dev->fn_table.vhost_dev_set_vring_num)\n+\t\tdev->fn_table.vhost_dev_set_vring_num(dev, vq);\n \treturn 0;\n }\n \n@@ -206,11 +303,11 @@ vhost_user_set_vring_num(struct virtio_net *dev,\n  * same numa node as the memory of vring descriptor.\n  */\n #ifdef RTE_LIBRTE_VHOST_NUMA\n-static struct virtio_net*\n-numa_realloc(struct virtio_net *dev, int index)\n+static struct virtio_dev*\n+numa_realloc(struct virtio_dev *dev, int index)\n {\n \tint oldnode, newnode;\n-\tstruct virtio_net *old_dev;\n+\tstruct virtio_dev *old_dev;\n \tstruct vhost_virtqueue *old_vq, *vq;\n \tint ret;\n \n@@ -222,7 +319,7 @@ numa_realloc(struct virtio_net *dev, int index)\n \t\treturn dev;\n \n \told_dev = dev;\n-\tvq = old_vq = dev->virtqueue[index];\n+\tvq = old_vq = dev->fn_table.virtio_dev_get_queues(dev, index);\n \n \tret = get_mempolicy(&newnode, NULL, 0, old_vq->desc,\n \t\t\t    MPOL_F_NODE | MPOL_F_ADDR);\n@@ -277,8 +374,8 @@ out:\n \treturn dev;\n }\n #else\n-static struct virtio_net*\n-numa_realloc(struct virtio_net *dev, int index __rte_unused)\n+static struct virtio_dev*\n+numa_realloc(struct virtio_dev *dev, int index __rte_unused)\n {\n \treturn dev;\n }\n@@ -289,7 +386,7 @@ numa_realloc(struct virtio_net *dev, int index __rte_unused)\n  * used to convert the ring addresses to our address space.\n  */\n static uint64_t\n-qva_to_vva(struct virtio_net *dev, uint64_t qva)\n+qva_to_vva(struct virtio_dev *dev, uint64_t qva)\n {\n \tstruct virtio_memory_region *reg;\n \tuint32_t i;\n@@ -313,15 +410,14 @@ qva_to_vva(struct virtio_net *dev, uint64_t qva)\n  * This function then converts these to our address space.\n  */\n static int\n-vhost_user_set_vring_addr(struct virtio_net *dev, struct vhost_vring_addr *addr)\n+vhost_user_set_vring_addr(struct virtio_dev *dev, struct vhost_vring_addr *addr)\n {\n \tstruct vhost_virtqueue *vq;\n \n \tif (dev->mem == NULL)\n \t\treturn -1;\n \n-\t/* addr->index refers to the queue index. The txq 1, rxq is 0. */\n-\tvq = dev->virtqueue[addr->index];\n+\tvq = dev->fn_table.vhost_dev_get_queues(dev, addr->index);\n \n \t/* The addresses are converted from QEMU virtual to Vhost virtual. */\n \tvq->desc = (struct vring_desc *)(uintptr_t)qva_to_vva(dev,\n@@ -334,7 +430,7 @@ vhost_user_set_vring_addr(struct virtio_net *dev, struct vhost_vring_addr *addr)\n \t}\n \n \tdev = numa_realloc(dev, addr->index);\n-\tvq = dev->virtqueue[addr->index];\n+\tvq = dev->fn_table.vhost_dev_get_queues(dev, addr->index);\n \n \tvq->avail = (struct vring_avail *)(uintptr_t)qva_to_vva(dev,\n \t\t\taddr->avail_user_addr);\n@@ -381,17 +477,19 @@ vhost_user_set_vring_addr(struct virtio_net *dev, struct vhost_vring_addr *addr)\n  * The virtio device sends us the available ring last used index.\n  */\n static int\n-vhost_user_set_vring_base(struct virtio_net *dev,\n-\t\t\t  struct vhost_vring_state *state)\n+vhost_user_set_vring_base(struct virtio_dev *dev, struct vhost_vring_state *state)\n {\n-\tdev->virtqueue[state->index]->last_used_idx  = state->num;\n-\tdev->virtqueue[state->index]->last_avail_idx = state->num;\n+\tstruct vhost_virtqueue *vq;\n+\n+\tvq = dev->fn_table.vhost_dev_get_queues(dev, state->index);\n+\tvq->last_used_idx = state->num;\n+\tvq->last_avail_idx = state->num;\n \n \treturn 0;\n }\n \n static void\n-add_one_guest_page(struct virtio_net *dev, uint64_t guest_phys_addr,\n+add_one_guest_page(struct virtio_dev *dev, uint64_t guest_phys_addr,\n \t\t   uint64_t host_phys_addr, uint64_t size)\n {\n \tstruct guest_page *page, *last_page;\n@@ -419,7 +517,7 @@ add_one_guest_page(struct virtio_net *dev, uint64_t guest_phys_addr,\n }\n \n static void\n-add_guest_pages(struct virtio_net *dev, struct virtio_memory_region *reg,\n+add_guest_pages(struct virtio_dev *dev, struct virtio_memory_region *reg,\n \t\tuint64_t page_size)\n {\n \tuint64_t reg_size = reg->size;\n@@ -450,7 +548,7 @@ add_guest_pages(struct virtio_net *dev, struct virtio_memory_region *reg,\n #ifdef RTE_LIBRTE_VHOST_DEBUG\n /* TODO: enable it only in debug mode? */\n static void\n-dump_guest_pages(struct virtio_net *dev)\n+dump_guest_pages(struct virtio_dev *dev)\n {\n \tuint32_t i;\n \tstruct guest_page *page;\n@@ -474,7 +572,7 @@ dump_guest_pages(struct virtio_net *dev)\n #endif\n \n static int\n-vhost_user_set_mem_table(struct virtio_net *dev, struct VhostUserMsg *pmsg)\n+vhost_user_set_mem_table(struct virtio_dev *dev, struct VhostUserMsg *pmsg)\n {\n \tstruct VhostUserMemory memory = pmsg->payload.memory;\n \tstruct virtio_memory_region *reg;\n@@ -488,7 +586,7 @@ vhost_user_set_mem_table(struct virtio_net *dev, struct VhostUserMsg *pmsg)\n \t/* Remove from the data plane. */\n \tif (dev->flags & VIRTIO_DEV_RUNNING) {\n \t\tdev->flags &= ~VIRTIO_DEV_RUNNING;\n-\t\tnotify_ops->destroy_device(dev->vid);\n+\t\tdev->notify_ops->destroy_device(dev->vid);\n \t}\n \n \tif (dev->mem) {\n@@ -588,41 +686,22 @@ err_mmap:\n }\n \n static int\n-vq_is_ready(struct vhost_virtqueue *vq)\n-{\n-\treturn vq && vq->desc   &&\n-\t       vq->kickfd != VIRTIO_UNINITIALIZED_EVENTFD &&\n-\t       vq->callfd != VIRTIO_UNINITIALIZED_EVENTFD;\n-}\n-\n-static int\n-virtio_is_ready(struct virtio_net *dev)\n+virtio_is_ready(struct virtio_dev *dev)\n {\n-\tstruct vhost_virtqueue *rvq, *tvq;\n-\tuint32_t i;\n-\n-\tfor (i = 0; i < dev->virt_qp_nb; i++) {\n-\t\trvq = dev->virtqueue[i * VIRTIO_QNUM + VIRTIO_RXQ];\n-\t\ttvq = dev->virtqueue[i * VIRTIO_QNUM + VIRTIO_TXQ];\n-\n-\t\tif (!vq_is_ready(rvq) || !vq_is_ready(tvq)) {\n-\t\t\tRTE_LOG(INFO, VHOST_CONFIG,\n-\t\t\t\t\"virtio is not ready for processing.\\n\");\n-\t\t\treturn 0;\n-\t\t}\n-\t}\n+\tif (dev->fn_table.vhost_dev_ready)\n+\t\treturn dev->fn_table.vhost_dev_ready(dev);\n \n-\tRTE_LOG(INFO, VHOST_CONFIG,\n-\t\t\"virtio is now ready for processing.\\n\");\n-\treturn 1;\n+\treturn -1;\n }\n \n+/*\n+ *  In vhost-user, when we receive kick message, will test whether virtio\n+ *  device is ready for packet processing.\n+ */\n static void\n-vhost_user_set_vring_call(struct virtio_net *dev, struct VhostUserMsg *pmsg)\n+vhost_user_set_vring_call(struct virtio_dev *dev, struct VhostUserMsg *pmsg)\n {\n \tstruct vhost_vring_file file;\n-\tstruct vhost_virtqueue *vq;\n-\tuint32_t cur_qp_idx;\n \n \tfile.index = pmsg->payload.u64 & VHOST_USER_VRING_IDX_MASK;\n \tif (pmsg->payload.u64 & VHOST_USER_VRING_NOFD_MASK)\n@@ -632,23 +711,8 @@ vhost_user_set_vring_call(struct virtio_net *dev, struct VhostUserMsg *pmsg)\n \tRTE_LOG(INFO, VHOST_CONFIG,\n \t\t\"vring call idx:%d file:%d\\n\", file.index, file.fd);\n \n-\t/*\n-\t * FIXME: VHOST_SET_VRING_CALL is the first per-vring message\n-\t * we get, so we do vring queue pair allocation here.\n-\t */\n-\tcur_qp_idx = file.index / VIRTIO_QNUM;\n-\tif (cur_qp_idx + 1 > dev->virt_qp_nb) {\n-\t\tif (alloc_vring_queue_pair(dev, cur_qp_idx) < 0)\n-\t\t\treturn;\n-\t}\n-\n-\tvq = dev->virtqueue[file.index];\n-\tassert(vq != NULL);\n-\n-\tif (vq->callfd >= 0)\n-\t\tclose(vq->callfd);\n-\n-\tvq->callfd = file.fd;\n+\tif (dev->fn_table.vhost_dev_set_vring_call)\n+\t\tdev->fn_table.vhost_dev_set_vring_call(dev, &file);\n }\n \n /*\n@@ -656,11 +720,14 @@ vhost_user_set_vring_call(struct virtio_net *dev, struct VhostUserMsg *pmsg)\n  *  device is ready for packet processing.\n  */\n static void\n-vhost_user_set_vring_kick(struct virtio_net *dev, struct VhostUserMsg *pmsg)\n+vhost_user_set_vring_kick(struct virtio_dev *dev, struct VhostUserMsg *pmsg)\n {\n \tstruct vhost_vring_file file;\n \tstruct vhost_virtqueue *vq;\n \n+\tif (!dev)\n+\t\treturn;\n+\n \tfile.index = pmsg->payload.u64 & VHOST_USER_VRING_IDX_MASK;\n \tif (pmsg->payload.u64 & VHOST_USER_VRING_NOFD_MASK)\n \t\tfile.fd = VIRTIO_INVALID_EVENTFD;\n@@ -668,69 +735,44 @@ vhost_user_set_vring_kick(struct virtio_net *dev, struct VhostUserMsg *pmsg)\n \t\tfile.fd = pmsg->fds[0];\n \tRTE_LOG(INFO, VHOST_CONFIG,\n \t\t\"vring kick idx:%d file:%d\\n\", file.index, file.fd);\n-\n-\tvq = dev->virtqueue[file.index];\n+\tvq = dev->fn_table.vhost_dev_get_queues(dev, file.index);\n \tif (vq->kickfd >= 0)\n \t\tclose(vq->kickfd);\n+\n \tvq->kickfd = file.fd;\n \n \tif (virtio_is_ready(dev) && !(dev->flags & VIRTIO_DEV_RUNNING)) {\n-\t\tif (dev->tx_zero_copy) {\n-\t\t\tRTE_LOG(INFO, VHOST_CONFIG,\n-\t\t\t\t\"Tx zero copy is enabled\\n\");\n-\t\t}\n-\n-\t\tif (notify_ops->new_device(dev->vid) == 0)\n+\t\tif (dev->notify_ops->new_device(dev->vid) == 0)\n \t\t\tdev->flags |= VIRTIO_DEV_RUNNING;\n \t}\n }\n \n-static void\n-free_zmbufs(struct vhost_virtqueue *vq)\n-{\n-\tstruct zcopy_mbuf *zmbuf, *next;\n-\n-\tfor (zmbuf = TAILQ_FIRST(&vq->zmbuf_list);\n-\t     zmbuf != NULL; zmbuf = next) {\n-\t\tnext = TAILQ_NEXT(zmbuf, next);\n-\n-\t\trte_pktmbuf_free(zmbuf->mbuf);\n-\t\tTAILQ_REMOVE(&vq->zmbuf_list, zmbuf, next);\n-\t}\n-\n-\trte_free(vq->zmbufs);\n-}\n-\n /*\n  * when virtio is stopped, qemu will send us the GET_VRING_BASE message.\n  */\n static int\n-vhost_user_get_vring_base(struct virtio_net *dev,\n-\t\t\t  struct vhost_vring_state *state)\n+vhost_user_get_vring_base(struct virtio_dev *dev, struct vhost_vring_state *state)\n {\n+\tstruct vhost_virtqueue *vq;\n+\tif (dev == NULL)\n+\t\treturn -1;\n+\n \t/* We have to stop the queue (virtio) if it is running. */\n \tif (dev->flags & VIRTIO_DEV_RUNNING) {\n \t\tdev->flags &= ~VIRTIO_DEV_RUNNING;\n-\t\tnotify_ops->destroy_device(dev->vid);\n+\t\tdev->notify_ops->destroy_device(dev->vid);\n \t}\n \n+\tvq = dev->fn_table.vhost_dev_get_queues(dev, state->index);\n+\t/* Here we are safe to get the last used index */\n+\tstate->num = vq->last_used_idx;\n+\n \t/* Here we are safe to get the last used index */\n-\tstate->num = dev->virtqueue[state->index]->last_used_idx;\n+\tif (dev->fn_table.vhost_dev_get_vring_base)\n+\t\tdev->fn_table.vhost_dev_get_vring_base(dev, vq);\n \n \tRTE_LOG(INFO, VHOST_CONFIG,\n \t\t\"vring base idx:%d file:%d\\n\", state->index, state->num);\n-\t/*\n-\t * Based on current qemu vhost-user implementation, this message is\n-\t * sent and only sent in vhost_vring_stop.\n-\t * TODO: cleanup the vring, it isn't usable since here.\n-\t */\n-\tif (dev->virtqueue[state->index]->kickfd >= 0)\n-\t\tclose(dev->virtqueue[state->index]->kickfd);\n-\n-\tdev->virtqueue[state->index]->kickfd = VIRTIO_UNINITIALIZED_EVENTFD;\n-\n-\tif (dev->tx_zero_copy)\n-\t\tfree_zmbufs(dev->virtqueue[state->index]);\n \n \treturn 0;\n }\n@@ -740,39 +782,54 @@ vhost_user_get_vring_base(struct virtio_net *dev,\n  * enable the virtio queue pair.\n  */\n static int\n-vhost_user_set_vring_enable(struct virtio_net *dev,\n-\t\t\t    struct vhost_vring_state *state)\n+vhost_user_set_vring_enable(struct virtio_dev *dev, struct vhost_vring_state *state)\n {\n+\tstruct vhost_virtqueue *vq;\n \tint enable = (int)state->num;\n \n+\tif (dev == NULL)\n+\t\treturn -1;\n+\n \tRTE_LOG(INFO, VHOST_CONFIG,\n \t\t\"set queue enable: %d to qp idx: %d\\n\",\n \t\tenable, state->index);\n \n-\tif (notify_ops->vring_state_changed)\n-\t\tnotify_ops->vring_state_changed(dev->vid, state->index, enable);\n-\n-\tdev->virtqueue[state->index]->enabled = enable;\n+\tif (dev->notify_ops->vring_state_changed)\n+\t\tdev->notify_ops->vring_state_changed(dev->vid, state->index, enable);\n+\t\n+\tvq = dev->fn_table.vhost_dev_get_queues(dev, state->index);\n+\tvq->enabled = enable;\n \n \treturn 0;\n }\n \n static void\n-vhost_user_set_protocol_features(struct virtio_net *dev,\n-\t\t\t\t uint64_t protocol_features)\n+vhost_user_set_protocol_features(struct virtio_dev *dev, uint64_t protocol_features)\n {\n-\tif (protocol_features & ~VHOST_USER_PROTOCOL_FEATURES)\n+\tif (dev == NULL)\n \t\treturn;\n \n-\tdev->protocol_features = protocol_features;\n+\tif (dev->fn_table.vhost_dev_set_protocol_features)\n+\t\tdev->fn_table.vhost_dev_set_protocol_features(dev, protocol_features);\n+}\n+\n+static uint64_t\n+vhost_user_get_protocol_features(struct virtio_dev *dev)\n+{\n+\tif (dev == NULL)\n+\t\treturn 0;\n+\n+\tif (dev->fn_table.vhost_dev_get_protocol_features)\n+\t\treturn dev->fn_table.vhost_dev_get_protocol_features(dev);\n+\n+\treturn 0;\n }\n \n static int\n-vhost_user_set_log_base(struct virtio_net *dev, struct VhostUserMsg *msg)\n+vhost_user_set_log_base(struct virtio_dev *dev, struct VhostUserMsg *msg)\n {\n \tint fd = msg->fds[0];\n \tuint64_t size, off;\n-\tvoid *addr;\n \n \tif (fd < 0) {\n \t\tRTE_LOG(ERR, VHOST_CONFIG, \"invalid log fd: %d\\n\", fd);\n@@ -792,58 +849,20 @@ vhost_user_set_log_base(struct virtio_net *dev, struct VhostUserMsg *msg)\n \t\t\"log mmap size: %\"PRId64\", offset: %\"PRId64\"\\n\",\n \t\tsize, off);\n \n-\t/*\n-\t * mmap from 0 to workaround a hugepage mmap bug: mmap will\n-\t * fail when offset is not page size aligned.\n-\t */\n-\taddr = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);\n-\tclose(fd);\n-\tif (addr == MAP_FAILED) {\n-\t\tRTE_LOG(ERR, VHOST_CONFIG, \"mmap log base failed!\\n\");\n-\t\treturn -1;\n-\t}\n-\n-\t/*\n-\t * Free previously mapped log memory on occasionally\n-\t * multiple VHOST_USER_SET_LOG_BASE.\n-\t */\n-\tif (dev->log_addr) {\n-\t\tmunmap((void *)(uintptr_t)dev->log_addr, dev->log_size);\n-\t}\n-\tdev->log_addr = (uint64_t)(uintptr_t)addr;\n-\tdev->log_base = dev->log_addr + off;\n-\tdev->log_size = size;\n+\tif (dev->fn_table.vhost_dev_set_log_base)\n+\t\treturn dev->fn_table.vhost_dev_set_log_base(dev, fd, size, off);\n \n \treturn 0;\n }\n \n-/*\n- * An rarp packet is constructed and broadcasted to notify switches about\n- * the new location of the migrated VM, so that packets from outside will\n- * not be lost after migration.\n- *\n- * However, we don't actually \"send\" a rarp packet here, instead, we set\n- * a flag 'broadcast_rarp' to let rte_vhost_dequeue_burst() inject it.\n- */\n-static int\n-vhost_user_send_rarp(struct virtio_net *dev, struct VhostUserMsg *msg)\n+static uint32_t\n+vhost_user_get_queue_num(struct virtio_dev *dev)\n {\n-\tuint8_t *mac = (uint8_t *)&msg->payload.u64;\n-\n-\tRTE_LOG(DEBUG, VHOST_CONFIG,\n-\t\t\":: mac: %02x:%02x:%02x:%02x:%02x:%02x\\n\",\n-\t\tmac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);\n-\tmemcpy(dev->mac.addr_bytes, mac, 6);\n+\tif (dev == NULL)\n+\t\treturn 0;\n \n-\t/*\n-\t * Set the flag to inject a RARP broadcast packet at\n-\t * rte_vhost_dequeue_burst().\n-\t *\n-\t * rte_smp_wmb() is for making sure the mac is copied\n-\t * before the flag is set.\n-\t */\n-\trte_smp_wmb();\n-\trte_atomic16_set(&dev->broadcast_rarp, 1);\n+\tif (dev->fn_table.vhost_dev_get_queue_num)\n+\t\treturn dev->fn_table.vhost_dev_get_queue_num(dev);\n \n \treturn 0;\n }\n@@ -899,7 +918,7 @@ send_vhost_message(int sockfd, struct VhostUserMsg *msg)\n int\n vhost_user_msg_handler(int vid, int fd)\n {\n-\tstruct virtio_net *dev;\n+\tstruct virtio_dev *dev;\n \tstruct VhostUserMsg msg;\n \tint ret;\n \n@@ -926,7 +945,7 @@ vhost_user_msg_handler(int vid, int fd)\n \t\tvhost_message_str[msg.request]);\n \tswitch (msg.request) {\n \tcase VHOST_USER_GET_FEATURES:\n-\t\tmsg.payload.u64 = vhost_user_get_features();\n+\t\tmsg.payload.u64 = vhost_user_get_features(dev);\n \t\tmsg.size = sizeof(msg.payload.u64);\n \t\tsend_vhost_message(fd, &msg);\n \t\tbreak;\n@@ -935,7 +954,7 @@ vhost_user_msg_handler(int vid, int fd)\n \t\tbreak;\n \n \tcase VHOST_USER_GET_PROTOCOL_FEATURES:\n-\t\tmsg.payload.u64 = VHOST_USER_PROTOCOL_FEATURES;\n+\t\tmsg.payload.u64 = vhost_user_get_protocol_features(dev);\n \t\tmsg.size = sizeof(msg.payload.u64);\n \t\tsend_vhost_message(fd, &msg);\n \t\tbreak;\n@@ -996,7 +1015,7 @@ vhost_user_msg_handler(int vid, int fd)\n \t\tbreak;\n \n \tcase VHOST_USER_GET_QUEUE_NUM:\n-\t\tmsg.payload.u64 = VHOST_MAX_QUEUE_PAIRS;\n+\t\tmsg.payload.u64 = vhost_user_get_queue_num(dev);\n \t\tmsg.size = sizeof(msg.payload.u64);\n \t\tsend_vhost_message(fd, &msg);\n \t\tbreak;\n@@ -1014,4 +1033,4 @@ vhost_user_msg_handler(int vid, int fd)\n \t}\n \n \treturn 0;\n-}\n+}\n\\ No newline at end of file\ndiff --git a/lib/librte_vhost/vhost_user.h b/lib/librte_vhost/vhost_user.h\nindex ba78d32..59f80f2 100644\n--- a/lib/librte_vhost/vhost_user.h\n+++ b/lib/librte_vhost/vhost_user.h\n@@ -38,19 +38,12 @@\n #include <linux/vhost.h>\n \n #include \"rte_virtio_net.h\"\n+#include \"rte_virtio_dev.h\"\n \n /* refer to hw/virtio/vhost-user.c */\n \n #define VHOST_MEMORY_MAX_NREGIONS 8\n \n-#define VHOST_USER_PROTOCOL_F_MQ\t0\n-#define VHOST_USER_PROTOCOL_F_LOG_SHMFD\t1\n-#define VHOST_USER_PROTOCOL_F_RARP\t2\n-\n-#define VHOST_USER_PROTOCOL_FEATURES\t((1ULL << VHOST_USER_PROTOCOL_F_MQ) | \\\n-\t\t\t\t\t (1ULL << VHOST_USER_PROTOCOL_F_LOG_SHMFD) |\\\n-\t\t\t\t\t (1ULL << VHOST_USER_PROTOCOL_F_RARP))\n-\n typedef enum VhostUserRequest {\n \tVHOST_USER_NONE = 0,\n \tVHOST_USER_GET_FEATURES = 1,\n@@ -117,12 +110,16 @@ typedef struct VhostUserMsg {\n /* The version of the protocol we support */\n #define VHOST_USER_VERSION    0x1\n \n-\n /* vhost_user.c */\n int vhost_user_msg_handler(int vid, int fd);\n \n /* socket.c */\n int read_fd_message(int sockfd, char *buf, int buflen, int *fds, int fd_num);\n int send_fd_message(int sockfd, char *buf, int buflen, int *fds, int fd_num);\n+void vhost_set_ifname(int vid, const char *if_name, unsigned int if_len);\n+int vhost_new_device(int type);\n+void vhost_destroy_device(int vid);\n+\n+struct virtio_dev *get_device(int vid);\n \n-#endif\n+#endif\n\\ No newline at end of file\ndiff --git a/lib/librte_vhost/virtio_net.c b/lib/librte_vhost/virtio_net.c\nindex 277b150..c11e9b2 100644\n--- a/lib/librte_vhost/virtio_net.c\n+++ b/lib/librte_vhost/virtio_net.c\n@@ -45,7 +45,8 @@\n #include <rte_sctp.h>\n #include <rte_arp.h>\n \n-#include \"vhost.h\"\n+#include \"vhost_net.h\"\n+#include \"vhost_device.h\"\n \n #define MAX_PKT_BURST 32\n #define VHOST_LOG_PAGE\t4096\n@@ -147,7 +148,7 @@ copy_mbuf_to_desc(struct virtio_net *dev, struct vhost_virtqueue *vq,\n \tstruct virtio_net_hdr_mrg_rxbuf virtio_hdr = {{0, 0, 0, 0, 0, 0}, 0};\n \n \tdesc = &vq->desc[desc_idx];\n-\tdesc_addr = gpa_to_vva(dev, desc->addr);\n+\tdesc_addr = gpa_to_vva(dev->device, desc->addr);\n \t/*\n \t * Checking of 'desc_addr' placed outside of 'unlikely' macro to avoid\n \t * performance issue with some versions of gcc (4.8.4 and 5.3.0) which\n@@ -187,7 +188,7 @@ copy_mbuf_to_desc(struct virtio_net *dev, struct vhost_virtqueue *vq,\n \t\t\t\treturn -1;\n \n \t\t\tdesc = &vq->desc[desc->next];\n-\t\t\tdesc_addr = gpa_to_vva(dev, desc->addr);\n+\t\t\tdesc_addr = gpa_to_vva(dev->device, desc->addr);\n \t\t\tif (unlikely(!desc_addr))\n \t\t\t\treturn -1;\n \n@@ -232,7 +233,7 @@ virtio_dev_rx(struct virtio_net *dev, uint16_t queue_id,\n \tLOG_DEBUG(VHOST_DATA, \"(%d) %s\\n\", dev->vid, __func__);\n \tif (unlikely(!is_valid_virt_queue_idx(queue_id, 0, dev->virt_qp_nb))) {\n \t\tRTE_LOG(ERR, VHOST_DATA, \"(%d) %s: invalid virtqueue idx %d.\\n\",\n-\t\t\tdev->vid, __func__, queue_id);\n+\t\t\tdev->device->vid, __func__, queue_id);\n \t\treturn 0;\n \t}\n \n@@ -395,7 +396,7 @@ copy_mbuf_to_desc_mergeable(struct virtio_net *dev, struct vhost_virtqueue *vq,\n \tLOG_DEBUG(VHOST_DATA, \"(%d) current index %d | end index %d\\n\",\n \t\tdev->vid, cur_idx, end_idx);\n \n-\tdesc_addr = gpa_to_vva(dev, buf_vec[vec_idx].buf_addr);\n+\tdesc_addr = gpa_to_vva(dev->device, buf_vec[vec_idx].buf_addr);\n \tif (buf_vec[vec_idx].buf_len < dev->vhost_hlen || !desc_addr)\n \t\treturn 0;\n \n@@ -432,7 +433,7 @@ copy_mbuf_to_desc_mergeable(struct virtio_net *dev, struct vhost_virtqueue *vq,\n \t\t\t}\n \n \t\t\tvec_idx++;\n-\t\t\tdesc_addr = gpa_to_vva(dev, buf_vec[vec_idx].buf_addr);\n+\t\t\tdesc_addr = gpa_to_vva(dev->device, buf_vec[vec_idx].buf_addr);\n \t\t\tif (unlikely(!desc_addr))\n \t\t\t\treturn 0;\n \n@@ -487,7 +488,7 @@ virtio_dev_merge_rx(struct virtio_net *dev, uint16_t queue_id,\n \tLOG_DEBUG(VHOST_DATA, \"(%d) %s\\n\", dev->vid, __func__);\n \tif (unlikely(!is_valid_virt_queue_idx(queue_id, 0, dev->virt_qp_nb))) {\n \t\tRTE_LOG(ERR, VHOST_DATA, \"(%d) %s: invalid virtqueue idx %d.\\n\",\n-\t\t\tdev->vid, __func__, queue_id);\n+\t\t\tdev->device->vid, __func__, queue_id);\n \t\treturn 0;\n \t}\n \n@@ -537,10 +538,12 @@ uint16_t\n rte_vhost_enqueue_burst(int vid, uint16_t queue_id,\n \tstruct rte_mbuf **pkts, uint16_t count)\n {\n-\tstruct virtio_net *dev = get_device(vid);\n+\tstruct virtio_dev *device = get_device(vid);\n+\tstruct virtio_net *dev;\n \n-\tif (!dev)\n+\tif (!device)\n \t\treturn 0;\n+\tdev = get_net_device(device);\n \n \tif (dev->features & (1 << VIRTIO_NET_F_MRG_RXBUF))\n \t\treturn virtio_dev_merge_rx(dev, queue_id, pkts, count);\n@@ -734,7 +737,7 @@ copy_desc_to_mbuf(struct virtio_net *dev, struct vhost_virtqueue *vq,\n \tif (unlikely(desc->len < dev->vhost_hlen))\n \t\treturn -1;\n \n-\tdesc_addr = gpa_to_vva(dev, desc->addr);\n+\tdesc_addr = gpa_to_vva(dev->device, desc->addr);\n \tif (unlikely(!desc_addr))\n \t\treturn -1;\n \n@@ -771,7 +774,7 @@ copy_desc_to_mbuf(struct virtio_net *dev, struct vhost_virtqueue *vq,\n \t\t   (desc->flags & VRING_DESC_F_NEXT) != 0)) {\n \t\tdesc = &vq->desc[desc->next];\n \n-\t\tdesc_addr = gpa_to_vva(dev, desc->addr);\n+\t\tdesc_addr = gpa_to_vva(dev->device, desc->addr);\n \t\tif (unlikely(!desc_addr))\n \t\t\treturn -1;\n \n@@ -800,7 +803,7 @@ copy_desc_to_mbuf(struct virtio_net *dev, struct vhost_virtqueue *vq,\n \t\t * copy is enabled.\n \t\t */\n \t\tif (dev->tx_zero_copy &&\n-\t\t    (hpa = gpa_to_hpa(dev, desc->addr + desc_offset, cpy_len))) {\n+\t\t    (hpa = gpa_to_hpa(dev->device, desc->addr + desc_offset, cpy_len))) {\n \t\t\tcur->data_len = cpy_len;\n \t\t\tcur->data_off = 0;\n \t\t\tcur->buf_addr = (void *)(uintptr_t)desc_addr;\n@@ -833,7 +836,7 @@ copy_desc_to_mbuf(struct virtio_net *dev, struct vhost_virtqueue *vq,\n \t\t\t\treturn -1;\n \t\t\tdesc = &vq->desc[desc->next];\n \n-\t\t\tdesc_addr = gpa_to_vva(dev, desc->addr);\n+\t\t\tdesc_addr = gpa_to_vva(dev->device, desc->addr);\n \t\t\tif (unlikely(!desc_addr))\n \t\t\t\treturn -1;\n \n@@ -924,6 +927,7 @@ uint16_t\n rte_vhost_dequeue_burst(int vid, uint16_t queue_id,\n \tstruct rte_mempool *mbuf_pool, struct rte_mbuf **pkts, uint16_t count)\n {\n+\tstruct virtio_dev *device;\n \tstruct virtio_net *dev;\n \tstruct rte_mbuf *rarp_mbuf = NULL;\n \tstruct vhost_virtqueue *vq;\n@@ -933,13 +937,14 @@ rte_vhost_dequeue_burst(int vid, uint16_t queue_id,\n \tuint16_t free_entries;\n \tuint16_t avail_idx;\n \n-\tdev = get_device(vid);\n-\tif (!dev)\n+\tdevice = get_device(vid);\n+\tif (!device)\n \t\treturn 0;\n+\tdev = get_net_device(device);\n \n \tif (unlikely(!is_valid_virt_queue_idx(queue_id, 1, dev->virt_qp_nb))) {\n \t\tRTE_LOG(ERR, VHOST_DATA, \"(%d) %s: invalid virtqueue idx %d.\\n\",\n-\t\t\tdev->vid, __func__, queue_id);\n+\t\t\tdev->device->vid, __func__, queue_id);\n \t\treturn 0;\n \t}\n \n",
    "prefixes": [
        "dpdk-dev"
    ]
}