get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 48780,
    "url": "https://patches.dpdk.org/api/patches/48780/?format=api",
    "web_url": "https://patches.dpdk.org/project/dpdk/patch/20181213133051.18779-1-jgrajcia@cisco.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": "<20181213133051.18779-1-jgrajcia@cisco.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20181213133051.18779-1-jgrajcia@cisco.com",
    "date": "2018-12-13T13:30:51",
    "name": "[RFC,v3] /net: memory interface (memif)",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "38d011109fcd7c48e5f4ca61cfdfbfbbc3530489",
    "submitter": {
        "id": 1169,
        "url": "https://patches.dpdk.org/api/people/1169/?format=api",
        "name": "Jakub Grajciar -X (jgrajcia - PANTHEON TECH SRO at Cisco)",
        "email": "jgrajcia@cisco.com"
    },
    "delegate": null,
    "mbox": "https://patches.dpdk.org/project/dpdk/patch/20181213133051.18779-1-jgrajcia@cisco.com/mbox/",
    "series": [
        {
            "id": 2762,
            "url": "https://patches.dpdk.org/api/series/2762/?format=api",
            "web_url": "https://patches.dpdk.org/project/dpdk/list/?series=2762",
            "date": "2018-12-13T13:30:51",
            "name": "[RFC,v3] /net: memory interface (memif)",
            "version": 3,
            "mbox": "https://patches.dpdk.org/series/2762/mbox/"
        }
    ],
    "comments": "https://patches.dpdk.org/api/patches/48780/comments/",
    "check": "warning",
    "checks": "https://patches.dpdk.org/api/patches/48780/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 [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id 1ED101B544;\n\tThu, 13 Dec 2018 14:31:12 +0100 (CET)",
            "from alln-iport-3.cisco.com (alln-iport-3.cisco.com\n\t[173.37.142.90]) by dpdk.org (Postfix) with ESMTP id 36DB91B540\n\tfor <dev@dpdk.org>; Thu, 13 Dec 2018 14:31:09 +0100 (CET)",
            "from rcdn-core-4.cisco.com ([173.37.93.155])\n\tby alln-iport-3.cisco.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384;\n\t13 Dec 2018 13:31:07 +0000",
            "from XCH-RCD-017.cisco.com (xch-rcd-017.cisco.com [173.37.102.27])\n\tby rcdn-core-4.cisco.com (8.15.2/8.15.2) with ESMTPS id\n\twBDDV7uP014350\n\t(version=TLSv1.2 cipher=AES256-SHA bits=256 verify=FAIL)\n\tfor <dev@dpdk.org>; Thu, 13 Dec 2018 13:31:07 GMT",
            "from localhost.localdomain (10.61.170.107) by XCH-RCD-017.cisco.com\n\t(173.37.102.27) with Microsoft SMTP Server (TLS) id 15.0.1395.4;\n\tThu, 13 Dec 2018 07:31:04 -0600"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple;\n\td=cisco.com; i=@cisco.com; l=83590; q=dns/txt;\n\ts=iport; t=1544707870; x=1545917470;\n\th=from:to:cc:subject:date:message-id:mime-version;\n\tbh=rUMbyY4R+gf/ZVHGTjyTwHuwnM6utGYM2P9K0efqadY=;\n\tb=hFTH8poEWpfaYzj+o3p38dWCa71wNI8IrCgyE6lKXN28QkJq5tNQQjm3\n\tpq0+LHLvVGIJKfK312U/qOa79F/m5Qz1cwQrR4XcV5wx09Y4KKXebTuOe\n\t2o+LDovz5JDVPR6HcxrWTlFpzOYNh/cBEhgQcTI54SOczKxKN9S8cPNLf 0=;",
        "X-IronPort-Anti-Spam-Filtered": "true",
        "X-IronPort-Anti-Spam-Result": "A0AFAAAUXhJc/5tdJa1jGQEBAQEBAQEBAQEBAQcBAQEBAQGBUQQBAQEBAQsBAYICZoECJwqMC5dAhSGJEhSBZgsBAR+ETYMEIjQJDQEDAQECAQECbRwMQgEOAYULAQxSLXoDFAoEBYMhAYFzDad1M4JMgnSEcId9VYNqF4FAP4ERh1iGFgKJNQYEhgiBT495CYZNQIpBCxiBXE2ET4MqhyiOJIp+AhEUgUY4gVZNIxU7gmwJghsCAReCbINCgTsyhgM+AQExiBGEHwGBHgEB",
        "X-IronPort-AV": "E=Sophos;i=\"5.56,349,1539648000\"; d=\"scan'208\";a=\"212909529\"",
        "From": "Jakub Grajciar <jgrajcia@cisco.com>",
        "To": "<dev@dpdk.org>",
        "CC": "Jakub Grajciar <jgrajcia@cisco.com>",
        "Date": "Thu, 13 Dec 2018 14:30:51 +0100",
        "Message-ID": "<20181213133051.18779-1-jgrajcia@cisco.com>",
        "X-Mailer": "git-send-email 2.17.1",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain",
        "X-Originating-IP": "[10.61.170.107]",
        "X-ClientProxiedBy": "xch-aln-006.cisco.com (173.36.7.16) To\n\tXCH-RCD-017.cisco.com (173.37.102.27)",
        "X-Outbound-SMTP-Client": "173.37.102.27, xch-rcd-017.cisco.com",
        "X-Outbound-Node": "rcdn-core-4.cisco.com",
        "Subject": "[dpdk-dev] [RFC v3] /net: memory interface (memif)",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n\t<mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://mails.dpdk.org/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n\t<mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "Memory interface (memif), provides high performance\npacket transfer over shared memory.\n\nSigned-off-by: Jakub Grajciar <jgrajcia@cisco.com>\n---\n config/common_base                          |    5 +\n config/common_linuxapp                      |    1 +\n doc/guides/nics/memif.rst                   |   80 ++\n drivers/net/Makefile                        |    1 +\n drivers/net/memif/Makefile                  |   29 +\n drivers/net/memif/memif.h                   |  143 +++\n drivers/net/memif/memif_socket.c            | 1093 +++++++++++++++++\n drivers/net/memif/memif_socket.h            |  104 ++\n drivers/net/memif/meson.build               |   10 +\n drivers/net/memif/rte_eth_memif.c           | 1189 +++++++++++++++++++\n drivers/net/memif/rte_eth_memif.h           |  207 ++++\n drivers/net/memif/rte_pmd_memif_version.map |    4 +\n drivers/net/meson.build                     |    1 +\n mk/rte.app.mk                               |    1 +\n 14 files changed, 2868 insertions(+)\n create mode 100644 doc/guides/nics/memif.rst\n create mode 100644 drivers/net/memif/Makefile\n create mode 100644 drivers/net/memif/memif.h\n create mode 100644 drivers/net/memif/memif_socket.c\n create mode 100644 drivers/net/memif/memif_socket.h\n create mode 100644 drivers/net/memif/meson.build\n create mode 100644 drivers/net/memif/rte_eth_memif.c\n create mode 100644 drivers/net/memif/rte_eth_memif.h\n create mode 100644 drivers/net/memif/rte_pmd_memif_version.map\n\nv3:\n- coding style fixes\n- documentation\n- doxygen comments\n- use strlcpy() instead of strncpy()\n- use RTE_BUILD_BUG_ON instead of _Static_assert()\n- fix meson build deps",
    "diff": "diff --git a/config/common_base b/config/common_base\nindex d12ae98bc..b8ed10ae5 100644\n--- a/config/common_base\n+++ b/config/common_base\n@@ -403,6 +403,11 @@ CONFIG_RTE_LIBRTE_VMXNET3_DEBUG_TX_FREE=n\n #\n CONFIG_RTE_LIBRTE_PMD_AF_PACKET=n\n \n+#\n+# Compile Memory Interface PMD driver (Linux only)\n+#\n+CONFIG_RTE_LIBRTE_PMD_MEMIF=n\n+\n #\n # Compile link bonding PMD library\n #\ndiff --git a/config/common_linuxapp b/config/common_linuxapp\nindex 6c1c8d0f4..42cbde8f5 100644\n--- a/config/common_linuxapp\n+++ b/config/common_linuxapp\n@@ -18,6 +18,7 @@ CONFIG_RTE_LIBRTE_VHOST_POSTCOPY=n\n CONFIG_RTE_LIBRTE_PMD_VHOST=y\n CONFIG_RTE_LIBRTE_IFC_PMD=y\n CONFIG_RTE_LIBRTE_PMD_AF_PACKET=y\n+CONFIG_RTE_LIBRTE_PMD_MEMIF=y\n CONFIG_RTE_LIBRTE_PMD_SOFTNIC=y\n CONFIG_RTE_LIBRTE_PMD_TAP=y\n CONFIG_RTE_LIBRTE_AVP_PMD=y\ndiff --git a/doc/guides/nics/memif.rst b/doc/guides/nics/memif.rst\nnew file mode 100644\nindex 000000000..55d477840\n--- /dev/null\n+++ b/doc/guides/nics/memif.rst\n@@ -0,0 +1,80 @@\n+..  SPDX-License-Identifier: BSD-3-Clause\n+    Copyright(c) 2018 Cisco Systems, Inc.\n+\n+Memif Poll Mode Driver\n+======================\n+\n+Memif PMD allows for DPDK and any other client using memif (DPDK, VPP, libmemif) to\n+communicate using shared memory.\n+\n+The created device, transmits packets in a raw format. It can be used with Ethernet\n+mode, IP mode, or Punt/Inject. At this moment, only Ethernet mode is supported in\n+DPDK memif implementation.\n+\n+The method to enable one or more interfaces is to use the\n+``--vdev=net_memif0`` option on the DPDK application command line. Each\n+``--vdev=net_memif1`` option given will create an interface named net_memif0, net_memif1,\n+and so on.  Memif uses unix domain socket to transmit control messages.\n+Each memif has a unique id per socket. If you are connecting multiple\n+interfaces using same socket, be sure to specify unique ids ``id=0``, ``id=1``, etc.\n+Note that if you assign a socket to a master interface it becomes a listener socket.\n+Listener socket can not be used by a slave interface on same client.\n+\n+Memif works in two roles: master and slave. Slave connects to master over an existing\n+socket. It is also a producer of shared memory file and initializes the shared memory.\n+Master creates the socket and listens for any slave connection requests. The socket may\n+already exist on the system. Be sure to remove any such sockets, if you are\n+creating a master interface, or you will see an \"Address already in use\" error. Function\n+``rte_pmd_memif_remove()``, which removes memif interface, will also remove a listener socket,\n+if  it is not beeing used by any other interface.\n+\n+.. csv-table:: Memif configuration options:\n+   :header: \"Option\", \"Description\", \"Default\"\n+\n+   \"id=0\", \"Each memif on same socket must be given a unique id\", 0\n+   \"role=master\", \"Set memif role\", slave\n+   \"bsize=1024\", \"Size of packet buffer\", 2048\n+   \"rsize=11\", \"Log2 of ring size. If rsize is 10, actual ring size is 1024\", 10\n+   \"nrxq=2\", \"Number of RX queues\", 1\n+   \"ntxq=2\", \"Number of TX queues\", 1\n+   \"socket=/tmp/memif.sock\", \"Socket filename\", \"/tmp/memif.sock\"\n+   \"mac=01:23:45:ab:cd:ef\", \"Mac address\", \"01:ab:23:cd:45:ef\"\n+   \"secret=abc123\", \"Secret is an optional security option, which if specified, must be matched by peer\",\n+    \"zero-copy=yes\", \"Enable/disable zero-copy slave mode\", no\n+\n+Example: testpmd and VPP\n+------------------------\n+\n+For information on how to get and run VPP please see `<https://wiki.fd.io/view/VPP>`_.\n+\n+Start VPP in interactive mode (should be by default). Create memif master interface in VPP::\n+\n+    vpp# create interface memif id 0 master no-zero-copy\n+    vpp# set interface state memif0/0 up\n+    vpp# set interface ip address memif0/0 192.168.1.1/24\n+\n+To see socket filename use show memif command::\n+\n+    vpp# show memif\n+    sockets\n+     id  listener    filename\n+      0   yes (1)     /run/vpp/memif.sock\n+    ...\n+\n+Now create memif interface by running testpmd with these command line options::\n+\n+    #./testpmd --vdev=net_memif,socket=/run/vpp/memif.sock -- -i\n+\n+Testpmd should now create memif slave interface and try to connect to master.\n+In testpmd set forward option to icmpecho and start forwarding::\n+\n+    testpmd> set fwd icmpecho\n+    testpmd> start\n+\n+Send ping from VPP::\n+\n+    vpp# ping 192.168.1.2\n+    64 bytes from 192.168.1.2: icmp_seq=2 ttl=254 time=36.2918 ms\n+    64 bytes from 192.168.1.2: icmp_seq=3 ttl=254 time=23.3927 ms\n+    64 bytes from 192.168.1.2: icmp_seq=4 ttl=254 time=24.2975 ms\n+    64 bytes from 192.168.1.2: icmp_seq=5 ttl=254 time=17.7049 ms\ndiff --git a/drivers/net/Makefile b/drivers/net/Makefile\nindex c0386feb9..0feab5241 100644\n--- a/drivers/net/Makefile\n+++ b/drivers/net/Makefile\n@@ -32,6 +32,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += fm10k\n DIRS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += i40e\n DIRS-$(CONFIG_RTE_LIBRTE_IXGBE_PMD) += ixgbe\n DIRS-$(CONFIG_RTE_LIBRTE_LIO_PMD) += liquidio\n+DIRS-$(CONFIG_RTE_LIBRTE_PMD_MEMIF) += memif\n DIRS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4\n DIRS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5\n DIRS-$(CONFIG_RTE_LIBRTE_MVNETA_PMD) += mvneta\ndiff --git a/drivers/net/memif/Makefile b/drivers/net/memif/Makefile\nnew file mode 100644\nindex 000000000..a82448423\n--- /dev/null\n+++ b/drivers/net/memif/Makefile\n@@ -0,0 +1,29 @@\n+# SPDX-License-Identifier: BSD-3-Clause\n+# Copyright 2018 Cisco Systems, Inc.  All rights reserved.\n+\n+include $(RTE_SDK)/mk/rte.vars.mk\n+\n+#\n+# library name\n+#\n+LIB = librte_pmd_memif.a\n+\n+EXPORT_MAP := rte_pmd_memif_version.map\n+\n+LIBABIVER := 1\n+\n+CFLAGS += -O3\n+CFLAGS += -I$(SRCDIR)\n+CFLAGS += $(WERROR_FLAGS)\n+CFLAGS += -Wno-pointer-arith\n+LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ring\n+LDLIBS += -lrte_ethdev -lrte_net -lrte_kvargs\n+LDLIBS += -lrte_bus_vdev\n+\n+#\n+# all source are stored in SRCS-y\n+#\n+SRCS-$(CONFIG_RTE_LIBRTE_PMD_MEMIF) += rte_eth_memif.c\n+SRCS-$(CONFIG_RTE_LIBRTE_PMD_MEMIF) += memif_socket.c\n+\n+include $(RTE_SDK)/mk/rte.lib.mk\ndiff --git a/drivers/net/memif/memif.h b/drivers/net/memif/memif.h\nnew file mode 100644\nindex 000000000..8b759d74b\n--- /dev/null\n+++ b/drivers/net/memif/memif.h\n@@ -0,0 +1,143 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright 2018 Cisco Systems, Inc.  All rights reserved.\n+ */\n+\n+#ifndef _MEMIF_H_\n+#define _MEMIF_H_\n+\n+#ifndef MEMIF_CACHELINE_SIZE\n+#define MEMIF_CACHELINE_SIZE 64\n+#endif\n+\n+#define MEMIF_COOKIE\t\t0x3E31F20\n+#define MEMIF_VERSION_MAJOR\t2\n+#define MEMIF_VERSION_MINOR\t0\n+#define MEMIF_VERSION\t\t((MEMIF_VERSION_MAJOR << 8) | MEMIF_VERSION_MINOR)\n+\n+/*\n+ *  Type definitions\n+ */\n+\n+typedef enum memif_msg_type {\n+\tMEMIF_MSG_TYPE_NONE = 0,\n+\tMEMIF_MSG_TYPE_ACK = 1,\n+\tMEMIF_MSG_TYPE_HELLO = 2,\n+\tMEMIF_MSG_TYPE_INIT = 3,\n+\tMEMIF_MSG_TYPE_ADD_REGION = 4,\n+\tMEMIF_MSG_TYPE_ADD_RING = 5,\n+\tMEMIF_MSG_TYPE_CONNECT = 6,\n+\tMEMIF_MSG_TYPE_CONNECTED = 7,\n+\tMEMIF_MSG_TYPE_DISCONNECT = 8,\n+} memif_msg_type_t;\n+\n+typedef enum {\n+\tMEMIF_RING_S2M = 0,\n+\tMEMIF_RING_M2S = 1\n+} memif_ring_type_t;\n+\n+typedef enum {\n+\tMEMIF_INTERFACE_MODE_ETHERNET = 0,\n+\tMEMIF_INTERFACE_MODE_IP = 1,\n+\tMEMIF_INTERFACE_MODE_PUNT_INJECT = 2,\n+} memif_interface_mode_t;\n+\n+typedef uint16_t memif_region_index_t;\n+typedef uint32_t memif_region_offset_t;\n+typedef uint64_t memif_region_size_t;\n+typedef uint16_t memif_ring_index_t;\n+typedef uint32_t memif_interface_id_t;\n+typedef uint16_t memif_version_t;\n+typedef uint8_t memif_log2_ring_size_t;\n+\n+/*\n+ *  Socket messages\n+ */\n+\n+typedef struct __attribute__ ((packed)) {\n+\tuint8_t name[32];\n+\tmemif_version_t min_version;\n+\tmemif_version_t max_version;\n+\tmemif_region_index_t max_region;\n+\tmemif_ring_index_t max_m2s_ring;\n+\tmemif_ring_index_t max_s2m_ring;\n+\tmemif_log2_ring_size_t max_log2_ring_size;\n+} memif_msg_hello_t;\n+\n+typedef struct __attribute__ ((packed)) {\n+\tmemif_version_t version;\n+\tmemif_interface_id_t id;\n+\tmemif_interface_mode_t mode:8;\n+\tuint8_t secret[24];\n+\tuint8_t name[32];\n+} memif_msg_init_t;\n+\n+typedef struct __attribute__ ((packed)) {\n+\tmemif_region_index_t index;\n+\tmemif_region_size_t size;\n+} memif_msg_add_region_t;\n+\n+typedef struct __attribute__ ((packed)) {\n+\tuint16_t flags;\n+#define MEMIF_MSG_ADD_RING_FLAG_S2M\t(1 << 0)\n+\tmemif_ring_index_t index;\n+\tmemif_region_index_t region;\n+\tmemif_region_offset_t offset;\n+\tmemif_log2_ring_size_t log2_ring_size;\n+\tuint16_t private_hdr_size;\t/* used for private metadata */\n+} memif_msg_add_ring_t;\n+\n+typedef struct __attribute__ ((packed)) {\n+\tuint8_t if_name[32];\n+} memif_msg_connect_t;\n+\n+typedef struct __attribute__ ((packed)) {\n+\tuint8_t if_name[32];\n+} memif_msg_connected_t;\n+\n+typedef struct __attribute__ ((packed)) {\n+\tuint32_t code;\n+\tuint8_t string[96];\n+} memif_msg_disconnect_t;\n+\n+typedef struct __attribute__ ((packed, aligned(128))) {\n+\tmemif_msg_type_t type:16;\n+\tunion {\n+\t\tmemif_msg_hello_t hello;\n+\t\tmemif_msg_init_t init;\n+\t\tmemif_msg_add_region_t add_region;\n+\t\tmemif_msg_add_ring_t add_ring;\n+\t\tmemif_msg_connect_t connect;\n+\t\tmemif_msg_connected_t connected;\n+\t\tmemif_msg_disconnect_t disconnect;\n+\t};\n+} memif_msg_t;\n+\n+/*\n+ *  Ring and Descriptor Layout\n+ */\n+\n+typedef struct __attribute__ ((packed)) {\n+\tuint16_t flags;\n+#define MEMIF_DESC_FLAG_NEXT (1 << 0)\n+\tmemif_region_index_t region;\n+\tuint32_t length;\n+\tmemif_region_offset_t offset;\n+\tuint32_t metadata;\n+} memif_desc_t;\n+\n+#define MEMIF_CACHELINE_ALIGN_MARK(mark) \\\n+\tuint8_t mark[0] __attribute__((aligned(MEMIF_CACHELINE_SIZE)))\n+\n+typedef struct {\n+\tMEMIF_CACHELINE_ALIGN_MARK(cacheline0);\n+\tuint32_t cookie;\n+\tuint16_t flags;\n+#define MEMIF_RING_FLAG_MASK_INT 1\n+\tvolatile uint16_t head;\n+\t MEMIF_CACHELINE_ALIGN_MARK(cacheline1);\n+\tvolatile uint16_t tail;\n+\t MEMIF_CACHELINE_ALIGN_MARK(cacheline2);\n+\tmemif_desc_t desc[0];\n+} memif_ring_t;\n+\n+#endif\t\t\t\t/* _MEMIF_H_ */\ndiff --git a/drivers/net/memif/memif_socket.c b/drivers/net/memif/memif_socket.c\nnew file mode 100644\nindex 000000000..a66b5741a\n--- /dev/null\n+++ b/drivers/net/memif/memif_socket.c\n@@ -0,0 +1,1093 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright 2018 Cisco Systems, Inc.  All rights reserved.\n+ */\n+\n+#include <stdlib.h>\n+#include <fcntl.h>\n+#include <unistd.h>\n+#include <sys/types.h>\n+#include <sys/socket.h>\n+#include <sys/un.h>\n+#include <sys/ioctl.h>\n+#include <errno.h>\n+\n+#include <rte_version.h>\n+#include <rte_mbuf.h>\n+#include <rte_ether.h>\n+#include <rte_ethdev_driver.h>\n+#include <rte_ethdev_vdev.h>\n+#include <rte_malloc.h>\n+#include <rte_kvargs.h>\n+#include <rte_bus_vdev.h>\n+#include <rte_hash.h>\n+#include <rte_jhash.h>\n+#include <rte_string_fns.h>\n+\n+#include <rte_eth_memif.h>\n+#include <memif_socket.h>\n+\n+static void memif_intr_handler(void *arg);\n+\n+static ssize_t\n+memif_msg_send(int fd, memif_msg_t *msg, int afd)\n+{\n+\tstruct msghdr mh = { 0 };\n+\tstruct iovec iov[1];\n+\tchar ctl[CMSG_SPACE(sizeof(int))];\n+\n+\tiov[0].iov_base = (void *)msg;\n+\tiov[0].iov_len = sizeof(memif_msg_t);\n+\tmh.msg_iov = iov;\n+\tmh.msg_iovlen = 1;\n+\n+\tif (afd > 0) {\n+\t\tstruct cmsghdr *cmsg;\n+\t\tmemset(&ctl, 0, sizeof(ctl));\n+\t\tmh.msg_control = ctl;\n+\t\tmh.msg_controllen = sizeof(ctl);\n+\t\tcmsg = CMSG_FIRSTHDR(&mh);\n+\t\tcmsg->cmsg_len = CMSG_LEN(sizeof(int));\n+\t\tcmsg->cmsg_level = SOL_SOCKET;\n+\t\tcmsg->cmsg_type = SCM_RIGHTS;\n+\t\trte_memcpy(CMSG_DATA(cmsg), &afd, sizeof(int));\n+\t}\n+\n+\treturn sendmsg(fd, &mh, 0);\n+}\n+\n+static int\n+memif_msg_send_from_queue(struct memif_control_channel *cc)\n+{\n+\tssize_t size;\n+\tint ret = 0;\n+\tstruct memif_msg_queue_elt *e;\n+\te = TAILQ_FIRST(&cc->msg_queue);\n+\tif (e == NULL)\n+\t\treturn 0;\n+\n+\tsize = memif_msg_send(cc->intr_handle.fd, &e->msg, e->fd);\n+\tif (size != sizeof(memif_msg_t)) {\n+\t\tMIF_LOG(ERR, \"sendmsg fail: %s.\", strerror(errno));\n+\t\tret = -1;\n+\t} else {\n+\t\tMIF_LOG(DEBUG, \"%s: Sent msg type %u.\",\n+\t\t\t(cc->pmd !=\n+\t\t\t NULL) ? rte_vdev_device_name(cc->pmd->vdev) :\n+\t\t\t\t \"memif_driver\",\n+\t\t\te->msg.type);\n+\t}\n+\tTAILQ_REMOVE(&cc->msg_queue, e, next);\n+\trte_free(e);\n+\n+\treturn ret;\n+}\n+\n+static struct memif_msg_queue_elt *\n+memif_msg_enq(struct memif_control_channel *cc)\n+{\n+\tstruct memif_msg_queue_elt *e = rte_zmalloc(\"memif_msg\",\n+\t\t\t\t\t\t    sizeof(struct\n+\t\t\t\t\t\t\t   memif_msg_queue_elt),\n+\t\t\t\t\t\t    0);\n+\tif (e == NULL) {\n+\t\tMIF_LOG(ERR, \"Failed to allocate control message.\");\n+\t\treturn NULL;\n+\t}\n+\n+\te->fd = -1;\n+\tTAILQ_INSERT_TAIL(&cc->msg_queue, e, next);\n+\n+\treturn e;\n+}\n+\n+void\n+memif_msg_enq_disconnect(struct memif_control_channel *cc, const char *reason,\n+\t\t\t int err_code)\n+{\n+\tstruct memif_msg_queue_elt *e = memif_msg_enq(cc);\n+\tif (e == NULL) {\n+\t\tMIF_LOG(WARNING, \"%s: Failed to enqueue disconnect message.\",\n+\t\t\t(cc->pmd !=\n+\t\t\t NULL) ? rte_vdev_device_name(cc->pmd->vdev) :\n+\t\t\t\t \"memif_driver\");\n+\t\treturn;\n+\t}\n+\n+\tmemif_msg_disconnect_t *d = &e->msg.disconnect;\n+\n+\te->msg.type = MEMIF_MSG_TYPE_DISCONNECT;\n+\td->code = err_code;\n+\n+\tif (reason != NULL) {\n+\t\tstrlcpy((char *)d->string, reason, sizeof(d->string));\n+\t\tif (cc->pmd != NULL) {\n+\t\t\tstrlcpy(cc->pmd->local_disc_string, reason,\n+\t\t\t\tsizeof(cc->pmd->local_disc_string));\n+\t\t}\n+\t}\n+}\n+\n+static int\n+memif_msg_enq_hello(struct memif_control_channel *cc)\n+{\n+\tstruct memif_msg_queue_elt *e = memif_msg_enq(cc);\n+\tif (e == NULL)\n+\t\treturn -1;\n+\n+\tmemif_msg_hello_t *h = &e->msg.hello;\n+\n+\te->msg.type = MEMIF_MSG_TYPE_HELLO;\n+\th->min_version = MEMIF_VERSION;\n+\th->max_version = MEMIF_VERSION;\n+\th->max_s2m_ring = ETH_MEMIF_MAX_NUM_Q_PAIRS;\n+\th->max_m2s_ring = ETH_MEMIF_MAX_NUM_Q_PAIRS;\n+\th->max_region = ETH_MEMIF_MAX_REGION_IDX;\n+\th->max_log2_ring_size = ETH_MEMIF_MAX_LOG2_RING_SIZE;\n+\n+\tstrlcpy((char *)h->name, rte_version(), sizeof(h->name));\n+\n+\treturn 0;\n+}\n+\n+static int\n+memif_msg_receive_hello(struct pmd_internals *pmd, memif_msg_t *msg)\n+{\n+\tmemif_msg_hello_t *h = &msg->hello;\n+\n+\tif (h->min_version > MEMIF_VERSION || h->max_version < MEMIF_VERSION) {\n+\t\tmemif_msg_enq_disconnect(pmd->cc, \"Incompatible memif version\",\n+\t\t\t\t\t 0);\n+\t\treturn -1;\n+\t}\n+\n+\t/* Set parameters for active connection */\n+\tpmd->run.num_s2m_rings = RTE_MIN(h->max_s2m_ring + 1,\n+\t\t\t\t\t   pmd->cfg.num_s2m_rings);\n+\tpmd->run.num_m2s_rings = RTE_MIN(h->max_m2s_ring + 1,\n+\t\t\t\t\t   pmd->cfg.num_m2s_rings);\n+\tpmd->run.log2_ring_size = RTE_MIN(h->max_log2_ring_size,\n+\t\t\t\t\t    pmd->cfg.log2_ring_size);\n+\tpmd->run.buffer_size = pmd->cfg.buffer_size;\n+\n+\tstrlcpy(pmd->remote_name, (char *)h->name, sizeof(pmd->remote_name));\n+\n+\tMIF_LOG(DEBUG, \"%s: Connecting to %s.\",\n+\t\trte_vdev_device_name(pmd->vdev), pmd->remote_name);\n+\n+\treturn 0;\n+}\n+\n+static int\n+memif_msg_receive_init(struct memif_control_channel *cc, memif_msg_t *msg)\n+{\n+\tmemif_msg_init_t *i = &msg->init;\n+\tstruct memif_socket_pmd_list_elt *elt;\n+\tstruct pmd_internals *pmd;\n+\n+\tif (i->version != MEMIF_VERSION) {\n+\t\tmemif_msg_enq_disconnect(cc, \"Incompatible memif version\", 0);\n+\t\treturn -1;\n+\t}\n+\n+\tif (cc->socket == NULL) {\n+\t\tmemif_msg_enq_disconnect(cc, \"Device error\", 0);\n+\t\treturn -1;\n+\t}\n+\n+\t/* Find device with requested ID */\n+\tTAILQ_FOREACH(elt, &cc->socket->pmd_queue, next) {\n+\t\tpmd = elt->pmd;\n+\t\tif (((pmd->flags & ETH_MEMIF_FLAG_DISABLED) == 0) &&\n+\t\t    pmd->id == i->id) {\n+\t\t\t/* assign control channel to device */\n+\t\t\tcc->pmd = pmd;\n+\t\t\tpmd->cc = cc;\n+\n+\t\t\tif (i->mode != MEMIF_INTERFACE_MODE_ETHERNET) {\n+\t\t\t\tmemif_msg_enq_disconnect(pmd->cc,\n+\t\t\t\t\t\t\t \"Only ethernet mode supported\",\n+\t\t\t\t\t\t\t 0);\n+\t\t\t\treturn -1;\n+\t\t\t}\n+\n+\t\t\tif (pmd->flags && (ETH_MEMIF_FLAG_CONNECTING |\n+\t\t\t\t\t   ETH_MEMIF_FLAG_CONNECTED)) {\n+\t\t\t\tmemif_msg_enq_disconnect(pmd->cc,\n+\t\t\t\t\t\t\t \"Already connected\",\n+\t\t\t\t\t\t\t 0);\n+\t\t\t\treturn -1;\n+\t\t\t}\n+\t\t\tstrlcpy(pmd->remote_name, (char *)i->name,\n+\t\t\t\tsizeof(pmd->remote_name));\n+\n+\t\t\tif (*pmd->secret != '\\0') {\n+\t\t\t\tif (*i->secret == '\\0') {\n+\t\t\t\t\tmemif_msg_enq_disconnect(pmd->cc,\n+\t\t\t\t\t\t\t\t \"Secret required\",\n+\t\t\t\t\t\t\t\t 0);\n+\t\t\t\t\treturn -1;\n+\t\t\t\t}\n+\t\t\t\tif (strcmp(pmd->secret, (char *)i->secret) != 0) {\n+\t\t\t\t\tmemif_msg_enq_disconnect(pmd->cc,\n+\t\t\t\t\t\t\t\t \"Incorrect secret\",\n+\t\t\t\t\t\t\t\t 0);\n+\t\t\t\t\treturn -1;\n+\t\t\t\t}\n+\t\t\t}\n+\n+\t\t\tpmd->flags |= ETH_MEMIF_FLAG_CONNECTING;\n+\t\t\treturn 0;\n+\t\t}\n+\t}\n+\n+\t/* ID not found on this socket */\n+\tMIF_LOG(DEBUG, \"ID %u not found.\", i->id);\n+\tmemif_msg_enq_disconnect(cc, \"ID not found\", 0);\n+\treturn -1;\n+}\n+\n+static int\n+memif_msg_receive_add_region(struct pmd_internals *pmd, memif_msg_t *msg,\n+\t\t\t     int fd)\n+{\n+\tmemif_msg_add_region_t *ar = &msg->add_region;\n+\n+\tif (fd < 0) {\n+\t\tmemif_msg_enq_disconnect(pmd->cc, \"Missing region fd\", 0);\n+\t\treturn -1;\n+\t}\n+\n+\tstruct memif_region *mr;\n+\n+\tif (ar->index > ETH_MEMIF_MAX_REGION_IDX) {\n+\t\tmemif_msg_enq_disconnect(pmd->cc, \"Invalid region index\", 0);\n+\t\treturn -1;\n+\t}\n+\n+\tmr = rte_realloc(pmd->regions, sizeof(struct memif_region) *\n+\t\t\t (ar->index + 1), 0);\n+\tif (mr == NULL) {\n+\t\tmemif_msg_enq_disconnect(pmd->cc, \"Device error\", 0);\n+\t\treturn -1;\n+\t}\n+\n+\tpmd->regions = mr;\n+\tpmd->regions[ar->index].fd = fd;\n+\tpmd->regions[ar->index].region_size = ar->size;\n+\tpmd->regions[ar->index].addr = NULL;\n+\tpmd->regions_num++;\n+\n+\treturn 0;\n+}\n+\n+static int\n+memif_msg_receive_add_ring(struct pmd_internals *pmd, memif_msg_t *msg, int fd)\n+{\n+\tmemif_msg_add_ring_t *ar = &msg->add_ring;\n+\n+\tif (fd < 0) {\n+\t\tmemif_msg_enq_disconnect(pmd->cc, \"Missing interrupt fd\", 0);\n+\t\treturn -1;\n+\t}\n+\n+\tstruct memif_queue *mq;\n+\n+\t/* check if we have enough queues */\n+\tif (ar->flags & MEMIF_MSG_ADD_RING_FLAG_S2M) {\n+\t\tif (ar->index >= pmd->cfg.num_s2m_rings) {\n+\t\t\tmemif_msg_enq_disconnect(pmd->cc, \"Invalid ring index\",\n+\t\t\t\t\t\t 0);\n+\t\t\treturn -1;\n+\t\t}\n+\t\tpmd->run.num_s2m_rings++;\n+\t} else {\n+\t\tif (ar->index >= pmd->cfg.num_m2s_rings) {\n+\t\t\tmemif_msg_enq_disconnect(pmd->cc, \"Invalid ring index\",\n+\t\t\t\t\t\t 0);\n+\t\t\treturn -1;\n+\t\t}\n+\t\tpmd->run.num_m2s_rings++;\n+\t}\n+\n+\tmq = (ar->flags & MEMIF_MSG_ADD_RING_FLAG_S2M) ?\n+\t    &pmd->rx_queues[ar->index] : &pmd->tx_queues[ar->index];\n+\n+\tmq->intr_handle.fd = fd;\n+\tmq->log2_ring_size = ar->log2_ring_size;\n+\tmq->region = ar->region;\n+\tmq->offset = ar->offset;\n+\n+\treturn 0;\n+}\n+\n+static int\n+memif_msg_receive_connect(struct pmd_internals *pmd, memif_msg_t *msg)\n+{\n+\tmemif_msg_connect_t *c = &msg->connect;\n+\tint ret;\n+\n+\tret = memif_connect(pmd);\n+\tif (ret < 0)\n+\t\treturn ret;\n+\n+\tstrlcpy(pmd->remote_if_name, (char *)c->if_name,\n+\t\tsizeof(pmd->remote_if_name));\n+\tMIF_LOG(INFO, \"%s: Remote interface %s connected.\",\n+\t\trte_vdev_device_name(pmd->vdev), pmd->remote_if_name);\n+\n+\treturn 0;\n+}\n+\n+static int\n+memif_msg_receive_connected(struct pmd_internals *pmd, memif_msg_t *msg)\n+{\n+\tmemif_msg_connected_t *c = &msg->connected;\n+\tint ret;\n+\n+\tret = memif_connect(pmd);\n+\tif (ret < 0)\n+\t\treturn ret;\n+\n+\tstrlcpy(pmd->remote_if_name, (char *)c->if_name,\n+\t\tsizeof(pmd->remote_if_name));\n+\tMIF_LOG(INFO, \"%s: Remote interface %s connected.\",\n+\t\trte_vdev_device_name(pmd->vdev), pmd->remote_if_name);\n+\n+\treturn 0;\n+}\n+\n+static int\n+memif_msg_receive_disconnect(struct pmd_internals *pmd, memif_msg_t *msg)\n+{\n+\tmemif_msg_disconnect_t *d = &msg->disconnect;\n+\n+\tmemset(pmd->remote_disc_string, 0, sizeof(pmd->remote_disc_string));\n+\tstrlcpy(pmd->remote_disc_string, (char *)d->string,\n+\t\tsizeof(pmd->remote_disc_string));\n+\n+\tMIF_LOG(INFO, \"%s: Disconnect received: %s\",\n+\t\trte_vdev_device_name(pmd->vdev), pmd->remote_disc_string);\n+\n+\tmemset(pmd->local_disc_string, 0, 96);\n+\tmemif_disconnect(rte_eth_dev_allocated\n+\t\t\t (rte_vdev_device_name(pmd->vdev)));\n+\treturn 0;\n+}\n+\n+static int\n+memif_msg_enq_ack(struct pmd_internals *pmd)\n+{\n+\tstruct memif_msg_queue_elt *e = memif_msg_enq(pmd->cc);\n+\tif (e == NULL)\n+\t\treturn -1;\n+\n+\te->msg.type = MEMIF_MSG_TYPE_ACK;\n+\n+\treturn 0;\n+}\n+\n+static int\n+memif_msg_enq_init(struct pmd_internals *pmd)\n+{\n+\tstruct memif_msg_queue_elt *e = memif_msg_enq(pmd->cc);\n+\tif (e == NULL)\n+\t\treturn -1;\n+\n+\tmemif_msg_init_t *i = &e->msg.init;\n+\n+\te->msg.type = MEMIF_MSG_TYPE_INIT;\n+\ti->version = MEMIF_VERSION;\n+\ti->id = pmd->id;\n+\ti->mode = MEMIF_INTERFACE_MODE_ETHERNET;\n+\n+\tstrlcpy((char *)i->name, rte_version(), sizeof(i->name));\n+\n+\tif (pmd->secret)\n+\t\tstrlcpy((char *)i->secret, pmd->secret, sizeof(i->secret));\n+\n+\treturn 0;\n+}\n+\n+static int\n+memif_msg_enq_add_region(struct pmd_internals *pmd, uint8_t idx)\n+{\n+\tstruct memif_msg_queue_elt *e = memif_msg_enq(pmd->cc);\n+\tif (e == NULL)\n+\t\treturn -1;\n+\n+\tmemif_msg_add_region_t *ar = &e->msg.add_region;\n+\tstruct memif_region *mr = &pmd->regions[idx];\n+\n+\te->msg.type = MEMIF_MSG_TYPE_ADD_REGION;\n+\te->fd = mr->fd;\n+\tar->index = idx;\n+\tar->size = mr->region_size;\n+\n+\treturn 0;\n+}\n+\n+static int\n+memif_msg_enq_add_ring(struct pmd_internals *pmd, uint8_t idx,\n+\t\t       memif_ring_type_t type)\n+{\n+\tstruct memif_msg_queue_elt *e = memif_msg_enq(pmd->cc);\n+\tif (e == NULL)\n+\t\treturn -1;\n+\n+\tmemif_msg_add_ring_t *ar = &e->msg.add_ring;\n+\tstruct memif_queue *mq;\n+\n+\tmq = (type == MEMIF_RING_S2M) ? &pmd->tx_queues[idx] :\n+\t    &pmd->rx_queues[idx];\n+\n+\te->msg.type = MEMIF_MSG_TYPE_ADD_RING;\n+\te->fd = mq->intr_handle.fd;\n+\tar->index = idx;\n+\tar->offset = mq->offset;\n+\tar->region = mq->region;\n+\tar->log2_ring_size = mq->log2_ring_size;\n+\tar->flags = (type == MEMIF_RING_S2M) ? MEMIF_MSG_ADD_RING_FLAG_S2M : 0;\n+\tar->private_hdr_size = 0;\n+\n+\treturn 0;\n+}\n+\n+static int\n+memif_msg_enq_connect(struct pmd_internals *pmd)\n+{\n+\tstruct memif_msg_queue_elt *e = memif_msg_enq(pmd->cc);\n+\tif (e == NULL)\n+\t\treturn -1;\n+\n+\tmemif_msg_connect_t *c = &e->msg.connect;\n+\tconst char *name = rte_vdev_device_name(pmd->vdev);\n+\n+\te->msg.type = MEMIF_MSG_TYPE_CONNECT;\n+\tstrlcpy((char *)c->if_name, name, sizeof(c->if_name));\n+\n+\treturn 0;\n+}\n+\n+static int\n+memif_msg_enq_connected(struct pmd_internals *pmd)\n+{\n+\tstruct memif_msg_queue_elt *e = memif_msg_enq(pmd->cc);\n+\tif (e == NULL)\n+\t\treturn -1;\n+\n+\tmemif_msg_connected_t *c = &e->msg.connected;\n+\n+\tconst char *name = rte_vdev_device_name(pmd->vdev);\n+\n+\te->msg.type = MEMIF_MSG_TYPE_CONNECTED;\n+\tstrlcpy((char *)c->if_name, name, sizeof(c->if_name));\n+\n+\treturn 0;\n+}\n+\n+static void\n+memif_intr_unregister_handler(struct rte_intr_handle *intr_handle, void *arg)\n+{\n+\tstruct memif_msg_queue_elt *elt;\n+\tstruct memif_control_channel *cc = arg;\n+\t/* close control channel fd */\n+\tclose(intr_handle->fd);\n+\t/* clear message queue */\n+\twhile ((elt = TAILQ_FIRST(&cc->msg_queue)) != NULL) {\n+\t\tTAILQ_REMOVE(&cc->msg_queue, elt, next);\n+\t\tfree(elt);\n+\t}\n+\t/* free control channel */\n+\trte_free(cc);\n+}\n+\n+void\n+memif_disconnect(struct rte_eth_dev *dev)\n+{\n+\tstruct pmd_internals *pmd = dev->data->dev_private;\n+\tstruct memif_msg_queue_elt *elt;\n+\tint i;\n+\tint ret;\n+\n+\tif (pmd->cc != NULL) {\n+\t\t/* Clear control message queue (except disconnect message if any). */\n+\t\twhile ((elt = TAILQ_FIRST(&pmd->cc->msg_queue)) != NULL) {\n+\t\t\tif (elt->msg.type != MEMIF_MSG_TYPE_DISCONNECT) {\n+\t\t\t\tTAILQ_REMOVE(&pmd->cc->msg_queue, elt, next);\n+\t\t\t\tfree(elt);\n+\t\t\t}\n+\t\t}\n+\t\t/* send disconnect message (if there is any in queue) */\n+\t\tmemif_msg_send_from_queue(pmd->cc);\n+\n+\t\t/* at this point, there should be no more messages in queue */\n+\t\tif (TAILQ_FIRST(&pmd->cc->msg_queue) != NULL) {\n+\t\t\tMIF_LOG(WARNING,\n+\t\t\t\t\"%s: Unexpected message(s) in message queue.\",\n+\t\t\t\trte_vdev_device_name(pmd->vdev));\n+\t\t}\n+\n+\t\tif (pmd->cc->intr_handle.fd > 0) {\n+\t\t\tret =\n+\t\t\t    rte_intr_callback_unregister(&pmd->cc->intr_handle,\n+\t\t\t\t\t\t\t memif_intr_handler,\n+\t\t\t\t\t\t\t pmd->cc);\n+\t\t\t/*\n+\t\t\t * If callback is active (disconnecting based on\n+\t\t\t * received control message).\n+\t\t\t */\n+\t\t\tif (ret == -EAGAIN) {\n+\t\t\t\tret =\n+\t\t\t\t    rte_intr_callback_unregister_pending(&pmd->\n+\t\t\t\t\t\t\tcc->intr_handle,\n+\t\t\t\t\t\t\tmemif_intr_handler,\n+\t\t\t\t\t\t\tpmd->cc,\n+\t\t\t\t\t\t\tmemif_intr_unregister_handler);\n+\t\t\t} else if (ret > 0) {\n+\t\t\t\tclose(pmd->cc->intr_handle.fd);\n+\t\t\t\trte_free(pmd->cc);\n+\t\t\t}\n+\t\t\tif (ret <= 0)\n+\t\t\t\tMIF_LOG(WARNING,\n+\t\t\t\t\t\"%s: Failed to unregister control channel callback.\",\n+\t\t\t\t\trte_vdev_device_name(pmd->vdev));\n+\t\t}\n+\t}\n+\n+\t/* unconfig interrupts */\n+\tstruct memif_queue *mq;\n+\tfor (i = 0; i < pmd->cfg.num_s2m_rings; i++) {\n+\t\tmq = (pmd->role == MEMIF_ROLE_SLAVE) ?\n+\t\t    &pmd->tx_queues[i] : &pmd->rx_queues[i];\n+\t\tif (mq->intr_handle.fd > 0) {\n+\t\t\trte_intr_disable(&mq->intr_handle);\n+\t\t\tclose(mq->intr_handle.fd);\n+\t\t\tmq->intr_handle.fd = -1;\n+\t\t}\n+\t\tmq->ring = NULL;\n+\t}\n+\tfor (i = 0; i < pmd->cfg.num_m2s_rings; i++) {\n+\t\tmq = (pmd->role == MEMIF_ROLE_SLAVE) ?\n+\t\t    &pmd->rx_queues[i] : &pmd->tx_queues[i];\n+\t\tif (mq->intr_handle.fd > 0) {\n+\t\t\trte_intr_disable(&mq->intr_handle);\n+\t\t\tclose(mq->intr_handle.fd);\n+\t\t\tmq->intr_handle.fd = -1;\n+\t\t}\n+\t\tmq->ring = NULL;\n+\t}\n+\n+\tmemif_free_regions(pmd);\n+\n+\tdev->data->dev_link.link_status = ETH_LINK_DOWN;\n+\tpmd->flags &= ~ETH_MEMIF_FLAG_CONNECTING;\n+\tpmd->flags &= ~ETH_MEMIF_FLAG_CONNECTED;\n+\tMIF_LOG(DEBUG, \"%s: Disconnected.\", rte_vdev_device_name(pmd->vdev));\n+}\n+\n+static int\n+memif_msg_receive(struct memif_control_channel *cc)\n+{\n+\tchar ctl[CMSG_SPACE(sizeof(int)) +\n+\t\t CMSG_SPACE(sizeof(struct ucred))] = { 0 };\n+\tstruct msghdr mh = { 0 };\n+\tstruct iovec iov[1];\n+\tmemif_msg_t msg = { 0 };\n+\tssize_t size;\n+\tint ret = 0;\n+\tstruct ucred *cr __rte_unused;\n+\tcr = 0;\n+\tstruct cmsghdr *cmsg;\n+\tint afd = -1;\n+\tint i;\n+\n+\tiov[0].iov_base = (void *)&msg;\n+\tiov[0].iov_len = sizeof(memif_msg_t);\n+\tmh.msg_iov = iov;\n+\tmh.msg_iovlen = 1;\n+\tmh.msg_control = ctl;\n+\tmh.msg_controllen = sizeof(ctl);\n+\n+\tsize = recvmsg(cc->intr_handle.fd, &mh, 0);\n+\tif (size != sizeof(memif_msg_t)) {\n+\t\tMIF_LOG(DEBUG, \"Invalid message size.\");\n+\t\tmemif_msg_enq_disconnect(cc, \"Invalid message size\", 0);\n+\t\treturn -1;\n+\t}\n+\tMIF_LOG(DEBUG, \"Received msg type: %u.\", msg.type);\n+\n+\tcmsg = CMSG_FIRSTHDR(&mh);\n+\twhile (cmsg) {\n+\t\tif (cmsg->cmsg_level == SOL_SOCKET) {\n+\t\t\tif (cmsg->cmsg_type == SCM_CREDENTIALS)\n+\t\t\t\tcr = (struct ucred *)CMSG_DATA(cmsg);\n+\t\t\telse if (cmsg->cmsg_type == SCM_RIGHTS)\n+\t\t\t\tafd = *(int *)CMSG_DATA(cmsg);\n+\t\t}\n+\t\tcmsg = CMSG_NXTHDR(&mh, cmsg);\n+\t}\n+\n+\tif (cc->pmd == NULL && msg.type != MEMIF_MSG_TYPE_INIT) {\n+\t\tMIF_LOG(DEBUG, \"Unexpected message.\");\n+\t\tmemif_msg_enq_disconnect(cc, \"Unexpected message\", 0);\n+\t\treturn -1;\n+\t}\n+\n+\t/* get device from hash data */\n+\tswitch (msg.type) {\n+\tcase MEMIF_MSG_TYPE_ACK:\n+\t\tbreak;\n+\tcase MEMIF_MSG_TYPE_HELLO:\n+\t\tret = memif_msg_receive_hello(cc->pmd, &msg);\n+\t\tif (ret < 0)\n+\t\t\tgoto exit;\n+\t\tret = memif_init_regions_and_queues(cc->pmd);\n+\t\tif (ret < 0)\n+\t\t\tgoto exit;\n+\t\tret = memif_msg_enq_init(cc->pmd);\n+\t\tif (ret < 0)\n+\t\t\tgoto exit;\n+\t\tfor (i = 0; i < cc->pmd->regions_num; i++) {\n+\t\t\tret = memif_msg_enq_add_region(cc->pmd, i);\n+\t\t\tif (ret < 0)\n+\t\t\t\tgoto exit;\n+\t\t}\n+\t\tfor (i = 0; i < cc->pmd->run.num_s2m_rings; i++) {\n+\t\t\tret = memif_msg_enq_add_ring(cc->pmd, i,\n+\t\t\t\t\t\t     MEMIF_RING_S2M);\n+\t\t\tif (ret < 0)\n+\t\t\t\tgoto exit;\n+\t\t}\n+\t\tfor (i = 0; i < cc->pmd->run.num_m2s_rings; i++) {\n+\t\t\tret = memif_msg_enq_add_ring(cc->pmd, i,\n+\t\t\t\t\t\t     MEMIF_RING_M2S);\n+\t\t\tif (ret < 0)\n+\t\t\t\tgoto exit;\n+\t\t}\n+\t\tret = memif_msg_enq_connect(cc->pmd);\n+\t\tif (ret < 0)\n+\t\t\tgoto exit;\n+\t\tbreak;\n+\tcase MEMIF_MSG_TYPE_INIT:\n+\t\tret = memif_msg_receive_init(cc, &msg);\n+\t\tif (ret < 0)\n+\t\t\tgoto exit;\n+\t\tret = memif_msg_enq_ack(cc->pmd);\n+\t\tif (ret < 0)\n+\t\t\tgoto exit;\n+\t\tbreak;\n+\tcase MEMIF_MSG_TYPE_ADD_REGION:\n+\t\tret = memif_msg_receive_add_region(cc->pmd, &msg, afd);\n+\t\tif (ret < 0)\n+\t\t\tgoto exit;\n+\t\tret = memif_msg_enq_ack(cc->pmd);\n+\t\tif (ret < 0)\n+\t\t\tgoto exit;\n+\t\tbreak;\n+\tcase MEMIF_MSG_TYPE_ADD_RING:\n+\t\tret = memif_msg_receive_add_ring(cc->pmd, &msg, afd);\n+\t\tif (ret < 0)\n+\t\t\tgoto exit;\n+\t\tret = memif_msg_enq_ack(cc->pmd);\n+\t\tif (ret < 0)\n+\t\t\tgoto exit;\n+\t\tbreak;\n+\tcase MEMIF_MSG_TYPE_CONNECT:\n+\t\tret = memif_msg_receive_connect(cc->pmd, &msg);\n+\t\tif (ret < 0)\n+\t\t\tgoto exit;\n+\t\tret = memif_msg_enq_connected(cc->pmd);\n+\t\tif (ret < 0)\n+\t\t\tgoto exit;\n+\t\tbreak;\n+\tcase MEMIF_MSG_TYPE_CONNECTED:\n+\t\tret = memif_msg_receive_connected(cc->pmd, &msg);\n+\t\tbreak;\n+\tcase MEMIF_MSG_TYPE_DISCONNECT:\n+\t\tret = memif_msg_receive_disconnect(cc->pmd, &msg);\n+\t\tif (ret < 0)\n+\t\t\tgoto exit;\n+\t\tbreak;\n+\tdefault:\n+\t\tmemif_msg_enq_disconnect(cc, \"Unknown message type\", 0);\n+\t\tret = -1;\n+\t\tgoto exit;\n+\t}\n+\n+ exit:\n+\treturn ret;\n+}\n+\n+static void\n+memif_intr_handler(void *arg)\n+{\n+\tstruct memif_control_channel *cc = arg;\n+\tstruct rte_eth_dev *dev;\n+\tint ret;\n+\n+\tret = memif_msg_receive(cc);\n+\t/* if driver failed to assign device */\n+\tif (cc->pmd == NULL) {\n+\t\tret = rte_intr_callback_unregister_pending(&cc->intr_handle,\n+\t\t\t\t\t\t\t   memif_intr_handler,\n+\t\t\t\t\t\t\t   cc,\n+\t\t\t\t\t\t\t   memif_intr_unregister_handler);\n+\t\tif (ret < 0)\n+\t\t\tMIF_LOG(WARNING,\n+\t\t\t\t\"Failed to unregister control channel callback.\");\n+\t\treturn;\n+\t}\n+\t/* if memif_msg_receive failed */\n+\tif (ret < 0)\n+\t\tgoto disconnect;\n+\n+\tret = memif_msg_send_from_queue(cc);\n+\tif (ret < 0)\n+\t\tgoto disconnect;\n+\n+\treturn;\n+\n+ disconnect:\n+\tdev = rte_eth_dev_allocated(rte_vdev_device_name(cc->pmd->vdev));\n+\tif (dev == NULL) {\n+\t\tMIF_LOG(WARNING, \"%s: eth dev not allocated\",\n+\t\t\trte_vdev_device_name(cc->pmd->vdev));\n+\t\treturn;\n+\t}\n+\tmemif_disconnect(dev);\n+}\n+\n+static void\n+memif_listener_handler(void *arg)\n+{\n+\tstruct memif_socket *socket = arg;\n+\tint sockfd;\n+\tint addr_len;\n+\tstruct sockaddr_un client;\n+\tstruct memif_control_channel *cc;\n+\tint ret;\n+\n+\taddr_len = sizeof(client);\n+\tsockfd = accept(socket->intr_handle.fd, (struct sockaddr *)&client,\n+\t\t\t(socklen_t *)&addr_len);\n+\tif (sockfd < 0) {\n+\t\tMIF_LOG(ERR,\n+\t\t\t\"Failed to accept connection request on socket fd %d\",\n+\t\t\tsocket->intr_handle.fd);\n+\t\treturn;\n+\t}\n+\n+\tMIF_LOG(DEBUG, \"%s: Connection request accepted.\", socket->filename);\n+\n+\tcc = rte_zmalloc(\"memif-cc\", sizeof(struct memif_control_channel), 0);\n+\tif (cc == NULL) {\n+\t\tMIF_LOG(ERR, \"Failed to allocate control channel.\");\n+\t\tgoto error;\n+\t}\n+\n+\tcc->intr_handle.fd = sockfd;\n+\tcc->intr_handle.type = RTE_INTR_HANDLE_EXT;\n+\tcc->socket = socket;\n+\tcc->pmd = NULL;\n+\tTAILQ_INIT(&cc->msg_queue);\n+\n+\tret =\n+\t    rte_intr_callback_register(&cc->intr_handle, memif_intr_handler,\n+\t\t\t\t       cc);\n+\tif (ret < 0) {\n+\t\tMIF_LOG(ERR, \"Failed to register control channel callback.\");\n+\t\tgoto error;\n+\t}\n+\n+\tret = memif_msg_enq_hello(cc);\n+\tif (ret < 0) {\n+\t\tMIF_LOG(ERR, \"Failed to enqueue hello message.\");\n+\t\tgoto error;\n+\t}\n+\tret = memif_msg_send_from_queue(cc);\n+\tif (ret < 0)\n+\t\tgoto error;\n+\n+\treturn;\n+\n+ error:\n+\tif (sockfd > 0) {\n+\t\tclose(sockfd);\n+\t\tsockfd = -1;\n+\t}\n+\tif (cc != NULL) {\n+\t\trte_free(cc);\n+\t\tcc = NULL;\n+\t}\n+}\n+\n+static struct memif_socket *\n+memif_socket_create(struct pmd_internals *pmd, char *key, uint8_t listener)\n+{\n+\tstruct memif_socket *sock;\n+\tstruct sockaddr_un un;\n+\tint sockfd;\n+\tint ret;\n+\tint on = 1;\n+\n+\tsock = rte_zmalloc(\"memif-socket\", sizeof(struct memif_socket), 0);\n+\tif (sock == NULL) {\n+\t\tMIF_LOG(ERR, \"Failed to allocate memory for memif socket\");\n+\t\treturn NULL;\n+\t}\n+\n+\tsock->listener = listener;\n+\trte_memcpy(sock->filename, key, 256);\n+\tTAILQ_INIT(&sock->pmd_queue);\n+\n+\tif (listener != 0) {\n+\t\tsockfd = socket(AF_UNIX, SOCK_SEQPACKET, 0);\n+\t\tif (sockfd < 0)\n+\t\t\tgoto error;\n+\n+\t\tun.sun_family = AF_UNIX;\n+\t\tmemcpy(un.sun_path, sock->filename,\n+\t\t\tsizeof(un.sun_path) - 1);\n+\n+\t\tret = setsockopt(sockfd, SOL_SOCKET, SO_PASSCRED, &on,\n+\t\t\t\t sizeof(on));\n+\t\tif (ret < 0)\n+\t\t\tgoto error;\n+\t\tret = bind(sockfd, (struct sockaddr *)&un, sizeof(un));\n+\t\tif (ret < 0)\n+\t\t\tgoto error;\n+\t\tret = listen(sockfd, 1);\n+\t\tif (ret < 0)\n+\t\t\tgoto error;\n+\n+\t\tMIF_LOG(DEBUG, \"%s: Memif listener socket %s created.\",\n+\t\t\trte_vdev_device_name(pmd->vdev), sock->filename);\n+\n+\t\tsock->intr_handle.fd = sockfd;\n+\t\tsock->intr_handle.type = RTE_INTR_HANDLE_EXT;\n+\t\tret = rte_intr_callback_register(&sock->intr_handle,\n+\t\t\t\t\t\t memif_listener_handler, sock);\n+\t\tif (ret < 0) {\n+\t\t\tMIF_LOG(ERR, \"%s: Failed to register interrupt \"\n+\t\t\t\t\"callback for listener socket\",\n+\t\t\t\trte_vdev_device_name(pmd->vdev));\n+\t\t\treturn NULL;\n+\t\t}\n+\t}\n+\n+\treturn sock;\n+\n+ error:\n+\tMIF_LOG(ERR, \"%s: Failed to setup socket %s: %s\",\n+\t\trte_vdev_device_name(pmd->vdev), key, strerror(errno));\n+\tif (sock != NULL)\n+\t\trte_free(sock);\n+\treturn NULL;\n+}\n+\n+static struct rte_hash *\n+memif_create_socket_hash(void)\n+{\n+\tstruct rte_hash_parameters params = { 0 };\n+\tparams.name = MEMIF_SOCKET_HASH_NAME;\n+\tparams.entries = 256;\n+\tparams.key_len = 256;\n+\tparams.hash_func = rte_jhash;\n+\tparams.hash_func_init_val = 0;\n+\treturn rte_hash_create(&params);\n+}\n+\n+int\n+memif_socket_init(struct rte_eth_dev *dev, const char *socket_filename)\n+{\n+\tstruct pmd_internals *pmd = dev->data->dev_private;\n+\tstruct memif_socket *socket = NULL;\n+\tstruct memif_socket_pmd_list_elt *elt;\n+\tint ret;\n+\tchar key[256];\n+\n+\tstruct rte_hash *hash = rte_hash_find_existing(MEMIF_SOCKET_HASH_NAME);\n+\tif (hash == NULL) {\n+\t\thash = memif_create_socket_hash();\n+\t\tif (hash == NULL) {\n+\t\t\tMIF_LOG(ERR, \"Failed to create memif socket hash.\");\n+\t\t\treturn -1;\n+\t\t}\n+\t}\n+\n+\tmemset(key, 0, 256);\n+\trte_memcpy(key, socket_filename, strlen(socket_filename));\n+\tret = rte_hash_lookup_data(hash, key, (void **)&socket);\n+\tif (ret < 0) {\n+\t\tsocket = memif_socket_create(pmd, key,\n+\t\t\t\t\t     (pmd->role ==\n+\t\t\t\t\t      MEMIF_ROLE_SLAVE) ? 0 : 1);\n+\t\tif (socket == NULL)\n+\t\t\treturn -1;\n+\t\tret = rte_hash_add_key_data(hash, key, socket);\n+\t\tif (ret < 0) {\n+\t\t\tMIF_LOG(ERR, \"Failed to add socket to socket hash.\");\n+\t\t\treturn ret;\n+\t\t}\n+\t}\n+\tpmd->socket_filename = socket->filename;\n+\n+\tif (socket->listener != 0 && pmd->role == MEMIF_ROLE_SLAVE) {\n+\t\tMIF_LOG(ERR, \"Socket is a listener.\");\n+\t\treturn -1;\n+\t} else if ((socket->listener == 0) && (pmd->role == MEMIF_ROLE_MASTER)) {\n+\t\tMIF_LOG(ERR, \"Socket is not a listener.\");\n+\t\treturn -1;\n+\t}\n+\n+\tTAILQ_FOREACH(elt, &socket->pmd_queue, next) {\n+\t\tif (elt->pmd->id == pmd->id) {\n+\t\t\tMIF_LOG(ERR, \"Memif device with id %d already \"\n+\t\t\t\t\"exists on socket %s\",\n+\t\t\t\tpmd->id, socket->filename);\n+\t\t\treturn -1;\n+\t\t}\n+\t}\n+\n+\telt =\n+\t    rte_malloc(\"pmd-queue\", sizeof(struct memif_socket_pmd_list_elt),\n+\t\t       0);\n+\tif (elt == NULL) {\n+\t\tMIF_LOG(ERR, \"%s: Failed to add device to socket device list.\",\n+\t\t\trte_vdev_device_name(pmd->vdev));\n+\t\treturn -1;\n+\t}\n+\telt->pmd = pmd;\n+\tTAILQ_INSERT_TAIL(&socket->pmd_queue, elt, next);\n+\n+\treturn 0;\n+}\n+\n+void\n+memif_socket_remove_device(struct pmd_internals *pmd)\n+{\n+\tstruct memif_socket *socket = NULL;\n+\tstruct memif_socket_pmd_list_elt *elt, *next;\n+\n+\tstruct rte_hash *hash = rte_hash_find_existing(MEMIF_SOCKET_HASH_NAME);\n+\tif (hash == NULL)\n+\t\treturn;\n+\n+\tif (rte_hash_lookup_data(hash, pmd->socket_filename, (void **)&socket) <\n+\t    0)\n+\t\treturn;\n+\n+\tfor (elt = TAILQ_FIRST(&socket->pmd_queue); elt != NULL; elt = next) {\n+\t\tnext = TAILQ_NEXT(elt, next);\n+\t\tif (elt->pmd == pmd) {\n+\t\t\tTAILQ_REMOVE(&socket->pmd_queue, elt, next);\n+\t\t\tfree(elt);\n+\t\t\tpmd->socket_filename = NULL;\n+\t\t}\n+\t}\n+\n+\t/* remove socket, if this was the last device using it */\n+\tif (TAILQ_EMPTY(&socket->pmd_queue)) {\n+\t\trte_hash_del_key(hash, socket->filename);\n+\t\tif (socket->listener) {\n+\t\t\t/* remove listener socket file,\n+\t\t\t * so we can create new one later.\n+\t\t\t */\n+\t\t\tremove(socket->filename);\n+\t\t}\n+\t\trte_free(socket);\n+\t}\n+}\n+\n+int\n+memif_connect_master(struct rte_eth_dev *dev)\n+{\n+\tstruct pmd_internals *pmd = dev->data->dev_private;\n+\tif (pmd->rx_queues == NULL || pmd->tx_queues == NULL ||\n+\t    pmd->socket_filename == NULL) {\n+\t\tMIF_LOG(ERR, \"%s: Device not configured!\",\n+\t\t\trte_vdev_device_name(pmd->vdev));\n+\t\treturn -1;\n+\t}\n+\tmemset(pmd->local_disc_string, 0, 96);\n+\tmemset(pmd->remote_disc_string, 0, 96);\n+\tpmd->flags &= ~ETH_MEMIF_FLAG_DISABLED;\n+\treturn 0;\n+}\n+\n+int\n+memif_connect_slave(struct rte_eth_dev *dev)\n+{\n+\tint sockfd;\n+\tint ret;\n+\tstruct sockaddr_un sun;\n+\tstruct pmd_internals *pmd = dev->data->dev_private;\n+\n+\tif (pmd->rx_queues == NULL || pmd->tx_queues == NULL ||\n+\t    pmd->socket_filename == NULL) {\n+\t\tMIF_LOG(ERR, \"%s: Device not configured!\",\n+\t\t\trte_vdev_device_name(pmd->vdev));\n+\t\treturn -1;\n+\t}\n+\n+\tmemset(pmd->local_disc_string, 0, 96);\n+\tmemset(pmd->remote_disc_string, 0, 96);\n+\tpmd->flags &= ~ETH_MEMIF_FLAG_DISABLED;\n+\n+\tsockfd = socket(AF_UNIX, SOCK_SEQPACKET, 0);\n+\tif (sockfd < 0) {\n+\t\tMIF_LOG(ERR, \"%s: Failed to open socket.\",\n+\t\t\trte_vdev_device_name(pmd->vdev));\n+\t\treturn -1;\n+\t}\n+\n+\tsun.sun_family = AF_UNIX;\n+\n+\tmemcpy(sun.sun_path, pmd->socket_filename, sizeof(sun.sun_path) - 1);\n+\n+\tret = connect(sockfd, (struct sockaddr *)&sun,\n+\t\t      sizeof(struct sockaddr_un));\n+\tif (ret < 0) {\n+\t\tMIF_LOG(ERR, \"%s: Failed to connect socket: %s.\",\n+\t\t\trte_vdev_device_name(pmd->vdev), pmd->socket_filename);\n+\t\tgoto error;\n+\t}\n+\n+\tMIF_LOG(DEBUG, \"%s: Memif socket: %s connected.\",\n+\t\trte_vdev_device_name(pmd->vdev), pmd->socket_filename);\n+\n+\tpmd->cc = rte_zmalloc(\"memif-cc\",\n+\t\t\t      sizeof(struct memif_control_channel), 0);\n+\tif (pmd->cc == NULL) {\n+\t\tMIF_LOG(ERR, \"%s: Failed to allocate control channel.\",\n+\t\t\trte_vdev_device_name(pmd->vdev));\n+\t\tgoto error;\n+\t}\n+\n+\tpmd->cc->intr_handle.fd = sockfd;\n+\tpmd->cc->intr_handle.type = RTE_INTR_HANDLE_EXT;\n+\tpmd->cc->socket = NULL;\n+\tpmd->cc->pmd = pmd;\n+\tTAILQ_INIT(&pmd->cc->msg_queue);\n+\n+\tret = rte_intr_callback_register(&pmd->cc->intr_handle,\n+\t\t\t\t\t memif_intr_handler, pmd->cc);\n+\tif (ret < 0) {\n+\t\tMIF_LOG(ERR, \"%s: Failed to register interrupt callback \"\n+\t\t\t\"for controll fd\", rte_vdev_device_name(pmd->vdev));\n+\t\tgoto error;\n+\t}\n+\n+\treturn 0;\n+\n+ error:\n+\tif (sockfd > 0) {\n+\t\tclose(sockfd);\n+\t\tsockfd = -1;\n+\t}\n+\tif (pmd->cc != NULL) {\n+\t\trte_free(pmd->cc);\n+\t\tpmd->cc = NULL;\n+\t}\n+\treturn -1;\n+}\ndiff --git a/drivers/net/memif/memif_socket.h b/drivers/net/memif/memif_socket.h\nnew file mode 100644\nindex 000000000..e67009404\n--- /dev/null\n+++ b/drivers/net/memif/memif_socket.h\n@@ -0,0 +1,104 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright 2018 Cisco Systems, Inc.  All rights reserved.\n+ */\n+\n+#ifndef _MEMIF_SOCKET_H_\n+#define _MEMIF_SOCKET_H_\n+\n+#include <sys/queue.h>\n+\n+/**\n+ * Remove device from socket device list. If no device is left on the socket,\n+ * remove the socket as well.\n+ *\n+ * @param pmd\n+ *   device internals\n+ */\n+void memif_socket_remove_device(struct pmd_internals *pmd);\n+\n+/**\n+ * Enqueue disconnect message to control channel message queue.\n+ *\n+ * @param cc\n+ *   control channel\n+ * @param reason\n+ *   const string stating disconnect reason (96 characters)\n+ * @param err_code\n+ *   error code\n+ */\n+void memif_msg_enq_disconnect(struct memif_control_channel *cc, const char *reason,\n+\t\t\t      int err_code);\n+\n+/**\n+ * Initialize memif socket for specified device. If socket doesn't exist, create socket.\n+ *\n+ * @param dev\n+ *   memif ethernet device\n+ * @param socket_filename\n+ *   socket filename\n+ * @return\n+ *   - On success, zero.\n+ *   - On failure, a negative value.\n+ */\n+int memif_socket_init(struct rte_eth_dev *dev, const char *socket_filename);\n+\n+/**\n+ * Disconnect memif device. Close control channel and shared memory.\n+ *\n+ * @param dev\n+ *   ethernet device\n+ */\n+void memif_disconnect(struct rte_eth_dev *dev);\n+\n+/**\n+ * If device is properly configured, enable connection establishment.\n+ *\n+ * @param dev\n+ *   memif ethernet device\n+ * @return\n+ *   - On success, zero.\n+ *   - On failure, a negative value.\n+ */\n+int memif_connect_master(struct rte_eth_dev *dev);\n+\n+/**\n+ * If device is properly configured, send connection request.\n+ *\n+ * @param dev\n+ *   memif ethernet device\n+ * @return\n+ *   - On success, zero.\n+ *   - On failure, a negative value.\n+ */\n+int memif_connect_slave(struct rte_eth_dev *dev);\n+\n+struct memif_socket_pmd_list_elt {\n+\tTAILQ_ENTRY(memif_socket_pmd_list_elt) next;\n+\tstruct pmd_internals *pmd;\t\t/**< pointer to device internals */\n+};\n+\n+#define MEMIF_SOCKET_HASH_NAME\t\t\t\"memif-sh\"\n+struct memif_socket {\n+\tstruct rte_intr_handle intr_handle;\t/**< interrupt handle */\n+\tuint8_t listener;\t\t\t/**< if not zero socket is listener */\n+\tchar filename[256];\t\t\t/**< socket filename */\n+\n+\tTAILQ_HEAD(, memif_socket_pmd_list_elt) pmd_queue;\n+\t/**< Queue of devices using this socket */\n+};\n+\n+/* Control message queue. */\n+struct memif_msg_queue_elt {\n+\tTAILQ_ENTRY(memif_msg_queue_elt) next;\n+\tmemif_msg_t msg;\t\t\t/**< control message */\n+\tint fd;\t\t\t\t\t/**< fd to be sent to peer */\n+};\n+\n+struct memif_control_channel {\n+\tstruct rte_intr_handle intr_handle;\t/**< interrupt handle */\n+\t TAILQ_HEAD(, memif_msg_queue_elt) msg_queue; /**< control message queue */\n+\tstruct memif_socket *socket;\t\t/**< pointer to socket */\n+\tstruct pmd_internals *pmd;\t\t/**< pointer to device internals */\n+};\n+\n+#endif\t\t\t\t/* MEMIF_SOCKET_H */\ndiff --git a/drivers/net/memif/meson.build b/drivers/net/memif/meson.build\nnew file mode 100644\nindex 000000000..a6f6ea8bc\n--- /dev/null\n+++ b/drivers/net/memif/meson.build\n@@ -0,0 +1,10 @@\n+# SPDX-License-Identifier: BSD-3-Clause\n+# Copyright 2018 Cisco Systems, Inc.  All rights reserved.\n+\n+if host_machine.system() != 'linux'\n+        build = false\n+endif\n+sources = files('rte_eth_memif.c',\n+\t\t'memif_socket.c')\n+\n+deps += ['hash']\ndiff --git a/drivers/net/memif/rte_eth_memif.c b/drivers/net/memif/rte_eth_memif.c\nnew file mode 100644\nindex 000000000..5540b10cc\n--- /dev/null\n+++ b/drivers/net/memif/rte_eth_memif.c\n@@ -0,0 +1,1189 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright 2018 Cisco Systems, Inc.  All rights reserved.\n+ */\n+\n+#include <stdlib.h>\n+#include <fcntl.h>\n+#include <unistd.h>\n+#include <sys/types.h>\n+#include <sys/socket.h>\n+#include <sys/un.h>\n+#include <sys/ioctl.h>\n+#include <sys/mman.h>\n+#include <linux/if_ether.h>\n+#include <errno.h>\n+#include <sys/eventfd.h>\n+\n+#include <rte_version.h>\n+#include <rte_mbuf.h>\n+#include <rte_ether.h>\n+#include <rte_ethdev_driver.h>\n+#include <rte_ethdev_vdev.h>\n+#include <rte_malloc.h>\n+#include <rte_kvargs.h>\n+#include <rte_bus_vdev.h>\n+#include <rte_string_fns.h>\n+\n+#include <rte_eth_memif.h>\n+#include <memif_socket.h>\n+\n+#define ETH_MEMIF_ID_ARG\t\t\"id\"\n+#define ETH_MEMIF_ROLE_ARG\t\t\"role\"\n+#define ETH_MEMIF_BUFFER_SIZE_ARG\t\"bsize\"\n+#define ETH_MEMIF_RING_SIZE_ARG\t\t\"rsize\"\n+#define ETH_MEMIF_NRXQ_ARG\t\t\"nrxq\"\n+#define ETH_MEMIF_NTXQ_ARG\t\t\"ntxq\"\n+#define ETH_MEMIF_SOCKET_ARG\t\t\"socket\"\n+#define ETH_MEMIF_MAC_ARG\t\t\"mac\"\n+#define ETH_MEMIF_ZC_ARG\t\t\"zero-copy\"\n+#define ETH_MEMIF_SECRET_ARG\t\t\"secret\"\n+\n+static const char *valid_arguments[] = {\n+\tETH_MEMIF_ID_ARG,\n+\tETH_MEMIF_ROLE_ARG,\n+\tETH_MEMIF_BUFFER_SIZE_ARG,\n+\tETH_MEMIF_RING_SIZE_ARG,\n+\tETH_MEMIF_NRXQ_ARG,\n+\tETH_MEMIF_NTXQ_ARG,\n+\tETH_MEMIF_SOCKET_ARG,\n+\tETH_MEMIF_MAC_ARG,\n+\tETH_MEMIF_ZC_ARG,\n+\tETH_MEMIF_SECRET_ARG,\n+\tNULL\n+};\n+\n+static struct rte_vdev_driver pmd_memif_drv;\n+\n+const char *\n+memif_version(void)\n+{\n+#define STR_HELP(s)\t#s\n+#define STR(s)\t\tSTR_HELP(s)\n+\treturn (\"memif-\" STR(MEMIF_VERSION_MAJOR) \".\" STR(MEMIF_VERSION_MINOR));\n+#undef STR\n+#undef STR_HELP\n+}\n+\n+static void\n+memif_dev_info(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)\n+{\n+\tstruct pmd_internals *pmd = dev->data->dev_private;\n+\n+\tdev_info->if_index = pmd->if_index;\n+\tdev_info->max_mac_addrs = 1;\n+\tdev_info->max_rx_pktlen = (uint32_t)ETH_FRAME_LEN;\n+\tdev_info->max_rx_queues = (pmd->role == MEMIF_ROLE_SLAVE) ?\n+\t    pmd->cfg.num_m2s_rings : pmd->cfg.num_s2m_rings;\n+\tdev_info->max_tx_queues = (pmd->role == MEMIF_ROLE_SLAVE) ?\n+\t    pmd->cfg.num_s2m_rings : pmd->cfg.num_m2s_rings;\n+\tdev_info->min_rx_bufsize = 0;\n+}\n+\n+static memif_ring_t *\n+memif_get_ring(struct pmd_internals *pmd, memif_ring_type_t type, uint16_t ring_num)\n+{\n+\t/* rings only in region 0 */\n+\tvoid *p = pmd->regions[0].addr;\n+\tint ring_size = sizeof(memif_ring_t) + sizeof(memif_desc_t) *\n+\t    (1 << pmd->run.log2_ring_size);\n+\tp += (ring_num + type * pmd->run.num_s2m_rings) * ring_size;\n+\n+\treturn (memif_ring_t *)p;\n+}\n+\n+static void *\n+memif_get_buffer(struct pmd_internals *pmd, memif_desc_t *d)\n+{\n+\treturn (pmd->regions[d->region].addr + d->offset);\n+}\n+\n+static uint16_t\n+eth_memif_rx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)\n+{\n+\tstruct memif_queue *mq = queue;\n+\tstruct pmd_internals *pmd = mq->pmd;\n+\tif (unlikely((pmd->flags & ETH_MEMIF_FLAG_CONNECTED) == 0))\n+\t\treturn 0;\n+\tmemif_ring_t *ring = mq->ring;\n+\tif (unlikely(ring == NULL))\n+\t\treturn 0;\n+\tuint16_t cur_slot, last_slot, n_slots, ring_size, mask, s0;\n+\tuint16_t n_rx_pkts = 0;\n+\tuint16_t mbuf_size = rte_pktmbuf_data_room_size(mq->mempool) -\n+\t    RTE_PKTMBUF_HEADROOM;\n+\tuint16_t src_len, src_off, dst_len, dst_off, cp_len;\n+\tmemif_ring_type_t type = mq->type;\n+\tmemif_desc_t *d0;\n+\tstruct rte_mbuf *mbuf;\n+\tstruct rte_mbuf *mbuf_head = NULL;\n+\n+\t/* consume interrupt */\n+\tif ((ring->flags & MEMIF_RING_FLAG_MASK_INT) == 0) {\n+\t\tuint64_t b;\n+\t\tssize_t size __rte_unused;\n+\t\tsize = read(mq->intr_handle.fd, &b, sizeof(b));\n+\t}\n+\n+\tring_size = 1 << mq->log2_ring_size;\n+\tmask = ring_size - 1;\n+\n+\tcur_slot = (type == MEMIF_RING_S2M) ? mq->last_head : mq->last_tail;\n+\tlast_slot = (type == MEMIF_RING_S2M) ? ring->head : ring->tail;\n+\tif (cur_slot == last_slot)\n+\t\tgoto refill;\n+\tn_slots = last_slot - cur_slot;\n+\n+\twhile (n_slots && n_rx_pkts < nb_pkts) {\n+\t\tmbuf_head = rte_pktmbuf_alloc(mq->mempool);\n+\t\tif (unlikely(mbuf_head == NULL))\n+\t\t\tgoto no_free_bufs;\n+\t\tmbuf = mbuf_head;\n+\t\tmbuf->port = mq->in_port;\n+\n+ next_slot:\n+\t\ts0 = cur_slot & mask;\n+\t\td0 = &ring->desc[s0];\n+\n+\t\tsrc_len = d0->length;\n+\t\tdst_off = 0;\n+\t\tsrc_off = 0;\n+\n+\t\tdo {\n+\t\t\tdst_len = mbuf_size - dst_off;\n+\t\t\tif (dst_len == 0) {\n+\t\t\t\tdst_off = 0;\n+\t\t\t\tdst_len = mbuf_size + RTE_PKTMBUF_HEADROOM;\n+\n+\t\t\t\tmbuf = rte_pktmbuf_alloc(mq->mempool);\n+\t\t\t\tif (unlikely(mbuf == NULL))\n+\t\t\t\t\tgoto no_free_bufs;\n+\t\t\t\tmbuf->port = mq->in_port;\n+\t\t\t\trte_pktmbuf_chain(mbuf_head, mbuf);\n+\t\t\t}\n+\t\t\tcp_len = RTE_MIN(dst_len, src_len);\n+\n+\t\t\trte_pktmbuf_pkt_len(mbuf) =\n+\t\t\t    rte_pktmbuf_data_len(mbuf) += cp_len;\n+\n+\t\t\tmemcpy(rte_pktmbuf_mtod_offset(mbuf, void *, dst_off),\n+\t\t\t       memif_get_buffer(pmd, d0) + src_off, cp_len);\n+\n+\t\t\tmq->n_bytes += cp_len;\n+\t\t\tsrc_off += cp_len;\n+\t\t\tdst_off += cp_len;\n+\t\t\tsrc_len -= cp_len;\n+\t\t} while (src_len);\n+\n+\t\tcur_slot++;\n+\t\tn_slots--;\n+\t\tif (d0->flags & MEMIF_DESC_FLAG_NEXT)\n+\t\t\tgoto next_slot;\n+\n+\t\t*bufs++ = mbuf_head;\n+\t\tn_rx_pkts++;\n+\t}\n+\n+ no_free_bufs:\n+\tif (type == MEMIF_RING_S2M) {\n+\t\trte_mb();\n+\t\tring->tail = cur_slot;\n+\t\tmq->last_head = cur_slot;\n+\t} else {\n+\t\tmq->last_tail = cur_slot;\n+\t}\n+\n+ refill:\n+\tif (type == MEMIF_RING_M2S) {\n+\t\tuint16_t head = ring->head;\n+\t\tn_slots = ring_size - head + mq->last_tail;\n+\n+\t\twhile (n_slots--) {\n+\t\t\ts0 = head++ & mask;\n+\t\t\td0 = &ring->desc[s0];\n+\t\t\td0->length = pmd->run.buffer_size;\n+\t\t}\n+\t\trte_mb();\n+\t\tring->head = head;\n+\t}\n+\n+\tmq->n_pkts += n_rx_pkts;\n+\treturn n_rx_pkts;\n+}\n+\n+static uint16_t\n+eth_memif_tx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)\n+{\n+\tstruct memif_queue *mq = queue;\n+\tstruct pmd_internals *pmd = mq->pmd;\n+\tif (unlikely((pmd->flags & ETH_MEMIF_FLAG_CONNECTED) == 0))\n+\t\treturn 0;\n+\tmemif_ring_t *ring = mq->ring;\n+\tif (unlikely(ring == NULL))\n+\t\treturn 0;\n+\tuint16_t slot, saved_slot, n_free, ring_size, mask, n_tx_pkts = 0;\n+\tuint16_t src_len, src_off, dst_len, dst_off, cp_len;\n+\tmemif_ring_type_t type = mq->type;\n+\tmemif_desc_t *d0;\n+\tstruct rte_mbuf *mbuf;\n+\tstruct rte_mbuf *mbuf_head;\n+\n+\tring_size = 1 << mq->log2_ring_size;\n+\tmask = ring_size - 1;\n+\n+\tn_free = ring->tail - mq->last_tail;\n+\tmq->last_tail += n_free;\n+\tslot = (type == MEMIF_RING_S2M) ? ring->head : ring->tail;\n+\n+\tif (type == MEMIF_RING_S2M)\n+\t\tn_free = ring_size - ring->head + mq->last_tail;\n+\telse\n+\t\tn_free = ring->head - ring->tail;\n+\n+\twhile (n_free && n_tx_pkts < nb_pkts) {\n+\t\tmbuf_head = *bufs++;\n+\t\tmbuf = mbuf_head;\n+\n+\t\tsaved_slot = slot;\n+\t\td0 = &ring->desc[slot & mask];\n+\t\tdst_off = 0;\n+\t\tdst_len =\n+\t\t    (type ==\n+\t\t     MEMIF_RING_S2M) ? pmd->run.buffer_size : d0->length;\n+\n+ next_in_chain:\n+\t\tsrc_off = 0;\n+\t\tsrc_len = rte_pktmbuf_data_len(mbuf);\n+\n+\t\twhile (src_len) {\n+\t\t\tif (dst_len == 0) {\n+\t\t\t\tif (n_free) {\n+\t\t\t\t\tslot++;\n+\t\t\t\t\tn_free--;\n+\t\t\t\t\td0->flags |= MEMIF_DESC_FLAG_NEXT;\n+\t\t\t\t\td0 = &ring->desc[slot & mask];\n+\t\t\t\t\tdst_off = 0;\n+\t\t\t\t\tdst_len = (type == MEMIF_RING_S2M) ?\n+\t\t\t\t\t    pmd->run.buffer_size : d0->length;\n+\t\t\t\t\td0->flags = 0;\n+\t\t\t\t} else {\n+\t\t\t\t\tslot = saved_slot;\n+\t\t\t\t\tgoto no_free_slots;\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tcp_len = RTE_MIN(dst_len, src_len);\n+\n+\t\t\tmemcpy(memif_get_buffer(pmd, d0) + dst_off,\n+\t\t\t       rte_pktmbuf_mtod_offset(mbuf, void *, src_off),\n+\t\t\t       cp_len);\n+\n+\t\t\tmq->n_bytes += cp_len;\n+\t\t\tsrc_off += cp_len;\n+\t\t\tdst_off += cp_len;\n+\t\t\tsrc_len -= cp_len;\n+\t\t\tdst_len -= cp_len;\n+\n+\t\t\td0->length = dst_off;\n+\t\t}\n+\n+\t\tif (rte_pktmbuf_is_contiguous(mbuf) == 0) {\n+\t\t\tmbuf = mbuf->next;\n+\t\t\tgoto next_in_chain;\n+\t\t}\n+\n+\t\tn_tx_pkts++;\n+\t\tslot++;\n+\t\tn_free--;\n+\t\trte_pktmbuf_free(mbuf_head);\n+\t}\n+\n+ no_free_slots:\n+\trte_mb();\n+\tif (type == MEMIF_RING_S2M)\n+\t\tring->head = slot;\n+\telse\n+\t\tring->tail = slot;\n+\n+\tif ((ring->flags & MEMIF_RING_FLAG_MASK_INT) == 0) {\n+\t\tuint64_t a = 1;\n+\t\tssize_t size = write(mq->intr_handle.fd, &a, sizeof(a));\n+\t\tif (unlikely(size < 0)) {\n+\t\t\tMIF_LOG(WARNING,\n+\t\t\t\t\"%s: Failed to send interrupt on qid %ld: %s\",\n+\t\t\t\trte_vdev_device_name(pmd->vdev),\n+\t\t\t\tmq - pmd->tx_queues, strerror(errno));\n+\t\t}\n+\t}\n+\n+\tmq->n_err += nb_pkts - n_tx_pkts;\n+\tmq->n_pkts += n_tx_pkts;\n+\treturn n_tx_pkts;\n+}\n+\n+void\n+memif_free_regions(struct pmd_internals *pmd)\n+{\n+\tint i;\n+\tstruct memif_region *r;\n+\n+\tfor (i = 0; i < pmd->regions_num; i++) {\n+\t\tr = pmd->regions + i;\n+\t\tif (r == NULL)\n+\t\t\treturn;\n+\t\tif (r->addr == NULL)\n+\t\t\treturn;\n+\t\tmunmap(r->addr, r->region_size);\n+\t\tif (r->fd > 0) {\n+\t\t\tclose(r->fd);\n+\t\t\tr->fd = -1;\n+\t\t}\n+\t}\n+\trte_free(pmd->regions);\n+}\n+\n+static int\n+memif_alloc_regions(struct pmd_internals *pmd, uint8_t brn)\n+{\n+\tstruct memif_region *r;\n+\tchar shm_name[32];\n+\tint i;\n+\tint ret = 0;\n+\n+\tr = rte_zmalloc(\"memif_region\", sizeof(struct memif_region) * (brn + 1), 0);\n+\tif (r == NULL) {\n+\t\tMIF_LOG(ERR, \"%s: Failed to allocate regions.\",\n+\t\t\trte_vdev_device_name(pmd->vdev));\n+\t\treturn -ENOMEM;\n+\t}\n+\n+\tpmd->regions = r;\n+\tpmd->regions_num = brn + 1;\n+\n+\t/*\n+\t * Create shm for every region. Region 0 is reserved for descriptors.\n+\t * Other regions contain buffers.\n+\t */\n+\tfor (i = 0; i < (brn + 1); i++) {\n+\t\tr = &pmd->regions[i];\n+\n+\t\tr->buffer_offset = (i == 0) ? (pmd->run.num_s2m_rings +\n+\t\t\t\t\t       pmd->run.num_m2s_rings) *\n+\t\t    (sizeof(memif_ring_t) +\n+\t\t     sizeof(memif_desc_t) * (1 << pmd->run.log2_ring_size)) : 0;\n+\t\tr->region_size = (i == 0) ? r->buffer_offset :\n+\t\t    (uint32_t)(pmd->run.buffer_size *\n+\t\t\t\t(1 << pmd->run.log2_ring_size) *\n+\t\t\t\t(pmd->run.num_s2m_rings +\n+\t\t\t\t pmd->run.num_m2s_rings));\n+\n+\t\tmemset(shm_name, 0, sizeof(char) * 32);\n+\t\tsprintf(shm_name, \"memif region %d\", i);\n+\n+\t\tr->fd = memfd_create(shm_name, MFD_ALLOW_SEALING);\n+\t\tif (r->fd < 0) {\n+\t\t\tMIF_LOG(ERR, \"%s: Failed to create shm file: %s.\",\n+\t\t\t\trte_vdev_device_name(pmd->vdev),\n+\t\t\t\tstrerror(errno));\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\tret = fcntl(r->fd, F_ADD_SEALS, F_SEAL_SHRINK);\n+\t\tif (ret < 0) {\n+\t\t\tMIF_LOG(ERR, \"%s: Failed to add seals to shm file: %s.\",\n+\t\t\t\trte_vdev_device_name(pmd->vdev),\n+\t\t\t\tstrerror(errno));\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\tret = ftruncate(r->fd, r->region_size);\n+\t\tif (ret < 0) {\n+\t\t\tMIF_LOG(ERR, \"%s: Failed to truncate shm file: %s.\",\n+\t\t\t\trte_vdev_device_name(pmd->vdev),\n+\t\t\t\tstrerror(errno));\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\tr->addr = mmap(NULL, r->region_size, PROT_READ |\n+\t\t\t       PROT_WRITE, MAP_SHARED, r->fd, 0);\n+\t\tif (r->addr == NULL) {\n+\t\t\tMIF_LOG(ERR, \"%s: Failed to mmap shm region: %s.\",\n+\t\t\t\trte_vdev_device_name(pmd->vdev),\n+\t\t\t\tstrerror(errno));\n+\t\t\treturn -1;\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static void\n+memif_init_rings(struct pmd_internals *pmd)\n+{\n+\tmemif_ring_t *ring;\n+\tint i, j;\n+\n+\tfor (i = 0; i < pmd->run.num_s2m_rings; i++) {\n+\t\tring = memif_get_ring(pmd, MEMIF_RING_S2M, i);\n+\t\tring->head = 0;\n+\t\tring->tail = 0;\n+\t\tring->cookie = MEMIF_COOKIE;\n+\t\tring->flags = 0;\n+\t\tfor (j = 0; j < (1 << pmd->run.log2_ring_size); j++) {\n+\t\t\tuint16_t slot = i * (1 << pmd->run.log2_ring_size) + j;\n+\t\t\tring->desc[j].region = 1;\n+\t\t\tring->desc[j].offset = pmd->regions[1].buffer_offset +\n+\t\t\t    (uint32_t)(slot * pmd->run.buffer_size);\n+\t\t\tring->desc[j].length = pmd->run.buffer_size;\n+\t\t}\n+\t}\n+\n+\tfor (i = 0; i < pmd->run.num_m2s_rings; i++) {\n+\t\tring = memif_get_ring(pmd, MEMIF_RING_M2S, i);\n+\t\tring->head = 0;\n+\t\tring->tail = 0;\n+\t\tring->cookie = MEMIF_COOKIE;\n+\t\tring->flags = 0;\n+\t\tfor (j = 0; j < (1 << pmd->run.log2_ring_size); j++) {\n+\t\t\tuint16_t slot = (i + pmd->run.num_s2m_rings) *\n+\t\t\t    (1 << pmd->run.log2_ring_size) + j;\n+\t\t\tring->desc[j].region = 1;\n+\t\t\tring->desc[j].offset = pmd->regions[1].buffer_offset +\n+\t\t\t    (uint32_t)(slot * pmd->run.buffer_size);\n+\t\t\tring->desc[j].length = pmd->run.buffer_size;\n+\t\t}\n+\t}\n+}\n+\n+static void\n+memif_init_queues(struct pmd_internals *pmd)\n+{\n+\tstruct memif_queue *mq;\n+\tint i;\n+\n+\tfor (i = 0; i < pmd->run.num_s2m_rings; i++) {\n+\t\tmq = &pmd->tx_queues[i];\n+\t\tmq->ring = memif_get_ring(pmd, MEMIF_RING_S2M, i);\n+\t\tmq->log2_ring_size = pmd->run.log2_ring_size;\n+\t\t/* queues located only in region 0 */\n+\t\tmq->region = 0;\n+\t\tmq->offset = (void *)mq->ring - (void *)pmd->regions[0].addr;\n+\t\tmq->last_head = 0;\n+\t\tmq->last_tail = 0;\n+\t\tmq->intr_handle.fd = eventfd(0, EFD_NONBLOCK);\n+\t\tif (mq->intr_handle.fd < 0) {\n+\t\t\tMIF_LOG(WARNING,\n+\t\t\t\t\"%s: Failed to create eventfd for tx queue %d: %s.\",\n+\t\t\t\trte_vdev_device_name(pmd->vdev), i,\n+\t\t\t\tstrerror(errno));\n+\t\t}\n+\t}\n+\n+\tfor (i = 0; i < pmd->run.num_m2s_rings; i++) {\n+\t\tmq = &pmd->rx_queues[i];\n+\t\tmq->ring = memif_get_ring(pmd, MEMIF_RING_M2S, i);\n+\t\tmq->log2_ring_size = pmd->run.log2_ring_size;\n+\t\t/* queues located only in region 0 */\n+\t\tmq->region = 0;\n+\t\tmq->offset = (void *)mq->ring - (void *)pmd->regions[0].addr;\n+\t\tmq->last_head = 0;\n+\t\tmq->last_tail = 0;\n+\t\tmq->intr_handle.fd = eventfd(0, EFD_NONBLOCK);\n+\t\tif (mq->intr_handle.fd < 0) {\n+\t\t\tMIF_LOG(WARNING,\n+\t\t\t\t\"%s: Failed to create eventfd for rx queue %d: %s.\",\n+\t\t\t\trte_vdev_device_name(pmd->vdev), i,\n+\t\t\t\tstrerror(errno));\n+\t\t}\n+\t}\n+}\n+\n+int\n+memif_init_regions_and_queues(struct pmd_internals *pmd)\n+{\n+\tint ret;\n+\n+\tret = memif_alloc_regions(pmd, /* num of buffer regions */ 1);\n+\tif (ret < 0)\n+\t\treturn ret;\n+\n+\tmemif_init_rings(pmd);\n+\n+\tmemif_init_queues(pmd);\n+\n+\treturn 0;\n+}\n+\n+int\n+memif_connect(struct pmd_internals *pmd)\n+{\n+\tstruct rte_eth_dev *eth_dev =\n+\t    rte_eth_dev_allocated(rte_vdev_device_name(pmd->vdev));\n+\tstruct memif_region *mr;\n+\tstruct memif_queue *mq;\n+\tint i;\n+\n+\tfor (i = 0; i < pmd->regions_num; i++) {\n+\t\tmr = pmd->regions + i;\n+\t\tif (mr != NULL) {\n+\t\t\tif (mr->addr == NULL) {\n+\t\t\t\tif (mr->fd < 0)\n+\t\t\t\t\treturn -1;\n+\t\t\t\tmr->addr = mmap(NULL, mr->region_size,\n+\t\t\t\t\t\tPROT_READ | PROT_WRITE,\n+\t\t\t\t\t\tMAP_SHARED, mr->fd, 0);\n+\t\t\t\tif (mr->addr == NULL)\n+\t\t\t\t\treturn -1;\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\tfor (i = 0; i < pmd->run.num_s2m_rings; i++) {\n+\t\tmq = (pmd->role == MEMIF_ROLE_SLAVE) ?\n+\t\t    &pmd->tx_queues[i] : &pmd->rx_queues[i];\n+\t\tmq->ring = pmd->regions[mq->region].addr + mq->offset;\n+\t\tif (mq->ring->cookie != MEMIF_COOKIE) {\n+\t\t\tMIF_LOG(ERR, \"%s: Wrong cookie\",\n+\t\t\t\trte_vdev_device_name(pmd->vdev));\n+\t\t\treturn -1;\n+\t\t}\n+\t\tmq->ring->head = 0;\n+\t\tmq->ring->tail = 0;\n+\t\tmq->last_head = 0;\n+\t\tmq->last_tail = 0;\n+\t\t/* polling mode by default */\n+\t\tif (pmd->role == MEMIF_ROLE_MASTER)\n+\t\t\tmq->ring->flags = MEMIF_RING_FLAG_MASK_INT;\n+\t}\n+\tfor (i = 0; i < pmd->run.num_m2s_rings; i++) {\n+\t\tmq = (pmd->role == MEMIF_ROLE_SLAVE) ?\n+\t\t    &pmd->rx_queues[i] : &pmd->tx_queues[i];\n+\t\tmq->ring = pmd->regions[mq->region].addr + mq->offset;\n+\t\tif (mq->ring->cookie != MEMIF_COOKIE) {\n+\t\t\tMIF_LOG(ERR, \"%s: Wrong cookie\",\n+\t\t\t\trte_vdev_device_name(pmd->vdev));\n+\t\t\treturn -1;\n+\t\t}\n+\t\tmq->ring->head = 0;\n+\t\tmq->ring->tail = 0;\n+\t\tmq->last_head = 0;\n+\t\tmq->last_tail = 0;\n+\t\t/* polling mode by default */\n+\t\tif (pmd->role == MEMIF_ROLE_SLAVE)\n+\t\t\tmq->ring->flags = MEMIF_RING_FLAG_MASK_INT;\n+\t}\n+\n+\tpmd->flags &= ~ETH_MEMIF_FLAG_CONNECTING;\n+\tpmd->flags |= ETH_MEMIF_FLAG_CONNECTED;\n+\teth_dev->data->dev_link.link_status = ETH_LINK_UP;\n+\tMIF_LOG(INFO, \"%s: Connected.\", rte_vdev_device_name(pmd->vdev));\n+\treturn 0;\n+}\n+\n+static int\n+memif_dev_start(struct rte_eth_dev *dev)\n+{\n+\tstruct pmd_internals *pmd = dev->data->dev_private;\n+\tint ret = 0;\n+\n+\tswitch (pmd->role) {\n+\tcase MEMIF_ROLE_SLAVE:\n+\t\tret = memif_connect_slave(dev);\n+\t\tbreak;\n+\tcase MEMIF_ROLE_MASTER:\n+\t\tret = memif_connect_master(dev);\n+\t\tbreak;\n+\tdefault:\n+\t\tMIF_LOG(ERR, \"%s: Unknown role: %d.\",\n+\t\t\trte_vdev_device_name(pmd->vdev), pmd->role);\n+\t\tret = -1;\n+\t\tbreak;\n+\t}\n+\n+\treturn ret;\n+}\n+\n+static int\n+memif_dev_configure(struct rte_eth_dev *dev __rte_unused)\n+{\n+\treturn 0;\n+}\n+\n+static int\n+memif_tx_queue_setup(struct rte_eth_dev *dev,\n+\t\t     uint16_t qid,\n+\t\t     uint16_t nb_tx_desc __rte_unused,\n+\t\t     unsigned int socket_id __rte_unused,\n+\t\t     const struct rte_eth_txconf *tx_conf __rte_unused)\n+{\n+\tstruct pmd_internals *pmd = dev->data->dev_private;\n+\tstruct memif_queue *mq;\n+\n+\tmq = rte_realloc(pmd->tx_queues, sizeof(struct memif_queue) * (qid + 1),\n+\t\t\t 0);\n+\tif (mq == NULL) {\n+\t\tMIF_LOG(ERR, \"%s: Failed to alloc tx queue %u.\",\n+\t\t\trte_vdev_device_name(pmd->vdev), qid);\n+\t\treturn -ENOMEM;\n+\t}\n+\n+\tpmd->tx_queues = mq;\n+\n+\tmq->type =\n+\t    (pmd->role == MEMIF_ROLE_SLAVE) ? MEMIF_RING_S2M : MEMIF_RING_M2S;\n+\tmq->n_pkts = 0;\n+\tmq->n_bytes = 0;\n+\tmq->n_err = 0;\n+\tmq->intr_handle.fd = -1;\n+\tmq->intr_handle.type = RTE_INTR_HANDLE_EXT;\n+\tmq->pmd = pmd;\n+\tdev->data->tx_queues[qid] = mq;\n+\n+\treturn 0;\n+}\n+\n+static int\n+memif_rx_queue_setup(struct rte_eth_dev *dev,\n+\t\t     uint16_t qid,\n+\t\t     uint16_t nb_rx_desc __rte_unused,\n+\t\t     unsigned int socket_id __rte_unused,\n+\t\t     const struct rte_eth_rxconf *rx_conf __rte_unused,\n+\t\t     struct rte_mempool *mb_pool)\n+{\n+\tstruct pmd_internals *pmd = dev->data->dev_private;\n+\tstruct memif_queue *mq;\n+\n+\tmq = rte_realloc(pmd->rx_queues, sizeof(struct memif_queue) * (qid + 1),\n+\t\t\t 0);\n+\tif (mq == NULL) {\n+\t\tMIF_LOG(ERR, \"%s: Failed to alloc rx queue %u.\",\n+\t\t\trte_vdev_device_name(pmd->vdev), qid);\n+\t\treturn -ENOMEM;\n+\t}\n+\n+\tpmd->rx_queues = mq;\n+\n+\tmq->type =\n+\t    (pmd->role == MEMIF_ROLE_SLAVE) ? MEMIF_RING_M2S : MEMIF_RING_S2M;\n+\tmq->n_pkts = 0;\n+\tmq->n_bytes = 0;\n+\tmq->n_err = 0;\n+\tmq->intr_handle.fd = -1;\n+\tmq->intr_handle.type = RTE_INTR_HANDLE_EXT;\n+\tmq->mempool = mb_pool;\n+\tmq->in_port = dev->data->port_id;\n+\tmq->pmd = pmd;\n+\tdev->data->rx_queues[qid] = mq;\n+\n+\treturn 0;\n+}\n+\n+static int\n+memif_link_update(struct rte_eth_dev *dev __rte_unused,\n+\t\t  int wait_to_complete __rte_unused)\n+{\n+\treturn 0;\n+}\n+\n+static int\n+memif_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)\n+{\n+\tstruct pmd_internals *pmd = dev->data->dev_private;\n+\tstruct memif_queue *mq;\n+\tint i;\n+\n+\tstats->ipackets = 0;\n+\tstats->ibytes = 0;\n+\tstats->opackets = 0;\n+\tstats->obytes = 0;\n+\tstats->oerrors = 0;\n+\n+\tuint8_t tmp = (pmd->role == MEMIF_ROLE_SLAVE) ? pmd->run.num_s2m_rings :\n+\t    pmd->run.num_m2s_rings;\n+\tuint8_t nq = (tmp < RTE_ETHDEV_QUEUE_STAT_CNTRS) ? tmp :\n+\t    RTE_ETHDEV_QUEUE_STAT_CNTRS;\n+\n+\t/* RX stats */\n+\tfor (i = 0; i < nq; i++) {\n+\t\tmq = &pmd->rx_queues[i];\n+\t\tstats->q_ipackets[i] = mq->n_pkts;\n+\t\tstats->q_ibytes[i] = mq->n_bytes;\n+\t\tstats->ipackets += mq->n_pkts;\n+\t\tstats->ibytes += mq->n_bytes;\n+\t}\n+\n+\ttmp = (pmd->role == MEMIF_ROLE_SLAVE) ? pmd->run.num_m2s_rings :\n+\t    pmd->run.num_s2m_rings;\n+\tnq = (tmp < RTE_ETHDEV_QUEUE_STAT_CNTRS) ? tmp :\n+\t    RTE_ETHDEV_QUEUE_STAT_CNTRS;\n+\n+\t/* TX stats */\n+\tfor (i = 0; i < nq; i++) {\n+\t\tmq = &pmd->tx_queues[i];\n+\t\tstats->q_opackets[i] = mq->n_pkts;\n+\t\tstats->q_obytes[i] = mq->n_bytes;\n+\t\tstats->q_errors[i] = mq->n_err;\n+\t\tstats->opackets += mq->n_pkts;\n+\t\tstats->obytes += mq->n_bytes;\n+\t\tstats->oerrors += mq->n_err;\n+\t}\n+\treturn 0;\n+}\n+\n+static void\n+memif_stats_reset(struct rte_eth_dev *dev)\n+{\n+\tstruct pmd_internals *pmd = dev->data->dev_private;\n+\tint i;\n+\tstruct memif_queue *mq;\n+\n+\tfor (i = 0; i < pmd->run.num_s2m_rings; i++) {\n+\t\tmq = (pmd->role == MEMIF_ROLE_SLAVE) ? &pmd->tx_queues[i] :\n+\t\t    &pmd->rx_queues[i];\n+\t\tmq->n_pkts = 0;\n+\t\tmq->n_bytes = 0;\n+\t\tmq->n_err = 0;\n+\t}\n+\tfor (i = 0; i < pmd->run.num_m2s_rings; i++) {\n+\t\tmq = (pmd->role == MEMIF_ROLE_SLAVE) ? &pmd->rx_queues[i] :\n+\t\t    &pmd->tx_queues[i];\n+\t\tmq->n_pkts = 0;\n+\t\tmq->n_bytes = 0;\n+\t\tmq->n_err = 0;\n+\t}\n+}\n+\n+static int\n+memif_rx_queue_intr_enable(struct rte_eth_dev *dev, uint16_t qid __rte_unused)\n+{\n+\tstruct pmd_internals *pmd = dev->data->dev_private;\n+\n+\tMIF_LOG(WARNING, \"%s: Interrupt mode not supported.\",\n+\t\trte_vdev_device_name(pmd->vdev));\n+\n+\t/* Enable MEMIF interrupts. */\n+\t/* pmd->rx_queues[qid].ring->flags  &= ~MEMIF_RING_FLAG_MASK_INT; */\n+\n+\t/*\n+\t * TODO: Tell dpdk to use interrupt mode.\n+\t *\n+\t * return rte_intr_enable(&pmd->rx_queues[qid].intr_handle);\n+\t */\n+\treturn -1;\n+}\n+\n+static int\n+memif_rx_queue_intr_disable(struct rte_eth_dev *dev, uint16_t qid __rte_unused)\n+{\n+\tstruct pmd_internals *pmd __rte_unused = dev->data->dev_private;\n+\n+\t/* Disable MEMIF interrupts. */\n+\t/* pmd->rx_queues[qid].ring->flags |= MEMIF_RING_FLAG_MASK_INT; */\n+\n+\t/*\n+\t * TODO: Tell dpdk to use polling mode.\n+\t *\n+\t * return rte_intr_disable(&pmd->rx_queues[qid].intr_handle);\n+\t */\n+\treturn 0;\n+}\n+\n+static const struct eth_dev_ops ops = {\n+\t.dev_start = memif_dev_start,\n+\t.dev_infos_get = memif_dev_info,\n+\t.dev_configure = memif_dev_configure,\n+\t.tx_queue_setup = memif_tx_queue_setup,\n+\t.rx_queue_setup = memif_rx_queue_setup,\n+\t.rx_queue_intr_enable = memif_rx_queue_intr_enable,\n+\t.rx_queue_intr_disable = memif_rx_queue_intr_disable,\n+\t.link_update = memif_link_update,\n+\t.stats_get = memif_stats_get,\n+\t.stats_reset = memif_stats_reset,\n+};\n+\n+static int\n+memif_create(struct rte_vdev_device *vdev, enum memif_role_t role,\n+\t     memif_interface_id_t id, uint32_t flags,\n+\t     const char *socket_filename,\n+\t     memif_log2_ring_size_t log2_ring_size, uint8_t nrxq,\n+\t     uint8_t ntxq, uint16_t buffer_size, const char *secret,\n+\t     const char *eth_addr)\n+{\n+\tint ret = 0;\n+\tstruct rte_eth_dev *eth_dev;\n+\tstruct rte_eth_dev_data *data;\n+\tstruct pmd_internals *pmd;\n+\tconst unsigned int numa_node = vdev->device.numa_node;\n+\tconst char *name = rte_vdev_device_name(vdev);\n+\n+\tif (flags & ETH_MEMIF_FLAG_ZERO_COPY) {\n+\t\tMIF_LOG(ERR, \"Zero-copy not supported.\");\n+\t\treturn -1;\n+\t}\n+\n+\teth_dev = rte_eth_vdev_allocate(vdev, sizeof(*pmd));\n+\tif (eth_dev == NULL) {\n+\t\tMIF_LOG(ERR, \"%s: Unable to allocate device struct.\", name);\n+\t\treturn -1;\n+\t}\n+\n+\tpmd = eth_dev->data->dev_private;\n+\tmemset(pmd, 0, sizeof(*pmd));\n+\n+\tpmd->if_index = id;\n+\tpmd->vdev = vdev;\n+\tpmd->id = id;\n+\tpmd->flags = flags;\n+\tpmd->flags |= ETH_MEMIF_FLAG_DISABLED;\n+\tpmd->role = role;\n+\tret = memif_socket_init(eth_dev, socket_filename);\n+\tif (ret < 0)\n+\t\treturn ret;\n+\n+\tmemset(pmd->secret, 0, sizeof(char) * 24);\n+\tif (secret != NULL)\n+\t\tstrlcpy(pmd->secret, secret, sizeof(pmd->secret));\n+\n+\tpmd->cfg.log2_ring_size = ETH_MEMIF_DEFAULT_RING_SIZE;\n+\tif (log2_ring_size != 0)\n+\t\tpmd->cfg.log2_ring_size = log2_ring_size;\n+\tpmd->cfg.num_s2m_rings = ETH_MEMIF_DEFAULT_NRXQ;\n+\tpmd->cfg.num_m2s_rings = ETH_MEMIF_DEFAULT_NTXQ;\n+\n+\tif (nrxq != 0) {\n+\t\tif (role == MEMIF_ROLE_SLAVE)\n+\t\t\tpmd->cfg.num_m2s_rings = nrxq;\n+\t\telse\n+\t\t\tpmd->cfg.num_s2m_rings = nrxq;\n+\t}\n+\tif (ntxq != 0) {\n+\t\tif (role == MEMIF_ROLE_SLAVE)\n+\t\t\tpmd->cfg.num_s2m_rings = ntxq;\n+\t\telse\n+\t\t\tpmd->cfg.num_m2s_rings = ntxq;\n+\t}\n+\n+\tpmd->cfg.buffer_size = ETH_MEMIF_DEFAULT_BUFFER_SIZE;\n+\tif (buffer_size != 0)\n+\t\tpmd->cfg.buffer_size = buffer_size;\n+\n+\t/* FIXME: generate mac? */\n+\tif (eth_addr == NULL)\n+\t\teth_addr = ETH_MEMIF_DEFAULT_ETH_ADDR;\n+\n+\tret = sscanf(eth_addr, \"%hhx:%hhx:%hhx:%hhx:%hhx:%hhx\",\n+\t       &pmd->eth_addr.addr_bytes[0], &pmd->eth_addr.addr_bytes[1],\n+\t       &pmd->eth_addr.addr_bytes[2], &pmd->eth_addr.addr_bytes[3],\n+\t       &pmd->eth_addr.addr_bytes[4], &pmd->eth_addr.addr_bytes[5]);\n+\tif (ret != 6) {\n+\t\tMIF_LOG(WARNING, \"%s: Failed to parse mac '%s'.\",\n+\t\t\trte_vdev_device_name(vdev), eth_addr);\n+\t}\n+\n+\tdata = eth_dev->data;\n+\tdata->dev_private = pmd;\n+\tdata->numa_node = numa_node;\n+\tdata->mac_addrs = &pmd->eth_addr;\n+\n+\teth_dev->dev_ops = &ops;\n+\teth_dev->device = &vdev->device;\n+\teth_dev->rx_pkt_burst = eth_memif_rx;\n+\teth_dev->tx_pkt_burst = eth_memif_tx;\n+\n+\trte_eth_dev_probing_finish(eth_dev);\n+\n+\treturn 0;\n+}\n+\n+static int\n+memif_set_role(const char *key __rte_unused, const char *value,\n+\t       void *extra_args)\n+{\n+\tenum memif_role_t *role = (enum memif_role_t *)extra_args;\n+\tif (strstr(value, \"master\") != NULL) {\n+\t\t*role = MEMIF_ROLE_MASTER;\n+\t} else if (strstr(value, \"slave\") != NULL) {\n+\t\t*role = MEMIF_ROLE_SLAVE;\n+\t} else {\n+\t\tMIF_LOG(ERR, \"Unknown role: %s.\", value);\n+\t\treturn -EINVAL;\n+\t}\n+\treturn 0;\n+}\n+\n+static int\n+memif_set_zc(const char *key __rte_unused, const char *value, void *extra_args)\n+{\n+\tuint32_t *flags = (uint32_t *)extra_args;\n+\n+\tif (strstr(value, \"yes\") != NULL) {\n+\t\t*flags |= ETH_MEMIF_FLAG_ZERO_COPY;\n+\t} else if (strstr(value, \"no\") != NULL) {\n+\t\t*flags &= ~ETH_MEMIF_FLAG_ZERO_COPY;\n+\t} else {\n+\t\tMIF_LOG(ERR, \"Failed to parse zero-copy param: %s.\", value);\n+\t\treturn -EINVAL;\n+\t}\n+\treturn 0;\n+}\n+\n+static int\n+memif_set_id(const char *key __rte_unused, const char *value, void *extra_args)\n+{\n+\tmemif_interface_id_t *id = (memif_interface_id_t *)extra_args;\n+\t/* even if parsing fails, 0 is a valid id */\n+\t*id = strtoul(value, NULL, 10);\n+\treturn 0;\n+}\n+\n+static int\n+memif_set_bs(const char *key __rte_unused, const char *value, void *extra_args)\n+{\n+\tunsigned long tmp;\n+\tuint16_t *buffer_size = (uint16_t *)extra_args;\n+\n+\ttmp = strtoul(value, NULL, 10);\n+\tif (tmp == 0 || tmp > 0xFFFF) {\n+\t\tMIF_LOG(ERR, \"Invalid buffer size: %s.\", value);\n+\t\treturn -EINVAL;\n+\t}\n+\t*buffer_size = tmp;\n+\treturn 0;\n+}\n+\n+static int\n+memif_set_rs(const char *key __rte_unused, const char *value, void *extra_args)\n+{\n+\tunsigned long tmp;\n+\tmemif_log2_ring_size_t *log2_ring_size =\n+\t    (memif_log2_ring_size_t *)extra_args;\n+\n+\ttmp = strtoul(value, NULL, 10);\n+\tif (tmp == 0 || tmp > ETH_MEMIF_MAX_LOG2_RING_SIZE) {\n+\t\tMIF_LOG(ERR, \"Invalid ring size: %s (max %u).\",\n+\t\t\tvalue, ETH_MEMIF_MAX_LOG2_RING_SIZE);\n+\t\treturn -EINVAL;\n+\t}\n+\t*log2_ring_size = tmp;\n+\treturn 0;\n+}\n+\n+static int\n+memif_set_nq(const char *key __rte_unused, const char *value, void *extra_args)\n+{\n+\tunsigned long tmp;\n+\tuint16_t *nq = (uint16_t *)extra_args;\n+\n+\ttmp = strtoul(value, NULL, 10);\n+\tif (tmp == 0 || tmp > 0xFF) {\n+\t\tMIF_LOG(ERR, \"Invalid number of queues: %s.\", value);\n+\t\treturn -EINVAL;\n+\t}\n+\t*nq = tmp;\n+\treturn 0;\n+}\n+\n+/* check if directory exists and if we have permission to read/write */\n+static int\n+memif_check_socket_filename(const char *filename)\n+{\n+\tchar *dir = NULL, *tmp;\n+\tuint32_t idx;\n+\tint ret = 0;\n+\n+\ttmp = strrchr(filename, '/');\n+\tif (tmp != NULL) {\n+\t\tidx = tmp - filename;\n+\t\tdir = rte_zmalloc(\"memif_tmp\", sizeof(char) * (idx + 1), 0);\n+\t\tif (dir == NULL) {\n+\t\t\tMIF_LOG(ERR, \"Failed to allocate memory.\");\n+\t\t\treturn -1;\n+\t\t}\n+\t\tstrlcpy(dir, filename, sizeof(char) * (idx + 1));\n+\t}\n+\n+\tif (dir == NULL || (faccessat(-1, dir, F_OK | R_OK |\n+\t\t\t\t\tW_OK, AT_EACCESS) < 0)) {\n+\t\tMIF_LOG(ERR, \"Invalid directory: '%s'.\", dir);\n+\t\tret = -EINVAL;\n+\t}\n+\n+\tif (dir != NULL)\n+\t\trte_free(dir);\n+\n+\treturn ret;\n+}\n+\n+static int\n+rte_pmd_memif_probe(struct rte_vdev_device *vdev)\n+{\n+\tRTE_BUILD_BUG_ON(sizeof(memif_msg_t) != 128);\n+\tRTE_BUILD_BUG_ON(sizeof(memif_desc_t) != 16);\n+\tint ret = 0;\n+\tunsigned int i;\n+\tstruct rte_kvargs *kvlist;\n+\tconst struct rte_kvargs_pair *pair;\n+\n+\tconst char *name = rte_vdev_device_name(vdev);\n+\n+\tenum memif_role_t role;\n+\tmemif_interface_id_t id;\n+\n+\tuint16_t buffer_size;\n+\tmemif_log2_ring_size_t log2_ring_size;\n+\tuint8_t nrxq, ntxq;\n+\tconst char *socket_filename;\n+\tconst char *eth_addr;\n+\tuint32_t flags;\n+\tconst char *secret;\n+\n+\tMIF_LOG(INFO, \"Initialize MEMIF: %s.\", name);\n+\n+\tkvlist = rte_kvargs_parse(rte_vdev_device_args(vdev), valid_arguments);\n+\n+\t/* set default values */\n+\trole = MEMIF_ROLE_SLAVE;\n+\tflags = 0;\n+\tid = 0;\n+\tbuffer_size = 2048;\n+\tlog2_ring_size = 10;\n+\tnrxq = 1;\n+\tntxq = 1;\n+\tsocket_filename = ETH_MEMIF_DEFAULT_SOCKET_FILENAME;\n+\tsecret = NULL;\n+\teth_addr = NULL;\n+\n+\t/* parse parameters */\n+\tif (kvlist != NULL) {\n+\t\tif (rte_kvargs_count(kvlist, ETH_MEMIF_ROLE_ARG) == 1) {\n+\t\t\tret = rte_kvargs_process(kvlist, ETH_MEMIF_ROLE_ARG,\n+\t\t\t\t\t\t &memif_set_role, &role);\n+\t\t\tif (ret < 0)\n+\t\t\t\tgoto exit;\n+\t\t}\n+\t\tif (rte_kvargs_count(kvlist, ETH_MEMIF_ID_ARG) == 1) {\n+\t\t\tret = rte_kvargs_process(kvlist, ETH_MEMIF_ID_ARG,\n+\t\t\t\t\t\t &memif_set_id, &id);\n+\t\t\tif (ret < 0)\n+\t\t\t\tgoto exit;\n+\t\t}\n+\t\tif (rte_kvargs_count(kvlist, ETH_MEMIF_BUFFER_SIZE_ARG) == 1) {\n+\t\t\tret =\n+\t\t\t    rte_kvargs_process(kvlist,\n+\t\t\t\t\t       ETH_MEMIF_BUFFER_SIZE_ARG,\n+\t\t\t\t\t       &memif_set_bs, &buffer_size);\n+\t\t\tif (ret < 0)\n+\t\t\t\tgoto exit;\n+\t\t}\n+\t\tif (rte_kvargs_count(kvlist, ETH_MEMIF_RING_SIZE_ARG) == 1) {\n+\t\t\tret =\n+\t\t\t    rte_kvargs_process(kvlist, ETH_MEMIF_RING_SIZE_ARG,\n+\t\t\t\t\t       &memif_set_rs, &log2_ring_size);\n+\t\t\tif (ret < 0)\n+\t\t\t\tgoto exit;\n+\t\t}\n+\t\tif (rte_kvargs_count(kvlist, ETH_MEMIF_NRXQ_ARG) == 1) {\n+\t\t\tret = rte_kvargs_process(kvlist, ETH_MEMIF_NRXQ_ARG,\n+\t\t\t\t\t\t &memif_set_nq, &nrxq);\n+\t\t\tif (ret < 0)\n+\t\t\t\tgoto exit;\n+\t\t}\n+\t\tif (rte_kvargs_count(kvlist, ETH_MEMIF_NTXQ_ARG) == 1) {\n+\t\t\tret = rte_kvargs_process(kvlist, ETH_MEMIF_NTXQ_ARG,\n+\t\t\t\t\t\t &memif_set_nq, &ntxq);\n+\t\t\tif (ret < 0)\n+\t\t\t\tgoto exit;\n+\t\t}\n+\t\tif (rte_kvargs_count(kvlist, ETH_MEMIF_SOCKET_ARG) == 1) {\n+\t\t\tfor (i = 0; i < kvlist->count; i++) {\n+\t\t\t\tpair = &kvlist->pairs[i];\n+\t\t\t\tif (strcmp(pair->key, ETH_MEMIF_SOCKET_ARG) == 0) {\n+\t\t\t\t\tsocket_filename = pair->value;\n+\t\t\t\t\tret = memif_check_socket_filename(\n+\t\t\t\t\t\tsocket_filename);\n+\t\t\t\t\tif (ret < 0)\n+\t\t\t\t\t\tgoto exit;\n+\t\t\t\t}\n+\t\t\t}\n+\t\t}\n+\t\tif (rte_kvargs_count(kvlist, ETH_MEMIF_MAC_ARG) == 1) {\n+\t\t\tfor (i = 0; i < kvlist->count; i++) {\n+\t\t\t\tpair = &kvlist->pairs[i];\n+\t\t\t\tif (strcmp(pair->key, ETH_MEMIF_MAC_ARG) == 0)\n+\t\t\t\t\teth_addr = pair->value;\n+\t\t\t}\n+\t\t}\n+\t\tif (rte_kvargs_count(kvlist, ETH_MEMIF_ZC_ARG) == 1) {\n+\t\t\tret = rte_kvargs_process(kvlist, ETH_MEMIF_ZC_ARG,\n+\t\t\t\t\t\t &memif_set_zc, &flags);\n+\t\t\tif (ret < 0)\n+\t\t\t\tgoto exit;\n+\t\t}\n+\t\tif (rte_kvargs_count(kvlist, ETH_MEMIF_SECRET_ARG) == 1) {\n+\t\t\tfor (i = 0; i < kvlist->count; i++) {\n+\t\t\t\tpair = &kvlist->pairs[i];\n+\t\t\t\tif (strcmp(pair->key, ETH_MEMIF_SECRET_ARG) == 0)\n+\t\t\t\t\tsecret = pair->value;\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\t/* create interface */\n+\tret =\n+\t    memif_create(vdev, role, id, flags, socket_filename, log2_ring_size,\n+\t\t\t nrxq, ntxq, buffer_size, secret, eth_addr);\n+\n+ exit:\n+\tif (kvlist != NULL)\n+\t\trte_kvargs_free(kvlist);\n+\treturn ret;\n+}\n+\n+static int\n+rte_pmd_memif_remove(struct rte_vdev_device *vdev)\n+{\n+\tstruct rte_eth_dev *eth_dev;\n+\n+\teth_dev = rte_eth_dev_allocated(rte_vdev_device_name(vdev));\n+\tif (eth_dev == NULL)\n+\t\treturn 0;\n+\n+\tstruct pmd_internals *pmd = eth_dev->data->dev_private;\n+\n+\tmemif_msg_enq_disconnect(pmd->cc, \"Invalid message size\", 0);\n+\tmemif_disconnect(eth_dev);\n+\n+\tmemif_socket_remove_device(pmd);\n+\n+\tpmd->vdev = NULL;\n+\n+\trte_free(eth_dev->data->dev_private);\n+\n+\trte_eth_dev_release_port(eth_dev);\n+\n+\treturn 0;\n+}\n+\n+static struct rte_vdev_driver pmd_memif_drv = {\n+\t.probe = rte_pmd_memif_probe,\n+\t.remove = rte_pmd_memif_remove,\n+};\n+\n+RTE_PMD_REGISTER_VDEV(net_memif, pmd_memif_drv);\n+RTE_PMD_REGISTER_ALIAS(net_memif, eth_memif);\n+RTE_PMD_REGISTER_PARAM_STRING(net_memif,\n+\t\t\t      ETH_MEMIF_ID_ARG \"=<int>\"\n+\t\t\t      ETH_MEMIF_ROLE_ARG \"=<string>\"\n+\t\t\t      ETH_MEMIF_BUFFER_SIZE_ARG \"=<int>\"\n+\t\t\t      ETH_MEMIF_RING_SIZE_ARG \"=<int>\"\n+\t\t\t      ETH_MEMIF_NRXQ_ARG \"=<int>\"\n+\t\t\t      ETH_MEMIF_NTXQ_ARG \"=<int>\"\n+\t\t\t      ETH_MEMIF_SOCKET_ARG \"=<string>\"\n+\t\t\t      ETH_MEMIF_MAC_ARG \"=xx:xx:xx:xx:xx:xx\"\n+\t\t\t      ETH_MEMIF_ZC_ARG \"=<string>\"\n+\t\t\t      ETH_MEMIF_SECRET_ARG \"=<string>\");\n+\n+RTE_INIT(memif_init_log)\n+{\n+\tmemif_logtype = rte_log_register(\"pmd.net.memif\");\n+\tif (memif_logtype >= 0)\n+\t\trte_log_set_level(memif_logtype, RTE_LOG_NOTICE);\n+}\ndiff --git a/drivers/net/memif/rte_eth_memif.h b/drivers/net/memif/rte_eth_memif.h\nnew file mode 100644\nindex 000000000..e122b2bb7\n--- /dev/null\n+++ b/drivers/net/memif/rte_eth_memif.h\n@@ -0,0 +1,207 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright 2018 Cisco Systems, Inc.  All rights reserved.\n+ */\n+\n+#ifndef _RTE_ETH_MEMIF_H_\n+#define _RTE_ETH_MEMIF_H_\n+\n+#ifndef _GNU_SOURCE\n+#define _GNU_SOURCE\n+#endif\t\t\t\t/* GNU_SOURCE */\n+\n+#include <sys/queue.h>\n+\n+#include <rte_ethdev_driver.h>\n+#include <rte_ether.h>\n+#include <rte_interrupts.h>\n+\n+#include <memif.h>\n+\n+/* generate mac? */\n+#define ETH_MEMIF_DEFAULT_ETH_ADDR\t\t\"01:ab:23:cd:45:ef\"\n+\n+#define ETH_MEMIF_DEFAULT_SOCKET_FILENAME\t\"/tmp/memif.sock\"\n+#define ETH_MEMIF_DEFAULT_RING_SIZE\t\t10\n+#define ETH_MEMIF_DEFAULT_NRXQ\t\t\t1\n+#define ETH_MEMIF_DEFAULT_NTXQ\t\t\t1\n+#define ETH_MEMIF_DEFAULT_BUFFER_SIZE\t\t2048\n+\n+#define ETH_MEMIF_MAX_NUM_Q_PAIRS\t\t256\n+#define ETH_MEMIF_MAX_LOG2_RING_SIZE\t\t14\n+#define ETH_MEMIF_MAX_REGION_IDX\t\t255\n+\n+int memif_logtype;\n+\n+#define MIF_LOG(level, fmt, args...) \\\n+\trte_log(RTE_LOG_ ## level, memif_logtype, \\\n+\t\t\"%s(): \" fmt \"\\n\", __func__, ##args)\n+\n+enum memif_role_t {\n+\tMEMIF_ROLE_MASTER = 0,\n+\tMEMIF_ROLE_SLAVE = 1,\n+};\n+\n+struct memif_region {\n+\tvoid *addr;\t\t\t\t/**< shared memory address */\n+\tmemif_region_size_t region_size;\t/**< shared memory size */\n+\tint fd;\t\t\t\t\t/**< shared memory file descriptor */\n+\tuint32_t buffer_offset;\t\t\t/**< offset at which buffers start */\n+};\n+\n+struct memif_queue {\n+\tstruct rte_mempool *mempool;\t\t/**< mempool for RX packets */\n+\tuint16_t in_port;\t\t\t/**< port id */\n+\n+\tstruct pmd_internals *pmd;\t\t/**< device internals */\n+\n+\tstruct rte_intr_handle intr_handle;\t/**< interrupt handle */\n+\n+\t/* ring info */\n+\tmemif_ring_type_t type;\t\t\t/**< ring type */\n+\tmemif_ring_t *ring;\t\t\t/**< pointer to ring */\n+\tmemif_log2_ring_size_t log2_ring_size;\t/**< log2 of ring size */\n+\n+\tmemif_region_index_t region;\t\t/**< shared memory region index */\n+\tmemif_region_offset_t offset;\t\t/**< offset at which the queue begins */\n+\n+\tuint16_t last_head;\t\t\t/**< last ring head */\n+\tuint16_t last_tail;\t\t\t/**< last ring tail */\n+\t/*uint32_t *buffers;*/\n+\n+\t/* rx/tx info */\n+\tuint64_t n_pkts;\t\t\t/**< number of rx/tx packets */\n+\tuint64_t n_bytes;\t\t\t/**< number of rx/tx bytes */\n+\tuint64_t n_err;\t\t\t\t/**< number of tx errors */\n+};\n+\n+struct pmd_internals {\n+\tint if_index;\t\t\t\t/**< index */\n+\tmemif_interface_id_t id;\t\t/**< unique id */\n+\tenum memif_role_t role;\t\t\t/**< device role */\n+\tuint32_t flags;\t\t\t\t/**< device status flags */\n+#define ETH_MEMIF_FLAG_CONNECTING\t(1 << 0)\n+/**< device is connecting */\n+#define ETH_MEMIF_FLAG_CONNECTED\t(1 << 1)\n+/**< device is connected */\n+#define ETH_MEMIF_FLAG_ZERO_COPY\t(1 << 2)\n+/**< device is zero-copy enabled */\n+#define ETH_MEMIF_FLAG_DISABLED\t\t(1 << 3)\n+/**< device has not been configured and can not accept connection requests */\n+\n+\tstruct ether_addr eth_addr;\t\t/**< mac address */\n+\tchar *socket_filename;\t\t\t/**< pointer to socket filename */\n+\tchar secret[24]; /**< secret (optional security parameter) */\n+\n+\tstruct memif_control_channel *cc;\t/**< control channel */\n+\n+\tstruct memif_region *regions;\t\t/**< shared memory regions */\n+\tuint8_t regions_num;\t\t\t/**< number of regions */\n+\n+\tstruct memif_queue *rx_queues;\t\t/**< RX queues */\n+\tstruct memif_queue *tx_queues;\t\t/**< TX queues */\n+\n+\t/* remote info */\n+\tchar remote_name[64];\t\t\t/**< remote app name */\n+\tchar remote_if_name[64];\t\t/**< remote peer name */\n+\n+\tstruct {\n+\t\tmemif_log2_ring_size_t log2_ring_size; /**< log2 of ring size */\n+\t\tuint8_t num_s2m_rings;\t\t/**< number of slave to master rings */\n+\t\tuint8_t num_m2s_rings;\t\t/**< number of master to slave rings */\n+\t\tuint16_t buffer_size;\t\t/**< buffer size */\n+\t} cfg;\t\t\t\t\t/**< Configured parameters (max values) */\n+\n+\tstruct {\n+\t\tmemif_log2_ring_size_t log2_ring_size; /**< log2 of ring size */\n+\t\tuint8_t num_s2m_rings;\t\t/**< number of slave to master rings */\n+\t\tuint8_t num_m2s_rings;\t\t/**< number of master to slave rings */\n+\t\tuint16_t buffer_size;\t\t/**< buffer size */\n+\t} run;\n+\t/**< Parameters used in active connection */\n+\n+\tchar local_disc_string[96];\t\t/**< local disconnect reason */\n+\tchar remote_disc_string[96];\t\t/**< remote disconnect reason */\n+\n+\tstruct rte_vdev_device *vdev;\t\t/**< vdev handle */\n+};\n+\n+/**\n+ * Unmap shared memory and free regions from memory.\n+ *\n+ * @param pmd\n+ *   device internals\n+ */\n+void memif_free_regions(struct pmd_internals *pmd);\n+\n+/**\n+ * Finalize connection establishment process. Map shared memory file\n+ * (master role), initialize ring queue, set link status up.\n+ *\n+ * @param pmd\n+ *   device internals\n+ * @return\n+ *   - On success, zero.\n+ *   - On failure, a negative value.\n+ */\n+int memif_connect(struct pmd_internals *pmd);\n+\n+/**\n+ * Create shared memory file and initialize ring queue.\n+ * Only called by slave when establishing connection\n+ *\n+ * @param pmd\n+ *   device internals\n+ * @return\n+ *   - On success, zero.\n+ *   - On failure, a negative value.\n+ */\n+int memif_init_regions_and_queues(struct pmd_internals *pmd);\n+\n+/**\n+ * Get memif version string.\n+ *\n+ * @return\n+ *   - memif version string\n+ */\n+const char *memif_version(void);\n+\n+#ifndef MFD_HUGETLB\n+#ifndef __NR_memfd_create\n+\n+#if defined __x86_64__\n+#define __NR_memfd_create 319\n+#elif defined __arm__\n+#define __NR_memfd_create 385\n+#elif defined __aarch64__\n+#define __NR_memfd_create 279\n+#else\n+#error \"__NR_memfd_create unknown for this architecture\"\n+#endif\n+\n+#endif\t\t\t\t/* __NR_memfd_create */\n+\n+static inline int memfd_create(const char *name, unsigned int flags)\n+{\n+\treturn syscall(__NR_memfd_create, name, flags);\n+}\n+#endif\t\t\t\t/* MFD_HUGETLB */\n+\n+#ifndef F_LINUX_SPECIFIC_BASE\n+#define F_LINUX_SPECIFIC_BASE 1024\n+#endif\n+\n+#ifndef MFD_ALLOW_SEALING\n+#define MFD_ALLOW_SEALING       0x0002U\n+#endif\n+\n+#ifndef F_ADD_SEALS\n+#define F_ADD_SEALS (F_LINUX_SPECIFIC_BASE + 9)\n+#define F_GET_SEALS (F_LINUX_SPECIFIC_BASE + 10)\n+\n+#define F_SEAL_SEAL     0x0001\t/* prevent further seals from being set */\n+#define F_SEAL_SHRINK   0x0002\t/* prevent file from shrinking */\n+#define F_SEAL_GROW     0x0004\t/* prevent file from growing */\n+#define F_SEAL_WRITE    0x0008\t/* prevent writes */\n+#endif\n+\n+#endif\t\t\t\t/* RTE_ETH_MEMIF_H */\ndiff --git a/drivers/net/memif/rte_pmd_memif_version.map b/drivers/net/memif/rte_pmd_memif_version.map\nnew file mode 100644\nindex 000000000..97fd251df\n--- /dev/null\n+++ b/drivers/net/memif/rte_pmd_memif_version.map\n@@ -0,0 +1,4 @@\n+DPDK_19.02 {\n+\n+        local: *;\n+};\ndiff --git a/drivers/net/meson.build b/drivers/net/meson.build\nindex 980eec233..b0becbf31 100644\n--- a/drivers/net/meson.build\n+++ b/drivers/net/meson.build\n@@ -21,6 +21,7 @@ drivers = ['af_packet',\n \t'ixgbe',\n \t'kni',\n \t'liquidio',\n+\t'memif',\n \t'mlx4',\n \t'mlx5',\n \t'mvneta',\ndiff --git a/mk/rte.app.mk b/mk/rte.app.mk\nindex 5699d979d..f236c5ebc 100644\n--- a/mk/rte.app.mk\n+++ b/mk/rte.app.mk\n@@ -168,6 +168,7 @@ ifeq ($(CONFIG_RTE_LIBRTE_KNI),y)\n _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_KNI)        += -lrte_pmd_kni\n endif\n _LDLIBS-$(CONFIG_RTE_LIBRTE_LIO_PMD)        += -lrte_pmd_lio\n+_LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_MEMIF)      += -lrte_pmd_memif\n ifeq ($(CONFIG_RTE_LIBRTE_MLX4_DLOPEN_DEPS),y)\n _LDLIBS-$(CONFIG_RTE_LIBRTE_MLX4_PMD)       += -lrte_pmd_mlx4 -ldl\n else\n",
    "prefixes": [
        "RFC",
        "v3"
    ]
}