get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 65436,
    "url": "http://patches.dpdk.org/api/patches/65436/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/20200131170201.3236153-6-jerinj@marvell.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": "<20200131170201.3236153-6-jerinj@marvell.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20200131170201.3236153-6-jerinj@marvell.com",
    "date": "2020-01-31T17:02:01",
    "name": "[RFC,5/5] example/l3fwd_graph: l3fwd using graph architecture",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "76d1af2e20ac78dd70aa109d87d66014fc09aba4",
    "submitter": {
        "id": 1188,
        "url": "http://patches.dpdk.org/api/people/1188/?format=api",
        "name": "Jerin Jacob Kollanukkaran",
        "email": "jerinj@marvell.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/20200131170201.3236153-6-jerinj@marvell.com/mbox/",
    "series": [
        {
            "id": 8382,
            "url": "http://patches.dpdk.org/api/series/8382/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=8382",
            "date": "2020-01-31T17:01:56",
            "name": "graph: introduce graph subsystem",
            "version": 1,
            "mbox": "http://patches.dpdk.org/series/8382/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/65436/comments/",
    "check": "warning",
    "checks": "http://patches.dpdk.org/api/patches/65436/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@inbox.dpdk.org",
        "Delivered-To": "patchwork@inbox.dpdk.org",
        "Received": [
            "from dpdk.org (dpdk.org [92.243.14.124])\n\tby inbox.dpdk.org (Postfix) with ESMTP id C6CAAA0524;\n\tFri, 31 Jan 2020 18:04:27 +0100 (CET)",
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id AB1CA1C0C3;\n\tFri, 31 Jan 2020 18:04:27 +0100 (CET)",
            "from mx0b-0016f401.pphosted.com (mx0b-0016f401.pphosted.com\n [67.231.156.173]) by dpdk.org (Postfix) with ESMTP id DDD751C030;\n Fri, 31 Jan 2020 18:04:25 +0100 (CET)",
            "from pps.filterd (m0045851.ppops.net [127.0.0.1])\n by mx0b-0016f401.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id\n 00VGuGqN032458; Fri, 31 Jan 2020 09:04:20 -0800",
            "from sc-exch03.marvell.com ([199.233.58.183])\n by mx0b-0016f401.pphosted.com with ESMTP id 2xrp2tmgd2-6\n (version=TLSv1.2 cipher=ECDHE-RSA-AES256-SHA384 bits=256 verify=NOT);\n Fri, 31 Jan 2020 09:04:19 -0800",
            "from SC-EXCH03.marvell.com (10.93.176.83) by SC-EXCH03.marvell.com\n (10.93.176.83) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Fri, 31 Jan\n 2020 09:03:23 -0800",
            "from maili.marvell.com (10.93.176.43) by SC-EXCH03.marvell.com\n (10.93.176.83) with Microsoft SMTP Server id 15.0.1497.2 via Frontend\n Transport; Fri, 31 Jan 2020 09:03:23 -0800",
            "from jerin-lab.marvell.com (jerin-lab.marvell.com [10.28.34.14])\n by maili.marvell.com (Postfix) with ESMTP id 75F493F7040;\n Fri, 31 Jan 2020 09:03:13 -0800 (PST)"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com;\n h=from : to : cc :\n subject : date : message-id : in-reply-to : references : mime-version :\n content-transfer-encoding : content-type; s=pfpt0818;\n bh=ufhLCgLyMdgvXhTyzVBPImoY45UJtuYoF8lxmE5S2VY=;\n b=FreqnbzNk7PgCEKbGDOm4d0hydJkz/tEI9G2Lh3jiOuU2Fb3VJ1U4E2kPknqjiqdjoWN\n CB9kPZaB9kvQqpg7Lz+60o5hJhN+K5xyuQopjub7rn90qCJzclnMkWWEsxBpFyywFUtQ\n aC+c4C/S/vEW4sAsvExUQlymhR0PjqLynaej9oHsuS+WnGQOCivYPXz/r6k6vOd0ELoI\n ZO05U4ktScblLw3IGqqrqloh31f0DZk9d6VdHZ0HCdOnH9zG9ms6p15vGZ468C27Q/LH\n gy6mie5/it5yk8Q6nzWiGc38QHtfbKmTFr72paXMhinBY8nf4YNbEvgObgFElyJwjH38 7A==",
        "From": "<jerinj@marvell.com>",
        "To": "<dev@dpdk.org>",
        "CC": "<pkapoor@marvell.com>, <ndabilpuram@marvell.com>,\n <kirankumark@marvell.com>, <pbhagavatula@marvell.com>,\n <pathreya@marvell.com>, <nsaxena@marvell.com>,\n <sshankarnara@marvell.com>, <honnappa.nagarahalli@arm.com>,\n <thomas@monjalon.net>, <david.marchand@redhat.com>,\n <ferruh.yigit@intel.com>, <arybchenko@solarflare.com>,\n <ajit.khaparde@broadcom.com>, <xiaolong.ye@intel.com>,\n <rasland@mellanox.com>, <maxime.coquelin@redhat.com>,\n <akhil.goyal@nxp.com>, <cristian.dumitrescu@intel.com>,\n <john.mcnamara@intel.com>, <bruce.richardson@intel.com>,\n <anatoly.burakov@intel.com>, <gavin.hu@arm.com>,\n <drc@linux.vnet.ibm.com>, <konstantin.ananyev@intel.com>,\n <pallavi.kadam@intel.com>, <olivier.matz@6wind.com>,\n <gage.eads@intel.com>, <nikhil.rao@intel.com>,\n <erik.g.carrillo@intel.com>, <hemant.agrawal@nxp.com>,\n <artem.andreev@oktetlabs.ru>, <sthemmin@microsoft.com>,\n <shahafs@mellanox.com>, <keith.wiles@intel.com>,\n <mattias.ronnblom@ericsson.com>, <jasvinder.singh@intel.com>,\n <vladimir.medvedkin@intel.com>, <mdr@ashroe.eu>, <techboard@dpdk.org>",
        "Date": "Fri, 31 Jan 2020 22:32:01 +0530",
        "Message-ID": "<20200131170201.3236153-6-jerinj@marvell.com>",
        "X-Mailer": "git-send-email 2.24.1",
        "In-Reply-To": "<20200131170201.3236153-1-jerinj@marvell.com>",
        "References": "<20200131170201.3236153-1-jerinj@marvell.com>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit",
        "Content-Type": "text/plain",
        "X-Proofpoint-Virus-Version": "vendor=fsecure engine=2.50.10434:6.0.138, 18.0.572\n definitions=2020-01-31_04:2020-01-31,\n 2020-01-31 signatures=0",
        "Subject": "[dpdk-dev] [RFC PATCH 5/5] example/l3fwd_graph: l3fwd using graph\n\tarchitecture",
        "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 <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 <mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "From: Nithin Dabilpuram <ndabilpuram@marvell.com>\n\nThis example application showcase the l3fwd implementation\nusing graph architecture.\n\nThe graphical topology representation of the l3fwd-graph is the following,\nhttp://bit.ly/39UPPGm\n\nSigned-off-by: Nithin Dabilpuram <ndabilpuram@marvell.com>\n---\n examples/Makefile                |    3 +\n examples/l3fwd-graph/Makefile    |   58 ++\n examples/l3fwd-graph/main.c      | 1131 ++++++++++++++++++++++++++++++\n examples/l3fwd-graph/meson.build |   13 +\n examples/meson.build             |    6 +-\n 5 files changed, 1209 insertions(+), 2 deletions(-)\n create mode 100644 examples/l3fwd-graph/Makefile\n create mode 100644 examples/l3fwd-graph/main.c\n create mode 100644 examples/l3fwd-graph/meson.build",
    "diff": "diff --git a/examples/Makefile b/examples/Makefile\nindex feff79784..96a2b9575 100644\n--- a/examples/Makefile\n+++ b/examples/Makefile\n@@ -51,6 +51,9 @@ DIRS-$(CONFIG_RTE_LIBRTE_ACL) += l3fwd-acl\n ifeq ($(CONFIG_RTE_LIBRTE_LPM)$(CONFIG_RTE_LIBRTE_HASH),yy)\n DIRS-$(CONFIG_RTE_LIBRTE_POWER) += l3fwd-power\n endif\n+ifeq ($(CONFIG_RTE_LIBRTE_GRAPH), y)\n+DIRS-y += l3fwd-graph\n+endif\n DIRS-y += link_status_interrupt\n DIRS-y += multi_process\n DIRS-y += ntb\ndiff --git a/examples/l3fwd-graph/Makefile b/examples/l3fwd-graph/Makefile\nnew file mode 100644\nindex 000000000..7596de500\n--- /dev/null\n+++ b/examples/l3fwd-graph/Makefile\n@@ -0,0 +1,58 @@\n+# SPDX-License-Identifier: BSD-3-Clause\n+# Copyright(C) 2020 Marvell International Ltd.\n+\n+# binary name\n+APP = l3fwd-graph\n+\n+# all source are stored in SRCS-y\n+SRCS-y := main.c \n+\n+# Build using pkg-config variables if possible\n+ifeq ($(shell pkg-config --exists libdpdk && echo 0),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+PKGCONF=pkg-config --define-prefix\n+\n+PC_FILE := $(shell $(PKGCONF) --path libdpdk)\n+CFLAGS += -O3 $(shell $(PKGCONF) --cflags libdpdk) -DALLOW_EXPERIMENTAL_API\n+LDFLAGS_SHARED = $(shell $(PKGCONF) --libs libdpdk)\n+LDFLAGS_STATIC = -Wl,-Bstatic $(shell $(PKGCONF) --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+\ttest -d build && rmdir -p build || true\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, detect a build directory, by looking for a path with a .config\n+RTE_TARGET ?= $(notdir $(abspath $(dir $(firstword $(wildcard $(RTE_SDK)/*/.config)))))\n+\n+include $(RTE_SDK)/mk/rte.vars.mk\n+\n+CFLAGS += -DALLOW_EXPERIMENTAL_API\n+CFLAGS += -I$(SRCDIR)\n+CFLAGS += -O3 $(USER_FLAGS)\n+CFLAGS += $(WERROR_FLAGS)\n+\n+include $(RTE_SDK)/mk/rte.extapp.mk\n+endif\ndiff --git a/examples/l3fwd-graph/main.c b/examples/l3fwd-graph/main.c\nnew file mode 100644\nindex 000000000..7be41c4dc\n--- /dev/null\n+++ b/examples/l3fwd-graph/main.c\n@@ -0,0 +1,1131 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(C) 2020 Marvell International Ltd.\n+ */\n+\n+#include <stdio.h>\n+#include <stdlib.h>\n+#include <stdint.h>\n+#include <inttypes.h>\n+#include <sys/types.h>\n+#include <string.h>\n+#include <sys/queue.h>\n+#include <stdarg.h>\n+#include <errno.h>\n+#include <getopt.h>\n+#include <signal.h>\n+#include <stdbool.h>\n+#include <arpa/inet.h>\n+\n+#include <rte_common.h>\n+#include <rte_vect.h>\n+#include <rte_byteorder.h>\n+#include <rte_log.h>\n+#include <rte_memory.h>\n+#include <rte_memcpy.h>\n+#include <rte_eal.h>\n+#include <rte_launch.h>\n+#include <rte_atomic.h>\n+#include <rte_cycles.h>\n+#include <rte_prefetch.h>\n+#include <rte_lcore.h>\n+#include <rte_per_lcore.h>\n+#include <rte_branch_prediction.h>\n+#include <rte_interrupts.h>\n+#include <rte_random.h>\n+#include <rte_debug.h>\n+#include <rte_ether.h>\n+#include <rte_ethdev.h>\n+#include <rte_mempool.h>\n+#include <rte_mbuf.h>\n+#include <rte_ip.h>\n+#include <rte_tcp.h>\n+#include <rte_udp.h>\n+#include <rte_string_fns.h>\n+#include <rte_cpuflags.h>\n+#include <rte_graph_worker.h>\n+#include <rte_node_eth_api.h>\n+#include <rte_node_ip4_api.h>\n+\n+#include <unistd.h>\n+#include <cmdline_parse.h>\n+#include <cmdline_parse_etheraddr.h>\n+\n+/* Log type */\n+#define RTE_LOGTYPE_L3FWD_GRAPH RTE_LOGTYPE_USER1\n+\n+/*\n+ * Configurable number of RX/TX ring descriptors\n+ */\n+#define RTE_TEST_RX_DESC_DEFAULT 1024\n+#define RTE_TEST_TX_DESC_DEFAULT 1024\n+\n+#define MAX_TX_QUEUE_PER_PORT RTE_MAX_ETHPORTS\n+#define MAX_RX_QUEUE_PER_PORT 128\n+\n+#define MAX_RX_QUEUE_PER_LCORE 16\n+\n+#define MAX_LCORE_PARAMS 1024\n+\n+#define NB_SOCKETS 8\n+\n+/* Static global variables used within this file. */\n+static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT;\n+static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT;\n+\n+/**< Ports set in promiscuous mode off by default. */\n+static int promiscuous_on;\n+\n+static int numa_on = 1; /**< NUMA is enabled by default. */\n+static int per_port_pool; /**< Use separate buffer pools per port; disabled */\n+\t\t\t  /**< by default */\n+\n+static volatile bool force_quit;\n+\n+/* ethernet addresses of ports */\n+static uint64_t dest_eth_addr[RTE_MAX_ETHPORTS];\n+static struct rte_ether_addr ports_eth_addr[RTE_MAX_ETHPORTS];\n+xmm_t val_eth[RTE_MAX_ETHPORTS];\n+\n+/* mask of enabled ports */\n+static uint32_t enabled_port_mask;\n+\n+struct lcore_rx_queue {\n+\tuint16_t port_id;\n+\tuint8_t queue_id;\n+\tchar node_name[RTE_NODE_NAMESIZE];\n+};\n+\n+/* lcore conf */\n+struct lcore_conf {\n+\tuint16_t n_rx_queue;\n+\tstruct lcore_rx_queue rx_queue_list[MAX_RX_QUEUE_PER_LCORE];\n+\n+\tstruct rte_graph *graph;\n+\tchar name[RTE_GRAPH_NAMESIZE];\n+\trte_graph_t graph_id;\n+} __rte_cache_aligned;\n+\n+static struct lcore_conf lcore_conf[RTE_MAX_LCORE];\n+\n+struct lcore_params {\n+\tuint16_t port_id;\n+\tuint8_t queue_id;\n+\tuint8_t lcore_id;\n+} __rte_cache_aligned;\n+\n+static struct lcore_params lcore_params_array[MAX_LCORE_PARAMS];\n+static struct lcore_params lcore_params_array_default[] = {\n+\t{0, 0, 2},\n+\t{0, 1, 2},\n+\t{0, 2, 2},\n+\t{1, 0, 2},\n+\t{1, 1, 2},\n+\t{1, 2, 2},\n+\t{2, 0, 2},\n+\t{3, 0, 3},\n+\t{3, 1, 3},\n+};\n+\n+static struct lcore_params * lcore_params = lcore_params_array_default;\n+static uint16_t nb_lcore_params = sizeof(lcore_params_array_default) /\n+\t\t\t\tsizeof(lcore_params_array_default[0]);\n+\n+static struct rte_eth_conf port_conf = {\n+\t.rxmode = {\n+\t\t.mq_mode = ETH_MQ_RX_RSS,\n+\t\t.max_rx_pkt_len = RTE_ETHER_MAX_LEN,\n+\t\t.split_hdr_size = 0,\n+\t},\n+\t.rx_adv_conf = {\n+\t\t.rss_conf = {\n+\t\t\t.rss_key = NULL,\n+\t\t\t.rss_hf = ETH_RSS_IP,\n+\t\t},\n+\t},\n+\t.txmode = {\n+\t\t.mq_mode = ETH_MQ_TX_NONE,\n+\t},\n+};\n+\n+static struct rte_mempool *pktmbuf_pool[RTE_MAX_ETHPORTS][NB_SOCKETS];\n+\n+static struct rte_node_ethdev_config ethdev_conf[RTE_MAX_ETHPORTS];\n+\n+struct ipv4_l3fwd_lpm_route {\n+\tuint32_t ip;\n+\tuint8_t  depth;\n+\tuint8_t  if_out;\n+};\n+\n+#define IPV4_L3FWD_LPM_NUM_ROUTES \\\n+\t(sizeof(ipv4_l3fwd_lpm_route_array) / sizeof(ipv4_l3fwd_lpm_route_array[0]))\n+/* 198.18.0.0/16 are set aside for RFC2544 benchmarking. */\n+static struct ipv4_l3fwd_lpm_route ipv4_l3fwd_lpm_route_array[] = {\n+\t{RTE_IPV4(198, 18, 0, 0), 24, 0},\n+\t{RTE_IPV4(198, 18, 1, 0), 24, 1},\n+\t{RTE_IPV4(198, 18, 2, 0), 24, 2},\n+\t{RTE_IPV4(198, 18, 3, 0), 24, 3},\n+\t{RTE_IPV4(198, 18, 4, 0), 24, 4},\n+\t{RTE_IPV4(198, 18, 5, 0), 24, 5},\n+\t{RTE_IPV4(198, 18, 6, 0), 24, 6},\n+\t{RTE_IPV4(198, 18, 7, 0), 24, 7},\n+};\n+\n+static int\n+check_lcore_params(void)\n+{\n+\tuint8_t queue, lcore;\n+\tuint16_t i;\n+\tint socketid;\n+\n+\tfor (i = 0; i < nb_lcore_params; ++i) {\n+\t\tqueue = lcore_params[i].queue_id;\n+\t\tif (queue >= MAX_RX_QUEUE_PER_PORT) {\n+\t\t\tprintf(\"invalid queue number: %hhu\\n\", queue);\n+\t\t\treturn -1;\n+\t\t}\n+\t\tlcore = lcore_params[i].lcore_id;\n+\t\tif (!rte_lcore_is_enabled(lcore)) {\n+\t\t\tprintf(\"error: lcore %hhu is not enabled in lcore mask\\n\", lcore);\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\tif (lcore == rte_get_master_lcore()) {\n+\t\t\tprintf(\"error: lcore %u is master lcore\\n\", lcore);\n+\t\t\treturn -1;\n+\t\t}\n+\t\tif ((socketid = rte_lcore_to_socket_id(lcore) != 0) &&\n+\t\t\t(numa_on == 0)) {\n+\t\t\tprintf(\"warning: lcore %hhu is on socket %d with numa off \\n\",\n+\t\t\t\tlcore, socketid);\n+\t\t}\n+\t}\n+\treturn 0;\n+}\n+\n+static int\n+check_port_config(void)\n+{\n+\tuint16_t portid;\n+\tuint16_t i;\n+\n+\tfor (i = 0; i < nb_lcore_params; ++i) {\n+\t\tportid = lcore_params[i].port_id;\n+\t\tif ((enabled_port_mask & (1 << portid)) == 0) {\n+\t\t\tprintf(\"port %u is not enabled in port mask\\n\", portid);\n+\t\t\treturn -1;\n+\t\t}\n+\t\tif (!rte_eth_dev_is_valid_port(portid)) {\n+\t\t\tprintf(\"port %u is not present on the board\\n\", portid);\n+\t\t\treturn -1;\n+\t\t}\n+\t}\n+\treturn 0;\n+}\n+\n+static uint8_t\n+get_port_n_rx_queues(const uint16_t port)\n+{\n+\tint queue = -1;\n+\tuint16_t i;\n+\n+\tfor (i = 0; i < nb_lcore_params; ++i) {\n+\t\tif (lcore_params[i].port_id == port) {\n+\t\t\tif (lcore_params[i].queue_id == queue+1)\n+\t\t\t\tqueue = lcore_params[i].queue_id;\n+\t\t\telse\n+\t\t\t\trte_exit(EXIT_FAILURE, \"queue ids of the port %d must be\"\n+\t\t\t\t\t\t\" in sequence and must start with 0\\n\",\n+\t\t\t\t\t\tlcore_params[i].port_id);\n+\t\t}\n+\t}\n+\treturn (uint8_t)(++queue);\n+}\n+\n+static int\n+init_lcore_rx_queues(void)\n+{\n+\tuint16_t i, nb_rx_queue;\n+\tuint8_t lcore;\n+\n+\tfor (i = 0; i < nb_lcore_params; ++i) {\n+\t\tlcore = lcore_params[i].lcore_id;\n+\t\tnb_rx_queue = lcore_conf[lcore].n_rx_queue;\n+\t\tif (nb_rx_queue >= MAX_RX_QUEUE_PER_LCORE) {\n+\t\t\tprintf(\"error: too many queues (%u) for lcore: %u\\n\",\n+\t\t\t\t(unsigned)nb_rx_queue + 1, (unsigned)lcore);\n+\t\t\treturn -1;\n+\t\t} else {\n+\t\t\tlcore_conf[lcore].rx_queue_list[nb_rx_queue].port_id =\n+\t\t\t\tlcore_params[i].port_id;\n+\t\t\tlcore_conf[lcore].rx_queue_list[nb_rx_queue].queue_id =\n+\t\t\t\tlcore_params[i].queue_id;\n+\t\t\tlcore_conf[lcore].n_rx_queue++;\n+\t\t}\n+\t}\n+\treturn 0;\n+}\n+\n+/* display usage */\n+static void\n+print_usage(const char *prgname)\n+{\n+\tfprintf(stderr, \"%s [EAL options] --\"\n+\t\t\" -p PORTMASK\"\n+\t\t\" [-P]\"\n+\t\t\" [-E]\"\n+\t\t\" [-L]\"\n+\t\t\" --config (port,queue,lcore)[,(port,queue,lcore)]\"\n+\t\t\" [--eth-dest=X,MM:MM:MM:MM:MM:MM]\"\n+\t\t\" [--enable-jumbo [--max-pkt-len PKTLEN]]\"\n+\t\t\" [--no-numa]\"\n+\t\t\" [--per-port-pool]\\n\\n\"\n+\n+\t\t\"  -p PORTMASK: Hexadecimal bitmask of ports to configure\\n\"\n+\t\t\"  -P : Enable promiscuous mode\\n\"\n+\t\t\"  --config (port,queue,lcore): Rx queue configuration\\n\"\n+\t\t\"  --eth-dest=X,MM:MM:MM:MM:MM:MM: Ethernet destination for port X\\n\"\n+\t\t\"  --enable-jumbo: Enable jumbo frames\\n\"\n+\t\t\"  --max-pkt-len: Under the premise of enabling jumbo,\\n\"\n+\t\t\"                 maximum packet length in decimal (64-9600)\\n\"\n+\t\t\"  --no-numa: Disable numa awareness\\n\"\n+\t\t\"  --per-port-pool: Use separate buffer pool per port\\n\\n\",\n+\t\tprgname);\n+}\n+\n+static int\n+parse_max_pkt_len(const char *pktlen)\n+{\n+\tchar *end = NULL;\n+\tunsigned long len;\n+\n+\t/* parse decimal string */\n+\tlen = strtoul(pktlen, &end, 10);\n+\tif ((pktlen[0] == '\\0') || (end == NULL) || (*end != '\\0'))\n+\t\treturn -1;\n+\n+\tif (len == 0)\n+\t\treturn -1;\n+\n+\treturn len;\n+}\n+\n+static int\n+parse_portmask(const char *portmask)\n+{\n+\tchar *end = NULL;\n+\tunsigned long pm;\n+\n+\t/* parse hexadecimal string */\n+\tpm = strtoul(portmask, &end, 16);\n+\tif ((portmask[0] == '\\0') || (end == NULL) || (*end != '\\0'))\n+\t\treturn -1;\n+\n+\tif (pm == 0)\n+\t\treturn -1;\n+\n+\treturn pm;\n+}\n+\n+static int\n+parse_config(const char *q_arg)\n+{\n+\tchar s[256];\n+\tconst char *p, *p0 = q_arg;\n+\tchar *end;\n+\tenum fieldnames {\n+\t\tFLD_PORT = 0,\n+\t\tFLD_QUEUE,\n+\t\tFLD_LCORE,\n+\t\t_NUM_FLD\n+\t};\n+\tunsigned long int_fld[_NUM_FLD];\n+\tchar *str_fld[_NUM_FLD];\n+\tint i;\n+\tunsigned size;\n+\n+\tnb_lcore_params = 0;\n+\n+\twhile ((p = strchr(p0,'(')) != NULL) {\n+\t\t++p;\n+\t\tif((p0 = strchr(p,')')) == NULL)\n+\t\t\treturn -1;\n+\n+\t\tsize = p0 - p;\n+\t\tif(size >= sizeof(s))\n+\t\t\treturn -1;\n+\n+\t\tsnprintf(s, sizeof(s), \"%.*s\", size, p);\n+\t\tif (rte_strsplit(s, sizeof(s), str_fld, _NUM_FLD, ',') != _NUM_FLD)\n+\t\t\treturn -1;\n+\t\tfor (i = 0; i < _NUM_FLD; i++){\n+\t\t\terrno = 0;\n+\t\t\tint_fld[i] = strtoul(str_fld[i], &end, 0);\n+\t\t\tif (errno != 0 || end == str_fld[i] || int_fld[i] > 255)\n+\t\t\t\treturn -1;\n+\t\t}\n+\t\tif (nb_lcore_params >= MAX_LCORE_PARAMS) {\n+\t\t\tprintf(\"exceeded max number of lcore params: %hu\\n\",\n+\t\t\t\tnb_lcore_params);\n+\t\t\treturn -1;\n+\t\t}\n+\t\tlcore_params_array[nb_lcore_params].port_id =\n+\t\t\t(uint8_t)int_fld[FLD_PORT];\n+\t\tlcore_params_array[nb_lcore_params].queue_id =\n+\t\t\t(uint8_t)int_fld[FLD_QUEUE];\n+\t\tlcore_params_array[nb_lcore_params].lcore_id =\n+\t\t\t(uint8_t)int_fld[FLD_LCORE];\n+\t\t++nb_lcore_params;\n+\t}\n+\tlcore_params = lcore_params_array;\n+\treturn 0;\n+}\n+\n+static void\n+parse_eth_dest(const char *optarg)\n+{\n+\tuint16_t portid;\n+\tchar *port_end;\n+\tuint8_t c, *dest, peer_addr[6];\n+\n+\terrno = 0;\n+\tportid = strtoul(optarg, &port_end, 10);\n+\tif (errno != 0 || port_end == optarg || *port_end++ != ',')\n+\t\trte_exit(EXIT_FAILURE,\n+\t\t\"Invalid eth-dest: %s\", optarg);\n+\tif (portid >= RTE_MAX_ETHPORTS)\n+\t\trte_exit(EXIT_FAILURE,\n+\t\t\"eth-dest: port %d >= RTE_MAX_ETHPORTS(%d)\\n\",\n+\t\tportid, RTE_MAX_ETHPORTS);\n+\n+\tif (cmdline_parse_etheraddr(NULL, port_end,\n+\t\t&peer_addr, sizeof(peer_addr)) < 0)\n+\t\trte_exit(EXIT_FAILURE,\n+\t\t\"Invalid ethernet address: %s\\n\",\n+\t\tport_end);\n+\tdest = (uint8_t *)&dest_eth_addr[portid];\n+\tfor (c = 0; c < 6; c++)\n+\t\tdest[c] = peer_addr[c];\n+\t*(uint64_t *)(val_eth + portid) = dest_eth_addr[portid];\n+}\n+\n+#define MAX_JUMBO_PKT_LEN  9600\n+#define MEMPOOL_CACHE_SIZE 256\n+\n+static const char short_options[] =\n+\t\"p:\"  /* portmask */\n+\t\"P\"   /* promiscuous */\n+\t\"L\"   /* enable long prefix match */\n+\t\"E\"   /* enable exact match */\n+\t;\n+\n+#define CMD_LINE_OPT_CONFIG \"config\"\n+#define CMD_LINE_OPT_ETH_DEST \"eth-dest\"\n+#define CMD_LINE_OPT_NO_NUMA \"no-numa\"\n+#define CMD_LINE_OPT_ENABLE_JUMBO \"enable-jumbo\"\n+#define CMD_LINE_OPT_PER_PORT_POOL \"per-port-pool\"\n+enum {\n+\t/* long options mapped to a short option */\n+\n+\t/* first long only option value must be >= 256, so that we won't\n+\t * conflict with short options */\n+\tCMD_LINE_OPT_MIN_NUM = 256,\n+\tCMD_LINE_OPT_CONFIG_NUM,\n+\tCMD_LINE_OPT_ETH_DEST_NUM,\n+\tCMD_LINE_OPT_NO_NUMA_NUM,\n+\tCMD_LINE_OPT_ENABLE_JUMBO_NUM,\n+\tCMD_LINE_OPT_PARSE_PER_PORT_POOL,\n+};\n+\n+static const struct option lgopts[] = {\n+\t{CMD_LINE_OPT_CONFIG, 1, 0, CMD_LINE_OPT_CONFIG_NUM},\n+\t{CMD_LINE_OPT_ETH_DEST, 1, 0, CMD_LINE_OPT_ETH_DEST_NUM},\n+\t{CMD_LINE_OPT_NO_NUMA, 0, 0, CMD_LINE_OPT_NO_NUMA_NUM},\n+\t{CMD_LINE_OPT_ENABLE_JUMBO, 0, 0, CMD_LINE_OPT_ENABLE_JUMBO_NUM},\n+\t{CMD_LINE_OPT_PER_PORT_POOL, 0, 0, CMD_LINE_OPT_PARSE_PER_PORT_POOL},\n+\t{NULL, 0, 0, 0}\n+};\n+\n+/*\n+ * This expression is used to calculate the number of mbufs needed\n+ * depending on user input, taking  into account memory for rx and\n+ * tx hardware rings, cache per lcore and mtable per port per lcore.\n+ * RTE_MAX is used to ensure that NB_MBUF never goes below a minimum\n+ * value of 8192\n+ */\n+#define NB_MBUF(nports) RTE_MAX(\t\\\n+\t(nports*nb_rx_queue*nb_rxd +\t\t\\\n+\tnports*nb_lcores*RTE_GRAPH_BURST_SIZE +\t\\\n+\tnports*n_tx_queue*nb_txd +\t\t\\\n+\tnb_lcores*MEMPOOL_CACHE_SIZE),\t\t\\\n+\t(unsigned)8192)\n+\n+/* Parse the argument given in the command line of the application */\n+static int\n+parse_args(int argc, char **argv)\n+{\n+\tint opt, ret;\n+\tchar **argvopt;\n+\tint option_index;\n+\tchar *prgname = argv[0];\n+\n+\targvopt = argv;\n+\n+\t/* Error or normal output strings. */\n+\twhile ((opt = getopt_long(argc, argvopt, short_options,\n+\t\t\t\tlgopts, &option_index)) != EOF) {\n+\n+\t\tswitch (opt) {\n+\t\t/* portmask */\n+\t\tcase 'p':\n+\t\t\tenabled_port_mask = parse_portmask(optarg);\n+\t\t\tif (enabled_port_mask == 0) {\n+\t\t\t\tfprintf(stderr, \"Invalid portmask\\n\");\n+\t\t\t\tprint_usage(prgname);\n+\t\t\t\treturn -1;\n+\t\t\t}\n+\t\t\tbreak;\n+\n+\t\tcase 'P':\n+\t\t\tpromiscuous_on = 1;\n+\t\t\tbreak;\n+\n+\t\t/* long options */\n+\t\tcase CMD_LINE_OPT_CONFIG_NUM:\n+\t\t\tret = parse_config(optarg);\n+\t\t\tif (ret) {\n+\t\t\t\tfprintf(stderr, \"Invalid config\\n\");\n+\t\t\t\tprint_usage(prgname);\n+\t\t\t\treturn -1;\n+\t\t\t}\n+\t\t\tbreak;\n+\n+\t\tcase CMD_LINE_OPT_ETH_DEST_NUM:\n+\t\t\tparse_eth_dest(optarg);\n+\t\t\tbreak;\n+\n+\t\tcase CMD_LINE_OPT_NO_NUMA_NUM:\n+\t\t\tnuma_on = 0;\n+\t\t\tbreak;\n+\n+\t\tcase CMD_LINE_OPT_ENABLE_JUMBO_NUM: {\n+\t\t\tconst struct option lenopts = {\n+\t\t\t\t\"max-pkt-len\", required_argument, 0, 0\n+\t\t\t};\n+\n+\t\t\tport_conf.rxmode.offloads |= DEV_RX_OFFLOAD_JUMBO_FRAME;\n+\t\t\tport_conf.txmode.offloads |= DEV_TX_OFFLOAD_MULTI_SEGS;\n+\n+\t\t\t/*\n+\t\t\t * if no max-pkt-len set, use the default\n+\t\t\t * value RTE_ETHER_MAX_LEN.\n+\t\t\t */\n+\t\t\tif (getopt_long(argc, argvopt, \"\",\n+\t\t\t\t\t&lenopts, &option_index) == 0) {\n+\t\t\t\tret = parse_max_pkt_len(optarg);\n+\t\t\t\tif (ret < 64 || ret > MAX_JUMBO_PKT_LEN) {\n+\t\t\t\t\tfprintf(stderr,\n+\t\t\t\t\t\t\"invalid maximum packet length\\n\");\n+\t\t\t\t\tprint_usage(prgname);\n+\t\t\t\t\treturn -1;\n+\t\t\t\t}\n+\t\t\t\tport_conf.rxmode.max_rx_pkt_len = ret;\n+\t\t\t}\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tcase CMD_LINE_OPT_PARSE_PER_PORT_POOL:\n+\t\t\tprintf(\"per port buffer pool is enabled\\n\");\n+\t\t\tper_port_pool = 1;\n+\t\t\tbreak;\n+\n+\t\tdefault:\n+\t\t\tprint_usage(prgname);\n+\t\t\treturn -1;\n+\t\t}\n+\t}\n+\n+\tif (optind >= 0)\n+\t\targv[optind-1] = prgname;\n+\n+\tret = optind-1;\n+\toptind = 1; /* reset getopt lib */\n+\treturn ret;\n+}\n+\n+static void\n+print_ethaddr(const char *name, const struct rte_ether_addr *eth_addr)\n+{\n+\tchar buf[RTE_ETHER_ADDR_FMT_SIZE];\n+\trte_ether_format_addr(buf, RTE_ETHER_ADDR_FMT_SIZE, eth_addr);\n+\tprintf(\"%s%s\", name, buf);\n+}\n+\n+static int\n+init_mem(uint16_t portid, unsigned int nb_mbuf)\n+{\n+\tint socketid;\n+\tunsigned lcore_id;\n+\tchar s[64];\n+\n+\tfor (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {\n+\t\tif (rte_lcore_is_enabled(lcore_id) == 0)\n+\t\t\tcontinue;\n+\n+\t\tif (numa_on)\n+\t\t\tsocketid = rte_lcore_to_socket_id(lcore_id);\n+\t\telse\n+\t\t\tsocketid = 0;\n+\n+\t\tif (socketid >= NB_SOCKETS) {\n+\t\t\trte_exit(EXIT_FAILURE,\n+\t\t\t\t\"Socket %d of lcore %u is out of range %d\\n\",\n+\t\t\t\tsocketid, lcore_id, NB_SOCKETS);\n+\t\t}\n+\n+\t\tif (pktmbuf_pool[portid][socketid] == NULL) {\n+\t\t\tsnprintf(s, sizeof(s), \"mbuf_pool_%d:%d\",\n+\t\t\t\t portid, socketid);\n+\t\t\t/* Create a pool with priv size of a cacheline */\n+\t\t\tpktmbuf_pool[portid][socketid] =\n+\t\t\t\trte_pktmbuf_pool_create(s, nb_mbuf,\n+\t\t\t\t\tMEMPOOL_CACHE_SIZE, RTE_CACHE_LINE_SIZE,\n+\t\t\t\t\tRTE_MBUF_DEFAULT_BUF_SIZE, socketid);\n+\t\t\tif (pktmbuf_pool[portid][socketid] == NULL)\n+\t\t\t\trte_exit(EXIT_FAILURE,\n+\t\t\t\t\t\"Cannot init mbuf pool on socket %d\\n\",\n+\t\t\t\t\tsocketid);\n+\t\t\telse\n+\t\t\t\tprintf(\"Allocated mbuf pool on socket %d\\n\",\n+\t\t\t\t\tsocketid);\n+\n+\t\t}\n+\t}\n+\treturn 0;\n+}\n+\n+/* Check the link status of all ports in up to 9s, and print them finally */\n+static void\n+check_all_ports_link_status(uint32_t port_mask)\n+{\n+#define CHECK_INTERVAL 100 /* 100ms */\n+#define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */\n+\tuint16_t portid;\n+\tuint8_t count, all_ports_up, print_flag = 0;\n+\tstruct rte_eth_link link;\n+\n+\tprintf(\"\\nChecking link status\");\n+\tfflush(stdout);\n+\tfor (count = 0; count <= MAX_CHECK_TIME; count++) {\n+\t\tif (force_quit)\n+\t\t\treturn;\n+\t\tall_ports_up = 1;\n+\t\tRTE_ETH_FOREACH_DEV(portid) {\n+\t\t\tif (force_quit)\n+\t\t\t\treturn;\n+\t\t\tif ((port_mask & (1 << portid)) == 0)\n+\t\t\t\tcontinue;\n+\t\t\tmemset(&link, 0, sizeof(link));\n+\t\t\trte_eth_link_get_nowait(portid, &link);\n+\t\t\t/* print link status if flag set */\n+\t\t\tif (print_flag == 1) {\n+\t\t\t\tif (link.link_status)\n+\t\t\t\t\tprintf(\n+\t\t\t\t\t\"Port%d Link Up. Speed %u Mbps -%s\\n\",\n+\t\t\t\t\t\tportid, link.link_speed,\n+\t\t\t\t(link.link_duplex == ETH_LINK_FULL_DUPLEX) ?\n+\t\t\t\t\t(\"full-duplex\") : (\"half-duplex\\n\"));\n+\t\t\t\telse\n+\t\t\t\t\tprintf(\"Port %d Link Down\\n\", portid);\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t\t/* clear all_ports_up flag if any link down */\n+\t\t\tif (link.link_status == ETH_LINK_DOWN) {\n+\t\t\t\tall_ports_up = 0;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\t\t/* after finally printing all link status, get out */\n+\t\tif (print_flag == 1)\n+\t\t\tbreak;\n+\n+\t\tif (all_ports_up == 0) {\n+\t\t\tprintf(\".\");\n+\t\t\tfflush(stdout);\n+\t\t\trte_delay_ms(CHECK_INTERVAL);\n+\t\t}\n+\n+\t\t/* set the print_flag if all ports up or timeout */\n+\t\tif (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {\n+\t\t\tprint_flag = 1;\n+\t\t\tprintf(\"done\\n\");\n+\t\t}\n+\t}\n+}\n+\n+static void\n+signal_handler(int signum)\n+{\n+\tif (signum == SIGINT || signum == SIGTERM) {\n+\t\tprintf(\"\\n\\nSignal %d received, preparing to exit...\\n\",\n+\t\t\t\tsignum);\n+\t\tforce_quit = true;\n+\t}\n+}\n+\n+static void\n+print_stats(void)\n+{\n+\tconst char topLeft[] = { 27, '[', '1', ';', '1', 'H','\\0' };\n+\tconst char clr[] = { 27, '[', '2', 'J', '\\0' };\n+\tstruct rte_graph_cluster_stats_param s_param;\n+\tstruct rte_graph_cluster_stats *stats;\n+\tconst char *pattern = \"worker_*\";\n+\n+\t/* Prepare stats object */\n+\tmemset(&s_param, 0, sizeof(s_param));\n+\ts_param.f = stdout;\n+\ts_param.socket_id = SOCKET_ID_ANY;\n+\ts_param.graph_patterns = &pattern;\n+\ts_param.nb_graph_patterns =  1;\n+\n+\tstats = rte_graph_cluster_stats_create(&s_param);\n+\tif (stats == NULL)\n+\t\trte_exit(EXIT_FAILURE,\n+\t\t\t \"Unable to create stats object\\n\");\n+\n+\twhile (!force_quit) {\n+\t\t/* Clear screen and move to top left */\n+\t\tprintf(\"%s%s\", clr, topLeft);\n+\t\trte_graph_cluster_stats_get(stats, 0);\n+\t\trte_delay_ms(1E3);\n+\t}\n+\n+\trte_graph_cluster_stats_destroy(stats);\n+}\n+\n+/* main processing loop */\n+static int\n+graph_main_loop(void *conf)\n+{\n+\tstruct lcore_conf *qconf;\n+\tstruct rte_graph *graph;\n+\tunsigned lcore_id;\n+\n+\tRTE_SET_USED(conf);\n+\n+\tlcore_id = rte_lcore_id();\n+\tqconf = &lcore_conf[lcore_id];\n+\tgraph = qconf->graph;\n+\n+\tif (!graph) {\n+\t\tRTE_LOG(INFO, L3FWD_GRAPH,\n+\t\t\t\"lcore %u has nothing to do\\n\", lcore_id);\n+\t\treturn 0;\n+\t}\n+\n+\tRTE_LOG(INFO, L3FWD_GRAPH,\n+\t\t\"entering main loop on lcore %u, graph %s(%p)\\n\",\n+\t\tlcore_id, qconf->name, graph);\n+\n+\twhile (likely(!force_quit)) {\n+\t\trte_graph_walk(graph);\n+\t}\n+\n+\treturn 0;\n+}\n+\n+int\n+main(int argc, char **argv)\n+{\n+\tconst char *node_patterns[64] = {\"ip4*\", \"ethdev_tx-*\", \"pkt_drop\", };\n+\tuint8_t rewrite_data[2 * sizeof(struct rte_ether_addr)];\n+\tuint8_t nb_rx_queue, queue, socketid;\n+\tstruct rte_ether_addr *ether_addr;\n+\tstruct rte_graph_param graph_conf;\n+\tstruct rte_eth_dev_info dev_info;\n+\tunsigned nb_ports, nb_conf = 0;\n+\tuint32_t n_tx_queue, nb_lcores;\n+\tstruct rte_eth_txconf *txconf;\n+\tuint16_t queueid, portid, i;\n+\tstruct lcore_conf *qconf;\n+\tuint16_t nb_patterns = 3;\n+\tuint16_t nb_graphs = 0;\n+\tuint8_t rewrite_len;\n+\tunsigned lcore_id;\n+\tint ret;\n+\n+\t/* init EAL */\n+\tret = rte_eal_init(argc, argv);\n+\tif (ret < 0)\n+\t\trte_exit(EXIT_FAILURE, \"Invalid EAL parameters\\n\");\n+\targc -= ret;\n+\targv += ret;\n+\n+\tforce_quit = false;\n+\tsignal(SIGINT, signal_handler);\n+\tsignal(SIGTERM, signal_handler);\n+\n+\t/* pre-init dst MACs for all ports to 02:00:00:00:00:xx */\n+\tfor (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {\n+\t\tdest_eth_addr[portid] =\n+\t\t\tRTE_ETHER_LOCAL_ADMIN_ADDR + ((uint64_t)portid << 40);\n+\t\t*(uint64_t *)(val_eth + portid) = dest_eth_addr[portid];\n+\t}\n+\n+\t/* parse application arguments (after the EAL ones) */\n+\tret = parse_args(argc, argv);\n+\tif (ret < 0)\n+\t\trte_exit(EXIT_FAILURE, \"Invalid L3FWD_GRAPH parameters\\n\");\n+\n+\tif (check_lcore_params() < 0)\n+\t\trte_exit(EXIT_FAILURE, \"check_lcore_params failed\\n\");\n+\n+\tret = init_lcore_rx_queues();\n+\tif (ret < 0)\n+\t\trte_exit(EXIT_FAILURE, \"init_lcore_rx_queues failed\\n\");\n+\n+\tnb_ports = rte_eth_dev_count_avail();\n+\n+\tif (check_port_config() < 0)\n+\t\trte_exit(EXIT_FAILURE, \"check_port_config failed\\n\");\n+\n+\tnb_lcores = rte_lcore_count();\n+\n+\t/* initialize all ports */\n+\tRTE_ETH_FOREACH_DEV(portid) {\n+\t\tstruct rte_eth_conf local_port_conf = port_conf;\n+\n+\t\t/* skip ports that are not enabled */\n+\t\tif ((enabled_port_mask & (1 << portid)) == 0) {\n+\t\t\tprintf(\"\\nSkipping disabled port %d\\n\", portid);\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\t/* init port */\n+\t\tprintf(\"Initializing port %d ... \", portid );\n+\t\tfflush(stdout);\n+\n+\t\tnb_rx_queue = get_port_n_rx_queues(portid);\n+\t\tn_tx_queue = nb_lcores;\n+\t\tif (n_tx_queue > MAX_TX_QUEUE_PER_PORT)\n+\t\t\tn_tx_queue = MAX_TX_QUEUE_PER_PORT;\n+\t\tprintf(\"Creating queues: nb_rxq=%d nb_txq=%u... \",\n+\t\t\tnb_rx_queue, (unsigned)n_tx_queue );\n+\n+\t\trte_eth_dev_info_get(portid, &dev_info);\n+\t\tif (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE)\n+\t\t\tlocal_port_conf.txmode.offloads |=\n+\t\t\t\tDEV_TX_OFFLOAD_MBUF_FAST_FREE;\n+\n+\t\tlocal_port_conf.rx_adv_conf.rss_conf.rss_hf &=\n+\t\t\tdev_info.flow_type_rss_offloads;\n+\t\tif (local_port_conf.rx_adv_conf.rss_conf.rss_hf !=\n+\t\t\t\tport_conf.rx_adv_conf.rss_conf.rss_hf) {\n+\t\t\tprintf(\"Port %u modified RSS hash function based on hardware support,\"\n+\t\t\t\t\"requested:%#\"PRIx64\" configured:%#\"PRIx64\"\\n\",\n+\t\t\t\tportid,\n+\t\t\t\tport_conf.rx_adv_conf.rss_conf.rss_hf,\n+\t\t\t\tlocal_port_conf.rx_adv_conf.rss_conf.rss_hf);\n+\t\t}\n+\n+\t\tret = rte_eth_dev_configure(portid, nb_rx_queue,\n+\t\t\t\t\t(uint16_t)n_tx_queue, &local_port_conf);\n+\t\tif (ret < 0)\n+\t\t\trte_exit(EXIT_FAILURE,\n+\t\t\t\t\"Cannot configure device: err=%d, port=%d\\n\",\n+\t\t\t\tret, portid);\n+\n+\t\tret = rte_eth_dev_adjust_nb_rx_tx_desc(portid, &nb_rxd,\n+\t\t\t\t\t\t       &nb_txd);\n+\t\tif (ret < 0)\n+\t\t\trte_exit(EXIT_FAILURE,\n+\t\t\t\t \"Cannot adjust number of descriptors: err=%d, \"\n+\t\t\t\t \"port=%d\\n\", ret, portid);\n+\n+\t\trte_eth_macaddr_get(portid, &ports_eth_addr[portid]);\n+\t\tprint_ethaddr(\" Address:\", &ports_eth_addr[portid]);\n+\t\tprintf(\", \");\n+\t\tprint_ethaddr(\"Destination:\",\n+\t\t\t(const struct rte_ether_addr *)&dest_eth_addr[portid]);\n+\t\tprintf(\", \");\n+\n+\t\t/*\n+\t\t * prepare src MACs for each port.\n+\t\t */\n+\t\trte_ether_addr_copy(&ports_eth_addr[portid],\n+\t\t\t(struct rte_ether_addr *)(val_eth + portid) + 1);\n+\n+\t\t/* init memory */\n+\t\tif (!per_port_pool) {\n+\t\t\t/* portid = 0; this is *not* signifying the first port,\n+\t\t\t * rather, it signifies that portid is ignored.\n+\t\t\t */\n+\t\t\tret = init_mem(0, NB_MBUF(nb_ports));\n+\t\t} else {\n+\t\t\tret = init_mem(portid, NB_MBUF(1));\n+\t\t}\n+\t\tif (ret < 0)\n+\t\t\trte_exit(EXIT_FAILURE, \"init_mem failed\\n\");\n+\n+\t\t/* init one TX queue per couple (lcore,port) */\n+\t\tqueueid = 0;\n+\t\tfor (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {\n+\t\t\tif (rte_lcore_is_enabled(lcore_id) == 0)\n+\t\t\t\tcontinue;\n+\n+\t\t\tqconf = &lcore_conf[lcore_id];\n+\n+\t\t\tif (numa_on)\n+\t\t\t\tsocketid =\n+\t\t\t\t(uint8_t)rte_lcore_to_socket_id(lcore_id);\n+\t\t\telse\n+\t\t\t\tsocketid = 0;\n+\n+\t\t\tprintf(\"txq=%u,%d,%d \", lcore_id, queueid, socketid);\n+\t\t\tfflush(stdout);\n+\n+\t\t\ttxconf = &dev_info.default_txconf;\n+\t\t\ttxconf->offloads = local_port_conf.txmode.offloads;\n+\t\t\tret = rte_eth_tx_queue_setup(portid, queueid, nb_txd,\n+\t\t\t\t\t\t     socketid, txconf);\n+\t\t\tif (ret < 0)\n+\t\t\t\trte_exit(EXIT_FAILURE,\n+\t\t\t\t\t\"rte_eth_tx_queue_setup: err=%d, \"\n+\t\t\t\t\t\"port=%d\\n\", ret, portid);\n+\t\t\tqueueid++;\n+\t\t}\n+\n+\t\t/* Setup ethdev node config */\n+\t\tethdev_conf[nb_conf].port_id = portid;\n+\t\tethdev_conf[nb_conf].num_rx_queues = nb_rx_queue;\n+\t\tethdev_conf[nb_conf].num_tx_queues = n_tx_queue;\n+\t\tif (!per_port_pool)\n+\t\t\tethdev_conf[nb_conf].mp =\n+\t\t\t\tpktmbuf_pool[0];\n+\n+\t\telse\n+\t\t\tethdev_conf[nb_conf].mp =\n+\t\t\t\tpktmbuf_pool[portid];\n+\t\tethdev_conf[nb_conf].mp_count = NB_SOCKETS;\n+\n+\t\tnb_conf++;\n+\t\tprintf(\"\\n\");\n+\t}\n+\n+\tfor (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {\n+\t\tif (rte_lcore_is_enabled(lcore_id) == 0)\n+\t\t\tcontinue;\n+\t\tqconf = &lcore_conf[lcore_id];\n+\t\tprintf(\"\\nInitializing rx queues on lcore %u ... \", lcore_id );\n+\t\tfflush(stdout);\n+\t\t/* init RX queues */\n+\t\tfor(queue = 0; queue < qconf->n_rx_queue; ++queue) {\n+\t\t\tstruct rte_eth_rxconf rxq_conf;\n+\n+\t\t\tportid = qconf->rx_queue_list[queue].port_id;\n+\t\t\tqueueid = qconf->rx_queue_list[queue].queue_id;\n+\n+\t\t\tif (numa_on)\n+\t\t\t\tsocketid =\n+\t\t\t\t(uint8_t)rte_lcore_to_socket_id(lcore_id);\n+\t\t\telse\n+\t\t\t\tsocketid = 0;\n+\n+\t\t\tprintf(\"rxq=%d,%d,%d \", portid, queueid, socketid);\n+\t\t\tfflush(stdout);\n+\n+\t\t\trte_eth_dev_info_get(portid, &dev_info);\n+\t\t\trxq_conf = dev_info.default_rxconf;\n+\t\t\trxq_conf.offloads = port_conf.rxmode.offloads;\n+\t\t\tif (!per_port_pool)\n+\t\t\t\tret = rte_eth_rx_queue_setup(portid, queueid,\n+\t\t\t\t\t\tnb_rxd, socketid,\n+\t\t\t\t\t\t&rxq_conf,\n+\t\t\t\t\t\tpktmbuf_pool[0][socketid]);\n+\t\t\telse\n+\t\t\t\tret = rte_eth_rx_queue_setup(portid, queueid,\n+\t\t\t\t\t\tnb_rxd, socketid,\n+\t\t\t\t\t\t&rxq_conf,\n+\t\t\t\t\t\tpktmbuf_pool[portid][socketid]);\n+\t\t\tif (ret < 0)\n+\t\t\t\trte_exit(EXIT_FAILURE,\n+\t\t\t\t\"rte_eth_rx_queue_setup: err=%d, port=%d\\n\",\n+\t\t\t\tret, portid);\n+\n+\t\t\t/* Add this queue node to its graph */\n+\t\t\tsnprintf(qconf->rx_queue_list[queue].node_name,\n+\t\t\t\t RTE_NODE_NAMESIZE, \"ethdev_rx-%u-%u\",\n+\t\t\t\t portid, queueid);\n+\t\t}\n+\n+\t\t/* Alloc a graph to this lcore only if source exists  */\n+\t\tif (qconf->n_rx_queue) {\n+\t\t\tqconf->graph_id = nb_graphs;\n+\t\t\tnb_graphs++;\n+\t\t}\n+\t}\n+\n+\tprintf(\"\\n\");\n+\n+\t/* Ethdev node config, skip rx queue mapping */\n+\tret = rte_node_eth_config(ethdev_conf, nb_conf, nb_graphs);\n+\tif (ret)\n+\t\trte_exit(EXIT_FAILURE,\n+\t\t\t \"rte_node_eth_config: err=%d\\n\", ret);\n+\n+\t/* start ports */\n+\tRTE_ETH_FOREACH_DEV(portid) {\n+\t\tif ((enabled_port_mask & (1 << portid)) == 0) {\n+\t\t\tcontinue;\n+\t\t}\n+\t\t/* Start device */\n+\t\tret = rte_eth_dev_start(portid);\n+\t\tif (ret < 0)\n+\t\t\trte_exit(EXIT_FAILURE,\n+\t\t\t\t\"rte_eth_dev_start: err=%d, port=%d\\n\",\n+\t\t\t\tret, portid);\n+\n+\t\t/*\n+\t\t * If enabled, put device in promiscuous mode.\n+\t\t * This allows IO forwarding mode to forward packets\n+\t\t * to itself through 2 cross-connected  ports of the\n+\t\t * target machine.\n+\t\t */\n+\t\tif (promiscuous_on)\n+\t\t\trte_eth_promiscuous_enable(portid);\n+\t}\n+\n+\tprintf(\"\\n\");\n+\n+\tcheck_all_ports_link_status(enabled_port_mask);\n+\n+\t/* Graph Initialization */\n+\tmemset(&graph_conf, 0, sizeof(graph_conf));\n+\tgraph_conf.node_patterns = node_patterns;\n+\n+\tfor (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {\n+\t\trte_graph_t graph_id;\n+\t\trte_edge_t i;\n+\n+\t\tif (rte_lcore_is_enabled(lcore_id) == 0)\n+\t\t\tcontinue;\n+\n+\t\tqconf = &lcore_conf[lcore_id];\n+\n+\t\t/* Skip graph creation if no source exists */\n+\t\tif (!qconf->n_rx_queue)\n+\t\t\tcontinue;\n+\n+\t\t/* Add rx node patterns of this lcore */\n+\t\tfor (i = 0; i < qconf->n_rx_queue; i++) {\n+\t\t\tgraph_conf.node_patterns[nb_patterns + i]\n+\t\t\t\t = qconf->rx_queue_list[i].node_name;\n+\t\t}\n+\n+\t\tgraph_conf.nb_node_patterns = nb_patterns + i;\n+\t\tgraph_conf.socket_id = rte_lcore_to_socket_id(lcore_id);\n+\n+\t\tsnprintf(qconf->name, sizeof(qconf->name),\n+\t\t\t \"worker_%u\", lcore_id);\n+\n+\t\tgraph_id = rte_graph_create(qconf->name, &graph_conf);\n+\t\tif (graph_id != qconf->graph_id)\n+\t\t\trte_exit(EXIT_FAILURE,\n+\t\t\t\t \"rte_graph_create(): graph_id=%d not \"\n+\t\t\t\t \" as expected for lcore %u(%u\\n\",\n+\t\t\t\t graph_id, lcore_id, qconf->graph_id);\n+\n+\t\tqconf->graph = rte_graph_lookup(qconf->name);\n+\t\tif (!qconf->graph)\n+\t\t\trte_exit(EXIT_FAILURE,\n+\t\t\t\t \"rte_graph_lookup(): graph %s not found\\n\",\n+\t\t\t\t qconf->name);\n+\n+\t}\n+\n+\t/* Update mac header rewrite data */\n+\tmemset(&rewrite_data, 0, sizeof(rewrite_data));\n+\trewrite_len = sizeof(rewrite_data);\n+\tether_addr = (struct rte_ether_addr *)rewrite_data;\n+\tether_addr[0].addr_bytes[0] = RTE_ETHER_LOCAL_ADMIN_ADDR;\n+\tether_addr[1].addr_bytes[0] = RTE_ETHER_LOCAL_ADMIN_ADDR;\n+\n+\t/* Add route to ip4 graph infra */\n+\tfor (i = 0; i < IPV4_L3FWD_LPM_NUM_ROUTES; i++) {\n+\t\tchar route_str[INET6_ADDRSTRLEN * 4];\n+\t\tchar abuf[INET6_ADDRSTRLEN];\n+\t\tstruct in_addr in;\n+\t\tuint32_t dst_port;\n+\t\tuint16_t next_hop;\n+\n+\t\t/* skip unused ports */\n+\t\tif ((1 << ipv4_l3fwd_lpm_route_array[i].if_out &\n+\t\t\t\tenabled_port_mask) == 0)\n+\t\t\tcontinue;\n+\n+\t\tdst_port = ipv4_l3fwd_lpm_route_array[i].if_out;\n+\t\tnext_hop = i;\n+\n+\t\tin.s_addr = htonl(ipv4_l3fwd_lpm_route_array[i].ip);\n+\t\tsnprintf(route_str, sizeof(route_str), \"%s / %d (%d)\",\n+\t\t\t inet_ntop(AF_INET, &in, abuf, sizeof(abuf)),\n+\t\t\t ipv4_l3fwd_lpm_route_array[i].depth,\n+\t\t\t ipv4_l3fwd_lpm_route_array[i].if_out);\n+\n+\t\tret = rte_node_ip4_route_add(ipv4_l3fwd_lpm_route_array[i].ip,\n+\t\t\tipv4_l3fwd_lpm_route_array[i].depth, next_hop,\n+\t\t\tIP4_LOOKUP_NEXT_REWRITE);\n+\n+\t\tif (ret < 0)\n+\t\t\trte_exit(EXIT_FAILURE,\n+\t\t\t\t\"Unable to add ip4 route %s to graph\\n\",\n+\t\t\t\troute_str);\n+\n+\t\tether_addr[0].addr_bytes[5] = dst_port + 1;\n+\n+\t\t/* Add next hop for a given destination */\n+\t\tret = rte_node_ip4_rewrite_add(next_hop, rewrite_data,\n+\t\t\t\t\t       rewrite_len, dst_port);\n+\t\tif (ret < 0)\n+\t\t\trte_exit(EXIT_FAILURE,\n+\t\t\t\t\"Unable to add next hop %u for \"\n+\t\t\t\t\"route %s\\n\", next_hop, route_str);\n+\n+\t\tRTE_LOG(INFO, L3FWD_GRAPH,\n+\t\t\t\"Added route %s, next_hop %u\\n\",\n+\t\t\troute_str, next_hop);\n+\t}\n+\n+\t/* launch per-lcore init on every slave lcore */\n+\trte_eal_mp_remote_launch(graph_main_loop, NULL, SKIP_MASTER);\n+\n+\t/* Accumulate and print stats on master until exit */\n+\tif (rte_graph_has_stats_feature())\n+\t\tprint_stats();\n+\n+\t/* Wait for slave cores to exit */\n+\tret = 0;\n+\tRTE_LCORE_FOREACH_SLAVE(lcore_id) {\n+\t\tret = rte_eal_wait_lcore(lcore_id);\n+\t\t/* Destroy graph */\n+\t\trte_graph_destroy(lcore_conf[lcore_id].name);\n+\t\tif (ret < 0) {\n+\t\t\tret = -1;\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\t/* stop ports */\n+\tRTE_ETH_FOREACH_DEV(portid) {\n+\t\tif ((enabled_port_mask & (1 << portid)) == 0)\n+\t\t\tcontinue;\n+\t\tprintf(\"Closing port %d...\", portid);\n+\t\trte_eth_dev_stop(portid);\n+\t\trte_eth_dev_close(portid);\n+\t\tprintf(\" Done\\n\");\n+\t}\n+\tprintf(\"Bye...\\n\");\n+\n+\treturn ret;\n+}\ndiff --git a/examples/l3fwd-graph/meson.build b/examples/l3fwd-graph/meson.build\nnew file mode 100644\nindex 000000000..a816bd890\n--- /dev/null\n+++ b/examples/l3fwd-graph/meson.build\n@@ -0,0 +1,13 @@\n+# SPDX-License-Identifier: BSD-3-Clause\n+# Copyright(C) 2020 Marvell International Ltd.\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+deps += ['graph', 'eal', 'lpm', 'ethdev', 'node' ]\n+sources = files(\n+\t'main.c'\n+)\n+allow_experimental_apis = true\ndiff --git a/examples/meson.build b/examples/meson.build\nindex 1f2b6f516..3b540012f 100644\n--- a/examples/meson.build\n+++ b/examples/meson.build\n@@ -2,8 +2,10 @@\n # Copyright(c) 2017-2019 Intel Corporation\n \n driver_libs = []\n+node_libs = []\n if get_option('default_library') == 'static'\n \tdriver_libs = dpdk_drivers\n+\tnode_libs = dpdk_graph_nodes\n endif\n \n execinfo = cc.find_library('execinfo', required: false)\n@@ -23,7 +25,7 @@ all_examples = [\n \t'l2fwd', 'l2fwd-cat', 'l2fwd-event',\n \t'l2fwd-crypto', 'l2fwd-jobstats',\n \t'l2fwd-keepalive', 'l3fwd',\n-\t'l3fwd-acl', 'l3fwd-power',\n+\t'l3fwd-acl', 'l3fwd-power', 'l3fwd-graph',\n \t'link_status_interrupt',\n \t'multi_process/client_server_mp/mp_client',\n \t'multi_process/client_server_mp/mp_server',\n@@ -99,7 +101,7 @@ foreach example: examples\n \t\tendif\n \t\texecutable('dpdk-' + name, sources,\n \t\t\tinclude_directories: includes,\n-\t\t\tlink_whole: driver_libs,\n+\t\t\tlink_whole: driver_libs + node_libs,\n \t\t\tlink_args: dpdk_extra_ldflags,\n \t\t\tc_args: cflags,\n \t\t\tdependencies: dep_objs)\n",
    "prefixes": [
        "RFC",
        "5/5"
    ]
}