get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 105162,
    "url": "http://patches.dpdk.org/api/patches/105162/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/20211216150104.860924-3-sean.morrissey@intel.com/",
    "project": {
        "id": 1,
        "url": "http://patches.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<20211216150104.860924-3-sean.morrissey@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20211216150104.860924-3-sean.morrissey@intel.com",
    "date": "2021-12-16T15:01:04",
    "name": "[v1,2/2] examples/l3fwd: add config file support for EM",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "8b86e0a2786882320d4d29ab80d23eefc013ee99",
    "submitter": {
        "id": 1359,
        "url": "http://patches.dpdk.org/api/people/1359/?format=api",
        "name": "Sean Morrissey",
        "email": "sean.morrissey@intel.com"
    },
    "delegate": null,
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/20211216150104.860924-3-sean.morrissey@intel.com/mbox/",
    "series": [
        {
            "id": 20954,
            "url": "http://patches.dpdk.org/api/series/20954/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=20954",
            "date": "2021-12-16T15:01:02",
            "name": "Add config file support for l3fwd",
            "version": 1,
            "mbox": "http://patches.dpdk.org/series/20954/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/105162/comments/",
    "check": "fail",
    "checks": "http://patches.dpdk.org/api/patches/105162/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 mails.dpdk.org (mails.dpdk.org [217.70.189.124])\n\tby inbox.dpdk.org (Postfix) with ESMTP id C6018A0032;\n\tThu, 16 Dec 2021 16:02:48 +0100 (CET)",
            "from [217.70.189.124] (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id 005A841148;\n\tThu, 16 Dec 2021 16:02:44 +0100 (CET)",
            "from mga05.intel.com (mga05.intel.com [192.55.52.43])\n by mails.dpdk.org (Postfix) with ESMTP id B953E4114F\n for <dev@dpdk.org>; Thu, 16 Dec 2021 16:02:40 +0100 (CET)",
            "from orsmga004.jf.intel.com ([10.7.209.38])\n by fmsmga105.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384;\n 16 Dec 2021 07:01:50 -0800",
            "from silpixa00401215.ir.intel.com ([10.55.128.96])\n by orsmga004.jf.intel.com with ESMTP; 16 Dec 2021 07:01:42 -0800"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple;\n d=intel.com; i=@intel.com; q=dns/txt; s=Intel;\n t=1639666961; x=1671202961;\n h=from:to:cc:subject:date:message-id:in-reply-to:\n references:mime-version:content-transfer-encoding;\n bh=lKkjCkQF2HeupsXLdwHekK9OPKHhlUoHJ7geU8o++fE=;\n b=XSxVtAoJ4Y8USqL4JoUZoMyNBReiBCx1sAO9Di19fOjE3+Eo7gwpOw3a\n 7NOqYPwl4S4uQUg+X1GigO6I5jIvXYk8EqlERxhoEUlOCJApOtGCjckOV\n uexc9XMTzd6FVnEe99es+hIAOd2GbCwOjzE5ZK0Vb4w0k/p8Rx94M+QqX\n bDPahVZXHJSed3BV1dFsuiGmdWy6X5KKu4xzYRrVVkeTDo7gbV6GYmOxi\n ACJrHR2obmpf8jCc9luZC14jKLfxG/cGifpmHTbIhmAY3v9HAwO6Kzad3\n LS2zwBd7x1q9gmUv059YjkAC+ALT2uUVk3Rd8w/osB067Z+1h5n6HitJY g==;",
        "X-IronPort-AV": [
            "E=McAfee;i=\"6200,9189,10199\"; a=\"325793918\"",
            "E=Sophos;i=\"5.88,211,1635231600\"; d=\"scan'208\";a=\"325793918\"",
            "E=Sophos;i=\"5.88,211,1635231600\"; d=\"scan'208\";a=\"615181606\""
        ],
        "X-ExtLoop1": "1",
        "From": "Sean Morrissey <sean.morrissey@intel.com>",
        "To": "",
        "Cc": "dev@dpdk.org, Sean Morrissey <sean.morrissey@intel.com>,\n Ravi Kerur <rkerur@gmail.com>",
        "Subject": "[PATCH v1 2/2] examples/l3fwd: add config file support for EM",
        "Date": "Thu, 16 Dec 2021 15:01:04 +0000",
        "Message-Id": "<20211216150104.860924-3-sean.morrissey@intel.com>",
        "X-Mailer": "git-send-email 2.25.1",
        "In-Reply-To": "<20211216150104.860924-1-sean.morrissey@intel.com>",
        "References": "<20211216150104.860924-1-sean.morrissey@intel.com>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.29",
        "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"
    },
    "content": "Add support to define ipv4 and ipv6 forwarding tables\nfrom reading from a config file for EM with a format\nsimilar to l3fwd-acl one.\n\nWith the removal of the hardcoded route tables for IPv4\nand IPv6 from 'l3fwd_em', these routes have been moved\nto a separate default config file for use with EM.\n\nRelated l3fwd docs have been updated to relfect these\nchanges.\n\nSigned-off-by: Sean Morrissey <sean.morrissey@intel.com>\nSigned-off-by: Ravi Kerur <rkerur@gmail.com>\n---\n doc/guides/sample_app_ug/l3_forward.rst |  89 +++--\n examples/l3fwd/em_default_v4.cfg        |  17 +\n examples/l3fwd/em_default_v6.cfg        |  17 +\n examples/l3fwd/l3fwd_em.c               | 473 ++++++++++++++----------\n examples/l3fwd/l3fwd_route.h            |  38 +-\n 5 files changed, 412 insertions(+), 222 deletions(-)\n create mode 100644 examples/l3fwd/em_default_v4.cfg\n create mode 100644 examples/l3fwd/em_default_v6.cfg",
    "diff": "diff --git a/doc/guides/sample_app_ug/l3_forward.rst b/doc/guides/sample_app_ug/l3_forward.rst\nindex 6d7d7c5cc1..01d86db95d 100644\n--- a/doc/guides/sample_app_ug/l3_forward.rst\n+++ b/doc/guides/sample_app_ug/l3_forward.rst\n@@ -47,6 +47,7 @@ and loaded into the LPM or FIB object at initialization time.\n In the sample application, hash-based and FIB-based forwarding supports\n both IPv4 and IPv6.\n LPM-based forwarding supports IPv4 only.\n+During the initialization phase route rules for IPv4 and IPv6 are read from rule files.\n \n Compiling the Application\n -------------------------\n@@ -61,6 +62,8 @@ Running the Application\n The application has a number of command line options::\n \n     ./dpdk-l3fwd [EAL options] -- -p PORTMASK\n+                             --rule_ipv4=FILE\n+                             --rule_ipv6=FILE\n                              [-P]\n                              [--lookup LOOKUP_METHOD]\n                              --config(port,queue,lcore)[,(port,queue,lcore)]\n@@ -82,6 +85,11 @@ Where,\n \n * ``-p PORTMASK:`` Hexadecimal bitmask of ports to configure\n \n+* ``--rule_ipv4=FILE:`` specify the ipv4 rules entries file.\n+  Each rule occupies one line.\n+\n+* ``--rule_ipv6=FILE:`` specify the ipv6 rules entries file.\n+\n * ``-P:`` Optional, sets all ports to promiscuous mode so that packets are accepted regardless of the packet's Ethernet MAC destination address.\n   Without this option, only packets with the Ethernet MAC destination address set to the Ethernet address of the port are accepted.\n \n@@ -135,7 +143,7 @@ To enable L3 forwarding between two ports, assuming that both ports are in the s\n \n .. code-block:: console\n \n-    ./<build_dir>/examples/dpdk-l3fwd -l 1,2 -n 4 -- -p 0x3 --config=\"(0,0,1),(1,0,2)\"\n+    ./<build_dir>/examples/dpdk-l3fwd -l 1,2 -n 4 -- -p 0x3 --config=\"(0,0,1),(1,0,2)\" --rule_ipv4=\"rule_ipv4.cfg\" --rule_ipv6=\"rule_ipv6.cfg\"\n \n In this command:\n \n@@ -157,19 +165,23 @@ In this command:\n |          |           |           |                                     |\n +----------+-----------+-----------+-------------------------------------+\n \n+*   The -rule_ipv4 option specifies the reading of IPv4 rules sets from the rule_ipv4.cfg file\n+\n+*   The -rule_ipv6 option specifies the reading of IPv6 rules sets from the rule_ipv6.cfg file.\n+\n To use eventdev mode with sync method **ordered** on above mentioned environment,\n Following is the sample command:\n \n .. code-block:: console\n \n-    ./<build_dir>/examples/dpdk-l3fwd -l 0-3 -n 4 -a <event device> -- -p 0x3 --eventq-sched=ordered\n+    ./<build_dir>/examples/dpdk-l3fwd -l 0-3 -n 4 -a <event device> -- -p 0x3 --eventq-sched=ordered --rule_ipv4=\"rule_ipv4.cfg\" --rule_ipv6=\"rule_ipv6.cfg\"\n \n or\n \n .. code-block:: console\n \n     ./<build_dir>/examples/dpdk-l3fwd -l 0-3 -n 4 -a <event device> \\\n-\t\t-- -p 0x03 --mode=eventdev --eventq-sched=ordered\n+\t\t-- -p 0x03 --mode=eventdev --eventq-sched=ordered --rule_ipv4=\"rule_ipv4.cfg\" --rule_ipv6=\"rule_ipv6.cfg\"\n \n In this command:\n \n@@ -192,7 +204,7 @@ scheduler. Following is the sample command:\n \n .. code-block:: console\n \n-    ./<build_dir>/examples/dpdk-l3fwd -l 0-7 -s 0xf0000 -n 4 --vdev event_sw0 -- -p 0x3 --mode=eventdev --eventq-sched=ordered\n+    ./<build_dir>/examples/dpdk-l3fwd -l 0-7 -s 0xf0000 -n 4 --vdev event_sw0 -- -p 0x3 --mode=eventdev --eventq-sched=ordered --rule_ipv4=\"rule_ipv4.cfg\" --rule_ipv6=\"rule_ipv6.cfg\"\n \n In case of eventdev mode, *--config* option is not used for ethernet port\n configuration. Instead each ethernet port will be configured with mentioned\n@@ -216,6 +228,49 @@ The following sections provide some explanation of the sample application code.\n the initialization and run-time paths are very similar to those of the :doc:`l2_forward_real_virtual` and :doc:`l2_forward_event`.\n The following sections describe aspects that are specific to the L3 Forwarding sample application.\n \n+Parse Rules from File\n+~~~~~~~~~~~~~~~~~~~~~\n+\n+The application parses the rules from the file and adds them to the appropriate route table by calling the appropriate function.\n+It ignores empty and comment lines, and parses and validates the rules it reads.\n+If errors are detected, the application exits with messages to identify the errors encountered.\n+\n+The format of the route rules differs based on which lookup method is being used.\n+Therefore, the code only decreases the priority number with each rule it parses.\n+Route rules are mandatory.\n+To read data from the specified file successfully, the application assumes the following:\n+\n+*   Each rule occupies a single line.\n+\n+*   Only the following four rule line types are valid in this application:\n+\n+*   Route rule line, which starts with a leading character 'R'\n+\n+*   Comment line, which starts with a leading character '#'\n+\n+*   Empty line, which consists of a space, form-feed ('\\f'), newline ('\\n'),\n+    carriage return ('\\r'), horizontal tab ('\\t'), or vertical tab ('\\v').\n+\n+Other lines types are considered invalid.\n+\n+*   Rules are organized in descending order of priority,\n+    which means rules at the head of the file always have a higher priority than those further down in the file.\n+\n+*   A typical IPv4 LPM/FIB rule line should have a format as shown below:\n+\n+R<destination_ip>/<ip_mask_length><output_port_number>\n+\n+*   A typical IPv4 EM rule line should have a format as shown below:\n+\n+R<destination_ip><source_ip><destination_port><source_port><protocol><output_port_number>\n+\n+IPv4 addresses are specified in CIDR format as specified in RFC 4632.\n+For LPM/FIB they consist of the dot notation for the address and a prefix length separated by '/'.\n+For example, 192.168.0.34/32, where the address is 192.168.0.34 and the prefix length is 32.\n+For EM they consist of just the dot notation for the address and no prefix length.\n+For example, 192.168.0.34, where the Address is 192.168.0.34.\n+EM also includes ports which are specified as a single number which represents a single port.\n+\n Hash Initialization\n ~~~~~~~~~~~~~~~~~~~\n \n@@ -227,8 +282,6 @@ for the convenience to execute hash performance test on 4M/8M/16M flows.\n \n     The Hash initialization will setup both ipv4 and ipv6 hash table,\n     and populate the either table depending on the value of variable ipv6.\n-    To support the hash performance test with up to 8M single direction flows/16M bi-direction flows,\n-    populate_ipv4_many_flow_into_table() function will populate the hash table with specified hash table entry number(default 4M).\n \n .. note::\n \n@@ -246,22 +299,14 @@ for the convenience to execute hash performance test on 4M/8M/16M flows.\n         {\n             // ...\n \n-            if (hash_entry_number != HASH_ENTRY_NUMBER_DEFAULT) {\n-                if (ipv6 == 0) {\n-                    /* populate the ipv4 hash */\n-                    populate_ipv4_many_flow_into_table(ipv4_l3fwd_lookup_struct[socketid], hash_entry_number);\n-                } else {\n-                    /* populate the ipv6 hash */\n-                    populate_ipv6_many_flow_into_table( ipv6_l3fwd_lookup_struct[socketid], hash_entry_number);\n-                }\n-            } else\n-                if (ipv6 == 0) {\n-                    /* populate the ipv4 hash */\n-                    populate_ipv4_few_flow_into_table(ipv4_l3fwd_lookup_struct[socketid]);\n-                } else {\n-                    /* populate the ipv6 hash */\n-                    populate_ipv6_few_flow_into_table(ipv6_l3fwd_lookup_struct[socketid]);\n-                }\n+            if (ipv6 == 0) {\n+                /* populate the ipv4 hash */\n+                populate_ipv4_flow_into_table(\n+                    ipv4_l3fwd_em_lookup_struct[socketid]);\n+            } else {\n+                /* populate the ipv6 hash */\n+                populate_ipv6_flow_into_table(\n+                    ipv6_l3fwd_em_lookup_struct[socketid]);\n             }\n         }\n     #endif\ndiff --git a/examples/l3fwd/em_default_v4.cfg b/examples/l3fwd/em_default_v4.cfg\nnew file mode 100644\nindex 0000000000..b70bdb6601\n--- /dev/null\n+++ b/examples/l3fwd/em_default_v4.cfg\n@@ -0,0 +1,17 @@\n+#Copy of hard-coded IPv4 FWD table for L3FWD EM\n+R198.18.0.0 198.18.0.1 9 9 0x11 0\n+R198.18.1.0 198.18.1.1 9 9 0x11 1\n+R198.18.2.0 198.18.2.1 9 9 0x11 2\n+R198.18.3.0 198.18.3.1 9 9 0x11 3\n+R198.18.4.0 198.18.4.1 9 9 0x11 4\n+R198.18.5.0 198.18.5.1 9 9 0x11 5\n+R198.18.6.0 198.18.6.1 9 9 0x11 6\n+R198.18.7.0 198.18.7.1 9 9 0x11 7\n+R198.18.8.0 198.18.8.1 9 9 0x11 8\n+R198.18.9.0 198.18.9.1 9 9 0x11 9\n+R198.18.10.0 198.18.10.1 9 9 0x11 10\n+R198.18.11.0 198.18.11.1 9 9 0x11 11\n+R198.18.12.0 198.18.12.1 9 9 0x11 12\n+R198.18.13.0 198.18.13.1 9 9 0x11 13\n+R198.18.14.0 198.18.14.1 9 9 0x11 14\n+R198.18.15.0 198.18.15.1 9 9 0x11 15\ndiff --git a/examples/l3fwd/em_default_v6.cfg b/examples/l3fwd/em_default_v6.cfg\nnew file mode 100644\nindex 0000000000..a18519ff2d\n--- /dev/null\n+++ b/examples/l3fwd/em_default_v6.cfg\n@@ -0,0 +1,17 @@\n+#Copy of hard-coded IPv4 FWD table for L3FWD EM\n+R2001:0200:0000:0000:0000:0000:0000:0000 2001:0200:0000:0000:0000:0000:0000:0001 9 9 0x11 0\n+R2001:0200:0000:0001:0000:0000:0000:0000 2001:0200:0000:0001:0000:0000:0000:0001 9 9 0x11 1\n+R2001:0200:0000:0002:0000:0000:0000:0000 2001:0200:0000:0002:0000:0000:0000:0001 9 9 0x11 2\n+R2001:0200:0000:0003:0000:0000:0000:0000 2001:0200:0000:0003:0000:0000:0000:0001 9 9 0x11 3\n+R2001:0200:0000:0004:0000:0000:0000:0000 2001:0200:0000:0004:0000:0000:0000:0001 9 9 0x11 4\n+R2001:0200:0000:0005:0000:0000:0000:0000 2001:0200:0000:0005:0000:0000:0000:0001 9 9 0x11 5\n+R2001:0200:0000:0006:0000:0000:0000:0000 2001:0200:0000:0006:0000:0000:0000:0001 9 9 0x11 6\n+R2001:0200:0000:0007:0000:0000:0000:0000 2001:0200:0000:0007:0000:0000:0000:0001 9 9 0x11 7\n+R2001:0200:0000:0008:0000:0000:0000:0000 2001:0200:0000:0008:0000:0000:0000:0001 9 9 0x11 8\n+R2001:0200:0000:0009:0000:0000:0000:0000 2001:0200:0000:0009:0000:0000:0000:0001 9 9 0x11 9\n+R2001:0200:0000:000A:0000:0000:0000:0000 2001:0200:0000:000A:0000:0000:0000:0001 9 9 0x11 10\n+R2001:0200:0000:000B:0000:0000:0000:0000 2001:0200:0000:000B:0000:0000:0000:0001 9 9 0x11 11\n+R2001:0200:0000:000C:0000:0000:0000:0000 2001:0200:0000:000C:0000:0000:0000:0001 9 9 0x11 12\n+R2001:0200:0000:000D:0000:0000:0000:0000 2001:0200:0000:000D:0000:0000:0000:0001 9 9 0x11 13\n+R2001:0200:0000:000E:0000:0000:0000:0000 2001:0200:0000:000E:0000:0000:0000:0001 9 9 0x11 14\n+R2001:0200:0000:000F:0000:0000:0000:0000 2001:0200:0000:000F:0000:0000:0000:0001 9 9 0x11 15\ndiff --git a/examples/l3fwd/l3fwd_em.c b/examples/l3fwd/l3fwd_em.c\nindex 4953cdae4e..9a337ed842 100644\n--- a/examples/l3fwd/l3fwd_em.c\n+++ b/examples/l3fwd/l3fwd_em.c\n@@ -27,6 +27,7 @@\n \n #include \"l3fwd.h\"\n #include \"l3fwd_event.h\"\n+#include \"l3fwd_route.h\"\n \n #if defined(RTE_ARCH_X86) || defined(__ARM_FEATURE_CRC32)\n #define EM_HASH_CRC 1\n@@ -42,13 +43,18 @@\n \n #define IPV6_ADDR_LEN 16\n \n-struct ipv4_5tuple {\n-\tuint32_t ip_dst;\n-\tuint32_t ip_src;\n-\tuint16_t port_dst;\n-\tuint16_t port_src;\n-\tuint8_t  proto;\n-} __rte_packed;\n+static struct em_rule *em_route_base_v4;\n+static struct em_rule *em_route_base_v6;\n+\n+enum {\n+\tCB_FLD_DST_ADDR,\n+\tCB_FLD_SRC_ADDR,\n+\tCB_FLD_DST_PORT,\n+\tCB_FLD_SRC_PORT,\n+\tCB_FLD_PROTO,\n+\tCB_FLD_IF_OUT,\n+\tCB_FLD_MAX\n+};\n \n union ipv4_5tuple_host {\n \tstruct {\n@@ -65,14 +71,6 @@ union ipv4_5tuple_host {\n \n #define XMM_NUM_IN_IPV6_5TUPLE 3\n \n-struct ipv6_5tuple {\n-\tuint8_t  ip_dst[IPV6_ADDR_LEN];\n-\tuint8_t  ip_src[IPV6_ADDR_LEN];\n-\tuint16_t port_dst;\n-\tuint16_t port_src;\n-\tuint8_t  proto;\n-} __rte_packed;\n-\n union ipv6_5tuple_host {\n \tstruct {\n \t\tuint16_t pad0;\n@@ -87,8 +85,6 @@ union ipv6_5tuple_host {\n \txmm_t xmm[XMM_NUM_IN_IPV6_5TUPLE];\n };\n \n-\n-\n struct ipv4_l3fwd_em_route {\n \tstruct ipv4_5tuple key;\n \tuint8_t if_out;\n@@ -99,66 +95,6 @@ struct ipv6_l3fwd_em_route {\n \tuint8_t if_out;\n };\n \n-/* 198.18.0.0/16 are set aside for RFC2544 benchmarking (RFC5735).\n- * Use RFC863 Discard Protocol.\n- */\n-static const struct ipv4_l3fwd_em_route ipv4_l3fwd_em_route_array[] = {\n-\t{{RTE_IPV4(198, 18, 0, 0), RTE_IPV4(198, 18, 0, 1),  9, 9, IPPROTO_UDP}, 0},\n-\t{{RTE_IPV4(198, 18, 1, 0), RTE_IPV4(198, 18, 1, 1),  9, 9, IPPROTO_UDP}, 1},\n-\t{{RTE_IPV4(198, 18, 2, 0), RTE_IPV4(198, 18, 2, 1),  9, 9, IPPROTO_UDP}, 2},\n-\t{{RTE_IPV4(198, 18, 3, 0), RTE_IPV4(198, 18, 3, 1),  9, 9, IPPROTO_UDP}, 3},\n-\t{{RTE_IPV4(198, 18, 4, 0), RTE_IPV4(198, 18, 4, 1),  9, 9, IPPROTO_UDP}, 4},\n-\t{{RTE_IPV4(198, 18, 5, 0), RTE_IPV4(198, 18, 5, 1),  9, 9, IPPROTO_UDP}, 5},\n-\t{{RTE_IPV4(198, 18, 6, 0), RTE_IPV4(198, 18, 6, 1),  9, 9, IPPROTO_UDP}, 6},\n-\t{{RTE_IPV4(198, 18, 7, 0), RTE_IPV4(198, 18, 7, 1),  9, 9, IPPROTO_UDP}, 7},\n-\t{{RTE_IPV4(198, 18, 8, 0), RTE_IPV4(198, 18, 8, 1),  9, 9, IPPROTO_UDP}, 8},\n-\t{{RTE_IPV4(198, 18, 9, 0), RTE_IPV4(198, 18, 9, 1),  9, 9, IPPROTO_UDP}, 9},\n-\t{{RTE_IPV4(198, 18, 10, 0), RTE_IPV4(198, 18, 10, 1),  9, 9, IPPROTO_UDP}, 10},\n-\t{{RTE_IPV4(198, 18, 11, 0), RTE_IPV4(198, 18, 11, 1),  9, 9, IPPROTO_UDP}, 11},\n-\t{{RTE_IPV4(198, 18, 12, 0), RTE_IPV4(198, 18, 12, 1),  9, 9, IPPROTO_UDP}, 12},\n-\t{{RTE_IPV4(198, 18, 13, 0), RTE_IPV4(198, 18, 13, 1),  9, 9, IPPROTO_UDP}, 13},\n-\t{{RTE_IPV4(198, 18, 14, 0), RTE_IPV4(198, 18, 14, 1),  9, 9, IPPROTO_UDP}, 14},\n-\t{{RTE_IPV4(198, 18, 15, 0), RTE_IPV4(198, 18, 15, 1),  9, 9, IPPROTO_UDP}, 15},\n-};\n-\n-/* 2001:0200::/48 is IANA reserved range for IPv6 benchmarking (RFC5180).\n- * Use RFC863 Discard Protocol.\n- */\n-static const struct ipv6_l3fwd_em_route ipv6_l3fwd_em_route_array[] = {\n-\t{{{32, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},\n-\t  {32, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, 9, 9, IPPROTO_UDP}, 0},\n-\t{{{32, 1, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0},\n-\t  {32, 1, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1}, 9, 9, IPPROTO_UDP}, 1},\n-\t{{{32, 1, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0},\n-\t  {32, 1, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 1}, 9, 9, IPPROTO_UDP}, 2},\n-\t{{{32, 1, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0},\n-\t  {32, 1, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 1}, 9, 9, IPPROTO_UDP}, 3},\n-\t{{{32, 1, 2, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0},\n-\t  {32, 1, 2, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 1}, 9, 9, IPPROTO_UDP}, 4},\n-\t{{{32, 1, 2, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0},\n-\t  {32, 1, 2, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 1}, 9, 9, IPPROTO_UDP}, 5},\n-\t{{{32, 1, 2, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0},\n-\t  {32, 1, 2, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 1}, 9, 9, IPPROTO_UDP}, 6},\n-\t{{{32, 1, 2, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0},\n-\t  {32, 1, 2, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 1}, 9, 9, IPPROTO_UDP}, 7},\n-\t{{{32, 1, 2, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0},\n-\t  {32, 1, 2, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 1}, 9, 9, IPPROTO_UDP}, 8},\n-\t{{{32, 1, 2, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0},\n-\t  {32, 1, 2, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 1}, 9, 9, IPPROTO_UDP}, 9},\n-\t{{{32, 1, 2, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0},\n-\t  {32, 1, 2, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 1}, 9, 9, IPPROTO_UDP}, 10},\n-\t{{{32, 1, 2, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0},\n-\t  {32, 1, 2, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 1}, 9, 9, IPPROTO_UDP}, 11},\n-\t{{{32, 1, 2, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0},\n-\t  {32, 1, 2, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 1}, 9, 9, IPPROTO_UDP}, 12},\n-\t{{{32, 1, 2, 0, 0, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0},\n-\t  {32, 1, 2, 0, 0, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 1}, 9, 9, IPPROTO_UDP}, 13},\n-\t{{{32, 1, 2, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0},\n-\t  {32, 1, 2, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 1}, 9, 9, IPPROTO_UDP}, 14},\n-\t{{{32, 1, 2, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0},\n-\t  {32, 1, 2, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 1}, 9, 9, IPPROTO_UDP}, 15},\n-};\n-\n struct rte_hash *ipv4_l3fwd_em_lookup_struct[NB_SOCKETS];\n struct rte_hash *ipv6_l3fwd_em_lookup_struct[NB_SOCKETS];\n \n@@ -235,10 +171,6 @@ ipv6_hash_crc(const void *data, __rte_unused uint32_t data_len,\n \treturn init_val;\n }\n \n-#define IPV4_L3FWD_EM_NUM_ROUTES RTE_DIM(ipv4_l3fwd_em_route_array)\n-\n-#define IPV6_L3FWD_EM_NUM_ROUTES RTE_DIM(ipv6_l3fwd_em_route_array)\n-\n static uint8_t ipv4_l3fwd_out_if[L3FWD_HASH_ENTRIES] __rte_cache_aligned;\n static uint8_t ipv6_l3fwd_out_if[L3FWD_HASH_ENTRIES] __rte_cache_aligned;\n \n@@ -346,6 +278,178 @@ em_get_ipv6_dst_port(void *ipv6_hdr, uint16_t portid, void *lookup_struct)\n #include \"l3fwd_em.h\"\n #endif\n \n+static int\n+em_parse_v6_net(const char *in, uint32_t *v)\n+{\n+\tint32_t rc;\n+\n+\t/* get address. */\n+\trc = inet_pton(AF_INET6, in, &v);\n+\tif (rc != 1)\n+\t\treturn -EINVAL;\n+\n+\treturn 0;\n+}\n+\n+static int\n+em_parse_v6_rule(char *str, struct em_rule *v)\n+{\n+\tint i, rc;\n+\tuint32_t ip[4];\n+\tchar *s, *sp, *in[CB_FLD_MAX];\n+\tstatic const char *dlm = \" \\t\\n\";\n+\tint dim = CB_FLD_MAX;\n+\ts = str;\n+\n+\tfor (i = 0; i != dim; i++, s = NULL) {\n+\t\tin[i] = strtok_r(s, dlm, &sp);\n+\t\tif (in[i] == NULL)\n+\t\t\treturn -EINVAL;\n+\t}\n+\n+\tip[0] = *(v->v6_key.ip32_dst);\n+\trc = em_parse_v6_net(in[CB_FLD_DST_ADDR], ip);\n+\tif (rc != 0)\n+\t\treturn rc;\n+\tip[0] = *(v->v6_key.ip32_src);\n+\trc = em_parse_v6_net(in[CB_FLD_SRC_ADDR], ip);\n+\tif (rc != 0)\n+\t\treturn rc;\n+\n+\n+\t/* source port. */\n+\tGET_CB_FIELD(in[CB_FLD_SRC_PORT], v->v6_key.port_src, 0, UINT16_MAX, 0);\n+\t/* destination port. */\n+\tGET_CB_FIELD(in[CB_FLD_DST_PORT], v->v6_key.port_dst, 0, UINT16_MAX, 0);\n+\t/* protocol. */\n+\tGET_CB_FIELD(in[CB_FLD_PROTO], v->v6_key.proto, 0, UINT8_MAX, 0);\n+\t/* out interface. */\n+\tGET_CB_FIELD(in[CB_FLD_IF_OUT], v->if_out, 0, UINT8_MAX, 0);\n+\n+\treturn 0;\n+}\n+\n+static int\n+em_parse_v4_rule(char *str, struct em_rule *v)\n+{\n+\tint i, rc;\n+\tchar *s, *sp, *in[CB_FLD_MAX];\n+\tstatic const char *dlm = \" \\t\\n\";\n+\tint dim = CB_FLD_MAX;\n+\ts = str;\n+\n+\tfor (i = 0; i != dim; i++, s = NULL) {\n+\t\tin[i] = strtok_r(s, dlm, &sp);\n+\t\tif (in[i] == NULL)\n+\t\t\treturn -EINVAL;\n+\t}\n+\n+\trc = inet_pton(AF_INET, in[CB_FLD_DST_ADDR], &(v->v4_key.ip_dst));\n+\tv->v4_key.ip_dst = ntohl(v->v4_key.ip_dst);\n+\tif (rc != 1)\n+\t\treturn rc;\n+\n+\trc = inet_pton(AF_INET, in[CB_FLD_SRC_ADDR], &(v->v4_key.ip_src));\n+\tv->v4_key.ip_src = ntohl(v->v4_key.ip_src);\n+\tif (rc != 1)\n+\t\treturn rc;\n+\n+\t/* source port. */\n+\tGET_CB_FIELD(in[CB_FLD_SRC_PORT], v->v4_key.port_src, 0, UINT16_MAX, 0);\n+\t/* destination port. */\n+\tGET_CB_FIELD(in[CB_FLD_DST_PORT], v->v4_key.port_dst, 0, UINT16_MAX, 0);\n+\t/* protocol. */\n+\tGET_CB_FIELD(in[CB_FLD_PROTO], v->v4_key.proto, 0, UINT8_MAX, 0);\n+\t/* out interface. */\n+\tGET_CB_FIELD(in[CB_FLD_IF_OUT], v->if_out, 0, UINT8_MAX, 0);\n+\n+\treturn 0;\n+}\n+\n+static int\n+em_add_rules(const char *rule_path,\n+\t\tstruct em_rule **proute_base,\n+\t\tint (*parser)(char *, struct em_rule *))\n+{\n+\tstruct em_rule *route_rules;\n+\tstruct em_rule *next;\n+\tunsigned int route_num = 0;\n+\tunsigned int route_cnt = 0;\n+\tchar buff[LINE_MAX];\n+\tFILE *fh;\n+\tunsigned int i = 0, rule_size = sizeof(*next);\n+\tint val;\n+\n+\t*proute_base = NULL;\n+\tfh = fopen(rule_path, \"rb\");\n+\tif (fh == NULL)\n+\t\treturn -EINVAL;\n+\n+\twhile ((fgets(buff, LINE_MAX, fh) != NULL)) {\n+\t\tif (buff[0] == ROUTE_LEAD_CHAR)\n+\t\t\troute_num++;\n+\t}\n+\n+\tif (route_num == 0) {\n+\t\tfclose(fh);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tval = fseek(fh, 0, SEEK_SET);\n+\tif (val < 0) {\n+\t\tfclose(fh);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\troute_rules = calloc(route_num, rule_size);\n+\n+\tif (route_rules == NULL) {\n+\t\tfclose(fh);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\ti = 0;\n+\twhile (fgets(buff, LINE_MAX, fh) != NULL) {\n+\t\ti++;\n+\t\tif (is_bypass_line(buff))\n+\t\t\tcontinue;\n+\n+\t\tchar s = buff[0];\n+\n+\t\t/* Route entry */\n+\t\tif (s == ROUTE_LEAD_CHAR)\n+\t\t\tnext = &route_rules[route_cnt];\n+\n+\t\t/* Illegal line */\n+\t\telse {\n+\t\t\tRTE_LOG(ERR, L3FWD,\n+\t\t\t\t\"%s Line %u: should start with leading \"\n+\t\t\t\t\"char %c\\n\",\n+\t\t\t\trule_path, i, ROUTE_LEAD_CHAR);\n+\t\t\tfclose(fh);\n+\t\t\tfree(route_rules);\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\n+\t\tif (parser(buff + 1, next) != 0) {\n+\t\t\tRTE_LOG(ERR, L3FWD,\n+\t\t\t\t\"%s Line %u: parse rules error\\n\",\n+\t\t\t\trule_path, i);\n+\t\t\tfclose(fh);\n+\t\t\tfree(route_rules);\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\n+\t\troute_cnt++;\n+\t}\n+\n+\tfclose(fh);\n+\n+\t*proute_base = route_rules;\n+\n+\treturn route_cnt;\n+}\n+\n static void\n convert_ipv4_5tuple(struct ipv4_5tuple *key1,\n \t\tunion ipv4_5tuple_host *key2)\n@@ -382,122 +486,92 @@ convert_ipv6_5tuple(struct ipv6_5tuple *key1,\n #define BIT_8_TO_15 0x0000ff00\n \n static inline void\n-populate_ipv4_few_flow_into_table(const struct rte_hash *h)\n+populate_ipv4_flow_into_table(const struct rte_hash *h)\n {\n-\tuint32_t i;\n+\tint i;\n \tint32_t ret;\n+\tstruct rte_eth_dev_info dev_info;\n+\tchar srcbuf[INET6_ADDRSTRLEN];\n+\tchar dstbuf[INET6_ADDRSTRLEN];\n \n \tmask0 = (rte_xmm_t){.u32 = {BIT_8_TO_15, ALL_32_BITS,\n \t\t\t\tALL_32_BITS, ALL_32_BITS} };\n \n-\tfor (i = 0; i < IPV4_L3FWD_EM_NUM_ROUTES; i++) {\n-\t\tstruct ipv4_l3fwd_em_route  entry;\n+\tfor (i = 0; i < route_num_v4; i++) {\n+\t\tstruct em_rule *entry;\n \t\tunion ipv4_5tuple_host newkey;\n+\t\tstruct in_addr src;\n+\t\tstruct in_addr dst;\n \n-\t\tentry = ipv4_l3fwd_em_route_array[i];\n-\t\tconvert_ipv4_5tuple(&entry.key, &newkey);\n+\t\tif ((1 << em_route_base_v4[i].if_out &\n+\t\t\t\tenabled_port_mask) == 0)\n+\t\t\tcontinue;\n+\n+\t\tentry = &em_route_base_v4[i];\n+\t\tconvert_ipv4_5tuple(&(entry->v4_key), &newkey);\n \t\tret = rte_hash_add_key(h, (void *) &newkey);\n \t\tif (ret < 0) {\n \t\t\trte_exit(EXIT_FAILURE, \"Unable to add entry %\" PRIu32\n \t\t\t\t\" to the l3fwd hash.\\n\", i);\n \t\t}\n-\t\tipv4_l3fwd_out_if[ret] = entry.if_out;\n+\t\tipv4_l3fwd_out_if[ret] = entry->if_out;\n+\t\trte_eth_dev_info_get(em_route_base_v4[i].if_out,\n+\t\t\t\t     &dev_info);\n+\n+\t\tsrc.s_addr = htonl(em_route_base_v4[i].v4_key.ip_src);\n+\t\tdst.s_addr = htonl(em_route_base_v4[i].v4_key.ip_dst);\n+\t\tprintf(\"EM: Adding route %s %s (%d) [%s]\\n\",\n+\t\t\t   inet_ntop(AF_INET, &dst, dstbuf, sizeof(dstbuf)),\n+\t\t       inet_ntop(AF_INET, &src, srcbuf, sizeof(srcbuf)),\n+\t\t       em_route_base_v4[i].if_out, dev_info.device->name);\n \t}\n \tprintf(\"Hash: Adding 0x%\" PRIx64 \" keys\\n\",\n-\t\t(uint64_t)IPV4_L3FWD_EM_NUM_ROUTES);\n+\t\t(uint64_t)route_num_v4);\n }\n \n #define BIT_16_TO_23 0x00ff0000\n static inline void\n-populate_ipv6_few_flow_into_table(const struct rte_hash *h)\n+populate_ipv6_flow_into_table(const struct rte_hash *h)\n {\n-\tuint32_t i;\n+\tint i;\n \tint32_t ret;\n+\tstruct rte_eth_dev_info dev_info;\n+\tchar srcbuf[INET6_ADDRSTRLEN];\n+\tchar dstbuf[INET6_ADDRSTRLEN];\n \n \tmask1 = (rte_xmm_t){.u32 = {BIT_16_TO_23, ALL_32_BITS,\n \t\t\t\tALL_32_BITS, ALL_32_BITS} };\n \n \tmask2 = (rte_xmm_t){.u32 = {ALL_32_BITS, ALL_32_BITS, 0, 0} };\n \n-\tfor (i = 0; i < IPV6_L3FWD_EM_NUM_ROUTES; i++) {\n-\t\tstruct ipv6_l3fwd_em_route entry;\n+\tfor (i = 0; i < route_num_v6; i++) {\n+\t\tstruct em_rule *entry;\n \t\tunion ipv6_5tuple_host newkey;\n \n-\t\tentry = ipv6_l3fwd_em_route_array[i];\n-\t\tconvert_ipv6_5tuple(&entry.key, &newkey);\n+\t\tif ((1 << em_route_base_v6[i].if_out &\n+\t\t\t\tenabled_port_mask) == 0)\n+\t\t\tcontinue;\n+\n+\t\tentry = &em_route_base_v6[i];\n+\t\tconvert_ipv6_5tuple(&(entry->v6_key), &newkey);\n \t\tret = rte_hash_add_key(h, (void *) &newkey);\n \t\tif (ret < 0) {\n \t\t\trte_exit(EXIT_FAILURE, \"Unable to add entry %\" PRIu32\n \t\t\t\t\" to the l3fwd hash.\\n\", i);\n \t\t}\n-\t\tipv6_l3fwd_out_if[ret] = entry.if_out;\n+\t\tipv6_l3fwd_out_if[ret] = entry->if_out;\n+\t\trte_eth_dev_info_get(em_route_base_v6[i].if_out,\n+\t\t\t\t     &dev_info);\n+\n+\t\tprintf(\"EM: Adding route %s %s (%d) [%s]\\n\",\n+\t\t\t   inet_ntop(AF_INET6, em_route_base_v6[i].v6_key.ip32_dst,\n+\t\t\t   dstbuf, sizeof(dstbuf)),\n+\t\t       inet_ntop(AF_INET6, em_route_base_v6[i].v6_key.ip32_src,\n+\t\t\t   srcbuf, sizeof(srcbuf)),\n+\t\t       em_route_base_v6[i].if_out, dev_info.device->name);\n \t}\n \tprintf(\"Hash: Adding 0x%\" PRIx64 \"keys\\n\",\n-\t\t(uint64_t)IPV6_L3FWD_EM_NUM_ROUTES);\n-}\n-\n-#define NUMBER_PORT_USED 16\n-static inline void\n-populate_ipv4_many_flow_into_table(const struct rte_hash *h,\n-\t\tunsigned int nr_flow)\n-{\n-\tunsigned i;\n-\n-\tmask0 = (rte_xmm_t){.u32 = {BIT_8_TO_15, ALL_32_BITS,\n-\t\t\t\tALL_32_BITS, ALL_32_BITS} };\n-\n-\tfor (i = 0; i < nr_flow; i++) {\n-\t\tuint8_t port = i % NUMBER_PORT_USED;\n-\t\tstruct ipv4_l3fwd_em_route entry;\n-\t\tunion ipv4_5tuple_host newkey;\n-\n-\t\tuint8_t a = (uint8_t)((port + 1) % BYTE_VALUE_MAX);\n-\n-\t\t/* Create the ipv4 exact match flow */\n-\t\tmemset(&entry, 0, sizeof(entry));\n-\t\tentry = ipv4_l3fwd_em_route_array[port];\n-\t\tentry.key.ip_dst = RTE_IPV4(198, 18, port, a);\n-\t\tconvert_ipv4_5tuple(&entry.key, &newkey);\n-\t\tint32_t ret = rte_hash_add_key(h, (void *) &newkey);\n-\n-\t\tif (ret < 0)\n-\t\t\trte_exit(EXIT_FAILURE, \"Unable to add entry %u\\n\", i);\n-\n-\t\tipv4_l3fwd_out_if[ret] = (uint8_t) entry.if_out;\n-\n-\t}\n-\tprintf(\"Hash: Adding 0x%x keys\\n\", nr_flow);\n-}\n-\n-static inline void\n-populate_ipv6_many_flow_into_table(const struct rte_hash *h,\n-\t\tunsigned int nr_flow)\n-{\n-\tunsigned i;\n-\n-\tmask1 = (rte_xmm_t){.u32 = {BIT_16_TO_23, ALL_32_BITS,\n-\t\t\t\tALL_32_BITS, ALL_32_BITS} };\n-\tmask2 = (rte_xmm_t){.u32 = {ALL_32_BITS, ALL_32_BITS, 0, 0} };\n-\n-\tfor (i = 0; i < nr_flow; i++) {\n-\t\tuint8_t port = i % NUMBER_PORT_USED;\n-\t\tstruct ipv6_l3fwd_em_route entry;\n-\t\tunion ipv6_5tuple_host newkey;\n-\n-\t\t/* Create the ipv6 exact match flow */\n-\t\tmemset(&entry, 0, sizeof(entry));\n-\t\tentry = ipv6_l3fwd_em_route_array[port];\n-\t\tentry.key.ip_dst[15] = (port + 1) % BYTE_VALUE_MAX;\n-\t\tconvert_ipv6_5tuple(&entry.key, &newkey);\n-\t\tint32_t ret = rte_hash_add_key(h, (void *) &newkey);\n-\n-\t\tif (ret < 0)\n-\t\t\trte_exit(EXIT_FAILURE, \"Unable to add entry %u\\n\", i);\n-\n-\t\tipv6_l3fwd_out_if[ret] = (uint8_t) entry.if_out;\n-\n-\t}\n-\tprintf(\"Hash: Adding 0x%x keys\\n\", nr_flow);\n+\t\t(uint64_t)route_num_v6);\n }\n \n /* Requirements:\n@@ -972,17 +1046,53 @@ em_event_main_loop_tx_q_burst_vector(__rte_unused void *dummy)\n \treturn 0;\n }\n \n+static void\n+free_em_routes(void)\n+{\n+\tfree(em_route_base_v4);\n+\tfree(em_route_base_v6);\n+\tem_route_base_v4 = NULL;\n+\tem_route_base_v6 = NULL;\n+\troute_num_v4 = 0;\n+\troute_num_v6 = 0;\n+}\n+\n /* Load rules from the input file */\n void\n read_config_files_em(void)\n {\n-\t/* Empty till config file support added to EM */\n+\t/* ipv4 check */\n+\tif (parm_config.rule_ipv4_name != NULL) {\n+\t\troute_num_v4 = em_add_rules(parm_config.rule_ipv4_name,\n+\t\t\t\t\t&em_route_base_v4, &em_parse_v4_rule);\n+\t\tif (route_num_v4 < 0) {\n+\t\t\tfree_em_routes();\n+\t\t\trte_exit(EXIT_FAILURE, \"Failed to add EM IPv4 rules\\n\");\n+\t\t}\n+\t} else {\n+\t\tRTE_LOG(ERR, L3FWD, \"EM IPv4 rule file not specified\\n\");\n+\t\trte_exit(EXIT_FAILURE, \"Failed to get valid EM options\\n\");\n+\t}\n+\n+\t/* ipv6 check */\n+\tif (parm_config.rule_ipv6_name != NULL) {\n+\t\troute_num_v6 = em_add_rules(parm_config.rule_ipv6_name,\n+\t\t\t\t\t&em_route_base_v6, &em_parse_v6_rule);\n+\t\tif (route_num_v6 < 0) {\n+\t\t\tfree_em_routes();\n+\t\t\trte_exit(EXIT_FAILURE, \"Failed to add EM IPv6 rules\\n\");\n+\t\t}\n+\t} else {\n+\t\tRTE_LOG(ERR, L3FWD, \"EM IPv6 rule file not specified\\n\");\n+\t\trte_exit(EXIT_FAILURE, \"Failed to get valid EM options\\n\");\n+\t}\n }\n \n /* Initialize exact match (hash) parameters. 8< */\n void\n setup_hash(const int socketid)\n {\n+\tprintf(\"IPPPROTO_UDP: %d\\n\", IPPROTO_UDP);\n \tstruct rte_hash_parameters ipv4_l3fwd_hash_params = {\n \t\t.name = NULL,\n \t\t.entries = L3FWD_HASH_ENTRIES,\n@@ -1023,35 +1133,18 @@ setup_hash(const int socketid)\n \t\t\t\"Unable to create the l3fwd hash on socket %d\\n\",\n \t\t\tsocketid);\n \n-\tif (hash_entry_number != HASH_ENTRY_NUMBER_DEFAULT) {\n-\t\t/* For testing hash matching with a large number of flows we\n-\t\t * generate millions of IP 5-tuples with an incremented dst\n-\t\t * address to initialize the hash table. */\n-\t\tif (ipv6 == 0) {\n-\t\t\t/* populate the ipv4 hash */\n-\t\t\tpopulate_ipv4_many_flow_into_table(\n-\t\t\t\tipv4_l3fwd_em_lookup_struct[socketid],\n-\t\t\t\thash_entry_number);\n-\t\t} else {\n-\t\t\t/* populate the ipv6 hash */\n-\t\t\tpopulate_ipv6_many_flow_into_table(\n-\t\t\t\tipv6_l3fwd_em_lookup_struct[socketid],\n-\t\t\t\thash_entry_number);\n-\t\t}\n+\t/*\n+\t * Use data from ipv4/ipv6 l3fwd config file\n+\t * directly to initialize the hash table.\n+\t */\n+\tif (ipv6 == 0) {\n+\t\t/* populate the ipv4 hash */\n+\t\tpopulate_ipv4_flow_into_table(\n+\t\t\tipv4_l3fwd_em_lookup_struct[socketid]);\n \t} else {\n-\t\t/*\n-\t\t * Use data in ipv4/ipv6 l3fwd lookup table\n-\t\t * directly to initialize the hash table.\n-\t\t */\n-\t\tif (ipv6 == 0) {\n-\t\t\t/* populate the ipv4 hash */\n-\t\t\tpopulate_ipv4_few_flow_into_table(\n-\t\t\t\tipv4_l3fwd_em_lookup_struct[socketid]);\n-\t\t} else {\n-\t\t\t/* populate the ipv6 hash */\n-\t\t\tpopulate_ipv6_few_flow_into_table(\n-\t\t\t\tipv6_l3fwd_em_lookup_struct[socketid]);\n-\t\t}\n+\t\t/* populate the ipv6 hash */\n+\t\tpopulate_ipv6_flow_into_table(\n+\t\t\tipv6_l3fwd_em_lookup_struct[socketid]);\n \t}\n }\n /* >8 End of initialization of hash parameters. */\ndiff --git a/examples/l3fwd/l3fwd_route.h b/examples/l3fwd/l3fwd_route.h\nindex 6d41c926b1..a3ac991407 100644\n--- a/examples/l3fwd/l3fwd_route.h\n+++ b/examples/l3fwd/l3fwd_route.h\n@@ -2,17 +2,27 @@\n  * Copyright(c) 2021 Intel Corporation\n  */\n \n-struct ipv4_l3fwd_route {\n-\tuint32_t ip;\n-\tuint8_t  depth;\n-\tuint8_t  if_out;\n-};\n+struct ipv4_5tuple {\n+\tuint32_t ip_dst;\n+\tuint32_t ip_src;\n+\tuint16_t port_dst;\n+\tuint16_t port_src;\n+\tuint8_t  proto;\n+} __rte_packed;\n \n-struct ipv6_l3fwd_route {\n-\tuint8_t ip[16];\n-\tuint8_t depth;\n-\tuint8_t if_out;\n-};\n+struct ipv6_5tuple {\n+\tunion {\n+\t\tuint8_t  ip_dst[IPV6_ADDR_LEN];\n+\t\tuint32_t ip32_dst[4];\n+\t};\n+\tunion {\n+\t\tuint8_t  ip_src[IPV6_ADDR_LEN];\n+\t\tuint32_t ip32_src[4];\n+\t};\n+\tuint16_t port_dst;\n+\tuint16_t port_src;\n+\tuint8_t  proto;\n+} __rte_packed;\n \n struct lpm_route_rule {\n \tunion {\n@@ -26,6 +36,14 @@ struct lpm_route_rule {\n \tuint8_t if_out;\n };\n \n+struct em_rule {\n+\t\tunion {\n+\t\tstruct ipv4_5tuple v4_key;\n+\t\tstruct ipv6_5tuple v6_key;\n+\t};\n+\tuint8_t if_out;\n+};\n+\n extern struct lpm_route_rule *route_base_v4;\n extern struct lpm_route_rule *route_base_v6;\n extern int route_num_v4;\n",
    "prefixes": [
        "v1",
        "2/2"
    ]
}