get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 52121,
    "url": "http://patches.dpdk.org/api/patches/52121/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/20190402154653.711-2-xiaolong.ye@intel.com/",
    "project": {
        "id": 1,
        "url": "http://patches.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<20190402154653.711-2-xiaolong.ye@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20190402154653.711-2-xiaolong.ye@intel.com",
    "date": "2019-04-02T15:46:53",
    "name": "[v9,1/1] net/af_xdp: introduce AF XDP PMD driver",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "b4be0b3aa9c9dc998a8c56e9b694c57f772ac82a",
    "submitter": {
        "id": 1120,
        "url": "http://patches.dpdk.org/api/people/1120/?format=api",
        "name": "Xiaolong Ye",
        "email": "xiaolong.ye@intel.com"
    },
    "delegate": {
        "id": 319,
        "url": "http://patches.dpdk.org/api/users/319/?format=api",
        "username": "fyigit",
        "first_name": "Ferruh",
        "last_name": "Yigit",
        "email": "ferruh.yigit@amd.com"
    },
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/20190402154653.711-2-xiaolong.ye@intel.com/mbox/",
    "series": [
        {
            "id": 4062,
            "url": "http://patches.dpdk.org/api/series/4062/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=4062",
            "date": "2019-04-02T15:46:52",
            "name": "Introduce AF_XDP PMD",
            "version": 9,
            "mbox": "http://patches.dpdk.org/series/4062/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/52121/comments/",
    "check": "success",
    "checks": "http://patches.dpdk.org/api/patches/52121/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 55B524D3A;\n\tTue,  2 Apr 2019 17:51:55 +0200 (CEST)",
            "from mga14.intel.com (mga14.intel.com [192.55.52.115])\n\tby dpdk.org (Postfix) with ESMTP id 3FE7D4CA9\n\tfor <dev@dpdk.org>; Tue,  2 Apr 2019 17:51:53 +0200 (CEST)",
            "from orsmga006.jf.intel.com ([10.7.209.51])\n\tby fmsmga103.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384;\n\t02 Apr 2019 08:51:52 -0700",
            "from yexl-server.sh.intel.com ([10.67.110.206])\n\tby orsmga006.jf.intel.com with ESMTP; 02 Apr 2019 08:51:49 -0700"
        ],
        "X-Amp-Result": "SKIPPED(no attachment in message)",
        "X-Amp-File-Uploaded": "False",
        "X-ExtLoop1": "1",
        "X-IronPort-AV": "E=Sophos;i=\"5.60,301,1549958400\"; d=\"scan'208\";a=\"132331464\"",
        "From": "Xiaolong Ye <xiaolong.ye@intel.com>",
        "To": "dev@dpdk.org, Stephen Hemminger <stephen@networkplumber.org>,\n\tFerruh Yigit <ferruh.yigit@intel.com>",
        "Cc": "Qi Zhang <qi.z.zhang@intel.com>,\n\tKarlsson Magnus <magnus.karlsson@intel.com>,\n\tTopel Bjorn <bjorn.topel@intel.com>,\n\tMaxime Coquelin <maxime.coquelin@redhat.com>,\n\tLuca Boccassi <bluca@debian.org>,\n\tBruce Richardson <bruce.richardson@intel.com>,\n\tAnanyev Konstantin <konstantin.ananyev@intel.com>,\n\tDavid Marchand <david.marchand@redhat.com>,\n\tAndrew Rybchenko <arybchenko@solarflare.com>,\n\tOlivier Matz <olivier.matz@6wind.com>,\n\tXiaolong Ye <xiaolong.ye@intel.com>",
        "Date": "Tue,  2 Apr 2019 23:46:53 +0800",
        "Message-Id": "<20190402154653.711-2-xiaolong.ye@intel.com>",
        "X-Mailer": "git-send-email 2.17.1",
        "In-Reply-To": "<20190402154653.711-1-xiaolong.ye@intel.com>",
        "References": "<20190301080947.91086-1-xiaolong.ye@intel.com>\n\t<20190402154653.711-1-xiaolong.ye@intel.com>",
        "Subject": "[dpdk-dev] [PATCH v9 1/1] net/af_xdp: introduce AF XDP PMD driver",
        "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": "Add a new PMD driver for AF_XDP which is a proposed faster version of\nAF_PACKET interface in Linux. More info about AF_XDP, please refer to [1]\n[2].\n\nThis is the vanilla version PMD which just uses a raw buffer registered as\nthe umem.\n\n[1] https://fosdem.org/2018/schedule/event/af_xdp/\n[2] https://lwn.net/Articles/745934/\n\nSigned-off-by: Xiaolong Ye <xiaolong.ye@intel.com>\n---\n MAINTAINERS                                   |   7 +\n config/common_base                            |   5 +\n doc/guides/nics/af_xdp.rst                    |  48 +\n doc/guides/nics/features/af_xdp.ini           |  11 +\n doc/guides/nics/index.rst                     |   1 +\n doc/guides/rel_notes/release_19_05.rst        |   7 +\n drivers/net/Makefile                          |   1 +\n drivers/net/af_xdp/Makefile                   |  32 +\n drivers/net/af_xdp/meson.build                |  21 +\n drivers/net/af_xdp/rte_eth_af_xdp.c           | 956 ++++++++++++++++++\n drivers/net/af_xdp/rte_pmd_af_xdp_version.map |   3 +\n drivers/net/meson.build                       |   1 +\n mk/rte.app.mk                                 |   1 +\n 13 files changed, 1094 insertions(+)\n create mode 100644 doc/guides/nics/af_xdp.rst\n create mode 100644 doc/guides/nics/features/af_xdp.ini\n create mode 100644 drivers/net/af_xdp/Makefile\n create mode 100644 drivers/net/af_xdp/meson.build\n create mode 100644 drivers/net/af_xdp/rte_eth_af_xdp.c\n create mode 100644 drivers/net/af_xdp/rte_pmd_af_xdp_version.map",
    "diff": "diff --git a/MAINTAINERS b/MAINTAINERS\nindex e9ff2b4c2..c13ae8215 100644\n--- a/MAINTAINERS\n+++ b/MAINTAINERS\n@@ -479,6 +479,13 @@ M: John W. Linville <linville@tuxdriver.com>\n F: drivers/net/af_packet/\n F: doc/guides/nics/features/afpacket.ini\n \n+Linux AF_XDP\n+M: Xiaolong Ye <xiaolong.ye@intel.com>\n+M: Qi Zhang <qi.z.zhang@intel.com>\n+F: drivers/net/af_xdp/\n+F: doc/guides/nics/af_xdp.rst\n+F: doc/guides/nics/features/af_xdp.ini\n+\n Amazon ENA\n M: Marcin Wojtas <mw@semihalf.com>\n M: Michal Krawczyk <mk@semihalf.com>\ndiff --git a/config/common_base b/config/common_base\nindex 6292bc4af..b95ee03d7 100644\n--- a/config/common_base\n+++ b/config/common_base\n@@ -430,6 +430,11 @@ CONFIG_RTE_LIBRTE_VMXNET3_DEBUG_TX_FREE=n\n #\n CONFIG_RTE_LIBRTE_PMD_AF_PACKET=n\n \n+#\n+# Compile software PMD backed by AF_XDP sockets (Linux only)\n+#\n+CONFIG_RTE_LIBRTE_PMD_AF_XDP=n\n+\n #\n # Compile link bonding PMD library\n #\ndiff --git a/doc/guides/nics/af_xdp.rst b/doc/guides/nics/af_xdp.rst\nnew file mode 100644\nindex 000000000..af675d910\n--- /dev/null\n+++ b/doc/guides/nics/af_xdp.rst\n@@ -0,0 +1,48 @@\n+..  SPDX-License-Identifier: BSD-3-Clause\n+    Copyright(c) 2019 Intel Corporation.\n+\n+AF_XDP Poll Mode Driver\n+==========================\n+\n+AF_XDP is an address family that is optimized for high performance\n+packet processing. AF_XDP sockets enable the possibility for XDP program to\n+redirect packets to a memory buffer in userspace.\n+\n+For the full details behind AF_XDP socket, you can refer to\n+`AF_XDP documentation in the Kernel\n+<https://www.kernel.org/doc/Documentation/networking/af_xdp.rst>`_.\n+\n+This Linux-specific PMD driver creates the AF_XDP socket and binds it to a\n+specific netdev queue, it allows a DPDK application to send and receive raw\n+packets through the socket which would bypass the kernel network stack.\n+Current implementation only supports single queue, multi-queues feature will\n+be added later.\n+\n+Note that MTU of AF_XDP PMD is limited due to XDP lacks support for\n+fragmentation.\n+\n+Options\n+-------\n+\n+The following options can be provided to set up an af_xdp port in DPDK.\n+\n+*   ``iface`` - name of the Kernel interface to attach to (required);\n+*   ``queue`` - netdev queue id (optional, default 0);\n+\n+Prerequisites\n+-------------\n+\n+This is a Linux-specific PMD, thus the following prerequisites apply:\n+\n+*  A Linux Kernel (version > 4.18) with XDP sockets configuration enabled;\n+*  libbpf (within kernel version > 5.1) with latest af_xdp support installed\n+*  A Kernel bound interface to attach to.\n+\n+Set up an af_xdp interface\n+-----------------------------\n+\n+The following example will set up an af_xdp interface in DPDK:\n+\n+.. code-block:: console\n+\n+    --vdev net_af_xdp,iface=ens786f1,queue=0\ndiff --git a/doc/guides/nics/features/af_xdp.ini b/doc/guides/nics/features/af_xdp.ini\nnew file mode 100644\nindex 000000000..36953c2de\n--- /dev/null\n+++ b/doc/guides/nics/features/af_xdp.ini\n@@ -0,0 +1,11 @@\n+;\n+; Supported features of the 'af_xdp' network poll mode driver.\n+;\n+; Refer to default.ini for the full list of available PMD features.\n+;\n+[Features]\n+Link status          = Y\n+MTU update           = Y\n+Promiscuous mode     = Y\n+Stats per queue      = Y\n+x86-64               = Y\ndiff --git a/doc/guides/nics/index.rst b/doc/guides/nics/index.rst\nindex 5c80e3baa..a4b80a3d0 100644\n--- a/doc/guides/nics/index.rst\n+++ b/doc/guides/nics/index.rst\n@@ -12,6 +12,7 @@ Network Interface Controller Drivers\n     features\n     build_and_test\n     af_packet\n+    af_xdp\n     ark\n     atlantic\n     avp\ndiff --git a/doc/guides/rel_notes/release_19_05.rst b/doc/guides/rel_notes/release_19_05.rst\nindex bdad1ddbe..79e36739f 100644\n--- a/doc/guides/rel_notes/release_19_05.rst\n+++ b/doc/guides/rel_notes/release_19_05.rst\n@@ -74,6 +74,13 @@ New Features\n     process.\n   * Added support for Rx packet types list in a secondary process.\n \n+* **Added the AF_XDP PMD.**\n+\n+  Added a Linux-specific PMD driver for AF_XDP, it can create the AF_XDP socket\n+  and bind it to a specific netdev queue, it allows a DPDK application to send\n+  and receive raw packets through the socket which would bypass the kernel\n+  network stack to achieve high performance packet processing.\n+\n * **Updated Mellanox drivers.**\n \n    New features and improvements were done in mlx4 and mlx5 PMDs:\ndiff --git a/drivers/net/Makefile b/drivers/net/Makefile\nindex 502869a87..5d401b8c5 100644\n--- a/drivers/net/Makefile\n+++ b/drivers/net/Makefile\n@@ -9,6 +9,7 @@ ifeq ($(CONFIG_RTE_LIBRTE_THUNDERX_NICVF_PMD),d)\n endif\n \n DIRS-$(CONFIG_RTE_LIBRTE_PMD_AF_PACKET) += af_packet\n+DIRS-$(CONFIG_RTE_LIBRTE_PMD_AF_XDP) += af_xdp\n DIRS-$(CONFIG_RTE_LIBRTE_ARK_PMD) += ark\n DIRS-$(CONFIG_RTE_LIBRTE_ATLANTIC_PMD) += atlantic\n DIRS-$(CONFIG_RTE_LIBRTE_AVP_PMD) += avp\ndiff --git a/drivers/net/af_xdp/Makefile b/drivers/net/af_xdp/Makefile\nnew file mode 100644\nindex 000000000..8343e3016\n--- /dev/null\n+++ b/drivers/net/af_xdp/Makefile\n@@ -0,0 +1,32 @@\n+# SPDX-License-Identifier: BSD-3-Clause\n+# Copyright(c) 2019 Intel Corporation\n+\n+include $(RTE_SDK)/mk/rte.vars.mk\n+\n+#\n+# library name\n+#\n+LIB = librte_pmd_af_xdp.a\n+\n+EXPORT_MAP := rte_pmd_af_xdp_version.map\n+\n+LIBABIVER := 1\n+\n+CFLAGS += -O3\n+\n+# require kernel version >= v5.1-rc1\n+CFLAGS += -I$(RTE_KERNELDIR)/tools/include\n+CFLAGS += -I$(RTE_KERNELDIR)/tools/lib/bpf\n+\n+CFLAGS += $(WERROR_FLAGS)\n+LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ring\n+LDLIBS += -lrte_ethdev -lrte_net -lrte_kvargs\n+LDLIBS += -lrte_bus_vdev\n+LDLIBS += -lbpf\n+\n+#\n+# all source are stored in SRCS-y\n+#\n+SRCS-$(CONFIG_RTE_LIBRTE_PMD_AF_XDP) += rte_eth_af_xdp.c\n+\n+include $(RTE_SDK)/mk/rte.lib.mk\ndiff --git a/drivers/net/af_xdp/meson.build b/drivers/net/af_xdp/meson.build\nnew file mode 100644\nindex 000000000..d40aae190\n--- /dev/null\n+++ b/drivers/net/af_xdp/meson.build\n@@ -0,0 +1,21 @@\n+# SPDX-License-Identifier: BSD-3-Clause\n+# Copyright(c) 2019 Intel Corporation\n+\n+if host_machine.system() != 'linux'\n+\tbuild = false\n+endif\n+\n+bpf_dep = dependency('libbpf', required: false)\n+if bpf_dep.found()\n+\tbuild = true\n+else\n+\tbpf_dep = cc.find_library('libbpf', required: false)\n+\tif bpf_dep.found() and cc.has_header('xsk.h', dependencies: bpf_dep) and cc.has_header('linux/if_xdp.h')\n+\t\tbuild = true\n+\t\tpkgconfig_extra_libs += '-lbpf'\n+\telse\n+\t\tbuild = false\n+\tendif\n+endif\n+sources = files('rte_eth_af_xdp.c')\n+ext_deps += bpf_dep\ndiff --git a/drivers/net/af_xdp/rte_eth_af_xdp.c b/drivers/net/af_xdp/rte_eth_af_xdp.c\nnew file mode 100644\nindex 000000000..628b160a2\n--- /dev/null\n+++ b/drivers/net/af_xdp/rte_eth_af_xdp.c\n@@ -0,0 +1,956 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2019 Intel Corporation.\n+ */\n+#include <unistd.h>\n+#include <errno.h>\n+#include <stdlib.h>\n+#include <string.h>\n+#include <netinet/in.h>\n+#include <net/if.h>\n+#include <bpf/bpf.h>\n+#include <sys/socket.h>\n+#include <sys/ioctl.h>\n+#include <linux/if_ether.h>\n+#include <linux/if_xdp.h>\n+#include <linux/if_link.h>\n+#include <asm/barrier.h>\n+#include <xsk.h>\n+\n+#include <rte_ethdev.h>\n+#include <rte_ethdev_driver.h>\n+#include <rte_ethdev_vdev.h>\n+#include <rte_kvargs.h>\n+#include <rte_bus_vdev.h>\n+#include <rte_string_fns.h>\n+#include <rte_branch_prediction.h>\n+#include <rte_common.h>\n+#include <rte_config.h>\n+#include <rte_dev.h>\n+#include <rte_eal.h>\n+#include <rte_ether.h>\n+#include <rte_lcore.h>\n+#include <rte_log.h>\n+#include <rte_memory.h>\n+#include <rte_memzone.h>\n+#include <rte_mbuf.h>\n+#include <rte_malloc.h>\n+#include <rte_ring.h>\n+\n+#ifndef SOL_XDP\n+#define SOL_XDP 283\n+#endif\n+\n+#ifndef AF_XDP\n+#define AF_XDP 44\n+#endif\n+\n+#ifndef PF_XDP\n+#define PF_XDP AF_XDP\n+#endif\n+\n+static int af_xdp_logtype;\n+\n+#define AF_XDP_LOG(level, fmt, args...)\t\t\t\\\n+\trte_log(RTE_LOG_ ## level, af_xdp_logtype,\t\\\n+\t\t\"%s(): \" fmt, __func__, ##args)\n+\n+#define ETH_AF_XDP_FRAME_SIZE\t\tXSK_UMEM__DEFAULT_FRAME_SIZE\n+#define ETH_AF_XDP_NUM_BUFFERS\t\t4096\n+#define ETH_AF_XDP_DATA_HEADROOM\t0\n+#define ETH_AF_XDP_DFLT_NUM_DESCS\tXSK_RING_CONS__DEFAULT_NUM_DESCS\n+#define ETH_AF_XDP_DFLT_QUEUE_IDX\t0\n+\n+#define ETH_AF_XDP_RX_BATCH_SIZE\t32\n+#define ETH_AF_XDP_TX_BATCH_SIZE\t32\n+\n+#define ETH_AF_XDP_MAX_QUEUE_PAIRS     16\n+\n+struct xsk_umem_info {\n+\tstruct xsk_ring_prod fq;\n+\tstruct xsk_ring_cons cq;\n+\tstruct xsk_umem *umem;\n+\tstruct rte_ring *buf_ring;\n+\tconst struct rte_memzone *mz;\n+};\n+\n+struct rx_stats {\n+\tuint64_t rx_pkts;\n+\tuint64_t rx_bytes;\n+\tuint64_t rx_dropped;\n+};\n+\n+struct pkt_rx_queue {\n+\tstruct xsk_ring_cons rx;\n+\tstruct xsk_umem_info *umem;\n+\tstruct xsk_socket *xsk;\n+\tstruct rte_mempool *mb_pool;\n+\n+\tstruct rx_stats stats;\n+\n+\tstruct pkt_tx_queue *pair;\n+\tuint16_t queue_idx;\n+};\n+\n+struct tx_stats {\n+\tuint64_t tx_pkts;\n+\tuint64_t err_pkts;\n+\tuint64_t tx_bytes;\n+};\n+\n+struct pkt_tx_queue {\n+\tstruct xsk_ring_prod tx;\n+\n+\tstruct tx_stats stats;\n+\n+\tstruct pkt_rx_queue *pair;\n+\tuint16_t queue_idx;\n+};\n+\n+struct pmd_internals {\n+\tint if_index;\n+\tchar if_name[IFNAMSIZ];\n+\tuint16_t queue_idx;\n+\tstruct ether_addr eth_addr;\n+\tstruct xsk_umem_info *umem;\n+\tstruct rte_mempool *mb_pool_share;\n+\n+\tstruct pkt_rx_queue rx_queues[ETH_AF_XDP_MAX_QUEUE_PAIRS];\n+\tstruct pkt_tx_queue tx_queues[ETH_AF_XDP_MAX_QUEUE_PAIRS];\n+};\n+\n+#define ETH_AF_XDP_IFACE_ARG\t\t\t\"iface\"\n+#define ETH_AF_XDP_QUEUE_IDX_ARG\t\t\"queue\"\n+\n+static const char * const valid_arguments[] = {\n+\tETH_AF_XDP_IFACE_ARG,\n+\tETH_AF_XDP_QUEUE_IDX_ARG,\n+\tNULL\n+};\n+\n+static const struct rte_eth_link pmd_link = {\n+\t.link_speed = ETH_SPEED_NUM_10G,\n+\t.link_duplex = ETH_LINK_FULL_DUPLEX,\n+\t.link_status = ETH_LINK_DOWN,\n+\t.link_autoneg = ETH_LINK_AUTONEG\n+};\n+\n+static inline int\n+reserve_fill_queue(struct xsk_umem_info *umem, int reserve_size)\n+{\n+\tstruct xsk_ring_prod *fq = &umem->fq;\n+\tuint32_t idx;\n+\tint i, ret;\n+\n+\tret = xsk_ring_prod__reserve(fq, reserve_size, &idx);\n+\tif (unlikely(!ret)) {\n+\t\tAF_XDP_LOG(ERR, \"Failed to reserve enough fq descs.\\n\");\n+\t\treturn ret;\n+\t}\n+\n+\tfor (i = 0; i < reserve_size; i++) {\n+\t\t__u64 *fq_addr;\n+\t\tvoid *addr = NULL;\n+\t\tif (rte_ring_dequeue(umem->buf_ring, &addr)) {\n+\t\t\ti--;\n+\t\t\tbreak;\n+\t\t}\n+\t\tfq_addr = xsk_ring_prod__fill_addr(fq, idx++);\n+\t\t*fq_addr = (uint64_t)addr;\n+\t}\n+\n+\txsk_ring_prod__submit(fq, i);\n+\n+\treturn 0;\n+}\n+\n+static uint16_t\n+eth_af_xdp_rx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)\n+{\n+\tstruct pkt_rx_queue *rxq = queue;\n+\tstruct xsk_ring_cons *rx = &rxq->rx;\n+\tstruct xsk_umem_info *umem = rxq->umem;\n+\tstruct xsk_ring_prod *fq = &umem->fq;\n+\tuint32_t idx_rx;\n+\tuint32_t free_thresh = fq->size >> 1;\n+\tstruct rte_mbuf *mbufs[ETH_AF_XDP_TX_BATCH_SIZE];\n+\tunsigned long dropped = 0;\n+\tunsigned long rx_bytes = 0;\n+\tuint16_t count = 0;\n+\tint rcvd, i;\n+\n+\tnb_pkts = RTE_MIN(nb_pkts, ETH_AF_XDP_TX_BATCH_SIZE);\n+\n+\trcvd = xsk_ring_cons__peek(rx, nb_pkts, &idx_rx);\n+\tif (rcvd == 0)\n+\t\treturn 0;\n+\n+\tif (xsk_prod_nb_free(fq, free_thresh) >= free_thresh)\n+\t\t(void)reserve_fill_queue(umem, ETH_AF_XDP_RX_BATCH_SIZE);\n+\n+\tif (unlikely(rte_pktmbuf_alloc_bulk(rxq->mb_pool, mbufs, rcvd) != 0))\n+\t\treturn 0;\n+\n+\tfor (i = 0; i < rcvd; i++) {\n+\t\tconst struct xdp_desc *desc;\n+\t\tuint64_t addr;\n+\t\tuint32_t len;\n+\t\tvoid *pkt;\n+\n+\t\tdesc = xsk_ring_cons__rx_desc(rx, idx_rx++);\n+\t\taddr = desc->addr;\n+\t\tlen = desc->len;\n+\t\tpkt = xsk_umem__get_data(rxq->umem->mz->addr, addr);\n+\n+\t\trte_memcpy(rte_pktmbuf_mtod(mbufs[i], void *), pkt, len);\n+\t\trte_pktmbuf_pkt_len(mbufs[i]) = len;\n+\t\trte_pktmbuf_data_len(mbufs[i]) = len;\n+\t\trx_bytes += len;\n+\t\tbufs[count++] = mbufs[i];\n+\n+\t\trte_ring_enqueue(umem->buf_ring, (void *)addr);\n+\t}\n+\n+\txsk_ring_cons__release(rx, rcvd);\n+\n+\t/* statistics */\n+\trxq->stats.rx_pkts += (rcvd - dropped);\n+\trxq->stats.rx_bytes += rx_bytes;\n+\n+\treturn count;\n+}\n+\n+static void\n+pull_umem_cq(struct xsk_umem_info *umem, int size)\n+{\n+\tstruct xsk_ring_cons *cq = &umem->cq;\n+\tsize_t i, n;\n+\tuint32_t idx_cq;\n+\n+\tn = xsk_ring_cons__peek(cq, size, &idx_cq);\n+\n+\tfor (i = 0; i < n; i++) {\n+\t\tuint64_t addr;\n+\t\taddr = *xsk_ring_cons__comp_addr(cq, idx_cq++);\n+\t\trte_ring_enqueue(umem->buf_ring, (void *)addr);\n+\t}\n+\n+\txsk_ring_cons__release(cq, n);\n+}\n+\n+static void\n+kick_tx(struct pkt_tx_queue *txq)\n+{\n+\tstruct xsk_umem_info *umem = txq->pair->umem;\n+\n+\twhile (send(xsk_socket__fd(txq->pair->xsk), NULL,\n+\t\t      0, MSG_DONTWAIT) < 0) {\n+\t\t/* some thing unexpected */\n+\t\tif (errno != EBUSY && errno != EAGAIN && errno != EINTR)\n+\t\t\tbreak;\n+\n+\t\t/* pull from complete qeueu to leave more space */\n+\t\tif (errno == EAGAIN)\n+\t\t\tpull_umem_cq(umem, ETH_AF_XDP_TX_BATCH_SIZE);\n+\t}\n+\tpull_umem_cq(umem, ETH_AF_XDP_TX_BATCH_SIZE);\n+}\n+\n+static uint16_t\n+eth_af_xdp_tx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)\n+{\n+\tstruct pkt_tx_queue *txq = queue;\n+\tstruct xsk_umem_info *umem = txq->pair->umem;\n+\tstruct rte_mbuf *mbuf;\n+\tvoid *addrs[ETH_AF_XDP_TX_BATCH_SIZE];\n+\tunsigned long tx_bytes = 0;\n+\tint i, valid = 0;\n+\tuint32_t idx_tx;\n+\n+\tnb_pkts = RTE_MIN(nb_pkts, ETH_AF_XDP_TX_BATCH_SIZE);\n+\n+\tpull_umem_cq(umem, nb_pkts);\n+\n+\tnb_pkts = rte_ring_dequeue_bulk(umem->buf_ring, addrs,\n+\t\t\t\t\tnb_pkts, NULL);\n+\tif (nb_pkts == 0)\n+\t\treturn 0;\n+\n+\tif (xsk_ring_prod__reserve(&txq->tx, nb_pkts, &idx_tx) != nb_pkts) {\n+\t\tkick_tx(txq);\n+\t\treturn 0;\n+\t}\n+\n+\tfor (i = 0; i < nb_pkts; i++) {\n+\t\tstruct xdp_desc *desc;\n+\t\tvoid *pkt;\n+\t\tuint32_t buf_len = ETH_AF_XDP_FRAME_SIZE\n+\t\t\t\t\t- ETH_AF_XDP_DATA_HEADROOM;\n+\t\tdesc = xsk_ring_prod__tx_desc(&txq->tx, idx_tx + i);\n+\t\tmbuf = bufs[i];\n+\t\tif (mbuf->pkt_len <= buf_len) {\n+\t\t\tdesc->addr = (uint64_t)addrs[valid];\n+\t\t\tdesc->len = mbuf->pkt_len;\n+\t\t\tpkt = xsk_umem__get_data(umem->mz->addr,\n+\t\t\t\t\t\t desc->addr);\n+\t\t\trte_memcpy(pkt, rte_pktmbuf_mtod(mbuf, void *),\n+\t\t\t       desc->len);\n+\t\t\tvalid++;\n+\t\t\ttx_bytes += mbuf->pkt_len;\n+\t\t}\n+\t\trte_pktmbuf_free(mbuf);\n+\t}\n+\n+\txsk_ring_prod__submit(&txq->tx, nb_pkts);\n+\n+\tkick_tx(txq);\n+\n+\tif (valid < nb_pkts)\n+\t\trte_ring_enqueue_bulk(umem->buf_ring, &addrs[valid],\n+\t\t\t\t nb_pkts - valid, NULL);\n+\n+\ttxq->stats.err_pkts += nb_pkts - valid;\n+\ttxq->stats.tx_pkts += valid;\n+\ttxq->stats.tx_bytes += tx_bytes;\n+\n+\treturn nb_pkts;\n+}\n+\n+static int\n+eth_dev_start(struct rte_eth_dev *dev)\n+{\n+\tdev->data->dev_link.link_status = ETH_LINK_UP;\n+\n+\treturn 0;\n+}\n+\n+/* This function gets called when the current port gets stopped. */\n+static void\n+eth_dev_stop(struct rte_eth_dev *dev)\n+{\n+\tdev->data->dev_link.link_status = ETH_LINK_DOWN;\n+}\n+\n+static int\n+eth_dev_configure(struct rte_eth_dev *dev)\n+{\n+\t/* rx/tx must be paired */\n+\tif (dev->data->nb_rx_queues != dev->data->nb_tx_queues)\n+\t\treturn -EINVAL;\n+\n+\treturn 0;\n+}\n+\n+static void\n+eth_dev_info(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)\n+{\n+\tstruct pmd_internals *internals = dev->data->dev_private;\n+\n+\tdev_info->if_index = internals->if_index;\n+\tdev_info->max_mac_addrs = 1;\n+\tdev_info->max_rx_pktlen = ETH_FRAME_LEN;\n+\tdev_info->max_rx_queues = 1;\n+\tdev_info->max_tx_queues = 1;\n+\n+\tdev_info->default_rxportconf.nb_queues = 1;\n+\tdev_info->default_txportconf.nb_queues = 1;\n+\tdev_info->default_rxportconf.ring_size = ETH_AF_XDP_DFLT_NUM_DESCS;\n+\tdev_info->default_txportconf.ring_size = ETH_AF_XDP_DFLT_NUM_DESCS;\n+}\n+\n+static int\n+eth_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)\n+{\n+\tstruct pmd_internals *internals = dev->data->dev_private;\n+\tstruct xdp_statistics xdp_stats;\n+\tstruct pkt_rx_queue *rxq;\n+\tsocklen_t optlen;\n+\tint i, ret;\n+\n+\tfor (i = 0; i < dev->data->nb_rx_queues; i++) {\n+\t\toptlen = sizeof(struct xdp_statistics);\n+\t\trxq = &internals->rx_queues[i];\n+\t\tstats->q_ipackets[i] = internals->rx_queues[i].stats.rx_pkts;\n+\t\tstats->q_ibytes[i] = internals->rx_queues[i].stats.rx_bytes;\n+\n+\t\tstats->q_opackets[i] = internals->tx_queues[i].stats.tx_pkts;\n+\t\tstats->q_obytes[i] = internals->tx_queues[i].stats.tx_bytes;\n+\n+\t\tstats->ipackets += stats->q_ipackets[i];\n+\t\tstats->ibytes += stats->q_ibytes[i];\n+\t\tstats->imissed += internals->rx_queues[i].stats.rx_dropped;\n+\t\tret = getsockopt(xsk_socket__fd(rxq->xsk), SOL_XDP,\n+\t\t\t\tXDP_STATISTICS, &xdp_stats, &optlen);\n+\t\tif (ret != 0) {\n+\t\t\tAF_XDP_LOG(ERR, \"getsockopt() failed for XDP_STATISTICS.\\n\");\n+\t\t\treturn -1;\n+\t\t}\n+\t\tstats->imissed += xdp_stats.rx_dropped;\n+\n+\t\tstats->opackets += stats->q_opackets[i];\n+\t\tstats->oerrors += internals->tx_queues[i].stats.err_pkts;\n+\t\tstats->obytes += stats->q_obytes[i];\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static void\n+eth_stats_reset(struct rte_eth_dev *dev)\n+{\n+\tstruct pmd_internals *internals = dev->data->dev_private;\n+\tint i;\n+\n+\tfor (i = 0; i < ETH_AF_XDP_MAX_QUEUE_PAIRS; i++) {\n+\t\tmemset(&internals->rx_queues[i].stats, 0,\n+\t\t\t\t\tsizeof(struct rx_stats));\n+\t\tmemset(&internals->tx_queues[i].stats, 0,\n+\t\t\t\t\tsizeof(struct tx_stats));\n+\t}\n+}\n+\n+static void\n+remove_xdp_program(struct pmd_internals *internals)\n+{\n+\tuint32_t curr_prog_id = 0;\n+\n+\tif (bpf_get_link_xdp_id(internals->if_index, &curr_prog_id,\n+\t\t\t\tXDP_FLAGS_UPDATE_IF_NOEXIST)) {\n+\t\tAF_XDP_LOG(ERR, \"bpf_get_link_xdp_id failed\\n\");\n+\t\treturn;\n+\t}\n+\tbpf_set_link_xdp_fd(internals->if_index, -1,\n+\t\t\tXDP_FLAGS_UPDATE_IF_NOEXIST);\n+}\n+\n+static void\n+eth_dev_close(struct rte_eth_dev *dev)\n+{\n+\tstruct pmd_internals *internals = dev->data->dev_private;\n+\tstruct pkt_rx_queue *rxq;\n+\tint i;\n+\n+\tAF_XDP_LOG(INFO, \"Closing AF_XDP ethdev on numa socket %u\\n\",\n+\t\trte_socket_id());\n+\n+\tfor (i = 0; i < ETH_AF_XDP_MAX_QUEUE_PAIRS; i++) {\n+\t\trxq = &internals->rx_queues[i];\n+\t\tif (rxq->umem == NULL)\n+\t\t\tbreak;\n+\t\txsk_socket__delete(rxq->xsk);\n+\t}\n+\n+\t(void)xsk_umem__delete(internals->umem->umem);\n+\tremove_xdp_program(internals);\n+}\n+\n+static void\n+eth_queue_release(void *q __rte_unused)\n+{\n+}\n+\n+static int\n+eth_link_update(struct rte_eth_dev *dev __rte_unused,\n+\t\tint wait_to_complete __rte_unused)\n+{\n+\treturn 0;\n+}\n+\n+static void\n+xdp_umem_destroy(struct xsk_umem_info *umem)\n+{\n+\trte_memzone_free(umem->mz);\n+\tumem->mz = NULL;\n+\n+\trte_ring_free(umem->buf_ring);\n+\tumem->buf_ring = NULL;\n+\n+\trte_free(umem);\n+\tumem = NULL;\n+}\n+\n+static struct\n+xsk_umem_info *xdp_umem_configure(void)\n+{\n+\tstruct xsk_umem_info *umem;\n+\tconst struct rte_memzone *mz;\n+\tstruct xsk_umem_config usr_config = {\n+\t\t.fill_size = ETH_AF_XDP_DFLT_NUM_DESCS,\n+\t\t.comp_size = ETH_AF_XDP_DFLT_NUM_DESCS,\n+\t\t.frame_size = ETH_AF_XDP_FRAME_SIZE,\n+\t\t.frame_headroom = ETH_AF_XDP_DATA_HEADROOM };\n+\tint ret;\n+\tuint64_t i;\n+\n+\tumem = rte_zmalloc_socket(\"umem\", sizeof(*umem), 0, rte_socket_id());\n+\tif (umem == NULL) {\n+\t\tAF_XDP_LOG(ERR, \"Failed to allocate umem info\");\n+\t\treturn NULL;\n+\t}\n+\n+\tumem->buf_ring = rte_ring_create(\"af_xdp_ring\",\n+\t\t\t\t\t ETH_AF_XDP_NUM_BUFFERS,\n+\t\t\t\t\t rte_socket_id(),\n+\t\t\t\t\t 0x0);\n+\tif (umem->buf_ring == NULL) {\n+\t\tAF_XDP_LOG(ERR, \"Failed to create rte_ring\\n\");\n+\t\tgoto err;\n+\t}\n+\n+\tfor (i = 0; i < ETH_AF_XDP_NUM_BUFFERS; i++)\n+\t\trte_ring_enqueue(umem->buf_ring,\n+\t\t\t\t (void *)(i * ETH_AF_XDP_FRAME_SIZE +\n+\t\t\t\t\t  ETH_AF_XDP_DATA_HEADROOM));\n+\n+\tmz = rte_memzone_reserve_aligned(\"af_xdp uemem\",\n+\t\t\tETH_AF_XDP_NUM_BUFFERS * ETH_AF_XDP_FRAME_SIZE,\n+\t\t\trte_socket_id(), RTE_MEMZONE_IOVA_CONTIG,\n+\t\t\tgetpagesize());\n+\tif (mz == NULL) {\n+\t\tAF_XDP_LOG(ERR, \"Failed to reserve memzone for af_xdp umem.\\n\");\n+\t\tgoto err;\n+\t}\n+\n+\tret = xsk_umem__create(&umem->umem, mz->addr,\n+\t\t\t       ETH_AF_XDP_NUM_BUFFERS * ETH_AF_XDP_FRAME_SIZE,\n+\t\t\t       &umem->fq, &umem->cq,\n+\t\t\t       &usr_config);\n+\n+\tif (ret) {\n+\t\tAF_XDP_LOG(ERR, \"Failed to create umem\");\n+\t\tgoto err;\n+\t}\n+\tumem->mz = mz;\n+\n+\treturn umem;\n+\n+err:\n+\txdp_umem_destroy(umem);\n+\treturn NULL;\n+}\n+\n+static int\n+xsk_configure(struct pmd_internals *internals, struct pkt_rx_queue *rxq,\n+\t      int ring_size)\n+{\n+\tstruct xsk_socket_config cfg;\n+\tstruct pkt_tx_queue *txq = rxq->pair;\n+\tint ret = 0;\n+\tint reserve_size;\n+\n+\trxq->umem = xdp_umem_configure();\n+\tif (rxq->umem == NULL)\n+\t\treturn -ENOMEM;\n+\n+\tcfg.rx_size = ring_size;\n+\tcfg.tx_size = ring_size;\n+\tcfg.libbpf_flags = 0;\n+\tcfg.xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST;\n+\tcfg.bind_flags = 0;\n+\tret = xsk_socket__create(&rxq->xsk, internals->if_name,\n+\t\t\tinternals->queue_idx, rxq->umem->umem, &rxq->rx,\n+\t\t\t&txq->tx, &cfg);\n+\tif (ret) {\n+\t\tAF_XDP_LOG(ERR, \"Failed to create xsk socket.\\n\");\n+\t\tgoto err;\n+\t}\n+\n+\treserve_size = ETH_AF_XDP_DFLT_NUM_DESCS / 2;\n+\tret = reserve_fill_queue(rxq->umem, reserve_size);\n+\tif (ret) {\n+\t\txsk_socket__delete(rxq->xsk);\n+\t\tAF_XDP_LOG(ERR, \"Failed to reserve fill queue.\\n\");\n+\t\tgoto err;\n+\t}\n+\n+\treturn 0;\n+\n+err:\n+\txdp_umem_destroy(rxq->umem);\n+\n+\treturn ret;\n+}\n+\n+static void\n+queue_reset(struct pmd_internals *internals, uint16_t queue_idx)\n+{\n+\tstruct pkt_rx_queue *rxq = &internals->rx_queues[queue_idx];\n+\tstruct pkt_tx_queue *txq = rxq->pair;\n+\n+\tmemset(rxq, 0, sizeof(*rxq));\n+\tmemset(txq, 0, sizeof(*txq));\n+\trxq->pair = txq;\n+\ttxq->pair = rxq;\n+\trxq->queue_idx = queue_idx;\n+\ttxq->queue_idx = queue_idx;\n+}\n+\n+static int\n+eth_rx_queue_setup(struct rte_eth_dev *dev,\n+\t\t   uint16_t rx_queue_id,\n+\t\t   uint16_t nb_rx_desc,\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 *internals = dev->data->dev_private;\n+\tuint32_t buf_size, data_size;\n+\tstruct pkt_rx_queue *rxq;\n+\tint ret;\n+\n+\trxq = &internals->rx_queues[rx_queue_id];\n+\tqueue_reset(internals, rx_queue_id);\n+\n+\t/* Now get the space available for data in the mbuf */\n+\tbuf_size = rte_pktmbuf_data_room_size(mb_pool) -\n+\t\tRTE_PKTMBUF_HEADROOM;\n+\tdata_size = ETH_AF_XDP_FRAME_SIZE - ETH_AF_XDP_DATA_HEADROOM;\n+\n+\tif (data_size > buf_size) {\n+\t\tAF_XDP_LOG(ERR, \"%s: %d bytes will not fit in mbuf (%d bytes)\\n\",\n+\t\t\tdev->device->name, data_size, buf_size);\n+\t\tret = -ENOMEM;\n+\t\tgoto err;\n+\t}\n+\n+\trxq->mb_pool = mb_pool;\n+\n+\tif (xsk_configure(internals, rxq, nb_rx_desc)) {\n+\t\tAF_XDP_LOG(ERR, \"Failed to configure xdp socket\\n\");\n+\t\tret = -EINVAL;\n+\t\tgoto err;\n+\t}\n+\n+\tinternals->umem = rxq->umem;\n+\n+\tdev->data->rx_queues[rx_queue_id] = rxq;\n+\treturn 0;\n+\n+err:\n+\tqueue_reset(internals, rx_queue_id);\n+\treturn ret;\n+}\n+\n+static int\n+eth_tx_queue_setup(struct rte_eth_dev *dev,\n+\t\t   uint16_t tx_queue_id,\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 *internals = dev->data->dev_private;\n+\tstruct pkt_tx_queue *txq;\n+\n+\ttxq = &internals->tx_queues[tx_queue_id];\n+\n+\tdev->data->tx_queues[tx_queue_id] = txq;\n+\treturn 0;\n+}\n+\n+static int\n+eth_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)\n+{\n+\tstruct pmd_internals *internals = dev->data->dev_private;\n+\tstruct ifreq ifr = { .ifr_mtu = mtu };\n+\tint ret;\n+\tint s;\n+\n+\ts = socket(PF_INET, SOCK_DGRAM, 0);\n+\tif (s < 0)\n+\t\treturn -EINVAL;\n+\n+\tstrlcpy(ifr.ifr_name, internals->if_name, IFNAMSIZ);\n+\tret = ioctl(s, SIOCSIFMTU, &ifr);\n+\tclose(s);\n+\n+\treturn (ret < 0) ? -errno : 0;\n+}\n+\n+static void\n+eth_dev_change_flags(char *if_name, uint32_t flags, uint32_t mask)\n+{\n+\tstruct ifreq ifr;\n+\tint s;\n+\n+\ts = socket(PF_INET, SOCK_DGRAM, 0);\n+\tif (s < 0)\n+\t\treturn;\n+\n+\tstrlcpy(ifr.ifr_name, if_name, IFNAMSIZ);\n+\tif (ioctl(s, SIOCGIFFLAGS, &ifr) < 0)\n+\t\tgoto out;\n+\tifr.ifr_flags &= mask;\n+\tifr.ifr_flags |= flags;\n+\tif (ioctl(s, SIOCSIFFLAGS, &ifr) < 0)\n+\t\tgoto out;\n+out:\n+\tclose(s);\n+}\n+\n+static void\n+eth_dev_promiscuous_enable(struct rte_eth_dev *dev)\n+{\n+\tstruct pmd_internals *internals = dev->data->dev_private;\n+\n+\teth_dev_change_flags(internals->if_name, IFF_PROMISC, ~0);\n+}\n+\n+static void\n+eth_dev_promiscuous_disable(struct rte_eth_dev *dev)\n+{\n+\tstruct pmd_internals *internals = dev->data->dev_private;\n+\n+\teth_dev_change_flags(internals->if_name, 0, ~IFF_PROMISC);\n+}\n+\n+static const struct eth_dev_ops ops = {\n+\t.dev_start = eth_dev_start,\n+\t.dev_stop = eth_dev_stop,\n+\t.dev_close = eth_dev_close,\n+\t.dev_configure = eth_dev_configure,\n+\t.dev_infos_get = eth_dev_info,\n+\t.mtu_set = eth_dev_mtu_set,\n+\t.promiscuous_enable = eth_dev_promiscuous_enable,\n+\t.promiscuous_disable = eth_dev_promiscuous_disable,\n+\t.rx_queue_setup = eth_rx_queue_setup,\n+\t.tx_queue_setup = eth_tx_queue_setup,\n+\t.rx_queue_release = eth_queue_release,\n+\t.tx_queue_release = eth_queue_release,\n+\t.link_update = eth_link_update,\n+\t.stats_get = eth_stats_get,\n+\t.stats_reset = eth_stats_reset,\n+};\n+\n+/** parse integer from integer argument */\n+static int\n+parse_integer_arg(const char *key __rte_unused,\n+\t\t  const char *value, void *extra_args)\n+{\n+\tint *i = (int *)extra_args;\n+\tchar *end;\n+\n+\t*i = strtol(value, &end, 10);\n+\tif (*i < 0) {\n+\t\tAF_XDP_LOG(ERR, \"Argument has to be positive.\\n\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+/** parse name argument */\n+static int\n+parse_name_arg(const char *key __rte_unused,\n+\t       const char *value, void *extra_args)\n+{\n+\tchar *name = extra_args;\n+\n+\tif (strnlen(value, IFNAMSIZ) > IFNAMSIZ - 1) {\n+\t\tAF_XDP_LOG(ERR, \"Invalid name %s, should be less than %u bytes.\\n\",\n+\t\t\t   value, IFNAMSIZ);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tstrlcpy(name, value, IFNAMSIZ);\n+\n+\treturn 0;\n+}\n+\n+static int\n+parse_parameters(struct rte_kvargs *kvlist,\n+\t\t char *if_name,\n+\t\t int *queue_idx)\n+{\n+\tint ret;\n+\n+\tret = rte_kvargs_process(kvlist, ETH_AF_XDP_IFACE_ARG,\n+\t\t\t\t &parse_name_arg, if_name);\n+\tif (ret < 0)\n+\t\tgoto free_kvlist;\n+\n+\tret = rte_kvargs_process(kvlist, ETH_AF_XDP_QUEUE_IDX_ARG,\n+\t\t\t\t &parse_integer_arg, queue_idx);\n+\tif (ret < 0)\n+\t\tgoto free_kvlist;\n+\n+free_kvlist:\n+\trte_kvargs_free(kvlist);\n+\treturn ret;\n+}\n+\n+static int\n+get_iface_info(const char *if_name,\n+\t       struct ether_addr *eth_addr,\n+\t       int *if_index)\n+{\n+\tstruct ifreq ifr;\n+\tint sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);\n+\n+\tif (sock < 0)\n+\t\treturn -1;\n+\n+\tstrlcpy(ifr.ifr_name, if_name, IFNAMSIZ);\n+\tif (ioctl(sock, SIOCGIFINDEX, &ifr))\n+\t\tgoto error;\n+\n+\t*if_index = ifr.ifr_ifindex;\n+\n+\tif (ioctl(sock, SIOCGIFHWADDR, &ifr))\n+\t\tgoto error;\n+\n+\trte_memcpy(eth_addr, ifr.ifr_hwaddr.sa_data, ETHER_ADDR_LEN);\n+\n+\tclose(sock);\n+\treturn 0;\n+\n+error:\n+\tclose(sock);\n+\treturn -1;\n+}\n+\n+static struct rte_eth_dev *\n+init_internals(struct rte_vdev_device *dev,\n+\t       const char *if_name,\n+\t       int queue_idx)\n+{\n+\tconst char *name = rte_vdev_device_name(dev);\n+\tconst unsigned int numa_node = dev->device.numa_node;\n+\tstruct pmd_internals *internals;\n+\tstruct rte_eth_dev *eth_dev;\n+\tint ret;\n+\tint i;\n+\n+\tinternals = rte_zmalloc_socket(name, sizeof(*internals), 0, numa_node);\n+\tif (internals == NULL)\n+\t\treturn NULL;\n+\n+\tinternals->queue_idx = queue_idx;\n+\tstrlcpy(internals->if_name, if_name, IFNAMSIZ);\n+\n+\tfor (i = 0; i < ETH_AF_XDP_MAX_QUEUE_PAIRS; i++) {\n+\t\tinternals->tx_queues[i].pair = &internals->rx_queues[i];\n+\t\tinternals->rx_queues[i].pair = &internals->tx_queues[i];\n+\t}\n+\n+\tret = get_iface_info(if_name, &internals->eth_addr,\n+\t\t\t     &internals->if_index);\n+\tif (ret)\n+\t\tgoto err;\n+\n+\teth_dev = rte_eth_vdev_allocate(dev, 0);\n+\tif (eth_dev == NULL)\n+\t\tgoto err;\n+\n+\teth_dev->data->dev_private = internals;\n+\teth_dev->data->dev_link = pmd_link;\n+\teth_dev->data->mac_addrs = &internals->eth_addr;\n+\teth_dev->dev_ops = &ops;\n+\teth_dev->rx_pkt_burst = eth_af_xdp_rx;\n+\teth_dev->tx_pkt_burst = eth_af_xdp_tx;\n+\n+\treturn eth_dev;\n+\n+err:\n+\trte_free(internals);\n+\treturn NULL;\n+}\n+\n+static int\n+rte_pmd_af_xdp_probe(struct rte_vdev_device *dev)\n+{\n+\tstruct rte_kvargs *kvlist;\n+\tchar if_name[IFNAMSIZ] = {'\\0'};\n+\tint xsk_queue_idx = ETH_AF_XDP_DFLT_QUEUE_IDX;\n+\tstruct rte_eth_dev *eth_dev = NULL;\n+\tconst char *name;\n+\n+\tAF_XDP_LOG(INFO, \"Initializing pmd_af_xdp for %s\\n\",\n+\t\trte_vdev_device_name(dev));\n+\n+\tname = rte_vdev_device_name(dev);\n+\tif (rte_eal_process_type() == RTE_PROC_SECONDARY &&\n+\t\tstrlen(rte_vdev_device_args(dev)) == 0) {\n+\t\teth_dev = rte_eth_dev_attach_secondary(name);\n+\t\tif (eth_dev == NULL) {\n+\t\t\tAF_XDP_LOG(ERR, \"Failed to probe %s\\n\", name);\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\t\teth_dev->dev_ops = &ops;\n+\t\trte_eth_dev_probing_finish(eth_dev);\n+\t\treturn 0;\n+\t}\n+\n+\tkvlist = rte_kvargs_parse(rte_vdev_device_args(dev), valid_arguments);\n+\tif (kvlist == NULL) {\n+\t\tAF_XDP_LOG(ERR, \"Invalid kvargs key\\n\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (dev->device.numa_node == SOCKET_ID_ANY)\n+\t\tdev->device.numa_node = rte_socket_id();\n+\n+\tif (parse_parameters(kvlist, if_name, &xsk_queue_idx) < 0) {\n+\t\tAF_XDP_LOG(ERR, \"Invalid kvargs value\\n\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (strlen(if_name) == 0) {\n+\t\tAF_XDP_LOG(ERR, \"Network interface must be specified\\n\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\teth_dev = init_internals(dev, if_name, xsk_queue_idx);\n+\tif (eth_dev == NULL) {\n+\t\tAF_XDP_LOG(ERR, \"Failed to init internals\\n\");\n+\t\treturn -1;\n+\t}\n+\n+\trte_eth_dev_probing_finish(eth_dev);\n+\n+\treturn 0;\n+}\n+\n+static int\n+rte_pmd_af_xdp_remove(struct rte_vdev_device *dev)\n+{\n+\tstruct rte_eth_dev *eth_dev = NULL;\n+\tstruct pmd_internals *internals;\n+\n+\tAF_XDP_LOG(INFO, \"Removing AF_XDP ethdev on numa socket %u\\n\",\n+\t\trte_socket_id());\n+\n+\tif (dev == NULL)\n+\t\treturn -1;\n+\n+\t/* find the ethdev entry */\n+\teth_dev = rte_eth_dev_allocated(rte_vdev_device_name(dev));\n+\tif (eth_dev == NULL)\n+\t\treturn -1;\n+\n+\tinternals = eth_dev->data->dev_private;\n+\n+\trte_ring_free(internals->umem->buf_ring);\n+\trte_memzone_free(internals->umem->mz);\n+\trte_free(internals->umem);\n+\n+\trte_eth_dev_release_port(eth_dev);\n+\n+\n+\treturn 0;\n+}\n+\n+static struct rte_vdev_driver pmd_af_xdp_drv = {\n+\t.probe = rte_pmd_af_xdp_probe,\n+\t.remove = rte_pmd_af_xdp_remove,\n+};\n+\n+RTE_PMD_REGISTER_VDEV(net_af_xdp, pmd_af_xdp_drv);\n+RTE_PMD_REGISTER_PARAM_STRING(net_af_xdp,\n+\t\t\t      \"iface=<string> \"\n+\t\t\t      \"queue=<int> \");\n+\n+RTE_INIT(af_xdp_init_log)\n+{\n+\taf_xdp_logtype = rte_log_register(\"pmd.net.af_xdp\");\n+\tif (af_xdp_logtype >= 0)\n+\t\trte_log_set_level(af_xdp_logtype, RTE_LOG_NOTICE);\n+}\ndiff --git a/drivers/net/af_xdp/rte_pmd_af_xdp_version.map b/drivers/net/af_xdp/rte_pmd_af_xdp_version.map\nnew file mode 100644\nindex 000000000..c6db030fe\n--- /dev/null\n+++ b/drivers/net/af_xdp/rte_pmd_af_xdp_version.map\n@@ -0,0 +1,3 @@\n+DPDK_19.05 {\n+\tlocal: *;\n+};\ndiff --git a/drivers/net/meson.build b/drivers/net/meson.build\nindex 3ecc78cee..1105e72d8 100644\n--- a/drivers/net/meson.build\n+++ b/drivers/net/meson.build\n@@ -2,6 +2,7 @@\n # Copyright(c) 2017 Intel Corporation\n \n drivers = ['af_packet',\n+\t'af_xdp',\n \t'ark',\n \t'atlantic',\n \t'avp',\ndiff --git a/mk/rte.app.mk b/mk/rte.app.mk\nindex 262132fc6..f916bc9ef 100644\n--- a/mk/rte.app.mk\n+++ b/mk/rte.app.mk\n@@ -143,6 +143,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_DPAA2_MEMPOOL)  += -lrte_mempool_dpaa2\n endif\n \n _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_AF_PACKET)  += -lrte_pmd_af_packet\n+_LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_AF_XDP)     += -lrte_pmd_af_xdp -lbpf\n _LDLIBS-$(CONFIG_RTE_LIBRTE_ARK_PMD)        += -lrte_pmd_ark\n _LDLIBS-$(CONFIG_RTE_LIBRTE_ATLANTIC_PMD)   += -lrte_pmd_atlantic\n _LDLIBS-$(CONFIG_RTE_LIBRTE_AVP_PMD)        += -lrte_pmd_avp\n",
    "prefixes": [
        "v9",
        "1/1"
    ]
}