get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 370,
    "url": "https://patches.dpdk.org/api/patches/370/?format=api",
    "web_url": "https://patches.dpdk.org/project/dpdk/patch/1410519304-14521-4-git-send-email-huawei.xie@intel.com/",
    "project": {
        "id": 1,
        "url": "https://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": "<1410519304-14521-4-git-send-email-huawei.xie@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1410519304-14521-4-git-send-email-huawei.xie@intel.com",
    "date": "2014-09-12T10:55:02",
    "name": "[dpdk-dev,v4,3/5] lib/librte_vhost: vhost lib refactor",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "5883a24d5a5566665c1a114d735f67ae290a0add",
    "submitter": {
        "id": 16,
        "url": "https://patches.dpdk.org/api/people/16/?format=api",
        "name": "Huawei Xie",
        "email": "huawei.xie@intel.com"
    },
    "delegate": null,
    "mbox": "https://patches.dpdk.org/project/dpdk/patch/1410519304-14521-4-git-send-email-huawei.xie@intel.com/mbox/",
    "series": [],
    "comments": "https://patches.dpdk.org/api/patches/370/comments/",
    "check": "pending",
    "checks": "https://patches.dpdk.org/api/patches/370/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 DEF44B399;\n\tFri, 12 Sep 2014 12:50:15 +0200 (CEST)",
            "from mga02.intel.com (mga02.intel.com [134.134.136.20])\n\tby dpdk.org (Postfix) with ESMTP id 35EC7B398\n\tfor <dev@dpdk.org>; Fri, 12 Sep 2014 12:50:13 +0200 (CEST)",
            "from orsmga001.jf.intel.com ([10.7.209.18])\n\tby orsmga101.jf.intel.com with ESMTP; 12 Sep 2014 03:55:29 -0700",
            "from shvmail01.sh.intel.com ([10.239.29.42])\n\tby orsmga001.jf.intel.com with ESMTP; 12 Sep 2014 03:55:27 -0700",
            "from shecgisg003.sh.intel.com (shecgisg003.sh.intel.com\n\t[10.239.29.90])\n\tby shvmail01.sh.intel.com with ESMTP id s8CAtPeA022092;\n\tFri, 12 Sep 2014 18:55:25 +0800",
            "from shecgisg003.sh.intel.com (localhost [127.0.0.1])\n\tby shecgisg003.sh.intel.com (8.13.6/8.13.6/SuSE Linux 0.8) with ESMTP\n\tid s8CAtMuf014578; Fri, 12 Sep 2014 18:55:24 +0800",
            "(from hxie5@localhost)\n\tby shecgisg003.sh.intel.com (8.13.6/8.13.6/Submit) id s8CAtMYE014574; \n\tFri, 12 Sep 2014 18:55:22 +0800"
        ],
        "X-ExtLoop1": "1",
        "X-IronPort-AV": "E=Sophos;i=\"5.04,512,1406617200\"; d=\"scan'208\";a=\"572239796\"",
        "From": "Huawei Xie <huawei.xie@intel.com>",
        "To": "dev@dpdk.org",
        "Date": "Fri, 12 Sep 2014 18:55:02 +0800",
        "Message-Id": "<1410519304-14521-4-git-send-email-huawei.xie@intel.com>",
        "X-Mailer": "git-send-email 1.7.4.1",
        "In-Reply-To": "<1410519304-14521-1-git-send-email-huawei.xie@intel.com>",
        "References": "<1410519304-14521-1-git-send-email-huawei.xie@intel.com>",
        "Subject": "[dpdk-dev] [PATCH v4 3/5] lib/librte_vhost: vhost lib refactor",
        "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": "This vhost lib consists of five APIs plus several other helper routines\nfor feature disable/enable.\n1) rte_vhost_driver_register to register vhost driver to the system.\n2) rte_vhost_driver_callback_register to register the callback. Callbacks are\ncalled when virtio device is ready for polling or is de-activated.\n3) rte_vhost_driver_session_start, a blocking API to start vhost message handler\nsession.\n4) rte_vhost_enqueue_burst and rte_vhost_dequeue_burst for enqueue/dequeue\nto/from virtio ring.\n\nModifications include:\nVMDQ, mac learning and other switch related logics are removed.\nzero copy feature isn't generic currently, so it is removed.\nretry logic is removed.\nThe above three logics will be implemented in example as reference.\nvhost lib Makefile is added.\nAdd several TODOs:\n1) allow application to disable cmpset reserve in rte_vhost_enqueue_burst\nin case there is no contention.\n2) fix memcpy from mbuf to vring desc when mbuf is chained and the desc couldn't\nhold all the data\n3) fix vhost_set_mem_table possible race condition: two vqs concurrently calls\nset_mem_table which cause saved mem_temp to be overide.\nmerge-able feature is removed, will be merged after this patch is applied.\n\nSigned-off-by: Huawei Xie <huawei.xie@intel.com>\nAcked-by: Konstantin Ananyev <konstantin.ananyev@intel.com>\nAcked-by: Tommy Long <thomas.long@intel.com>\n---\n lib/librte_vhost/Makefile         |  48 ++++++++\n lib/librte_vhost/rte_virtio_net.h | 179 ++++++++++++++++-----------\n lib/librte_vhost/vhost-net-cdev.c |  35 +++---\n lib/librte_vhost/vhost-net-cdev.h |  45 +++++--\n lib/librte_vhost/vhost_rxtx.c     | 157 +++++++++++++-----------\n lib/librte_vhost/virtio-net.c     | 249 +++++++-------------------------------\n 6 files changed, 341 insertions(+), 372 deletions(-)\n create mode 100644 lib/librte_vhost/Makefile",
    "diff": "diff --git a/lib/librte_vhost/Makefile b/lib/librte_vhost/Makefile\nnew file mode 100644\nindex 0000000..6ad706d\n--- /dev/null\n+++ b/lib/librte_vhost/Makefile\n@@ -0,0 +1,48 @@\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+include $(RTE_SDK)/mk/rte.vars.mk\n+\n+# library name\n+LIB = librte_vhost.a\n+\n+CFLAGS += $(WERROR_FLAGS) -I$(SRCDIR) -O3 -D_FILE_OFFSET_BITS=64 -lfuse\n+LDFLAGS += -lfuse\n+# all source are stored in SRCS-y\n+SRCS-$(CONFIG_RTE_LIBRTE_VHOST) := vhost-net-cdev.c virtio-net.c vhost_rxtx.c\n+\n+# install includes\n+SYMLINK-$(CONFIG_RTE_LIBRTE_VHOST)-include += rte_virtio_net.h\n+\n+# this lib needs eal\n+DEPDIRS-$(CONFIG_RTE_LIBRTE_VHOST) += lib/librte_eal lib/librte_mbuf\n+\n+include $(RTE_SDK)/mk/rte.lib.mk\ndiff --git a/lib/librte_vhost/rte_virtio_net.h b/lib/librte_vhost/rte_virtio_net.h\nindex 1a2f0dc..08dc6f4 100644\n--- a/lib/librte_vhost/rte_virtio_net.h\n+++ b/lib/librte_vhost/rte_virtio_net.h\n@@ -34,28 +34,25 @@\n #ifndef _VIRTIO_NET_H_\n #define _VIRTIO_NET_H_\n \n+#include <stdint.h>\n+#include <linux/virtio_ring.h>\n+#include <linux/virtio_net.h>\n+#include <sys/eventfd.h>\n+\n+#include <rte_memory.h>\n+#include <rte_mempool.h>\n+#include <rte_mbuf.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 PAGE_SIZE   4096\n \n /* Enum for virtqueue management. */\n enum {VIRTIO_RXQ, VIRTIO_TXQ, VIRTIO_QNUM};\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-uint64_t buf_addr;\n-uint32_t buf_len;\n-uint32_t desc_idx;\n-};\n \n /*\n  * Structure contains variables relevant to TX/RX virtqueues.\n@@ -72,36 +69,8 @@ struct vhost_virtqueue\n \tvolatile uint16_t\tlast_used_idx_res;\t/* Used for multiple devices reserving buffers. */\n \teventfd_t\t\t\tcallfd;\t\t\t\t/* Currently unused as polling mode is enabled. */\n \teventfd_t\t\t\tkickfd;\t\t\t\t/* Used to notify the guest (trigger interrupt). */\n-\t/* Used for scatter RX. */\n-\tstruct buf_vector\tbuf_vec[BUF_VECTOR_MAX];\n-} __rte_cache_aligned;\n-\n-/*\n- * Device structure contains all configuration information relating to the device.\n- */\n-struct virtio_net\n-{\n-\tstruct vhost_virtqueue\t*virtqueue[VIRTIO_QNUM];\t/* Contains all virtqueue information. */\n-\tstruct virtio_memory \t*mem;\t\t\t\t\t\t/* QEMU memory and memory region information. */\n-\tstruct ether_addr \t\tmac_address;\t\t\t\t/* Device MAC address (Obtained on first TX packet). */\n-\tuint64_t \t\t\t\tfeatures;\t\t\t\t\t/* Negotiated feature set. */\n-\tuint64_t \t\t\t\tdevice_fh;\t\t\t\t\t/* device identifier. */\n-\tuint32_t \t\t\t\tvmdq_rx_q;\t\t\t\t\t/* RX VMDQ queue number. */\n-\tuint32_t \t\t\t\tflags;\t\t\t\t\t\t/* Device flags. Only used to check if device is running on data core. */\n-\tuint32_t \t\t\t\tvlan_tag;\t\t\t\t\t/* Vlan tag for device. Currently set to device_id (0-63). */\n-\tuint16_t \t\t\t\tcoreid;\t\t\t\t\t\t/* Data core that the device is added to. */\n-\tvolatile uint8_t \t\tready;\t\t\t\t\t\t/* A device is set as ready if the MAC address has been set. */\n-\tvolatile uint8_t\t\tremove;\t\t\t\t\t\t/* Device is marked for removal from the data core. */\n } __rte_cache_aligned;\n \n-/*\n- * Device linked list structure for configuration.\n- */\n-struct virtio_net_config_ll\n-{\n-\tstruct virtio_net\t\tdev;\t/* Virtio device. */\n-\tstruct virtio_net_config_ll\t*next; /* Next entry on linked list. */\n-};\n \n /*\n  * Information relating to memory regions including offsets to addresses in QEMUs memory file.\n@@ -114,48 +83,116 @@ struct virtio_memory_regions {\n \tuint64_t\taddress_offset;\t\t\t/* Offset of region for address translation. */\n };\n \n-/*\n- * Information relating to memory regions including offsets to\n- * addresses in host physical space.\n- */\n-struct virtio_memory_regions_hpa {\n-\t/* Base guest physical address of region. */\n-\tuint64_t\tguest_phys_address;\n-\t/* End guest physical address of region. */\n-\tuint64_t\tguest_phys_address_end;\n-\t/* Size of region. */\n-\tuint64_t\tmemory_size;\n-\t/* Offset of region for gpa to hpa translation. */\n-\tuint64_t\thost_phys_addr_offset;\n-};\n \n-/*\n+/**\n  * Memory structure includes region and mapping information.\n  */\n struct virtio_memory {\n-\tuint64_t\t\t\tbase_address;\t\t\t/* Base QEMU userspace address of the memory file. */\n-\tuint64_t\t\t\tmapped_address;\t\t\t/* Mapped address of memory file base in our applications memory space. */\n-\tuint64_t\t\t\tmapped_size;\t\t\t/* Total size of memory file. */\n-\tuint32_t\t\t\tnregions;\t\t\t\t/* Number of memory regions. */\n-\t /* Number of memory regions for gpa to hpa translation. */\n-\tuint32_t\t\t\tnregions_hpa;\n-\t/* Memory region information for gpa to hpa translation. */\n-\tstruct virtio_memory_regions_hpa  *regions_hpa;\n-\t/* Memory region information. */\n-\tstruct virtio_memory_regions      regions[0];\n+\tuint64_t    base_address;    /**< Base QEMU userspace address of the memory file. */\n+\tuint64_t    mapped_address;  /**< Mapped address of memory file base in our applications memory space. */\n+\tuint64_t    mapped_size;     /**< Total size of memory file. */\n+\tuint32_t    nregions;        /**< Number of memory regions. */\n+\tstruct virtio_memory_regions      regions[0]; /**< Memory region information. */\n };\n \n-/*\n+/**\n+ * Device structure contains all configuration information relating to the device.\n+ */\n+struct virtio_net {\n+\tstruct vhost_virtqueue  *virtqueue[VIRTIO_QNUM]; /**< Contains all virtqueue information. */\n+\tstruct virtio_memory    *mem;                    /**< QEMU memory and memory region information. */\n+\tuint64_t features;    /**< Negotiated feature set. */\n+\tuint64_t device_fh;   /**< Device identifier. */\n+\tuint32_t flags;       /**< Device flags. Only used to check if device is running on data core. */\n+\tvoid     *priv;\n+} __rte_cache_aligned;\n+\n+/**\n  * Device operations to add/remove device.\n  */\n struct virtio_net_device_ops {\n-\tint (* new_device) \t\t(struct virtio_net *);\t/* Add device. */\n-\tvoid (* destroy_device)\t(volatile struct virtio_net *);\t/* Remove device. */\n+\tint (*new_device)(struct virtio_net *); /**< Add device. */\n+\tvoid (*destroy_device)(struct virtio_net *); /**< Remove device. */\n };\n \n-int init_virtio_net(struct virtio_net_device_ops const * const);\n-int deinit_virtio_net(void);\n \n-struct vhost_net_device_ops const * get_virtio_net_callbacks(void);\n+static inline uint16_t __attribute__((always_inline))\n+rte_vring_available_entries(struct virtio_net *dev, uint16_t queue_id)\n+{\n+\tstruct vhost_virtqueue *vq = dev->virtqueue[queue_id];\n+\treturn *(volatile uint16_t *)&vq->avail->idx - vq->last_used_idx_res;\n+}\n+\n+/**\n+ * Function to convert guest physical addresses to vhost virtual addresses.\n+ * This is used to convert guest virtio buffer addresses.\n+ */\n+static inline uint64_t __attribute__((always_inline))\n+gpa_to_vva(struct virtio_net *dev, uint64_t guest_pa)\n+{\n+\tstruct virtio_memory_regions *region;\n+\tuint32_t regionidx;\n+\tuint64_t vhost_va = 0;\n+\n+\tfor (regionidx = 0; regionidx < dev->mem->nregions; regionidx++) {\n+\t\tregion = &dev->mem->regions[regionidx];\n+\t\tif ((guest_pa >= region->guest_phys_address) &&\n+\t\t\t(guest_pa <= region->guest_phys_address_end)) {\n+\t\t\tvhost_va = region->address_offset + guest_pa;\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\treturn vhost_va;\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(struct virtio_net *dev, uint16_t queue_id, int enable);\n+\n+/* Register vhost driver. dev_name could be different for multiple instance support. */\n+int rte_vhost_driver_register(const char *dev_name);\n+\n+/* Register callbacks. */\n+int rte_vhost_driver_callback_register(struct virtio_net_device_ops const * const);\n+\n+int rte_vhost_driver_session_start(void);\n+\n+/**\n+ * This function adds buffers to the virtio devices RX virtqueue. Buffers can\n+ * be received from the physical port or from another virtual device. A packet\n+ * count is returned to indicate the number of packets that were succesfully\n+ * added to the RX queue.\n+ * @param queue_id\n+ *  virtio queue index in mq case\n+ * @return\n+ *  num of packets enqueued\n+ */\n+uint32_t rte_vhost_enqueue_burst(struct virtio_net *dev, uint16_t queue_id,\n+\tstruct rte_mbuf **pkts, uint32_t count);\n+\n+/**\n+ * This function gets guest buffers from the virtio device TX virtqueue,\n+ * construct host mbufs, copies guest buffer content to host mbufs and\n+ * store them in pkts to be processed.\n+ * @param mbuf_pool\n+ *  mbuf_pool where host mbuf is allocated.\n+ * @param queue_id\n+ *  virtio queue index in mq case.\n+ * @return\n+ *  num of packets dequeued\n+ */\n+uint32_t rte_vhost_dequeue_burst(struct virtio_net *dev, uint16_t queue_id,\n+\tstruct rte_mempool *mbuf_pool, struct rte_mbuf **pkts, uint32_t count);\n \n #endif /* _VIRTIO_NET_H_ */\ndiff --git a/lib/librte_vhost/vhost-net-cdev.c b/lib/librte_vhost/vhost-net-cdev.c\nindex 8cf806a..e73bf23 100644\n--- a/lib/librte_vhost/vhost-net-cdev.c\n+++ b/lib/librte_vhost/vhost-net-cdev.c\n@@ -42,18 +42,18 @@\n #include <rte_ethdev.h>\n #include <rte_log.h>\n #include <rte_string_fns.h>\n+#include <rte_virtio_net.h>\n \n-#include \"main.h\"\n #include \"vhost-net-cdev.h\"\n \n #define FUSE_OPT_DUMMY \t\t\"\\0\\0\"\n #define FUSE_OPT_FORE \t\t\"-f\\0\\0\"\n #define FUSE_OPT_NOMULTI \t\"-s\\0\\0\"\n \n-const uint32_t\tdefault_major = 231;\n-const uint32_t\tdefault_minor = 1;\n-const char\t\tcuse_device_name[]\t= \"/dev/cuse\";\n-const char\t\tdefault_cdev[] = \"vhost-net\";\n+static const uint32_t\tdefault_major = 231;\n+static const uint32_t\tdefault_minor = 1;\n+static const char\tcuse_device_name[]\t= \"/dev/cuse\";\n+static const char\tdefault_cdev[] = \"vhost-net\";\n \n static struct fuse_session\t\t\t*session;\n static struct vhost_net_device_ops\tconst *ops;\n@@ -116,7 +116,7 @@ vhost_net_release(fuse_req_t req, struct fuse_file_info *fi)\n #define VHOST_IOCTL(func) do {\t\t\t\t\t\t\t\t\\\n \tresult = (func)(ctx);\t\t\t\t\t\t\t\t\t\\\n \tfuse_reply_ioctl(req, result, NULL, 0);\t\t\t\t\t\\\n-} while(0)\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n+} while(0)\t\t\t\t\t\t\t\t\t\t\t\t\t\n \n /*\n  * Boilerplate IOCTL RETRY\n@@ -215,6 +215,7 @@ vhost_net_ioctl(fuse_req_t req, int cmd, void *arg,\n \t\t\tbreak;\n \n \t\tcase VHOST_SET_MEM_TABLE:\n+\t\t\t/*TODO fix race condition.*/\n \t\t\tLOG_DEBUG(VHOST_CONFIG, \"(%\"PRIu64\") IOCTL: VHOST_SET_MEM_TABLE\\n\", ctx.fh);\n \t\t\tstatic struct vhost_memory mem_temp;\n \n@@ -302,7 +303,7 @@ static const struct cuse_lowlevel_ops vhost_net_ops = {\n  * also passed when the device is registered in main.c.\n  */\n int\n-register_cuse_device(const char *base_name, int index, struct vhost_net_device_ops const * const pops)\n+rte_vhost_driver_register(const char *dev_name)\n {\n \tstruct cuse_info cuse_info;\n \tchar device_name[PATH_MAX] = \"\";\n@@ -321,16 +322,11 @@ register_cuse_device(const char *base_name, int index, struct vhost_net_device_o\n \n \t/*\n \t * The device name is created. This is passed to QEMU so that it can register\n-\t * the device with our application. The index allows us to have multiple instances\n+\t * the device with our application. The dev_name allows us to have multiple instances\n \t * of userspace vhost which we can then add devices to separately.\n \t */\n-\tif (strncmp(base_name, default_cdev, PATH_MAX)!=0) {\n-\t\tsnprintf(device_name, PATH_MAX, \"DEVNAME=%s-%d\", base_name, index);\n-\t\tsnprintf(char_device_name, PATH_MAX, \"/dev/%s-%d\", base_name, index);\n-\t} else {\n-\t\tsnprintf(device_name, PATH_MAX, \"DEVNAME=%s\", base_name);\n-\t\tsnprintf(char_device_name, PATH_MAX, \"/dev/%s\", base_name);\n-\t}\n+\tsnprintf(device_name, PATH_MAX, \"DEVNAME=%s\", dev_name);\n+\tsnprintf(char_device_name, PATH_MAX, \"/dev/%s\", dev_name);\n \n \t/* Check if device already exists. */\n \tif (access(char_device_name, F_OK) != -1) {\n@@ -340,12 +336,12 @@ register_cuse_device(const char *base_name, int index, struct vhost_net_device_o\n \n \tmemset(&cuse_info, 0, sizeof(cuse_info));\n \tcuse_info.dev_major = default_major;\n-\tcuse_info.dev_minor = default_minor + index;\n+\tcuse_info.dev_minor = default_minor;\n \tcuse_info.dev_info_argc = 1;\n \tcuse_info.dev_info_argv = device_argv;\n \tcuse_info.flags = CUSE_UNRESTRICTED_IOCTL;\n \n-\tops = pops;\n+\tops = get_virtio_net_callbacks();\n \n \tsession = cuse_lowlevel_setup(3, fuse_argv,\n \t\t\t\t&cuse_info, &vhost_net_ops, 0, NULL);\n@@ -355,11 +351,12 @@ register_cuse_device(const char *base_name, int index, struct vhost_net_device_o\n \treturn 0;\n }\n \n-/*\n+\n+/**\n  * The CUSE session is launched allowing the application to receive open, release and ioctl calls.\n  */\n int\n-start_cuse_session_loop(void)\n+rte_vhost_driver_session_start(void)\n {\n \tfuse_session_loop(session);\n \ndiff --git a/lib/librte_vhost/vhost-net-cdev.h b/lib/librte_vhost/vhost-net-cdev.h\nindex 575daa9..d9a5a9a 100644\n--- a/lib/librte_vhost/vhost-net-cdev.h\n+++ b/lib/librte_vhost/vhost-net-cdev.h\n@@ -33,13 +33,45 @@\n \n #ifndef _VHOST_NET_CDEV_H_\n #define _VHOST_NET_CDEV_H_\n-\n+#include <stdint.h>\n+#include <stdio.h>\n+#include <sys/types.h>\n+#include <unistd.h>\n #include <linux/vhost.h>\n \n-struct vhost_memory;\n-struct vhost_vring_state;\n-struct vhost_vring_addr;\n-struct vhost_vring_file;\n+#include <rte_log.h>\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 VHOST_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, \"(%\"PRIu64\") Header size %d: \", (device->device_fh), (size)); \\\n+\telse \\\n+\t\tsnprintf(packet, VHOST_MAX_PRINT_BUFF, \"(%\"PRIu64\") Packet size %d: \", (device->device_fh), (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 VHOST_PRINT_PACKET(device, addr, size, header) do {} while (0)\n+#endif\n+\n \n /*\n  * Structure used to identify device context.\n@@ -77,7 +109,6 @@ struct vhost_net_device_ops {\n \tint (* reset_owner) \t(struct vhost_device_ctx);\n };\n \n-int register_cuse_device(const char *base_name, int index, struct vhost_net_device_ops const * const);\n-int start_cuse_session_loop(void);\n \n+struct vhost_net_device_ops const *get_virtio_net_callbacks(void);\n #endif /* _VHOST_NET_CDEV_H_ */\ndiff --git a/lib/librte_vhost/vhost_rxtx.c b/lib/librte_vhost/vhost_rxtx.c\nindex 78fce0d..0d96c43 100644\n--- a/lib/librte_vhost/vhost_rxtx.c\n+++ b/lib/librte_vhost/vhost_rxtx.c\n@@ -40,17 +40,17 @@\n \n #include \"vhost-net-cdev.h\"\n \n-#define MAX_PKT_BURST 64\n-#define MAX_MRG_PKT_BURST 64\n+#define VHOST_MAX_PKT_BURST 64\n+#define VHOST_MAX_MRG_PKT_BURST 64\n \n-/*\n+/**\n  * This function adds buffers to the virtio devices RX virtqueue. Buffers can\n  * be received from the physical port or from another virtio device. A packet\n  * count is returned to indicate the number of packets that were succesfully\n  * added to the RX queue. This function works when mergeable is disabled.\n  */\n-static inline uint32_t __attribute__((always_inline))\n-virtio_dev_rx(struct virtio_net *dev, struct rte_mbuf **pkts, uint32_t count)\n+uint32_t\n+rte_vhost_enqueue_burst(struct virtio_net *dev, uint16_t queue_id, struct rte_mbuf **pkts, uint32_t count)\n {\n \tstruct vhost_virtqueue *vq;\n \tstruct vring_desc *desc;\n@@ -59,36 +59,28 @@ virtio_dev_rx(struct virtio_net *dev, struct rte_mbuf **pkts, uint32_t count)\n \tstruct virtio_net_hdr_mrg_rxbuf virtio_hdr = {{0,0,0,0,0,0},0};\n \tuint64_t buff_addr = 0;\n \tuint64_t buff_hdr_addr = 0;\n-\tuint32_t head[MAX_PKT_BURST], packet_len = 0;\n+\tuint32_t head[VHOST_MAX_PKT_BURST], packet_len = 0;\n \tuint32_t head_idx, packet_success = 0;\n-\tuint32_t retry = 0;\n+\tuint32_t mergeable, mrg_count = 0;\n \tuint16_t avail_idx, res_cur_idx;\n \tuint16_t res_base_idx, res_end_idx;\n \tuint16_t free_entries;\n \tuint8_t success = 0;\n \n \tLOG_DEBUG(VHOST_DATA, \"(%\"PRIu64\") virtio_dev_rx()\\n\", dev->device_fh);\n-\tvq = dev->virtqueue[VIRTIO_RXQ];\n-\tcount = (count > MAX_PKT_BURST) ? MAX_PKT_BURST : count;\n+\tif (unlikely(queue_id != VIRTIO_RXQ)) {\n+\t\tLOG_DEBUG(VHOST_DATA, \"mq isn't supported in this version.\\n\");\n+\t\treturn 0;\n+\t}\n \n+\tvq = dev->virtqueue[VIRTIO_RXQ];\n+\tcount = (count > VHOST_MAX_PKT_BURST) ? VHOST_MAX_PKT_BURST : count;\n \t/* As many data cores may want access to available buffers, they need to be reserved. */\n \tdo {\n \t\tres_base_idx = vq->last_used_idx_res;\n \t\tavail_idx = *((volatile uint16_t *)&vq->avail->idx);\n \n \t\tfree_entries = (avail_idx - res_base_idx);\n-\t\t/* If retry is enabled and the queue is full then we wait and retry to avoid packet loss. */\n-\t\tif (enable_retry && unlikely(count > free_entries)) {\n-\t\t\tfor (retry = 0; retry < burst_rx_retry_num; retry++) {\n-\t\t\t\trte_delay_us(burst_rx_delay_time);\n-\t\t\t\tavail_idx =\n-\t\t\t\t\t*((volatile uint16_t *)&vq->avail->idx);\n-\t\t\t\tfree_entries = (avail_idx - res_base_idx);\n-\t\t\t\tif (count <= free_entries)\n-\t\t\t\t\tbreak;\n-\t\t\t}\n-\t\t}\n-\n \t\t/*check that we have enough buffers*/\n \t\tif (unlikely(count > free_entries))\n \t\t\tcount = free_entries;\n@@ -98,8 +90,10 @@ virtio_dev_rx(struct virtio_net *dev, struct rte_mbuf **pkts, uint32_t count)\n \n \t\tres_end_idx = res_base_idx + count;\n \t\t/* vq->last_used_idx_res is atomically updated. */\n-\t\tsuccess = rte_atomic16_cmpset(&vq->last_used_idx_res, res_base_idx,\n-\t\t\t\t\t\t\t\t\tres_end_idx);\n+\t\t/* TODO: Allow to disable cmpset if no concurrency in application */\n+\t\tsuccess = rte_atomic16_cmpset(&vq->last_used_idx_res,\n+\t\t\t\tres_base_idx, res_end_idx);\n+\t\t/* If there is contention here and failed, try again. */\n \t} while (unlikely(success == 0));\n \tres_cur_idx = res_base_idx;\n \tLOG_DEBUG(VHOST_DATA, \"(%\"PRIu64\") Current Index %d| End Index %d\\n\", dev->device_fh, res_cur_idx, res_end_idx);\n@@ -107,6 +101,9 @@ virtio_dev_rx(struct virtio_net *dev, struct rte_mbuf **pkts, uint32_t count)\n \t/* Prefetch available ring to retrieve indexes. */\n \trte_prefetch0(&vq->avail->ring[res_cur_idx & (vq->size - 1)]);\n \n+\t/* Check if the VIRTIO_NET_F_MRG_RXBUF feature is enabled. */\n+\tmergeable = dev->features & (1 << VIRTIO_NET_F_MRG_RXBUF);\n+\n \t/* Retrieve all of the head indexes first to avoid caching issues. */\n \tfor (head_idx = 0; head_idx < count; head_idx++)\n \t\thead[head_idx] = vq->avail->ring[(res_cur_idx + head_idx) & (vq->size - 1)];\n@@ -125,44 +122,60 @@ virtio_dev_rx(struct virtio_net *dev, struct rte_mbuf **pkts, uint32_t count)\n \t\t/* Prefetch buffer address. */\n \t\trte_prefetch0((void*)(uintptr_t)buff_addr);\n \n-\t\t/* Copy virtio_hdr to packet and increment buffer address */\n-\t\tbuff_hdr_addr = buff_addr;\n-\t\tpacket_len = rte_pktmbuf_data_len(buff) + vq->vhost_hlen;\n-\n-\t\t/*\n-\t\t * If the descriptors are chained the header and data are\n-\t\t * placed in separate buffers.\n-\t\t */\n-\t\tif (desc->flags & VRING_DESC_F_NEXT) {\n-\t\t\tdesc->len = vq->vhost_hlen;\n-\t\t\tdesc = &vq->desc[desc->next];\n-\t\t\t/* Buffer address translation. */\n-\t\t\tbuff_addr = gpa_to_vva(dev, desc->addr);\n-\t\t\tdesc->len = rte_pktmbuf_data_len(buff);\n+\t\tif (mergeable && (mrg_count != 0)) {\n+\t\t\tdesc->len = packet_len = rte_pktmbuf_data_len(buff);\n \t\t} else {\n-\t\t\tbuff_addr += vq->vhost_hlen;\n-\t\t\tdesc->len = packet_len;\n+\t\t\t/* Copy virtio_hdr to packet and increment buffer address */\n+\t\t\tbuff_hdr_addr = buff_addr;\n+\t\t\tpacket_len = rte_pktmbuf_data_len(buff) + vq->vhost_hlen;\n+\n+\t\t\t/*\n+\t\t\t * If the descriptors are chained the header and data are placed in\n+\t\t\t * separate buffers.\n+\t\t\t */\n+\t\t\tif (desc->flags & VRING_DESC_F_NEXT) {\n+\t\t\t\tdesc->len = vq->vhost_hlen;\n+\t\t\t\tdesc = &vq->desc[desc->next];\n+\t\t\t\t/* Buffer address translation. */\n+\t\t\t\tbuff_addr = gpa_to_vva(dev, desc->addr);\n+\t\t\t\tdesc->len = rte_pktmbuf_data_len(buff);\n+\t\t\t} else {\n+\t\t\t\tbuff_addr += vq->vhost_hlen;\n+\t\t\t\tdesc->len = packet_len;\n+\t\t\t}\n \t\t}\n \n+\n \t\t/* Update used ring with desc information */\n \t\tvq->used->ring[res_cur_idx & (vq->size - 1)].id = head[packet_success];\n \t\tvq->used->ring[res_cur_idx & (vq->size - 1)].len = packet_len;\n \n \t\t/* Copy mbuf data to buffer */\n+\t\t/* TODO fixme for sg mbuf and the case that desc couldn't hold the mbuf data */\n \t\trte_memcpy((void *)(uintptr_t)buff_addr,\n \t\t\t(const void *)buff->pkt.data,\n \t\t\trte_pktmbuf_data_len(buff));\n-\t\tPRINT_PACKET(dev, (uintptr_t)buff_addr,\n+\t\tVHOST_PRINT_PACKET(dev, (uintptr_t)buff_addr,\n \t\t\trte_pktmbuf_data_len(buff), 0);\n \n \t\tres_cur_idx++;\n \t\tpacket_success++;\n-\n-\t\trte_memcpy((void *)(uintptr_t)buff_hdr_addr,\n-\t\t\t(const void *)&virtio_hdr, vq->vhost_hlen);\n-\n-\t\tPRINT_PACKET(dev, (uintptr_t)buff_hdr_addr, vq->vhost_hlen, 1);\n-\n+\t\n+\t\t/* If mergeable is disabled then a header is required per buffer. */\n+\t\tif (!mergeable) {\n+\t\t\trte_memcpy((void *)(uintptr_t)buff_hdr_addr, (const void *)&virtio_hdr, vq->vhost_hlen);\n+\t\t\tVHOST_PRINT_PACKET(dev, (uintptr_t)buff_hdr_addr, vq->vhost_hlen, 1);\n+\t\t} else {\n+\t\t\tmrg_count++;\n+\t\t\t/* Merge buffer can only handle so many buffers at a time. Tell the guest if this limit is reached. */\n+\t\t\tif ((mrg_count == VHOST_MAX_MRG_PKT_BURST) || (res_cur_idx == res_end_idx)) {\n+\t\t\t\tvirtio_hdr.num_buffers = mrg_count;\n+\t\t\t\tLOG_DEBUG(VHOST_DATA, \"(%\"PRIu64\") RX: Num merge buffers %d\\n\", dev->device_fh, virtio_hdr.num_buffers);\n+\t\t\t\trte_memcpy((void *)(uintptr_t)buff_hdr_addr, (const void *)&virtio_hdr, vq->vhost_hlen);\n+\t\t\t\tVHOST_PRINT_PACKET(dev, (uintptr_t)buff_hdr_addr, vq->vhost_hlen, 1);\n+\t\t\t\tmrg_count = 0;\n+\t\t\t}\n+\t\t}\n \t\tif (res_cur_idx < res_end_idx) {\n \t\t\t/* Prefetch descriptor index. */\n \t\t\trte_prefetch0(&vq->desc[head[packet_success]]);\n@@ -185,25 +198,30 @@ virtio_dev_rx(struct virtio_net *dev, struct rte_mbuf **pkts, uint32_t count)\n }\n \n \n-static inline void __attribute__((always_inline))\n-virtio_dev_tx(struct virtio_net* dev, struct rte_mempool *mbuf_pool)\n+uint32_t\n+rte_vhost_dequeue_burst(struct virtio_net *dev, uint16_t queue_id, struct rte_mempool *mbuf_pool, struct rte_mbuf **pkts, uint32_t count)\n {\n-\tstruct rte_mbuf m;\n+\tstruct rte_mbuf *mbuf;\n \tstruct vhost_virtqueue *vq;\n \tstruct vring_desc *desc;\n \tuint64_t buff_addr = 0;\n-\tuint32_t head[MAX_PKT_BURST];\n+\tuint32_t head[VHOST_MAX_PKT_BURST];\n \tuint32_t used_idx;\n \tuint32_t i;\n \tuint16_t free_entries, packet_success = 0;\n \tuint16_t avail_idx;\n \n+\tif (unlikely(queue_id != VIRTIO_TXQ)) {\n+\t\tLOG_DEBUG(VHOST_DATA, \"mq isn't supported in this version.\\n\");\n+\t\treturn 0;\n+\t}\n+\n \tvq = dev->virtqueue[VIRTIO_TXQ];\n \tavail_idx =  *((volatile uint16_t *)&vq->avail->idx);\n \n \t/* If there are no available buffers then return. */\n \tif (vq->last_used_idx == avail_idx)\n-\t\treturn;\n+\t\treturn 0;\n \n \tLOG_DEBUG(VHOST_DATA, \"(%\"PRIu64\") virtio_dev_tx()\\n\", dev->device_fh);\n \n@@ -213,9 +231,11 @@ virtio_dev_tx(struct virtio_net* dev, struct rte_mempool *mbuf_pool)\n \t/*get the number of free entries in the ring*/\n \tfree_entries = (avail_idx - vq->last_used_idx);\n \n+\tif (free_entries > count)\n+\t\tfree_entries = count;\n \t/* Limit to MAX_PKT_BURST. */\n-\tif (free_entries > MAX_PKT_BURST)\n-\t\tfree_entries = MAX_PKT_BURST;\n+\tif (free_entries > VHOST_MAX_PKT_BURST)\n+\t\tfree_entries = VHOST_MAX_PKT_BURST;\n \n \tLOG_DEBUG(VHOST_DATA, \"(%\"PRIu64\") Buffers available %d\\n\", dev->device_fh, free_entries);\n \t/* Retrieve all of the head indexes first to avoid caching issues. */\n@@ -249,23 +269,20 @@ virtio_dev_tx(struct virtio_net* dev, struct rte_mempool *mbuf_pool)\n \t\tvq->used->ring[used_idx].id = head[packet_success];\n \t\tvq->used->ring[used_idx].len = 0;\n \n-\t\t/* Setup dummy mbuf. This is copied to a real mbuf if transmitted out the physical port. */\n-\t\tm.pkt.data_len = desc->len;\n-\t\tm.pkt.pkt_len = desc->len;\n-\t\tm.pkt.data = (void*)(uintptr_t)buff_addr;\n+\t\tmbuf = rte_pktmbuf_alloc(mbuf_pool);\n+\t\tif (unlikely(mbuf == NULL)) {\n+\t\t\tRTE_LOG(ERR, VHOST_DATA, \"Failed to allocate memory for mbuf.\\n\");\n+\t\t\treturn packet_success;\n+\t\t}\n+\t\tmbuf->pkt.data_len = desc->len;\n+\t\tmbuf->pkt.pkt_len  = mbuf->pkt.data_len;\n+\n+\t\trte_memcpy((void *) mbuf->pkt.data,\n+\t\t\t(const void *) buff_addr, mbuf->pkt.data_len);\n \n-\t\tPRINT_PACKET(dev, (uintptr_t)buff_addr, desc->len, 0);\n+\t\tpkts[packet_success] = mbuf;\n \n-\t\t/* If this is the first received packet we need to learn the MAC and setup VMDQ */\n-\t\tif (dev->ready == DEVICE_MAC_LEARNING) {\n-\t\t\tif (dev->remove || (link_vmdq(dev, &m) == -1)) {\n-\t\t\t\t/*discard frame if device is scheduled for removal or a duplicate MAC address is found. */\n-\t\t\t\tpacket_success += free_entries;\n-\t\t\t\tvq->last_used_idx += packet_success;\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t}\n-\t\tvirtio_tx_route(dev, &m, mbuf_pool, (uint16_t)dev->device_fh);\n+\t\tVHOST_PRINT_PACKET(dev, (uintptr_t)buff_addr, desc->len, 0);\n \n \t\tvq->last_used_idx++;\n \t\tpacket_success++;\n@@ -276,6 +293,6 @@ virtio_dev_tx(struct virtio_net* dev, struct rte_mempool *mbuf_pool)\n \t/* Kick guest if required. */\n \tif (!(vq->avail->flags & VRING_AVAIL_F_NO_INTERRUPT))\n \t\teventfd_write((int)vq->kickfd, 1);\n-}\n-\n \n+\treturn packet_success;\n+}\ndiff --git a/lib/librte_vhost/virtio-net.c b/lib/librte_vhost/virtio-net.c\nindex 5e659c7..9852961 100644\n--- a/lib/librte_vhost/virtio-net.c\n+++ b/lib/librte_vhost/virtio-net.c\n@@ -47,27 +47,32 @@\n #include <rte_log.h>\n #include <rte_string_fns.h>\n #include <rte_memory.h>\n+#include <rte_virtio_net.h>\n \n-#include \"main.h\"\n-#include \"virtio-net.h\"\n #include \"vhost-net-cdev.h\"\n #include \"eventfd_link/eventfd_link.h\"\n \n-const char eventfd_cdev[] = \"/dev/eventfd-link\";\n+/**\n+ * Device linked list structure for configuration.\n+ */\n+struct virtio_net_config_ll {\n+\tstruct virtio_net             dev;    /* Virtio device. */\n+\tstruct virtio_net_config_ll   *next;  /* Next entry on linked list. */\n+};\n \n-extern uint32_t num_devices;\n-static uint32_t num_cur_devices = 0;\n+static const char eventfd_cdev[] = \"/dev/eventfd-link\";\n \n /* device ops to add/remove device to data core. */\n static struct virtio_net_device_ops const * notify_ops;\n /* Root address of the linked list in the configuration core. */\n static struct virtio_net_config_ll\t\t\t*ll_root = NULL;\n \n-/* Features supported by this application. RX merge buffers are disabled by default. */\n-uint64_t VHOST_FEATURES = (0ULL << VIRTIO_NET_F_MRG_RXBUF);\n+/* Features supported by this library. */\n+#define VHOST_SUPPORTED_FEATURES (1ULL << VIRTIO_NET_F_MRG_RXBUF)\n+static uint64_t VHOST_FEATURES = VHOST_SUPPORTED_FEATURES;\n \n /* Line size for reading maps file. */\n-const uint32_t BUFSIZE = PATH_MAX;\n+static const uint32_t BUFSIZE = PATH_MAX;\n \n /* Size of prot char array in procmap. */\n #define PROT_SZ 5\n@@ -347,8 +352,6 @@ cleanup_device(struct virtio_net *dev)\n \t/* Unmap QEMU memory file if mapped. */\n \tif (dev->mem) {\n \t\tmunmap((void*)(uintptr_t)dev->mem->mapped_address, (size_t)dev->mem->mapped_size);\n-\t\tif (dev->mem->regions_hpa)\n-\t\t\tfree(dev->mem->regions_hpa);\n \t\tfree(dev->mem);\n \t}\n \n@@ -434,12 +437,6 @@ new_device(struct vhost_device_ctx ctx)\n \tstruct virtio_net_config_ll *new_ll_dev;\n \tstruct vhost_virtqueue *virtqueue_rx, *virtqueue_tx;\n \n-\t/*check the number of devices in the system*/\n-\tif (num_cur_devices == num_devices) {\n-\t\tRTE_LOG(ERR, VHOST_CONFIG, \"() Max num devices (%u) exceeded\\n\", num_devices);\n-\t\treturn -1;\n-\t}\n-\n \t/* Setup device and virtqueues. */\n \tnew_ll_dev = malloc(sizeof(struct virtio_net_config_ll));\n \tif (new_ll_dev == NULL) {\n@@ -473,9 +470,6 @@ new_device(struct vhost_device_ctx ctx)\n \t/* Add entry to device configuration linked list. */\n \tadd_config_ll_entry(new_ll_dev);\n \n-\t/*increment the number of devices in the system*/\n-\tnum_cur_devices++;\n-\n \treturn new_ll_dev->dev.device_fh;\n }\n \n@@ -506,9 +500,6 @@ destroy_device(struct vhost_device_ctx ctx)\n \t\t\tll_dev_cur = ll_dev_cur->next;\n \t\t}\n \t}\n-\n-\t/*decrement the number of devices in the system*/\n-\tnum_cur_devices--;\n }\n \n /*\n@@ -592,153 +583,6 @@ set_features(struct vhost_device_ctx ctx, uint64_t *pu)\n \treturn 0;\n }\n \n-/*\n- * Calculate the region count of physical continous regions for one particular\n- * region of whose vhost virtual address is continous. The particular region\n- * start from vva_start, with size of 'size' in argument.\n- */\n-static uint32_t check_hpa_regions(uint64_t vva_start, uint64_t size)\n-{\n-\tuint32_t i, nregions = 0, page_size = PAGE_SIZE;\n-\tuint64_t cur_phys_addr = 0, next_phys_addr = 0;\n-\tif (vva_start % page_size) {\n-\t\tLOG_DEBUG(VHOST_CONFIG,\n-\t\t\t\"in check_countinous: vva start(%p) mod page_size(%d) \"\n-\t\t\t\"has remainder\\n\",\n-\t\t\t(void *)(uintptr_t)vva_start, page_size);\n-\t\treturn 0;\n-\t}\n-\tif (size % page_size) {\n-\t\tLOG_DEBUG(VHOST_CONFIG,\n-\t\t\t\"in check_countinous: \"\n-\t\t\t\"size((%\"PRIu64\")) mod page_size(%d) has remainder\\n\",\n-\t\t\tsize, page_size);\n-\t\treturn 0;\n-\t}\n-\tfor (i = 0; i < size - page_size; i = i + page_size) {\n-\t\tcur_phys_addr\n-\t\t\t= rte_mem_virt2phy((void *)(uintptr_t)(vva_start + i));\n-\t\tnext_phys_addr = rte_mem_virt2phy(\n-\t\t\t(void *)(uintptr_t)(vva_start + i + page_size));\n-\t\tif ((cur_phys_addr + page_size) != next_phys_addr) {\n-\t\t\t++nregions;\n-\t\t\tLOG_DEBUG(VHOST_CONFIG,\n-\t\t\t\t\"in check_continuous: hva addr:(%p) is not \"\n-\t\t\t\t\"continuous with hva addr:(%p), diff:%d\\n\",\n-\t\t\t\t(void *)(uintptr_t)(vva_start + (uint64_t)i),\n-\t\t\t\t(void *)(uintptr_t)(vva_start + (uint64_t)i\n-\t\t\t\t+ page_size), page_size);\n-\t\t\tLOG_DEBUG(VHOST_CONFIG,\n-\t\t\t\t\"in check_continuous: hpa addr:(%p) is not \"\n-\t\t\t\t\"continuous with hpa addr:(%p), \"\n-\t\t\t\t\"diff:(%\"PRIu64\")\\n\",\n-\t\t\t\t(void *)(uintptr_t)cur_phys_addr,\n-\t\t\t\t(void *)(uintptr_t)next_phys_addr,\n-\t\t\t\t(next_phys_addr-cur_phys_addr));\n-\t\t}\n-\t}\n-\treturn nregions;\n-}\n-\n-/*\n- * Divide each region whose vhost virtual address is continous into a few\n- * sub-regions, make sure the physical address within each sub-region are\n- * continous. And fill offset(to GPA) and size etc. information of each\n- * sub-region into regions_hpa.\n- */\n-static uint32_t fill_hpa_memory_regions(void *memory)\n-{\n-\tuint32_t regionidx, regionidx_hpa = 0, i, k, page_size = PAGE_SIZE;\n-\tuint64_t cur_phys_addr = 0, next_phys_addr = 0, vva_start;\n-\tstruct virtio_memory *virtio_memory = (struct virtio_memory *)memory;\n-\tstruct virtio_memory_regions_hpa *mem_region_hpa\n-\t\t= virtio_memory->regions_hpa;\n-\n-\tif (mem_region_hpa == NULL)\n-\t\treturn 0;\n-\n-\tfor (regionidx = 0; regionidx < virtio_memory->nregions; regionidx++) {\n-\t\tvva_start = virtio_memory->regions[regionidx].guest_phys_address\n-\t\t\t+ virtio_memory->regions[regionidx].address_offset;\n-\t\tmem_region_hpa[regionidx_hpa].guest_phys_address\n-\t\t\t= virtio_memory->regions[regionidx].guest_phys_address;\n-\t\tmem_region_hpa[regionidx_hpa].host_phys_addr_offset =\n-\t\t\trte_mem_virt2phy((void *)(uintptr_t)(vva_start))\n-\t\t\t- mem_region_hpa[regionidx_hpa].guest_phys_address;\n-\t\tLOG_DEBUG(VHOST_CONFIG,\n-\t\t\t\"in fill_hpa_regions: guest phys addr start[%d]:(%p)\\n\",\n-\t\t\tregionidx_hpa,\n-\t\t\t(void *)(uintptr_t)\n-\t\t\t(mem_region_hpa[regionidx_hpa].guest_phys_address));\n-\t\tLOG_DEBUG(VHOST_CONFIG,\n-\t\t\t\"in fill_hpa_regions: host  phys addr start[%d]:(%p)\\n\",\n-\t\t\tregionidx_hpa,\n-\t\t\t(void *)(uintptr_t)\n-\t\t\t(mem_region_hpa[regionidx_hpa].host_phys_addr_offset));\n-\t\tfor (i = 0, k = 0;\n-\t\t\ti < virtio_memory->regions[regionidx].memory_size\n-\t\t\t\t- page_size;\n-\t\t\ti += page_size) {\n-\t\t\tcur_phys_addr = rte_mem_virt2phy(\n-\t\t\t\t\t(void *)(uintptr_t)(vva_start + i));\n-\t\t\tnext_phys_addr = rte_mem_virt2phy(\n-\t\t\t\t\t(void *)(uintptr_t)(vva_start\n-\t\t\t\t\t+ i + page_size));\n-\t\t\tif ((cur_phys_addr + page_size) != next_phys_addr) {\n-\t\t\t\tmem_region_hpa[regionidx_hpa].guest_phys_address_end =\n-\t\t\t\t\tmem_region_hpa[regionidx_hpa].guest_phys_address\n-\t\t\t\t\t+ k + page_size;\n-\t\t\t\tmem_region_hpa[regionidx_hpa].memory_size\n-\t\t\t\t\t= k + page_size;\n-\t\t\t\tLOG_DEBUG(VHOST_CONFIG, \"in fill_hpa_regions: guest \"\n-\t\t\t\t\t\"phys addr end  [%d]:(%p)\\n\",\n-\t\t\t\t\tregionidx_hpa,\n-\t\t\t\t\t(void *)(uintptr_t)\n-\t\t\t\t\t(mem_region_hpa[regionidx_hpa].guest_phys_address_end));\n-\t\t\t\tLOG_DEBUG(VHOST_CONFIG,\n-\t\t\t\t\t\"in fill_hpa_regions: guest phys addr \"\n-\t\t\t\t\t\"size [%d]:(%p)\\n\",\n-\t\t\t\t\tregionidx_hpa,\n-\t\t\t\t\t(void *)(uintptr_t)\n-\t\t\t\t\t(mem_region_hpa[regionidx_hpa].memory_size));\n-\t\t\t\tmem_region_hpa[regionidx_hpa + 1].guest_phys_address\n-\t\t\t\t\t= mem_region_hpa[regionidx_hpa].guest_phys_address_end;\n-\t\t\t\t++regionidx_hpa;\n-\t\t\t\tmem_region_hpa[regionidx_hpa].host_phys_addr_offset =\n-\t\t\t\t\tnext_phys_addr\n-\t\t\t\t\t- mem_region_hpa[regionidx_hpa].guest_phys_address;\n-\t\t\t\tLOG_DEBUG(VHOST_CONFIG, \"in fill_hpa_regions: guest\"\n-\t\t\t\t\t\" phys addr start[%d]:(%p)\\n\",\n-\t\t\t\t\tregionidx_hpa,\n-\t\t\t\t\t(void *)(uintptr_t)\n-\t\t\t\t\t(mem_region_hpa[regionidx_hpa].guest_phys_address));\n-\t\t\t\tLOG_DEBUG(VHOST_CONFIG,\n-\t\t\t\t\t\"in fill_hpa_regions: host  phys addr \"\n-\t\t\t\t\t\"start[%d]:(%p)\\n\",\n-\t\t\t\t\tregionidx_hpa,\n-\t\t\t\t\t(void *)(uintptr_t)\n-\t\t\t\t\t(mem_region_hpa[regionidx_hpa].host_phys_addr_offset));\n-\t\t\t\tk = 0;\n-\t\t\t} else {\n-\t\t\t\tk += page_size;\n-\t\t\t}\n-\t\t}\n-\t\tmem_region_hpa[regionidx_hpa].guest_phys_address_end\n-\t\t\t= mem_region_hpa[regionidx_hpa].guest_phys_address\n-\t\t\t+ k + page_size;\n-\t\tmem_region_hpa[regionidx_hpa].memory_size = k + page_size;\n-\t\tLOG_DEBUG(VHOST_CONFIG, \"in fill_hpa_regions: guest phys addr end  \"\n-\t\t\t\"[%d]:(%p)\\n\", regionidx_hpa,\n-\t\t\t(void *)(uintptr_t)\n-\t\t\t(mem_region_hpa[regionidx_hpa].guest_phys_address_end));\n-\t\tLOG_DEBUG(VHOST_CONFIG, \"in fill_hpa_regions: guest phys addr size \"\n-\t\t\t\"[%d]:(%p)\\n\", regionidx_hpa,\n-\t\t\t(void *)(uintptr_t)\n-\t\t\t(mem_region_hpa[regionidx_hpa].memory_size));\n-\t\t++regionidx_hpa;\n-\t}\n-\treturn regionidx_hpa;\n-}\n \n /*\n  * Called from CUSE IOCTL: VHOST_SET_MEM_TABLE\n@@ -832,7 +676,6 @@ set_mem_table(struct vhost_device_ctx ctx, const void *mem_regions_addr, uint32_\n \t\t}\n \t}\n \tmem->nregions = valid_regions;\n-\tmem->nregions_hpa = mem->nregions;\n \tdev->mem = mem;\n \n \t/*\n@@ -843,34 +686,7 @@ set_mem_table(struct vhost_device_ctx ctx, const void *mem_regions_addr, uint32_\n \t\tdev->mem->regions[regionidx].address_offset = dev->mem->regions[regionidx].userspace_address - dev->mem->base_address\n \t\t\t+ dev->mem->mapped_address - dev->mem->regions[regionidx].guest_phys_address;\n \n-\t\tdev->mem->nregions_hpa\n-\t\t\t+= check_hpa_regions(\n-\t\t\t\tdev->mem->regions[regionidx].guest_phys_address\n-\t\t\t\t+ dev->mem->regions[regionidx].address_offset,\n-\t\t\t\tdev->mem->regions[regionidx].memory_size);\n-\t}\n-\tif (dev->mem->regions_hpa != NULL) {\n-\t\tfree(dev->mem->regions_hpa);\n-\t\tdev->mem->regions_hpa = NULL;\n \t}\n-\n-\tdev->mem->regions_hpa = (struct virtio_memory_regions_hpa *) calloc(1,\n-\t\t(sizeof(struct virtio_memory_regions_hpa)\n-\t\t* dev->mem->nregions_hpa));\n-\tif (dev->mem->regions_hpa == NULL) {\n-\t\tRTE_LOG(ERR, VHOST_CONFIG,\n-\t\t\t\"(%\"PRIu64\") Failed to allocate memory for \"\n-\t\t\t\"dev->mem->regions_hpa.\\n\", dev->device_fh);\n-\t\treturn -1;\n-\t}\n-\tif (fill_hpa_memory_regions(\n-\t\t(void *)dev->mem) != dev->mem->nregions_hpa) {\n-\t\tRTE_LOG(ERR, VHOST_CONFIG,\n-\t\t\t\"in set_mem_table: hpa memory regions number mismatch: \"\n-\t\t\t\"[%d]\\n\", dev->mem->nregions_hpa);\n-\t\treturn -1;\n-\t}\n-\n \treturn 0;\n }\n \n@@ -1144,22 +960,45 @@ get_virtio_net_callbacks(void)\n \treturn &vhost_device_ops;\n }\n \n-/*\n- * Register ops so that we can add/remove device to data core.\n- */\n-int\n-init_virtio_net(struct virtio_net_device_ops const * const ops)\n+int rte_vhost_enable_guest_notification(struct virtio_net *dev, uint16_t queue_id, int enable)\n {\n-\tnotify_ops = ops;\n+\tif (enable) {\n+\t\tRTE_LOG(ERR, VHOST_CONFIG, \"guest notification isn't supported.\\n\");\n+\t\treturn -1;\n+\t}\n \n+\tdev->virtqueue[queue_id]->used->flags = enable ? 0 : 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 /*\n- * Currently not used as we Ctrl+c to exit application.\n+ * Register ops so that we can add/remove device to data core.\n  */\n int\n-deinit_virtio_net(void)\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",
    "prefixes": [
        "dpdk-dev",
        "v4",
        "3/5"
    ]
}