get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 7329,
    "url": "https://patches.dpdk.org/api/patches/7329/?format=api",
    "web_url": "https://patches.dpdk.org/project/dpdk/patch/1443626450-27607-1-git-send-email-jasvinder.singh@intel.com/",
    "project": {
        "id": 1,
        "url": "https://patches.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<1443626450-27607-1-git-send-email-jasvinder.singh@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1443626450-27607-1-git-send-email-jasvinder.singh@intel.com",
    "date": "2015-09-30T15:20:50",
    "name": "[dpdk-dev] ip_pipeline: add more functions to routing-pipeline",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "425b224e76f634f3e432c52b06b5f159606be3af",
    "submitter": {
        "id": 285,
        "url": "https://patches.dpdk.org/api/people/285/?format=api",
        "name": "Jasvinder Singh",
        "email": "jasvinder.singh@intel.com"
    },
    "delegate": null,
    "mbox": "https://patches.dpdk.org/project/dpdk/patch/1443626450-27607-1-git-send-email-jasvinder.singh@intel.com/mbox/",
    "series": [],
    "comments": "https://patches.dpdk.org/api/patches/7329/comments/",
    "check": "pending",
    "checks": "https://patches.dpdk.org/api/patches/7329/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 F2D688DA4;\n\tWed, 30 Sep 2015 17:21:06 +0200 (CEST)",
            "from mga11.intel.com (mga11.intel.com [192.55.52.93])\n\tby dpdk.org (Postfix) with ESMTP id 904D68D9E\n\tfor <dev@dpdk.org>; Wed, 30 Sep 2015 17:21:03 +0200 (CEST)",
            "from orsmga003.jf.intel.com ([10.7.209.27])\n\tby fmsmga102.fm.intel.com with ESMTP; 30 Sep 2015 08:20:52 -0700",
            "from irvmail001.ir.intel.com ([163.33.26.43])\n\tby orsmga003.jf.intel.com with ESMTP; 30 Sep 2015 08:20:51 -0700",
            "from sivswdev02.ir.intel.com (sivswdev02.ir.intel.com\n\t[10.237.217.46])\n\tby irvmail001.ir.intel.com (8.14.3/8.13.6/MailSET/Hub) with ESMTP id\n\tt8UFKohA025590; Wed, 30 Sep 2015 16:20:50 +0100",
            "from sivswdev02.ir.intel.com (localhost [127.0.0.1])\n\tby sivswdev02.ir.intel.com with ESMTP id t8UFKovr027641;\n\tWed, 30 Sep 2015 16:20:50 +0100",
            "(from jasvinde@localhost)\n\tby sivswdev02.ir.intel.com with  id t8UFKoqQ027637;\n\tWed, 30 Sep 2015 16:20:50 +0100"
        ],
        "X-ExtLoop1": "1",
        "X-IronPort-AV": "E=Sophos;i=\"5.17,612,1437462000\"; d=\"scan'208\";a=\"655162329\"",
        "From": "Jasvinder Singh <jasvinder.singh@intel.com>",
        "To": "dev@dpdk.org",
        "Date": "Wed, 30 Sep 2015 16:20:50 +0100",
        "Message-Id": "<1443626450-27607-1-git-send-email-jasvinder.singh@intel.com>",
        "X-Mailer": "git-send-email 1.7.4.1",
        "Subject": "[dpdk-dev] [PATCH] ip_pipeline: add more functions to\n\trouting-pipeline",
        "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 following features to the\nrouting-pipeline to enable it for various NFV\nuse-cases;\n\n1.Fast-path ARP table enable/disable\n2.Double-tagged VLAN (Q-in-Q) packet enacapsulation\nfor the next-hop\n3.MPLS encapsulation for the next-hop\n4.Add colour (Traffic-class for QoS) to the MPLS tag\n5.Classification action to select the input queue\nof the hierarchical scehdular (QoS)\n\nThe above proposed features can be enabled\n(or disabled) through the parameters specified\nin configuration file as below;\n\n[PIPELINE0]\ntype = ROUTING\ncore = 1\npktq_in = RXQ0.0 RXQ1.0 RXQ2.0 RXQ3.0\npktq_out = TXQ0.0 TXQ1.0 TXQ2.0 TXQ3.0\nn_routes = 4096\nn_arp_entries = 1024\nip_hdr_offset = 142\narp_key_offset = 64\nl2 = qinq\nqinq_sched = no\n\nThe LPM table entries might include additional\nfields depending upon the packet encapsulation\n(Q-in-Q, MPLS)for the next-hop. Therefore, the\nCLI commands for adding or deleting such entries\nto LPM table have been implemented. The key\nfunctions such as QinQ and MPLS encapsulation,\nclassification action to select the input queue\nof the hierarchical schedular(QoS) and adding\ncolour (Traffic-class for QoS) to the MPLS\ntag have been implemented as action handlers.\n\nSigned-off-by: Jasvinder Singh <jasvinder.singh@intel.com>\n---\n examples/ip_pipeline/pipeline/pipeline_routing.c   |  795 ++++++++++-\n examples/ip_pipeline/pipeline/pipeline_routing.h   |    8 +-\n .../ip_pipeline/pipeline/pipeline_routing_be.c     | 1393 ++++++++++++++++++--\n .../ip_pipeline/pipeline/pipeline_routing_be.h     |   62 +-\n 4 files changed, 2074 insertions(+), 184 deletions(-)",
    "diff": "diff --git a/examples/ip_pipeline/pipeline/pipeline_routing.c b/examples/ip_pipeline/pipeline/pipeline_routing.c\nindex beec982..8ba1e25 100644\n--- a/examples/ip_pipeline/pipeline/pipeline_routing.c\n+++ b/examples/ip_pipeline/pipeline/pipeline_routing.c\n@@ -43,7 +43,7 @@\n \n struct app_pipeline_routing_route {\n \tstruct pipeline_routing_route_key key;\n-\tstruct app_pipeline_routing_route_params params;\n+\tstruct pipeline_routing_route_data data;\n \tvoid *entry_ptr;\n \n \tTAILQ_ENTRY(app_pipeline_routing_route) node;\n@@ -196,12 +196,44 @@ print_route(const struct app_pipeline_routing_route *route)\n \t\t\tkey->ip & 0xFF,\n \n \t\t\tkey->depth,\n-\t\t\troute->params.port_id,\n+\t\t\troute->data.port_id);\n+\n+\t\tif (route->data.flags & PIPELINE_ROUTING_ROUTE_ARP)\n+\t\t\tprintf(\n+\t\t\t\t\", Next Hop IP = %\" PRIu32 \".%\" PRIu32\n+\t\t\t\t\".%\" PRIu32 \".%\" PRIu32,\n+\t\t\t\t(route->data.ethernet.ip >> 24) & 0xFF,\n+\t\t\t\t(route->data.ethernet.ip >> 16) & 0xFF,\n+\t\t\t\t(route->data.ethernet.ip >> 8) & 0xFF,\n+\t\t\t\troute->data.ethernet.ip & 0xFF);\n+\t\telse\n+\t\t\tprintf(\n+\t\t\t\t\", Next Hop HWaddress = %02\" PRIx32\n+\t\t\t\t\":%02\" PRIx32 \":%02\" PRIx32\n+\t\t\t\t\":%02\" PRIx32 \":%02\" PRIx32\n+\t\t\t\t\":%02\" PRIx32,\n+\t\t\t\troute->data.ethernet.macaddr.addr_bytes[0],\n+\t\t\t\troute->data.ethernet.macaddr.addr_bytes[1],\n+\t\t\t\troute->data.ethernet.macaddr.addr_bytes[2],\n+\t\t\t\troute->data.ethernet.macaddr.addr_bytes[3],\n+\t\t\t\troute->data.ethernet.macaddr.addr_bytes[4],\n+\t\t\t\troute->data.ethernet.macaddr.addr_bytes[5]);\n+\n+\t\tif (route->data.flags & PIPELINE_ROUTING_ROUTE_QINQ)\n+\t\t\tprintf(\", QinQ SVLAN = %\" PRIu32 \" CVLAN = %\" PRIu32,\n+\t\t\t\troute->data.l2.qinq.svlan,\n+\t\t\t\troute->data.l2.qinq.cvlan);\n+\n+\t\tif (route->data.flags & PIPELINE_ROUTING_ROUTE_MPLS) {\n+\t\t\tuint32_t i;\n+\n+\t\t\tprintf(\", MPLS labels\");\n+\t\t\tfor (i = 0; i < route->data.l2.mpls.n_labels; i++)\n+\t\t\t\tprintf(\" %\" PRIu32,\n+\t\t\t\t\troute->data.l2.mpls.labels[i]);\n+\t\t}\n \n-\t\t\t(route->params.ip >> 24) & 0xFF,\n-\t\t\t(route->params.ip >> 16) & 0xFF,\n-\t\t\t(route->params.ip >> 8) & 0xFF,\n-\t\t\troute->params.ip & 0xFF);\n+\t\tprintf(\")\\n\");\n \t}\n }\n \n@@ -212,6 +244,8 @@ print_arp_entry(const struct app_pipeline_routing_arp_entry *entry)\n \t\t\".%\" PRIu32 \".%\" PRIu32 \") => \"\n \t\t\"HWaddress = %02\" PRIx32 \":%02\" PRIx32 \":%02\" PRIx32\n \t\t\":%02\" PRIx32 \":%02\" PRIx32 \":%02\" PRIx32 \"\\n\",\n+\n+\n \t\tentry->key.key.ipv4.port_id,\n \t\t(entry->key.key.ipv4.ip >> 24) & 0xFF,\n \t\t(entry->key.key.ipv4.ip >> 16) & 0xFF,\n@@ -253,7 +287,7 @@ int\n app_pipeline_routing_add_route(struct app_params *app,\n \tuint32_t pipeline_id,\n \tstruct pipeline_routing_route_key *key,\n-\tstruct app_pipeline_routing_route_params *route_params)\n+\tstruct pipeline_routing_route_data *data)\n {\n \tstruct pipeline_routing *p;\n \n@@ -267,7 +301,7 @@ app_pipeline_routing_add_route(struct app_params *app,\n \t/* Check input arguments */\n \tif ((app == NULL) ||\n \t\t(key == NULL) ||\n-\t\t(route_params == NULL))\n+\t\t(data == NULL))\n \t\treturn -1;\n \n \tp = app_pipeline_data_fe(app, pipeline_id);\n@@ -287,8 +321,8 @@ app_pipeline_routing_add_route(struct app_params *app,\n \t\tnetmask = (~0) << (32 - depth);\n \t\tkey->key.ipv4.ip &= netmask;\n \n-\t\t/* route params */\n-\t\tif (route_params->port_id >= p->n_ports_out)\n+\t\t/* data */\n+\t\tif (data->port_id >= p->n_ports_out)\n \t\t\treturn -1;\n \t}\n \tbreak;\n@@ -318,9 +352,7 @@ app_pipeline_routing_add_route(struct app_params *app,\n \treq->type = PIPELINE_MSG_REQ_CUSTOM;\n \treq->subtype = PIPELINE_ROUTING_MSG_REQ_ROUTE_ADD;\n \tmemcpy(&req->key, key, sizeof(*key));\n-\treq->flags = route_params->flags;\n-\treq->port_id = route_params->port_id;\n-\treq->ip = route_params->ip;\n+\tmemcpy(&req->data, data, sizeof(*data));\n \n \trsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);\n \tif (rsp == NULL) {\n@@ -341,7 +373,7 @@ app_pipeline_routing_add_route(struct app_params *app,\n \t}\n \n \tmemcpy(&entry->key, key, sizeof(*key));\n-\tmemcpy(&entry->params, route_params, sizeof(*route_params));\n+\tmemcpy(&entry->data, data, sizeof(*data));\n \tentry->entry_ptr = rsp->entry_ptr;\n \n \t/* Commit entry */\n@@ -820,31 +852,174 @@ app_pipeline_routing_delete_default_arp_entry(struct app_params *app,\n \treturn 0;\n }\n \n+static int\n+parse_labels(char *string, uint32_t *labels, uint32_t *n_labels)\n+{\n+\tuint32_t n_max_labels = *n_labels, count = 0;\n+\n+\t/* Check for void list of labels */\n+\tif (strcmp(string, \"<void>\") == 0) {\n+\t\t*n_labels = 0;\n+\t\treturn 0;\n+\t}\n+\n+\t/* At least one label should be present */\n+\tfor ( ; (*string != '\\0'); ) {\n+\t\tchar *next;\n+\t\tint value;\n+\n+\t\tif (count >= n_max_labels)\n+\t\t\treturn -1;\n+\n+\t\tif (count > 0) {\n+\t\t\tif (string[0] != ':')\n+\t\t\t\treturn -1;\n+\n+\t\t\tstring++;\n+\t\t}\n+\n+\t\tvalue = strtol(string, &next, 10);\n+\t\tif (next == string)\n+\t\t\treturn -1;\n+\t\tstring = next;\n+\n+\t\tlabels[count++] = (uint32_t) value;\n+\t}\n+\n+\t*n_labels = count;\n+\treturn 0;\n+}\n+\n+/*\n+ * route add (mpls = no, qinq = no, arp = no)\n+ */\n+\n+struct cmd_route_add1_result {\n+\tcmdline_fixed_string_t p_string;\n+\tuint32_t p;\n+\tcmdline_fixed_string_t route_string;\n+\tcmdline_fixed_string_t add_string;\n+\tcmdline_ipaddr_t ip;\n+\tuint32_t depth;\n+\tcmdline_fixed_string_t port_string;\n+\tuint32_t port;\n+\tcmdline_fixed_string_t ether_string;\n+\tstruct ether_addr macaddr;\n+};\n+\n+static void\n+cmd_route_add1_parsed(\n+\tvoid *parsed_result,\n+\t__rte_unused struct cmdline *cl,\n+\tvoid *data)\n+{\n+\tstruct cmd_route_add1_result *params = parsed_result;\n+\tstruct app_params *app = data;\n+\tstruct pipeline_routing_route_key key;\n+\tstruct pipeline_routing_route_data route_data;\n+\tint status;\n+\n+\t/* Create route */\n+\tkey.type = PIPELINE_ROUTING_ROUTE_IPV4;\n+\tkey.key.ipv4.ip = rte_bswap32((uint32_t) params->ip.addr.ipv4.s_addr);\n+\tkey.key.ipv4.depth = params->depth;\n+\n+\troute_data.flags = 0;\n+\troute_data.port_id = params->port;\n+\troute_data.ethernet.macaddr = params->macaddr;\n+\n+\tstatus = app_pipeline_routing_add_route(app,\n+\t\tparams->p,\n+\t\t&key,\n+\t\t&route_data);\n+\n+\tif (status != 0) {\n+\t\tprintf(\"Command failed\\n\");\n+\t\treturn;\n+\t}\n+}\n+\n+static cmdline_parse_token_string_t cmd_route_add1_p_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_route_add1_result, p_string,\n+\t\"p\");\n+\n+static cmdline_parse_token_num_t cmd_route_add1_p =\n+\tTOKEN_NUM_INITIALIZER(struct cmd_route_add1_result, p, UINT32);\n+\n+static cmdline_parse_token_string_t cmd_route_add1_route_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_route_add1_result, route_string,\n+\t\"route\");\n+\n+static cmdline_parse_token_string_t cmd_route_add1_add_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_route_add1_result, add_string,\n+\t\"add\");\n+\n+static cmdline_parse_token_ipaddr_t cmd_route_add1_ip =\n+\tTOKEN_IPV4_INITIALIZER(struct cmd_route_add1_result, ip);\n+\n+static cmdline_parse_token_num_t cmd_route_add1_depth =\n+\tTOKEN_NUM_INITIALIZER(struct cmd_route_add1_result, depth, UINT32);\n+\n+static cmdline_parse_token_string_t cmd_route_add1_port_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_route_add1_result, port_string,\n+\t\"port\");\n+\n+static cmdline_parse_token_num_t cmd_route_add1_port =\n+\tTOKEN_NUM_INITIALIZER(struct cmd_route_add1_result, port, UINT32);\n+\n+static cmdline_parse_token_string_t cmd_route_add1_ether_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_route_add1_result, ether_string,\n+\t\"ether\");\n+\n+static cmdline_parse_token_etheraddr_t cmd_route_add1_macaddr =\n+\tTOKEN_ETHERADDR_INITIALIZER(struct cmd_route_add1_result, macaddr);\n+\n+static cmdline_parse_inst_t cmd_route_add1 = {\n+\t.f = cmd_route_add1_parsed,\n+\t.data = NULL,\n+\t.help_str = \"Route add (mpls = no, qinq = no, arp = no)\",\n+\t.tokens = {\n+\t\t(void *)&cmd_route_add1_p_string,\n+\t\t(void *)&cmd_route_add1_p,\n+\t\t(void *)&cmd_route_add1_route_string,\n+\t\t(void *)&cmd_route_add1_add_string,\n+\t\t(void *)&cmd_route_add1_ip,\n+\t\t(void *)&cmd_route_add1_depth,\n+\t\t(void *)&cmd_route_add1_port_string,\n+\t\t(void *)&cmd_route_add1_port,\n+\t\t(void *)&cmd_route_add1_ether_string,\n+\t\t(void *)&cmd_route_add1_macaddr,\n+\t\tNULL,\n+\t},\n+};\n+\n /*\n- * route add\n+ * route add (mpls = no, qinq = no, arp = yes)\n  */\n \n-struct cmd_route_add_result {\n+struct cmd_route_add2_result {\n \tcmdline_fixed_string_t p_string;\n \tuint32_t p;\n \tcmdline_fixed_string_t route_string;\n \tcmdline_fixed_string_t add_string;\n \tcmdline_ipaddr_t ip;\n \tuint32_t depth;\n+\tcmdline_fixed_string_t port_string;\n \tuint32_t port;\n+\tcmdline_fixed_string_t ether_string;\n \tcmdline_ipaddr_t nh_ip;\n };\n \n static void\n-cmd_route_add_parsed(\n+cmd_route_add2_parsed(\n \tvoid *parsed_result,\n \t__rte_unused struct cmdline *cl,\n \tvoid *data)\n {\n-\tstruct cmd_route_add_result *params = parsed_result;\n+\tstruct cmd_route_add2_result *params = parsed_result;\n \tstruct app_params *app = data;\n \tstruct pipeline_routing_route_key key;\n-\tstruct app_pipeline_routing_route_params rt_params;\n+\tstruct pipeline_routing_route_data route_data;\n \tint status;\n \n \t/* Create route */\n@@ -852,14 +1027,15 @@ cmd_route_add_parsed(\n \tkey.key.ipv4.ip = rte_bswap32((uint32_t) params->ip.addr.ipv4.s_addr);\n \tkey.key.ipv4.depth = params->depth;\n \n-\trt_params.flags = 0; /* remote route */\n-\trt_params.port_id = params->port;\n-\trt_params.ip = rte_bswap32((uint32_t) params->nh_ip.addr.ipv4.s_addr);\n+\troute_data.flags = PIPELINE_ROUTING_ROUTE_ARP;\n+\troute_data.port_id = params->port;\n+\troute_data.ethernet.ip =\n+\t\trte_bswap32((uint32_t) params->nh_ip.addr.ipv4.s_addr);\n \n \tstatus = app_pipeline_routing_add_route(app,\n \t\tparams->p,\n \t\t&key,\n-\t\t&rt_params);\n+\t\t&route_data);\n \n \tif (status != 0) {\n \t\tprintf(\"Command failed\\n\");\n@@ -867,46 +1043,558 @@ cmd_route_add_parsed(\n \t}\n }\n \n-static cmdline_parse_token_string_t cmd_route_add_p_string =\n-\tTOKEN_STRING_INITIALIZER(struct cmd_route_add_result, p_string,\n+static cmdline_parse_token_string_t cmd_route_add2_p_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_route_add2_result, p_string,\n \t\"p\");\n \n-static cmdline_parse_token_num_t cmd_route_add_p =\n-\tTOKEN_NUM_INITIALIZER(struct cmd_route_add_result, p, UINT32);\n+static cmdline_parse_token_num_t cmd_route_add2_p =\n+\tTOKEN_NUM_INITIALIZER(struct cmd_route_add2_result, p, UINT32);\n \n-static cmdline_parse_token_string_t cmd_route_add_route_string =\n-\tTOKEN_STRING_INITIALIZER(struct cmd_route_add_result, route_string,\n+static cmdline_parse_token_string_t cmd_route_add2_route_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_route_add2_result, route_string,\n \t\"route\");\n \n-static cmdline_parse_token_string_t cmd_route_add_add_string =\n-\tTOKEN_STRING_INITIALIZER(struct cmd_route_add_result, add_string,\n+static cmdline_parse_token_string_t cmd_route_add2_add_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_route_add2_result, add_string,\n \t\"add\");\n \n-static cmdline_parse_token_ipaddr_t cmd_route_add_ip =\n-\tTOKEN_IPV4_INITIALIZER(struct cmd_route_add_result, ip);\n+static cmdline_parse_token_ipaddr_t cmd_route_add2_ip =\n+\tTOKEN_IPV4_INITIALIZER(struct cmd_route_add2_result, ip);\n+\n+static cmdline_parse_token_num_t cmd_route_add2_depth =\n+\tTOKEN_NUM_INITIALIZER(struct cmd_route_add2_result, depth, UINT32);\n+\n+static cmdline_parse_token_string_t cmd_route_add2_port_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_route_add2_result, port_string,\n+\t\"port\");\n+\n+static cmdline_parse_token_num_t cmd_route_add2_port =\n+\tTOKEN_NUM_INITIALIZER(struct cmd_route_add2_result, port, UINT32);\n+\n+static cmdline_parse_token_string_t cmd_route_add2_ether_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_route_add2_result, ether_string,\n+\t\"ether\");\n+\n+static cmdline_parse_token_ipaddr_t cmd_route_add2_nh_ip =\n+\tTOKEN_IPV4_INITIALIZER(struct cmd_route_add2_result, nh_ip);\n+\n+static cmdline_parse_inst_t cmd_route_add2 = {\n+\t.f = cmd_route_add2_parsed,\n+\t.data = NULL,\n+\t.help_str = \"Route add (mpls = no, qinq = no, arp = yes)\",\n+\t.tokens = {\n+\t\t(void *)&cmd_route_add2_p_string,\n+\t\t(void *)&cmd_route_add2_p,\n+\t\t(void *)&cmd_route_add2_route_string,\n+\t\t(void *)&cmd_route_add2_add_string,\n+\t\t(void *)&cmd_route_add2_ip,\n+\t\t(void *)&cmd_route_add2_depth,\n+\t\t(void *)&cmd_route_add2_port_string,\n+\t\t(void *)&cmd_route_add2_port,\n+\t\t(void *)&cmd_route_add2_ether_string,\n+\t\t(void *)&cmd_route_add2_nh_ip,\n+\t\tNULL,\n+\t},\n+};\n+\n+/*\n+ * route add (mpls = no, qinq = yes, arp = no)\n+ */\n+\n+struct cmd_route_add3_result {\n+\tcmdline_fixed_string_t p_string;\n+\tuint32_t p;\n+\tcmdline_fixed_string_t route_string;\n+\tcmdline_fixed_string_t add_string;\n+\tcmdline_ipaddr_t ip;\n+\tuint32_t depth;\n+\tcmdline_fixed_string_t port_string;\n+\tuint32_t port;\n+\tcmdline_fixed_string_t ether_string;\n+\tstruct ether_addr macaddr;\n+\tcmdline_fixed_string_t qinq_string;\n+\tuint32_t svlan;\n+\tuint32_t cvlan;\n+};\n+\n+static void\n+cmd_route_add3_parsed(\n+\tvoid *parsed_result,\n+\t__rte_unused struct cmdline *cl,\n+\tvoid *data)\n+{\n+\tstruct cmd_route_add3_result *params = parsed_result;\n+\tstruct app_params *app = data;\n+\tstruct pipeline_routing_route_key key;\n+\tstruct pipeline_routing_route_data route_data;\n+\tint status;\n+\n+\t/* Create route */\n+\tkey.type = PIPELINE_ROUTING_ROUTE_IPV4;\n+\tkey.key.ipv4.ip = rte_bswap32((uint32_t) params->ip.addr.ipv4.s_addr);\n+\tkey.key.ipv4.depth = params->depth;\n+\n+\troute_data.flags = PIPELINE_ROUTING_ROUTE_QINQ;\n+\troute_data.port_id = params->port;\n+\troute_data.ethernet.macaddr = params->macaddr;\n+\troute_data.l2.qinq.svlan = params->svlan;\n+\troute_data.l2.qinq.cvlan = params->cvlan;\n+\n+\tstatus = app_pipeline_routing_add_route(app,\n+\t\tparams->p,\n+\t\t&key,\n+\t\t&route_data);\n+\n+\tif (status != 0) {\n+\t\tprintf(\"Command failed\\n\");\n+\t\treturn;\n+\t}\n+}\n+\n+static cmdline_parse_token_string_t cmd_route_add3_p_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_route_add3_result, p_string,\n+\t\"p\");\n+\n+static cmdline_parse_token_num_t cmd_route_add3_p =\n+\tTOKEN_NUM_INITIALIZER(struct cmd_route_add3_result, p, UINT32);\n+\n+static cmdline_parse_token_string_t cmd_route_add3_route_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_route_add3_result, route_string,\n+\t\"route\");\n+\n+static cmdline_parse_token_string_t cmd_route_add3_add_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_route_add3_result, add_string,\n+\t\"add\");\n+\n+static cmdline_parse_token_ipaddr_t cmd_route_add3_ip =\n+\tTOKEN_IPV4_INITIALIZER(struct cmd_route_add3_result, ip);\n+\n+static cmdline_parse_token_num_t cmd_route_add3_depth =\n+\tTOKEN_NUM_INITIALIZER(struct cmd_route_add3_result, depth, UINT32);\n+\n+static cmdline_parse_token_string_t cmd_route_add3_port_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_route_add3_result, port_string,\n+\t\"port\");\n+\n+static cmdline_parse_token_num_t cmd_route_add3_port =\n+\tTOKEN_NUM_INITIALIZER(struct cmd_route_add3_result, port, UINT32);\n+\n+static cmdline_parse_token_string_t cmd_route_add3_ether_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_route_add3_result, ether_string,\n+\t\"ether\");\n+\n+static cmdline_parse_token_etheraddr_t cmd_route_add3_macaddr =\n+\tTOKEN_ETHERADDR_INITIALIZER(struct cmd_route_add3_result, macaddr);\n+\n+static cmdline_parse_token_string_t cmd_route_add3_qinq_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_route_add3_result, qinq_string,\n+\t\"qinq\");\n+\n+static cmdline_parse_token_num_t cmd_route_add3_svlan =\n+\tTOKEN_NUM_INITIALIZER(struct cmd_route_add3_result, svlan, UINT32);\n+\n+static cmdline_parse_token_num_t cmd_route_add3_cvlan =\n+\tTOKEN_NUM_INITIALIZER(struct cmd_route_add3_result, cvlan, UINT32);\n+\n+static cmdline_parse_inst_t cmd_route_add3 = {\n+\t.f = cmd_route_add3_parsed,\n+\t.data = NULL,\n+\t.help_str = \"Route add (qinq = yes, arp = no)\",\n+\t.tokens = {\n+\t\t(void *)&cmd_route_add3_p_string,\n+\t\t(void *)&cmd_route_add3_p,\n+\t\t(void *)&cmd_route_add3_route_string,\n+\t\t(void *)&cmd_route_add3_add_string,\n+\t\t(void *)&cmd_route_add3_ip,\n+\t\t(void *)&cmd_route_add3_depth,\n+\t\t(void *)&cmd_route_add3_port_string,\n+\t\t(void *)&cmd_route_add3_port,\n+\t\t(void *)&cmd_route_add3_ether_string,\n+\t\t(void *)&cmd_route_add3_macaddr,\n+\t\t(void *)&cmd_route_add3_qinq_string,\n+\t\t(void *)&cmd_route_add3_svlan,\n+\t\t(void *)&cmd_route_add3_cvlan,\n+\t\tNULL,\n+\t},\n+};\n+\n+/*\n+ * route add (mpls = no, qinq = yes, arp = yes)\n+ */\n+\n+struct cmd_route_add4_result {\n+\tcmdline_fixed_string_t p_string;\n+\tuint32_t p;\n+\tcmdline_fixed_string_t route_string;\n+\tcmdline_fixed_string_t add_string;\n+\tcmdline_ipaddr_t ip;\n+\tuint32_t depth;\n+\tcmdline_fixed_string_t port_string;\n+\tuint32_t port;\n+\tcmdline_fixed_string_t ether_string;\n+\tcmdline_ipaddr_t nh_ip;\n+\tcmdline_fixed_string_t qinq_string;\n+\tuint32_t svlan;\n+\tuint32_t cvlan;\n+};\n+\n+static void\n+cmd_route_add4_parsed(\n+\tvoid *parsed_result,\n+\t__rte_unused struct cmdline *cl,\n+\tvoid *data)\n+{\n+\tstruct cmd_route_add4_result *params = parsed_result;\n+\tstruct app_params *app = data;\n+\tstruct pipeline_routing_route_key key;\n+\tstruct pipeline_routing_route_data route_data;\n+\tint status;\n+\n+\t/* Create route */\n+\tkey.type = PIPELINE_ROUTING_ROUTE_IPV4;\n+\tkey.key.ipv4.ip = rte_bswap32((uint32_t) params->ip.addr.ipv4.s_addr);\n+\tkey.key.ipv4.depth = params->depth;\n+\n+\troute_data.flags = PIPELINE_ROUTING_ROUTE_QINQ |\n+\t\tPIPELINE_ROUTING_ROUTE_ARP;\n+\troute_data.port_id = params->port;\n+\troute_data.ethernet.ip =\n+\t\trte_bswap32((uint32_t) params->nh_ip.addr.ipv4.s_addr);\n+\troute_data.l2.qinq.svlan = params->svlan;\n+\troute_data.l2.qinq.cvlan = params->cvlan;\n+\n+\tstatus = app_pipeline_routing_add_route(app,\n+\t\tparams->p,\n+\t\t&key,\n+\t\t&route_data);\n+\n+\tif (status != 0) {\n+\t\tprintf(\"Command failed\\n\");\n+\t\treturn;\n+\t}\n+}\n+\n+static cmdline_parse_token_string_t cmd_route_add4_p_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_route_add4_result, p_string,\n+\t\"p\");\n+\n+static cmdline_parse_token_num_t cmd_route_add4_p =\n+\tTOKEN_NUM_INITIALIZER(struct cmd_route_add4_result, p, UINT32);\n+\n+static cmdline_parse_token_string_t cmd_route_add4_route_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_route_add4_result, route_string,\n+\t\"route\");\n+\n+static cmdline_parse_token_string_t cmd_route_add4_add_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_route_add4_result, add_string,\n+\t\"add\");\n+\n+static cmdline_parse_token_ipaddr_t cmd_route_add4_ip =\n+\tTOKEN_IPV4_INITIALIZER(struct cmd_route_add4_result, ip);\n+\n+static cmdline_parse_token_num_t cmd_route_add4_depth =\n+\tTOKEN_NUM_INITIALIZER(struct cmd_route_add4_result, depth, UINT32);\n+\n+static cmdline_parse_token_string_t cmd_route_add4_port_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_route_add4_result, port_string,\n+\t\"port\");\n+\n+static cmdline_parse_token_num_t cmd_route_add4_port =\n+\tTOKEN_NUM_INITIALIZER(struct cmd_route_add4_result, port, UINT32);\n+\n+static cmdline_parse_token_string_t cmd_route_add4_ether_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_route_add4_result, ether_string,\n+\t\"ether\");\n+\n+static cmdline_parse_token_ipaddr_t cmd_route_add4_nh_ip =\n+\tTOKEN_IPV4_INITIALIZER(struct cmd_route_add4_result, nh_ip);\n+\n+static cmdline_parse_token_string_t cmd_route_add4_qinq_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_route_add4_result, qinq_string,\n+\t\"qinq\");\n+\n+static cmdline_parse_token_num_t cmd_route_add4_svlan =\n+\tTOKEN_NUM_INITIALIZER(struct cmd_route_add4_result, svlan, UINT32);\n+\n+static cmdline_parse_token_num_t cmd_route_add4_cvlan =\n+\tTOKEN_NUM_INITIALIZER(struct cmd_route_add4_result, cvlan, UINT32);\n+\n+static cmdline_parse_inst_t cmd_route_add4 = {\n+\t.f = cmd_route_add4_parsed,\n+\t.data = NULL,\n+\t.help_str = \"Route add (qinq = yes, arp = yes)\",\n+\t.tokens = {\n+\t\t(void *)&cmd_route_add4_p_string,\n+\t\t(void *)&cmd_route_add4_p,\n+\t\t(void *)&cmd_route_add4_route_string,\n+\t\t(void *)&cmd_route_add4_add_string,\n+\t\t(void *)&cmd_route_add4_ip,\n+\t\t(void *)&cmd_route_add4_depth,\n+\t\t(void *)&cmd_route_add4_port_string,\n+\t\t(void *)&cmd_route_add4_port,\n+\t\t(void *)&cmd_route_add4_ether_string,\n+\t\t(void *)&cmd_route_add4_nh_ip,\n+\t\t(void *)&cmd_route_add4_qinq_string,\n+\t\t(void *)&cmd_route_add4_svlan,\n+\t\t(void *)&cmd_route_add4_cvlan,\n+\t\tNULL,\n+\t},\n+};\n+\n+/*\n+ * route add (mpls = yes, qinq = no, arp = no)\n+ */\n+\n+struct cmd_route_add5_result {\n+\tcmdline_fixed_string_t p_string;\n+\tuint32_t p;\n+\tcmdline_fixed_string_t route_string;\n+\tcmdline_fixed_string_t add_string;\n+\tcmdline_ipaddr_t ip;\n+\tuint32_t depth;\n+\tcmdline_fixed_string_t port_string;\n+\tuint32_t port;\n+\tcmdline_fixed_string_t ether_string;\n+\tstruct ether_addr macaddr;\n+\tcmdline_fixed_string_t mpls_string;\n+\tcmdline_fixed_string_t mpls_labels;\n+};\n+\n+static void\n+cmd_route_add5_parsed(\n+\tvoid *parsed_result,\n+\t__rte_unused struct cmdline *cl,\n+\tvoid *data)\n+{\n+\tstruct cmd_route_add5_result *params = parsed_result;\n+\tstruct app_params *app = data;\n+\tstruct pipeline_routing_route_key key;\n+\tstruct pipeline_routing_route_data route_data;\n+\tuint32_t mpls_labels[PIPELINE_ROUTING_MPLS_LABELS_MAX];\n+\tuint32_t n_labels = RTE_DIM(mpls_labels);\n+\tuint32_t i;\n+\tint status;\n+\n+\t/* Parse MPLS labels */\n+\tstatus = parse_labels(params->mpls_labels, mpls_labels, &n_labels);\n+\tif (status) {\n+\t\tprintf(\"MPLS labels parse error\\n\");\n+\t\treturn;\n+\t}\n+\n+\t/* Create route */\n+\tkey.type = PIPELINE_ROUTING_ROUTE_IPV4;\n+\tkey.key.ipv4.ip = rte_bswap32((uint32_t) params->ip.addr.ipv4.s_addr);\n+\tkey.key.ipv4.depth = params->depth;\n+\n+\troute_data.flags = PIPELINE_ROUTING_ROUTE_MPLS;\n+\troute_data.port_id = params->port;\n+\troute_data.ethernet.macaddr = params->macaddr;\n+\tfor (i = 0; i < n_labels; i++)\n+\t\troute_data.l2.mpls.labels[i] = mpls_labels[i];\n+\troute_data.l2.mpls.n_labels = n_labels;\n+\n+\tstatus = app_pipeline_routing_add_route(app,\n+\t\tparams->p,\n+\t\t&key,\n+\t\t&route_data);\n+\n+\tif (status != 0) {\n+\t\tprintf(\"Command failed\\n\");\n+\t\treturn;\n+\t}\n+}\n+\n+static cmdline_parse_token_string_t cmd_route_add5_p_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_route_add5_result, p_string,\n+\t\"p\");\n+\n+static cmdline_parse_token_num_t cmd_route_add5_p =\n+\tTOKEN_NUM_INITIALIZER(struct cmd_route_add5_result, p, UINT32);\n+\n+static cmdline_parse_token_string_t cmd_route_add5_route_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_route_add5_result, route_string,\n+\t\"route\");\n+\n+static cmdline_parse_token_string_t cmd_route_add5_add_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_route_add5_result, add_string,\n+\t\"add\");\n+\n+static cmdline_parse_token_ipaddr_t cmd_route_add5_ip =\n+\tTOKEN_IPV4_INITIALIZER(struct cmd_route_add5_result, ip);\n+\n+static cmdline_parse_token_num_t cmd_route_add5_depth =\n+\tTOKEN_NUM_INITIALIZER(struct cmd_route_add5_result, depth, UINT32);\n+\n+static cmdline_parse_token_string_t cmd_route_add5_port_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_route_add5_result, port_string,\n+\t\"port\");\n+\n+static cmdline_parse_token_num_t cmd_route_add5_port =\n+\tTOKEN_NUM_INITIALIZER(struct cmd_route_add5_result, port, UINT32);\n+\n+static cmdline_parse_token_string_t cmd_route_add5_ether_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_route_add5_result, ether_string,\n+\t\"ether\");\n+\n+static cmdline_parse_token_etheraddr_t cmd_route_add5_macaddr =\n+\tTOKEN_ETHERADDR_INITIALIZER(struct cmd_route_add5_result, macaddr);\n+\n+static cmdline_parse_token_string_t cmd_route_add5_mpls_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_route_add5_result, mpls_string,\n+\t\"mpls\");\n+\n+static cmdline_parse_token_string_t cmd_route_add5_mpls_labels =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_route_add5_result, mpls_labels,\n+\tNULL);\n+\n+static cmdline_parse_inst_t cmd_route_add5 = {\n+\t.f = cmd_route_add5_parsed,\n+\t.data = NULL,\n+\t.help_str = \"Route add (mpls = yes, arp = no)\",\n+\t.tokens = {\n+\t\t(void *)&cmd_route_add5_p_string,\n+\t\t(void *)&cmd_route_add5_p,\n+\t\t(void *)&cmd_route_add5_route_string,\n+\t\t(void *)&cmd_route_add5_add_string,\n+\t\t(void *)&cmd_route_add5_ip,\n+\t\t(void *)&cmd_route_add5_depth,\n+\t\t(void *)&cmd_route_add5_port_string,\n+\t\t(void *)&cmd_route_add5_port,\n+\t\t(void *)&cmd_route_add5_ether_string,\n+\t\t(void *)&cmd_route_add5_macaddr,\n+\t\t(void *)&cmd_route_add5_mpls_string,\n+\t\t(void *)&cmd_route_add5_mpls_labels,\n+\t\tNULL,\n+\t},\n+};\n+\n+/*\n+ * route add (mpls = yes, qinq = no, arp = yes)\n+ */\n+\n+struct cmd_route_add6_result {\n+\tcmdline_fixed_string_t p_string;\n+\tuint32_t p;\n+\tcmdline_fixed_string_t route_string;\n+\tcmdline_fixed_string_t add_string;\n+\tcmdline_ipaddr_t ip;\n+\tuint32_t depth;\n+\tcmdline_fixed_string_t port_string;\n+\tuint32_t port;\n+\tcmdline_fixed_string_t ether_string;\n+\tcmdline_ipaddr_t nh_ip;\n+\tcmdline_fixed_string_t mpls_string;\n+\tcmdline_fixed_string_t mpls_labels;\n+};\n+\n+static void\n+cmd_route_add6_parsed(\n+\tvoid *parsed_result,\n+\t__rte_unused struct cmdline *cl,\n+\tvoid *data)\n+{\n+\tstruct cmd_route_add6_result *params = parsed_result;\n+\tstruct app_params *app = data;\n+\tstruct pipeline_routing_route_key key;\n+\tstruct pipeline_routing_route_data route_data;\n+\tuint32_t mpls_labels[PIPELINE_ROUTING_MPLS_LABELS_MAX];\n+\tuint32_t n_labels = RTE_DIM(mpls_labels);\n+\tuint32_t i;\n+\tint status;\n+\n+\t/* Parse MPLS labels */\n+\tstatus = parse_labels(params->mpls_labels, mpls_labels, &n_labels);\n+\tif (status) {\n+\t\tprintf(\"MPLS labels parse error\\n\");\n+\t\treturn;\n+\t}\n+\n+\t/* Create route */\n+\tkey.type = PIPELINE_ROUTING_ROUTE_IPV4;\n+\tkey.key.ipv4.ip = rte_bswap32((uint32_t) params->ip.addr.ipv4.s_addr);\n+\tkey.key.ipv4.depth = params->depth;\n+\n+\troute_data.flags = PIPELINE_ROUTING_ROUTE_MPLS |\n+\t\tPIPELINE_ROUTING_ROUTE_ARP;\n+\troute_data.port_id = params->port;\n+\troute_data.ethernet.ip =\n+\t\trte_bswap32((uint32_t) params->nh_ip.addr.ipv4.s_addr);\n+\tfor (i = 0; i < n_labels; i++)\n+\t\troute_data.l2.mpls.labels[i] = mpls_labels[i];\n+\troute_data.l2.mpls.n_labels = n_labels;\n+\n+\tstatus = app_pipeline_routing_add_route(app,\n+\t\tparams->p,\n+\t\t&key,\n+\t\t&route_data);\n+\n+\tif (status != 0) {\n+\t\tprintf(\"Command failed\\n\");\n+\t\treturn;\n+\t}\n+}\n+\n+static cmdline_parse_token_string_t cmd_route_add6_p_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_route_add6_result, p_string,\n+\t\"p\");\n+\n+static cmdline_parse_token_num_t cmd_route_add6_p =\n+\tTOKEN_NUM_INITIALIZER(struct cmd_route_add6_result, p, UINT32);\n+\n+static cmdline_parse_token_string_t cmd_route_add6_route_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_route_add6_result, route_string,\n+\t\"route\");\n+\n+static cmdline_parse_token_string_t cmd_route_add6_add_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_route_add6_result, add_string,\n+\t\"add\");\n+\n+static cmdline_parse_token_ipaddr_t cmd_route_add6_ip =\n+\tTOKEN_IPV4_INITIALIZER(struct cmd_route_add6_result, ip);\n+\n+static cmdline_parse_token_num_t cmd_route_add6_depth =\n+\tTOKEN_NUM_INITIALIZER(struct cmd_route_add6_result, depth, UINT32);\n+\n+static cmdline_parse_token_string_t cmd_route_add6_port_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_route_add6_result, port_string,\n+\t\"port\");\n+\n+static cmdline_parse_token_num_t cmd_route_add6_port =\n+\tTOKEN_NUM_INITIALIZER(struct cmd_route_add6_result, port, UINT32);\n+\n+static cmdline_parse_token_string_t cmd_route_add6_ether_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_route_add6_result, ether_string,\n+\t\"ether\");\n \n-static cmdline_parse_token_num_t cmd_route_add_depth =\n-\tTOKEN_NUM_INITIALIZER(struct cmd_route_add_result, depth, UINT32);\n+static cmdline_parse_token_ipaddr_t cmd_route_add6_nh_ip =\n+\tTOKEN_IPV4_INITIALIZER(struct cmd_route_add6_result, nh_ip);\n \n-static cmdline_parse_token_num_t cmd_route_add_port =\n-\tTOKEN_NUM_INITIALIZER(struct cmd_route_add_result, port, UINT32);\n+static cmdline_parse_token_string_t cmd_route_add6_mpls_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_route_add6_result, mpls_string,\n+\t\"mpls\");\n \n-static cmdline_parse_token_ipaddr_t cmd_route_add_nh_ip =\n-\tTOKEN_IPV4_INITIALIZER(struct cmd_route_add_result, nh_ip);\n+static cmdline_parse_token_string_t cmd_route_add6_mpls_labels =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_route_add6_result, mpls_labels,\n+\tNULL);\n \n-static cmdline_parse_inst_t cmd_route_add = {\n-\t.f = cmd_route_add_parsed,\n+static cmdline_parse_inst_t cmd_route_add6 = {\n+\t.f = cmd_route_add6_parsed,\n \t.data = NULL,\n-\t.help_str = \"Route add\",\n+\t.help_str = \"Route add (mpls = yes, arp = yes)\",\n \t.tokens = {\n-\t\t(void *)&cmd_route_add_p_string,\n-\t\t(void *)&cmd_route_add_p,\n-\t\t(void *)&cmd_route_add_route_string,\n-\t\t(void *)&cmd_route_add_add_string,\n-\t\t(void *)&cmd_route_add_ip,\n-\t\t(void *)&cmd_route_add_depth,\n-\t\t(void *)&cmd_route_add_port,\n-\t\t(void *)&cmd_route_add_nh_ip,\n+\t\t(void *)&cmd_route_add6_p_string,\n+\t\t(void *)&cmd_route_add6_p,\n+\t\t(void *)&cmd_route_add6_route_string,\n+\t\t(void *)&cmd_route_add6_add_string,\n+\t\t(void *)&cmd_route_add6_ip,\n+\t\t(void *)&cmd_route_add6_depth,\n+\t\t(void *)&cmd_route_add6_port_string,\n+\t\t(void *)&cmd_route_add6_port,\n+\t\t(void *)&cmd_route_add6_ether_string,\n+\t\t(void *)&cmd_route_add6_nh_ip,\n+\t\t(void *)&cmd_route_add6_mpls_string,\n+\t\t(void *)&cmd_route_add6_mpls_labels,\n \t\tNULL,\n \t},\n };\n@@ -1519,7 +2207,12 @@ static cmdline_parse_inst_t cmd_arp_ls = {\n };\n \n static cmdline_parse_ctx_t pipeline_cmds[] = {\n-\t(cmdline_parse_inst_t *)&cmd_route_add,\n+\t(cmdline_parse_inst_t *)&cmd_route_add1,\n+\t(cmdline_parse_inst_t *)&cmd_route_add2,\n+\t(cmdline_parse_inst_t *)&cmd_route_add3,\n+\t(cmdline_parse_inst_t *)&cmd_route_add4,\n+\t(cmdline_parse_inst_t *)&cmd_route_add5,\n+\t(cmdline_parse_inst_t *)&cmd_route_add6,\n \t(cmdline_parse_inst_t *)&cmd_route_del,\n \t(cmdline_parse_inst_t *)&cmd_route_add_default,\n \t(cmdline_parse_inst_t *)&cmd_route_del_default,\ndiff --git a/examples/ip_pipeline/pipeline/pipeline_routing.h b/examples/ip_pipeline/pipeline/pipeline_routing.h\nindex e1016f9..fa41642 100644\n--- a/examples/ip_pipeline/pipeline/pipeline_routing.h\n+++ b/examples/ip_pipeline/pipeline/pipeline_routing.h\n@@ -41,17 +41,11 @@\n  * Route\n  */\n \n-struct app_pipeline_routing_route_params {\n-\tuint32_t flags;\n-\tuint32_t port_id; /* Output port ID */\n-\tuint32_t ip; /* IP address for the next hop (only for remote routes) */\n-};\n-\n int\n app_pipeline_routing_add_route(struct app_params *app,\n \tuint32_t pipeline_id,\n \tstruct pipeline_routing_route_key *key,\n-\tstruct app_pipeline_routing_route_params *route_params);\n+\tstruct pipeline_routing_route_data *data);\n \n int\n app_pipeline_routing_delete_route(struct app_params *app,\ndiff --git a/examples/ip_pipeline/pipeline/pipeline_routing_be.c b/examples/ip_pipeline/pipeline/pipeline_routing_be.c\nindex 1e817dd..14e6ce8 100644\n--- a/examples/ip_pipeline/pipeline/pipeline_routing_be.c\n+++ b/examples/ip_pipeline/pipeline/pipeline_routing_be.c\n@@ -49,16 +49,29 @@\n #include \"pipeline_actions_common.h\"\n #include \"hash_func.h\"\n \n+#define MPLS_LABEL(label, exp, s, ttl)\t\t\t\t\t\\\n+\t(((((uint64_t) (label)) & 0xFFFFFLLU) << 12) |\t\t\\\n+\t((((uint64_t) (exp)) & 0x7LLU) << 9) |\t\t\t\t\\\n+\t((((uint64_t) (s)) & 0x1LLU) << 8) |\t\t\t\t\\\n+\t(((uint64_t) (ttl)) & 0xFFLU))\n+\n+#define RTE_SCHED_PORT_HIERARCHY(subport, pipe,\t\t\\\n+\ttraffic_class, queue, color)\t\t\t\t\t\\\n+\t((((uint32_t) (queue)) & 0x3) |\t\t\t\t\t\\\n+\t((((uint32_t) (traffic_class)) & 0x3) << 2) |\t\t\\\n+\t((((uint32_t) (pipe)) & 0xFFFFF) << 4) |\t\t\t\\\n+\t((((uint32_t) (subport)) & 0x3F) << 24) |\t\t\t\\\n+\t((((uint32_t) (color)) & 0x3) << 30))\n+\n struct pipeline_routing {\n \tstruct pipeline p;\n+\tstruct pipeline_routing_params params;\n \tpipeline_msg_req_handler custom_handlers[PIPELINE_ROUTING_MSG_REQS];\n-\n-\tuint32_t n_routes;\n-\tuint32_t n_arp_entries;\n-\tuint32_t ip_da_offset;\n-\tuint32_t arp_key_offset;\n } __rte_cache_aligned;\n \n+/*\n+ * Message handlers\n+ */\n static void *\n pipeline_routing_msg_req_custom_handler(struct pipeline *p, void *msg);\n \n@@ -138,35 +151,152 @@ struct routing_table_entry {\n \tuint32_t flags;\n \tuint32_t port_id; /* Output port ID */\n \tuint32_t ip; /* Next hop IP address (only valid for remote routes) */\n+\n+\t/* ether_l2 */\n+\tuint16_t data_offset;\n+\tuint16_t ether_l2_length;\n+\tuint64_t slab[4];\n+\tuint16_t slab_offset[4];\n };\n \n-static inline void\n+static inline __attribute__((always_inline)) void\n pkt_work_routing(\n \tstruct rte_mbuf *pkt,\n \tstruct rte_pipeline_table_entry *table_entry,\n-\tvoid *arg)\n+\tvoid *arg,\n+\tint arp,\n+\tint qinq,\n+\tint qinq_sched,\n+\tint mpls,\n+\tint mpls_color_mark)\n {\n+\tstruct pipeline_routing *p_rt = arg;\n+\n \tstruct routing_table_entry *entry =\n \t\t(struct routing_table_entry *) table_entry;\n-\tstruct pipeline_routing *p_rt = arg;\n+\n+\tstruct ipv4_hdr *ip = (struct ipv4_hdr *)\n+\t\tRTE_MBUF_METADATA_UINT8_PTR(pkt, p_rt->params.ip_hdr_offset);\n+\n+\tenum rte_meter_color pkt_color = (enum rte_meter_color)\n+\t\tRTE_MBUF_METADATA_UINT32(pkt, p_rt->params.color_offset);\n \n \tstruct pipeline_routing_arp_key_ipv4 *arp_key =\n \t\t(struct pipeline_routing_arp_key_ipv4 *)\n-\t\tRTE_MBUF_METADATA_UINT8_PTR(pkt, p_rt->arp_key_offset);\n-\tuint32_t ip = RTE_MBUF_METADATA_UINT32(pkt, p_rt->ip_da_offset);\n+\t\tRTE_MBUF_METADATA_UINT8_PTR(pkt, p_rt->params.arp_key_offset);\n+\n+\tuint64_t *slab0_ptr, *slab1_ptr, *slab2_ptr, *slab3_ptr;\n+\tuint32_t ip_da, nh_ip, port_id, sched;\n+\tuint16_t total_length, data_offset, ether_l2_length;\n+\n+\t/* Read */\n+\ttotal_length = rte_bswap16(ip->total_length);\n+\tip_da = ip->dst_addr;\n+\tdata_offset = entry->data_offset;\n+\tether_l2_length = entry->ether_l2_length;\n+\tslab0_ptr = RTE_MBUF_METADATA_UINT64_PTR(pkt, entry->slab_offset[0]);\n+\tslab1_ptr = RTE_MBUF_METADATA_UINT64_PTR(pkt, entry->slab_offset[1]);\n+\tslab2_ptr = RTE_MBUF_METADATA_UINT64_PTR(pkt, entry->slab_offset[2]);\n+\tslab3_ptr = RTE_MBUF_METADATA_UINT64_PTR(pkt, entry->slab_offset[3]);\n+\n+\tif (arp) {\n+\t\tport_id = entry->port_id;\n+\t\tnh_ip = entry->ip;\n+\t\tif (entry->flags & PIPELINE_ROUTING_ROUTE_LOCAL)\n+\t\t\tnh_ip = ip_da;\n+\t}\n+\n+\t/* Compute */\n+\ttotal_length += ether_l2_length;\n+\n+\tif (qinq && qinq_sched) {\n+\t\tuint32_t dscp = ip->type_of_service >> 2;\n+\t\tuint32_t svlan, cvlan, tc, tc_q;\n+\n+\t\tif (qinq_sched == 1) {\n+\t\t\tuint64_t slab_qinq = rte_bswap64(entry->slab[0]);\n+\n+\t\t\tsvlan = (slab_qinq >> 48) & 0xFFF;\n+\t\t\tcvlan = (slab_qinq >> 16) & 0xFFF;\n+\t\t\ttc = (dscp >> 2) & 0x3;\n+\t\t\ttc_q = dscp & 0x3;\n+\t\t} else {\n+\t\t\tuint32_t ip_src = rte_bswap32(ip->src_addr);\n+\n+\t\t\tsvlan = 0;\n+\t\t\tcvlan = (ip_src >> 16) & 0xFFF;\n+\t\t\ttc = (ip_src >> 2) & 0x3;\n+\t\t\ttc_q = ip_src & 0x3;\n+\t\t}\n+\n+\t\tsched = RTE_SCHED_PORT_HIERARCHY(svlan,\n+\t\t\tcvlan,\n+\t\t\ttc,\n+\t\t\ttc_q,\n+\t\t\te_RTE_METER_GREEN);\n+\t}\n+\n+\t/* Write */\n+\tpkt->data_off = data_offset;\n+\tpkt->data_len = total_length;\n+\tpkt->pkt_len = total_length;\n+\n+\tif ((qinq == 0) && (mpls == 0)) {\n+\t\t*slab0_ptr = entry->slab[0];\n+\n+\t\tif (arp == 0)\n+\t\t\t*slab1_ptr = entry->slab[1];\n+\t}\n+\n+\tif (qinq) {\n+\t\t*slab0_ptr = entry->slab[0];\n+\t\t*slab1_ptr = entry->slab[1];\n+\n+\t\tif (arp == 0)\n+\t\t\t*slab2_ptr = entry->slab[2];\n+\n+\t\tif (qinq_sched)\n+\t\t\tpkt->hash.sched = sched;\n+\t}\n+\n+\tif (mpls) {\n+\t\tif (mpls_color_mark) {\n+\t\t\tuint64_t mpls_exp = rte_bswap64(\n+\t\t\t\t(MPLS_LABEL(0, pkt_color, 0, 0) << 32) |\n+\t\t\t\tMPLS_LABEL(0, pkt_color, 0, 0));\n+\n+\t\t\t*slab0_ptr = entry->slab[0] | mpls_exp;\n+\t\t\t*slab1_ptr = entry->slab[1] | mpls_exp;\n+\t\t\t*slab2_ptr = entry->slab[2];\n+\t\t} else {\n+\t\t\t*slab0_ptr = entry->slab[0];\n+\t\t\t*slab1_ptr = entry->slab[1];\n+\t\t\t*slab2_ptr = entry->slab[2];\n+\t\t}\n+\n+\t\tif (arp == 0)\n+\t\t\t*slab3_ptr = entry->slab[3];\n+\t}\n \n-\tarp_key->port_id = entry->port_id;\n-\tarp_key->ip = entry->ip;\n-\tif (entry->flags & PIPELINE_ROUTING_ROUTE_LOCAL)\n-\t\tarp_key->ip = ip;\n+\tif (arp) {\n+\t\tarp_key->port_id = port_id;\n+\t\tarp_key->ip = nh_ip;\n+\t}\n }\n \n-static inline void\n+static inline __attribute__((always_inline)) void\n pkt4_work_routing(\n \tstruct rte_mbuf **pkts,\n \tstruct rte_pipeline_table_entry **table_entries,\n-\tvoid *arg)\n+\tvoid *arg,\n+\tint arp,\n+\tint qinq,\n+\tint qinq_sched,\n+\tint mpls,\n+\tint mpls_color_mark)\n {\n+\tstruct pipeline_routing *p_rt = arg;\n+\n \tstruct routing_table_entry *entry0 =\n \t\t(struct routing_table_entry *) table_entries[0];\n \tstruct routing_table_entry *entry1 =\n@@ -175,51 +305,692 @@ pkt4_work_routing(\n \t\t(struct routing_table_entry *) table_entries[2];\n \tstruct routing_table_entry *entry3 =\n \t\t(struct routing_table_entry *) table_entries[3];\n-\tstruct pipeline_routing *p_rt = arg;\n+\n+\tstruct ipv4_hdr *ip0 = (struct ipv4_hdr *)\n+\t\tRTE_MBUF_METADATA_UINT8_PTR(pkts[0],\n+\t\t\tp_rt->params.ip_hdr_offset);\n+\tstruct ipv4_hdr *ip1 = (struct ipv4_hdr *)\n+\t\tRTE_MBUF_METADATA_UINT8_PTR(pkts[1],\n+\t\t\tp_rt->params.ip_hdr_offset);\n+\tstruct ipv4_hdr *ip2 = (struct ipv4_hdr *)\n+\t\tRTE_MBUF_METADATA_UINT8_PTR(pkts[2],\n+\t\t\tp_rt->params.ip_hdr_offset);\n+\tstruct ipv4_hdr *ip3 = (struct ipv4_hdr *)\n+\t\tRTE_MBUF_METADATA_UINT8_PTR(pkts[3],\n+\t\t\tp_rt->params.ip_hdr_offset);\n+\n+\tenum rte_meter_color pkt0_color = (enum rte_meter_color)\n+\t\tRTE_MBUF_METADATA_UINT32(pkts[0], p_rt->params.color_offset);\n+\tenum rte_meter_color pkt1_color = (enum rte_meter_color)\n+\t\tRTE_MBUF_METADATA_UINT32(pkts[1], p_rt->params.color_offset);\n+\tenum rte_meter_color pkt2_color = (enum rte_meter_color)\n+\t\tRTE_MBUF_METADATA_UINT32(pkts[2], p_rt->params.color_offset);\n+\tenum rte_meter_color pkt3_color = (enum rte_meter_color)\n+\t\tRTE_MBUF_METADATA_UINT32(pkts[3], p_rt->params.color_offset);\n \n \tstruct pipeline_routing_arp_key_ipv4 *arp_key0 =\n \t\t(struct pipeline_routing_arp_key_ipv4 *)\n-\t\tRTE_MBUF_METADATA_UINT8_PTR(pkts[0], p_rt->arp_key_offset);\n+\t\tRTE_MBUF_METADATA_UINT8_PTR(pkts[0],\n+\t\t\tp_rt->params.arp_key_offset);\n \tstruct pipeline_routing_arp_key_ipv4 *arp_key1 =\n \t\t(struct pipeline_routing_arp_key_ipv4 *)\n-\t\tRTE_MBUF_METADATA_UINT8_PTR(pkts[1], p_rt->arp_key_offset);\n+\t\tRTE_MBUF_METADATA_UINT8_PTR(pkts[1],\n+\t\t\tp_rt->params.arp_key_offset);\n \tstruct pipeline_routing_arp_key_ipv4 *arp_key2 =\n \t\t(struct pipeline_routing_arp_key_ipv4 *)\n-\t\tRTE_MBUF_METADATA_UINT8_PTR(pkts[2], p_rt->arp_key_offset);\n+\t\tRTE_MBUF_METADATA_UINT8_PTR(pkts[2],\n+\t\t\tp_rt->params.arp_key_offset);\n \tstruct pipeline_routing_arp_key_ipv4 *arp_key3 =\n \t\t(struct pipeline_routing_arp_key_ipv4 *)\n-\t\tRTE_MBUF_METADATA_UINT8_PTR(pkts[3], p_rt->arp_key_offset);\n+\t\tRTE_MBUF_METADATA_UINT8_PTR(pkts[3],\n+\t\t\tp_rt->params.arp_key_offset);\n+\n+\tuint64_t *slab0_ptr0, *slab1_ptr0, *slab2_ptr0, *slab3_ptr0;\n+\tuint64_t *slab0_ptr1, *slab1_ptr1, *slab2_ptr1, *slab3_ptr1;\n+\tuint64_t *slab0_ptr2, *slab1_ptr2, *slab2_ptr2, *slab3_ptr2;\n+\tuint64_t *slab0_ptr3, *slab1_ptr3, *slab2_ptr3, *slab3_ptr3;\n+\n+\tuint32_t ip_da0, nh_ip0, port_id0, sched0;\n+\tuint32_t ip_da1, nh_ip1, port_id1, sched1;\n+\tuint32_t ip_da2, nh_ip2, port_id2, sched2;\n+\tuint32_t ip_da3, nh_ip3, port_id3, sched3;\n+\n+\tuint16_t total_length0, data_offset0, ether_l2_length0;\n+\tuint16_t total_length1, data_offset1, ether_l2_length1;\n+\tuint16_t total_length2, data_offset2, ether_l2_length2;\n+\tuint16_t total_length3, data_offset3, ether_l2_length3;\n+\n+\t/* Read */\n+\ttotal_length0 = rte_bswap16(ip0->total_length);\n+\ttotal_length1 = rte_bswap16(ip1->total_length);\n+\ttotal_length2 = rte_bswap16(ip2->total_length);\n+\ttotal_length3 = rte_bswap16(ip3->total_length);\n+\n+\tip_da0 = ip0->dst_addr;\n+\tip_da1 = ip1->dst_addr;\n+\tip_da2 = ip2->dst_addr;\n+\tip_da3 = ip3->dst_addr;\n+\n+\tdata_offset0 = entry0->data_offset;\n+\tdata_offset1 = entry1->data_offset;\n+\tdata_offset2 = entry2->data_offset;\n+\tdata_offset3 = entry3->data_offset;\n+\n+\tether_l2_length0 = entry0->ether_l2_length;\n+\tether_l2_length1 = entry1->ether_l2_length;\n+\tether_l2_length2 = entry2->ether_l2_length;\n+\tether_l2_length3 = entry3->ether_l2_length;\n+\n+\tslab0_ptr0 = RTE_MBUF_METADATA_UINT64_PTR(pkts[0],\n+\t\tentry0->slab_offset[0]);\n+\tslab1_ptr0 = RTE_MBUF_METADATA_UINT64_PTR(pkts[0],\n+\t\tentry0->slab_offset[1]);\n+\tslab2_ptr0 = RTE_MBUF_METADATA_UINT64_PTR(pkts[0],\n+\t\tentry0->slab_offset[2]);\n+\tslab3_ptr0 = RTE_MBUF_METADATA_UINT64_PTR(pkts[0],\n+\t\tentry0->slab_offset[3]);\n+\n+\tslab0_ptr1 = RTE_MBUF_METADATA_UINT64_PTR(pkts[1],\n+\t\tentry1->slab_offset[0]);\n+\tslab1_ptr1 = RTE_MBUF_METADATA_UINT64_PTR(pkts[1],\n+\t\tentry1->slab_offset[1]);\n+\tslab2_ptr1 = RTE_MBUF_METADATA_UINT64_PTR(pkts[1],\n+\t\tentry1->slab_offset[2]);\n+\tslab3_ptr1 = RTE_MBUF_METADATA_UINT64_PTR(pkts[1],\n+\t\tentry1->slab_offset[3]);\n+\n+\tslab0_ptr2 = RTE_MBUF_METADATA_UINT64_PTR(pkts[2],\n+\t\tentry2->slab_offset[0]);\n+\tslab1_ptr2 = RTE_MBUF_METADATA_UINT64_PTR(pkts[2],\n+\t\tentry2->slab_offset[1]);\n+\tslab2_ptr2 = RTE_MBUF_METADATA_UINT64_PTR(pkts[2],\n+\t\tentry2->slab_offset[2]);\n+\tslab3_ptr2 = RTE_MBUF_METADATA_UINT64_PTR(pkts[2],\n+\t\tentry2->slab_offset[3]);\n+\n+\tslab0_ptr3 = RTE_MBUF_METADATA_UINT64_PTR(pkts[3],\n+\t\tentry3->slab_offset[0]);\n+\tslab1_ptr3 = RTE_MBUF_METADATA_UINT64_PTR(pkts[3],\n+\t\tentry3->slab_offset[1]);\n+\tslab2_ptr3 = RTE_MBUF_METADATA_UINT64_PTR(pkts[3],\n+\t\tentry3->slab_offset[2]);\n+\tslab3_ptr3 = RTE_MBUF_METADATA_UINT64_PTR(pkts[3],\n+\t\tentry3->slab_offset[3]);\n+\n+\tif (arp) {\n+\t\tport_id0 = entry0->port_id;\n+\t\tnh_ip0 = entry0->ip;\n+\t\tif (entry0->flags & PIPELINE_ROUTING_ROUTE_LOCAL)\n+\t\t\tnh_ip0 = ip_da0;\n+\n+\t\tport_id1 = entry1->port_id;\n+\t\tnh_ip1 = entry1->ip;\n+\t\tif (entry1->flags & PIPELINE_ROUTING_ROUTE_LOCAL)\n+\t\t\tnh_ip1 = ip_da1;\n+\n+\t\tport_id2 = entry2->port_id;\n+\t\tnh_ip2 = entry2->ip;\n+\t\tif (entry2->flags & PIPELINE_ROUTING_ROUTE_LOCAL)\n+\t\t\tnh_ip2 = ip_da2;\n+\n+\t\tport_id3 = entry3->port_id;\n+\t\tnh_ip3 = entry3->ip;\n+\t\tif (entry3->flags & PIPELINE_ROUTING_ROUTE_LOCAL)\n+\t\t\tnh_ip3 = ip_da3;\n+\t}\n+\n+\t/* Compute */\n+\ttotal_length0 += ether_l2_length0;\n+\ttotal_length1 += ether_l2_length1;\n+\ttotal_length2 += ether_l2_length2;\n+\ttotal_length3 += ether_l2_length3;\n+\n+\tif (qinq && qinq_sched) {\n+\t\tuint32_t dscp0 = ip0->type_of_service >> 2;\n+\t\tuint32_t dscp1 = ip1->type_of_service >> 2;\n+\t\tuint32_t dscp2 = ip2->type_of_service >> 2;\n+\t\tuint32_t dscp3 = ip3->type_of_service >> 2;\n+\t\tuint32_t svlan0, cvlan0, tc0, tc_q0;\n+\t\tuint32_t svlan1, cvlan1, tc1, tc_q1;\n+\t\tuint32_t svlan2, cvlan2, tc2, tc_q2;\n+\t\tuint32_t svlan3, cvlan3, tc3, tc_q3;\n+\n+\t\tif (qinq_sched == 1) {\n+\t\t\tuint64_t slab_qinq0 = rte_bswap64(entry0->slab[0]);\n+\t\t\tuint64_t slab_qinq1 = rte_bswap64(entry1->slab[0]);\n+\t\t\tuint64_t slab_qinq2 = rte_bswap64(entry2->slab[0]);\n+\t\t\tuint64_t slab_qinq3 = rte_bswap64(entry3->slab[0]);\n+\n+\t\t\tsvlan0 = (slab_qinq0 >> 48) & 0xFFF;\n+\t\t\tsvlan1 = (slab_qinq1 >> 48) & 0xFFF;\n+\t\t\tsvlan2 = (slab_qinq2 >> 48) & 0xFFF;\n+\t\t\tsvlan3 = (slab_qinq3 >> 48) & 0xFFF;\n+\n+\t\t\tcvlan0 = (slab_qinq0 >> 16) & 0xFFF;\n+\t\t\tcvlan1 = (slab_qinq1 >> 16) & 0xFFF;\n+\t\t\tcvlan2 = (slab_qinq2 >> 16) & 0xFFF;\n+\t\t\tcvlan3 = (slab_qinq3 >> 16) & 0xFFF;\n+\n+\t\t\ttc0 = (dscp0 >> 2) & 0x3;\n+\t\t\ttc1 = (dscp1 >> 2) & 0x3;\n+\t\t\ttc2 = (dscp2 >> 2) & 0x3;\n+\t\t\ttc3 = (dscp3 >> 2) & 0x3;\n+\n+\t\t\ttc_q0 = dscp0 & 0x3;\n+\t\t\ttc_q1 = dscp1 & 0x3;\n+\t\t\ttc_q2 = dscp2 & 0x3;\n+\t\t\ttc_q3 = dscp3 & 0x3;\n+\t\t} else {\n+\t\t\tuint32_t ip_src0 = rte_bswap32(ip0->src_addr);\n+\t\t\tuint32_t ip_src1 = rte_bswap32(ip1->src_addr);\n+\t\t\tuint32_t ip_src2 = rte_bswap32(ip2->src_addr);\n+\t\t\tuint32_t ip_src3 = rte_bswap32(ip3->src_addr);\n+\n+\t\t\tsvlan0 = 0;\n+\t\t\tsvlan1 = 0;\n+\t\t\tsvlan2 = 0;\n+\t\t\tsvlan3 = 0;\n+\n+\t\t\tcvlan0 = (ip_src0 >> 16) & 0xFFF;\n+\t\t\tcvlan1 = (ip_src1 >> 16) & 0xFFF;\n+\t\t\tcvlan2 = (ip_src2 >> 16) & 0xFFF;\n+\t\t\tcvlan3 = (ip_src3 >> 16) & 0xFFF;\n+\n+\t\t\ttc0 = (ip_src0 >> 2) & 0x3;\n+\t\t\ttc1 = (ip_src1 >> 2) & 0x3;\n+\t\t\ttc2 = (ip_src2 >> 2) & 0x3;\n+\t\t\ttc3 = (ip_src3 >> 2) & 0x3;\n+\n+\t\t\ttc_q0 = ip_src0 & 0x3;\n+\t\t\ttc_q1 = ip_src1 & 0x3;\n+\t\t\ttc_q2 = ip_src2 & 0x3;\n+\t\t\ttc_q3 = ip_src3 & 0x3;\n+\t\t}\n+\n+\t\tsched0 = RTE_SCHED_PORT_HIERARCHY(svlan0,\n+\t\t\tcvlan0,\n+\t\t\ttc0,\n+\t\t\ttc_q0,\n+\t\t\te_RTE_METER_GREEN);\n+\t\tsched1 = RTE_SCHED_PORT_HIERARCHY(svlan1,\n+\t\t\tcvlan1,\n+\t\t\ttc1,\n+\t\t\ttc_q1,\n+\t\t\te_RTE_METER_GREEN);\n+\t\tsched2 = RTE_SCHED_PORT_HIERARCHY(svlan2,\n+\t\t\tcvlan2,\n+\t\t\ttc2,\n+\t\t\ttc_q2,\n+\t\t\te_RTE_METER_GREEN);\n+\t\tsched3 = RTE_SCHED_PORT_HIERARCHY(svlan3,\n+\t\t\tcvlan3,\n+\t\t\ttc3,\n+\t\t\ttc_q3,\n+\t\t\te_RTE_METER_GREEN);\n+\t}\n+\n+\t/* Write */\n+\tpkts[0]->data_off = data_offset0;\n+\tpkts[1]->data_off = data_offset1;\n+\tpkts[2]->data_off = data_offset2;\n+\tpkts[3]->data_off = data_offset3;\n+\n+\tpkts[0]->data_len = total_length0;\n+\tpkts[1]->data_len = total_length1;\n+\tpkts[2]->data_len = total_length2;\n+\tpkts[3]->data_len = total_length3;\n+\n+\tpkts[0]->pkt_len = total_length0;\n+\tpkts[1]->pkt_len = total_length1;\n+\tpkts[2]->pkt_len = total_length2;\n+\tpkts[3]->pkt_len = total_length3;\n+\n+\tif ((qinq == 0) && (mpls == 0)) {\n+\t\t*slab0_ptr0 = entry0->slab[0];\n+\t\t*slab0_ptr1 = entry1->slab[0];\n+\t\t*slab0_ptr2 = entry2->slab[0];\n+\t\t*slab0_ptr3 = entry3->slab[0];\n+\n+\t\tif (arp == 0) {\n+\t\t\t*slab1_ptr0 = entry0->slab[1];\n+\t\t\t*slab1_ptr1 = entry1->slab[1];\n+\t\t\t*slab1_ptr2 = entry2->slab[1];\n+\t\t\t*slab1_ptr3 = entry3->slab[1];\n+\t\t}\n+\t}\n+\n+\tif (qinq) {\n+\t\t*slab0_ptr0 = entry0->slab[0];\n+\t\t*slab0_ptr1 = entry1->slab[0];\n+\t\t*slab0_ptr2 = entry2->slab[0];\n+\t\t*slab0_ptr3 = entry3->slab[0];\n+\n+\t\t*slab1_ptr0 = entry0->slab[1];\n+\t\t*slab1_ptr1 = entry1->slab[1];\n+\t\t*slab1_ptr2 = entry2->slab[1];\n+\t\t*slab1_ptr3 = entry3->slab[1];\n+\n+\t\tif (arp == 0) {\n+\t\t\t*slab2_ptr0 = entry0->slab[2];\n+\t\t\t*slab2_ptr1 = entry1->slab[2];\n+\t\t\t*slab2_ptr2 = entry2->slab[2];\n+\t\t\t*slab2_ptr3 = entry3->slab[2];\n+\t\t}\n+\n+\t\tif (qinq_sched) {\n+\t\t\tpkts[0]->hash.sched = sched0;\n+\t\t\tpkts[1]->hash.sched = sched1;\n+\t\t\tpkts[2]->hash.sched = sched2;\n+\t\t\tpkts[3]->hash.sched = sched3;\n+\t\t}\n+\t}\n+\n+\tif (mpls) {\n+\t\tif (mpls_color_mark) {\n+\t\t\tuint64_t mpls_exp0 = rte_bswap64(\n+\t\t\t\t(MPLS_LABEL(0, pkt0_color, 0, 0) << 32) |\n+\t\t\t\tMPLS_LABEL(0, pkt0_color, 0, 0));\n+\t\t\tuint64_t mpls_exp1 = rte_bswap64(\n+\t\t\t\t(MPLS_LABEL(0, pkt1_color, 0, 0) << 32) |\n+\t\t\t\tMPLS_LABEL(0, pkt1_color, 0, 0));\n+\t\t\tuint64_t mpls_exp2 = rte_bswap64(\n+\t\t\t\t(MPLS_LABEL(0, pkt2_color, 0, 0) << 32) |\n+\t\t\t\tMPLS_LABEL(0, pkt2_color, 0, 0));\n+\t\t\tuint64_t mpls_exp3 = rte_bswap64(\n+\t\t\t\t(MPLS_LABEL(0, pkt3_color, 0, 0) << 32) |\n+\t\t\t\tMPLS_LABEL(0, pkt3_color, 0, 0));\n+\n+\t\t\t*slab0_ptr0 = entry0->slab[0] | mpls_exp0;\n+\t\t\t*slab0_ptr1 = entry1->slab[0] | mpls_exp1;\n+\t\t\t*slab0_ptr2 = entry2->slab[0] | mpls_exp2;\n+\t\t\t*slab0_ptr3 = entry3->slab[0] | mpls_exp3;\n+\n+\t\t\t*slab1_ptr0 = entry0->slab[1] | mpls_exp0;\n+\t\t\t*slab1_ptr1 = entry1->slab[1] | mpls_exp1;\n+\t\t\t*slab1_ptr2 = entry2->slab[1] | mpls_exp2;\n+\t\t\t*slab1_ptr3 = entry3->slab[1] | mpls_exp3;\n+\n+\t\t\t*slab2_ptr0 = entry0->slab[2];\n+\t\t\t*slab2_ptr1 = entry1->slab[2];\n+\t\t\t*slab2_ptr2 = entry2->slab[2];\n+\t\t\t*slab2_ptr3 = entry3->slab[2];\n+\t\t} else {\n+\t\t\t*slab0_ptr0 = entry0->slab[0];\n+\t\t\t*slab0_ptr1 = entry1->slab[0];\n+\t\t\t*slab0_ptr2 = entry2->slab[0];\n+\t\t\t*slab0_ptr3 = entry3->slab[0];\n+\n+\t\t\t*slab1_ptr0 = entry0->slab[1];\n+\t\t\t*slab1_ptr1 = entry1->slab[1];\n+\t\t\t*slab1_ptr2 = entry2->slab[1];\n+\t\t\t*slab1_ptr3 = entry3->slab[1];\n+\n+\t\t\t*slab2_ptr0 = entry0->slab[2];\n+\t\t\t*slab2_ptr1 = entry1->slab[2];\n+\t\t\t*slab2_ptr2 = entry2->slab[2];\n+\t\t\t*slab2_ptr3 = entry3->slab[2];\n+\t\t}\n+\n+\t\tif (arp == 0) {\n+\t\t\t*slab3_ptr0 = entry0->slab[3];\n+\t\t\t*slab3_ptr1 = entry1->slab[3];\n+\t\t\t*slab3_ptr2 = entry2->slab[3];\n+\t\t\t*slab3_ptr3 = entry3->slab[3];\n+\t\t}\n+\t}\n+\n+\tif (arp) {\n+\t\tarp_key0->port_id = port_id0;\n+\t\tarp_key1->port_id = port_id1;\n+\t\tarp_key2->port_id = port_id2;\n+\t\tarp_key3->port_id = port_id3;\n+\n+\t\tarp_key0->ip = nh_ip0;\n+\t\tarp_key1->ip = nh_ip1;\n+\t\tarp_key2->ip = nh_ip2;\n+\t\tarp_key3->ip = nh_ip3;\n+\t}\n+}\n+\n+static inline void\n+pkt_work_routing_ether_arp0(\n+\tstruct rte_mbuf *pkt,\n+\tstruct rte_pipeline_table_entry *table_entry,\n+\tvoid *arg)\n+{\n+\tpkt_work_routing(pkt, table_entry, arg, 0, 0, 0, 0, 0);\n+}\n+\n+static inline void\n+pkt_work_routing_ether_arp1(\n+\tstruct rte_mbuf *pkt,\n+\tstruct rte_pipeline_table_entry *table_entry,\n+\tvoid *arg)\n+{\n+\tpkt_work_routing(pkt, table_entry, arg, 1, 0, 0, 0, 0);\n+}\n+\n+static inline void\n+pkt_work_routing_ether_qinq_sched0_arp0(\n+\tstruct rte_mbuf *pkt,\n+\tstruct rte_pipeline_table_entry *table_entry,\n+\tvoid *arg)\n+{\n+\tpkt_work_routing(pkt, table_entry, arg, 0, 1, 0, 0, 0);\n+}\n+\n+static inline void\n+pkt_work_routing_ether_qinq_sched0_arp1(\n+\tstruct rte_mbuf *pkt,\n+\tstruct rte_pipeline_table_entry *table_entry,\n+\tvoid *arg)\n+{\n+\tpkt_work_routing(pkt, table_entry, arg, 1, 1, 0, 0, 0);\n+}\n+\n+static inline void\n+pkt_work_routing_ether_qinq_sched1_arp0(\n+\tstruct rte_mbuf *pkt,\n+\tstruct rte_pipeline_table_entry *table_entry,\n+\tvoid *arg)\n+{\n+\tpkt_work_routing(pkt, table_entry, arg, 0, 1, 1, 0, 0);\n+}\n+\n+static inline void\n+pkt_work_routing_ether_qinq_sched1_arp1(\n+\tstruct rte_mbuf *pkt,\n+\tstruct rte_pipeline_table_entry *table_entry,\n+\tvoid *arg)\n+{\n+\tpkt_work_routing(pkt, table_entry, arg, 1, 1, 1, 0, 0);\n+}\n+\n+static inline void\n+pkt_work_routing_ether_qinq_sched2_arp0(\n+\tstruct rte_mbuf *pkt,\n+\tstruct rte_pipeline_table_entry *table_entry,\n+\tvoid *arg)\n+{\n+\tpkt_work_routing(pkt, table_entry, arg, 0, 1, 2, 0, 0);\n+}\n+\n+static inline void\n+pkt_work_routing_ether_qinq_sched2_arp1(\n+\tstruct rte_mbuf *pkt,\n+\tstruct rte_pipeline_table_entry *table_entry,\n+\tvoid *arg)\n+{\n+\tpkt_work_routing(pkt, table_entry, arg, 1, 1, 2, 0, 0);\n+}\n+\n+static inline void\n+pkt_work_routing_ether_mpls_color0_arp0(\n+\tstruct rte_mbuf *pkt,\n+\tstruct rte_pipeline_table_entry *table_entry,\n+\tvoid *arg)\n+{\n+\tpkt_work_routing(pkt, table_entry, arg, 0, 0, 0, 1, 0);\n+}\n+\n+static inline void\n+pkt_work_routing_ether_mpls_color0_arp1(\n+\tstruct rte_mbuf *pkt,\n+\tstruct rte_pipeline_table_entry *table_entry,\n+\tvoid *arg)\n+{\n+\tpkt_work_routing(pkt, table_entry, arg, 1, 0, 0, 1, 0);\n+}\n+\n+static inline void\n+pkt_work_routing_ether_mpls_color1_arp0(\n+\tstruct rte_mbuf *pkt,\n+\tstruct rte_pipeline_table_entry *table_entry,\n+\tvoid *arg)\n+{\n+\tpkt_work_routing(pkt, table_entry, arg, 0, 0, 0, 1, 1);\n+}\n+\n+static inline void\n+pkt_work_routing_ether_mpls_color1_arp1(\n+\tstruct rte_mbuf *pkt,\n+\tstruct rte_pipeline_table_entry *table_entry,\n+\tvoid *arg)\n+{\n+\tpkt_work_routing(pkt, table_entry, arg, 1, 0, 0, 1, 1);\n+}\n+\n+static inline void\n+pkt4_work_routing_ether_arp0(\n+\tstruct rte_mbuf **pkts,\n+\tstruct rte_pipeline_table_entry **table_entries,\n+\tvoid *arg)\n+{\n+\tpkt4_work_routing(pkts, table_entries, arg, 0, 0, 0, 0, 0);\n+}\n+\n+static inline void\n+pkt4_work_routing_ether_arp1(\n+\tstruct rte_mbuf **pkts,\n+\tstruct rte_pipeline_table_entry **table_entries,\n+\tvoid *arg)\n+{\n+\tpkt4_work_routing(pkts, table_entries, arg, 1, 0, 0, 0, 0);\n+}\n \n-\tuint32_t ip0 = RTE_MBUF_METADATA_UINT32(pkts[0], p_rt->ip_da_offset);\n-\tuint32_t ip1 = RTE_MBUF_METADATA_UINT32(pkts[1], p_rt->ip_da_offset);\n-\tuint32_t ip2 = RTE_MBUF_METADATA_UINT32(pkts[2], p_rt->ip_da_offset);\n-\tuint32_t ip3 = RTE_MBUF_METADATA_UINT32(pkts[3], p_rt->ip_da_offset);\n+static inline void\n+pkt4_work_routing_ether_qinq_sched0_arp0(\n+\tstruct rte_mbuf **pkts,\n+\tstruct rte_pipeline_table_entry **table_entries,\n+\tvoid *arg)\n+{\n+\tpkt4_work_routing(pkts, table_entries, arg, 0, 1, 0, 0, 0);\n+}\n+\n+static inline void\n+pkt4_work_routing_ether_qinq_sched0_arp1(\n+\tstruct rte_mbuf **pkts,\n+\tstruct rte_pipeline_table_entry **table_entries,\n+\tvoid *arg)\n+{\n+\tpkt4_work_routing(pkts, table_entries, arg, 1, 1, 0, 0, 0);\n+}\n+\n+static inline void\n+pkt4_work_routing_ether_qinq_sched1_arp0(\n+\tstruct rte_mbuf **pkts,\n+\tstruct rte_pipeline_table_entry **table_entries,\n+\tvoid *arg)\n+{\n+\tpkt4_work_routing(pkts, table_entries, arg, 0, 1, 1, 0, 0);\n+}\n \n-\tarp_key0->port_id = entry0->port_id;\n-\tarp_key1->port_id = entry1->port_id;\n-\tarp_key2->port_id = entry2->port_id;\n-\tarp_key3->port_id = entry3->port_id;\n+static inline void\n+pkt4_work_routing_ether_qinq_sched1_arp1(\n+\tstruct rte_mbuf **pkts,\n+\tstruct rte_pipeline_table_entry **table_entries,\n+\tvoid *arg)\n+{\n+\tpkt4_work_routing(pkts, table_entries, arg, 1, 1, 1, 0, 0);\n+}\n+\n+static inline void\n+pkt4_work_routing_ether_qinq_sched2_arp0(\n+\tstruct rte_mbuf **pkts,\n+\tstruct rte_pipeline_table_entry **table_entries,\n+\tvoid *arg)\n+{\n+\tpkt4_work_routing(pkts, table_entries, arg, 0, 1, 2, 0, 0);\n+}\n+\n+static inline void\n+pkt4_work_routing_ether_qinq_sched2_arp1(\n+\tstruct rte_mbuf **pkts,\n+\tstruct rte_pipeline_table_entry **table_entries,\n+\tvoid *arg)\n+{\n+\tpkt4_work_routing(pkts, table_entries, arg, 1, 1, 2, 0, 0);\n+}\n \n-\tarp_key0->ip = entry0->ip;\n-\tif (entry0->flags & PIPELINE_ROUTING_ROUTE_LOCAL)\n-\t\tarp_key0->ip = ip0;\n+static inline void\n+pkt4_work_routing_ether_mpls_color0_arp0(\n+\tstruct rte_mbuf **pkts,\n+\tstruct rte_pipeline_table_entry **table_entries,\n+\tvoid *arg)\n+{\n+\tpkt4_work_routing(pkts, table_entries, arg, 0, 0, 0, 1, 0);\n+}\n \n-\tarp_key1->ip = entry1->ip;\n-\tif (entry1->flags & PIPELINE_ROUTING_ROUTE_LOCAL)\n-\t\tarp_key1->ip = ip1;\n+static inline void\n+pkt4_work_routing_ether_mpls_color0_arp1(\n+\tstruct rte_mbuf **pkts,\n+\tstruct rte_pipeline_table_entry **table_entries,\n+\tvoid *arg)\n+{\n+\tpkt4_work_routing(pkts, table_entries, arg, 1, 0, 0, 1, 0);\n+}\n \n-\tarp_key2->ip = entry2->ip;\n-\tif (entry2->flags & PIPELINE_ROUTING_ROUTE_LOCAL)\n-\t\tarp_key2->ip = ip2;\n+static inline void\n+pkt4_work_routing_ether_mpls_color1_arp0(\n+\tstruct rte_mbuf **pkts,\n+\tstruct rte_pipeline_table_entry **table_entries,\n+\tvoid *arg)\n+{\n+\tpkt4_work_routing(pkts, table_entries, arg, 0, 0, 0, 1, 1);\n+}\n \n-\tarp_key3->ip = entry3->ip;\n-\tif (entry3->flags & PIPELINE_ROUTING_ROUTE_LOCAL)\n-\t\tarp_key3->ip = ip3;\n+static inline void\n+pkt4_work_routing_ether_mpls_color1_arp1(\n+\tstruct rte_mbuf **pkts,\n+\tstruct rte_pipeline_table_entry **table_entries,\n+\tvoid *arg)\n+{\n+\tpkt4_work_routing(pkts, table_entries, arg, 1, 0, 0, 1, 1);\n }\n \n-PIPELINE_TABLE_AH_HIT(routing_table_ah_hit,\n-\tpkt_work_routing,\n-\tpkt4_work_routing);\n+PIPELINE_TABLE_AH_HIT(routing_table_ah_hit_ether_arp0,\n+\tpkt_work_routing_ether_arp0,\n+\tpkt4_work_routing_ether_arp0);\n+\n+PIPELINE_TABLE_AH_HIT(routing_table_ah_hit_ether_arp1,\n+\tpkt_work_routing_ether_arp1,\n+\tpkt4_work_routing_ether_arp1);\n+\n+PIPELINE_TABLE_AH_HIT(routing_table_ah_hit_ether_qinq_sched0_arp0,\n+\tpkt_work_routing_ether_qinq_sched0_arp0,\n+\tpkt4_work_routing_ether_qinq_sched0_arp0);\n+\n+PIPELINE_TABLE_AH_HIT(routing_table_ah_hit_ether_qinq_sched0_arp1,\n+\tpkt_work_routing_ether_qinq_sched0_arp1,\n+\tpkt4_work_routing_ether_qinq_sched0_arp1);\n+\n+PIPELINE_TABLE_AH_HIT(routing_table_ah_hit_ether_qinq_sched1_arp0,\n+\tpkt_work_routing_ether_qinq_sched1_arp0,\n+\tpkt4_work_routing_ether_qinq_sched1_arp0);\n+\n+PIPELINE_TABLE_AH_HIT(routing_table_ah_hit_ether_qinq_sched1_arp1,\n+\tpkt_work_routing_ether_qinq_sched1_arp1,\n+\tpkt4_work_routing_ether_qinq_sched1_arp1);\n+\n+PIPELINE_TABLE_AH_HIT(routing_table_ah_hit_ether_qinq_sched2_arp0,\n+\tpkt_work_routing_ether_qinq_sched2_arp0,\n+\tpkt4_work_routing_ether_qinq_sched2_arp0);\n+\n+PIPELINE_TABLE_AH_HIT(routing_table_ah_hit_ether_qinq_sched2_arp1,\n+\tpkt_work_routing_ether_qinq_sched2_arp1,\n+\tpkt4_work_routing_ether_qinq_sched2_arp1);\n+\n+PIPELINE_TABLE_AH_HIT(routing_table_ah_hit_ether_mpls_color0_arp0,\n+\tpkt_work_routing_ether_mpls_color0_arp0,\n+\tpkt4_work_routing_ether_mpls_color0_arp0);\n+\n+PIPELINE_TABLE_AH_HIT(routing_table_ah_hit_ether_mpls_color0_arp1,\n+\tpkt_work_routing_ether_mpls_color0_arp1,\n+\tpkt4_work_routing_ether_mpls_color0_arp1);\n+\n+PIPELINE_TABLE_AH_HIT(routing_table_ah_hit_ether_mpls_color1_arp0,\n+\tpkt_work_routing_ether_mpls_color1_arp0,\n+\tpkt4_work_routing_ether_mpls_color1_arp0);\n+\n+PIPELINE_TABLE_AH_HIT(routing_table_ah_hit_ether_mpls_color1_arp1,\n+\tpkt_work_routing_ether_mpls_color1_arp1,\n+\tpkt4_work_routing_ether_mpls_color1_arp1);\n+\n+static rte_pipeline_table_action_handler_hit\n+get_routing_table_ah_hit(struct pipeline_routing *p)\n+{\n+\tif ((p->params.qinq == 0) &&\n+\t\t(p->params.mpls == 0) &&\n+\t\t(p->params.arp == 0))\n+\t\treturn routing_table_ah_hit_ether_arp0;\n+\n+\tif ((p->params.qinq == 0) &&\n+\t\t(p->params.mpls == 0) &&\n+\t\t(p->params.arp == 1))\n+\t\treturn routing_table_ah_hit_ether_arp1;\n+\n+\tif ((p->params.qinq == 1) &&\n+\t\t(p->params.qinq_sched == 0) &&\n+\t\t(p->params.mpls == 0) &&\n+\t\t(p->params.arp == 0))\n+\t\treturn routing_table_ah_hit_ether_qinq_sched0_arp0;\n+\n+\tif ((p->params.qinq == 1) &&\n+\t\t(p->params.qinq_sched == 0) &&\n+\t\t(p->params.mpls == 0) &&\n+\t\t(p->params.arp == 1))\n+\t\treturn routing_table_ah_hit_ether_qinq_sched0_arp1;\n+\n+\tif ((p->params.qinq == 1) &&\n+\t\t(p->params.qinq_sched == 1) &&\n+\t\t(p->params.mpls == 0) &&\n+\t\t(p->params.arp == 0))\n+\t\treturn routing_table_ah_hit_ether_qinq_sched1_arp0;\n+\n+\tif ((p->params.qinq == 1) &&\n+\t\t(p->params.qinq_sched == 1) &&\n+\t\t(p->params.mpls == 0) &&\n+\t\t(p->params.arp == 1))\n+\t\treturn routing_table_ah_hit_ether_qinq_sched1_arp1;\n+\n+\tif ((p->params.qinq == 1) &&\n+\t\t(p->params.qinq_sched == 2) &&\n+\t\t(p->params.mpls == 0) &&\n+\t\t(p->params.arp == 0))\n+\t\treturn routing_table_ah_hit_ether_qinq_sched2_arp0;\n+\n+\tif ((p->params.qinq == 1) &&\n+\t\t(p->params.qinq_sched == 2) &&\n+\t\t(p->params.mpls == 0) &&\n+\t\t(p->params.arp == 1))\n+\t\treturn routing_table_ah_hit_ether_qinq_sched2_arp1;\n+\n+\tif ((p->params.qinq == 0) &&\n+\t\t(p->params.mpls == 1) &&\n+\t\t(p->params.mpls_color_mark == 0) &&\n+\t\t(p->params.arp == 0))\n+\t\treturn routing_table_ah_hit_ether_mpls_color0_arp0;\n+\n+\tif ((p->params.qinq == 0) &&\n+\t\t(p->params.mpls == 1) &&\n+\t\t(p->params.mpls_color_mark == 0) &&\n+\t\t(p->params.arp == 1))\n+\t\treturn routing_table_ah_hit_ether_mpls_color0_arp1;\n+\n+\tif ((p->params.qinq == 0) &&\n+\t\t(p->params.mpls == 1) &&\n+\t\t(p->params.mpls_color_mark == 1) &&\n+\t\t(p->params.arp == 0))\n+\t\treturn routing_table_ah_hit_ether_mpls_color1_arp0;\n+\n+\tif ((p->params.qinq == 0) &&\n+\t\t(p->params.mpls == 1) &&\n+\t\t(p->params.mpls_color_mark == 1) &&\n+\t\t(p->params.arp == 1))\n+\t\treturn routing_table_ah_hit_ether_mpls_color1_arp1;\n+\n+\treturn NULL;\n+}\n \n /*\n  * ARP table\n@@ -229,6 +1000,9 @@ struct arp_table_entry {\n \tuint64_t macaddr;\n };\n \n+/**\n+ * ARP table AH\n+ */\n static inline void\n pkt_work_arp(\n \tstruct rte_mbuf *pkt,\n@@ -237,20 +1011,15 @@ pkt_work_arp(\n {\n \tstruct arp_table_entry *entry = (struct arp_table_entry *) table_entry;\n \n-\t/* Read: pkt buffer - mbuf */\n-\tuint8_t *raw = rte_pktmbuf_mtod(pkt, uint8_t *);\n+\t/* Read */\n+\tuint64_t macaddr_dst = entry->macaddr;\n+\tuint64_t *slab_ptr = (uint64_t *) ((char *) pkt->buf_addr +\n+\t\t(pkt->data_off - 2));\n \n-\t/* Read: table entry */\n-\tuint64_t mac_addr_dst = entry->macaddr;\n-\tuint64_t mac_addr_src = 0;\n+\t/* Compute */\n \n-\t/* Compute: Ethernet header */\n-\tuint64_t slab0 = mac_addr_dst | (mac_addr_src << 48);\n-\tuint32_t slab1 = mac_addr_src >> 16;\n-\n-\t/* Write: pkt buffer - pkt headers */\n-\t*((uint64_t *) raw) = slab0;\n-\t*((uint32_t *) (raw + 8)) = slab1;\n+\t/* Write */\n+\t*slab_ptr = macaddr_dst;\n }\n \n static inline void\n@@ -268,59 +1037,56 @@ pkt4_work_arp(\n \tstruct arp_table_entry *entry3 =\n \t\t(struct arp_table_entry *) table_entries[3];\n \n-\t/* Read: pkt buffer - mbuf */\n-\tuint8_t *raw0 = rte_pktmbuf_mtod(pkts[0], uint8_t *);\n-\tuint8_t *raw1 = rte_pktmbuf_mtod(pkts[1], uint8_t *);\n-\tuint8_t *raw2 = rte_pktmbuf_mtod(pkts[2], uint8_t *);\n-\tuint8_t *raw3 = rte_pktmbuf_mtod(pkts[3], uint8_t *);\n-\n-\t/* Read: table entry */\n-\tuint64_t mac_addr_dst0 = entry0->macaddr;\n-\tuint64_t mac_addr_dst1 = entry1->macaddr;\n-\tuint64_t mac_addr_dst2 = entry2->macaddr;\n-\tuint64_t mac_addr_dst3 = entry3->macaddr;\n-\n-\tuint64_t mac_addr_src0 = 0;\n-\tuint64_t mac_addr_src1 = 0;\n-\tuint64_t mac_addr_src2 = 0;\n-\tuint64_t mac_addr_src3 = 0;\n-\n-\t/* Compute: Ethernet header */\n-\tuint64_t pkt0_slab0 = mac_addr_dst0 | (mac_addr_src0 << 48);\n-\tuint64_t pkt1_slab0 = mac_addr_dst1 | (mac_addr_src1 << 48);\n-\tuint64_t pkt2_slab0 = mac_addr_dst2 | (mac_addr_src2 << 48);\n-\tuint64_t pkt3_slab0 = mac_addr_dst3 | (mac_addr_src3 << 48);\n-\n-\tuint32_t pkt0_slab1 = mac_addr_src0 >> 16;\n-\tuint32_t pkt1_slab1 = mac_addr_src1 >> 16;\n-\tuint32_t pkt2_slab1 = mac_addr_src2 >> 16;\n-\tuint32_t pkt3_slab1 = mac_addr_src3 >> 16;\n-\n-\t/* Write: pkt buffer - pkt headers */\n-\t*((uint64_t *) raw0) = pkt0_slab0;\n-\t*((uint32_t *) (raw0 + 8)) = pkt0_slab1;\n-\t*((uint64_t *) raw1) = pkt1_slab0;\n-\t*((uint32_t *) (raw1 + 8)) = pkt1_slab1;\n-\t*((uint64_t *) raw2) = pkt2_slab0;\n-\t*((uint32_t *) (raw2 + 8)) = pkt2_slab1;\n-\t*((uint64_t *) raw3) = pkt3_slab0;\n-\t*((uint32_t *) (raw3 + 8)) = pkt3_slab1;\n+\t/* Read */\n+\tuint64_t macaddr_dst0 = entry0->macaddr;\n+\tuint64_t macaddr_dst1 = entry1->macaddr;\n+\tuint64_t macaddr_dst2 = entry2->macaddr;\n+\tuint64_t macaddr_dst3 = entry3->macaddr;\n+\n+\tuint64_t *slab_ptr0 = (uint64_t *) ((char *) pkts[0]->buf_addr +\n+\t\t(pkts[0]->data_off - 2));\n+\tuint64_t *slab_ptr1 = (uint64_t *) ((char *) pkts[1]->buf_addr +\n+\t\t(pkts[1]->data_off - 2));\n+\tuint64_t *slab_ptr2 = (uint64_t *) ((char *) pkts[2]->buf_addr +\n+\t\t(pkts[2]->data_off - 2));\n+\tuint64_t *slab_ptr3 = (uint64_t *) ((char *) pkts[3]->buf_addr +\n+\t\t(pkts[3]->data_off - 2));\n+\n+\t/* Compute */\n+\n+\t/* Write */\n+\t*slab_ptr0 = macaddr_dst0;\n+\t*slab_ptr1 = macaddr_dst1;\n+\t*slab_ptr2 = macaddr_dst2;\n+\t*slab_ptr3 = macaddr_dst3;\n }\n \n PIPELINE_TABLE_AH_HIT(arp_table_ah_hit,\n \tpkt_work_arp,\n \tpkt4_work_arp);\n \n-static int\n-pipeline_routing_parse_args(struct pipeline_routing *p,\n+/*\n+ * Argument parsing\n+ */\n+int\n+pipeline_routing_parse_args(struct pipeline_routing_params *p,\n \tstruct pipeline_params *params)\n {\n \tuint32_t n_routes_present = 0;\n \tuint32_t n_arp_entries_present = 0;\n-\tuint32_t ip_da_offset_present = 0;\n+\tuint32_t ip_hdr_offset_present = 0;\n \tuint32_t arp_key_offset_present = 0;\n+\tuint32_t l2_present = 0;\n+\tuint32_t qinq_sched_present = 0;\n+\tuint32_t mpls_color_mark_present = 0;\n+\tuint32_t color_offset_present = 0;\n \tuint32_t i;\n \n+\t/* default values */\n+\tp->arp = 0;\n+\tp->qinq_sched = 0;\n+\tp->mpls_color_mark = 0;\n+\n \tfor (i = 0; i < params->n_args; i++) {\n \t\tchar *arg_name = params->args_name[i];\n \t\tchar *arg_value = params->args_value[i];\n@@ -338,12 +1104,26 @@ pipeline_routing_parse_args(struct pipeline_routing *p,\n \t\t\tcontinue;\n \t\t}\n \n+\t\t/* ip_hdr_offset */\n+\t\tif (strcmp(arg_name, \"ip_hdr_offset\") == 0) {\n+\t\t\tif (ip_hdr_offset_present)\n+\t\t\t\treturn -1;\n+\t\t\tip_hdr_offset_present = 1;\n+\n+\t\t\tp->ip_hdr_offset = atoi(arg_value);\n+\t\t\tp->ip_da_offset = p->ip_hdr_offset +\n+\t\t\t\t__builtin_offsetof(struct ipv4_hdr, dst_addr);\n+\n+\t\t\tcontinue;\n+\t\t}\n+\n \t\t/* n_arp_entries */\n \t\tif (strcmp(arg_name, \"n_arp_entries\") == 0) {\n \t\t\tif (n_arp_entries_present)\n \t\t\t\treturn -1;\n \t\t\tn_arp_entries_present = 1;\n \n+\t\t\tp->arp = 1;\n \t\t\tp->n_arp_entries = atoi(arg_value);\n \t\t\tif (p->n_arp_entries == 0)\n \t\t\t\treturn -1;\n@@ -351,24 +1131,84 @@ pipeline_routing_parse_args(struct pipeline_routing *p,\n \t\t\tcontinue;\n \t\t}\n \n-\t\t/* ip_da_offset */\n-\t\tif (strcmp(arg_name, \"ip_da_offset\") == 0) {\n-\t\t\tif (ip_da_offset_present)\n+\t\t/* arp_key_offset */\n+\t\tif (strcmp(arg_name, \"arp_key_offset\") == 0) {\n+\t\t\tif (arp_key_offset_present)\n \t\t\t\treturn -1;\n-\t\t\tip_da_offset_present = 1;\n+\t\t\tarp_key_offset_present = 1;\n \n-\t\t\tp->ip_da_offset = atoi(arg_value);\n+\t\t\tp->arp = 1;\n+\t\t\tp->arp_key_offset = atoi(arg_value);\n \n \t\t\tcontinue;\n \t\t}\n \n-\t\t/* arp_key_offset */\n-\t\tif (strcmp(arg_name, \"arp_key_offset\") == 0) {\n-\t\t\tif (arp_key_offset_present)\n+\t\t/* l2 */\n+\t\tif (strcmp(arg_name, \"l2\") == 0) {\n+\t\t\tif (l2_present)\n \t\t\t\treturn -1;\n-\t\t\tarp_key_offset_present = 1;\n+\t\t\tl2_present = 1;\n+\n+\t\t\t/* qinq */\n+\t\t\tif (strcmp(arg_value, \"qinq\") == 0) {\n+\t\t\t\tp->qinq = 1;\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\n+\t\t\t/* mpls */\n+\t\t\tif (strcmp(arg_value, \"mpls\") == 0) {\n+\t\t\t\tp->mpls = 1;\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\n+\t\t\t/* any other */\n+\t\t\treturn -1;\n+\t\t}\n \n-\t\t\tp->arp_key_offset = atoi(arg_value);\n+\t\t/* qinq_sched */\n+\t\tif (strcmp(arg_name, \"qinq_sched\") == 0) {\n+\t\t\tif (qinq_sched_present)\n+\t\t\t\treturn -1;\n+\n+\t\t\tqinq_sched_present = 1;\n+\n+\t\t\tif (strcmp(arg_value, \"no\") == 0)\n+\t\t\t\tp->qinq_sched = 0;\n+\t\t\telse if (strcmp(arg_value, \"yes\") == 0)\n+\t\t\t\tp->qinq_sched = 1;\n+\t\t\telse if (strcmp(arg_value, \"test\") == 0)\n+\t\t\t\tp->qinq_sched = 2;\n+\t\t\telse\n+\t\t\t\treturn -1;\n+\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\t/* mpls_color_mark */\n+\t\tif (strcmp(arg_name, \"mpls_color_mark\") == 0) {\n+\t\t\tif (mpls_color_mark_present)\n+\t\t\t\treturn -1;\n+\n+\t\t\tmpls_color_mark_present = 1;\n+\n+\t\t\tif (strcmp(arg_value, \"no\") == 0)\n+\t\t\t\tp->mpls_color_mark = 0;\n+\t\t\telse if (strcmp(arg_value, \"yes\") == 0)\n+\t\t\t\tp->mpls_color_mark = 1;\n+\t\t\telse\n+\t\t\t\treturn -1;\n+\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\t/* color_offset */\n+\t\tif (strcmp(arg_name, \"color_offset\") == 0) {\n+\t\t\tif (color_offset_present)\n+\t\t\t\treturn -1;\n+\n+\t\t\tcolor_offset_present = 1;\n+\n+\t\t\tp->color_offset = atoi(arg_value);\n \n \t\t\tcontinue;\n \t\t}\n@@ -379,9 +1219,19 @@ pipeline_routing_parse_args(struct pipeline_routing *p,\n \n \t/* Check that mandatory arguments are present */\n \tif ((n_routes_present == 0) ||\n-\t\t(n_arp_entries_present == 0) ||\n-\t\t(ip_da_offset_present == 0) ||\n-\t\t(n_arp_entries_present && (arp_key_offset_present == 0)))\n+\t\t(ip_hdr_offset_present == 0) ||\n+\t\t(n_arp_entries_present && (arp_key_offset_present == 0)) ||\n+\t\t((n_arp_entries_present == 0) && arp_key_offset_present))\n+\t\treturn -1;\n+\n+\t/* Check relations between arguments */\n+\tif ((p->qinq == 0) && qinq_sched_present)\n+\t\treturn -1;\n+\n+\tif (((p->mpls == 0) && (mpls_color_mark_present ||\n+\t\tcolor_offset_present)) ||\n+\t\t((mpls_color_mark_present == 0) && color_offset_present) ||\n+\t\t(mpls_color_mark_present && (color_offset_present == 0)))\n \t\treturn -1;\n \n \treturn 0;\n@@ -414,7 +1264,7 @@ pipeline_routing_init(struct pipeline_params *params,\n \tPLOG(p, HIGH, \"Routing\");\n \n \t/* Parse arguments */\n-\tif (pipeline_routing_parse_args(p_rt, params))\n+\tif (pipeline_routing_parse_args(&p_rt->params, params))\n \t\treturn NULL;\n \n \t/* Pipeline */\n@@ -484,15 +1334,15 @@ pipeline_routing_init(struct pipeline_params *params,\n \tp->n_tables = 1;\n \t{\n \t\tstruct rte_table_lpm_params table_lpm_params = {\n-\t\t\t.n_rules = p_rt->n_routes,\n+\t\t\t.n_rules = p_rt->params.n_routes,\n \t\t\t.entry_unique_size = sizeof(struct routing_table_entry),\n-\t\t\t.offset = p_rt->ip_da_offset,\n+\t\t\t.offset = p_rt->params.ip_da_offset,\n \t\t};\n \n \t\tstruct rte_pipeline_table_params table_params = {\n \t\t\t\t.ops = &rte_table_lpm_ops,\n \t\t\t\t.arg_create = &table_lpm_params,\n-\t\t\t\t.f_action_hit = routing_table_ah_hit,\n+\t\t\t\t.f_action_hit = get_routing_table_ah_hit(p_rt),\n \t\t\t\t.f_action_miss = NULL,\n \t\t\t\t.arg_ah = p_rt,\n \t\t\t\t.action_data_size =\n@@ -514,14 +1364,14 @@ pipeline_routing_init(struct pipeline_params *params,\n \t}\n \n \t/* ARP table configuration */\n-\tif (p_rt->n_arp_entries) {\n+\tif (p_rt->params.arp) {\n \t\tstruct rte_table_hash_key8_ext_params table_arp_params = {\n-\t\t\t.n_entries = p_rt->n_arp_entries,\n-\t\t\t.n_entries_ext = p_rt->n_arp_entries,\n+\t\t\t.n_entries = p_rt->params.n_arp_entries,\n+\t\t\t.n_entries_ext = p_rt->params.n_arp_entries,\n \t\t\t.f_hash = hash_default_key8,\n \t\t\t.seed = 0,\n \t\t\t.signature_offset = 0, /* Unused */\n-\t\t\t.key_offset = p_rt->arp_key_offset,\n+\t\t\t.key_offset = p_rt->params.arp_key_offset,\n \t\t};\n \n \t\tstruct rte_pipeline_table_params table_params = {\n@@ -665,6 +1515,7 @@ pipeline_routing_msg_req_custom_handler(struct pipeline *p,\n void *\n pipeline_routing_msg_req_route_add_handler(struct pipeline *p, void *msg)\n {\n+\tstruct pipeline_routing *p_rt = (struct pipeline_routing *) p;\n \tstruct pipeline_routing_route_add_msg_req *req = msg;\n \tstruct pipeline_routing_route_add_msg_rsp *rsp = msg;\n \n@@ -673,26 +1524,321 @@ pipeline_routing_msg_req_route_add_handler(struct pipeline *p, void *msg)\n \t\t.depth = req->key.key.ipv4.depth,\n \t};\n \n-\tstruct routing_table_entry entry = {\n+\tstruct routing_table_entry entry_arp0 = {\n+\t\t.head = {\n+\t\t\t.action = RTE_PIPELINE_ACTION_PORT,\n+\t\t\t{.port_id = p->port_out_id[req->data.port_id]},\n+\t\t},\n+\n+\t\t.flags = req->data.flags,\n+\t\t.port_id = req->data.port_id,\n+\t\t.ip = 0,\n+\t\t.data_offset = 0,\n+\t\t.ether_l2_length = 0,\n+\t\t.slab = {0},\n+\t\t.slab_offset = {0},\n+\t};\n+\n+\tstruct routing_table_entry entry_arp1 = {\n \t\t.head = {\n \t\t\t.action = RTE_PIPELINE_ACTION_TABLE,\n \t\t\t{.table_id = p->table_id[1]},\n \t\t},\n \n-\t\t.flags = req->flags,\n-\t\t.port_id = req->port_id,\n-\t\t.ip = rte_bswap32(req->ip),\n+\t\t.flags = req->data.flags,\n+\t\t.port_id = req->data.port_id,\n+\t\t.ip = rte_bswap32(req->data.ethernet.ip),\n+\t\t.data_offset = 0,\n+\t\t.ether_l2_length = 0,\n+\t\t.slab = {0},\n+\t\t.slab_offset = {0},\n \t};\n \n-\tif (req->key.type != PIPELINE_ROUTING_ROUTE_IPV4) {\n+\tstruct rte_pipeline_table_entry *entry = (p_rt->params.arp) ?\n+\t\t(struct rte_pipeline_table_entry *) &entry_arp1 :\n+\t\t(struct rte_pipeline_table_entry *) &entry_arp0;\n+\n+\tif ((req->key.type != PIPELINE_ROUTING_ROUTE_IPV4) ||\n+\t\t((p_rt->params.arp == 0) &&\n+\t\t(req->data.flags & PIPELINE_ROUTING_ROUTE_ARP)) ||\n+\t\t(p_rt->params.arp &&\n+\t\t((req->data.flags & PIPELINE_ROUTING_ROUTE_ARP) == 0)) ||\n+\t\t((p_rt->params.qinq == 0) &&\n+\t\t(req->data.flags & PIPELINE_ROUTING_ROUTE_QINQ)) ||\n+\t\t(p_rt->params.qinq &&\n+\t\t((req->data.flags & PIPELINE_ROUTING_ROUTE_QINQ) == 0)) ||\n+\t\t((p_rt->params.mpls == 0) &&\n+\t\t(req->data.flags & PIPELINE_ROUTING_ROUTE_MPLS)) ||\n+\t\t(p_rt->params.mpls &&\n+\t\t((req->data.flags & PIPELINE_ROUTING_ROUTE_MPLS) == 0))) {\n+\n \t\trsp->status = -1;\n \t\treturn rsp;\n \t}\n \n+\t/* Ether - ARP off */\n+\tif ((p_rt->params.qinq == 0) &&\n+\t\t(p_rt->params.mpls == 0) &&\n+\t\t(p_rt->params.arp == 0)) {\n+\n+\t\tuint64_t macaddr_src = 0x112233445566;\n+\t\tuint64_t macaddr_dst;\n+\t\tuint64_t ethertype = ETHER_TYPE_IPv4;\n+\n+\t\t*((struct ether_addr *) &macaddr_dst) =\n+\t\t\treq->data.ethernet.macaddr;\n+\t\tmacaddr_dst = rte_bswap64(macaddr_dst << 16);\n+\n+\t\tentry_arp0.slab[0] =\n+\t\t\trte_bswap64((macaddr_src << 16) | ethertype);\n+\t\tentry_arp0.slab_offset[0] = p_rt->params.ip_hdr_offset - 8;\n+\n+\t\tentry_arp0.slab[1] = rte_bswap64(macaddr_dst);\n+\t\tentry_arp0.slab_offset[1] = p_rt->params.ip_hdr_offset - 2 * 8;\n+\n+\t\tentry_arp0.data_offset = entry_arp0.slab_offset[1] + 2;\n+\t\tentry_arp0.ether_l2_length = 14;\n+\t}\n+\n+\t/* Ether - ARP on */\n+\tif ((p_rt->params.qinq == 0) && (p_rt->params.mpls == 0) &&\n+\t\tp_rt->params.arp) {\n+\t\tuint64_t macaddr_src = 0x112233445566;\n+\t\tuint64_t ethertype = ETHER_TYPE_IPv4;\n+\n+\t\tentry_arp1.slab[0] = rte_bswap64((macaddr_src << 16) |\n+\t\t\tethertype);\n+\t\tentry_arp1.slab_offset[0] = p_rt->params.ip_hdr_offset - 8;\n+\n+\t\tentry_arp1.data_offset = entry_arp1.slab_offset[0] - 6;\n+\t\tentry_arp1.ether_l2_length = 14;\n+\t}\n+\n+\t/* Ether QinQ - ARP off */\n+\tif ((p_rt->params.qinq == 1) && (p_rt->params.mpls == 0) &&\n+\t\t(p_rt->params.arp == 0)) {\n+\t\tuint64_t macaddr_src = 0x112233445566;\n+\t\tuint64_t macaddr_dst;\n+\t\tuint64_t ethertype_ipv4 = ETHER_TYPE_IPv4;\n+\t\tuint64_t ethertype_vlan = 0x8100;\n+\t\tuint64_t ethertype_qinq = 0x9100;\n+\t\tuint64_t svlan = req->data.l2.qinq.svlan;\n+\t\tuint64_t cvlan = req->data.l2.qinq.cvlan;\n+\n+\t\t*((struct ether_addr *) &macaddr_dst) =\n+\t\t\treq->data.ethernet.macaddr;\n+\t\tmacaddr_dst = rte_bswap64(macaddr_dst << 16);\n+\n+\t\tentry_arp0.slab[0] = rte_bswap64((svlan << 48) |\n+\t\t\t(ethertype_vlan << 32) |\n+\t\t\t(cvlan << 16) |\n+\t\t\tethertype_ipv4);\n+\t\tentry_arp0.slab_offset[0] = p_rt->params.ip_hdr_offset - 8;\n+\n+\t\tentry_arp0.slab[1] = rte_bswap64((macaddr_src << 16) |\n+\t\t\tethertype_qinq);\n+\t\tentry_arp0.slab_offset[1] = p_rt->params.ip_hdr_offset - 2 * 8;\n+\n+\t\tentry_arp0.slab[2] = rte_bswap64(macaddr_dst);\n+\t\tentry_arp0.slab_offset[2] = p_rt->params.ip_hdr_offset - 3 * 8;\n+\n+\t\tentry_arp0.data_offset = entry_arp0.slab_offset[2] + 2;\n+\t\tentry_arp0.ether_l2_length = 22;\n+\t}\n+\n+\t/* Ether QinQ - ARP on */\n+\tif ((p_rt->params.qinq == 1) && (p_rt->params.mpls == 0) &&\n+\t\tp_rt->params.arp) {\n+\t\tuint64_t macaddr_src = 0x112233445566;\n+\t\tuint64_t ethertype_ipv4 = ETHER_TYPE_IPv4;\n+\t\tuint64_t ethertype_vlan = 0x8100;\n+\t\tuint64_t ethertype_qinq = 0x9100;\n+\t\tuint64_t svlan = req->data.l2.qinq.svlan;\n+\t\tuint64_t cvlan = req->data.l2.qinq.cvlan;\n+\n+\t\tentry_arp1.slab[0] = rte_bswap64((svlan << 48) |\n+\t\t\t(ethertype_vlan << 32) |\n+\t\t\t(cvlan << 16) |\n+\t\t\tethertype_ipv4);\n+\t\tentry_arp1.slab_offset[0] = p_rt->params.ip_hdr_offset - 8;\n+\n+\t\tentry_arp1.slab[1] = rte_bswap64((macaddr_src << 16) |\n+\t\t\tethertype_qinq);\n+\t\tentry_arp1.slab_offset[1] = p_rt->params.ip_hdr_offset - 2 * 8;\n+\n+\t\tentry_arp1.data_offset = entry_arp1.slab_offset[1] - 6;\n+\t\tentry_arp1.ether_l2_length = 22;\n+\t}\n+\n+\t/* Ether MPLS - ARP off */\n+\tif ((p_rt->params.qinq == 0) &&\n+\t\t(p_rt->params.mpls == 1) &&\n+\t\t(p_rt->params.arp == 0)) {\n+\t\tuint64_t macaddr_src = 0x112233445566;\n+\t\tuint64_t macaddr_dst;\n+\t\tuint64_t ethertype_mpls = 0x8847;\n+\n+\t\tuint64_t label0 = req->data.l2.mpls.labels[0];\n+\t\tuint64_t label1 = req->data.l2.mpls.labels[1];\n+\t\tuint64_t label2 = req->data.l2.mpls.labels[2];\n+\t\tuint64_t label3 = req->data.l2.mpls.labels[3];\n+\t\tuint32_t n_labels = req->data.l2.mpls.n_labels;\n+\n+\t\t*((struct ether_addr *) &macaddr_dst) =\n+\t\t\treq->data.ethernet.macaddr;\n+\t\tmacaddr_dst = rte_bswap64(macaddr_dst << 16);\n+\n+\t\tswitch (n_labels) {\n+\t\tcase 1:\n+\t\t\tentry_arp0.slab[0] = 0;\n+\t\t\tentry_arp0.slab_offset[0] =\n+\t\t\t\tp_rt->params.ip_hdr_offset - 8;\n+\n+\t\t\tentry_arp0.slab[1] = rte_bswap64(\n+\t\t\t\tMPLS_LABEL(label0, 0, 1, 0));\n+\t\t\tentry_arp0.slab_offset[1] =\n+\t\t\t\tp_rt->params.ip_hdr_offset - 8;\n+\t\t\tbreak;\n+\n+\t\tcase 2:\n+\t\t\tentry_arp0.slab[0] = 0;\n+\t\t\tentry_arp0.slab_offset[0] =\n+\t\t\t\tp_rt->params.ip_hdr_offset - 8;\n+\n+\t\t\tentry_arp0.slab[1] = rte_bswap64(\n+\t\t\t\t(MPLS_LABEL(label0, 0, 0, 0) << 32) |\n+\t\t\t\tMPLS_LABEL(label1, 0, 1, 0));\n+\t\t\tentry_arp0.slab_offset[1] =\n+\t\t\t\tp_rt->params.ip_hdr_offset - 8;\n+\t\t\tbreak;\n+\n+\t\tcase 3:\n+\t\t\tentry_arp0.slab[0] = rte_bswap64(\n+\t\t\t\t(MPLS_LABEL(label1, 0, 0, 0) << 32) |\n+\t\t\t\tMPLS_LABEL(label2, 0, 1, 0));\n+\t\t\tentry_arp0.slab_offset[0] =\n+\t\t\t\tp_rt->params.ip_hdr_offset - 8;\n+\n+\t\t\tentry_arp0.slab[1] = rte_bswap64(\n+\t\t\t\tMPLS_LABEL(label0, 0, 0, 0));\n+\t\t\tentry_arp0.slab_offset[1] =\n+\t\t\t\tp_rt->params.ip_hdr_offset - 2 * 8;\n+\t\t\tbreak;\n+\n+\t\tcase 4:\n+\t\t\tentry_arp0.slab[0] = rte_bswap64(\n+\t\t\t\t(MPLS_LABEL(label2, 0, 0, 0) << 32) |\n+\t\t\t\tMPLS_LABEL(label3, 0, 1, 0));\n+\t\t\tentry_arp0.slab_offset[0] =\n+\t\t\t\tp_rt->params.ip_hdr_offset - 8;\n+\n+\t\t\tentry_arp0.slab[1] = rte_bswap64(\n+\t\t\t\t(MPLS_LABEL(label0, 0, 0, 0) << 32) |\n+\t\t\t\tMPLS_LABEL(label1, 0, 0, 0));\n+\t\t\tentry_arp0.slab_offset[1] =\n+\t\t\t\tp_rt->params.ip_hdr_offset - 2 * 8;\n+\t\t\tbreak;\n+\n+\t\tdefault:\n+\t\t\trsp->status = -1;\n+\t\t\treturn rsp;\n+\t\t}\n+\n+\t\tentry_arp0.slab[2] = rte_bswap64((macaddr_src << 16) |\n+\t\t\tethertype_mpls);\n+\t\tentry_arp0.slab_offset[2] = p_rt->params.ip_hdr_offset -\n+\t\t\t(n_labels * 4 + 8);\n+\n+\t\tentry_arp0.slab[3] = rte_bswap64(macaddr_dst);\n+\t\tentry_arp0.slab_offset[3] = p_rt->params.ip_hdr_offset -\n+\t\t\t(n_labels * 4 + 2 * 8);\n+\n+\t\tentry_arp0.data_offset = entry_arp0.slab_offset[3] + 2;\n+\t\tentry_arp0.ether_l2_length = n_labels * 4 + 14;\n+\t}\n+\n+\t/* Ether MPLS - ARP on */\n+\tif ((p_rt->params.qinq == 0) &&\n+\t\t(p_rt->params.mpls == 1) &&\n+\t\tp_rt->params.arp) {\n+\t\tuint64_t macaddr_src = 0x112233445566;\n+\t\tuint64_t ethertype_mpls = 0x8847;\n+\n+\t\tuint64_t label0 = req->data.l2.mpls.labels[0];\n+\t\tuint64_t label1 = req->data.l2.mpls.labels[1];\n+\t\tuint64_t label2 = req->data.l2.mpls.labels[2];\n+\t\tuint64_t label3 = req->data.l2.mpls.labels[3];\n+\t\tuint32_t n_labels = req->data.l2.mpls.n_labels;\n+\n+\t\tswitch (n_labels) {\n+\t\tcase 1:\n+\t\t\tentry_arp1.slab[0] = 0;\n+\t\t\tentry_arp1.slab_offset[0] =\n+\t\t\t\tp_rt->params.ip_hdr_offset - 8;\n+\n+\t\t\tentry_arp1.slab[1] = rte_bswap64(\n+\t\t\t\tMPLS_LABEL(label0, 0, 1, 0));\n+\t\t\tentry_arp1.slab_offset[1] =\n+\t\t\t\tp_rt->params.ip_hdr_offset - 8;\n+\t\t\tbreak;\n+\n+\t\tcase 2:\n+\t\t\tentry_arp1.slab[0] = 0;\n+\t\t\tentry_arp1.slab_offset[0] =\n+\t\t\t\tp_rt->params.ip_hdr_offset - 8;\n+\n+\t\t\tentry_arp1.slab[1] = rte_bswap64(\n+\t\t\t\t(MPLS_LABEL(label0, 0, 0, 0) << 32) |\n+\t\t\t\tMPLS_LABEL(label1, 0, 1, 0));\n+\t\t\tentry_arp1.slab_offset[1] =\n+\t\t\t\tp_rt->params.ip_hdr_offset - 8;\n+\t\t\tbreak;\n+\n+\t\tcase 3:\n+\t\t\tentry_arp1.slab[0] = rte_bswap64(\n+\t\t\t\t(MPLS_LABEL(label1, 0, 0, 0) << 32) |\n+\t\t\t\tMPLS_LABEL(label2, 0, 1, 0));\n+\t\t\tentry_arp1.slab_offset[0] =\n+\t\t\t\tp_rt->params.ip_hdr_offset - 8;\n+\n+\t\t\tentry_arp1.slab[1] = rte_bswap64(\n+\t\t\t\tMPLS_LABEL(label0, 0, 0, 0));\n+\t\t\tentry_arp1.slab_offset[1] =\n+\t\t\t\tp_rt->params.ip_hdr_offset - 2 * 8;\n+\t\t\tbreak;\n+\n+\t\tcase 4:\n+\t\t\tentry_arp1.slab[0] = rte_bswap64(\n+\t\t\t\t(MPLS_LABEL(label2, 0, 0, 0) << 32) |\n+\t\t\t\tMPLS_LABEL(label3, 0, 1, 0));\n+\t\t\tentry_arp1.slab_offset[0] =\n+\t\t\t\tp_rt->params.ip_hdr_offset - 8;\n+\n+\t\t\tentry_arp1.slab[1] = rte_bswap64(\n+\t\t\t\t(MPLS_LABEL(label0, 0, 0, 0) << 32) |\n+\t\t\t\tMPLS_LABEL(label1, 0, 0, 0));\n+\t\t\tentry_arp1.slab_offset[1] =\n+\t\t\t\tp_rt->params.ip_hdr_offset - 2 * 8;\n+\t\t\tbreak;\n+\n+\t\tdefault:\n+\t\t\trsp->status = -1;\n+\t\t\treturn rsp;\n+\t\t}\n+\n+\t\tentry_arp1.slab[2] = rte_bswap64((macaddr_src << 16) |\n+\t\t\tethertype_mpls);\n+\t\tentry_arp1.slab_offset[2] = p_rt->params.ip_hdr_offset -\n+\t\t\t(n_labels * 4 + 8);\n+\n+\t\tentry_arp1.data_offset = entry_arp1.slab_offset[2] - 6;\n+\t\tentry_arp1.ether_l2_length = n_labels * 4 + 14;\n+\t}\n+\n \trsp->status = rte_pipeline_table_entry_add(p->p,\n \t\tp->table_id[0],\n \t\t&key,\n-\t\t(struct rte_pipeline_table_entry *) &entry,\n+\t\tentry,\n \t\t&rsp->key_found,\n \t\t(struct rte_pipeline_table_entry **) &rsp->entry_ptr);\n \n@@ -789,6 +1935,7 @@ pipeline_routing_msg_req_arp_add_handler(struct pipeline *p, void *msg)\n \t}\n \n \t*((struct ether_addr *) &entry.macaddr) = req->macaddr;\n+\tentry.macaddr = entry.macaddr << 16;\n \n \trsp->status = rte_pipeline_table_entry_add(p->p,\n \t\tp->table_id[1],\ndiff --git a/examples/ip_pipeline/pipeline/pipeline_routing_be.h b/examples/ip_pipeline/pipeline/pipeline_routing_be.h\nindex 45f37a1..7848dc1 100644\n--- a/examples/ip_pipeline/pipeline/pipeline_routing_be.h\n+++ b/examples/ip_pipeline/pipeline/pipeline_routing_be.h\n@@ -39,6 +39,34 @@\n #include \"pipeline_common_be.h\"\n \n /*\n+ * Pipeline argument parsing\n+ */\n+struct pipeline_routing_params {\n+\t/* routing */\n+\tuint32_t n_routes;\n+\n+\t/* arp */\n+\tuint32_t n_arp_entries;\n+\tuint32_t arp;\n+\n+\t/* l2 */\n+\tuint32_t qinq;\n+\tuint32_t qinq_sched;\n+\tuint32_t mpls;\n+\tuint32_t mpls_color_mark;\n+\n+\t/* packet buffer offsets */\n+\tuint32_t ip_hdr_offset;\n+\tuint32_t ip_da_offset;\n+\tuint32_t arp_key_offset;\n+\tuint32_t color_offset;\n+};\n+\n+int\n+pipeline_routing_parse_args(struct pipeline_routing_params *p,\n+\tstruct pipeline_params *params);\n+\n+/*\n  * Route\n  */\n enum pipeline_routing_route_key_type {\n@@ -59,6 +87,36 @@ struct pipeline_routing_route_key {\n \n enum pipeline_routing_route_flags {\n \tPIPELINE_ROUTING_ROUTE_LOCAL = 1 << 0, /* 0 = remote; 1 = local */\n+\tPIPELINE_ROUTING_ROUTE_ARP = 1 << 1, /* 0 = ARP OFF; 1 = ARP ON */\n+\tPIPELINE_ROUTING_ROUTE_QINQ = 1 << 2, /* 0 = QINQ OFF; 1 = QINQ ON */\n+\tPIPELINE_ROUTING_ROUTE_MPLS = 1 << 3, /* 0 = MPLS OFF; 1 = MPLS ON */\n+};\n+\n+#define PIPELINE_ROUTING_MPLS_LABELS_MAX         4\n+\n+struct pipeline_routing_route_data {\n+\tuint32_t flags;\n+\tuint32_t port_id; /* Output port ID */\n+\n+\tunion {\n+\t\t/* Next hop IP (valid only when ARP is enabled) */\n+\t\tuint32_t ip;\n+\n+\t\t/* Next hop MAC address (valid only when ARP disabled */\n+\t\tstruct ether_addr macaddr;\n+\t} ethernet;\n+\n+\tunion {\n+\t\tstruct {\n+\t\t\tuint16_t svlan;\n+\t\t\tuint16_t cvlan;\n+\t\t} qinq;\n+\n+\t\tstruct {\n+\t\t\tuint32_t labels[PIPELINE_ROUTING_MPLS_LABELS_MAX];\n+\t\t\tuint32_t n_labels;\n+\t\t} mpls;\n+\t} l2;\n };\n \n /*\n@@ -106,9 +164,7 @@ struct pipeline_routing_route_add_msg_req {\n \tstruct pipeline_routing_route_key key;\n \n \t/* data */\n-\tuint32_t flags;\n-\tuint32_t port_id; /* Output port ID */\n-\tuint32_t ip; /* Next hop IP address (only valid for remote routes) */\n+\tstruct pipeline_routing_route_data data;\n };\n \n struct pipeline_routing_route_add_msg_rsp {\n",
    "prefixes": [
        "dpdk-dev"
    ]
}