get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 14782,
    "url": "http://patches.dpdk.org/api/patches/14782/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/1468316684-220669-2-git-send-email-roy.fan.zhang@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": "<1468316684-220669-2-git-send-email-roy.fan.zhang@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1468316684-220669-2-git-send-email-roy.fan.zhang@intel.com",
    "date": "2016-07-12T09:44:43",
    "name": "[dpdk-dev,v3,1/2] examples/ipsec-secgw: add configuration file support",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "7e8c2a15c5be4be69ec79eba62dce45850b35d38",
    "submitter": {
        "id": 304,
        "url": "http://patches.dpdk.org/api/people/304/?format=api",
        "name": "Fan Zhang",
        "email": "roy.fan.zhang@intel.com"
    },
    "delegate": null,
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/1468316684-220669-2-git-send-email-roy.fan.zhang@intel.com/mbox/",
    "series": [],
    "comments": "http://patches.dpdk.org/api/patches/14782/comments/",
    "check": "pending",
    "checks": "http://patches.dpdk.org/api/patches/14782/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 [IPv6:::1])\n\tby dpdk.org (Postfix) with ESMTP id 9DA7F374F;\n\tTue, 12 Jul 2016 11:44:51 +0200 (CEST)",
            "from mga14.intel.com (mga14.intel.com [192.55.52.115])\n\tby dpdk.org (Postfix) with ESMTP id E05B93237\n\tfor <dev@dpdk.org>; Tue, 12 Jul 2016 11:44:48 +0200 (CEST)",
            "from orsmga001.jf.intel.com ([10.7.209.18])\n\tby fmsmga103.fm.intel.com with ESMTP; 12 Jul 2016 02:44:48 -0700",
            "from sie-lab-212-071.ir.intel.com (HELO silvfanzhan2.ir.intel.com)\n\t([10.237.212.71])\n\tby orsmga001.jf.intel.com with ESMTP; 12 Jul 2016 02:44:46 -0700"
        ],
        "X-ExtLoop1": "1",
        "X-IronPort-AV": "E=Sophos;i=\"5.28,351,1464678000\"; d=\"scan'208\";a=\"993538038\"",
        "From": "Fan Zhang <roy.fan.zhang@intel.com>",
        "To": "dev@dpdk.org",
        "Cc": "sergio.gonzalez.monroy@intel.com",
        "Date": "Tue, 12 Jul 2016 10:44:43 +0100",
        "Message-Id": "<1468316684-220669-2-git-send-email-roy.fan.zhang@intel.com>",
        "X-Mailer": "git-send-email 2.5.5",
        "In-Reply-To": "<1468316684-220669-1-git-send-email-roy.fan.zhang@intel.com>",
        "References": "<1468248213-13100-1-git-send-email-roy.fan.zhang@intel.com>\n\t<1468316684-220669-1-git-send-email-roy.fan.zhang@intel.com>",
        "Subject": "[dpdk-dev] [PATCH v3 1/2] examples/ipsec-secgw: add configuration\n\tfile support",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "patches and discussions about DPDK <dev.dpdk.org>",
        "List-Unsubscribe": "<http://dpdk.org/ml/options/dev>,\n\t<mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://dpdk.org/ml/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<http://dpdk.org/ml/listinfo/dev>,\n\t<mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "This patch adds the configuration file support to ipsec_secgw\nsample application. Instead of hard-coded rules, the users can\nspecify their own SP, SA, and routing rules in the configuration\nfile. An command line option \"-f\" is added to pass the\nconfiguration file location to the application.\n\nConfiguration item formats:\n\nSP rule format:\nsp <ip_ver> <dir> esp <action> <priority> <src_ip> <dst_ip> \\\n<proto> <sport> <dport>\n\nSA rule format:\nsa <dir> <spi> <cipher_algo> <auth_algo> <mode> <src_ip> <dst_ip>\n\nRouting rule format:\nrt <ip_ver> <src_ip> <dst_ip> <port>\n\nSigned-off-by: Fan Zhang <roy.fan.zhang@intel.com>\n---\n doc/guides/sample_app_ug/ipsec_secgw.rst | 809 ++++++++++++-------------------\n examples/ipsec-secgw/Makefile            |   1 +\n examples/ipsec-secgw/ipsec-secgw.c       |  58 +--\n examples/ipsec-secgw/ipsec.h             |   8 +-\n examples/ipsec-secgw/parser.c            | 599 +++++++++++++++++++++++\n examples/ipsec-secgw/parser.h            | 116 +++++\n examples/ipsec-secgw/rt.c                | 255 +++++-----\n examples/ipsec-secgw/sa.c                | 462 ++++++++++--------\n examples/ipsec-secgw/sp4.c               | 539 +++++++++++---------\n examples/ipsec-secgw/sp6.c               | 540 ++++++++++++++-------\n 10 files changed, 2116 insertions(+), 1271 deletions(-)\n create mode 100644 examples/ipsec-secgw/parser.c\n create mode 100644 examples/ipsec-secgw/parser.h",
    "diff": "diff --git a/doc/guides/sample_app_ug/ipsec_secgw.rst b/doc/guides/sample_app_ug/ipsec_secgw.rst\nindex fcb33c2..2757df5 100644\n--- a/doc/guides/sample_app_ug/ipsec_secgw.rst\n+++ b/doc/guides/sample_app_ug/ipsec_secgw.rst\n@@ -122,7 +122,7 @@ The application has a number of command line options::\n                         -p PORTMASK -P -u PORTMASK\n                         --config (port,queue,lcore)[,(port,queue,lcore]\n                         --single-sa SAIDX\n-\t\t\t--ep0|--ep1\n+                        -f CONFIG_FILE_PATH\n \n Where:\n \n@@ -142,14 +142,11 @@ Where:\n     on both Inbound and Outbound. This option is meant for debugging/performance\n     purposes.\n \n-*   ``--ep0``: configure the app as Endpoint 0.\n+*   ``-f CONFIG_FILE_PATH``: the full path of text-based file containing all\n+    configuration items for running the application (See Configuration file\n+    syntax section below). ``-f CONFIG_FILE_PATH`` **must** be specified.\n+    **ONLY** the UNIX format configuration file is accepted.\n \n-*   ``--ep1``: configure the app as Endpoint 1.\n-\n-Either one of ``--ep0`` or ``--ep1`` **must** be specified.\n-The main purpose of these options is to easily configure two systems\n-back-to-back that would forward traffic through an IPsec tunnel (see\n-:ref:`figure_ipsec_endpoints`).\n \n The mapping of lcores to port/queues is similar to other l3fwd applications.\n \n@@ -157,7 +154,8 @@ For example, given the following command line::\n \n     ./build/ipsec-secgw -l 20,21 -n 4 --socket-mem 0,2048       \\\n            --vdev \"cryptodev_null_pmd\" -- -p 0xf -P -u 0x3      \\\n-           --config=\"(0,0,20),(1,0,20),(2,0,21),(3,0,21)\" --ep0 \\\n+           --config=\"(0,0,20),(1,0,20),(2,0,21),(3,0,21)\"       \\\n+           -f /path/to/config_file                              \\\n \n where each options means:\n \n@@ -194,8 +192,12 @@ where each options means:\n     |          |           |           |                                       |\n     +----------+-----------+-----------+---------------------------------------+\n \n-*   The ``--ep0`` options configures the app with a given set of SP, SA and Routing\n-    entries as explained below in more detail.\n+*   The ``-f /path/to/config_file`` option enables the application read and\n+    parse the configuration file specified, and configures the application\n+    with a given set of SP, SA and Routing entries accordingly. The syntax of\n+    the configuration file will be explained below in more detail. Please\n+    **note** the parser only accepts UNIX format text file. Other formats\n+    such as DOS/MAC format will cause a parse error.\n \n Refer to the *DPDK Getting Started Guide* for general information on running\n applications and the Environment Abstraction Layer (EAL) options.\n@@ -219,496 +221,321 @@ For example, something like the following command line:\n             --vdev \"cryptodev_aesni_mb_pmd\" --vdev \"cryptodev_null_pmd\" \\\n \t    -- \\\n             -p 0xf -P -u 0x3 --config=\"(0,0,20),(1,0,20),(2,0,21),(3,0,21)\" \\\n-            --ep0\n+            -f sample.cfg\n \n \n Configurations\n --------------\n \n-The following sections provide some details on the default values used to\n-initialize the SP, SA and Routing tables.\n-Currently all configuration information is hard coded into the application.\n+The following sections provide the syntax of configurations to initialize\n+your SP, SA and Routing tables.\n+Configurations shall be specified in the configuration file to be passed to\n+the application. The file is then parsed by the application. The successful\n+parsing will result in the appropriate rules being applied to the tables\n+accordingly.\n \n-The following image illustrate a few of the concepts regarding IPSec, such\n-as protected/unprotected and inbound/outbound traffic, from the point of\n-view of two back-to-back endpoints:\n \n-.. _figure_ipsec_endpoints:\n+Configuration File Syntax\n+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n \n-.. figure:: img/ipsec_endpoints.*\n+As mention in the overview, the Security Policies are ACL rules.\n+The application parsers the rules specified in the configuration file and\n+passes them to the ACL table, and replicates them per socket in use.\n \n-   IPSec Inbound/Outbound traffic\n+Following are the configuration file syntax.\n \n-Note that the above image only displays unidirectional traffic per port\n-for illustration purposes.\n-The application supports bidirectional traffic on all ports,\n+General rule syntax\n+^^^^^^^^^^^^^^^^^^^\n \n+The parse treats one line in the configuration file as one configuration\n+item (unless the line concatenation symbol exists). Every configuration\n+item shall follow the syntax of either SP, SA, or Routing rules specified\n+below.\n \n-Security Policy Initialization\n-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n+The configuration parser supports the following special symbols:\n \n-As mention in the overview, the Security Policies are ACL rules.\n-The application defines two ACLs, one each of Inbound and Outbound, and\n-it replicates them per socket in use.\n-\n-Following are the default rules which show only the relevant information,\n-assuming ANY value is valid for the fields not mentioned (src ip, proto,\n-src/dst ports).\n-\n-.. _table_ipsec_endpoint_outbound_sp:\n-\n-.. table:: Endpoint 0 Outbound Security Policies\n-\n-   +-----------------------------------+------------+\n-   | **Dst**                           | **SA idx** |\n-   |                                   |            |\n-   +-----------------------------------+------------+\n-   | 192.168.105.0/24                  | 5          |\n-   |                                   |            |\n-   +-----------------------------------+------------+\n-   | 192.168.106.0/24                  | 6          |\n-   |                                   |            |\n-   +-----------------------------------+------------+\n-   | 192.168.175.0/24                  | 10         |\n-   |                                   |            |\n-   +-----------------------------------+------------+\n-   | 192.168.176.0/24                  | 11         |\n-   |                                   |            |\n-   +-----------------------------------+------------+\n-   | 192.168.200.0/24                  | 15         |\n-   |                                   |            |\n-   +-----------------------------------+------------+\n-   | 192.168.201.0/24                  | 16         |\n-   |                                   |            |\n-   +-----------------------------------+------------+\n-   | 192.168.55.0/24                   | 25         |\n-   |                                   |            |\n-   +-----------------------------------+------------+\n-   | 192.168.56.0/24                   | 26         |\n-   |                                   |            |\n-   +-----------------------------------+------------+\n-   | 192.168.240.0/24                  | BYPASS     |\n-   |                                   |            |\n-   +-----------------------------------+------------+\n-   | 192.168.241.0/24                  | BYPASS     |\n-   |                                   |            |\n-   +-----------------------------------+------------+\n-   | 0:0:0:0:5555:5555:0:0/96          | 5          |\n-   |                                   |            |\n-   +-----------------------------------+------------+\n-   | 0:0:0:0:6666:6666:0:0/96          | 6          |\n-   |                                   |            |\n-   +-----------------------------------+------------+\n-   | 0:0:1111:1111:0:0:0:0/96          | 10         |\n-   |                                   |            |\n-   +-----------------------------------+------------+\n-   | 0:0:1111:1111:1111:1111:0:0/96    | 11         |\n-   |                                   |            |\n-   +-----------------------------------+------------+\n-   | 0:0:0:0:aaaa:aaaa:0:0/96          | 25         |\n-   |                                   |            |\n-   +-----------------------------------+------------+\n-   | 0:0:0:0:bbbb:bbbb:0:0/96          | 26         |\n-   |                                   |            |\n-   +-----------------------------------+------------+\n-\n-.. _table_ipsec_endpoint_inbound_sp:\n-\n-.. table:: Endpoint 0 Inbound Security Policies\n-\n-   +-----------------------------------+------------+\n-   | **Dst**                           | **SA idx** |\n-   |                                   |            |\n-   +-----------------------------------+------------+\n-   | 192.168.115.0/24                  | 105        |\n-   |                                   |            |\n-   +-----------------------------------+------------+\n-   | 192.168.116.0/24                  | 106        |\n-   |                                   |            |\n-   +-----------------------------------+------------+\n-   | 192.168.185.0/24                  | 110        |\n-   |                                   |            |\n-   +-----------------------------------+------------+\n-   | 192.168.186.0/24                  | 111        |\n-   |                                   |            |\n-   +-----------------------------------+------------+\n-   | 192.168.210.0/24                  | 115        |\n-   |                                   |            |\n-   +-----------------------------------+------------+\n-   | 192.168.211.0/24                  | 116        |\n-   |                                   |            |\n-   +-----------------------------------+------------+\n-   | 192.168.65.0/24                   | 125        |\n-   |                                   |            |\n-   +-----------------------------------+------------+\n-   | 192.168.66.0/24                   | 126        |\n-   |                                   |            |\n-   +-----------------------------------+------------+\n-   | 192.168.245.0/24                  | BYPASS     |\n-   |                                   |            |\n-   +-----------------------------------+------------+\n-   | 192.168.246.0/24                  | BYPASS     |\n-   |                                   |            |\n-   +-----------------------------------+------------+\n-   | ffff:0:0:0:5555:5555:0:0/96       | 105        |\n-   |                                   |            |\n-   +-----------------------------------+------------+\n-   | ffff:0:0:0:6666:6666:0:0/96       | 106        |\n-   |                                   |            |\n-   +-----------------------------------+------------+\n-   | ffff:0:1111:1111:0:0:0:0/96       | 110        |\n-   |                                   |            |\n-   +-----------------------------------+------------+\n-   | ffff:0:1111:1111:1111:1111:0:0/96 | 111        |\n-   |                                   |            |\n-   +-----------------------------------+------------+\n-   | ffff:0:0:0:aaaa:aaaa:0:0/96       | 125        |\n-   |                                   |            |\n-   +-----------------------------------+------------+\n-   | ffff:0:0:0:bbbb:bbbb:0:0/96       | 126        |\n-   |                                   |            |\n-   +-----------------------------------+------------+\n-\n-For Endpoint 1, we use the same policies in reverse, meaning the Inbound SP\n-entries are set as Outbound and vice versa.\n-\n-\n-Security Association Initialization\n-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n-\n-The SAs are kept in a array table.\n-\n-For Inbound, the SPI is used as index modulo the table size.\n-This means that on a table for 100 SA, SPI 5 and 105 would use the same index\n-and that is not currently supported.\n-\n-Notice that it is not an issue for Outbound traffic as we store the index and\n-not the SPI in the Security Policy.\n-\n-All SAs configured with AES-CBC and HMAC-SHA1 share the same values for cipher\n-block size and key, and authentication digest size and key.\n-\n-The following are the default values:\n-\n-.. _table_ipsec_endpoint_outbound_sa:\n-\n-.. table:: Endpoint 0 Outbound Security Associations\n-\n-   +---------+----------+------------+-----------+----------------+----------------+\n-   | **SPI** | **Mode** | **Cipher** | **Auth**  | **Tunnel src** | **Tunnel dst** |\n-   |         |          |            |           |                |                |\n-   +---------+----------+------------+-----------+----------------+----------------+\n-   | 5       | Tunnel   | AES-CBC    | HMAC-SHA1 | 172.16.1.5     | 172.16.2.5     |\n-   |         |          |            |           |                |                |\n-   +---------+----------+------------+-----------+----------------+----------------+\n-   | 6       | Tunnel   | AES-CBC    | HMAC-SHA1 | 172.16.1.6     | 172.16.2.6     |\n-   |         |          |            |           |                |                |\n-   +---------+----------+------------+-----------+----------------+----------------+\n-   | 10      | Trans    | AES-CBC    | HMAC-SHA1 | N/A            | N/A            |\n-   |         |          |            |           |                |                |\n-   +---------+----------+------------+-----------+----------------+----------------+\n-   | 11      | Trans    | AES-CBC    | HMAC-SHA1 | N/A            | N/A            |\n-   |         |          |            |           |                |                |\n-   +---------+----------+------------+-----------+----------------+----------------+\n-   | 15      | Tunnel   | NULL       | NULL      | 172.16.1.5     | 172.16.2.5     |\n-   |         |          |            |           |                |                |\n-   +---------+----------+------------+-----------+----------------+----------------+\n-   | 16      | Tunnel   | NULL       | NULL      | 172.16.1.6     | 172.16.2.6     |\n-   |         |          |            |           |                |                |\n-   +---------+----------+------------+-----------+----------------+----------------+\n-   | 25      | Tunnel   | AES-CBC    | HMAC-SHA1 | 1111:1111:     | 2222:2222:     |\n-   |         |          |            |           | 1111:1111:     | 2222:2222:     |\n-   |         |          |            |           | 1111:1111:     | 2222:2222:     |\n-   |         |          |            |           | 1111:5555      | 2222:5555      |\n-   |         |          |            |           |                |                |\n-   +---------+----------+------------+-----------+----------------+----------------+\n-   | 26      | Tunnel   | AES-CBC    | HMAC-SHA1 | 1111:1111:     | 2222:2222:     |\n-   |         |          |            |           | 1111:1111:     | 2222:2222:     |\n-   |         |          |            |           | 1111:1111:     | 2222:2222:     |\n-   |         |          |            |           | 1111:6666      | 2222:6666      |\n-   |         |          |            |           |                |                |\n-   +---------+----------+------------+-----------+----------------+----------------+\n-\n-.. _table_ipsec_endpoint_inbound_sa:\n-\n-.. table:: Endpoint 0 Inbound Security Associations\n-\n-   +---------+----------+------------+-----------+----------------+----------------+\n-   | **SPI** | **Mode** | **Cipher** | **Auth**  | **Tunnel src** | **Tunnel dst** |\n-   |         |          |            |           |                |                |\n-   +---------+----------+------------+-----------+----------------+----------------+\n-   | 105     | Tunnel   | AES-CBC    | HMAC-SHA1 | 172.16.2.5     | 172.16.1.5     |\n-   |         |          |            |           |                |                |\n-   +---------+----------+------------+-----------+----------------+----------------+\n-   | 106     | Tunnel   | AES-CBC    | HMAC-SHA1 | 172.16.2.6     | 172.16.1.6     |\n-   |         |          |            |           |                |                |\n-   +---------+----------+------------+-----------+----------------+----------------+\n-   | 110     | Trans    | AES-CBC    | HMAC-SHA1 | N/A            | N/A            |\n-   |         |          |            |           |                |                |\n-   +---------+----------+------------+-----------+----------------+----------------+\n-   | 111     | Trans    | AES-CBC    | HMAC-SHA1 | N/A            | N/A            |\n-   |         |          |            |           |                |                |\n-   +---------+----------+------------+-----------+----------------+----------------+\n-   | 115     | Tunnel   | NULL       | NULL      | 172.16.2.5     | 172.16.1.5     |\n-   |         |          |            |           |                |                |\n-   +---------+----------+------------+-----------+----------------+----------------+\n-   | 116     | Tunnel   | NULL       | NULL      | 172.16.2.6     | 172.16.1.6     |\n-   |         |          |            |           |                |                |\n-   +---------+----------+------------+-----------+----------------+----------------+\n-   | 125     | Tunnel   | AES-CBC    | HMAC-SHA1 | 2222:2222:     | 1111:1111:     |\n-   |         |          |            |           | 2222:2222:     | 1111:1111:     |\n-   |         |          |            |           | 2222:2222:     | 1111:1111:     |\n-   |         |          |            |           | 2222:5555      | 1111:5555      |\n-   |         |          |            |           |                |                |\n-   +---------+----------+------------+-----------+----------------+----------------+\n-   | 126     | Tunnel   | AES-CBC    | HMAC-SHA1 | 2222:2222:     | 1111:1111:     |\n-   |         |          |            |           | 2222:2222:     | 1111:1111:     |\n-   |         |          |            |           | 2222:2222:     | 1111:1111:     |\n-   |         |          |            |           | 2222:6666      | 1111:6666      |\n-   |         |          |            |           |                |                |\n-   +---------+----------+------------+-----------+----------------+----------------+\n-\n-For Endpoint 1, we use the same policies in reverse, meaning the Inbound SP\n-entries are set as Outbound and vice versa.\n-\n-\n-Routing Initialization\n-~~~~~~~~~~~~~~~~~~~~~~\n-\n-The Routing is implemented using an LPM table.\n-\n-Following default values:\n-\n-.. _table_ipsec_endpoint_outbound_routing:\n-\n-.. table:: Endpoint 0 Routing Table\n-\n-   +------------------+----------+\n-   | **Dst addr**     | **Port** |\n-   |                  |          |\n-   +------------------+----------+\n-   | 172.16.2.5/32    | 0        |\n-   |                  |          |\n-   +------------------+----------+\n-   | 172.16.2.6/32    | 1        |\n-   |                  |          |\n-   +------------------+----------+\n-   | 192.168.175.0/24 | 0        |\n-   |                  |          |\n-   +------------------+----------+\n-   | 192.168.176.0/24 | 1        |\n-   |                  |          |\n-   +------------------+----------+\n-   | 192.168.240.0/24 | 0        |\n-   |                  |          |\n-   +------------------+----------+\n-   | 192.168.241.0/24 | 1        |\n-   |                  |          |\n-   +------------------+----------+\n-   | 192.168.115.0/24 | 2        |\n-   |                  |          |\n-   +------------------+----------+\n-   | 192.168.116.0/24 | 3        |\n-   |                  |          |\n-   +------------------+----------+\n-   | 192.168.65.0/24  | 2        |\n-   |                  |          |\n-   +------------------+----------+\n-   | 192.168.66.0/24  | 3        |\n-   |                  |          |\n-   +------------------+----------+\n-   | 192.168.185.0/24 | 2        |\n-   |                  |          |\n-   +------------------+----------+\n-   | 192.168.186.0/24 | 3        |\n-   |                  |          |\n-   +------------------+----------+\n-   | 192.168.210.0/24 | 2        |\n-   |                  |          |\n-   +------------------+----------+\n-   | 192.168.211.0/24 | 3        |\n-   |                  |          |\n-   +------------------+----------+\n-   | 192.168.245.0/24 | 2        |\n-   |                  |          |\n-   +------------------+----------+\n-   | 192.168.246.0/24 | 3        |\n-   |                  |          |\n-   +------------------+----------+\n-   | 2222:2222:       | 0        |\n-   | 2222:2222:       |          |\n-   | 2222:2222:       |          |\n-   | 2222:5555/116    |          |\n-   |                  |          |\n-   +------------------+----------+\n-   | 2222:2222:       | 1        |\n-   | 2222:2222:       |          |\n-   | 2222:2222:       |          |\n-   | 2222:6666/116    |          |\n-   |                  |          |\n-   +------------------+----------+\n-   | 0000:0000:       | 0        |\n-   | 1111:1111:       |          |\n-   | 0000:0000:       |          |\n-   | 0000:0000/116    |          |\n-   |                  |          |\n-   +------------------+----------+\n-   | 0000:0000:       | 1        |\n-   | 1111:1111:       |          |\n-   | 1111:1111:       |          |\n-   | 0000:0000/116    |          |\n-   |                  |          |\n-   +------------------+----------+\n-   | ffff:0000:       | 2        |\n-   | 0000:0000:       |          |\n-   | aaaa:aaaa:       |          |\n-   | 0000:0/116       |          |\n-   |                  |          |\n-   +------------------+----------+\n-   | ffff:0000:       | 3        |\n-   | 0000:0000:       |          |\n-   | bbbb:bbbb:       |          |\n-   | 0000:0/116       |          |\n-   |                  |          |\n-   +------------------+----------+\n-   | ffff:0000:       | 2        |\n-   | 0000:0000:       |          |\n-   | 5555:5555:       |          |\n-   | 0000:0/116       |          |\n-   |                  |          |\n-   +------------------+----------+\n-   | ffff:0000:       | 3        |\n-   | 0000:0000:       |          |\n-   | 6666:6666:       |          |\n-   | 0000:0/116       |          |\n-   |                  |          |\n-   +------------------+----------+\n-   | ffff:0000:       | 2        |\n-   | 1111:1111:       |          |\n-   | 0000:0000:       |          |\n-   | 0000:0000/116    |          |\n-   |                  |          |\n-   +------------------+----------+\n-   | ffff:0000:       | 3        |\n-   | 1111:1111:       |          |\n-   | 1111:1111:       |          |\n-   | 0000:0000/116    |          |\n-   |                  |          |\n-   +------------------+----------+\n-\n-.. _table_ipsec_endpoint_inbound_routing:\n-\n-.. table:: Endpoint 1 Routing Table\n-\n-   +------------------+----------+\n-   | **Dst addr**     | **Port** |\n-   |                  |          |\n-   +------------------+----------+\n-   | 172.16.1.5/32    | 0        |\n-   |                  |          |\n-   +------------------+----------+\n-   | 172.16.1.6/32    | 1        |\n-   |                  |          |\n-   +------------------+----------+\n-   | 192.168.185.0/24 | 0        |\n-   |                  |          |\n-   +------------------+----------+\n-   | 192.168.186.0/24 | 1        |\n-   |                  |          |\n-   +------------------+----------+\n-   | 192.168.245.0/24 | 0        |\n-   |                  |          |\n-   +------------------+----------+\n-   | 192.168.246.0/24 | 1        |\n-   |                  |          |\n-   +------------------+----------+\n-   | 192.168.105.0/24 | 2        |\n-   |                  |          |\n-   +------------------+----------+\n-   | 192.168.106.0/24 | 3        |\n-   |                  |          |\n-   +------------------+----------+\n-   | 192.168.55.0/24  | 2        |\n-   |                  |          |\n-   +------------------+----------+\n-   | 192.168.56.0/24  | 3        |\n-   |                  |          |\n-   +------------------+----------+\n-   | 192.168.175.0/24 | 2        |\n-   |                  |          |\n-   +------------------+----------+\n-   | 192.168.176.0/24 | 3        |\n-   |                  |          |\n-   +------------------+----------+\n-   | 192.168.200.0/24 | 2        |\n-   |                  |          |\n-   +------------------+----------+\n-   | 192.168.201.0/24 | 3        |\n-   |                  |          |\n-   +------------------+----------+\n-   | 192.168.240.0/24 | 2        |\n-   |                  |          |\n-   +------------------+----------+\n-   | 192.168.241.0/24 | 3        |\n-   |                  |          |\n-   +------------------+----------+\n-   | 1111:1111:       | 0        |\n-   | 1111:1111:       |          |\n-   | 1111:1111:       |          |\n-   | 1111:5555/116    |          |\n-   |                  |          |\n-   +------------------+----------+\n-   | 1111:1111:       | 1        |\n-   | 1111:1111:       |          |\n-   | 1111:1111:       |          |\n-   | 1111:6666/116    |          |\n-   |                  |          |\n-   +------------------+----------+\n-   | ffff:0000:       | 0        |\n-   | 1111:1111:       |          |\n-   | 0000:0000:       |          |\n-   | 0000:0000/116    |          |\n-   |                  |          |\n-   +------------------+----------+\n-   | ffff:0000:       | 1        |\n-   | 1111:1111:       |          |\n-   | 1111:1111:       |          |\n-   | 0000:0000/116    |          |\n-   |                  |          |\n-   +------------------+----------+\n-   | 0000:0000:       | 2        |\n-   | 0000:0000:       |          |\n-   | aaaa:aaaa:       |          |\n-   | 0000:0/116       |          |\n-   |                  |          |\n-   +------------------+----------+\n-   | 0000:0000:       | 3        |\n-   | 0000:0000:       |          |\n-   | bbbb:bbbb:       |          |\n-   | 0000:0/116       |          |\n-   |                  |          |\n-   +------------------+----------+\n-   | 0000:0000:       | 2        |\n-   | 0000:0000:       |          |\n-   | 5555:5555:       |          |\n-   | 0000:0/116       |          |\n-   |                  |          |\n-   +------------------+----------+\n-   | 0000:0000:       | 3        |\n-   | 0000:0000:       |          |\n-   | 6666:6666:       |          |\n-   | 0000:0/116       |          |\n-   |                  |          |\n-   +------------------+----------+\n-   | 0000:0000:       | 2        |\n-   | 1111:1111:       |          |\n-   | 0000:0000:       |          |\n-   | 0000:0000/116    |          |\n-   |                  |          |\n-   +------------------+----------+\n-   | 0000:0000:       | 3        |\n-   | 1111:1111:       |          |\n-   | 1111:1111:       |          |\n-   | 0000:0000/116    |          |\n-   |                  |          |\n-   +------------------+----------+\n+ * Comment symbol **#**. Any character from this symbol to the end of\n+   line is treated as comment and will not be parsed.\n+\n+ * Line concatenation symbol **\\\\**. This symbol shall be placed in the end\n+   of the line to be concatenated to the line below. Multiple lines'\n+   concatenation is supported.\n+\n+\n+SP rule syntax\n+^^^^^^^^^^^^^^\n+\n+The SP rule syntax is shown as follows:\n+\n+.. code-block:: console\n+\n+    sp <ip_ver> <dir> esp <action> <priority> <src_ip> <dst_ip>\n+    <proto> <sport> <dport>\n+\n+\n+where each options means:\n+\n+``<ip_ver>``\n+\n+ * IP protocol version\n+\n+ * Optional: No\n+\n+ * Available options:\n+\n+   * *ipv4*: IP protocol version 4\n+   * *ipv6*: IP protocol version 6\n+\n+``<dir>``\n+\n+ * The traffic direction\n+\n+ * Optional: No\n+\n+ * Available options:\n+\n+   * *in*: inbound traffic\n+   * *out*: outbound traffic\n+\n+``<action>``\n+\n+ * IPsec action\n+\n+ * Optional: No\n+\n+ * Available options:\n+\n+   * *protect <SA_idx>*: the specified traffic is protected by SA rule\n+     with id SA_idx\n+   * *bypass*: the specified traffic traffic is bypassed\n+   * *discard*: the specified traffic is discarded\n+\n+``<priority>``\n+\n+ * Rule priority\n+\n+ * Optional: Yes, default priority 0 will be used\n+\n+ * Syntax: *pri <id>*\n+\n+``<src_ip>``\n+\n+ * The source IP address and mask\n+\n+ * Optional: Yes, default address 0.0.0.0 and mask of 0 will be used\n+\n+ * Syntax:\n+\n+   * *src X.X.X.X/Y* for IPv4\n+   * *src XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX/Y* for IPv6\n+\n+``<dst_ip>``\n+\n+ * The destination IP address and mask\n+\n+ * Optional: Yes, default address 0.0.0.0 and mask of 0 will be used\n+\n+ * Syntax:\n+\n+   * *dst X.X.X.X/Y* for IPv4\n+   * *dst XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX/Y* for IPv6\n+\n+``<proto>``\n+\n+ * The protocol start and end range\n+\n+ * Optional: yes, default range of 0 to 0 will be used\n+\n+ * Syntax: *proto X:Y*\n+\n+``<sport>``\n+\n+ * The source port start and end range\n+\n+ * Optional: yes, default range of 0 to 0 will be used\n+\n+ * Syntax: *sport X:Y*\n+\n+``<dport>``\n+\n+ * The destination port start and end range\n+\n+ * Optional: yes, default range of 0 to 0 will be used\n+\n+ * Format: *dport X:Y*\n+\n+Example SP rules:\n+\n+.. code-block:: console\n+\n+    sp ipv4 out esp protect 105 pri 1 dst 192.168.115.0/24 sport 0:65535 \\\n+    dport 0:65535\n+\n+    sp ipv6 in esp bypass pri 1 dst 0000:0000:0000:0000:5555:5555:\\\n+    0000:0000/96 sport 0:65535 dport 0:65535\n+\n+\n+SA rule syntax\n+^^^^^^^^^^^^^^\n+\n+The successfully parsed SA rules will be stored in an array table.\n+\n+All SAs configured with AES-CBC and HMAC-SHA1 share the same values for\n+cipher block size and key, and authentication digest size and key.\n+\n+The SA rule syntax is shown as follows:\n+\n+.. code-block:: console\n+\n+    sa <dir> <spi> <cipher_algo> <auth_algo> <mode> <src_ip> <dst_ip>\n+\n+where each options means:\n+\n+``<dir>``\n+\n+ * The traffic direction\n+\n+ * Optional: No\n+\n+ * Available options:\n+\n+   * *in*: inbound traffic\n+   * *out*: outbound traffic\n+\n+``<spi>``\n+\n+ * The SPI number\n+\n+ * Optional: No\n+\n+ * Syntax: unsigned integer number\n+\n+``<cipher_algo>``\n+\n+ * Cipher algorithm\n+\n+ * Optional: No\n+\n+ * Available options:\n+\n+   * *null*: NULL algorithm\n+   * *aes-128-cbc*: AES-CBC 128-bit algorithm\n+\n+``<auth_algo>``\n+\n+ * Authentication algorithm\n+\n+ * Optional: No\n+\n+ * Available options:\n+\n+    * *null*: NULL algorithm\n+    * *sha1-hmac*: HMAC SHA1 algorithm\n+\n+``<mode>``\n+\n+ * The operation mode\n+\n+ * Optional: No\n+\n+ * Available options:\n+\n+   * *ipv4-tunnel*: Tunnel mode for IPv4 packets\n+   * *ipv6-tunnel*: Tunnel mode for IPv6 packets\n+   * *transport*: transport mode\n+\n+``<src_ip>``\n+\n+ * The source IP address. This option is not available when\n+   transport mode is used\n+\n+ * Optional: Yes, default address 0.0.0.0 will be used\n+\n+ * Syntax:\n+\n+   * *src X.X.X.X* for IPv4\n+   * *src XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX* for IPv6\n+\n+``<dst_ip>``\n+\n+ * The destination IP address. This option is not available when\n+   transport mode is used\n+\n+ * Optional: Yes, default address 0.0.0.0 will be used\n+\n+ * Syntax:\n+\n+   * *dst X.X.X.X* for IPv4\n+   * *dst XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX* for IPv6\n+\n+Example SA rules:\n+\n+.. code-block:: console\n+\n+    sa in 5 aes-128-cbc sha1-hmac ipv4-tunnel src 172.16.1.5 dst 172.16.2.5\n+\n+    sa out 125 aes-128-cbc sha1-hmac ipv6-tunnel \\\n+    src 2222:2222:2222:2222:2222:2222:2222:5555 \\\n+    dst 1111:1111:1111:1111:1111:1111:1111:5555\n+\n+\n+Routing rule syntax\n+^^^^^^^^^^^^^^^^^^^\n+\n+The Routing rule syntax is shown as follows:\n+\n+.. code-block:: console\n+\n+    rt <ip_ver> <src_ip> <dst_ip> <port>\n+\n+\n+where each options means:\n+\n+``<ip_ver>``\n+\n+ * IP protocol version\n+\n+ * Optional: No\n+\n+ * Available options:\n+\n+   * *ipv4*: IP protocol version 4\n+   * *ipv6*: IP protocol version 6\n+\n+``<src_ip>``\n+\n+ * The source IP address and mask\n+\n+ * Optional: Yes, default address 0.0.0.0 and mask of 0 will be used\n+\n+ * Syntax:\n+\n+   * *src X.X.X.X/Y* for IPv4\n+   * *src XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX/Y* for IPv6\n+\n+``<dst_ip>``\n+\n+ * The destination IP address and mask\n+\n+ * Optional: Yes, default address 0.0.0.0 and mask of 0 will be used\n+\n+ * Syntax:\n+\n+   * *dst X.X.X.X/Y* for IPv4\n+   * *dst XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX/Y* for IPv6\n+\n+``<port>``\n+\n+ * The traffic output port id\n+\n+ * Optional: yes, default output port 0 will be used\n+\n+ * Syntax: *port X*\n+\n+Example SP rules:\n+\n+.. code-block:: console\n+\n+    rt ipv4 dst 172.16.1.5/32 port 0\n+\n+    rt ipv6 dst 1111:1111:1111:1111:1111:1111:1111:5555/116 port 0\ndiff --git a/examples/ipsec-secgw/Makefile b/examples/ipsec-secgw/Makefile\nindex 06b6db1..17e9155 100644\n--- a/examples/ipsec-secgw/Makefile\n+++ b/examples/ipsec-secgw/Makefile\n@@ -53,6 +53,7 @@ endif\n #\n # all source are stored in SRCS-y\n #\n+SRCS-y += parser.c\n SRCS-y += ipsec.c\n SRCS-y += esp.c\n SRCS-y += sp4.c\ndiff --git a/examples/ipsec-secgw/ipsec-secgw.c b/examples/ipsec-secgw/ipsec-secgw.c\nindex f78743d..5ef1f44 100644\n--- a/examples/ipsec-secgw/ipsec-secgw.c\n+++ b/examples/ipsec-secgw/ipsec-secgw.c\n@@ -72,6 +72,7 @@\n #include <rte_cryptodev.h>\n \n #include \"ipsec.h\"\n+#include \"parser.h\"\n \n #define RTE_LOGTYPE_IPSEC RTE_LOGTYPE_USER1\n \n@@ -88,8 +89,6 @@\n \n #define OPTION_CONFIG\t\t\"config\"\n #define OPTION_SINGLE_SA\t\"single-sa\"\n-#define OPTION_EP0\t\t\"ep0\"\n-#define OPTION_EP1\t\t\"ep1\"\n \n #define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */\n \n@@ -158,7 +157,6 @@ static uint32_t enabled_port_mask;\n static uint32_t unprotected_port_mask;\n static int32_t promiscuous_on = 1;\n static int32_t numa_on = 1; /**< NUMA is enabled by default. */\n-static int32_t ep = -1; /**< Endpoint configuration (0 or 1) */\n static uint32_t nb_lcores;\n static uint32_t single_sa;\n static uint32_t single_sa_idx;\n@@ -832,7 +830,7 @@ print_usage(const char *prgname)\n {\n \tprintf(\"%s [EAL options] -- -p PORTMASK -P -u PORTMASK\"\n \t\t\"  --\"OPTION_CONFIG\" (port,queue,lcore)[,(port,queue,lcore]\"\n-\t\t\" --single-sa SAIDX --ep0|--ep1\\n\"\n+\t\t\" --single-sa SAIDX -f CONFIG_FILE\\n\"\n \t\t\"  -p PORTMASK: hexadecimal bitmask of ports to configure\\n\"\n \t\t\"  -P : enable promiscuous mode\\n\"\n \t\t\"  -u PORTMASK: hexadecimal bitmask of unprotected ports\\n\"\n@@ -840,8 +838,8 @@ print_usage(const char *prgname)\n \t\t\"rx queues configuration\\n\"\n \t\t\"  --single-sa SAIDX: use single SA index for outbound, \"\n \t\t\"bypassing the SP\\n\"\n-\t\t\"  --ep0: Configure as Endpoint 0\\n\"\n-\t\t\"  --ep1: Configure as Endpoint 1\\n\", prgname);\n+\t\t\"  -f CONFIG_FILE: Configuration file path\\n\",\n+\t\tprgname);\n }\n \n static int32_t\n@@ -954,18 +952,6 @@ parse_args_long_options(struct option *lgopts, int32_t option_index)\n \t\t}\n \t}\n \n-\tif (__STRNCMP(optname, OPTION_EP0)) {\n-\t\tprintf(\"endpoint 0\\n\");\n-\t\tep = 0;\n-\t\tret = 0;\n-\t}\n-\n-\tif (__STRNCMP(optname, OPTION_EP1)) {\n-\t\tprintf(\"endpoint 1\\n\");\n-\t\tep = 1;\n-\t\tret = 0;\n-\t}\n-\n \treturn ret;\n }\n #undef __STRNCMP\n@@ -980,14 +966,13 @@ parse_args(int32_t argc, char **argv)\n \tstatic struct option lgopts[] = {\n \t\t{OPTION_CONFIG, 1, 0, 0},\n \t\t{OPTION_SINGLE_SA, 1, 0, 0},\n-\t\t{OPTION_EP0, 0, 0, 0},\n-\t\t{OPTION_EP1, 0, 0, 0},\n \t\t{NULL, 0, 0, 0}\n \t};\n+\tint32_t f_present = 0;\n \n \targvopt = argv;\n \n-\twhile ((opt = getopt_long(argc, argvopt, \"p:Pu:\",\n+\twhile ((opt = getopt_long(argc, argvopt, \"p:Pu:f:\",\n \t\t\t\tlgopts, &option_index)) != EOF) {\n \n \t\tswitch (opt) {\n@@ -1011,6 +996,21 @@ parse_args(int32_t argc, char **argv)\n \t\t\t\treturn -1;\n \t\t\t}\n \t\t\tbreak;\n+\t\tcase 'f':\n+\t\t\tif (f_present == 1) {\n+\t\t\t\tprintf(\"\\\"-f\\\" option present more than \"\n+\t\t\t\t\t\"once!\\n\");\n+\t\t\t\tprint_usage(prgname);\n+\t\t\t\treturn -1;\n+\t\t\t}\n+\t\t\tif (parse_cfg_file(optarg) < 0) {\n+\t\t\t\tprintf(\"parsing file \\\"%s\\\" failed\\n\",\n+\t\t\t\t\toptarg);\n+\t\t\t\tprint_usage(prgname);\n+\t\t\t\treturn -1;\n+\t\t\t}\n+\t\t\tf_present = 1;\n+\t\t\tbreak;\n \t\tcase 0:\n \t\t\tif (parse_args_long_options(lgopts, option_index)) {\n \t\t\t\tprint_usage(prgname);\n@@ -1023,6 +1023,11 @@ parse_args(int32_t argc, char **argv)\n \t\t}\n \t}\n \n+\tif (f_present == 0) {\n+\t\tprintf(\"Mandatory option \\\"-f\\\" not present\\n\");\n+\t\treturn -1;\n+\t}\n+\n \tif (optind >= 0)\n \t\targv[optind-1] = prgname;\n \n@@ -1401,9 +1406,6 @@ main(int32_t argc, char **argv)\n \tif (ret < 0)\n \t\trte_exit(EXIT_FAILURE, \"Invalid parameters\\n\");\n \n-\tif (ep < 0)\n-\t\trte_exit(EXIT_FAILURE, \"need to choose either EP0 or EP1\\n\");\n-\n \tif ((unprotected_port_mask & enabled_port_mask) !=\n \t\t\tunprotected_port_mask)\n \t\trte_exit(EXIT_FAILURE, \"Invalid unprotected portmask 0x%x\\n\",\n@@ -1433,13 +1435,13 @@ main(int32_t argc, char **argv)\n \t\tif (socket_ctx[socket_id].mbuf_pool)\n \t\t\tcontinue;\n \n-\t\tsa_init(&socket_ctx[socket_id], socket_id, ep);\n+\t\tsa_init(&socket_ctx[socket_id], socket_id);\n \n-\t\tsp4_init(&socket_ctx[socket_id], socket_id, ep);\n+\t\tsp4_init(&socket_ctx[socket_id], socket_id);\n \n-\t\tsp6_init(&socket_ctx[socket_id], socket_id, ep);\n+\t\tsp6_init(&socket_ctx[socket_id], socket_id);\n \n-\t\trt_init(&socket_ctx[socket_id], socket_id, ep);\n+\t\trt_init(&socket_ctx[socket_id], socket_id);\n \n \t\tpool_init(&socket_ctx[socket_id], socket_id, NB_MBUF);\n \t}\ndiff --git a/examples/ipsec-secgw/ipsec.h b/examples/ipsec-secgw/ipsec.h\nindex 0d2ee25..ce6071d 100644\n--- a/examples/ipsec-secgw/ipsec.h\n+++ b/examples/ipsec-secgw/ipsec.h\n@@ -183,15 +183,15 @@ outbound_sa_lookup(struct sa_ctx *sa_ctx, uint32_t sa_idx[],\n \t\tstruct ipsec_sa *sa[], uint16_t nb_pkts);\n \n void\n-sp4_init(struct socket_ctx *ctx, int32_t socket_id, uint32_t ep);\n+sp4_init(struct socket_ctx *ctx, int32_t socket_id);\n \n void\n-sp6_init(struct socket_ctx *ctx, int32_t socket_id, uint32_t ep);\n+sp6_init(struct socket_ctx *ctx, int32_t socket_id);\n \n void\n-sa_init(struct socket_ctx *ctx, int32_t socket_id, uint32_t ep);\n+sa_init(struct socket_ctx *ctx, int32_t socket_id);\n \n void\n-rt_init(struct socket_ctx *ctx, int32_t socket_id, uint32_t ep);\n+rt_init(struct socket_ctx *ctx, int32_t socket_id);\n \n #endif /* __IPSEC_H__ */\ndiff --git a/examples/ipsec-secgw/parser.c b/examples/ipsec-secgw/parser.c\nnew file mode 100644\nindex 0000000..99bdfc5\n--- /dev/null\n+++ b/examples/ipsec-secgw/parser.c\n@@ -0,0 +1,599 @@\n+/*-\n+ *   BSD LICENSE\n+ *\n+ *   Copyright(c) 2016 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+#include <rte_common.h>\n+#include <rte_crypto.h>\n+\n+#include <cmdline_parse_string.h>\n+#include <cmdline_parse_num.h>\n+#include <cmdline_parse_ipaddr.h>\n+#include <cmdline_socket.h>\n+#include <cmdline.h>\n+\n+#include \"ipsec.h\"\n+#include \"parser.h\"\n+\n+#define PARSE_DELIMITER\t\t\" \\f\\n\\r\\t\\v\"\n+static int\n+parse_tokenize_string(char *string, char *tokens[], uint32_t *n_tokens)\n+{\n+\tuint32_t i;\n+\n+\tif ((string == NULL) ||\n+\t\t(tokens == NULL) ||\n+\t\t(*n_tokens < 1))\n+\t\treturn -EINVAL;\n+\n+\tfor (i = 0; i < *n_tokens; i++) {\n+\t\ttokens[i] = strtok_r(string, PARSE_DELIMITER, &string);\n+\t\tif (tokens[i] == NULL)\n+\t\t\tbreak;\n+\t}\n+\n+\tif ((i == *n_tokens) &&\n+\t\t(NULL != strtok_r(string, PARSE_DELIMITER, &string)))\n+\t\treturn -E2BIG;\n+\n+\t*n_tokens = i;\n+\treturn 0;\n+}\n+\n+#define INADDRSZ 4\n+#define IN6ADDRSZ 16\n+\n+/* int\n+ * inet_pton4(src, dst)\n+ *      like inet_aton() but without all the hexadecimal and shorthand.\n+ * return:\n+ *      1 if `src' is a valid dotted quad, else 0.\n+ * notice:\n+ *      does not touch `dst' unless it's returning 1.\n+ * author:\n+ *      Paul Vixie, 1996.\n+ */\n+static int\n+inet_pton4(const char *src, unsigned char *dst)\n+{\n+\tstatic const char digits[] = \"0123456789\";\n+\tint saw_digit, octets, ch;\n+\tunsigned char tmp[INADDRSZ], *tp;\n+\n+\tsaw_digit = 0;\n+\toctets = 0;\n+\t*(tp = tmp) = 0;\n+\twhile ((ch = *src++) != '\\0') {\n+\t\tconst char *pch;\n+\n+\t\tpch = strchr(digits, ch);\n+\t\tif (pch != NULL) {\n+\t\t\tunsigned int new = *tp * 10 + (pch - digits);\n+\n+\t\t\tif (new > 255)\n+\t\t\t\treturn 0;\n+\t\t\tif (!saw_digit) {\n+\t\t\t\tif (++octets > 4)\n+\t\t\t\t\treturn 0;\n+\t\t\t\tsaw_digit = 1;\n+\t\t\t}\n+\t\t\t*tp = (unsigned char)new;\n+\t\t} else if (ch == '.' && saw_digit) {\n+\t\t\tif (octets == 4)\n+\t\t\t\treturn 0;\n+\t\t\t*++tp = 0;\n+\t\t\tsaw_digit = 0;\n+\t\t} else\n+\t\t\treturn 0;\n+\t}\n+\tif (octets < 4)\n+\t\treturn 0;\n+\n+\tmemcpy(dst, tmp, INADDRSZ);\n+\treturn 1;\n+}\n+\n+/* int\n+ * inet_pton6(src, dst)\n+ *      convert presentation level address to network order binary form.\n+ * return:\n+ *      1 if `src' is a valid [RFC1884 2.2] address, else 0.\n+ * notice:\n+ *      (1) does not touch `dst' unless it's returning 1.\n+ *      (2) :: in a full address is silently ignored.\n+ * credit:\n+ *      inspired by Mark Andrews.\n+ * author:\n+ *      Paul Vixie, 1996.\n+ */\n+static int\n+inet_pton6(const char *src, unsigned char *dst)\n+{\n+\tstatic const char xdigits_l[] = \"0123456789abcdef\",\n+\t\txdigits_u[] = \"0123456789ABCDEF\";\n+\tunsigned char tmp[IN6ADDRSZ], *tp = 0, *endp = 0, *colonp = 0;\n+\tconst char *xdigits = 0, *curtok = 0;\n+\tint ch = 0, saw_xdigit = 0, count_xdigit = 0;\n+\tunsigned int val = 0;\n+\tunsigned dbloct_count = 0;\n+\n+\tmemset((tp = tmp), '\\0', IN6ADDRSZ);\n+\tendp = tp + IN6ADDRSZ;\n+\tcolonp = NULL;\n+\t/* Leading :: requires some special handling. */\n+\tif (*src == ':')\n+\t\tif (*++src != ':')\n+\t\t\treturn 0;\n+\tcurtok = src;\n+\tsaw_xdigit = count_xdigit = 0;\n+\tval = 0;\n+\n+\twhile ((ch = *src++) != '\\0') {\n+\t\tconst char *pch;\n+\n+\t\tpch = strchr((xdigits = xdigits_l), ch);\n+\t\tif (pch == NULL)\n+\t\t\tpch = strchr((xdigits = xdigits_u), ch);\n+\t\tif (pch != NULL) {\n+\t\t\tif (count_xdigit >= 4)\n+\t\t\t\treturn 0;\n+\t\t\tval <<= 4;\n+\t\t\tval |= (pch - xdigits);\n+\t\t\tif (val > 0xffff)\n+\t\t\t\treturn 0;\n+\t\t\tsaw_xdigit = 1;\n+\t\t\tcount_xdigit++;\n+\t\t\tcontinue;\n+\t\t}\n+\t\tif (ch == ':') {\n+\t\t\tcurtok = src;\n+\t\t\tif (!saw_xdigit) {\n+\t\t\t\tif (colonp)\n+\t\t\t\t\treturn 0;\n+\t\t\t\tcolonp = tp;\n+\t\t\t\tcontinue;\n+\t\t\t} else if (*src == '\\0') {\n+\t\t\t\treturn 0;\n+\t\t\t}\n+\t\t\tif (tp + sizeof(int16_t) > endp)\n+\t\t\t\treturn 0;\n+\t\t\t*tp++ = (unsigned char) ((val >> 8) & 0xff);\n+\t\t\t*tp++ = (unsigned char) (val & 0xff);\n+\t\t\tsaw_xdigit = 0;\n+\t\t\tcount_xdigit = 0;\n+\t\t\tval = 0;\n+\t\t\tdbloct_count++;\n+\t\t\tcontinue;\n+\t\t}\n+\t\tif (ch == '.' && ((tp + INADDRSZ) <= endp) &&\n+\t\t    inet_pton4(curtok, tp) > 0) {\n+\t\t\ttp += INADDRSZ;\n+\t\t\tsaw_xdigit = 0;\n+\t\t\tdbloct_count += 2;\n+\t\t\tbreak;  /* '\\0' was seen by inet_pton4(). */\n+\t\t}\n+\t\treturn 0;\n+\t}\n+\tif (saw_xdigit) {\n+\t\tif (tp + sizeof(int16_t) > endp)\n+\t\t\treturn 0;\n+\t\t*tp++ = (unsigned char) ((val >> 8) & 0xff);\n+\t\t*tp++ = (unsigned char) (val & 0xff);\n+\t\tdbloct_count++;\n+\t}\n+\tif (colonp != NULL) {\n+\t\t/* if we already have 8 double octets, having a colon\n+\t\t * means error */\n+\t\tif (dbloct_count == 8)\n+\t\t\treturn 0;\n+\n+\t\t/*\n+\t\t * Since some memmove()'s erroneously fail to handle\n+\t\t * overlapping regions, we'll do the shift by hand.\n+\t\t */\n+\t\tconst int n = tp - colonp;\n+\t\tint i;\n+\n+\t\tfor (i = 1; i <= n; i++) {\n+\t\t\tendp[-i] = colonp[n - i];\n+\t\t\tcolonp[n - i] = 0;\n+\t\t}\n+\t\ttp = endp;\n+\t}\n+\tif (tp != endp)\n+\t\treturn 0;\n+\tmemcpy(dst, tmp, IN6ADDRSZ);\n+\treturn 1;\n+}\n+\n+int\n+parse_ipv4_addr(const char *token, struct in_addr *ipv4, uint32_t *mask)\n+{\n+\tchar ip_str[256] = {0};\n+\tchar *pch;\n+\n+\tpch = strchr(token, '/');\n+\tif (pch != NULL) {\n+\t\tstrncpy(ip_str, token, pch - token);\n+\t\tpch += 1;\n+\t\tif (is_str_num(pch) != 0)\n+\t\t\treturn -EINVAL;\n+\t\tif (mask)\n+\t\t\t*mask = atoi(pch);\n+\t} else {\n+\t\tstrncpy(ip_str, token, sizeof(ip_str));\n+\t\tif (mask)\n+\t\t\t*mask = 0;\n+\t}\n+\n+\tif (strlen(ip_str) >= INET_ADDRSTRLEN)\n+\t\treturn -EINVAL;\n+\n+\tif (inet_pton4(ip_str, (unsigned char *)ipv4) != 1)\n+\t\treturn -EINVAL;\n+\n+\treturn 0;\n+}\n+\n+int\n+parse_ipv6_addr(const char *token, struct in6_addr *ipv6, uint32_t *mask)\n+{\n+\tchar ip_str[256] = {0};\n+\tchar *pch;\n+\n+\tpch = strchr(token, '/');\n+\tif (pch != NULL) {\n+\t\tstrncpy(ip_str, token, pch - token);\n+\t\tpch += 1;\n+\t\tif (is_str_num(pch) != 0)\n+\t\t\treturn -EINVAL;\n+\t\tif (mask)\n+\t\t\t*mask = atoi(pch);\n+\t} else {\n+\t\tstrncpy(ip_str, token, sizeof(ip_str));\n+\t\tif (mask)\n+\t\t\t*mask = 0;\n+\t}\n+\n+\tif (strlen(ip_str) >= INET6_ADDRSTRLEN)\n+\t\treturn -EINVAL;\n+\n+\tif (inet_pton6(ip_str, (unsigned char *)ipv6) != 1)\n+\t\treturn -EINVAL;\n+\n+\treturn 0;\n+}\n+\n+int\n+parse_range(const char *token, uint16_t *low, uint16_t *high)\n+{\n+\tchar ch;\n+\tchar num_str[20];\n+\tuint32_t pos;\n+\tint range_low = -1;\n+\tint range_high = -1;\n+\n+\tif (!low || !high)\n+\t\treturn -1;\n+\n+\tmemset(num_str, 0, 20);\n+\tpos = 0;\n+\n+\twhile ((ch = *token++) != '\\0') {\n+\t\tif (isdigit(ch)) {\n+\t\t\tif (pos >= 19)\n+\t\t\t\treturn -1;\n+\t\t\tnum_str[pos++] = ch;\n+\t\t} else if (ch == ':') {\n+\t\t\tif (range_low != -1)\n+\t\t\t\treturn -1;\n+\t\t\trange_low = atoi(num_str);\n+\t\t\tmemset(num_str, 0, 20);\n+\t\t\tpos = 0;\n+\t\t}\n+\t}\n+\n+\tif (strlen(num_str) == 0)\n+\t\treturn -1;\n+\n+\trange_high = atoi(num_str);\n+\n+\t*low = (uint16_t)range_low;\n+\t*high = (uint16_t)range_high;\n+\n+\treturn 0;\n+}\n+\n+/** sp add parse */\n+struct cfg_sp_add_cfg_item {\n+\tcmdline_fixed_string_t sp_keyword;\n+\tcmdline_multi_string_t multi_string;\n+};\n+\n+static void\n+cfg_sp_add_cfg_item_parsed(void *parsed_result,\n+\t__rte_unused struct cmdline *cl, void *data)\n+{\n+\tstruct cfg_sp_add_cfg_item *params = parsed_result;\n+\tchar *tokens[32];\n+\tuint32_t n_tokens = RTE_DIM(tokens);\n+\tstruct parse_status *status = (struct parse_status *)data;\n+\n+\tAPP_CHECK((parse_tokenize_string(params->multi_string, tokens,\n+\t\t&n_tokens) == 0), status, \"too many arguments\");\n+\n+\tif (status->status < 0)\n+\t\treturn;\n+\n+\tif (strcmp(tokens[0], \"ipv4\") == 0) {\n+\t\tparse_sp4_tokens(tokens, n_tokens, status);\n+\t\tif (status->status < 0)\n+\t\t\treturn;\n+\t} else if (strcmp(tokens[0], \"ipv6\") == 0) {\n+\t\tparse_sp6_tokens(tokens, n_tokens, status);\n+\t\tif (status->status < 0)\n+\t\t\treturn;\n+\t} else {\n+\t\tAPP_CHECK(0, status, \"unrecognizable input %s\\n\",\n+\t\t\ttokens[0]);\n+\t\treturn;\n+\t}\n+}\n+\n+static cmdline_parse_token_string_t cfg_sp_add_sp_str =\n+\tTOKEN_STRING_INITIALIZER(struct cfg_sp_add_cfg_item,\n+\t\tsp_keyword, \"sp\");\n+\n+static cmdline_parse_token_string_t cfg_sp_add_multi_str =\n+\tTOKEN_STRING_INITIALIZER(struct cfg_sp_add_cfg_item, multi_string,\n+\t\tTOKEN_STRING_MULTI);\n+\n+cmdline_parse_inst_t cfg_sp_add_rule = {\n+\t.f = cfg_sp_add_cfg_item_parsed,\n+\t.data = NULL,\n+\t.help_str = \"\",\n+\t.tokens = {\n+\t\t(void *) &cfg_sp_add_sp_str,\n+\t\t(void *) &cfg_sp_add_multi_str,\n+\t\tNULL,\n+\t},\n+};\n+\n+/* sa add parse */\n+struct cfg_sa_add_cfg_item {\n+\tcmdline_fixed_string_t sa_keyword;\n+\tcmdline_multi_string_t multi_string;\n+};\n+\n+static void\n+cfg_sa_add_cfg_item_parsed(void *parsed_result,\n+\t__rte_unused struct cmdline *cl, void *data)\n+{\n+\tstruct cfg_sa_add_cfg_item *params = parsed_result;\n+\tchar *tokens[32];\n+\tuint32_t n_tokens = RTE_DIM(tokens);\n+\tstruct parse_status *status = (struct parse_status *)data;\n+\n+\tAPP_CHECK(parse_tokenize_string(params->multi_string, tokens,\n+\t\t&n_tokens) == 0, status, \"too many arguments\\n\");\n+\n+\tparse_sa_tokens(tokens, n_tokens, status);\n+}\n+\n+static cmdline_parse_token_string_t cfg_sa_add_sa_str =\n+\tTOKEN_STRING_INITIALIZER(struct cfg_sa_add_cfg_item,\n+\t\tsa_keyword, \"sa\");\n+\n+static cmdline_parse_token_string_t cfg_sa_add_multi_str =\n+\tTOKEN_STRING_INITIALIZER(struct cfg_sa_add_cfg_item, multi_string,\n+\t\tTOKEN_STRING_MULTI);\n+\n+cmdline_parse_inst_t cfg_sa_add_rule = {\n+\t.f = cfg_sa_add_cfg_item_parsed,\n+\t.data = NULL,\n+\t.help_str = \"\",\n+\t.tokens = {\n+\t\t(void *) &cfg_sa_add_sa_str,\n+\t\t(void *) &cfg_sa_add_multi_str,\n+\t\tNULL,\n+\t},\n+};\n+\n+/* rt add parse */\n+struct cfg_rt_add_cfg_item {\n+\tcmdline_fixed_string_t rt_keyword;\n+\tcmdline_multi_string_t multi_string;\n+};\n+\n+static void\n+cfg_rt_add_cfg_item_parsed(void *parsed_result,\n+\t__rte_unused struct cmdline *cl, void *data)\n+{\n+\tstruct cfg_rt_add_cfg_item *params = parsed_result;\n+\tchar *tokens[32];\n+\tuint32_t n_tokens = RTE_DIM(tokens);\n+\tstruct parse_status *status = (struct parse_status *)data;\n+\n+\tAPP_CHECK(parse_tokenize_string(\n+\t\tparams->multi_string, tokens, &n_tokens) == 0,\n+\t\tstatus, \"too many arguments\\n\");\n+\tif (status->status < 0)\n+\t\treturn;\n+\n+\tparse_rt_tokens(tokens, n_tokens, status);\n+}\n+\n+static cmdline_parse_token_string_t cfg_rt_add_rt_str =\n+\tTOKEN_STRING_INITIALIZER(struct cfg_rt_add_cfg_item,\n+\t\trt_keyword, \"rt\");\n+\n+static cmdline_parse_token_string_t cfg_rt_add_multi_str =\n+\tTOKEN_STRING_INITIALIZER(struct cfg_rt_add_cfg_item, multi_string,\n+\t\tTOKEN_STRING_MULTI);\n+\n+cmdline_parse_inst_t cfg_rt_add_rule = {\n+\t.f = cfg_rt_add_cfg_item_parsed,\n+\t.data = NULL,\n+\t.help_str = \"\",\n+\t.tokens = {\n+\t\t(void *) &cfg_rt_add_rt_str,\n+\t\t(void *) &cfg_rt_add_multi_str,\n+\t\tNULL,\n+\t},\n+};\n+\n+/** set of cfg items */\n+cmdline_parse_ctx_t ipsec_ctx[] = {\n+\t(cmdline_parse_inst_t *)&cfg_sp_add_rule,\n+\t(cmdline_parse_inst_t *)&cfg_sa_add_rule,\n+\t(cmdline_parse_inst_t *)&cfg_rt_add_rule,\n+\tNULL,\n+};\n+\n+int\n+parse_cfg_file(const char *cfg_filename)\n+{\n+\tstruct cmdline *cl = cmdline_stdin_new(ipsec_ctx, \"\");\n+\tFILE *f = fopen(cfg_filename, \"r\");\n+\tchar str[1024] = {0}, *get_s = NULL;\n+\tuint32_t line_num = 0;\n+\tstruct parse_status status = {0};\n+\n+\tif (f == NULL) {\n+\t\trte_panic(\"Error: invalid file descriptor %s\\n\",\n+\t\t\tcfg_filename);\n+\t\tgoto error_exit;\n+\t}\n+\n+\tif (cl == NULL) {\n+\t\trte_panic(\"Error: cannot create cmdline instance\\n\");\n+\t\tgoto error_exit;\n+\t}\n+\n+\tcfg_sp_add_rule.data = &status;\n+\tcfg_sa_add_rule.data = &status;\n+\tcfg_rt_add_rule.data = &status;\n+\n+\tdo {\n+\t\tchar oneline[1024];\n+\n+\t\tget_s = fgets(oneline, 1024, f);\n+\t\tif (get_s) {\n+\t\t\tchar *pos;\n+\n+\t\t\tline_num++;\n+\n+\t\t\tif (strlen(oneline) > 1022) {\n+\t\t\t\trte_panic(\"%s:%u: error: the line \"\n+\t\t\t\t\t\"contains more characters the \"\n+\t\t\t\t\t\"parser can handle\\n\",\n+\t\t\t\t\tcfg_filename, line_num);\n+\t\t\t\tgoto error_exit;\n+\t\t\t}\n+\n+\t\t\t/* process comment char '#' */\n+\t\t\tif (oneline[0] == '#')\n+\t\t\t\tcontinue;\n+\n+\t\t\tpos = strchr(oneline, '#');\n+\t\t\tif (pos != NULL)\n+\t\t\t\t*pos = '\\0';\n+\n+\t\t\t/* process line concatenator '\\' */\n+\t\t\tpos = strchr(oneline, 92);\n+\t\t\tif (pos != NULL) {\n+\t\t\t\tif (pos != oneline+strlen(oneline) - 2) {\n+\t\t\t\t\trte_panic(\"%s:%u: error: no \"\n+\t\t\t\t\t\t\"character should exist \"\n+\t\t\t\t\t\t\"after '\\\\' symbol\\n\",\n+\t\t\t\t\t\tcfg_filename, line_num);\n+\t\t\t\t\tgoto error_exit;\n+\t\t\t\t}\n+\n+\t\t\t\t*pos = '\\0';\n+\n+\t\t\t\tif (strlen(oneline) + strlen(str) > 1022) {\n+\t\t\t\t\trte_panic(\"%s:%u: error: the \"\n+\t\t\t\t\t\t\"concatenated line \"\n+\t\t\t\t\t\t\"contains more characters \"\n+\t\t\t\t\t\t\"the parser can handle\\n\",\n+\t\t\t\t\t\tcfg_filename, line_num);\n+\t\t\t\t\tgoto error_exit;\n+\t\t\t\t}\n+\n+\t\t\t\tstrncpy(str + strlen(str), oneline,\n+\t\t\t\t\tstrlen(oneline));\n+\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\n+\t\t\t/* copy the line to str and process */\n+\t\t\tif (strlen(oneline) + strlen(str) > 1022) {\n+\t\t\t\trte_panic(\"%s:%u: error: the line \"\n+\t\t\t\t\t\"contains more characters the \"\n+\t\t\t\t\t\"parser can handle\\n\",\n+\t\t\t\t\tcfg_filename, line_num);\n+\t\t\t\tgoto error_exit;\n+\t\t\t}\n+\t\t\tstrncpy(str + strlen(str), oneline,\n+\t\t\t\tstrlen(oneline));\n+\n+\t\t\tstr[strlen(str)] = '\\n';\n+\t\t\tif (cmdline_parse(cl, str) < 0) {\n+\t\t\t\trte_panic(\"%s:%u: error: parsing \\\"%s\\\" \"\n+\t\t\t\t\t\"failed\\n\", cfg_filename,\n+\t\t\t\t\tline_num, str);\n+\t\t\t\tgoto error_exit;\n+\t\t\t}\n+\n+\t\t\tif (status.status < 0) {\n+\t\t\t\trte_panic(\"%s:%u: error: %s\",\n+\t\t\t\t\tcfg_filename, line_num,\n+\t\t\t\t\tstatus.parse_msg);\n+\t\t\t\tgoto error_exit;\n+\t\t\t}\n+\n+\t\t\tmemset(str, 0, 1024);\n+\t\t}\n+\t} while (get_s != NULL);\n+\n+\tcmdline_stdin_exit(cl);\n+\tfclose(f);\n+\n+\treturn 0;\n+\n+error_exit:\n+\tif (cl)\n+\t\tcmdline_stdin_exit(cl);\n+\tif (f)\n+\t\tfclose(f);\n+\n+\treturn -1;\n+}\ndiff --git a/examples/ipsec-secgw/parser.h b/examples/ipsec-secgw/parser.h\nnew file mode 100644\nindex 0000000..d31ae01\n--- /dev/null\n+++ b/examples/ipsec-secgw/parser.h\n@@ -0,0 +1,116 @@\n+/*   BSD LICENSE\n+ *\n+ *   Copyright(c) 2016 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 <sys/types.h>\n+#include <netinet/in.h>\n+#include <netinet/ip.h>\n+\n+#ifndef __PARSER_H\n+#define __PARSER_H\n+\n+struct parse_status {\n+\tint status;\n+\tchar parse_msg[256];\n+};\n+\n+#define\tAPP_CHECK(exp, status, fmt, ...)\t\t\t\t\\\n+do {\t\t\t\t\t\t\t\t\t\\\n+\tif (!(exp)) {\t\t\t\t\t\t\t\\\n+\t\tsprintf(status->parse_msg, fmt \"\\n\",\t\t\t\\\n+\t\t\t## __VA_ARGS__);\t\t\t\t\\\n+\t\tstatus->status = -1;\t\t\t\t\t\\\n+\t} else\t\t\t\t\t\t\t\t\\\n+\t\tstatus->status = 0;\t\t\t\t\t\\\n+} while (0)\n+\n+#define APP_CHECK_PRESENCE(val, str, status)\t\t\t\t\\\n+\tAPP_CHECK(val == 0, status,\t\t\t\t\t\\\n+\t\t\"item \\\"%s\\\" already present\", str)\n+\n+#define APP_CHECK_TOKEN_EQUAL(tokens, index, ref, status)\t\t\\\n+\tAPP_CHECK(strcmp(tokens[index], ref) == 0, status,\t\t\\\n+\t\t\"unrecognized input \\\"%s\\\": expect \\\"%s\\\"\\n\",\t\t\\\n+\t\ttokens[index], ref)\n+\n+static inline int\n+is_str_num(const char *str)\n+{\n+\tuint32_t i;\n+\n+\tfor (i = 0; i < strlen(str); i++)\n+\t\tif (!isdigit(str[i]))\n+\t\t\treturn -1;\n+\n+\treturn 0;\n+}\n+\n+#define APP_CHECK_TOKEN_IS_NUM(tokens, index, status)\t\t\t\\\n+\tAPP_CHECK(is_str_num(tokens[index]) == 0, status,\t\t\\\n+\t\"input \\\"%s\\\" is not valid number string\", tokens[index])\n+\n+\n+#define INCREMENT_TOKEN_INDEX(index, max_num, status)\t\t\t\\\n+do {\t\t\t\t\t\t\t\t\t\\\n+\tAPP_CHECK(index + 1 < max_num, status, \"reaching the end of \"\t\\\n+\t\t\"the token array\");\t\t\t\t\t\\\n+\tindex++;\t\t\t\t\t\t\t\\\n+} while (0)\n+\n+int\n+parse_ipv4_addr(const char *token, struct in_addr *ipv4, uint32_t *mask);\n+\n+int\n+parse_ipv6_addr(const char *token, struct in6_addr *ipv6, uint32_t *mask);\n+\n+int\n+parse_range(const char *token, uint16_t *low, uint16_t *high);\n+\n+void\n+parse_sp4_tokens(char **tokens, uint32_t n_tokens,\n+\tstruct parse_status *status);\n+\n+void\n+parse_sp6_tokens(char **tokens, uint32_t n_tokens,\n+\tstruct parse_status *status);\n+\n+void\n+parse_sa_tokens(char **tokens, uint32_t n_tokens,\n+\tstruct parse_status *status);\n+\n+void\n+parse_rt_tokens(char **tokens, uint32_t n_tokens,\n+\tstruct parse_status *status);\n+\n+int\n+parse_cfg_file(const char *cfg_filename);\n+\n+#endif\ndiff --git a/examples/ipsec-secgw/rt.c b/examples/ipsec-secgw/rt.c\nindex fa5f042..e03c5f0 100644\n--- a/examples/ipsec-secgw/rt.c\n+++ b/examples/ipsec-secgw/rt.c\n@@ -41,6 +41,7 @@\n #include <rte_ip.h>\n \n #include \"ipsec.h\"\n+#include \"parser.h\"\n \n #define RT_IPV4_MAX_RULES\t1024\n #define RT_IPV6_MAX_RULES\t1024\n@@ -57,135 +58,106 @@ struct ip6_route {\n \tuint8_t if_out;\n };\n \n-static struct ip4_route rt_ip4_ep0[] = {\n-\t/* Outbound */\n-\t/* Tunnels */\n-\t{ IPv4(172, 16, 2, 5), 32, 0 },\n-\t{ IPv4(172, 16, 2, 6), 32, 1 },\n-\t/* Transport */\n-\t{ IPv4(192, 168, 175, 0), 24, 0 },\n-\t{ IPv4(192, 168, 176, 0), 24, 1 },\n-\t/* Bypass */\n-\t{ IPv4(192, 168, 240, 0), 24, 0 },\n-\t{ IPv4(192, 168, 241, 0), 24, 1 },\n+struct ip4_route rt_ip4[RT_IPV4_MAX_RULES];\n+uint32_t nb_rt_ip4;\n \n-\t/* Inbound */\n-\t/* Tunnels */\n-\t{ IPv4(192, 168, 115, 0), 24, 2 },\n-\t{ IPv4(192, 168, 116, 0), 24, 3 },\n-\t{ IPv4(192, 168, 65, 0), 24, 2 },\n-\t{ IPv4(192, 168, 66, 0), 24, 3 },\n-\t/* Transport */\n-\t{ IPv4(192, 168, 185, 0), 24, 2 },\n-\t{ IPv4(192, 168, 186, 0), 24, 3 },\n-\t/* NULL */\n-\t{ IPv4(192, 168, 210, 0), 24, 2 },\n-\t{ IPv4(192, 168, 211, 0), 24, 3 },\n-\t/* Bypass */\n-\t{ IPv4(192, 168, 245, 0), 24, 2 },\n-\t{ IPv4(192, 168, 246, 0), 24, 3 },\n-};\n-\n-static struct ip6_route rt_ip6_ep0[] = {\n-\t/* Outbound */\n-\t/* Tunnels */\n-\t{ { 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,\n-\t\t  0x22, 0x22, 0x22, 0x22, 0x22, 0x55, 0x55 }, 116, 0 },\n-\t{ { 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,\n-\t\t  0x22, 0x22, 0x22, 0x22, 0x22, 0x66, 0x66 }, 116, 1 },\n-\t/* Transport */\n-\t{ { 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x00,\n-\t\t  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 116, 0 },\n-\t{ { 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x11,\n-\t\t  0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00 }, 116, 1 },\n-\t/* Inbound */\n-\t/* Tunnels */\n-\t{ { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa,\n-\t\t  0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00 }, 116, 2 },\n-\t{ { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbb,\n-\t\t  0xbb, 0xbb, 0xbb, 0x00, 0x00, 0x00, 0x00 }, 116, 3 },\n-\t{ { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55,\n-\t\t  0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00 }, 116, 2 },\n-\t{ { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66,\n-\t\t  0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00 }, 116, 3 },\n-\t/* Transport */\n-\t{ { 0xff, 0xff, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x00,\n-\t\t  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 116, 2 },\n-\t{ { 0xff, 0xff, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x11,\n-\t\t  0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00 }, 116, 3 },\n-};\n-\n-static struct ip4_route rt_ip4_ep1[] = {\n-\t/* Outbound */\n-\t/* Tunnels */\n-\t{ IPv4(172, 16, 1, 5), 32, 0 },\n-\t{ IPv4(172, 16, 1, 6), 32, 1 },\n-\t/* Transport */\n-\t{ IPv4(192, 168, 185, 0), 24, 0 },\n-\t{ IPv4(192, 168, 186, 0), 24, 1 },\n-\t/* Bypass */\n-\t{ IPv4(192, 168, 245, 0), 24, 0 },\n-\t{ IPv4(192, 168, 246, 0), 24, 1 },\n+struct ip6_route rt_ip6[RT_IPV4_MAX_RULES];\n+uint32_t nb_rt_ip6;\n \n-\t/* Inbound */\n-\t/* Tunnels */\n-\t{ IPv4(192, 168, 105, 0), 24, 2 },\n-\t{ IPv4(192, 168, 106, 0), 24, 3 },\n-\t{ IPv4(192, 168, 55, 0), 24, 2 },\n-\t{ IPv4(192, 168, 56, 0), 24, 3 },\n-\t/* Transport */\n-\t{ IPv4(192, 168, 175, 0), 24, 2 },\n-\t{ IPv4(192, 168, 176, 0), 24, 3 },\n-\t/* NULL */\n-\t{ IPv4(192, 168, 200, 0), 24, 2 },\n-\t{ IPv4(192, 168, 201, 0), 24, 3 },\n-\t/* Bypass */\n-\t{ IPv4(192, 168, 240, 0), 24, 2 },\n-\t{ IPv4(192, 168, 241, 0), 24, 3 },\n-};\n+void\n+parse_rt_tokens(char **tokens, uint32_t n_tokens,\n+\tstruct parse_status *status)\n+{\n+\tuint32_t ti;\n+\tuint32_t *n_rts = NULL;\n+\tstruct ip4_route *route_ipv4 = NULL;\n+\tstruct ip6_route *route_ipv6 = NULL;\n+\n+\tif (strcmp(tokens[0], \"ipv4\") == 0) {\n+\t\tn_rts = &nb_rt_ip4;\n+\t\troute_ipv4 = &rt_ip4[*n_rts];\n+\n+\t\tAPP_CHECK(*n_rts <= RT_IPV4_MAX_RULES - 1, status,\n+\t\t\t\"too many rt rules, abort insertion\\n\");\n+\t\tif (status->status < 0)\n+\t\t\treturn;\n+\n+\t} else if (strcmp(tokens[0], \"ipv6\") == 0) {\n+\t\tn_rts = &nb_rt_ip6;\n+\t\troute_ipv6 = &rt_ip6[*n_rts];\n+\n+\t\tAPP_CHECK(*n_rts <= RT_IPV6_MAX_RULES - 1, status,\n+\t\t\t\"too many rt rules, abort insertion\\n\");\n+\t\tif (status->status < 0)\n+\t\t\treturn;\n+\t} else {\n+\t\tAPP_CHECK(0, status, \"unrecognized input \\\"%s\\\"\",\n+\t\t\ttokens[0]);\n+\t\treturn;\n+\t}\n \n-static struct ip6_route rt_ip6_ep1[] = {\n-\t/* Outbound */\n-\t/* Tunnels */\n-\t{ { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,\n-\t\t  0x11, 0x11, 0x11, 0x11, 0x11, 0x55, 0x55 }, 116, 0 },\n-\t{ { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,\n-\t\t  0x11, 0x11, 0x11, 0x11, 0x11, 0x66, 0x66 }, 116, 1 },\n-\t/* Transport */\n-\t{ { 0xff, 0xff, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x00,\n-\t\t  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 116, 0 },\n-\t{ { 0xff, 0xff, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x11,\n-\t\t  0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00 }, 116, 1 },\n+\tfor (ti = 1; ti < n_tokens; ti++) {\n+\t\tif (strcmp(tokens[ti], \"dst\") == 0) {\n+\t\t\tINCREMENT_TOKEN_INDEX(ti, n_tokens, status);\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\n+\t\t\tif (route_ipv4 != NULL) {\n+\t\t\t\tstruct in_addr ip;\n+\t\t\t\tuint32_t depth = 0;\n+\n+\t\t\t\tAPP_CHECK(parse_ipv4_addr(tokens[ti],\n+\t\t\t\t\t&ip, &depth) == 0, status,\n+\t\t\t\t\t\"unrecognized input \\\"%s\\\", \"\n+\t\t\t\t\t\"expect valid ipv4 addr\",\n+\t\t\t\t\ttokens[ti]);\n+\t\t\t\tif (status->status < 0)\n+\t\t\t\t\treturn;\n+\t\t\t\troute_ipv4->ip = rte_bswap32(\n+\t\t\t\t\t(uint32_t)ip.s_addr);\n+\t\t\t\troute_ipv4->depth = (uint8_t)depth;\n+\t\t\t} else {\n+\t\t\t\tstruct in6_addr ip;\n+\t\t\t\tuint32_t depth;\n+\n+\t\t\t\tAPP_CHECK(parse_ipv6_addr(tokens[ti],\n+\t\t\t\t\t&ip, &depth) == 0, status,\n+\t\t\t\t\t\"unrecognized input \\\"%s\\\", \"\n+\t\t\t\t\t\"expect valid ipv6 address\",\n+\t\t\t\t\ttokens[ti]);\n+\t\t\t\tif (status->status < 0)\n+\t\t\t\t\treturn;\n+\t\t\t\tmemcpy(route_ipv6->ip, ip.s6_addr, 16);\n+\t\t\t\troute_ipv6->depth = (uint8_t)depth;\n+\t\t\t}\n+\t\t}\n+\n+\t\tif (strcmp(tokens[ti], \"port\") == 0) {\n+\t\t\tINCREMENT_TOKEN_INDEX(ti, n_tokens, status);\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\t\t\tAPP_CHECK_TOKEN_IS_NUM(tokens, ti, status);\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\t\t\tif (route_ipv4 != NULL)\n+\t\t\t\troute_ipv4->if_out = atoi(tokens[ti]);\n+\t\t\telse\n+\t\t\t\troute_ipv6->if_out = atoi(tokens[ti]);\n+\t\t}\n+\t}\n \n-\t/* Inbound */\n-\t/* Tunnels */\n-\t{ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa,\n-\t\t  0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00 }, 116, 2 },\n-\t{ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbb,\n-\t\t  0xbb, 0xbb, 0xbb, 0x00, 0x00, 0x00, 0x00 }, 116, 3 },\n-\t{ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55,\n-\t\t  0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00 }, 116, 2 },\n-\t{ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66,\n-\t\t  0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00 }, 116, 3 },\n-\t/* Transport */\n-\t{ { 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x00,\n-\t\t  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 116, 2 },\n-\t{ { 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x11,\n-\t\t  0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00 }, 116, 3 },\n-};\n+\t*n_rts = *n_rts + 1;\n+}\n \n void\n-rt_init(struct socket_ctx *ctx, int32_t socket_id, uint32_t ep)\n+rt_init(struct socket_ctx *ctx, int32_t socket_id)\n {\n \tchar name[PATH_MAX];\n \tuint32_t i;\n \tint32_t ret;\n \tstruct rte_lpm *lpm;\n \tstruct rte_lpm6 *lpm6;\n-\tstruct ip4_route *rt;\n-\tstruct ip6_route *rt6;\n \tchar a, b, c, d;\n-\tuint32_t nb_routes, nb_routes6;\n \tstruct rte_lpm_config conf = { 0 };\n \tstruct rte_lpm6_config conf6 = { 0 };\n \n@@ -200,23 +172,12 @@ rt_init(struct socket_ctx *ctx, int32_t socket_id, uint32_t ep)\n \t\trte_exit(EXIT_FAILURE, \"IPv6 Routing Table for socket %u \"\n \t\t\t\"already initialized\\n\", socket_id);\n \n+\tif (nb_rt_ip4 == 0 && nb_rt_ip6 == 0)\n+\t\tRTE_LOG(WARNING, IPSEC, \"No Routing rule specified\\n\");\n+\n \tprintf(\"Creating IPv4 Routing Table (RT) context with %u max routes\\n\",\n \t\t\tRT_IPV4_MAX_RULES);\n \n-\tif (ep == 0) {\n-\t\trt = rt_ip4_ep0;\n-\t\tnb_routes = RTE_DIM(rt_ip4_ep0);\n-\t\trt6 = rt_ip6_ep0;\n-\t\tnb_routes6 = RTE_DIM(rt_ip6_ep0);\n-\t} else if (ep == 1) {\n-\t\trt = rt_ip4_ep1;\n-\t\tnb_routes = RTE_DIM(rt_ip4_ep1);\n-\t\trt6 = rt_ip6_ep1;\n-\t\tnb_routes6 = RTE_DIM(rt_ip6_ep1);\n-\t} else\n-\t\trte_exit(EXIT_FAILURE, \"Invalid EP value %u. Only 0 or 1 \"\n-\t\t\t\"supported.\\n\", ep);\n-\n \t/* create the LPM table */\n \tsnprintf(name, sizeof(name), \"%s_%u\", \"rt_ip4\", socket_id);\n \tconf.max_rules = RT_IPV4_MAX_RULES;\n@@ -227,15 +188,17 @@ rt_init(struct socket_ctx *ctx, int32_t socket_id, uint32_t ep)\n \t\t\t\"on socket %d\\n\", name, socket_id);\n \n \t/* populate the LPM table */\n-\tfor (i = 0; i < nb_routes; i++) {\n-\t\tret = rte_lpm_add(lpm, rt[i].ip, rt[i].depth, rt[i].if_out);\n+\tfor (i = 0; i < nb_rt_ip4; i++) {\n+\t\tret = rte_lpm_add(lpm, rt_ip4[i].ip, rt_ip4[i].depth,\n+\t\t\trt_ip4[i].if_out);\n \t\tif (ret < 0)\n \t\t\trte_exit(EXIT_FAILURE, \"Fail to add entry num %u to %s \"\n \t\t\t\t\"LPM table on socket %d\\n\", i, name, socket_id);\n \n-\t\tuint32_t_to_char(rt[i].ip, &a, &b, &c, &d);\n+\t\tuint32_t_to_char(rt_ip4[i].ip, &a, &b, &c, &d);\n \t\tprintf(\"LPM: Adding route %hhu.%hhu.%hhu.%hhu/%hhu (%hhu)\\n\",\n-\t\t\t\ta, b, c, d, rt[i].depth, rt[i].if_out);\n+\t\t\t\ta, b, c, d, rt_ip4[i].depth,\n+\t\t\t\trt_ip4[i].if_out);\n \t}\n \n \tsnprintf(name, sizeof(name), \"%s_%u\", \"rt_ip6\", socket_id);\n@@ -247,24 +210,24 @@ rt_init(struct socket_ctx *ctx, int32_t socket_id, uint32_t ep)\n \t\t\t\"on socket %d\\n\", name, socket_id);\n \n \t/* populate the LPM table */\n-\tfor (i = 0; i < nb_routes6; i++) {\n-\t\tret = rte_lpm6_add(lpm6, rt6[i].ip, rt6[i].depth,\n-\t\t\t\trt6[i].if_out);\n+\tfor (i = 0; i < nb_rt_ip6; i++) {\n+\t\tret = rte_lpm6_add(lpm6, rt_ip6[i].ip, rt_ip6[i].depth,\n+\t\t\t\trt_ip6[i].if_out);\n \t\tif (ret < 0)\n \t\t\trte_exit(EXIT_FAILURE, \"Fail to add entry num %u to %s \"\n \t\t\t\t\"LPM table on socket %d\\n\", i, name, socket_id);\n \n \t\tprintf(\"LPM6: Adding route \"\n \t\t\t\" %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx/%hhx (%hhx)\\n\",\n-\t\t\t(uint16_t)((rt6[i].ip[0] << 8) | rt6[i].ip[1]),\n-\t\t\t(uint16_t)((rt6[i].ip[2] << 8) | rt6[i].ip[3]),\n-\t\t\t(uint16_t)((rt6[i].ip[4] << 8) | rt6[i].ip[5]),\n-\t\t\t(uint16_t)((rt6[i].ip[6] << 8) | rt6[i].ip[7]),\n-\t\t\t(uint16_t)((rt6[i].ip[8] << 8) | rt6[i].ip[9]),\n-\t\t\t(uint16_t)((rt6[i].ip[10] << 8) | rt6[i].ip[11]),\n-\t\t\t(uint16_t)((rt6[i].ip[12] << 8) | rt6[i].ip[13]),\n-\t\t\t(uint16_t)((rt6[i].ip[14] << 8) | rt6[i].ip[15]),\n-\t\t\trt6[i].depth, rt6[i].if_out);\n+\t\t\t(uint16_t)((rt_ip6[i].ip[0] << 8) | rt_ip6[i].ip[1]),\n+\t\t\t(uint16_t)((rt_ip6[i].ip[2] << 8) | rt_ip6[i].ip[3]),\n+\t\t\t(uint16_t)((rt_ip6[i].ip[4] << 8) | rt_ip6[i].ip[5]),\n+\t\t\t(uint16_t)((rt_ip6[i].ip[6] << 8) | rt_ip6[i].ip[7]),\n+\t\t\t(uint16_t)((rt_ip6[i].ip[8] << 8) | rt_ip6[i].ip[9]),\n+\t\t\t(uint16_t)((rt_ip6[i].ip[10] << 8) | rt_ip6[i].ip[11]),\n+\t\t\t(uint16_t)((rt_ip6[i].ip[12] << 8) | rt_ip6[i].ip[13]),\n+\t\t\t(uint16_t)((rt_ip6[i].ip[14] << 8) | rt_ip6[i].ip[15]),\n+\t\t\trt_ip6[i].depth, rt_ip6[i].if_out);\n \t}\n \n \tctx->rt_ip4 = (struct rt_ctx *)lpm;\ndiff --git a/examples/ipsec-secgw/sa.c b/examples/ipsec-secgw/sa.c\nindex ab18b81..66733ef 100644\n--- a/examples/ipsec-secgw/sa.c\n+++ b/examples/ipsec-secgw/sa.c\n@@ -48,191 +48,248 @@\n \n #include \"ipsec.h\"\n #include \"esp.h\"\n+#include \"parser.h\"\n \n-/* SAs Outbound */\n-const struct ipsec_sa sa_out[] = {\n-\t{\n-\t.spi = 5,\n-\t.src.ip4 = IPv4(172, 16, 1, 5),\n-\t.dst.ip4 = IPv4(172, 16, 2, 5),\n-\t.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,\n-\t.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,\n-\t.digest_len = 12,\n-\t.iv_len = 16,\n-\t.block_size = 16,\n-\t.flags = IP4_TUNNEL\n-\t},\n-\t{\n-\t.spi = 6,\n-\t.src.ip4 = IPv4(172, 16, 1, 6),\n-\t.dst.ip4 = IPv4(172, 16, 2, 6),\n-\t.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,\n-\t.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,\n-\t.digest_len = 12,\n-\t.iv_len = 16,\n-\t.block_size = 16,\n-\t.flags = IP4_TUNNEL\n-\t},\n-\t{\n-\t.spi = 10,\n-\t.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,\n-\t.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,\n-\t.digest_len = 12,\n-\t.iv_len = 16,\n-\t.block_size = 16,\n-\t.flags = TRANSPORT\n-\t},\n-\t{\n-\t.spi = 11,\n-\t.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,\n-\t.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,\n-\t.digest_len = 12,\n-\t.iv_len = 16,\n-\t.block_size = 16,\n-\t.flags = TRANSPORT\n-\t},\n-\t{\n-\t.spi = 15,\n-\t.src.ip4 = IPv4(172, 16, 1, 5),\n-\t.dst.ip4 = IPv4(172, 16, 2, 5),\n-\t.cipher_algo = RTE_CRYPTO_CIPHER_NULL,\n-\t.auth_algo = RTE_CRYPTO_AUTH_NULL,\n-\t.digest_len = 0,\n-\t.iv_len = 0,\n-\t.block_size = 4,\n-\t.flags = IP4_TUNNEL\n-\t},\n-\t{\n-\t.spi = 16,\n-\t.src.ip4 = IPv4(172, 16, 1, 6),\n-\t.dst.ip4 = IPv4(172, 16, 2, 6),\n-\t.cipher_algo = RTE_CRYPTO_CIPHER_NULL,\n-\t.auth_algo = RTE_CRYPTO_AUTH_NULL,\n-\t.digest_len = 0,\n-\t.iv_len = 0,\n-\t.block_size = 4,\n-\t.flags = IP4_TUNNEL\n-\t},\n-\t{\n-\t.spi = 25,\n-\t.src.ip6_b = { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,\n-\t\t0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x55, 0x55 },\n-\t.dst.ip6_b = { 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,\n-\t\t0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x55, 0x55 },\n-\t.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,\n-\t.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,\n-\t.digest_len = 12,\n-\t.iv_len = 16,\n-\t.block_size = 16,\n-\t.flags = IP6_TUNNEL\n-\t},\n-\t{\n-\t.spi = 26,\n-\t.src.ip6_b = { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,\n-\t\t0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x66, 0x66 },\n-\t.dst.ip6_b = { 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,\n-\t\t0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x66, 0x66 },\n-\t.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,\n-\t.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,\n-\t.digest_len = 12,\n-\t.iv_len = 16,\n-\t.block_size = 16,\n-\t.flags = IP6_TUNNEL\n-\t},\n+struct supported_cipher_algo {\n+\tconst char *keyword;\n+\tenum rte_crypto_cipher_algorithm algo;\n+\tuint16_t iv_len;\n+\tuint16_t block_size;\n };\n \n-/* SAs Inbound */\n-const struct ipsec_sa sa_in[] = {\n-\t{\n-\t.spi = 105,\n-\t.src.ip4 = IPv4(172, 16, 2, 5),\n-\t.dst.ip4 = IPv4(172, 16, 1, 5),\n-\t.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,\n-\t.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,\n-\t.digest_len = 12,\n-\t.iv_len = 16,\n-\t.block_size = 16,\n-\t.flags = IP4_TUNNEL\n-\t},\n-\t{\n-\t.spi = 106,\n-\t.src.ip4 = IPv4(172, 16, 2, 6),\n-\t.dst.ip4 = IPv4(172, 16, 1, 6),\n-\t.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,\n-\t.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,\n-\t.digest_len = 12,\n-\t.iv_len = 16,\n-\t.block_size = 16,\n-\t.flags = IP4_TUNNEL\n-\t},\n-\t{\n-\t.spi = 110,\n-\t.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,\n-\t.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,\n-\t.digest_len = 12,\n-\t.iv_len = 16,\n-\t.block_size = 16,\n-\t.flags = TRANSPORT\n-\t},\n-\t{\n-\t.spi = 111,\n-\t.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,\n-\t.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,\n-\t.digest_len = 12,\n-\t.iv_len = 16,\n-\t.block_size = 16,\n-\t.flags = TRANSPORT\n-\t},\n+struct supported_auth_algo {\n+\tconst char *keyword;\n+\tenum rte_crypto_auth_algorithm algo;\n+\tuint16_t digest_len;\n+};\n+\n+const struct supported_cipher_algo cipher_algos[] = {\n \t{\n-\t.spi = 115,\n-\t.src.ip4 = IPv4(172, 16, 2, 5),\n-\t.dst.ip4 = IPv4(172, 16, 1, 5),\n-\t.cipher_algo = RTE_CRYPTO_CIPHER_NULL,\n-\t.auth_algo = RTE_CRYPTO_AUTH_NULL,\n-\t.digest_len = 0,\n-\t.iv_len = 0,\n-\t.block_size = 4,\n-\t.flags = IP4_TUNNEL\n+\t\t.keyword = \"null\",\n+\t\t.algo = RTE_CRYPTO_CIPHER_NULL,\n+\t\t.iv_len = 0,\n+\t\t.block_size = 4\n \t},\n \t{\n-\t.spi = 116,\n-\t.src.ip4 = IPv4(172, 16, 2, 6),\n-\t.dst.ip4 = IPv4(172, 16, 1, 6),\n-\t.cipher_algo = RTE_CRYPTO_CIPHER_NULL,\n-\t.auth_algo = RTE_CRYPTO_AUTH_NULL,\n-\t.digest_len = 0,\n-\t.iv_len = 0,\n-\t.block_size = 4,\n-\t.flags = IP4_TUNNEL\n-\t},\n+\t\t.keyword = \"aes-128-cbc\",\n+\t\t.algo = RTE_CRYPTO_CIPHER_AES_CBC,\n+\t\t.iv_len = 16,\n+\t\t.block_size = 16\n+\t}\n+};\n+\n+const struct supported_auth_algo auth_algos[] = {\n \t{\n-\t.spi = 125,\n-\t.src.ip6_b = { 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,\n-\t\t0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x55, 0x55 },\n-\t.dst.ip6_b = { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,\n-\t\t0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x55, 0x55 },\n-\t.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,\n-\t.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,\n-\t.digest_len = 12,\n-\t.iv_len = 16,\n-\t.block_size = 16,\n-\t.flags = IP6_TUNNEL\n+\t\t.keyword = \"null\",\n+\t\t.algo = RTE_CRYPTO_AUTH_NULL,\n+\t\t.digest_len = 0,\n \t},\n \t{\n-\t.spi = 126,\n-\t.src.ip6_b = { 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,\n-\t\t0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x66, 0x66 },\n-\t.dst.ip6_b = { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,\n-\t\t0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x66, 0x66 },\n-\t.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,\n-\t.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,\n-\t.digest_len = 12,\n-\t.iv_len = 16,\n-\t.block_size = 16,\n-\t.flags = IP6_TUNNEL\n-\t},\n+\t\t.keyword = \"sha1-hmac\",\n+\t\t.algo = RTE_CRYPTO_AUTH_SHA1_HMAC,\n+\t\t.digest_len = 12\n+\t}\n };\n \n+static int\n+find_match_algo(struct ipsec_sa *rule,\n+\tconst char *cipher_keyword, const char *auth_keyword)\n+{\n+\tsize_t i;\n+\tint ret = -2;\n+\n+\tif (cipher_keyword != NULL) {\n+\t\tfor (i = 0; i < RTE_DIM(cipher_algos); i++) {\n+\t\t\tconst struct supported_cipher_algo *algo =\n+\t\t\t\t&cipher_algos[i];\n+\n+\t\t\tif (strcmp(cipher_keyword, algo->keyword) == 0) {\n+\t\t\t\trule->cipher_algo = algo->algo;\n+\t\t\t\trule->block_size = algo->block_size;\n+\t\t\t\trule->iv_len = algo->iv_len;\n+\t\t\t\tret += 1;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\tif (auth_keyword != NULL) {\n+\t\tfor (i = 0; i < RTE_DIM(auth_algos); i++) {\n+\t\t\tconst struct supported_auth_algo *algo =\n+\t\t\t\t&auth_algos[i];\n+\n+\t\t\tif (strcmp(auth_keyword, algo->keyword) == 0) {\n+\t\t\t\trule->auth_algo = algo->algo;\n+\t\t\t\trule->digest_len = algo->digest_len;\n+\t\t\t\tret += 1;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\treturn ret;\n+}\n+\n+#define MAX_SA_RULE_NUM\t\t1000\n+\n+struct ipsec_sa sa_out[MAX_SA_RULE_NUM];\n+uint32_t nb_sa_out;\n+\n+struct ipsec_sa sa_in[MAX_SA_RULE_NUM];\n+uint32_t nb_sa_in;\n+\n+void\n+parse_sa_tokens(char **tokens, uint32_t n_tokens,\n+\tstruct parse_status *status)\n+{\n+\tstruct ipsec_sa *rule = NULL;\n+\tuint32_t ti; /*token index*/\n+\tuint32_t *ri /*rule index*/;\n+\tconst char *cipher_str, *auth_str;\n+\tuint32_t src_p = 0;\n+\tuint32_t dst_p = 0;\n+\n+\tif (strcmp(tokens[0], \"in\") == 0) {\n+\t\tri = &nb_sa_in;\n+\n+\t\tAPP_CHECK(*ri <= MAX_SA_RULE_NUM - 1, status,\n+\t\t\t\"too many sa rules, abort insertion\\n\");\n+\t\tif (status->status < 0)\n+\t\t\treturn;\n+\n+\t\trule = &sa_in[*ri];\n+\t} else {\n+\t\tri = &nb_sa_out;\n+\n+\t\tAPP_CHECK(*ri <= MAX_SA_RULE_NUM - 1, status,\n+\t\t\t\"too many sa rules, abort insertion\\n\");\n+\t\tif (status->status < 0)\n+\t\t\treturn;\n+\n+\t\trule = &sa_out[*ri];\n+\t}\n+\n+\t/* spi number */\n+\tAPP_CHECK_TOKEN_IS_NUM(tokens, 1, status);\n+\tif (status->status < 0)\n+\t\treturn;\n+\trule->spi = atoi(tokens[1]);\n+\n+\tcipher_str = tokens[2];\n+\tauth_str = tokens[3];\n+\n+\tAPP_CHECK(find_match_algo(rule, cipher_str, auth_str) == 0,\n+\t\tstatus, \"Unrecognized cipher or auth algorithm (%s:%s)\",\n+\t\tcipher_str, auth_str);\n+\tif (status->status < 0)\n+\t\treturn;\n+\n+\tif (strcmp(tokens[4], \"ipv4-tunnel\") == 0)\n+\t\trule->flags = IP4_TUNNEL;\n+\telse if (strcmp(tokens[4], \"ipv6-tunnel\") == 0)\n+\t\trule->flags = IP6_TUNNEL;\n+\telse if (strcmp(tokens[4], \"transport\") == 0)\n+\t\trule->flags = TRANSPORT;\n+\telse {\n+\t\tAPP_CHECK(0, status, \"unrecognized input \\\"%s\\\"\",\n+\t\t\ttokens[4]);\n+\t\treturn;\n+\t}\n+\n+\tfor (ti = 5; ti < n_tokens; ti++) {\n+\t\tif (strcmp(tokens[ti], \"src\") == 0) {\n+\t\t\tAPP_CHECK_PRESENCE(src_p, tokens[ti], status);\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\n+\t\t\tINCREMENT_TOKEN_INDEX(ti, n_tokens, status);\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\n+\t\t\tif (rule->flags == IP4_TUNNEL) {\n+\t\t\t\tstruct in_addr ip;\n+\n+\t\t\t\tAPP_CHECK(parse_ipv4_addr(tokens[ti],\n+\t\t\t\t\t&ip, NULL) == 0, status,\n+\t\t\t\t\t\"unrecognized input \\\"%s\\\", \"\n+\t\t\t\t\t\"expect valid ipv4 addr\",\n+\t\t\t\t\ttokens[ti]);\n+\t\t\t\tif (status->status < 0)\n+\t\t\t\t\treturn;\n+\t\t\t\trule->src.ip4 = rte_bswap32(\n+\t\t\t\t\t(uint32_t)ip.s_addr);\n+\t\t\t} else if (rule->flags == IP6_TUNNEL) {\n+\t\t\t\tstruct in6_addr ip;\n+\n+\t\t\t\tAPP_CHECK(parse_ipv6_addr(tokens[ti], &ip,\n+\t\t\t\t\tNULL) == 0, status,\n+\t\t\t\t\t\"unrecognized input \\\"%s\\\", \"\n+\t\t\t\t\t\"expect valid ipv6 addr\",\n+\t\t\t\t\ttokens[ti]);\n+\t\t\t\tif (status->status < 0)\n+\t\t\t\t\treturn;\n+\t\t\t\tmemcpy(rule->src.ip6_b, ip.s6_addr, 16);\n+\t\t\t} else if (rule->flags == TRANSPORT) {\n+\t\t\t\tAPP_CHECK(0, status, \"unrecognized input \"\n+\t\t\t\t\t\"\\\"%s\\\"\", tokens[ti]);\n+\t\t\t\treturn;\n+\t\t\t}\n+\n+\t\t\tsrc_p = 1;\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tif (strcmp(tokens[ti], \"dst\") == 0) {\n+\t\t\tAPP_CHECK_PRESENCE(dst_p, tokens[ti], status);\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\n+\t\t\tINCREMENT_TOKEN_INDEX(ti, n_tokens, status);\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\n+\t\t\tif (rule->flags == IP4_TUNNEL) {\n+\t\t\t\tstruct in_addr ip;\n+\n+\t\t\t\tAPP_CHECK(parse_ipv4_addr(tokens[ti],\n+\t\t\t\t\t&ip, NULL) == 0, status,\n+\t\t\t\t\t\"unrecognized input \\\"%s\\\", \"\n+\t\t\t\t\t\"expect valid ipv4 addr\",\n+\t\t\t\t\ttokens[ti]);\n+\t\t\t\tif (status->status < 0)\n+\t\t\t\t\treturn;\n+\t\t\t\trule->dst.ip4 = rte_bswap32(\n+\t\t\t\t\t(uint32_t)ip.s_addr);\n+\t\t\t} else if (rule->flags == IP6_TUNNEL) {\n+\t\t\t\tstruct in6_addr ip;\n+\n+\t\t\t\tAPP_CHECK(parse_ipv6_addr(tokens[ti], &ip,\n+\t\t\t\t\tNULL) == 0, status,\n+\t\t\t\t\t\"unrecognized input \\\"%s\\\", \"\n+\t\t\t\t\t\"expect valid ipv6 addr\",\n+\t\t\t\t\ttokens[ti]);\n+\t\t\t\tif (status->status < 0)\n+\t\t\t\t\treturn;\n+\t\t\t\tmemcpy(rule->dst.ip6_b, ip.s6_addr, 16);\n+\t\t\t} else if (rule->flags == TRANSPORT) {\n+\t\t\t\tAPP_CHECK(0, status, \"unrecognized \"\n+\t\t\t\t\t\"input \\\"%s\\\"\",\ttokens[ti]);\n+\t\t\t\treturn;\n+\t\t\t}\n+\n+\t\t\tdst_p = 1;\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\t/* unrecognizeable input */\n+\t\tAPP_CHECK(0, status, \"unrecognized input \\\"%s\\\"\",\n+\t\t\ttokens[ti]);\n+\t\treturn;\n+\t}\n+\n+\t*ri = *ri + 1;\n+}\n+\n static uint8_t cipher_key[256] = \"sixteenbytes key\";\n \n /* AES CBC xform */\n@@ -386,10 +443,8 @@ sa_in_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],\n }\n \n void\n-sa_init(struct socket_ctx *ctx, int32_t socket_id, uint32_t ep)\n+sa_init(struct socket_ctx *ctx, int32_t socket_id)\n {\n-\tconst struct ipsec_sa *sa_out_entries, *sa_in_entries;\n-\tuint32_t nb_out_entries, nb_in_entries;\n \tconst char *name;\n \n \tif (ctx == NULL)\n@@ -403,35 +458,30 @@ sa_init(struct socket_ctx *ctx, int32_t socket_id, uint32_t ep)\n \t\trte_exit(EXIT_FAILURE, \"Outbound SA DB for socket %u already \"\n \t\t\t\t\"initialized\\n\", socket_id);\n \n-\tif (ep == 0) {\n-\t\tsa_out_entries = sa_out;\n-\t\tnb_out_entries = RTE_DIM(sa_out);\n-\t\tsa_in_entries = sa_in;\n-\t\tnb_in_entries = RTE_DIM(sa_in);\n-\t} else if (ep == 1) {\n-\t\tsa_out_entries = sa_in;\n-\t\tnb_out_entries = RTE_DIM(sa_in);\n-\t\tsa_in_entries = sa_out;\n-\t\tnb_in_entries = RTE_DIM(sa_out);\n-\t} else\n-\t\trte_exit(EXIT_FAILURE, \"Invalid EP value %u. \"\n-\t\t\t\t\"Only 0 or 1 supported.\\n\", ep);\n-\n-\tname = \"sa_in\";\n-\tctx->sa_in = sa_create(name, socket_id);\n-\tif (ctx->sa_in == NULL)\n-\t\trte_exit(EXIT_FAILURE, \"Error [%d] creating SA context %s \"\n-\t\t\t\t\"in socket %d\\n\", rte_errno, name, socket_id);\n-\n-\tname = \"sa_out\";\n-\tctx->sa_out = sa_create(name, socket_id);\n-\tif (ctx->sa_out == NULL)\n-\t\trte_exit(EXIT_FAILURE, \"Error [%d] creating SA context %s \"\n-\t\t\t\t\"in socket %d\\n\", rte_errno, name, socket_id);\n-\n-\tsa_in_add_rules(ctx->sa_in, sa_in_entries, nb_in_entries);\n-\n-\tsa_out_add_rules(ctx->sa_out, sa_out_entries, nb_out_entries);\n+\tif (nb_sa_out == 0 && nb_sa_in == 0)\n+\t\tRTE_LOG(WARNING, IPSEC, \"No SA rule specified\\n\");\n+\n+\tif (nb_sa_in > 0) {\n+\t\tname = \"sa_in\";\n+\t\tctx->sa_in = sa_create(name, socket_id);\n+\t\tif (ctx->sa_in == NULL)\n+\t\t\trte_exit(EXIT_FAILURE, \"Error [%d] creating SA \"\n+\t\t\t\t\"context %s in socket %d\\n\", rte_errno,\n+\t\t\t\tname, socket_id);\n+\n+\t\tsa_in_add_rules(ctx->sa_in, sa_in, nb_sa_in);\n+\t}\n+\n+\tif (nb_sa_out > 0) {\n+\t\tname = \"sa_out\";\n+\t\tctx->sa_out = sa_create(name, socket_id);\n+\t\tif (ctx->sa_out == NULL)\n+\t\t\trte_exit(EXIT_FAILURE, \"Error [%d] creating SA \"\n+\t\t\t\t\"context %s in socket %d\\n\", rte_errno,\n+\t\t\t\tname, socket_id);\n+\n+\t\tsa_out_add_rules(ctx->sa_out, sa_out, nb_sa_out);\n+\t}\n }\n \n int\ndiff --git a/examples/ipsec-secgw/sp4.c b/examples/ipsec-secgw/sp4.c\nindex 9c4b256..d2c0849 100644\n--- a/examples/ipsec-secgw/sp4.c\n+++ b/examples/ipsec-secgw/sp4.c\n@@ -42,6 +42,7 @@\n #include <rte_ip.h>\n \n #include \"ipsec.h\"\n+#include \"parser.h\"\n \n #define MAX_ACL_RULE_NUM\t1000\n \n@@ -113,211 +114,306 @@ struct rte_acl_field_def ip4_defs[NUM_FIELDS_IPV4] = {\n \n RTE_ACL_RULE_DEF(acl4_rules, RTE_DIM(ip4_defs));\n \n-const struct acl4_rules acl4_rules_out[] = {\n-\t{\n-\t.data = {.userdata = PROTECT(5), .category_mask = 1, .priority = 1},\n-\t/* destination IPv4 */\n-\t.field[2] = {.value.u32 = IPv4(192, 168, 105, 0),\n-\t\t\t\t.mask_range.u32 = 24,},\n-\t/* source port */\n-\t.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},\n-\t/* destination port */\n-\t.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}\n-\t},\n-\t{\n-\t.data = {.userdata = PROTECT(6), .category_mask = 1, .priority = 1},\n-\t/* destination IPv4 */\n-\t.field[2] = {.value.u32 = IPv4(192, 168, 106, 0),\n-\t\t\t\t.mask_range.u32 = 24,},\n-\t/* source port */\n-\t.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},\n-\t/* destination port */\n-\t.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}\n-\t},\n-\t{\n-\t.data = {.userdata = PROTECT(10), .category_mask = 1, .priority = 1},\n-\t/* destination IPv4 */\n-\t.field[2] = {.value.u32 = IPv4(192, 168, 175, 0),\n-\t\t\t\t.mask_range.u32 = 24,},\n-\t/* source port */\n-\t.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},\n-\t/* destination port */\n-\t.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}\n-\t},\n-\t{\n-\t.data = {.userdata = PROTECT(11), .category_mask = 1, .priority = 1},\n-\t/* destination IPv4 */\n-\t.field[2] = {.value.u32 = IPv4(192, 168, 176, 0),\n-\t\t\t\t.mask_range.u32 = 24,},\n-\t/* source port */\n-\t.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},\n-\t/* destination port */\n-\t.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}\n-\t},\n-\t{\n-\t.data = {.userdata = PROTECT(15), .category_mask = 1, .priority = 1},\n-\t/* destination IPv4 */\n-\t.field[2] = {.value.u32 = IPv4(192, 168, 200, 0),\n-\t\t\t\t.mask_range.u32 = 24,},\n-\t/* source port */\n-\t.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},\n-\t/* destination port */\n-\t.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}\n-\t},\n-\t{\n-\t.data = {.userdata = PROTECT(16), .category_mask = 1, .priority = 1},\n-\t/* destination IPv4 */\n-\t.field[2] = {.value.u32 = IPv4(192, 168, 201, 0),\n-\t\t\t\t.mask_range.u32 = 24,},\n-\t/* source port */\n-\t.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},\n-\t/* destination port */\n-\t.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}\n-\t},\n-\t{\n-\t.data = {.userdata = PROTECT(25), .category_mask = 1, .priority = 1},\n-\t/* destination IPv4 */\n-\t.field[2] = {.value.u32 = IPv4(192, 168, 55, 0),\n-\t\t\t\t.mask_range.u32 = 24,},\n-\t/* source port */\n-\t.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},\n-\t/* destination port */\n-\t.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}\n-\t},\n-\t{\n-\t.data = {.userdata = PROTECT(26), .category_mask = 1, .priority = 1},\n-\t/* destination IPv4 */\n-\t.field[2] = {.value.u32 = IPv4(192, 168, 56, 0),\n-\t\t\t\t.mask_range.u32 = 24,},\n-\t/* source port */\n-\t.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},\n-\t/* destination port */\n-\t.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}\n-\t},\n-\t{\n-\t.data = {.userdata = BYPASS, .category_mask = 1, .priority = 1},\n-\t/* destination IPv4 */\n-\t.field[2] = {.value.u32 = IPv4(192, 168, 240, 0),\n-\t\t\t\t.mask_range.u32 = 24,},\n-\t/* source port */\n-\t.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},\n-\t/* destination port */\n-\t.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}\n-\t},\n-\t{\n-\t.data = {.userdata = BYPASS, .category_mask = 1, .priority = 1},\n-\t/* destination IPv4 */\n-\t.field[2] = {.value.u32 = IPv4(192, 168, 241, 0),\n-\t\t\t\t.mask_range.u32 = 24,},\n-\t/* source port */\n-\t.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},\n-\t/* destination port */\n-\t.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}\n+struct acl4_rules acl4_rules_out[MAX_ACL_RULE_NUM];\n+uint32_t nb_acl4_rules_out;\n+\n+struct acl4_rules acl4_rules_in[MAX_ACL_RULE_NUM];\n+uint32_t nb_acl4_rules_in;\n+\n+void\n+parse_sp4_tokens(char **tokens, uint32_t n_tokens,\n+\tstruct parse_status *status)\n+{\n+\tstruct acl4_rules *rule_ipv4 = NULL;\n+\n+\tuint32_t *ri = NULL; /* rule index */\n+\tuint32_t ti = 0; /* token index */\n+\n+\tuint32_t esp_p = 0;\n+\tuint32_t protect_p = 0;\n+\tuint32_t bypass_p = 0;\n+\tuint32_t discard_p = 0;\n+\tuint32_t pri_p = 0;\n+\tuint32_t src_p = 0;\n+\tuint32_t dst_p = 0;\n+\tuint32_t proto_p = 0;\n+\tuint32_t sport_p = 0;\n+\tuint32_t dport_p = 0;\n+\n+\tif (strcmp(tokens[1], \"in\") == 0) {\n+\t\tri = &nb_acl4_rules_in;\n+\n+\t\tAPP_CHECK(*ri <= MAX_ACL_RULE_NUM - 1, status,\n+\t\t\t\"too many sp rules, abort insertion\\n\");\n+\t\tif (status->status < 0)\n+\t\t\treturn;\n+\n+\t\trule_ipv4 = &acl4_rules_in[*ri];\n+\n+\t} else if (strcmp(tokens[1], \"out\") == 0) {\n+\t\tri = &nb_acl4_rules_out;\n+\n+\t\tAPP_CHECK(*ri <= MAX_ACL_RULE_NUM - 1, status,\n+\t\t\t\"too many sp rules, abort insertion\\n\");\n+\t\tif (status->status < 0)\n+\t\t\treturn;\n+\n+\t\trule_ipv4 = &acl4_rules_out[*ri];\n+\t} else {\n+\t\tAPP_CHECK(0, status, \"unrecognized input \\\"%s\\\", expect\"\n+\t\t\t\" \\\"in\\\" or \\\"out\\\"\\n\", tokens[ti]);\n+\t\treturn;\n \t}\n-};\n \n-const struct acl4_rules acl4_rules_in[] = {\n-\t{\n-\t.data = {.userdata = PROTECT(105), .category_mask = 1, .priority = 1},\n-\t/* destination IPv4 */\n-\t.field[2] = {.value.u32 = IPv4(192, 168, 115, 0),\n-\t\t\t\t.mask_range.u32 = 24,},\n-\t/* source port */\n-\t.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},\n-\t/* destination port */\n-\t.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}\n-\t},\n-\t{\n-\t.data = {.userdata = PROTECT(106), .category_mask = 1, .priority = 1},\n-\t/* destination IPv4 */\n-\t.field[2] = {.value.u32 = IPv4(192, 168, 116, 0),\n-\t\t\t\t.mask_range.u32 = 24,},\n-\t/* source port */\n-\t.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},\n-\t/* destination port */\n-\t.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}\n-\t},\n-\t{\n-\t.data = {.userdata = PROTECT(110), .category_mask = 1, .priority = 1},\n-\t/* destination IPv4 */\n-\t.field[2] = {.value.u32 = IPv4(192, 168, 185, 0),\n-\t\t\t\t.mask_range.u32 = 24,},\n-\t/* source port */\n-\t.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},\n-\t/* destination port */\n-\t.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}\n-\t},\n-\t{\n-\t.data = {.userdata = PROTECT(111), .category_mask = 1, .priority = 1},\n-\t/* destination IPv4 */\n-\t.field[2] = {.value.u32 = IPv4(192, 168, 186, 0),\n-\t\t\t\t.mask_range.u32 = 24,},\n-\t/* source port */\n-\t.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},\n-\t/* destination port */\n-\t.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}\n-\t},\n-\t{\n-\t.data = {.userdata = PROTECT(115), .category_mask = 1, .priority = 1},\n-\t/* destination IPv4 */\n-\t.field[2] = {.value.u32 = IPv4(192, 168, 210, 0),\n-\t\t\t\t.mask_range.u32 = 24,},\n-\t/* source port */\n-\t.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},\n-\t/* destination port */\n-\t.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}\n-\t},\n-\t{\n-\t.data = {.userdata = PROTECT(116), .category_mask = 1, .priority = 1},\n-\t/* destination IPv4 */\n-\t.field[2] = {.value.u32 = IPv4(192, 168, 211, 0),\n-\t\t\t\t.mask_range.u32 = 24,},\n-\t/* source port */\n-\t.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},\n-\t/* destination port */\n-\t.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}\n-\t},\n-\t{\n-\t.data = {.userdata = PROTECT(125), .category_mask = 1, .priority = 1},\n-\t/* destination IPv4 */\n-\t.field[2] = {.value.u32 = IPv4(192, 168, 65, 0),\n-\t\t\t\t.mask_range.u32 = 24,},\n-\t/* source port */\n-\t.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},\n-\t/* destination port */\n-\t.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}\n-\t},\n-\t{\n-\t.data = {.userdata = PROTECT(126), .category_mask = 1, .priority = 1},\n-\t/* destination IPv4 */\n-\t.field[2] = {.value.u32 = IPv4(192, 168, 66, 0),\n-\t\t\t\t.mask_range.u32 = 24,},\n-\t/* source port */\n-\t.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},\n-\t/* destination port */\n-\t.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}\n-\t},\n-\t{\n-\t.data = {.userdata = BYPASS, .category_mask = 1, .priority = 1},\n-\t/* destination IPv4 */\n-\t.field[2] = {.value.u32 = IPv4(192, 168, 245, 0),\n-\t\t\t\t.mask_range.u32 = 24,},\n-\t/* source port */\n-\t.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},\n-\t/* destination port */\n-\t.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}\n-\t},\n-\t{\n-\t.data = {.userdata = BYPASS, .category_mask = 1, .priority = 1},\n-\t/* destination IPv4 */\n-\t.field[2] = {.value.u32 = IPv4(192, 168, 246, 0),\n-\t\t\t\t.mask_range.u32 = 24,},\n-\t/* source port */\n-\t.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},\n-\t/* destination port */\n-\t.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}\n+\trule_ipv4->data.category_mask = 1;\n+\n+\tfor (ti = 2; ti < n_tokens; ti++) {\n+\t\tif (strcmp(tokens[ti], \"esp\") == 0) {\n+\t\t\t/* currently do nothing */\n+\t\t\tAPP_CHECK_PRESENCE(esp_p, tokens[ti], status);\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\t\t\tesp_p = 1;\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tif (strcmp(tokens[ti], \"protect\") == 0) {\n+\t\t\tAPP_CHECK_PRESENCE(protect_p, tokens[ti], status);\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\t\t\tAPP_CHECK(bypass_p == 0, status, \"conflict item \"\n+\t\t\t\t\"between \\\"%s\\\" and \\\"%s\\\"\", tokens[ti],\n+\t\t\t\t\"bypass\");\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\t\t\tAPP_CHECK(discard_p == 0, status, \"conflict item \"\n+\t\t\t\t\"between \\\"%s\\\" and \\\"%s\\\"\", tokens[ti],\n+\t\t\t\t\"discard\");\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\t\t\tINCREMENT_TOKEN_INDEX(ti, n_tokens, status);\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\t\t\tAPP_CHECK_TOKEN_IS_NUM(tokens, ti, status);\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\n+\t\t\trule_ipv4->data.userdata =\n+\t\t\t\tPROTECT(atoi(tokens[ti]));\n+\n+\t\t\tprotect_p = 1;\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tif (strcmp(tokens[ti], \"bypass\") == 0) {\n+\t\t\tAPP_CHECK_PRESENCE(bypass_p, tokens[ti], status);\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\t\t\tAPP_CHECK(protect_p == 0, status, \"conflict item \"\n+\t\t\t\t\"between \\\"%s\\\" and \\\"%s\\\"\", tokens[ti],\n+\t\t\t\t\"protect\");\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\t\t\tAPP_CHECK(discard_p == 0, status, \"conflict item \"\n+\t\t\t\t\"between \\\"%s\\\" and \\\"%s\\\"\", tokens[ti],\n+\t\t\t\t\"discard\");\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\n+\t\t\trule_ipv4->data.userdata = BYPASS;\n+\n+\t\t\tbypass_p = 1;\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tif (strcmp(tokens[ti], \"discard\") == 0) {\n+\t\t\tAPP_CHECK_PRESENCE(discard_p, tokens[ti], status);\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\t\t\tAPP_CHECK(protect_p == 0, status, \"conflict item \"\n+\t\t\t\t\"between \\\"%s\\\" and \\\"%s\\\"\", tokens[ti],\n+\t\t\t\t\"protect\");\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\t\t\tAPP_CHECK(bypass_p == 0, status, \"conflict item \"\n+\t\t\t\t\"between \\\"%s\\\" and \\\"%s\\\"\", tokens[ti],\n+\t\t\t\t\"discard\");\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\n+\t\t\trule_ipv4->data.userdata = DISCARD;\n+\n+\t\t\tdiscard_p = 1;\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tif (strcmp(tokens[ti], \"pri\") == 0) {\n+\t\t\tAPP_CHECK_PRESENCE(pri_p, tokens[ti], status);\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\t\t\tINCREMENT_TOKEN_INDEX(ti, n_tokens, status);\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\t\t\tAPP_CHECK_TOKEN_IS_NUM(tokens, ti, status);\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\n+\t\t\trule_ipv4->data.priority = atoi(tokens[ti]);\n+\n+\t\t\tpri_p = 1;\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tif (strcmp(tokens[ti], \"src\") == 0) {\n+\t\t\tstruct in_addr ip;\n+\t\t\tuint32_t depth;\n+\n+\t\t\tAPP_CHECK_PRESENCE(src_p, tokens[ti], status);\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\t\t\tINCREMENT_TOKEN_INDEX(ti, n_tokens, status);\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\n+\t\t\tAPP_CHECK(parse_ipv4_addr(tokens[ti], &ip,\n+\t\t\t\t&depth) == 0, status, \"unrecognized \"\n+\t\t\t\t\"input \\\"%s\\\", expect valid ipv4 addr\",\n+\t\t\t\ttokens[ti]);\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\n+\t\t\trule_ipv4->field[1].value.u32 =\n+\t\t\t\trte_bswap32(ip.s_addr);\n+\t\t\trule_ipv4->field[1].mask_range.u32 =\n+\t\t\t\tdepth;\n+\n+\t\t\tsrc_p = 1;\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tif (strcmp(tokens[ti], \"dst\") == 0) {\n+\t\t\tstruct in_addr ip;\n+\t\t\tuint32_t depth;\n+\n+\t\t\tAPP_CHECK_PRESENCE(dst_p, tokens[ti], status);\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\t\t\tINCREMENT_TOKEN_INDEX(ti, n_tokens, status);\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\t\t\tAPP_CHECK(parse_ipv4_addr(tokens[ti], &ip,\n+\t\t\t\t&depth) == 0, status, \"unrecognized \"\n+\t\t\t\t\"input \\\"%s\\\", expect valid ipv4 addr\",\n+\t\t\t\ttokens[ti]);\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\n+\t\t\trule_ipv4->field[2].value.u32 =\n+\t\t\t\trte_bswap32(ip.s_addr);\n+\t\t\trule_ipv4->field[2].mask_range.u32 =\n+\t\t\t\tdepth;\n+\n+\t\t\tdst_p = 1;\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tif (strcmp(tokens[ti], \"proto\") == 0) {\n+\t\t\tuint16_t low, high;\n+\n+\t\t\tAPP_CHECK_PRESENCE(proto_p, tokens[ti], status);\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\t\t\tINCREMENT_TOKEN_INDEX(ti, n_tokens, status);\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\n+\t\t\tAPP_CHECK(parse_range(tokens[ti], &low, &high)\n+\t\t\t\t== 0, status, \"unrecognized input \\\"%s\\\"\"\n+\t\t\t\t\", expect \\\"from:to\\\"\", tokens[ti]);\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\t\t\tAPP_CHECK(low <= 0xff, status, \"proto low \"\n+\t\t\t\t\"over-limit\");\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\t\t\tAPP_CHECK(high <= 0xff, status, \"proto high \"\n+\t\t\t\t\"over-limit\");\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\n+\t\t\trule_ipv4->field[0].value.u8 = (uint8_t)low;\n+\t\t\trule_ipv4->field[0].mask_range.u8 = (uint8_t)high;\n+\n+\t\t\tproto_p = 1;\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tif (strcmp(tokens[ti], \"sport\") == 0) {\n+\t\t\tuint16_t port_low, port_high;\n+\n+\t\t\tAPP_CHECK_PRESENCE(sport_p, tokens[ti], status);\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\t\t\tINCREMENT_TOKEN_INDEX(ti, n_tokens, status);\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\n+\t\t\tAPP_CHECK(parse_range(tokens[ti], &port_low,\n+\t\t\t\t&port_high) == 0, status, \"unrecognized \"\n+\t\t\t\t\"input \\\"%s\\\", expect \\\"port_from:\"\n+\t\t\t\t\"port_to\\\"\", tokens[ti]);\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\n+\t\t\trule_ipv4->field[3].value.u16 = port_low;\n+\t\t\trule_ipv4->field[3].mask_range.u16 = port_high;\n+\n+\t\t\tsport_p = 1;\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tif (strcmp(tokens[ti], \"dport\") == 0) {\n+\t\t\tuint16_t port_low, port_high;\n+\n+\t\t\tAPP_CHECK_PRESENCE(dport_p, tokens[ti], status);\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\t\t\tINCREMENT_TOKEN_INDEX(ti, n_tokens, status);\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\n+\t\t\tAPP_CHECK(parse_range(tokens[ti], &port_low,\n+\t\t\t\t&port_high) == 0, status, \"unrecognized \"\n+\t\t\t\t\"input \\\"%s\\\", expect \\\"port_from:\"\n+\t\t\t\t\"port_to\\\"\", tokens[ti]);\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\n+\t\t\trule_ipv4->field[4].value.u16 = port_low;\n+\t\t\trule_ipv4->field[4].mask_range.u16 = port_high;\n+\n+\t\t\tdport_p = 1;\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\t/* unrecognizeable input */\n+\t\tAPP_CHECK(0, status, \"unrecognized input \\\"%s\\\"\",\n+\t\t\ttokens[ti]);\n+\t\treturn;\n \t}\n-};\n+\n+\t/* check if argument(s) are missing */\n+\tAPP_CHECK(esp_p == 1, status, \"missing argument \\\"esp\\\"\");\n+\tif (status->status < 0)\n+\t\treturn;\n+\n+\tAPP_CHECK(protect_p | bypass_p | discard_p, status, \"missing \"\n+\t\t\"argument \\\"protect\\\", \\\"bypass\\\", or \\\"discard\\\"\");\n+\tif (status->status < 0)\n+\t\treturn;\n+\n+\t*ri = *ri + 1;\n+}\n \n static void\n print_one_ip4_rule(const struct acl4_rules *rule, int32_t extra)\n@@ -406,11 +502,9 @@ acl4_init(const char *name, int32_t socketid, const struct acl4_rules *rules,\n }\n \n void\n-sp4_init(struct socket_ctx *ctx, int32_t socket_id, uint32_t ep)\n+sp4_init(struct socket_ctx *ctx, int32_t socket_id)\n {\n \tconst char *name;\n-\tconst struct acl4_rules *rules_out, *rules_in;\n-\tuint32_t nb_out_rules, nb_in_rules;\n \n \tif (ctx == NULL)\n \t\trte_exit(EXIT_FAILURE, \"NULL context.\\n\");\n@@ -423,25 +517,18 @@ sp4_init(struct socket_ctx *ctx, int32_t socket_id, uint32_t ep)\n \t\trte_exit(EXIT_FAILURE, \"Outbound SP DB for socket %u already \"\n \t\t\t\t\"initialized\\n\", socket_id);\n \n-\tif (ep == 0) {\n-\t\trules_out = acl4_rules_out;\n-\t\tnb_out_rules = RTE_DIM(acl4_rules_out);\n-\t\trules_in = acl4_rules_in;\n-\t\tnb_in_rules = RTE_DIM(acl4_rules_in);\n-\t} else if (ep == 1) {\n-\t\trules_out = acl4_rules_in;\n-\t\tnb_out_rules = RTE_DIM(acl4_rules_in);\n-\t\trules_in = acl4_rules_out;\n-\t\tnb_in_rules = RTE_DIM(acl4_rules_out);\n-\t} else\n-\t\trte_exit(EXIT_FAILURE, \"Invalid EP value %u. \"\n-\t\t\t\t\"Only 0 or 1 supported.\\n\", ep);\n-\n-\tname = \"sp_ip4_in\";\n-\tctx->sp_ip4_in = (struct sp_ctx *)acl4_init(name, socket_id,\n-\t\t\trules_in, nb_in_rules);\n-\n-\tname = \"sp_ip4_out\";\n-\tctx->sp_ip4_out = (struct sp_ctx *)acl4_init(name, socket_id,\n-\t\t\trules_out, nb_out_rules);\n+\tif (nb_acl4_rules_out == 0 && nb_acl4_rules_in == 0)\n+\t\tRTE_LOG(WARNING, IPSEC, \"No IPv4 SP rule specified\\n\");\n+\n+\tif (nb_acl4_rules_in > 0) {\n+\t\tname = \"sp_ip4_in\";\n+\t\tctx->sp_ip4_in = (struct sp_ctx *)acl4_init(name,\n+\t\t\tsocket_id, acl4_rules_in, nb_acl4_rules_in);\n+\t}\n+\n+\tif (nb_acl4_rules_out > 0) {\n+\t\tname = \"sp_ip4_out\";\n+\t\tctx->sp_ip4_out = (struct sp_ctx *)acl4_init(name,\n+\t\t\tsocket_id, acl4_rules_out, nb_acl4_rules_out);\n+\t}\n }\ndiff --git a/examples/ipsec-secgw/sp6.c b/examples/ipsec-secgw/sp6.c\nindex 1dda11a..4360630 100644\n--- a/examples/ipsec-secgw/sp6.c\n+++ b/examples/ipsec-secgw/sp6.c\n@@ -42,6 +42,7 @@\n #include <rte_ip.h>\n \n #include \"ipsec.h\"\n+#include \"parser.h\"\n \n #define MAX_ACL_RULE_NUM\t1000\n \n@@ -144,155 +145,363 @@ struct rte_acl_field_def ip6_defs[IP6_NUM] = {\n \n RTE_ACL_RULE_DEF(acl6_rules, RTE_DIM(ip6_defs));\n \n-const struct acl6_rules acl6_rules_out[] = {\n-\t{\n-\t.data = {.userdata = PROTECT(5), .category_mask = 1, .priority = 1},\n-\t/* destination IPv6 */\n-\t.field[5] = {.value.u32 = 0x0, .mask_range.u32 = 32,},\n-\t.field[6] = {.value.u32 = 0x0, .mask_range.u32 = 32,},\n-\t.field[7] = {.value.u32 = 0x55555555, .mask_range.u32 = 32,},\n-\t.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},\n-\t/* source port */\n-\t.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},\n-\t/* destination port */\n-\t.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}\n-\t},\n-\t{\n-\t.data = {.userdata = PROTECT(6), .category_mask = 1, .priority = 1},\n-\t/* destination IPv6 */\n-\t.field[5] = {.value.u32 = 0x0, .mask_range.u32 = 32,},\n-\t.field[6] = {.value.u32 = 0x0, .mask_range.u32 = 32,},\n-\t.field[7] = {.value.u32 = 0x66666666, .mask_range.u32 = 32,},\n-\t.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},\n-\t/* source port */\n-\t.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},\n-\t/* destination port */\n-\t.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}\n-\t},\n-\t{\n-\t.data = {.userdata = PROTECT(10), .category_mask = 1, .priority = 1},\n-\t/* destination IPv6 */\n-\t.field[5] = {.value.u32 = 0x0, .mask_range.u32 = 32,},\n-\t.field[6] = {.value.u32 = 0x11111111, .mask_range.u32 = 32,},\n-\t.field[7] = {.value.u32 = 0x00000000, .mask_range.u32 = 32,},\n-\t.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},\n-\t/* source port */\n-\t.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},\n-\t/* destination port */\n-\t.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}\n-\t},\n-\t{\n-\t.data = {.userdata = PROTECT(11), .category_mask = 1, .priority = 1},\n-\t/* destination IPv6 */\n-\t.field[5] = {.value.u32 = 0x0, .mask_range.u32 = 32,},\n-\t.field[6] = {.value.u32 = 0x11111111, .mask_range.u32 = 32,},\n-\t.field[7] = {.value.u32 = 0x11111111, .mask_range.u32 = 32,},\n-\t.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},\n-\t/* source port */\n-\t.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},\n-\t/* destination port */\n-\t.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}\n-\t},\n-\t{\n-\t.data = {.userdata = PROTECT(25), .category_mask = 1, .priority = 1},\n-\t/* destination IPv6 */\n-\t.field[5] = {.value.u32 = 0x0, .mask_range.u32 = 32,},\n-\t.field[6] = {.value.u32 = 0x0, .mask_range.u32 = 32,},\n-\t.field[7] = {.value.u32 = 0xaaaaaaaa, .mask_range.u32 = 32,},\n-\t.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},\n-\t/* source port */\n-\t.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},\n-\t/* destination port */\n-\t.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}\n-\t},\n-\t{\n-\t.data = {.userdata = PROTECT(26), .category_mask = 1, .priority = 1},\n-\t/* destination IPv6 */\n-\t.field[5] = {.value.u32 = 0x0, .mask_range.u32 = 32,},\n-\t.field[6] = {.value.u32 = 0x0, .mask_range.u32 = 32,},\n-\t.field[7] = {.value.u32 = 0xbbbbbbbb, .mask_range.u32 = 32,},\n-\t.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},\n-\t/* source port */\n-\t.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},\n-\t/* destination port */\n-\t.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}\n+struct acl6_rules acl6_rules_out[MAX_ACL_RULE_NUM];\n+uint32_t nb_acl6_rules_out;\n+\n+struct acl6_rules acl6_rules_in[MAX_ACL_RULE_NUM];\n+uint32_t nb_acl6_rules_in;\n+\n+void\n+parse_sp6_tokens(char **tokens, uint32_t n_tokens,\n+\tstruct parse_status *status)\n+{\n+\tstruct acl6_rules *rule_ipv6 = NULL;\n+\n+\tuint32_t *ri = NULL; /* rule index */\n+\tuint32_t ti = 0; /* token index */\n+\n+\tuint32_t esp_p = 0;\n+\tuint32_t protect_p = 0;\n+\tuint32_t bypass_p = 0;\n+\tuint32_t discard_p = 0;\n+\tuint32_t pri_p = 0;\n+\tuint32_t src_p = 0;\n+\tuint32_t dst_p = 0;\n+\tuint32_t proto_p = 0;\n+\tuint32_t sport_p = 0;\n+\tuint32_t dport_p = 0;\n+\n+\tif (strcmp(tokens[1], \"in\") == 0) {\n+\t\tri = &nb_acl6_rules_in;\n+\n+\t\tAPP_CHECK(*ri <= MAX_ACL_RULE_NUM - 1, status, \"too \"\n+\t\t\t\"many sp rules, abort insertion\\n\");\n+\t\tif (status->status < 0)\n+\t\t\treturn;\n+\n+\t\trule_ipv6 = &acl6_rules_in[*ri];\n+\n+\t} else if (strcmp(tokens[1], \"out\") == 0) {\n+\t\tri = &nb_acl6_rules_out;\n+\n+\t\tAPP_CHECK(*ri <= MAX_ACL_RULE_NUM - 1, status, \"too \"\n+\t\t\t\"many sp rules, abort insertion\\n\");\n+\t\tif (status->status < 0)\n+\t\t\treturn;\n+\n+\t\trule_ipv6 = &acl6_rules_out[*ri];\n+\n+\t} else {\n+\t\tAPP_CHECK(0, status, \"unrecognized input \\\"%s\\\", expect\"\n+\t\t\t\" \\\"in\\\" or \\\"out\\\"\\n\", tokens[ti]);\n+\t\treturn;\n \t}\n-};\n \n-const struct acl6_rules acl6_rules_in[] = {\n-\t{\n-\t.data = {.userdata = PROTECT(15), .category_mask = 1, .priority = 1},\n-\t/* destination IPv6 */\n-\t.field[5] = {.value.u32 = 0xffff0000, .mask_range.u32 = 32,},\n-\t.field[6] = {.value.u32 = 0x0, .mask_range.u32 = 32,},\n-\t.field[7] = {.value.u32 = 0x55555555, .mask_range.u32 = 32,},\n-\t.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},\n-\t/* source port */\n-\t.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},\n-\t/* destination port */\n-\t.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}\n-\t},\n-\t{\n-\t.data = {.userdata = PROTECT(16), .category_mask = 1, .priority = 1},\n-\t/* destination IPv6 */\n-\t.field[5] = {.value.u32 = 0xffff0000, .mask_range.u32 = 32,},\n-\t.field[6] = {.value.u32 = 0x0, .mask_range.u32 = 32,},\n-\t.field[7] = {.value.u32 = 0x66666666, .mask_range.u32 = 32,},\n-\t.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},\n-\t/* source port */\n-\t.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},\n-\t/* destination port */\n-\t.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}\n-\t},\n-\t{\n-\t.data = {.userdata = PROTECT(110), .category_mask = 1, .priority = 1},\n-\t/* destination IPv6 */\n-\t.field[5] = {.value.u32 = 0xffff0000, .mask_range.u32 = 32,},\n-\t.field[6] = {.value.u32 = 0x11111111, .mask_range.u32 = 32,},\n-\t.field[7] = {.value.u32 = 0x00000000, .mask_range.u32 = 32,},\n-\t.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},\n-\t/* source port */\n-\t.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},\n-\t/* destination port */\n-\t.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}\n-\t},\n-\t{\n-\t.data = {.userdata = PROTECT(111), .category_mask = 1, .priority = 1},\n-\t/* destination IPv6 */\n-\t.field[5] = {.value.u32 = 0xffff0000, .mask_range.u32 = 32,},\n-\t.field[6] = {.value.u32 = 0x11111111, .mask_range.u32 = 32,},\n-\t.field[7] = {.value.u32 = 0x11111111, .mask_range.u32 = 32,},\n-\t.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},\n-\t/* source port */\n-\t.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},\n-\t/* destination port */\n-\t.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}\n-\t},\n-\t{\n-\t.data = {.userdata = PROTECT(125), .category_mask = 1, .priority = 1},\n-\t/* destination IPv6 */\n-\t.field[5] = {.value.u32 = 0xffff0000, .mask_range.u32 = 32,},\n-\t.field[6] = {.value.u32 = 0x0, .mask_range.u32 = 32,},\n-\t.field[7] = {.value.u32 = 0xaaaaaaaa, .mask_range.u32 = 32,},\n-\t.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},\n-\t/* source port */\n-\t.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},\n-\t/* destination port */\n-\t.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}\n-\t},\n-\t{\n-\t.data = {.userdata = PROTECT(126), .category_mask = 1, .priority = 1},\n-\t/* destination IPv6 */\n-\t.field[5] = {.value.u32 = 0xffff0000, .mask_range.u32 = 32,},\n-\t.field[6] = {.value.u32 = 0x0, .mask_range.u32 = 32,},\n-\t.field[7] = {.value.u32 = 0xbbbbbbbb, .mask_range.u32 = 32,},\n-\t.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},\n-\t/* source port */\n-\t.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},\n-\t/* destination port */\n-\t.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}\n+\trule_ipv6->data.category_mask = 1;\n+\n+\n+\tfor (ti = 2; ti < n_tokens; ti++) {\n+\t\tif (strcmp(tokens[ti], \"esp\") == 0) {\n+\t\t\t/* currently do nothing */\n+\t\t\tAPP_CHECK_PRESENCE(esp_p, tokens[ti], status);\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\t\t\tesp_p = 1;\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tif (strcmp(tokens[ti], \"protect\") == 0) {\n+\t\t\tAPP_CHECK_PRESENCE(protect_p, tokens[ti], status);\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\t\t\tAPP_CHECK(bypass_p == 0, status, \"conflict item \"\n+\t\t\t\t\"between \\\"%s\\\" and \\\"%s\\\"\", tokens[ti],\n+\t\t\t\t\"bypass\");\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\t\t\tAPP_CHECK(discard_p == 0, status, \"conflict item \"\n+\t\t\t\t\"between \\\"%s\\\" and \\\"%s\\\"\", tokens[ti],\n+\t\t\t\t\"discard\");\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\t\t\tINCREMENT_TOKEN_INDEX(ti, n_tokens, status);\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\t\t\tAPP_CHECK_TOKEN_IS_NUM(tokens, ti, status);\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\n+\t\t\trule_ipv6->data.userdata =\n+\t\t\t\tPROTECT(atoi(tokens[ti]));\n+\n+\t\t\tprotect_p = 1;\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tif (strcmp(tokens[ti], \"bypass\") == 0) {\n+\t\t\tAPP_CHECK_PRESENCE(bypass_p, tokens[ti], status);\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\t\t\tAPP_CHECK(protect_p == 0, status, \"conflict item \"\n+\t\t\t\t\"between \\\"%s\\\" and \\\"%s\\\"\", tokens[ti],\n+\t\t\t\t\"protect\");\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\t\t\tAPP_CHECK(discard_p == 0, status, \"conflict item \"\n+\t\t\t\t\"between \\\"%s\\\" and \\\"%s\\\"\", tokens[ti],\n+\t\t\t\t\"discard\");\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\n+\t\t\trule_ipv6->data.userdata = BYPASS;\n+\n+\t\t\tbypass_p = 1;\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tif (strcmp(tokens[ti], \"discard\") == 0) {\n+\t\t\tAPP_CHECK_PRESENCE(discard_p, tokens[ti], status);\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\t\t\tAPP_CHECK(protect_p == 0, status, \"conflict item \"\n+\t\t\t\t\"between \\\"%s\\\" and \\\"%s\\\"\", tokens[ti],\n+\t\t\t\t\"protect\");\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\t\t\tAPP_CHECK(bypass_p == 0, status, \"conflict item \"\n+\t\t\t\t\"between \\\"%s\\\" and \\\"%s\\\"\", tokens[ti],\n+\t\t\t\t\"discard\");\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\n+\t\t\trule_ipv6->data.userdata = DISCARD;\n+\n+\t\t\tdiscard_p = 1;\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tif (strcmp(tokens[ti], \"pri\") == 0) {\n+\t\t\tAPP_CHECK_PRESENCE(pri_p, tokens[ti], status);\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\t\t\tINCREMENT_TOKEN_INDEX(ti, n_tokens, status);\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\t\t\tAPP_CHECK_TOKEN_IS_NUM(tokens, ti, status);\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\n+\t\t\trule_ipv6->data.priority = atoi(tokens[ti]);\n+\n+\t\t\tpri_p = 1;\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tif (strcmp(tokens[ti], \"src\") == 0) {\n+\t\t\tstruct in6_addr ip;\n+\t\t\tuint32_t depth;\n+\n+\t\t\tAPP_CHECK_PRESENCE(src_p, tokens[ti], status);\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\t\t\tINCREMENT_TOKEN_INDEX(ti, n_tokens, status);\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\n+\t\t\tAPP_CHECK(parse_ipv6_addr(tokens[ti], &ip,\n+\t\t\t\t&depth) == 0, status, \"unrecognized \"\n+\t\t\t\t\"input \\\"%s\\\", expect valid ipv6 \"\n+\t\t\t\t\"addr\", tokens[ti]);\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\n+\t\t\trule_ipv6->field[1].value.u32 =\n+\t\t\t\t(uint32_t)ip.s6_addr[0] << 24 |\n+\t\t\t\t(uint32_t)ip.s6_addr[1] << 16 |\n+\t\t\t\t(uint32_t)ip.s6_addr[2] << 8 |\n+\t\t\t\t(uint32_t)ip.s6_addr[3];\n+\t\t\trule_ipv6->field[1].mask_range.u32 =\n+\t\t\t\t(depth > 32) ? 32 : depth;\n+\t\t\tdepth = (depth > 32) ? (depth - 32) : 0;\n+\t\t\trule_ipv6->field[2].value.u32 =\n+\t\t\t\t(uint32_t)ip.s6_addr[4] << 24 |\n+\t\t\t\t(uint32_t)ip.s6_addr[5] << 16 |\n+\t\t\t\t(uint32_t)ip.s6_addr[6] << 8 |\n+\t\t\t\t(uint32_t)ip.s6_addr[7];\n+\t\t\trule_ipv6->field[2].mask_range.u32 =\n+\t\t\t\t(depth > 32) ? 32 : depth;\n+\t\t\tdepth = (depth > 32) ? (depth - 32) : 0;\n+\t\t\trule_ipv6->field[3].value.u32 =\n+\t\t\t\t(uint32_t)ip.s6_addr[8] << 24 |\n+\t\t\t\t(uint32_t)ip.s6_addr[9] << 16 |\n+\t\t\t\t(uint32_t)ip.s6_addr[10] << 8 |\n+\t\t\t\t(uint32_t)ip.s6_addr[11];\n+\t\t\trule_ipv6->field[3].mask_range.u32 =\n+\t\t\t\t(depth > 32) ? 32 : depth;\n+\t\t\tdepth = (depth > 32) ? (depth - 32) : 0;\n+\t\t\trule_ipv6->field[4].value.u32 =\n+\t\t\t\t(uint32_t)ip.s6_addr[12] << 24 |\n+\t\t\t\t(uint32_t)ip.s6_addr[13] << 16 |\n+\t\t\t\t(uint32_t)ip.s6_addr[14] << 8 |\n+\t\t\t\t(uint32_t)ip.s6_addr[15];\n+\t\t\trule_ipv6->field[4].mask_range.u32 =\n+\t\t\t\t(depth > 32) ? 32 : depth;\n+\n+\t\t\tsrc_p = 1;\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tif (strcmp(tokens[ti], \"dst\") == 0) {\n+\t\t\tstruct in6_addr ip;\n+\t\t\tuint32_t depth;\n+\n+\t\t\tAPP_CHECK_PRESENCE(dst_p, tokens[ti], status);\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\t\t\tINCREMENT_TOKEN_INDEX(ti, n_tokens, status);\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\n+\t\t\tAPP_CHECK(parse_ipv6_addr(tokens[ti], &ip,\n+\t\t\t\t&depth) == 0, status, \"unrecognized \"\n+\t\t\t\t\"input \\\"%s\\\", expect valid ipv6 \"\n+\t\t\t\t\"addr\", tokens[ti]);\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\n+\t\t\trule_ipv6->field[5].value.u32 =\n+\t\t\t\t(uint32_t)ip.s6_addr[0] << 24 |\n+\t\t\t\t(uint32_t)ip.s6_addr[1] << 16 |\n+\t\t\t\t(uint32_t)ip.s6_addr[2] << 8 |\n+\t\t\t\t(uint32_t)ip.s6_addr[3];\n+\t\t\trule_ipv6->field[5].mask_range.u32 =\n+\t\t\t\t(depth > 32) ? 32 : depth;\n+\t\t\tdepth = (depth > 32) ? (depth - 32) : 0;\n+\t\t\trule_ipv6->field[6].value.u32 =\n+\t\t\t\t(uint32_t)ip.s6_addr[4] << 24 |\n+\t\t\t\t(uint32_t)ip.s6_addr[5] << 16 |\n+\t\t\t\t(uint32_t)ip.s6_addr[6] << 8 |\n+\t\t\t\t(uint32_t)ip.s6_addr[7];\n+\t\t\trule_ipv6->field[6].mask_range.u32 =\n+\t\t\t\t(depth > 32) ? 32 : depth;\n+\t\t\tdepth = (depth > 32) ? (depth - 32) : 0;\n+\t\t\trule_ipv6->field[7].value.u32 =\n+\t\t\t\t(uint32_t)ip.s6_addr[8] << 24 |\n+\t\t\t\t(uint32_t)ip.s6_addr[9] << 16 |\n+\t\t\t\t(uint32_t)ip.s6_addr[10] << 8 |\n+\t\t\t\t(uint32_t)ip.s6_addr[11];\n+\t\t\trule_ipv6->field[7].mask_range.u32 =\n+\t\t\t\t(depth > 32) ? 32 : depth;\n+\t\t\tdepth = (depth > 32) ? (depth - 32) : 0;\n+\t\t\trule_ipv6->field[8].value.u32 =\n+\t\t\t\t(uint32_t)ip.s6_addr[12] << 24 |\n+\t\t\t\t(uint32_t)ip.s6_addr[13] << 16 |\n+\t\t\t\t(uint32_t)ip.s6_addr[14] << 8 |\n+\t\t\t\t(uint32_t)ip.s6_addr[15];\n+\t\t\trule_ipv6->field[8].mask_range.u32 =\n+\t\t\t\t(depth > 32) ? 32 : depth;\n+\n+\t\t\tdst_p = 1;\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tif (strcmp(tokens[ti], \"proto\") == 0) {\n+\t\t\tuint16_t low, high;\n+\n+\t\t\tAPP_CHECK_PRESENCE(proto_p, tokens[ti], status);\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\t\t\tINCREMENT_TOKEN_INDEX(ti, n_tokens, status);\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\n+\t\t\tAPP_CHECK(parse_range(tokens[ti], &low, &high)\n+\t\t\t\t== 0, status, \"unrecognized input \\\"%s\\\"\"\n+\t\t\t\t\", expect \\\"from:to\\\"\", tokens[ti]);\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\t\t\tAPP_CHECK(low <= 0xff, status, \"proto low \"\n+\t\t\t\t\"over-limit\");\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\t\t\tAPP_CHECK(high <= 0xff, status, \"proto high \"\n+\t\t\t\t\"over-limit\");\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\n+\t\t\trule_ipv6->field[0].value.u8 = (uint8_t)low;\n+\t\t\trule_ipv6->field[0].mask_range.u8 = (uint8_t)high;\n+\n+\t\t\tproto_p = 1;\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tif (strcmp(tokens[ti], \"sport\") == 0) {\n+\t\t\tuint16_t port_low, port_high;\n+\n+\t\t\tAPP_CHECK_PRESENCE(sport_p, tokens[ti], status);\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\t\t\tINCREMENT_TOKEN_INDEX(ti, n_tokens, status);\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\n+\t\t\tAPP_CHECK(parse_range(tokens[ti], &port_low,\n+\t\t\t\t&port_high) == 0, status, \"unrecognized \"\n+\t\t\t\t\"input \\\"%s\\\", expect \\\"port_from:\"\n+\t\t\t\t\"port_to\\\"\", tokens[ti]);\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\n+\t\t\trule_ipv6->field[9].value.u16 = port_low;\n+\t\t\trule_ipv6->field[9].mask_range.u16 = port_high;\n+\n+\t\t\tsport_p = 1;\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tif (strcmp(tokens[ti], \"dport\") == 0) {\n+\t\t\tuint16_t port_low, port_high;\n+\n+\t\t\tAPP_CHECK_PRESENCE(dport_p, tokens[ti], status);\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\t\t\tINCREMENT_TOKEN_INDEX(ti, n_tokens, status);\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\n+\t\t\tAPP_CHECK(parse_range(tokens[ti], &port_low,\n+\t\t\t\t&port_high) == 0, status, \"unrecognized \"\n+\t\t\t\t\"input \\\"%s\\\", expect \\\"port_from:\"\n+\t\t\t\t\"port_to\\\"\", tokens[ti]);\n+\t\t\tif (status->status < 0)\n+\t\t\t\treturn;\n+\n+\t\t\trule_ipv6->field[10].value.u16 = port_low;\n+\t\t\trule_ipv6->field[10].mask_range.u16 = port_high;\n+\n+\t\t\tdport_p = 1;\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\t/* unrecognizeable input */\n+\t\tAPP_CHECK(0, status, \"unrecognized input \\\"%s\\\"\",\n+\t\t\ttokens[ti]);\n+\t\treturn;\n \t}\n-};\n+\n+\t/* check if argument(s) are missing */\n+\tAPP_CHECK(esp_p == 1, status, \"missing argument \\\"esp\\\"\");\n+\tif (status->status < 0)\n+\t\treturn;\n+\n+\tAPP_CHECK(protect_p | bypass_p | discard_p, status, \"missing \"\n+\t\t\"argument \\\"protect\\\", \\\"bypass\\\", or \\\"discard\\\"\");\n+\tif (status->status < 0)\n+\t\treturn;\n+\n+\t*ri = *ri + 1;\n+}\n \n static inline void\n print_one_ip6_rule(const struct acl6_rules *rule, int32_t extra)\n@@ -407,11 +616,9 @@ acl6_init(const char *name, int32_t socketid, const struct acl6_rules *rules,\n }\n \n void\n-sp6_init(struct socket_ctx *ctx, int32_t socket_id, uint32_t ep)\n+sp6_init(struct socket_ctx *ctx, int32_t socket_id)\n {\n \tconst char *name;\n-\tconst struct acl6_rules *rules_out, *rules_in;\n-\tuint32_t nb_out_rules, nb_in_rules;\n \n \tif (ctx == NULL)\n \t\trte_exit(EXIT_FAILURE, \"NULL context.\\n\");\n@@ -424,25 +631,18 @@ sp6_init(struct socket_ctx *ctx, int32_t socket_id, uint32_t ep)\n \t\trte_exit(EXIT_FAILURE, \"Outbound IPv6 SP DB for socket %u \"\n \t\t\t\t\"already initialized\\n\", socket_id);\n \n-\tif (ep == 0) {\n-\t\trules_out = acl6_rules_out;\n-\t\tnb_out_rules = RTE_DIM(acl6_rules_out);\n-\t\trules_in = acl6_rules_in;\n-\t\tnb_in_rules = RTE_DIM(acl6_rules_in);\n-\t} else if (ep == 1) {\n-\t\trules_out = acl6_rules_in;\n-\t\tnb_out_rules = RTE_DIM(acl6_rules_in);\n-\t\trules_in = acl6_rules_out;\n-\t\tnb_in_rules = RTE_DIM(acl6_rules_out);\n-\t} else\n-\t\trte_exit(EXIT_FAILURE, \"Invalid EP value %u. \"\n-\t\t\t\t\"Only 0 or 1 supported.\\n\", ep);\n-\n-\tname = \"sp_ip6_in\";\n-\tctx->sp_ip6_in = (struct sp_ctx *)acl6_init(name, socket_id,\n-\t\t\trules_in, nb_in_rules);\n-\n-\tname = \"sp_ip6_out\";\n-\tctx->sp_ip6_out = (struct sp_ctx *)acl6_init(name, socket_id,\n-\t\t\trules_out, nb_out_rules);\n+\tif (nb_acl6_rules_out == 0 && nb_acl6_rules_in == 0)\n+\t\tRTE_LOG(WARNING, IPSEC, \"No IPv6 SP rule specified\\n\");\n+\n+\tif (nb_acl6_rules_in > 0) {\n+\t\tname = \"sp_ip6_in\";\n+\t\tctx->sp_ip6_in = (struct sp_ctx *)acl6_init(name,\n+\t\t\tsocket_id, acl6_rules_in, nb_acl6_rules_in);\n+\t}\n+\n+\tif (nb_acl6_rules_out > 0) {\n+\t\tname = \"sp_ip6_out\";\n+\t\tctx->sp_ip6_out = (struct sp_ctx *)acl6_init(name,\n+\t\t\tsocket_id, acl6_rules_out, nb_acl6_rules_out);\n+\t}\n }\n",
    "prefixes": [
        "dpdk-dev",
        "v3",
        "1/2"
    ]
}