get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 45023,
    "url": "http://patches.dpdk.org/api/patches/45023/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/665a207254fdcf2a86dd371f78e7c15c3f9ed298.1537443103.git.anatoly.burakov@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": "<665a207254fdcf2a86dd371f78e7c15c3f9ed298.1537443103.git.anatoly.burakov@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/665a207254fdcf2a86dd371f78e7c15c3f9ed298.1537443103.git.anatoly.burakov@intel.com",
    "date": "2018-09-20T11:36:30",
    "name": "[v3,17/20] examples: add external memory example app",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "19f20fbac58e1669481f9ebf7d2c54c6e31ab35d",
    "submitter": {
        "id": 4,
        "url": "http://patches.dpdk.org/api/people/4/?format=api",
        "name": "Burakov, Anatoly",
        "email": "anatoly.burakov@intel.com"
    },
    "delegate": {
        "id": 1,
        "url": "http://patches.dpdk.org/api/users/1/?format=api",
        "username": "tmonjalo",
        "first_name": "Thomas",
        "last_name": "Monjalon",
        "email": "thomas@monjalon.net"
    },
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/665a207254fdcf2a86dd371f78e7c15c3f9ed298.1537443103.git.anatoly.burakov@intel.com/mbox/",
    "series": [
        {
            "id": 1415,
            "url": "http://patches.dpdk.org/api/series/1415/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=1415",
            "date": "2018-09-20T11:36:13",
            "name": "Support externally allocated memory in DPDK",
            "version": 3,
            "mbox": "http://patches.dpdk.org/series/1415/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/45023/comments/",
    "check": "success",
    "checks": "http://patches.dpdk.org/api/patches/45023/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 850481B13D;\n\tThu, 20 Sep 2018 13:37:24 +0200 (CEST)",
            "from mga07.intel.com (mga07.intel.com [134.134.136.100])\n\tby dpdk.org (Postfix) with ESMTP id 352BC7CCA\n\tfor <dev@dpdk.org>; Thu, 20 Sep 2018 13:36:53 +0200 (CEST)",
            "from orsmga001.jf.intel.com ([10.7.209.18])\n\tby orsmga105.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384;\n\t20 Sep 2018 04:36:53 -0700",
            "from irvmail001.ir.intel.com ([163.33.26.43])\n\tby orsmga001.jf.intel.com with ESMTP; 20 Sep 2018 04:36:41 -0700",
            "from sivswdev01.ir.intel.com (sivswdev01.ir.intel.com\n\t[10.237.217.45])\n\tby irvmail001.ir.intel.com (8.14.3/8.13.6/MailSET/Hub) with ESMTP id\n\tw8KBafUO022846; Thu, 20 Sep 2018 12:36:41 +0100",
            "from sivswdev01.ir.intel.com (localhost [127.0.0.1])\n\tby sivswdev01.ir.intel.com with ESMTP id w8KBaec4011586;\n\tThu, 20 Sep 2018 12:36:40 +0100",
            "(from aburakov@localhost)\n\tby sivswdev01.ir.intel.com with LOCAL id w8KBae2p011582;\n\tThu, 20 Sep 2018 12:36:40 +0100"
        ],
        "X-Amp-Result": "SKIPPED(no attachment in message)",
        "X-Amp-File-Uploaded": "False",
        "X-ExtLoop1": "1",
        "X-IronPort-AV": "E=Sophos;i=\"5.53,398,1531810800\"; d=\"scan'208\";a=\"92199771\"",
        "From": "Anatoly Burakov <anatoly.burakov@intel.com>",
        "To": "dev@dpdk.org",
        "Cc": "laszlo.madarassy@ericsson.com, laszlo.vadkerti@ericsson.com,\n\tandras.kovacs@ericsson.com, winnie.tian@ericsson.com,\n\tdaniel.andrasi@ericsson.com, janos.kobor@ericsson.com,\n\tgeza.koblo@ericsson.com, srinath.mannam@broadcom.com,\n\tscott.branden@broadcom.com, ajit.khaparde@broadcom.com,\n\tkeith.wiles@intel.com, bruce.richardson@intel.com, thomas@monjalon.net,\n\tshreyansh.jain@nxp.com, shahafs@mellanox.com, arybchenko@solarflare.com",
        "Date": "Thu, 20 Sep 2018 12:36:30 +0100",
        "Message-Id": "<665a207254fdcf2a86dd371f78e7c15c3f9ed298.1537443103.git.anatoly.burakov@intel.com>",
        "X-Mailer": "git-send-email 1.7.0.7",
        "In-Reply-To": [
            "<cover.1537443103.git.anatoly.burakov@intel.com>",
            "<cover.1537443103.git.anatoly.burakov@intel.com>"
        ],
        "References": [
            "<cover.1537443103.git.anatoly.burakov@intel.com>",
            "<cover.1537363686.git.anatoly.burakov@intel.com>\n\t<cover.1537443103.git.anatoly.burakov@intel.com>"
        ],
        "Subject": "[dpdk-dev] [PATCH v3 17/20] examples: add external memory example\n\tapp",
        "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": "Introduce an example application demonstrating the use of\nexternal memory support. This is a simple application based on\nskeleton app, but instead of using internal DPDK memory, it is\nusing externally allocated memory.\n\nThe RX/TX and init path is a carbon-copy of skeleton app, with\nno modifications whatseoever. The only difference is an additional\ninit stage to allocate memory and create a heap for it, and the\nsocket ID supplied to the mempool initialization function. The\nmemory used by this app is hugepage memory allocated anonymously.\n\nAnonymous hugepage memory will not be allocated in a NUMA-aware\nfashion, so there is a chance of performance degradation when\nusing this app, but given that kernel usually gives hugepages on\nlocal socket first, this should not be a problem in most cases.\n\nSigned-off-by: Anatoly Burakov <anatoly.burakov@intel.com>\n---\n examples/external_mem/Makefile    |  62 ++++\n examples/external_mem/extmem.c    | 461 ++++++++++++++++++++++++++++++\n examples/external_mem/meson.build |  12 +\n 3 files changed, 535 insertions(+)\n create mode 100644 examples/external_mem/Makefile\n create mode 100644 examples/external_mem/extmem.c\n create mode 100644 examples/external_mem/meson.build",
    "diff": "diff --git a/examples/external_mem/Makefile b/examples/external_mem/Makefile\nnew file mode 100644\nindex 000000000..3b6ab3b2f\n--- /dev/null\n+++ b/examples/external_mem/Makefile\n@@ -0,0 +1,62 @@\n+# SPDX-License-Identifier: BSD-3-Clause\n+# Copyright(c) 2010-2018 Intel Corporation\n+\n+# binary name\n+APP = extmem\n+\n+# all source are stored in SRCS-y\n+SRCS-y := extmem.c\n+\n+# Build using pkg-config variables if possible\n+$(shell pkg-config --exists libdpdk)\n+ifeq ($(.SHELLSTATUS),0)\n+\n+all: shared\n+.PHONY: shared static\n+shared: build/$(APP)-shared\n+\tln -sf $(APP)-shared build/$(APP)\n+static: build/$(APP)-static\n+\tln -sf $(APP)-static build/$(APP)\n+\n+PC_FILE := $(shell pkg-config --path libdpdk)\n+CFLAGS += -O3 $(shell pkg-config --cflags libdpdk)\n+CFLAGS += -DALLOW_EXPERIMENTAL_API\n+LDFLAGS_SHARED = $(shell pkg-config --libs libdpdk)\n+LDFLAGS_STATIC = -Wl,-Bstatic $(shell pkg-config --static --libs libdpdk)\n+\n+build/$(APP)-shared: $(SRCS-y) Makefile $(PC_FILE) | build\n+\t$(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_SHARED)\n+\n+build/$(APP)-static: $(SRCS-y) Makefile $(PC_FILE) | build\n+\t$(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_STATIC)\n+\n+build:\n+\t@mkdir -p $@\n+\n+.PHONY: clean\n+clean:\n+\trm -f build/$(APP) build/$(APP)-static build/$(APP)-shared\n+\trmdir --ignore-fail-on-non-empty build\n+\n+else # Build using legacy build system\n+\n+ifeq ($(RTE_SDK),)\n+$(error \"Please define RTE_SDK environment variable\")\n+endif\n+\n+# Default target, can be overridden by command line or environment\n+RTE_TARGET ?= x86_64-native-linuxapp-gcc\n+\n+include $(RTE_SDK)/mk/rte.vars.mk\n+\n+CFLAGS += $(WERROR_FLAGS)\n+CFLAGS += -DALLOW_EXPERIMENTAL_API\n+\n+# workaround for a gcc bug with noreturn attribute\n+# http://gcc.gnu.org/bugzilla/show_bug.cgi?id=12603\n+ifeq ($(CONFIG_RTE_TOOLCHAIN_GCC),y)\n+CFLAGS_main.o += -Wno-return-type\n+endif\n+\n+include $(RTE_SDK)/mk/rte.extapp.mk\n+endif\ndiff --git a/examples/external_mem/extmem.c b/examples/external_mem/extmem.c\nnew file mode 100644\nindex 000000000..818a02171\n--- /dev/null\n+++ b/examples/external_mem/extmem.c\n@@ -0,0 +1,461 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2010-2018 Intel Corporation\n+ */\n+\n+#include <stdint.h>\n+#include <inttypes.h>\n+#include <stdbool.h>\n+#include <unistd.h>\n+#include <sys/mman.h>\n+\n+#include <rte_eal.h>\n+#include <rte_ethdev.h>\n+#include <rte_cycles.h>\n+#include <rte_lcore.h>\n+#include <rte_mbuf.h>\n+#include <rte_malloc.h>\n+#include <rte_memory.h>\n+#include <rte_vfio.h>\n+\n+#define RX_RING_SIZE 1024\n+#define TX_RING_SIZE 1024\n+\n+#define NUM_MBUFS 8191\n+#define MBUF_CACHE_SIZE 250\n+#define BURST_SIZE 32\n+#define EXTMEM_HEAP_NAME \"extmem\"\n+\n+static const struct rte_eth_conf port_conf_default = {\n+\t.rxmode = {\n+\t\t.max_rx_pkt_len = ETHER_MAX_LEN,\n+\t},\n+};\n+\n+/* extmem.c: Basic DPDK skeleton forwarding example using external memory. */\n+\n+/*\n+ * Initializes a given port using global settings and with the RX buffers\n+ * coming from the mbuf_pool passed as a parameter.\n+ */\n+static inline int\n+port_init(uint16_t port, struct rte_mempool *mbuf_pool)\n+{\n+\tstruct rte_eth_conf port_conf = port_conf_default;\n+\tconst uint16_t rx_rings = 1, tx_rings = 1;\n+\tuint16_t nb_rxd = RX_RING_SIZE;\n+\tuint16_t nb_txd = TX_RING_SIZE;\n+\tint retval;\n+\tuint16_t q;\n+\tstruct rte_eth_dev_info dev_info;\n+\tstruct rte_eth_txconf txconf;\n+\n+\tif (!rte_eth_dev_is_valid_port(port))\n+\t\treturn -1;\n+\n+\trte_eth_dev_info_get(port, &dev_info);\n+\tif (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE)\n+\t\tport_conf.txmode.offloads |=\n+\t\t\tDEV_TX_OFFLOAD_MBUF_FAST_FREE;\n+\n+\t/* Configure the Ethernet device. */\n+\tretval = rte_eth_dev_configure(port, rx_rings, tx_rings, &port_conf);\n+\tif (retval != 0)\n+\t\treturn retval;\n+\n+\tretval = rte_eth_dev_adjust_nb_rx_tx_desc(port, &nb_rxd, &nb_txd);\n+\tif (retval != 0)\n+\t\treturn retval;\n+\n+\t/* Allocate and set up 1 RX queue per Ethernet port. */\n+\tfor (q = 0; q < rx_rings; q++) {\n+\t\tretval = rte_eth_rx_queue_setup(port, q, nb_rxd,\n+\t\t\t\trte_eth_dev_socket_id(port), NULL, mbuf_pool);\n+\t\tif (retval < 0)\n+\t\t\treturn retval;\n+\t}\n+\n+\ttxconf = dev_info.default_txconf;\n+\ttxconf.offloads = port_conf.txmode.offloads;\n+\t/* Allocate and set up 1 TX queue per Ethernet port. */\n+\tfor (q = 0; q < tx_rings; q++) {\n+\t\tretval = rte_eth_tx_queue_setup(port, q, nb_txd,\n+\t\t\t\trte_eth_dev_socket_id(port), &txconf);\n+\t\tif (retval < 0)\n+\t\t\treturn retval;\n+\t}\n+\n+\t/* Start the Ethernet port. */\n+\tretval = rte_eth_dev_start(port);\n+\tif (retval < 0)\n+\t\treturn retval;\n+\n+\t/* Display the port MAC address. */\n+\tstruct ether_addr addr;\n+\trte_eth_macaddr_get(port, &addr);\n+\tprintf(\"Port %u MAC: %02\" PRIx8 \" %02\" PRIx8 \" %02\" PRIx8\n+\t\t\t   \" %02\" PRIx8 \" %02\" PRIx8 \" %02\" PRIx8 \"\\n\",\n+\t\t\tport,\n+\t\t\taddr.addr_bytes[0], addr.addr_bytes[1],\n+\t\t\taddr.addr_bytes[2], addr.addr_bytes[3],\n+\t\t\taddr.addr_bytes[4], addr.addr_bytes[5]);\n+\n+\t/* Enable RX in promiscuous mode for the Ethernet device. */\n+\trte_eth_promiscuous_enable(port);\n+\n+\treturn 0;\n+}\n+\n+/*\n+ * The lcore main. This is the main thread that does the work, reading from\n+ * an input port and writing to an output port.\n+ */\n+static __attribute__((noreturn)) void\n+lcore_main(void)\n+{\n+\tuint16_t port;\n+\n+\t/*\n+\t * Check that the port is on the same NUMA node as the polling thread\n+\t * for best performance.\n+\t */\n+\tRTE_ETH_FOREACH_DEV(port)\n+\t\tif (rte_eth_dev_socket_id(port) > 0 &&\n+\t\t\t\trte_eth_dev_socket_id(port) !=\n+\t\t\t\t\t\t(int)rte_socket_id())\n+\t\t\tprintf(\"WARNING, port %u is on remote NUMA node to \"\n+\t\t\t\t\t\"polling thread.\\n\\tPerformance will \"\n+\t\t\t\t\t\"not be optimal.\\n\", port);\n+\n+\tprintf(\"\\nCore %u forwarding packets. [Ctrl+C to quit]\\n\",\n+\t\t\trte_lcore_id());\n+\n+\t/* Run until the application is quit or killed. */\n+\tfor (;;) {\n+\t\t/*\n+\t\t * Receive packets on a port and forward them on the paired\n+\t\t * port. The mapping is 0 -> 1, 1 -> 0, 2 -> 3, 3 -> 2, etc.\n+\t\t */\n+\t\tRTE_ETH_FOREACH_DEV(port) {\n+\n+\t\t\t/* Get burst of RX packets, from first port of pair. */\n+\t\t\tstruct rte_mbuf *bufs[BURST_SIZE];\n+\t\t\tconst uint16_t nb_rx = rte_eth_rx_burst(port, 0,\n+\t\t\t\t\tbufs, BURST_SIZE);\n+\n+\t\t\tif (unlikely(nb_rx == 0))\n+\t\t\t\tcontinue;\n+\n+\t\t\t/* Send burst of TX packets, to second port of pair. */\n+\t\t\tconst uint16_t nb_tx = rte_eth_tx_burst(port ^ 1, 0,\n+\t\t\t\t\tbufs, nb_rx);\n+\n+\t\t\t/* Free any unsent packets. */\n+\t\t\tif (unlikely(nb_tx < nb_rx)) {\n+\t\t\t\tuint16_t buf;\n+\t\t\t\tfor (buf = nb_tx; buf < nb_rx; buf++)\n+\t\t\t\t\trte_pktmbuf_free(bufs[buf]);\n+\t\t\t}\n+\t\t}\n+\t}\n+}\n+\n+/* extremely pessimistic estimation of memory required to create a mempool */\n+static int\n+calc_mem_size(uint32_t nb_ports, uint32_t nb_mbufs_per_port,\n+\t\tuint32_t mbuf_sz, size_t pgsz, size_t *out)\n+{\n+\tuint32_t nb_mbufs = nb_ports * nb_mbufs_per_port;\n+\tuint64_t total_mem, mbuf_mem, obj_sz;\n+\n+\t/* there is no good way to predict how much space the mempool will\n+\t * occupy because it will allocate chunks on the fly, and some of those\n+\t * will come from default DPDK memory while some will come from our\n+\t * external memory, so just assume 16MB will be enough for everyone.\n+\t */\n+\tuint64_t hdr_mem = 16 << 20;\n+\n+\tobj_sz = rte_mempool_calc_obj_size(mbuf_sz, 0, NULL);\n+\tif (rte_eal_iova_mode() == RTE_IOVA_VA) {\n+\t\t/* contiguous - no need to account for page boundaries */\n+\t\tmbuf_mem = nb_mbufs * obj_sz;\n+\t} else {\n+\t\t/* account for possible non-contiguousness */\n+\t\tunsigned int n_pages, mbuf_per_pg, leftover;\n+\n+\t\tmbuf_per_pg = pgsz / obj_sz;\n+\t\tleftover = (nb_mbufs % mbuf_per_pg) > 0;\n+\t\tn_pages = (nb_mbufs / mbuf_per_pg) + leftover;\n+\n+\t\tmbuf_mem = n_pages * pgsz;\n+\t}\n+\n+\ttotal_mem = RTE_ALIGN(hdr_mem + mbuf_mem, pgsz);\n+\n+\tif (total_mem > SIZE_MAX) {\n+\t\tprintf(\"Memory size too big\\n\");\n+\t\treturn -1;\n+\t}\n+\t*out = (size_t)total_mem;\n+\n+\treturn 0;\n+}\n+\n+static inline uint32_t\n+bsf64(uint64_t v)\n+{\n+\treturn (uint32_t)__builtin_ctzll(v);\n+}\n+\n+static inline uint32_t\n+log2_u64(uint64_t v)\n+{\n+\tif (v == 0)\n+\t\treturn 0;\n+\tv = rte_align64pow2(v);\n+\treturn bsf64(v);\n+}\n+\n+#ifndef MAP_HUGE_SHIFT\n+#define HUGE_SHIFT 26\n+#else\n+#define HUGE_SHIFT MAP_HUGE_SHIFT\n+#endif\n+\n+static int\n+pagesz_flags(uint64_t page_sz)\n+{\n+\t/* as per mmap() manpage, all page sizes are log2 of page size\n+\t * shifted by MAP_HUGE_SHIFT\n+\t */\n+\tint log2 = log2_u64(page_sz);\n+\treturn log2 << HUGE_SHIFT;\n+}\n+\n+static void *\n+alloc_mem(size_t memsz, size_t pgsz)\n+{\n+\tvoid *addr;\n+\tint flags;\n+\n+\t/* allocate anonymous hugepages */\n+\tflags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_HUGETLB | pagesz_flags(pgsz);\n+\n+\taddr = mmap(NULL, memsz, PROT_READ | PROT_WRITE, flags, -1, 0);\n+\tif (addr == MAP_FAILED)\n+\t\treturn NULL;\n+\n+\treturn addr;\n+}\n+\n+struct extmem_param {\n+\tvoid *addr;\n+\tsize_t len;\n+\tsize_t pgsz;\n+\trte_iova_t *iova_table;\n+\tunsigned int iova_table_len;\n+};\n+\n+static int\n+create_extmem(uint32_t nb_ports, uint32_t nb_mbufs_per_port, uint32_t mbuf_sz,\n+\t\tstruct extmem_param *param)\n+{\n+\tuint64_t pgsizes[] = {RTE_PGSIZE_2M, RTE_PGSIZE_1G, /* x86_64, ARM */\n+\t\t\tRTE_PGSIZE_16M, RTE_PGSIZE_16G};    /* POWER */\n+\tunsigned int n_pages, cur_page, pgsz_idx;\n+\tsize_t mem_sz, offset, cur_pgsz;\n+\tbool vfio_supported = true;\n+\trte_iova_t *iovas = NULL;\n+\tvoid *addr;\n+\tint ret;\n+\n+\tfor (pgsz_idx = 0; pgsz_idx < RTE_DIM(pgsizes); pgsz_idx++) {\n+\t\t/* skip anything that is too big */\n+\t\tif (pgsizes[pgsz_idx] > SIZE_MAX)\n+\t\t\tcontinue;\n+\n+\t\tcur_pgsz = pgsizes[pgsz_idx];\n+\n+\t\tret = calc_mem_size(nb_ports, nb_mbufs_per_port,\n+\t\t\t\tmbuf_sz, cur_pgsz, &mem_sz);\n+\t\tif (ret < 0) {\n+\t\t\tprintf(\"Cannot calculate memory size\\n\");\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\t/* allocate our memory */\n+\t\taddr = alloc_mem(mem_sz, cur_pgsz);\n+\n+\t\t/* if we couldn't allocate memory with a specified page size,\n+\t\t * that doesn't mean we can't do it with other page sizes, so\n+\t\t * try another one.\n+\t\t */\n+\t\tif (addr == NULL)\n+\t\t\tcontinue;\n+\n+\t\t/* store IOVA addresses for every page in this memory area */\n+\t\tn_pages = mem_sz / cur_pgsz;\n+\n+\t\tiovas = malloc(sizeof(*iovas) * n_pages);\n+\n+\t\tif (iovas == NULL) {\n+\t\t\tprintf(\"Cannot allocate memory for iova addresses\\n\");\n+\t\t\tgoto fail;\n+\t\t}\n+\n+\t\t/* populate IOVA table */\n+\t\tfor (cur_page = 0; cur_page < n_pages; cur_page++) {\n+\t\t\trte_iova_t iova;\n+\t\t\tvoid *cur;\n+\n+\t\t\toffset = cur_pgsz * cur_page;\n+\t\t\tcur = RTE_PTR_ADD(addr, offset);\n+\n+\t\t\tiova = (uintptr_t)rte_mem_virt2iova(cur);\n+\n+\t\t\tiovas[cur_page] = iova;\n+\n+\t\t\tif (vfio_supported) {\n+\t\t\t\t/* map memory for DMA */\n+\t\t\t\tret = rte_vfio_dma_map((uintptr_t)addr,\n+\t\t\t\t\t\tiova, cur_pgsz);\n+\t\t\t\tif (ret < 0) {\n+\t\t\t\t\t/*\n+\t\t\t\t\t * ENODEV means VFIO is not initialized\n+\t\t\t\t\t * ENOTSUP means current IOMMU mode\n+\t\t\t\t\t * doesn't support mapping\n+\t\t\t\t\t * both cases are not an error\n+\t\t\t\t\t */\n+\t\t\t\t\tif (rte_errno == ENOTSUP ||\n+\t\t\t\t\t\t\trte_errno == ENODEV)\n+\t\t\t\t\t\t/* VFIO is unsupported, don't\n+\t\t\t\t\t\t * try again.\n+\t\t\t\t\t\t */\n+\t\t\t\t\t\tvfio_supported = false;\n+\t\t\t\t\telse\n+\t\t\t\t\t\t/* this is an actual error */\n+\t\t\t\t\t\tgoto fail;\n+\t\t\t\t}\n+\t\t\t}\n+\t\t}\n+\n+\t\tbreak;\n+\t}\n+\t/* if we couldn't allocate anything */\n+\tif (iovas == NULL)\n+\t\treturn -1;\n+\n+\tparam->addr = addr;\n+\tparam->len = mem_sz;\n+\tparam->pgsz = cur_pgsz;\n+\tparam->iova_table = iovas;\n+\tparam->iova_table_len = n_pages;\n+\n+\treturn 0;\n+fail:\n+\tif (iovas)\n+\t\tfree(iovas);\n+\tif (addr)\n+\t\tmunmap(addr, mem_sz);\n+\n+\treturn -1;\n+}\n+\n+static int\n+setup_extmem(uint32_t nb_ports, uint32_t nb_mbufs_per_port, uint32_t mbuf_sz)\n+{\n+\tstruct extmem_param param;\n+\tint ret;\n+\n+\t/* create our heap */\n+\tret = rte_malloc_heap_create(EXTMEM_HEAP_NAME);\n+\tif (ret < 0) {\n+\t\tprintf(\"Cannot create heap\\n\");\n+\t\treturn -1;\n+\t}\n+\n+\tret = create_extmem(nb_ports, nb_mbufs_per_port, mbuf_sz, &param);\n+\tif (ret < 0) {\n+\t\tprintf(\"Cannot create memory area\\n\");\n+\t\treturn -1;\n+\t}\n+\n+\t/* we now have a valid memory area, so add it to heap */\n+\tret = rte_malloc_heap_memory_add(EXTMEM_HEAP_NAME,\n+\t\t\tparam.addr, param.len, param.iova_table,\n+\t\t\tparam.iova_table_len, param.pgsz);\n+\n+\t/* not needed any more */\n+\tfree(param.iova_table);\n+\n+\tif (ret < 0) {\n+\t\tprintf(\"Cannot add memory to heap\\n\");\n+\t\tmunmap(param.addr, param.len);\n+\t\treturn -1;\n+\t}\n+\n+\tprintf(\"Allocated %zuMB of memory\\n\", param.len >> 20);\n+\n+\t/* success */\n+\treturn 0;\n+}\n+\n+\n+/*\n+ * The main function, which does initialization and calls the per-lcore\n+ * functions.\n+ */\n+int\n+main(int argc, char *argv[])\n+{\n+\tstruct rte_mempool *mbuf_pool;\n+\tunsigned int nb_ports;\n+\tint socket_id;\n+\tuint16_t portid;\n+\tuint32_t nb_mbufs_per_port, mbuf_sz;\n+\n+\t/* Initialize the Environment Abstraction Layer (EAL). */\n+\tint ret = rte_eal_init(argc, argv);\n+\tif (ret < 0)\n+\t\trte_exit(EXIT_FAILURE, \"Error with EAL initialization\\n\");\n+\n+\targc -= ret;\n+\targv += ret;\n+\n+\t/* Check that there is an even number of ports to send/receive on. */\n+\tnb_ports = rte_eth_dev_count_avail();\n+\tif (nb_ports < 2 || (nb_ports & 1))\n+\t\trte_exit(EXIT_FAILURE, \"Error: number of ports must be even\\n\");\n+\n+\tnb_mbufs_per_port = NUM_MBUFS;\n+\tmbuf_sz = RTE_MBUF_DEFAULT_BUF_SIZE;\n+\n+\tif (setup_extmem(nb_ports, nb_mbufs_per_port, mbuf_sz) < 0)\n+\t\trte_exit(EXIT_FAILURE, \"Error: cannot set up external memory\\n\");\n+\n+\t/* retrieve socket ID for our heap */\n+\tsocket_id = rte_malloc_heap_get_socket(EXTMEM_HEAP_NAME);\n+\tif (socket_id < 0)\n+\t\trte_exit(EXIT_FAILURE, \"Invalid socket for external heap\\n\");\n+\n+\t/* Creates a new mempool in memory to hold the mbufs. */\n+\tmbuf_pool = rte_pktmbuf_pool_create(\"MBUF_POOL\",\n+\t\t\tnb_mbufs_per_port * nb_ports, MBUF_CACHE_SIZE, 0,\n+\t\t\tmbuf_sz, socket_id);\n+\n+\tif (mbuf_pool == NULL)\n+\t\trte_exit(EXIT_FAILURE, \"Cannot create mbuf pool\\n\");\n+\n+\t/* Initialize all ports. */\n+\tRTE_ETH_FOREACH_DEV(portid)\n+\t\tif (port_init(portid, mbuf_pool) != 0)\n+\t\t\trte_exit(EXIT_FAILURE, \"Cannot init port %\"PRIu16 \"\\n\",\n+\t\t\t\t\tportid);\n+\n+\tif (rte_lcore_count() > 1)\n+\t\tprintf(\"\\nWARNING: Too many lcores enabled. Only 1 used.\\n\");\n+\n+\t/* Call lcore_main on the master core only. */\n+\tlcore_main();\n+\n+\treturn 0;\n+}\ndiff --git a/examples/external_mem/meson.build b/examples/external_mem/meson.build\nnew file mode 100644\nindex 000000000..17a363ad2\n--- /dev/null\n+++ b/examples/external_mem/meson.build\n@@ -0,0 +1,12 @@\n+# SPDX-License-Identifier: BSD-3-Clause\n+# Copyright(c) 2017 Intel Corporation\n+\n+# meson file, for building this example as part of a main DPDK build.\n+#\n+# To build this example as a standalone application with an already-installed\n+# DPDK instance, use 'make'\n+\n+allow_experimental_apis = true\n+sources = files(\n+\t'extmem.c'\n+)\n",
    "prefixes": [
        "v3",
        "17/20"
    ]
}