get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 62039,
    "url": "https://patches.dpdk.org/api/patches/62039/?format=api",
    "web_url": "https://patches.dpdk.org/project/dpdk/patch/20191026111054.15491-11-pbhagavatula@marvell.com/",
    "project": {
        "id": 1,
        "url": "https://patches.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<20191026111054.15491-11-pbhagavatula@marvell.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20191026111054.15491-11-pbhagavatula@marvell.com",
    "date": "2019-10-26T11:10:54",
    "name": "[v7,10/10] doc: add application usage guide for l2fwd-event",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "deb9e96c1e03c2be6342a0f08a3a054ab9c365ca",
    "submitter": {
        "id": 1183,
        "url": "https://patches.dpdk.org/api/people/1183/?format=api",
        "name": "Pavan Nikhilesh Bhagavatula",
        "email": "pbhagavatula@marvell.com"
    },
    "delegate": {
        "id": 310,
        "url": "https://patches.dpdk.org/api/users/310/?format=api",
        "username": "jerin",
        "first_name": "Jerin",
        "last_name": "Jacob",
        "email": "jerinj@marvell.com"
    },
    "mbox": "https://patches.dpdk.org/project/dpdk/patch/20191026111054.15491-11-pbhagavatula@marvell.com/mbox/",
    "series": [
        {
            "id": 7083,
            "url": "https://patches.dpdk.org/api/series/7083/?format=api",
            "web_url": "https://patches.dpdk.org/project/dpdk/list/?series=7083",
            "date": "2019-10-26T11:10:44",
            "name": "example/l2fwd-event: introduce l2fwd-event example",
            "version": 7,
            "mbox": "https://patches.dpdk.org/series/7083/mbox/"
        }
    ],
    "comments": "https://patches.dpdk.org/api/patches/62039/comments/",
    "check": "fail",
    "checks": "https://patches.dpdk.org/api/patches/62039/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 3919E1BFB8;\n\tSat, 26 Oct 2019 13:12:13 +0200 (CEST)",
            "from mx0b-0016f401.pphosted.com (mx0a-0016f401.pphosted.com\n\t[67.231.148.174]) by dpdk.org (Postfix) with ESMTP id 129A11BFC4\n\tfor <dev@dpdk.org>; Sat, 26 Oct 2019 13:11:46 +0200 (CEST)",
            "from pps.filterd (m0045849.ppops.net [127.0.0.1])\n\tby mx0a-0016f401.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id\n\tx9QB5Jjd010394; Sat, 26 Oct 2019 04:11:46 -0700",
            "from sc-exch04.marvell.com ([199.233.58.184])\n\tby mx0a-0016f401.pphosted.com with ESMTP id 2vvkgq06d4-1\n\t(version=TLSv1.2 cipher=ECDHE-RSA-AES256-SHA384 bits=256 verify=NOT); \n\tSat, 26 Oct 2019 04:11:46 -0700",
            "from SC-EXCH03.marvell.com (10.93.176.83) by SC-EXCH04.marvell.com\n\t(10.93.176.84) with Microsoft SMTP Server (TLS) id 15.0.1367.3;\n\tSat, 26 Oct 2019 04:11:45 -0700",
            "from maili.marvell.com (10.93.176.43) by SC-EXCH03.marvell.com\n\t(10.93.176.83) with Microsoft SMTP Server id 15.0.1367.3 via Frontend\n\tTransport; Sat, 26 Oct 2019 04:11:45 -0700",
            "from BG-LT7430.marvell.com (unknown [10.28.17.85])\n\tby maili.marvell.com (Postfix) with ESMTP id DBB3A3F703F;\n\tSat, 26 Oct 2019 04:11:40 -0700 (PDT)"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com;\n\th=from : to : cc :\n\tsubject : date : message-id : in-reply-to : references : mime-version\n\t: content-transfer-encoding : content-type; s=pfpt0818;\n\tbh=ouvT8MYBQXA1dnSpvvxKI75Xm/zi+uYT2eewnxMQBaQ=;\n\tb=KyrlAJNs1mpM1LQ18/GcwjOYjpOYx4hyuhekigtrWL10iJdUREWh7WQYPC2bbxFhv9tQ\n\tzgbuv3rgX9qhIxUGDH4CxAHq7GtoXLfDHarL9NjxLAQqXIH4LjwuIlOepIuu+fj+LEV8\n\tzWWrdcz/yh8d8nsWr0/nX0nLgddpDYTXwifzbOa2B0OJFLl2eZ9hEaJWGqnAi5xGh0fy\n\tO8MOc7RHca91UOHnvHdXAJyrnFM52ddCY5hQK4xdjQMdc1AkhwDUX1yje0VCmq4y00JX\n\tQbHTNQhEzhJ+Rbxmrrj+T6+o/0nFBlHjHt3oJRTJmZOUKu+WlwV7tgz9dLfAFOul52/V\n\teQ== ",
        "From": "<pbhagavatula@marvell.com>",
        "To": "<jerinj@marvell.com>, <bruce.richardson@intel.com>,\n\t<hemant.agrawal@nxp.com>, Thomas Monjalon <thomas@monjalon.net>, \"John\n\tMcNamara\" <john.mcnamara@intel.com>, Marko Kovacevic\n\t<marko.kovacevic@intel.com>, Ori Kam <orika@mellanox.com>, Radu Nicolau\n\t<radu.nicolau@intel.com>, Akhil Goyal <akhil.goyal@nxp.com>,\n\tTomasz Kantecki <tomasz.kantecki@intel.com>,\n\tSunil Kumar Kori <skori@marvell.com>, \"Pavan\n\tNikhilesh\" <pbhagavatula@marvell.com>",
        "CC": "<dev@dpdk.org>",
        "Date": "Sat, 26 Oct 2019 16:40:54 +0530",
        "Message-ID": "<20191026111054.15491-11-pbhagavatula@marvell.com>",
        "X-Mailer": "git-send-email 2.17.1",
        "In-Reply-To": "<20191026111054.15491-1-pbhagavatula@marvell.com>",
        "References": "<20191014182247.961-1-pbhagavatula@marvell.com>\n\t<20191026111054.15491-1-pbhagavatula@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.95,1.0.8\n\tdefinitions=2019-10-26_02:2019-10-25,2019-10-26 signatures=0",
        "Subject": "[dpdk-dev] [PATCH v7 10/10] doc: add application usage guide for\n\tl2fwd-event",
        "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": "From: Sunil Kumar Kori <skori@marvell.com>\n\nAdd documentation for l2fwd-event example.\nUpdate release notes.\n\nSigned-off-by: Sunil Kumar Kori <skori@marvell.com>\n---\n MAINTAINERS                                   |   1 +\n doc/guides/rel_notes/release_19_11.rst        |   6 +\n doc/guides/sample_app_ug/index.rst            |   1 +\n doc/guides/sample_app_ug/intro.rst            |   5 +\n doc/guides/sample_app_ug/l2_forward_event.rst | 698 ++++++++++++++++++\n 5 files changed, 711 insertions(+)\n create mode 100644 doc/guides/sample_app_ug/l2_forward_event.rst",
    "diff": "diff --git a/MAINTAINERS b/MAINTAINERS\nindex 6957b2a24..8898ff252 100644\n--- a/MAINTAINERS\n+++ b/MAINTAINERS\n@@ -1478,6 +1478,7 @@ F: examples/l2fwd-cat/\n M: Sunil Kumar Kori <skori@marvell.com>\n M: Pavan Nikhilesh <pbhagavatula@marvell.com>\n F: examples/l2fwd-event/\n+F: doc/guides/sample_app_ug/l2_forward_event.rst\n T: git://dpdk.org/next/dpdk-next-eventdev\n \n F: examples/l3fwd/\ndiff --git a/doc/guides/rel_notes/release_19_11.rst b/doc/guides/rel_notes/release_19_11.rst\nindex 08dafa76f..c8e9158af 100644\n--- a/doc/guides/rel_notes/release_19_11.rst\n+++ b/doc/guides/rel_notes/release_19_11.rst\n@@ -115,6 +115,12 @@ New Features\n   Added eBPF JIT support for arm64 architecture to improve the eBPF program\n   performance.\n \n+* **Added new example l2fwd-event application.**\n+\n+  Added an example application `l2fwd-event` that adds event device support to\n+  traditional l2fwd example. It demonstrates usage of poll and event mode IO\n+  mechanism under a single application.\n+\n \n Removed Items\n -------------\ndiff --git a/doc/guides/sample_app_ug/index.rst b/doc/guides/sample_app_ug/index.rst\nindex f23f8f59e..41388231a 100644\n--- a/doc/guides/sample_app_ug/index.rst\n+++ b/doc/guides/sample_app_ug/index.rst\n@@ -26,6 +26,7 @@ Sample Applications User Guides\n     l2_forward_crypto\n     l2_forward_job_stats\n     l2_forward_real_virtual\n+    l2_forward_event\n     l2_forward_cat\n     l3_forward\n     l3_forward_power_man\ndiff --git a/doc/guides/sample_app_ug/intro.rst b/doc/guides/sample_app_ug/intro.rst\nindex 90704194a..15bbbec44 100644\n--- a/doc/guides/sample_app_ug/intro.rst\n+++ b/doc/guides/sample_app_ug/intro.rst\n@@ -87,6 +87,11 @@ examples are highlighted below.\n   forwarding, or ``l2fwd`` application does forwarding based on Ethernet MAC\n   addresses like a simple switch.\n \n+* :doc:`Network Layer 2 forwarding<l2_forward_event>`: The Network Layer 2\n+  forwarding, or ``l2fwd-event`` application does forwarding based on Ethernet MAC\n+  addresses like a simple switch. It demonstrates usage of poll and event mode\n+  IO mechanism under a single application.\n+\n * :doc:`Network Layer 3 forwarding<l3_forward>`: The Network Layer3\n   forwarding, or ``l3fwd`` application does forwarding based on Internet\n   Protocol, IPv4 or IPv6 like a simple router.\ndiff --git a/doc/guides/sample_app_ug/l2_forward_event.rst b/doc/guides/sample_app_ug/l2_forward_event.rst\nnew file mode 100644\nindex 000000000..52a570b97\n--- /dev/null\n+++ b/doc/guides/sample_app_ug/l2_forward_event.rst\n@@ -0,0 +1,698 @@\n+..  SPDX-License-Identifier: BSD-3-Clause\n+    Copyright(c) 2010-2014 Intel Corporation.\n+\n+.. _l2_fwd_event_app:\n+\n+L2 Forwarding Eventdev Sample Application\n+=========================================\n+\n+The L2 Forwarding eventdev sample application is a simple example of packet\n+processing using the Data Plane Development Kit (DPDK) to demonstrate usage of\n+poll and event mode packet I/O mechanism.\n+\n+Overview\n+--------\n+\n+The L2 Forwarding eventdev sample application, performs L2 forwarding for each\n+packet that is received on an RX_PORT. The destination port is the adjacent port\n+from the enabled portmask, that is, if the first four ports are enabled (portmask=0x0f),\n+ports 1 and 2 forward into each other, and ports 3 and 4 forward into each other.\n+Also, if MAC addresses updating is enabled, the MAC addresses are affected as follows:\n+\n+*   The source MAC address is replaced by the TX_PORT MAC address\n+\n+*   The destination MAC address is replaced by  02:00:00:00:00:TX_PORT_ID\n+\n+Application receives packets from RX_PORT using below mentioned methods:\n+\n+*   Poll mode\n+\n+*   Eventdev mode (default)\n+\n+This application can be used to benchmark performance using a traffic-generator,\n+as shown in the :numref:`figure_l2fwd_event_benchmark_setup`.\n+\n+.. _figure_l2fwd_event_benchmark_setup:\n+\n+.. figure:: img/l2_fwd_benchmark_setup.*\n+\n+   Performance Benchmark Setup (Basic Environment)\n+\n+Compiling the Application\n+-------------------------\n+\n+To compile the sample application see :doc:`compiling`.\n+\n+The application is located in the ``l2fwd-event`` sub-directory.\n+\n+Running the Application\n+-----------------------\n+\n+The application requires a number of command line options:\n+\n+.. code-block:: console\n+\n+    ./build/l2fwd-event [EAL options] -- -p PORTMASK [-q NQ] --[no-]mac-updating --mode=MODE --eventq-sched=SCHED_MODE\n+\n+where,\n+\n+*   p PORTMASK: A hexadecimal bitmask of the ports to configure\n+\n+*   q NQ: A number of queues (=ports) per lcore (default is 1)\n+\n+*   --[no-]mac-updating: Enable or disable MAC addresses updating (enabled by default).\n+\n+*   --mode=MODE: Packet transfer mode for I/O, poll or eventdev. Eventdev by default.\n+\n+*   --eventq-sched=SCHED_MODE: Event queue schedule mode, Ordered, Atomic or Parallel. Atomic by default.\n+\n+Sample usage commands are given below to run the application into different mode:\n+\n+Poll mode with 4 lcores, 16 ports and 8 RX queues per lcore and MAC address updating enabled,\n+issue the command:\n+\n+.. code-block:: console\n+\n+    ./build/l2fwd-event -l 0-3 -n 4 -- -q 8 -p ffff --mode=poll\n+\n+Eventdev mode with 4 lcores, 16 ports , sched method ordered and MAC address updating enabled,\n+issue the command:\n+\n+.. code-block:: console\n+\n+    ./build/l2fwd-event -l 0-3 -n 4 -- -p ffff --eventq-sched=ordered\n+\n+or\n+\n+.. code-block:: console\n+\n+    ./build/l2fwd-event -l 0-3 -n 4 -- -q 8 -p ffff --mode=eventdev --eventq-sched=ordered\n+\n+Refer to the *DPDK Getting Started Guide* for general information on running\n+applications and the Environment Abstraction Layer (EAL) options.\n+\n+To run application with S/W scheduler, it uses following DPDK services:\n+\n+*   Software scheduler\n+*   Rx adapter service function\n+*   Tx adapter service function\n+\n+Application needs service cores to run above mentioned services. Service cores\n+must be provided as EAL parameters along with the --vdev=event_sw0 to enable S/W\n+scheduler. Following is the sample command:\n+\n+.. code-block:: console\n+\n+    ./build/l2fwd-event -l 0-7 -s 0-3 -n 4 ---vdev event_sw0 --q 8 -p ffff --mode=eventdev --eventq-sched=ordered\n+\n+Explanation\n+-----------\n+\n+The following sections provide some explanation of the code.\n+\n+.. _l2_fwd_event_app_cmd_arguments:\n+\n+Command Line Arguments\n+~~~~~~~~~~~~~~~~~~~~~~\n+\n+The L2 Forwarding eventdev sample application takes specific parameters,\n+in addition to Environment Abstraction Layer (EAL) arguments.\n+The preferred way to parse parameters is to use the getopt() function,\n+since it is part of a well-defined and portable library.\n+\n+The parsing of arguments is done in the **l2fwd_parse_args()** function for non\n+eventdev parameters and in **parse_eventdev_args()** for eventdev parameters.\n+The method of argument parsing is not described here. Refer to the\n+*glibc getopt(3)* man page for details.\n+\n+EAL arguments are parsed first, then application-specific arguments.\n+This is done at the beginning of the main() function and eventdev parameters\n+are parsed in eventdev_resource_setup() function during eventdev setup:\n+\n+.. code-block:: c\n+\n+    /* init EAL */\n+\n+    ret = rte_eal_init(argc, argv);\n+    if (ret < 0)\n+        rte_panic(\"Invalid EAL arguments\\n\");\n+\n+    argc -= ret;\n+    argv += ret;\n+\n+    /* parse application arguments (after the EAL ones) */\n+\n+    ret = l2fwd_parse_args(argc, argv);\n+    if (ret < 0)\n+        rte_panic(\"Invalid L2FWD arguments\\n\");\n+    .\n+    .\n+    .\n+\n+    /* Parse eventdev command line options */\n+    ret = parse_eventdev_args(argc, argv);\n+    if (ret < 0)\n+        return ret;\n+\n+\n+\n+\n+.. _l2_fwd_event_app_mbuf_init:\n+\n+Mbuf Pool Initialization\n+~~~~~~~~~~~~~~~~~~~~~~~~\n+\n+Once the arguments are parsed, the mbuf pool is created.\n+The mbuf pool contains a set of mbuf objects that will be used by the driver\n+and the application to store network packet data:\n+\n+.. code-block:: c\n+\n+    /* create the mbuf pool */\n+\n+    l2fwd_pktmbuf_pool = rte_pktmbuf_pool_create(\"mbuf_pool\", NB_MBUF,\n+                                                 MEMPOOL_CACHE_SIZE, 0,\n+                                                 RTE_MBUF_DEFAULT_BUF_SIZE,\n+                                                 rte_socket_id());\n+    if (l2fwd_pktmbuf_pool == NULL)\n+        rte_panic(\"Cannot init mbuf pool\\n\");\n+\n+The rte_mempool is a generic structure used to handle pools of objects.\n+In this case, it is necessary to create a pool that will be used by the driver.\n+The number of allocated pkt mbufs is NB_MBUF, with a data room size of\n+RTE_MBUF_DEFAULT_BUF_SIZE each.\n+A per-lcore cache of 32 mbufs is kept.\n+The memory is allocated in NUMA socket 0,\n+but it is possible to extend this code to allocate one mbuf pool per socket.\n+\n+The rte_pktmbuf_pool_create() function uses the default mbuf pool and mbuf\n+initializers, respectively rte_pktmbuf_pool_init() and rte_pktmbuf_init().\n+An advanced application may want to use the mempool API to create the\n+mbuf pool with more control.\n+\n+.. _l2_fwd_event_app_drv_init:\n+\n+Driver Initialization\n+~~~~~~~~~~~~~~~~~~~~~\n+\n+The main part of the code in the main() function relates to the initialization\n+of the driver. To fully understand this code, it is recommended to study the\n+chapters that related to the Poll Mode and Event mode Driver in the\n+*DPDK Programmer's Guide* - Rel 1.4 EAR and the *DPDK API Reference*.\n+\n+.. code-block:: c\n+\n+    if (rte_pci_probe() < 0)\n+        rte_panic(\"Cannot probe PCI\\n\");\n+\n+    /* reset l2fwd_dst_ports */\n+\n+    for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++)\n+        l2fwd_dst_ports[portid] = 0;\n+\n+    last_port = 0;\n+\n+    /*\n+     * Each logical core is assigned a dedicated TX queue on each port.\n+     */\n+\n+    RTE_ETH_FOREACH_DEV(portid) {\n+        /* skip ports that are not enabled */\n+\n+        if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)\n+           continue;\n+\n+        if (nb_ports_in_mask % 2) {\n+            l2fwd_dst_ports[portid] = last_port;\n+            l2fwd_dst_ports[last_port] = portid;\n+        }\n+        else\n+           last_port = portid;\n+\n+        nb_ports_in_mask++;\n+\n+        rte_eth_dev_info_get((uint8_t) portid, &dev_info);\n+    }\n+\n+Observe that:\n+\n+*   rte_pci_probe() parses the devices on the PCI bus and initializes recognized\n+    devices.\n+\n+The next step is to configure the RX and TX queues. For each port, there is only\n+one RX queue (only one lcore is able to poll a given port). The number of TX\n+queues depends on the number of available lcores. The rte_eth_dev_configure()\n+function is used to configure the number of queues for a port:\n+\n+.. code-block:: c\n+\n+    ret = rte_eth_dev_configure((uint8_t)portid, 1, 1, &port_conf);\n+    if (ret < 0)\n+        rte_panic(\"Cannot configure device: err=%d, port=%u\\n\",\n+                  ret, portid);\n+\n+.. _l2_fwd_event_app_rx_init:\n+\n+RX Queue Initialization\n+~~~~~~~~~~~~~~~~~~~~~~~\n+\n+The application uses one lcore to poll one or several ports, depending on the -q\n+option, which specifies the number of queues per lcore.\n+\n+For example, if the user specifies -q 4, the application is able to poll four\n+ports with one lcore. If there are 16 ports on the target (and if the portmask\n+argument is -p ffff ), the application will need four lcores to poll all the\n+ports.\n+\n+.. code-block:: c\n+\n+    ret = rte_eth_rx_queue_setup((uint8_t) portid, 0, nb_rxd, SOCKET0,\n+                                 &rx_conf, l2fwd_pktmbuf_pool);\n+    if (ret < 0)\n+\n+        rte_panic(\"rte_eth_rx_queue_setup: err=%d, port=%u\\n\",\n+                  ret, portid);\n+\n+The list of queues that must be polled for a given lcore is stored in a private\n+structure called struct lcore_queue_conf.\n+\n+.. code-block:: c\n+\n+    struct lcore_queue_conf {\n+        unsigned n_rx_port;\n+        unsigned rx_port_list[MAX_RX_QUEUE_PER_LCORE];\n+        struct mbuf_table tx_mbufs[L2FWD_MAX_PORTS];\n+    } rte_cache_aligned;\n+\n+    struct lcore_queue_conf lcore_queue_conf[RTE_MAX_LCORE];\n+\n+The values n_rx_port and rx_port_list[] are used in the main packet processing\n+loop (see :ref:`l2_fwd_event_app_rx_tx_packets`).\n+\n+.. _l2_fwd_event_app_tx_init:\n+\n+TX Queue Initialization\n+~~~~~~~~~~~~~~~~~~~~~~~\n+\n+Each lcore should be able to transmit on any port. For every port, a single TX\n+queue is initialized.\n+\n+.. code-block:: c\n+\n+    /* init one TX queue on each port */\n+\n+    fflush(stdout);\n+\n+    ret = rte_eth_tx_queue_setup((uint8_t) portid, 0, nb_txd,\n+                                 rte_eth_dev_socket_id(portid), &tx_conf);\n+    if (ret < 0)\n+        rte_panic(\"rte_eth_tx_queue_setup:err=%d, port=%u\\n\",\n+                  ret, (unsigned) portid);\n+\n+To configure eventdev support, application setups following components:\n+\n+*   Event dev\n+*   Event queue\n+*   Event Port\n+*   Rx/Tx adapters\n+*   Ethernet ports\n+\n+.. _l2_fwd_event_app_event_dev_init:\n+\n+Event device Initialization\n+~~~~~~~~~~~~~~~~~~~~~~~~~~~\n+Application can use either H/W or S/W based event device scheduler\n+implementation and supports single instance of event device. It configures event\n+device as per below configuration\n+\n+.. code-block:: c\n+\n+   struct rte_event_dev_config event_d_conf = {\n+        .nb_event_queues = ethdev_count, /* Dedicated to each Ethernet port */\n+        .nb_event_ports = num_workers, /* Dedicated to each lcore */\n+        .nb_events_limit  = 4096,\n+        .nb_event_queue_flows = 1024,\n+        .nb_event_port_dequeue_depth = 128,\n+        .nb_event_port_enqueue_depth = 128\n+   };\n+\n+   ret = rte_event_dev_configure(event_d_id, &event_d_conf);\n+   if (ret < 0)\n+        rte_panic(\"Error in configuring event device\\n\");\n+\n+In case of S/W scheduler, application runs eventdev scheduler service on service\n+core. Application retrieves service id and finds the best possible service core to\n+run S/W scheduler.\n+\n+.. code-block:: c\n+\n+        rte_event_dev_info_get(evt_rsrc->event_d_id, &evdev_info);\n+        if (evdev_info.event_dev_cap  & RTE_EVENT_DEV_CAP_DISTRIBUTED_SCHED) {\n+                ret = rte_event_dev_service_id_get(evt_rsrc->event_d_id,\n+                                &service_id);\n+                if (ret != -ESRCH && ret != 0)\n+                        rte_panic(\"Error in starting eventdev service\\n\");\n+                l2fwd_event_service_enable(service_id);\n+        }\n+\n+.. _l2_fwd_app_event_queue_init:\n+\n+Event queue Initialization\n+~~~~~~~~~~~~~~~~~~~~~~~~~~\n+Each Ethernet device is assigned a dedicated event queue which will be linked\n+to all available event ports i.e. each lcore can dequeue packets from any of the\n+Ethernet ports.\n+\n+.. code-block:: c\n+\n+   struct rte_event_queue_conf event_q_conf = {\n+        .nb_atomic_flows = 1024,\n+        .nb_atomic_order_sequences = 1024,\n+        .event_queue_cfg = 0,\n+        .schedule_type = RTE_SCHED_TYPE_ATOMIC,\n+        .priority = RTE_EVENT_DEV_PRIORITY_HIGHEST\n+   };\n+\n+   /* User requested sched mode */\n+   event_q_conf.schedule_type = eventq_sched_mode;\n+   for (event_q_id = 0; event_q_id < ethdev_count; event_q_id++) {\n+        ret = rte_event_queue_setup(event_d_id, event_q_id,\n+                                            &event_q_conf);\n+        if (ret < 0)\n+              rte_panic(\"Error in configuring event queue\\n\");\n+   }\n+\n+In case of S/W scheduler, an extra event queue is created which will be used for\n+Tx adapter service function for enqueue operation.\n+\n+.. _l2_fwd_app_event_port_init:\n+\n+Event port Initialization\n+~~~~~~~~~~~~~~~~~~~~~~~~~\n+Each worker thread is assigned a dedicated event port for enq/deq operations\n+to/from an event device. All event ports are linked with all available event\n+queues.\n+\n+.. code-block:: c\n+\n+   struct rte_event_port_conf event_p_conf = {\n+        .dequeue_depth = 32,\n+        .enqueue_depth = 32,\n+        .new_event_threshold = 4096\n+   };\n+\n+   for (event_p_id = 0; event_p_id < num_workers; event_p_id++) {\n+        ret = rte_event_port_setup(event_d_id, event_p_id,\n+                                   &event_p_conf);\n+        if (ret < 0)\n+              rte_panic(\"Error in configuring event port %d\\n\", event_p_id);\n+\n+        ret = rte_event_port_link(event_d_id, event_p_id, NULL,\n+                                  NULL, 0);\n+        if (ret < 0)\n+              rte_panic(\"Error in linking event port %d to queue\\n\",\n+                        event_p_id);\n+   }\n+\n+In case of S/W scheduler, an extra event port is created by DPDK library which\n+is retrieved  by the application and same will be used by Tx adapter service.\n+\n+.. code-block:: c\n+\n+        ret = rte_event_eth_tx_adapter_event_port_get(tx_adptr_id, &tx_port_id);\n+        if (ret)\n+                rte_panic(\"Failed to get Tx adapter port id: %d\\n\", ret);\n+\n+        ret = rte_event_port_link(event_d_id, tx_port_id,\n+                                  &evt_rsrc.evq.event_q_id[\n+                                        evt_rsrc.evq.nb_queues - 1],\n+                                  NULL, 1);\n+        if (ret != 1)\n+                rte_panic(\"Unable to link Tx adapter port to Tx queue:err=%d\\n\",\n+                          ret);\n+\n+.. _l2_fwd_event_app_adapter_init:\n+\n+Rx/Tx adapter Initialization\n+~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n+Each Ethernet port is assigned a dedicated Rx/Tx adapter for H/W scheduler. Each\n+Ethernet port's Rx queues are connected to its respective event queue at\n+priority 0 via Rx adapter configuration and Ethernet port's tx queues are\n+connected via Tx adapter.\n+\n+.. code-block:: c\n+\n+\tRTE_ETH_FOREACH_DEV(port_id) {\n+\t\tif ((rsrc->enabled_port_mask & (1 << port_id)) == 0)\n+\t\t\tcontinue;\n+\t\tret = rte_event_eth_rx_adapter_create(adapter_id, event_d_id,\n+\t\t\t\t\t\t&evt_rsrc->def_p_conf);\n+\t\tif (ret)\n+\t\t\trte_panic(\"Failed to create rx adapter[%d]\\n\",\n+                                  adapter_id);\n+\n+\t\t/* Configure user requested sched type*/\n+\t\teth_q_conf.ev.sched_type = rsrc->sched_type;\n+\t\teth_q_conf.ev.queue_id = evt_rsrc->evq.event_q_id[q_id];\n+\t\tret = rte_event_eth_rx_adapter_queue_add(adapter_id, port_id,\n+\t\t\t\t\t\t\t -1, &eth_q_conf);\n+\t\tif (ret)\n+\t\t\trte_panic(\"Failed to add queues to Rx adapter\\n\");\n+\n+\t\tret = rte_event_eth_rx_adapter_start(adapter_id);\n+\t\tif (ret)\n+\t\t\trte_panic(\"Rx adapter[%d] start Failed\\n\", adapter_id);\n+\n+\t\tevt_rsrc->rx_adptr.rx_adptr[adapter_id] = adapter_id;\n+\t\tadapter_id++;\n+\t\tif (q_id < evt_rsrc->evq.nb_queues)\n+\t\t\tq_id++;\n+\t}\n+\n+\tadapter_id = 0;\n+\tRTE_ETH_FOREACH_DEV(port_id) {\n+\t\tif ((rsrc->enabled_port_mask & (1 << port_id)) == 0)\n+\t\t\tcontinue;\n+\t\tret = rte_event_eth_tx_adapter_create(adapter_id, event_d_id,\n+\t\t\t\t\t\t&evt_rsrc->def_p_conf);\n+\t\tif (ret)\n+\t\t\trte_panic(\"Failed to create tx adapter[%d]\\n\",\n+                                  adapter_id);\n+\n+\t\tret = rte_event_eth_tx_adapter_queue_add(adapter_id, port_id,\n+\t\t\t\t\t\t\t -1);\n+\t\tif (ret)\n+\t\t\trte_panic(\"Failed to add queues to Tx adapter\\n\");\n+\n+\t\tret = rte_event_eth_tx_adapter_start(adapter_id);\n+\t\tif (ret)\n+\t\t\trte_panic(\"Tx adapter[%d] start Failed\\n\", adapter_id);\n+\n+\t\tevt_rsrc->tx_adptr.tx_adptr[adapter_id] = adapter_id;\n+\t\tadapter_id++;\n+\t}\n+\n+For S/W scheduler instead of dedicated adapters, common Rx/Tx adapters are\n+configured which will be shared among all the Ethernet ports. Also DPDK library\n+need service cores to run internal services for Rx/Tx adapters. Application gets\n+service id for Rx/Tx adapters and after successful setup it runs the services\n+on dedicated service cores.\n+\n+.. code-block:: c\n+\n+\tfor (i = 0; i < evt_rsrc->rx_adptr.nb_rx_adptr; i++) {\n+\t\tret = rte_event_eth_rx_adapter_caps_get(evt_rsrc->event_d_id,\n+\t\t\t\tevt_rsrc->rx_adptr.rx_adptr[i], &caps);\n+\t\tif (ret < 0)\n+\t\t\trte_panic(\"Failed to get Rx adapter[%d] caps\\n\",\n+                                  evt_rsrc->rx_adptr.rx_adptr[i]);\n+\t\tret = rte_event_eth_rx_adapter_service_id_get(\n+                                                evt_rsrc->event_d_id,\n+                                                &service_id);\n+\t\tif (ret != -ESRCH && ret != 0)\n+\t\t\trte_panic(\"Error in starting Rx adapter[%d] service\\n\",\n+                                  evt_rsrc->rx_adptr.rx_adptr[i]);\n+\t\tl2fwd_event_service_enable(service_id);\n+\t}\n+\n+\tfor (i = 0; i < evt_rsrc->tx_adptr.nb_tx_adptr; i++) {\n+\t\tret = rte_event_eth_tx_adapter_caps_get(evt_rsrc->event_d_id,\n+\t\t\t\tevt_rsrc->tx_adptr.tx_adptr[i], &caps);\n+\t\tif (ret < 0)\n+\t\t\trte_panic(\"Failed to get Rx adapter[%d] caps\\n\",\n+                                  evt_rsrc->tx_adptr.tx_adptr[i]);\n+\t\tret = rte_event_eth_tx_adapter_service_id_get(\n+\t\t\t\tevt_rsrc->event_d_id,\n+\t\t\t\t&service_id);\n+\t\tif (ret != -ESRCH && ret != 0)\n+\t\t\trte_panic(\"Error in starting Rx adapter[%d] service\\n\",\n+                                  evt_rsrc->tx_adptr.tx_adptr[i]);\n+\t\tl2fwd_event_service_enable(service_id);\n+\t}\n+\n+.. _l2_fwd_event_app_rx_tx_packets:\n+\n+Receive, Process and Transmit Packets\n+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n+\n+In the **l2fwd_main_loop()** function, the main task is to read ingress packets from\n+the RX queues. This is done using the following code:\n+\n+.. code-block:: c\n+\n+    /*\n+     * Read packet from RX queues\n+     */\n+\n+    for (i = 0; i < qconf->n_rx_port; i++) {\n+        portid = qconf->rx_port_list[i];\n+        nb_rx = rte_eth_rx_burst((uint8_t) portid, 0,  pkts_burst,\n+                                 MAX_PKT_BURST);\n+\n+        for (j = 0; j < nb_rx; j++) {\n+            m = pkts_burst[j];\n+            rte_prefetch0(rte_pktmbuf_mtod(m, void *));\n+            l2fwd_simple_forward(m, portid);\n+        }\n+    }\n+\n+Packets are read in a burst of size MAX_PKT_BURST. The rte_eth_rx_burst()\n+function writes the mbuf pointers in a local table and returns the number of\n+available mbufs in the table.\n+\n+Then, each mbuf in the table is processed by the l2fwd_simple_forward()\n+function. The processing is very simple: process the TX port from the RX port,\n+then replace the source and destination MAC addresses if MAC addresses updating\n+is enabled.\n+\n+During the initialization process, a static array of destination ports\n+(l2fwd_dst_ports[]) is filled such that for each source port, a destination port\n+is assigned that is either the next or previous enabled port from the portmask.\n+If number of ports are odd in portmask then packet from last port will be\n+forwarded to first port i.e. if portmask=0x07, then forwarding will take place\n+like p0--->p1, p1--->p2, p2--->p0.\n+\n+Also to optimize enqueue operation, l2fwd_simple_forward() stores incoming mbufs\n+up to MAX_PKT_BURST. Once it reaches up to limit, all packets are transmitted to\n+destination ports.\n+\n+.. code-block:: c\n+\n+   static void\n+   l2fwd_simple_forward(struct rte_mbuf *m, uint32_t portid)\n+   {\n+       uint32_t dst_port;\n+       int32_t sent;\n+       struct rte_eth_dev_tx_buffer *buffer;\n+\n+       dst_port = l2fwd_dst_ports[portid];\n+\n+       if (mac_updating)\n+           l2fwd_mac_updating(m, dst_port);\n+\n+       buffer = tx_buffer[dst_port];\n+       sent = rte_eth_tx_buffer(dst_port, 0, buffer, m);\n+       if (sent)\n+       port_statistics[dst_port].tx += sent;\n+   }\n+\n+For this test application, the processing is exactly the same for all packets\n+arriving on the same RX port. Therefore, it would have been possible to call\n+the rte_eth_tx_buffer() function directly from the main loop to send all the\n+received packets on the same TX port, using the burst-oriented send function,\n+which is more efficient.\n+\n+However, in real-life applications (such as, L3 routing),\n+packet N is not necessarily forwarded on the same port as packet N-1.\n+The application is implemented to illustrate that, so the same approach can be\n+reused in a more complex application.\n+\n+To ensure that no packets remain in the tables, each lcore does a draining of TX\n+queue in its main loop. This technique introduces some latency when there are\n+not many packets to send, however it improves performance:\n+\n+.. code-block:: c\n+\n+        cur_tsc = rte_rdtsc();\n+\n+        /*\n+        * TX burst queue drain\n+        */\n+        diff_tsc = cur_tsc - prev_tsc;\n+        if (unlikely(diff_tsc > drain_tsc)) {\n+                for (i = 0; i < qconf->n_rx_port; i++) {\n+                        portid = l2fwd_dst_ports[qconf->rx_port_list[i]];\n+                        buffer = tx_buffer[portid];\n+                        sent = rte_eth_tx_buffer_flush(portid, 0,\n+                                                       buffer);\n+                        if (sent)\n+                                port_statistics[portid].tx += sent;\n+                }\n+\n+                /* if timer is enabled */\n+                if (timer_period > 0) {\n+                        /* advance the timer */\n+                        timer_tsc += diff_tsc;\n+\n+                        /* if timer has reached its timeout */\n+                        if (unlikely(timer_tsc >= timer_period)) {\n+                                /* do this only on master core */\n+                                if (lcore_id == rte_get_master_lcore()) {\n+                                        print_stats();\n+                                        /* reset the timer */\n+                                        timer_tsc = 0;\n+                                }\n+                        }\n+                }\n+\n+                prev_tsc = cur_tsc;\n+        }\n+\n+In the **l2fwd_event_loop()** function, the main task is to read ingress\n+packets from the event ports. This is done using the following code:\n+\n+.. code-block:: c\n+\n+        /* Read packet from eventdev */\n+        nb_rx = rte_event_dequeue_burst(event_d_id, event_p_id,\n+                                        events, deq_len, 0);\n+        if (nb_rx == 0) {\n+                rte_pause();\n+                continue;\n+        }\n+\n+        for (i = 0; i < nb_rx; i++) {\n+                mbuf[i] = events[i].mbuf;\n+                rte_prefetch0(rte_pktmbuf_mtod(mbuf[i], void *));\n+        }\n+\n+\n+Before reading packets, deq_len is fetched to ensure correct allowed deq length\n+by the eventdev.\n+The rte_event_dequeue_burst() function writes the mbuf pointers in a local table\n+and returns the number of available mbufs in the table.\n+\n+Then, each mbuf in the table is processed by the l2fwd_eventdev_forward()\n+function. The processing is very simple: process the TX port from the RX port,\n+then replace the source and destination MAC addresses if MAC addresses updating\n+is enabled.\n+\n+During the initialization process, a static array of destination ports\n+(l2fwd_dst_ports[]) is filled such that for each source port, a destination port\n+is assigned that is either the next or previous enabled port from the portmask.\n+If number of ports are odd in portmask then packet from last port will be\n+forwarded to first port i.e. if portmask=0x07, then forwarding will take place\n+like p0--->p1, p1--->p2, p2--->p0.\n+\n+l2fwd_eventdev_forward() does not stores incoming mbufs. Packet will forwarded\n+be to destination ports via Tx adapter or generic event dev enqueue API\n+depending H/W or S/W scheduler is used.\n+\n+.. code-block:: c\n+\n+\tnb_tx = rte_event_eth_tx_adapter_enqueue(event_d_id, port_id, ev,\n+\t\t\t\t\t\t nb_rx);\n+\twhile (nb_tx < nb_rx && !rsrc->force_quit)\n+\t\tnb_tx += rte_event_eth_tx_adapter_enqueue(\n+\t\t\t\tevent_d_id, port_id,\n+\t\t\t\tev + nb_tx, nb_rx - nb_tx);\n",
    "prefixes": [
        "v7",
        "10/10"
    ]
}