Show a patch.

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

{
    "id": 476,
    "url": "https://patches.dpdk.org/api/patches/476/",
    "web_url": "https://patches.dpdk.org/patch/476/",
    "project": {
        "id": 1,
        "url": "https://patches.dpdk.org/api/projects/1/",
        "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"
    },
    "msgid": "<1411568210-2555-1-git-send-email-reshma.pattan@intel.com>",
    "date": "2014-09-24T14:16:50",
    "name": "[dpdk-dev,v2] distributor_app: new sample app",
    "commit_ref": null,
    "pull_url": null,
    "state": "changes-requested",
    "archived": true,
    "hash": "648f5a8f3bbda64649294c2501bf3869d92c51c4",
    "submitter": {
        "id": 70,
        "url": "https://patches.dpdk.org/api/people/70/",
        "name": "Reshma Pattan",
        "email": "reshma.pattan@intel.com"
    },
    "delegate": null,
    "mbox": "https://patches.dpdk.org/patch/476/mbox/",
    "series": [],
    "comments": "https://patches.dpdk.org/api/patches/476/comments/",
    "check": "pending",
    "checks": "https://patches.dpdk.org/api/patches/476/checks/",
    "tags": {},
    "headers": {
        "Delivered-To": "patchwork@dpdk.org",
        "List-Subscribe": "<http://dpdk.org/ml/listinfo/dev>,\n\t<mailto:dev-request@dpdk.org?subject=subscribe>",
        "X-Original-To": "patchwork@dpdk.org",
        "Date": "Wed, 24 Sep 2014 15:16:50 +0100",
        "In-Reply-To": "<1410869607-16842-1-git-send-email-reshma.pattan@intel.com>",
        "Precedence": "list",
        "X-BeenThere": "dev@dpdk.org",
        "References": "<1410869607-16842-1-git-send-email-reshma.pattan@intel.com>",
        "X-Mailer": "git-send-email 1.7.4.1",
        "List-Archive": "<http://dpdk.org/ml/archives/dev/>",
        "To": "dev@dpdk.org",
        "Errors-To": "dev-bounces@dpdk.org",
        "Received": [
            "from [92.243.14.124] (localhost [IPv6:::1])\n\tby dpdk.org (Postfix) with ESMTP id E3C08137D;\n\tWed, 24 Sep 2014 16:11:25 +0200 (CEST)",
            "from mga02.intel.com (mga02.intel.com [134.134.136.20])\n\tby dpdk.org (Postfix) with ESMTP id 795101F5\n\tfor <dev@dpdk.org>; Wed, 24 Sep 2014 16:11:22 +0200 (CEST)",
            "from orsmga002.jf.intel.com ([10.7.209.21])\n\tby orsmga101.jf.intel.com with ESMTP; 24 Sep 2014 07:17:34 -0700",
            "from irvmail001.ir.intel.com ([163.33.26.43])\n\tby orsmga002.jf.intel.com with ESMTP; 24 Sep 2014 07:17:31 -0700",
            "from sivswdev02.ir.intel.com (sivswdev02.ir.intel.com\n\t[10.237.217.46])\n\tby irvmail001.ir.intel.com (8.14.3/8.13.6/MailSET/Hub) with ESMTP id\n\ts8OEHUSU026652; Wed, 24 Sep 2014 15:17:30 +0100",
            "from sivswdev02.ir.intel.com (localhost [127.0.0.1])\n\tby sivswdev02.ir.intel.com with ESMTP id s8OEHUAG002800;\n\tWed, 24 Sep 2014 15:17:30 +0100",
            "(from reshmapa@localhost)\n\tby sivswdev02.ir.intel.com with  id s8OEHTbo002796;\n\tWed, 24 Sep 2014 15:17:29 +0100"
        ],
        "From": "reshmapa <reshma.pattan@intel.com>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "X-ExtLoop1": "1",
        "Message-Id": "<1411568210-2555-1-git-send-email-reshma.pattan@intel.com>",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>",
        "List-Id": "patches and discussions about DPDK <dev.dpdk.org>",
        "Subject": "[dpdk-dev] [PATCH v2] distributor_app: new sample app",
        "List-Unsubscribe": "<http://dpdk.org/ml/options/dev>,\n\t<mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-IronPort-AV": "E=Sophos;i=\"5.04,589,1406617200\"; d=\"scan'208\";a=\"607849525\"",
        "List-Post": "<mailto:dev@dpdk.org>",
        "X-Mailman-Version": "2.1.15"
    },
    "content": "From: Reshma Pattan <reshma.pattan@intel.com>\n\nA new sample app that shows the usage of the distributor library. This\napp works as follows:\n\n* An RX thread runs which pulls packets from each ethernet port in turn\n  and passes those packets to worker using a distributor component.\n* The workers take the packets in turn, and determine the output port\n  for those packets using basic l2forwarding doing an xor on the source\n  port id.\n* The RX thread takes the returned packets from the workers and enqueue\n  those packets into an rte_ring structure.\n* A TX thread pulls the packets off the rte_ring structure and then\n  sends each packet out the output port specified previously by the worker\n* Command-line option support provided only for portmask.\n\nSigned-off-by: Bruce Richardson <bruce.richardson@intel.com>\nSigned-off-by: Reshma Pattan <reshma.pattan@intel.com>\n---\n examples/Makefile                 |   1 +\n examples/distributor_app/Makefile |  57 ++++\n examples/distributor_app/main.c   | 585 ++++++++++++++++++++++++++++++++++++++\n examples/distributor_app/main.h   |  46 +++\n 4 files changed, 689 insertions(+)\n create mode 100644 examples/distributor_app/Makefile\n create mode 100644 examples/distributor_app/main.c\n create mode 100644 examples/distributor_app/main.h",
    "diff": "diff --git a/examples/Makefile b/examples/Makefile\nindex 6245f83..2ba82b0 100644\n--- a/examples/Makefile\n+++ b/examples/Makefile\n@@ -66,5 +66,6 @@ DIRS-y += vhost\n DIRS-$(CONFIG_RTE_LIBRTE_XEN_DOM0) += vhost_xen\n DIRS-y += vmdq\n DIRS-y += vmdq_dcb\n+DIRS-$(CONFIG_RTE_LIBRTE_DISTRIBUTOR) += distributor_app\n \n include $(RTE_SDK)/mk/rte.extsubdir.mk\ndiff --git a/examples/distributor_app/Makefile b/examples/distributor_app/Makefile\nnew file mode 100644\nindex 0000000..394785d\n--- /dev/null\n+++ b/examples/distributor_app/Makefile\n@@ -0,0 +1,57 @@\n+#   BSD LICENSE\n+#\n+#   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.\n+#   All rights reserved.\n+#\n+#   Redistribution and use in source and binary forms, with or without\n+#   modification, are permitted provided that the following conditions\n+#   are met:\n+#\n+#     * Redistributions of source code must retain the above copyright\n+#       notice, this list of conditions and the following disclaimer.\n+#     * Redistributions in binary form must reproduce the above copyright\n+#       notice, this list of conditions and the following disclaimer in\n+#       the documentation and/or other materials provided with the\n+#       distribution.\n+#     * Neither the name of Intel Corporation nor the names of its\n+#       contributors may be used to endorse or promote products derived\n+#       from this software without specific prior written permission.\n+#\n+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n+#   \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+\n+ifeq ($(RTE_SDK),)\n+$(error \"Please define RTE_SDK environment variable\")\n+endif\n+\n+# Default target, can be overriden by command line or environment\n+RTE_TARGET ?= x86_64-default-linuxapp-gcc\n+\n+include $(RTE_SDK)/mk/rte.vars.mk\n+\n+# binary name\n+APP = distributor_app\n+\n+# all source are stored in SRCS-y\n+SRCS-y := main.c\n+\n+CFLAGS += $(WERROR_FLAGS)\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+EXTRA_CFLAGS += -O3 -Wfatal-errors\n+\n+include $(RTE_SDK)/mk/rte.extapp.mk\ndiff --git a/examples/distributor_app/main.c b/examples/distributor_app/main.c\nnew file mode 100644\nindex 0000000..628810a\n--- /dev/null\n+++ b/examples/distributor_app/main.c\n@@ -0,0 +1,585 @@\n+/*-\n+ *   BSD LICENSE\n+ *\n+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.\n+ *   All rights reserved.\n+ *\n+ *   Redistribution and use in source and binary forms, with or without\n+ *   modification, are permitted provided that the following conditions\n+ *   are met:\n+ *\n+ *     * Redistributions of source code must retain the above copyright\n+ *       notice, this list of conditions and the following disclaimer.\n+ *     * Redistributions in binary form must reproduce the above copyright\n+ *       notice, this list of conditions and the following disclaimer in\n+ *       the documentation and/or other materials provided with the\n+ *       distribution.\n+ *     * Neither the name of Intel Corporation nor the names of its\n+ *       contributors may be used to endorse or promote products derived\n+ *       from this software without specific prior written permission.\n+ *\n+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n+ *   \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+ */\n+\n+#include <stdint.h>\n+#include <inttypes.h>\n+#include <unistd.h>\n+#include <signal.h>\n+#include <getopt.h>\n+\n+#include <rte_eal.h>\n+#include <rte_ethdev.h>\n+#include <rte_cycles.h>\n+#include <rte_malloc.h>\n+#include <rte_debug.h>\n+#include <rte_distributor.h>\n+\n+#include \"main.h\"\n+\n+#define RX_RING_SIZE 256\n+#define RX_FREE_THRESH 32\n+#define RX_PTHRESH 8\n+#define RX_HTHRESH 8\n+#define RX_WTHRESH 0\n+\n+#define TX_RING_SIZE 512\n+#define TX_FREE_THRESH 32\n+#define TX_PTHRESH 32\n+#define TX_HTHRESH 0\n+#define TX_WTHRESH 0\n+#define TX_RSBIT_THRESH 32\n+#define TX_Q_FLAGS (ETH_TXQ_FLAGS_NOMULTSEGS | ETH_TXQ_FLAGS_NOVLANOFFL |\\\n+\tETH_TXQ_FLAGS_NOXSUMSCTP | ETH_TXQ_FLAGS_NOXSUMUDP | \\\n+\tETH_TXQ_FLAGS_NOXSUMTCP)\n+\n+#define NUM_MBUFS ((64*1024)-1)\n+#define MBUF_SIZE (2048 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM)\n+#define MBUF_CACHE_SIZE 250\n+#define BURST_SIZE 32\n+#define RTE_RING_SZ 1024\n+\n+/* mask of enabled ports */\n+static uint32_t enabled_port_mask = 0;\n+\n+static volatile struct app_stats {\n+\tstruct {\n+\t\tuint64_t rx_pkts;\n+\t\tuint64_t returned_pkts;\n+\t\tuint64_t enqueued_pkts;\n+\t} rx __rte_cache_aligned;\n+\n+\tstruct {\n+\t\tuint64_t dequeue_pkts;\n+\t\tuint64_t tx_pkts;\n+\t} tx __rte_cache_aligned;\n+} app_stats;\n+\n+static const struct rte_eth_conf port_conf_default = {\n+\t.rxmode = {\n+\t\t.mq_mode = ETH_MQ_RX_RSS,\n+\t\t.max_rx_pkt_len = ETHER_MAX_LEN,\n+\t\t.split_hdr_size = 0,\n+\t\t.header_split   = 0, /**< Header Split disabled */\n+\t\t.hw_ip_checksum = 0, /**< IP checksum offload enabled */\n+\t\t.hw_vlan_filter = 0, /**< VLAN filtering disabled */\n+\t\t.jumbo_frame    = 0, /**< Jumbo Frame Support disabled */\n+\t\t.hw_strip_crc   = 0, /**< CRC stripped by hardware */\n+\t},\n+\t.txmode = {\n+\t\t.mq_mode = ETH_MQ_TX_NONE,\n+\t},\n+\t.lpbk_mode = 0,\n+\t.rx_adv_conf = {\n+\t\t\t.rss_conf = {\n+\t\t\t\t.rss_hf = ETH_RSS_IPV4 | ETH_RSS_IPV6 |\n+\t\t\t\t\tETH_RSS_IPV4_TCP | ETH_RSS_IPV4_UDP |\n+\t\t\t\t\tETH_RSS_IPV6_TCP | ETH_RSS_IPV6_UDP,\n+\t\t\t}\n+\t},\n+};\n+\n+static const struct rte_eth_rxconf rx_conf_default = {\n+\t.rx_thresh = {\n+\t\t.pthresh = RX_PTHRESH,\n+\t\t.hthresh = RX_HTHRESH,\n+\t\t.wthresh = RX_WTHRESH,\n+\t},\n+\t.rx_free_thresh = RX_FREE_THRESH,\n+\t.rx_drop_en = 0,\n+};\n+\n+static const struct rte_eth_txconf tx_conf_default = {\n+\t.tx_thresh = {\n+\t\t.pthresh = TX_PTHRESH,\n+\t\t.hthresh = TX_HTHRESH,\n+\t\t.wthresh = TX_WTHRESH,\n+\t},\n+\t.tx_free_thresh = TX_FREE_THRESH,\n+\t.tx_rs_thresh = TX_RSBIT_THRESH,\n+\t.txq_flags = TX_Q_FLAGS\n+\n+};\n+\n+struct output_buffer {\n+\tunsigned count;\n+\tstruct rte_mbuf *mbufs[BURST_SIZE];\n+};\n+\n+/*\n+ * Initialises a given port using global settings and with the rx buffers\n+ * coming from the mbuf_pool passed as parameter\n+ */\n+static inline int\n+port_init(uint8_t port, struct rte_mempool *mbuf_pool)\n+{\n+\tstruct rte_eth_conf port_conf = port_conf_default;\n+\tconst uint16_t rxRings = 1, txRings = rte_lcore_count() - 1;\n+\tint retval;\n+\tuint16_t q;\n+\n+\tif (port >= rte_eth_dev_count())\n+\t\treturn -1;\n+\n+\tretval = rte_eth_dev_configure(port, rxRings, txRings, &port_conf);\n+\tif (retval != 0)\n+\t\treturn retval;\n+\n+\tfor (q = 0; q < rxRings; q++) {\n+\t\tretval = rte_eth_rx_queue_setup(port, q, RX_RING_SIZE,\n+\t\t\t\t\t\trte_eth_dev_socket_id(port),\n+\t\t\t\t\t\t&rx_conf_default, mbuf_pool);\n+\t\tif (retval < 0)\n+\t\t\treturn retval;\n+\t}\n+\n+\tfor (q = 0; q < txRings; q++) {\n+\t\tretval = rte_eth_tx_queue_setup(port, q, TX_RING_SIZE,\n+\t\t\t\t\t\trte_eth_dev_socket_id(port),\n+\t\t\t\t\t\t&tx_conf_default);\n+\t\tif (retval < 0)\n+\t\t\treturn retval;\n+\t}\n+\n+\tretval  = rte_eth_dev_start(port);\n+\tif (retval < 0)\n+\t\treturn retval;\n+\n+\tstruct rte_eth_link link;\n+\trte_eth_link_get_nowait(port, &link);\n+\tif (!link.link_status) {\n+\t\tsleep(1);\n+\t\trte_eth_link_get_nowait(port, &link);\n+\t}\n+\n+\tif (!link.link_status) {\n+\t\tprintf(\"Link down on port %\"PRIu8\"\\n\", port);\n+\t\treturn 0;\n+\t}\n+\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\t(unsigned)port,\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+\trte_eth_promiscuous_enable(port);\n+\n+\treturn 0;\n+}\n+\n+struct lcore_params {\n+\tunsigned worker_id;\n+\tstruct rte_distributor *d;\n+\tstruct rte_ring *r;\n+};\n+\n+static __attribute__((noreturn)) void\n+lcore_rx(struct lcore_params *p)\n+{\n+\tstruct rte_distributor *d = p->d;\n+\tstruct rte_ring *r = p->r;\n+\tconst uint8_t nb_ports = rte_eth_dev_count();\n+\tconst int socket_id = rte_socket_id();\n+\tuint8_t port;\n+\n+\tfor (port = 0; port < nb_ports; port++) {\n+\t\t/* skip ports that are not enabled */\n+\t\tif ((enabled_port_mask & (1 << port)) == 0)\n+\t\t\tcontinue;\n+\n+\t\tif (rte_eth_dev_socket_id(port) > 0 &&\n+\t\t\t\trte_eth_dev_socket_id(port) != socket_id)\n+\t\t\tprintf(\"WARNING, port %u is on remote NUMA node to \"\n+\t\t\t\t\t\"RX thread.\\n\\tPerformance will not \"\n+\t\t\t\t\t\"be optimal.\\n\", port);\n+\t}\n+\n+\tprintf(\"\\nCore %u doing packet RX.\\n\", rte_lcore_id());\n+\tport = 0;\n+\tfor (;;) {\n+\t\t/* skip ports that are not enabled */\n+\t\tif ((enabled_port_mask & (1 << port)) == 0) {\n+\t\t\tif (++port == nb_ports)\n+\t\t\t\tport = 0;\n+\t\t\tcontinue;\n+\t\t}\n+\t\tstruct rte_mbuf *bufs[BURST_SIZE*2];\n+\t\tconst uint16_t nb_rx = rte_eth_rx_burst(port, 0, bufs,\n+\t\t\t\tBURST_SIZE);\n+\t\tapp_stats.rx.rx_pkts += nb_rx;\n+\n+\t\trte_distributor_process(d, bufs, nb_rx);\n+\t\tconst uint16_t nb_ret = rte_distributor_returned_pkts(d,\n+\t\t\t\tbufs, BURST_SIZE*2);\n+\t\tapp_stats.rx.returned_pkts += nb_ret;\n+\t\tif (unlikely(nb_ret == 0))\n+\t\t\tcontinue;\n+\n+\t\tuint16_t sent = rte_ring_enqueue_burst(r, (void *)bufs, nb_ret);\n+\t\tapp_stats.rx.enqueued_pkts += sent;\n+\t\tif (unlikely(sent < nb_ret)) {\n+\t\t\tprintf(\"Packet loss due to full ring\\n\");\n+\t\t\twhile (sent < nb_ret)\n+\t\t\t\trte_pktmbuf_free(bufs[sent++]);\n+\t\t}\n+\t\tif (++port == nb_ports)\n+\t\t\tport = 0;\n+\t}\n+}\n+\n+static inline void\n+flush_one_port(struct output_buffer *outbuf, uint8_t outp)\n+{\n+\tunsigned nb_tx = rte_eth_tx_burst(outp, 0, outbuf->mbufs,\n+\t\t\toutbuf->count);\n+\tapp_stats.tx.tx_pkts += nb_tx;\n+\n+\tif (unlikely(nb_tx < outbuf->count)) {\n+\t\tprintf(\"Packet loss with tx_burst\\n\");\n+\t\tdo {\n+\t\t\trte_pktmbuf_free(outbuf->mbufs[nb_tx]);\n+\t\t} while (++nb_tx < outbuf->count);\n+\t}\n+\toutbuf->count = 0;\n+}\n+\n+static inline void\n+flush_all_ports(struct output_buffer *tx_buffers, uint8_t nb_ports)\n+{\n+\tuint8_t outp;\n+\tfor (outp = 0; outp < nb_ports; outp++) {\n+\t\t/* skip ports that are not enabled */\n+\t\tif ((enabled_port_mask & (1 << outp)) == 0)\n+\t\t\tcontinue;\n+\n+\t\tif (tx_buffers[outp].count == 0)\n+\t\t\tcontinue;\n+\n+\t\tflush_one_port(&tx_buffers[outp], outp);\n+\t}\n+}\n+\n+static __attribute__((noreturn)) void\n+lcore_tx(struct rte_ring *in_r)\n+{\n+\tstatic struct output_buffer tx_buffers[RTE_MAX_ETHPORTS];\n+\tconst uint8_t nb_ports = rte_eth_dev_count();\n+\tconst int socket_id = rte_socket_id();\n+\tuint8_t port;\n+\n+\tfor (port = 0; port < nb_ports; port++) {\n+\t\t/* skip ports that are not enabled */\n+\t\tif ((enabled_port_mask & (1 << port)) == 0)\n+\t\t\tcontinue;\n+\n+\t\tif (rte_eth_dev_socket_id(port) > 0 &&\n+\t\t\t\trte_eth_dev_socket_id(port) != socket_id)\n+\t\t\tprintf(\"WARNING, port %u is on remote NUMA node to \"\n+\t\t\t\t\t\"TX thread.\\n\\tPerformance will not \"\n+\t\t\t\t\t\"be optimal.\\n\", port);\n+\t}\n+\n+\tprintf(\"\\nCore %u doing packet TX.\\n\", rte_lcore_id());\n+\tfor (;;) {\n+\t\tfor (port = 0; port < nb_ports; port++) {\n+\t\t\t/* skip ports that are not enabled */\n+\t\t\tif ((enabled_port_mask & (1 << port)) == 0)\n+\t\t\t\tcontinue;\n+\n+\t\t\tstruct rte_mbuf *bufs[BURST_SIZE];\n+\t\t\tconst uint16_t nb_rx = rte_ring_dequeue_burst(in_r,\n+\t\t\t\t\t(void *)bufs, BURST_SIZE);\n+\t\t\tapp_stats.tx.dequeue_pkts += nb_rx;\n+\n+\t\t\t/* if we get no traffic, flush anything we have */\n+\t\t\tif (unlikely(nb_rx == 0)) {\n+\t\t\t\tflush_all_ports(tx_buffers, nb_ports);\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\n+\t\t\t/* for traffic we receive, queue it up for transmit */\n+\t\t\tuint16_t i;\n+\t\t\t_mm_prefetch(bufs[0], 0);\n+\t\t\t_mm_prefetch(bufs[1], 0);\n+\t\t\t_mm_prefetch(bufs[2], 0);\n+\t\t\tfor (i = 0; i < nb_rx; i++) {\n+\t\t\t\tstruct output_buffer *outbuf;\n+\t\t\t\tuint8_t outp;\n+\t\t\t\t_mm_prefetch(bufs[i + 3], 0);\n+\t\t\t\t/* workers should update in_port to hold the\n+\t\t\t\t * output port value */\n+\t\t\t\toutp = bufs[i]->port;\n+\t\t\t\t/* skip ports that are not enabled */\n+\t\t\t\tif ((enabled_port_mask & (1 << outp)) == 0)\n+\t\t\t\t\tcontinue;\n+\n+\t\t\t\toutbuf = &tx_buffers[outp];\n+\t\t\t\toutbuf->mbufs[outbuf->count++] = bufs[i];\n+\t\t\t\tif (outbuf->count == BURST_SIZE)\n+\t\t\t\t\tflush_one_port(outbuf, outp);\n+\t\t\t}\n+\t\t}\n+\t}\n+}\n+\n+\n+static __attribute__((noreturn)) void\n+lcore_worker(struct lcore_params *p)\n+{\n+\tstruct rte_distributor *d = p->d;\n+\tconst unsigned id = p->worker_id;\n+\t/* for single port, xor_val will be zero so we won't modify the output\n+\t * port, otherwise we send traffic from 0 to 1, 2 to 3, and vice versa\n+\t */\n+\tconst unsigned xor_val = (rte_eth_dev_count() > 1);\n+\tstruct rte_mbuf *buf = NULL;\n+\n+\tprintf(\"\\nCore %u acting as worker core.\\n\", rte_lcore_id());\n+\tfor (;;) {\n+\t\tbuf = rte_distributor_get_pkt(d, id, buf);\n+\t\tbuf->port ^= xor_val;\n+\t}\n+}\n+\n+static void\n+int_handler(int sig_num)\n+{\n+\tstruct rte_eth_stats eth_stats;\n+\tunsigned i;\n+\n+\tprintf(\"Exiting on signal %d\\n\", sig_num);\n+\n+\tprintf(\"\\nRX thread stats:\\n\");\n+\tprintf(\" - Received:    %\"PRIu64\"\\n\", app_stats.rx.rx_pkts);\n+\tprintf(\" - Processed:   %\"PRIu64\"\\n\", app_stats.rx.returned_pkts);\n+\tprintf(\" - Enqueued:    %\"PRIu64\"\\n\", app_stats.rx.enqueued_pkts);\n+\n+\tprintf(\"\\nTX thread stats:\\n\");\n+\tprintf(\" - Dequeued:    %\"PRIu64\"\\n\", app_stats.tx.dequeue_pkts);\n+\tprintf(\" - Transmitted: %\"PRIu64\"\\n\", app_stats.tx.tx_pkts);\n+\n+\tfor (i = 0; i < rte_eth_dev_count(); i++) {\n+\t\trte_eth_stats_get(i, &eth_stats);\n+\t\tprintf(\"\\nPort %u stats:\\n\", i);\n+\t\tprintf(\" - Pkts in:   %\"PRIu64\"\\n\", eth_stats.ipackets);\n+\t\tprintf(\" - Pkts out:  %\"PRIu64\"\\n\", eth_stats.opackets);\n+\t\tprintf(\" - In Errs:   %\"PRIu64\"\\n\", eth_stats.ierrors);\n+\t\tprintf(\" - Out Errs:  %\"PRIu64\"\\n\", eth_stats.oerrors);\n+\t\tprintf(\" - Mbuf Errs: %\"PRIu64\"\\n\", eth_stats.rx_nombuf);\n+\t}\n+\texit(0);\n+}\n+\n+/* display usage */\n+static void\n+print_usage(const char *prgname)\n+{\n+\tprintf(\"%s [EAL options] -- -p PORTMASK\\n\"\n+\t\t\t\"  -p PORTMASK: hexadecimal bitmask of ports to configure\\n\",\n+\t\t\tprgname);\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+/* 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;\n+\tchar **argvopt;\n+\tint option_index;\n+\tchar *prgname = argv[0];\n+\tstatic struct option lgopts[] = {\n+\t\t{NULL, 0, 0, 0}\n+\t};\n+\n+\targvopt = argv;\n+\n+\twhile ((opt = getopt_long(argc, argvopt, \"p:\",\n+\t\t\tlgopts, &option_index)) != EOF) {\n+\n+\t\tswitch (opt) {\n+\t\t\t/* portmask */\n+\t\t\tcase 'p':\n+\t\t\t\tenabled_port_mask = parse_portmask(optarg);\n+\t\t\t\tif (enabled_port_mask == 0) {\n+\t\t\t\t\tprintf(\"invalid portmask\\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\tbreak;\n+\n+\t\t\tdefault:\n+\t\t\t\tprint_usage(prgname);\n+\t\t\t\treturn -1;\n+\t\t}\n+\t}\n+\n+if (optind <= 1) {\n+\tprint_usage(prgname);\n+\treturn -1;\n+}\n+\n+\targv[optind-1] = prgname;\n+\n+\toptind = 0; /* reset getopt lib */\n+\treturn 0;\n+}\n+\n+/* Main function, does initialization and calls the per-lcore functions */\n+int\n+MAIN(int argc, char *argv[])\n+{\n+\tstruct rte_mempool *mbuf_pool;\n+\tstruct rte_distributor *d;\n+\tstruct rte_ring *output_ring;\n+\tunsigned lcore_id, worker_id = 0;\n+\tunsigned nb_ports;\n+\tuint8_t portid;\n+\tuint8_t nb_ports_available;\n+\n+\t/* catch ctrl-c so we can print on exit */\n+\tsignal(SIGINT, int_handler);\n+\n+\t/* init 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+\targc -= ret;\n+\targv += ret;\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 distributor parameters\\n\");\n+\n+\tif (rte_lcore_count() < 3)\n+\t\trte_exit(EXIT_FAILURE, \"Error, This application needs at \"\n+\t\t\t\t\"least 3 logical cores to run:\\n\"\n+\t\t\t\t\"1 lcore for packet RX and distribution\\n\"\n+\t\t\t\t\"1 lcore for packet TX\\n\"\n+\t\t\t\t\"and at least 1 lcore for worker threads\\n\");\n+\n+\tif (rte_eal_pci_probe() != 0)\n+\t\trte_exit(EXIT_FAILURE, \"Error with PCI probing\\n\");\n+\n+\tnb_ports = rte_eth_dev_count();\n+\tif (nb_ports == 0)\n+\t\trte_exit(EXIT_FAILURE, \"Error: no ethernet ports detected\\n\");\n+\tif (nb_ports != 1 && (nb_ports & 1))\n+\t\trte_exit(EXIT_FAILURE, \"Error: number of ports must be even, except \"\n+\t\t\t\t\"when using a single port\\n\");\n+\n+\tmbuf_pool = rte_mempool_create(\"MBUF_POOL\", NUM_MBUFS * nb_ports,\n+\t\t\tMBUF_SIZE, MBUF_CACHE_SIZE,\n+\t\t\tsizeof(struct rte_pktmbuf_pool_private),\n+\t\t\trte_pktmbuf_pool_init, NULL,\n+\t\t\trte_pktmbuf_init, NULL,\n+\t\t\trte_socket_id(), 0);\n+\tif (mbuf_pool == NULL)\n+\t\trte_exit(EXIT_FAILURE, \"Cannot create mbuf pool\\n\");\n+\n+\tnb_ports_available = nb_ports;\n+\n+\t/* initialize all ports */\n+\tfor (portid = 0; portid < nb_ports; portid++) {\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\tnb_ports_available--;\n+\t\t\tcontinue;\n+\t\t}\n+\t\t/* init port */\n+\t\tprintf(\"Initializing port %u... done\\n\", (unsigned) portid);\n+\n+\t\tif (port_init(portid, mbuf_pool) != 0)\n+\t\t\trte_exit(EXIT_FAILURE, \"Cannot initialize port %\"PRIu8\"\\n\",\n+\t\t\t\t\tportid);\n+\t}\n+\n+\tif (!nb_ports_available) {\n+\t\trte_exit(EXIT_FAILURE,\n+\t\t\t\t\"All available ports are disabled. Please set portmask.\\n\");\n+\t}\n+\n+\td = rte_distributor_create(\"PKT_DIST\", rte_socket_id(),\n+\t\t\trte_lcore_count() - 2);\n+\tif (d == NULL)\n+\t\trte_exit(EXIT_FAILURE, \"Cannot create distributor\\n\");\n+\n+\t/* scheduler ring is read only by the transmitter core, but written to\n+\t * by multiple threads\n+\t */\n+\toutput_ring = rte_ring_create(\"Output_ring\", RTE_RING_SZ,\n+\t\t\trte_socket_id(), RING_F_SC_DEQ);\n+\tif (output_ring == NULL)\n+\t\trte_exit(EXIT_FAILURE, \"Cannot create output ring\\n\");\n+\n+\tRTE_LCORE_FOREACH_SLAVE(lcore_id) {\n+\t\tif (worker_id == rte_lcore_count() - 2)\n+\t\t\trte_eal_remote_launch((lcore_function_t *)lcore_tx,\n+\t\t\t\t\toutput_ring, lcore_id);\n+\t\telse {\n+\t\t\tstruct lcore_params *p =\n+\t\t\t\t\trte_malloc(NULL, sizeof(*p), 0);\n+\t\t\tif (!p)\n+\t\t\t\trte_panic(\"malloc failure\\n\");\n+\t\t\t*p = (struct lcore_params){worker_id, d, output_ring};\n+\t\t\trte_eal_remote_launch((lcore_function_t *)lcore_worker,\n+\t\t\t\t\tp, lcore_id);\n+\t\t}\n+\t\tworker_id++;\n+\t}\n+\t/* call lcore_main on master core only */\n+\tstruct lcore_params p = { 0, d, output_ring };\n+\tlcore_rx(&p);\n+\treturn 0;\n+}\ndiff --git a/examples/distributor_app/main.h b/examples/distributor_app/main.h\nnew file mode 100644\nindex 0000000..2682d15\n--- /dev/null\n+++ b/examples/distributor_app/main.h\n@@ -0,0 +1,46 @@\n+/*-\n+ *   BSD LICENSE\n+ *\n+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.\n+ *   All rights reserved.\n+ *\n+ *   Redistribution and use in source and binary forms, with or without\n+ *   modification, are permitted provided that the following conditions\n+ *   are met:\n+ *\n+ *     * Redistributions of source code must retain the above copyright\n+ *       notice, this list of conditions and the following disclaimer.\n+ *     * Redistributions in binary form must reproduce the above copyright\n+ *       notice, this list of conditions and the following disclaimer in\n+ *       the documentation and/or other materials provided with the\n+ *       distribution.\n+ *     * Neither the name of Intel Corporation nor the names of its\n+ *       contributors may be used to endorse or promote products derived\n+ *       from this software without specific prior written permission.\n+ *\n+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n+ *   \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+ */\n+\n+#ifndef _MAIN_H_\n+#define _MAIN_H_\n+\n+\n+#ifdef RTE_EXEC_ENV_BAREMETAL\n+#define MAIN _main\n+#else\n+#define MAIN main\n+#endif\n+\n+int MAIN(int argc, char *argv[]);\n+\n+#endif /* ifndef _MAIN_H_ */\n",
    "prefixes": [
        "dpdk-dev",
        "v2"
    ]
}