get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 4999,
    "url": "http://patches.dpdk.org/api/patches/4999/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/1432914198-11812-11-git-send-email-maciejx.t.gajdzica@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": "<1432914198-11812-11-git-send-email-maciejx.t.gajdzica@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1432914198-11812-11-git-send-email-maciejx.t.gajdzica@intel.com",
    "date": "2015-05-29T15:43:17",
    "name": "[dpdk-dev,10/11] ip_pipeline: added new implementation of routing pipeline",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "24e70686a8df40149cb85554f3d77f31d4f7202c",
    "submitter": {
        "id": 18,
        "url": "http://patches.dpdk.org/api/people/18/?format=api",
        "name": "Maciej Gajdzica",
        "email": "maciejx.t.gajdzica@intel.com"
    },
    "delegate": null,
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/1432914198-11812-11-git-send-email-maciejx.t.gajdzica@intel.com/mbox/",
    "series": [],
    "comments": "http://patches.dpdk.org/api/patches/4999/comments/",
    "check": "pending",
    "checks": "http://patches.dpdk.org/api/patches/4999/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 72B5FC310;\n\tFri, 29 May 2015 18:24:49 +0200 (CEST)",
            "from mga02.intel.com (mga02.intel.com [134.134.136.20])\n\tby dpdk.org (Postfix) with ESMTP id 6C3319A8A\n\tfor <dev@dpdk.org>; Fri, 29 May 2015 18:24:45 +0200 (CEST)",
            "from orsmga002.jf.intel.com ([10.7.209.21])\n\tby orsmga101.jf.intel.com with ESMTP; 29 May 2015 09:24:35 -0700",
            "from unknown (HELO stargo) ([10.217.248.233])\n\tby orsmga002.jf.intel.com with SMTP; 29 May 2015 09:24:32 -0700",
            "by stargo (sSMTP sendmail emulation);\n\tFri, 29 May 2015 18:20:51 +0200"
        ],
        "X-ExtLoop1": "1",
        "X-IronPort-AV": "E=Sophos;i=\"5.13,517,1427785200\"; d=\"scan'208\";a=\"737448010\"",
        "From": "Maciej Gajdzica <maciejx.t.gajdzica@intel.com>",
        "To": "dev@dpdk.org",
        "Date": "Fri, 29 May 2015 17:43:17 +0200",
        "Message-Id": "<1432914198-11812-11-git-send-email-maciejx.t.gajdzica@intel.com>",
        "X-Mailer": "git-send-email 1.9.1",
        "In-Reply-To": "<1432914198-11812-1-git-send-email-maciejx.t.gajdzica@intel.com>",
        "References": "<1432914198-11812-1-git-send-email-maciejx.t.gajdzica@intel.com>",
        "Subject": "[dpdk-dev] [PATCH 10/11] ip_pipeline: added new implementation of\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": "Routing pipeline implementation is split to two files.\npipeline_routing.c file handles front-end functions (cli commands\nparsing) pipeline_routing_ops.c contains implementation of functions\ndone by pipeline (back-end).\n\nSigned-off-by: Pawel Wodkowski <pawelx.wodkowski@intel.com>\n---\n examples/ip_pipeline/Makefile                      |    3 +-\n examples/ip_pipeline/init.c                        |    2 +\n examples/ip_pipeline/pipeline/pipeline_routing.c   | 1660 +++++++++++++++-----\n examples/ip_pipeline/pipeline/pipeline_routing.h   |   99 ++\n .../ip_pipeline/pipeline/pipeline_routing_ops.c    |  978 ++++++++++++\n .../ip_pipeline/pipeline/pipeline_routing_ops.h    |  231 +++\n 6 files changed, 2618 insertions(+), 355 deletions(-)\n create mode 100644 examples/ip_pipeline/pipeline/pipeline_routing.h\n create mode 100644 examples/ip_pipeline/pipeline/pipeline_routing_ops.c\n create mode 100644 examples/ip_pipeline/pipeline/pipeline_routing_ops.h",
    "diff": "diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile\nindex 0f8b1cc..f8c7c5f 100644\n--- a/examples/ip_pipeline/Makefile\n+++ b/examples/ip_pipeline/Makefile\n@@ -63,8 +63,9 @@ SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_passthrough_ops.c\n SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_passthrough.c\n SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_firewall_ops.c\n SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_firewall.c\n+SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_routing_ops.c\n+SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_routing.c\n #SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_flow_classification.c\n-#SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_routing.c\n \n CFLAGS += -I$(SRCDIR) -I$(SRCDIR)/pipeline\n CFLAGS += -O3\ndiff --git a/examples/ip_pipeline/init.c b/examples/ip_pipeline/init.c\nindex 29d87ae..29caae8 100644\n--- a/examples/ip_pipeline/init.c\n+++ b/examples/ip_pipeline/init.c\n@@ -46,6 +46,7 @@\n #include \"pipeline_master.h\"\n #include \"pipeline_passthrough.h\"\n #include \"pipeline_firewall.h\"\n+#include \"pipeline_routing.h\"\n \n #define APP_NAME_SIZE\t32\n \n@@ -1148,6 +1149,7 @@ int app_init(struct app_params *app)\n \tapp_pipeline_type_register(app, &pipeline_master);\n \tapp_pipeline_type_register(app, &pipeline_passthrough);\n \tapp_pipeline_type_register(app, &pipeline_firewall);\n+\tapp_pipeline_type_register(app, &pipeline_routing);\n \n \tapp_init_pipelines(app);\n \tapp_init_threads(app);\ndiff --git a/examples/ip_pipeline/pipeline/pipeline_routing.c b/examples/ip_pipeline/pipeline/pipeline_routing.c\nindex b1ce624..d7dd495 100644\n--- a/examples/ip_pipeline/pipeline/pipeline_routing.c\n+++ b/examples/ip_pipeline/pipeline/pipeline_routing.c\n@@ -1,7 +1,7 @@\n /*-\n  *   BSD LICENSE\n  *\n- *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.\n+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.\n  *   All rights reserved.\n  *\n  *   Redistribution and use in source and binary forms, with or without\n@@ -31,444 +31,1396 @@\n  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n  */\n \n-#include <stdio.h>\n-#include <stdlib.h>\n-#include <stdint.h>\n+#include <cmdline_parse.h>\n+#include <cmdline_parse_num.h>\n+#include <cmdline_parse_string.h>\n+#include <cmdline_parse_ipaddr.h>\n+#include <cmdline_parse_etheraddr.h>\n \n-#include <rte_malloc.h>\n-#include <rte_log.h>\n-#include <rte_ethdev.h>\n-#include <rte_ether.h>\n-#include <rte_ip.h>\n-#include <rte_byteorder.h>\n+#include \"app.h\"\n+#include \"pipeline_routing_ops.h\"\n+#include \"pipeline_routing.h\"\n \n-#include <rte_port_ring.h>\n-#include <rte_table_lpm.h>\n-#include <rte_table_hash.h>\n-#include <rte_pipeline.h>\n+#include \"pipeline_common.h\"\n \n-#include \"main.h\"\n+#define MSG_TIMEOUT 1000\n \n-#include <unistd.h>\n+struct app_pipeline_routing_arp_entry {\n+\tstruct pipeline_routing_arp_key key;\n+\tstruct ether_addr nh_arp;\n+\tvoid *entry_ptr;\n \n-struct app_routing_table_entry {\n-\tstruct rte_pipeline_table_entry head;\n-\tuint32_t nh_ip;\n-\tuint32_t nh_iface;\n+\tTAILQ_ENTRY(app_pipeline_routing_arp_entry) node;\n };\n \n-struct app_arp_table_entry {\n-\tstruct rte_pipeline_table_entry head;\n-\tstruct ether_addr nh_arp;\n+struct app_pipeline_routing_entry {\n+\tstruct pipeline_routing_route_key key;\n+\tstruct app_pipeline_routing_route_params params;\n+\tvoid *entry_ptr;\n+\n+\tTAILQ_ENTRY(app_pipeline_routing_entry) node;\n+};\n+\n+struct pipeline_routing {\n+\t/* parameters */\n+\tuint32_t n_ports_in;\n+\tuint32_t n_ports_out;\n+\n+\t/* ARP entries */\n+\tTAILQ_HEAD(, app_pipeline_routing_arp_entry) arp_entries;\n+\tuint32_t n_arp_entries;\n+\n+\tuint32_t default_arp_entry_present;\n+\tuint32_t default_arp_entry_port_id;\n+\tvoid *default_arp_entry_ptr;\n+\n+\t/* Routing routes */\n+\tTAILQ_HEAD(, app_pipeline_routing_entry) routes;\n+\tuint32_t n_routes;\n+\n+\tuint32_t default_route_present;\n+\tuint32_t default_route_port_id;\n+\tvoid *default_route_entry_ptr;\n };\n \n-static inline void\n-app_routing_table_write_metadata(\n-\tstruct rte_mbuf *pkt,\n-\tstruct app_routing_table_entry *entry)\n+static void *\n+pipeline_routing_init(struct pipeline_params *params,\n+\t__rte_unused void *arg)\n {\n-\tstruct app_pkt_metadata *c =\n-\t\t(struct app_pkt_metadata *) RTE_MBUF_METADATA_UINT8_PTR(pkt, 0);\n+\tstruct pipeline_routing *p;\n+\tuint32_t size;\n+\n+\t/* Check input arguments */\n+\tif ((params == NULL) ||\n+\t\t(params->n_ports_in == 0) ||\n+\t\t(params->n_ports_out == 0))\n+\t\treturn NULL;\n+\n+\t/* Memory allocation */\n+\tsize = RTE_CACHE_LINE_ROUNDUP(sizeof(struct pipeline_routing));\n+\tp = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);\n+\tif (p == NULL)\n+\t\treturn NULL;\n+\n+\t/* Initialization */\n+\tp->n_ports_in = params->n_ports_in;\n+\tp->n_ports_out = params->n_ports_out;\n+\n+\tTAILQ_INIT(&p->arp_entries);\n+\tp->n_arp_entries = 0;\n \n-\tc->arp_key.nh_ip = entry->nh_ip;\n-\tc->arp_key.nh_iface = entry->nh_iface;\n+\tTAILQ_INIT(&p->routes);\n+\tp->n_routes = 0;\n+\n+\treturn p;\n }\n \n static int\n-app_routing_table_ah(\n-\tstruct rte_mbuf **pkts,\n-\tuint64_t *pkts_mask,\n-\tstruct rte_pipeline_table_entry **entries,\n-\t__attribute__((unused)) void *arg)\n+app_pipeline_routing_free(void *pipeline)\n {\n-\tuint64_t pkts_in_mask = *pkts_mask;\n+\tstruct pipeline_routing *p = pipeline;\n+\tstruct app_pipeline_routing_arp_entry *arp_entry;\n \n-\tif ((pkts_in_mask & (pkts_in_mask + 1)) == 0) {\n-\t\tuint64_t n_pkts = __builtin_popcountll(pkts_in_mask);\n-\t\tuint32_t i;\n+\t/* Check input arguments */\n+\tif (p == NULL)\n+\t\treturn -1;\n+\n+\t/* Free resources */\n+\twhile (!TAILQ_EMPTY(&p->arp_entries)) {\n+\t\tarp_entry = TAILQ_FIRST(&p->arp_entries);\n+\t\tTAILQ_REMOVE(&p->arp_entries, arp_entry, node);\n+\t\trte_free(arp_entry);\n+\t}\n+\n+\trte_free(p);\n+\treturn 0;\n+}\n \n-\t\tfor (i = 0; i < n_pkts; i++) {\n-\t\t\tstruct rte_mbuf *m = pkts[i];\n-\t\t\tstruct app_routing_table_entry *a =\n-\t\t\t\t(struct app_routing_table_entry *) entries[i];\n+static struct app_pipeline_routing_arp_entry *\n+app_pipeline_routing_find_arp_entry(struct pipeline_routing *p,\n+\t\tconst struct pipeline_routing_arp_key *key)\n+{\n+\tstruct app_pipeline_routing_arp_entry *it, *found;\n \n-\t\t\tapp_routing_table_write_metadata(m, a);\n+\tfound = NULL;\n+\tTAILQ_FOREACH(it, &p->arp_entries, node) {\n+\t\tif (memcmp(key, &it->key, sizeof(it->key)) == 0) {\n+\t\t\tfound = it;\n+\t\t\tbreak;\n \t\t}\n-\t} else\n-\t\tfor ( ; pkts_in_mask; ) {\n-\t\t\tstruct rte_mbuf *m;\n-\t\t\tstruct app_routing_table_entry *a;\n-\t\t\tuint64_t pkt_mask;\n-\t\t\tuint32_t packet_index;\n-\n-\t\t\tpacket_index = __builtin_ctzll(pkts_in_mask);\n-\t\t\tpkt_mask = 1LLU << packet_index;\n-\t\t\tpkts_in_mask &= ~pkt_mask;\n-\n-\t\t\tm = pkts[packet_index];\n-\t\t\ta = (struct app_routing_table_entry *)\n-\t\t\t\tentries[packet_index];\n-\t\t\tapp_routing_table_write_metadata(m, a);\n+\t}\n+\n+\treturn found;\n+}\n+\n+static struct app_pipeline_routing_entry *\n+app_pipeline_routing_find_route(struct pipeline_routing *p,\n+\t\tconst struct pipeline_routing_route_key *key)\n+{\n+\tstruct app_pipeline_routing_entry *it, *found;\n+\n+\tfound = NULL;\n+\tTAILQ_FOREACH(it, &p->routes, node) {\n+\t\tif (memcmp(key, &it->key, sizeof(it->key)) == 0) {\n+\t\t\tfound = it;\n+\t\t\tbreak;\n \t\t}\n+\t}\n \n-\treturn 0;\n+\treturn found;\n }\n \n-static inline void\n-app_arp_table_write_metadata(\n-\tstruct rte_mbuf *pkt,\n-\tstruct app_arp_table_entry *entry)\n+static void\n+print_route(const struct app_pipeline_routing_entry *route)\n+{\n+\tAPP_CHECK(route->key.type == PIPELINE_ROUTING_ROUTE_IPV4, \"Only IPv6\");\n+\tif (route->key.type == PIPELINE_ROUTING_ROUTE_IPV4) {\n+\t\tconst struct pipeline_routing_route_key_ipv4 *key =\n+\t\t\t\t&route->key.key.ipv4;\n+\n+\t\tprintf(\"IP Prefix = %u.%u.%u.%u/%u => \"\n+\t\t\t\"(Port = %u, Next Hop = %u.%u.%u.%u)\\n\",\n+\t\t\t(key->ip >> 24) & 0xFF,\n+\t\t\t(key->ip >> 16) & 0xFF,\n+\t\t\t(key->ip >> 8) & 0xFF,\n+\t\t\tkey->ip & 0xFF,\n+\n+\t\t\tkey->depth,\n+\t\t\troute->params.port_id,\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}\n+\n+}\n+\n+static void\n+print_arp_entry(const struct app_pipeline_routing_arp_entry *entry)\n {\n-\tstruct app_pkt_metadata *c =\n-\t\t(struct app_pkt_metadata *) RTE_MBUF_METADATA_UINT8_PTR(pkt, 0);\n-\tether_addr_copy(&entry->nh_arp, &c->nh_arp);\n+\tprintf(\"(Port = %u, IP = %u.%u.%u.%u) => \"\n+\t\t\"HWaddress = %02x:%02x:%02x:%02x:%02x:%02x\\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+\t\t(entry->key.key.ipv4.ip >> 8) & 0xFF,\n+\t\tentry->key.key.ipv4.ip & 0xFF,\n+\n+\t\tentry->nh_arp.addr_bytes[0],\n+\t\tentry->nh_arp.addr_bytes[1],\n+\t\tentry->nh_arp.addr_bytes[2],\n+\t\tentry->nh_arp.addr_bytes[3],\n+\t\tentry->nh_arp.addr_bytes[4],\n+\t\tentry->nh_arp.addr_bytes[5]);\n }\n \n static int\n-app_arp_table_ah(\n-\tstruct rte_mbuf **pkts,\n-\tuint64_t *pkts_mask,\n-\tstruct rte_pipeline_table_entry **entries,\n-\t__attribute__((unused)) void *arg)\n+app_pipeline_routing_arp_ls(struct app_params *app, uint32_t pipeline_id)\n {\n-\tuint64_t pkts_in_mask = *pkts_mask;\n+\tstruct pipeline_routing *p;\n+\tstruct app_pipeline_routing_arp_entry *it;\n \n-\tif ((pkts_in_mask & (pkts_in_mask + 1)) == 0) {\n-\t\tuint64_t n_pkts = __builtin_popcountll(pkts_in_mask);\n-\t\tuint32_t i;\n+\tp = app_pipeline_data_fe(app, pipeline_id);\n+\tif (p == NULL)\n+\t\treturn -EINVAL;\n \n-\t\tfor (i = 0; i < n_pkts; i++) {\n-\t\t\tstruct rte_mbuf *m = pkts[i];\n-\t\t\tstruct app_arp_table_entry *a =\n-\t\t\t\t(struct app_arp_table_entry *) entries[i];\n+\tTAILQ_FOREACH(it, &p->arp_entries, node)\n+\t\tprint_arp_entry(it);\n \n-\t\t\tapp_arp_table_write_metadata(m, a);\n-\t\t}\n-\t} else {\n-\t\tfor ( ; pkts_in_mask; ) {\n-\t\t\tstruct rte_mbuf *m;\n-\t\t\tstruct app_arp_table_entry *a;\n-\t\t\tuint64_t pkt_mask;\n-\t\t\tuint32_t packet_index;\n-\n-\t\t\tpacket_index = __builtin_ctzll(pkts_in_mask);\n-\t\t\tpkt_mask = 1LLU << packet_index;\n-\t\t\tpkts_in_mask &= ~pkt_mask;\n-\n-\t\t\tm = pkts[packet_index];\n-\t\t\ta = (struct app_arp_table_entry *)\n-\t\t\t\tentries[packet_index];\n-\t\t\tapp_arp_table_write_metadata(m, a);\n-\t\t}\n+\tif (p->default_arp_entry_present)\n+\t\tprintf(\"Default entry: port %u (entry ptr = %p)\\n\",\n+\t\t\t\tp->default_arp_entry_port_id,\n+\t\t\t\tp->default_arp_entry_ptr);\n+\telse\n+\t\tprintf(\"Default: DROP\\n\"); /* FIXME: msg OK ? */\n+\n+\treturn 0;\n+}\n+\n+int\n+app_pipeline_routing_add_arp_entry(struct app_params *app, uint32_t pipeline_id,\n+\t\tstruct pipeline_routing_arp_key *key,\n+\t\tstruct ether_addr *macaddr)\n+{\n+\tstruct pipeline_routing *p;\n+\n+\tstruct pipeline_routing_arp_add_msg_req *req;\n+\tstruct pipeline_routing_arp_add_msg_rsp *rsp;\n+\n+\tstruct app_pipeline_routing_arp_entry *entry;\n+\n+\tint new_entry;\n+\n+\tp = app_pipeline_data_fe(app, pipeline_id);\n+\tif (p == NULL)\n+\t\treturn -EINVAL;\n+\n+\t/* Find existing entry or allocate new */\n+\tentry = app_pipeline_routing_find_arp_entry(p, key);\n+\tnew_entry = (entry == NULL);\n+\tif (entry == NULL) {\n+\t\tentry = rte_malloc(NULL, sizeof(*entry), RTE_CACHE_LINE_SIZE);\n+\n+\t\tif (entry == NULL)\n+\t\t\treturn -1;\n+\t}\n+\n+\t/* Message buffer allocation */\n+\treq = app_msg_alloc(app);\n+\tif (req == NULL) {\n+\t\tif (new_entry)\n+\t\t\trte_free(entry);\n+\t\treturn -1;\n \t}\n \n+\treq->type = PIPELINE_MSG_REQ_CUSTOM;\n+\treq->subtype = PIPELINE_ROUTING_MSG_REQ_ARP_ADD;\n+\tmemcpy(&req->key, key, sizeof(*key));\n+\tether_addr_copy(macaddr, &req->macaddr);\n+\n+\t/* Send request and wait for response */\n+\trsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT);\n+\tif (rsp == NULL) {\n+\t\tif (new_entry)\n+\t\t\trte_free(entry);\n+\t\treturn -1;\n+\t}\n+\n+\t/* Read response and write entry */\n+\tif (rsp->status || rsp->entry_ptr == NULL) {\n+\t\tapp_msg_free(app, rsp);\n+\t\tif (new_entry)\n+\t\t\trte_free(entry);\n+\t\treturn -1;\n+\t}\n+\n+\tmemcpy(&entry->key, key, sizeof(*key));\n+\tether_addr_copy(macaddr, &entry->nh_arp);\n+\tentry->entry_ptr = rsp->entry_ptr;\n+\n+\t/* Commit entry */\n+\tif (new_entry) {\n+\t\tTAILQ_INSERT_TAIL(&p->arp_entries, entry, node);\n+\t\tp->n_arp_entries++;\n+\t}\n+\n+\tprint_arp_entry(entry);\n+\n+\t/* Message buffer free */\n+\tapp_msg_free(app, rsp);\n \treturn 0;\n }\n \n-static uint64_t app_arp_table_hash(\n-\tvoid *key,\n-\t__attribute__((unused)) uint32_t key_size,\n-\t__attribute__((unused)) uint64_t seed)\n+int\n+app_pipeline_routing_delete_arp_entry(struct app_params *app,\n+\tuint32_t pipeline_id,\n+\tstruct pipeline_routing_arp_key *key)\n {\n-\tuint32_t *k = (uint32_t *) key;\n+\tstruct pipeline_routing *p;\n+\n+\tstruct pipeline_routing_arp_delete_msg_req *req;\n+\tstruct pipeline_routing_arp_delete_msg_rsp *rsp;\n+\n+\tstruct app_pipeline_routing_arp_entry *entry;\n+\n+\tp = app_pipeline_data_fe(app, pipeline_id);\n+\tif (p == NULL)\n+\t\treturn -EINVAL;\n+\n+\t/* Find rule */\n+\tentry = app_pipeline_routing_find_arp_entry(p, key);\n+\tif (entry == NULL)\n+\t\treturn 0;\n+\n+\t/* Allocate and write request */\n+\treq = app_msg_alloc(app);\n+\tif (req == NULL)\n+\t\treturn -1;\n+\n+\treq->type = PIPELINE_MSG_REQ_CUSTOM;\n+\treq->subtype = PIPELINE_ROUTING_MSG_REQ_ARP_DEL;\n+\tmemcpy(&req->key, key, sizeof(*key));\n+\n+\n+\trsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT);\n+\tif (rsp == NULL)\n+\t\treturn -1;\n+\n+\trsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT);\n+\tif (rsp == NULL)\n+\t\treturn -1;\n \n-\treturn k[1];\n+\t/* Read response */\n+\tif (rsp->status) {\n+\t\tapp_msg_free(app, rsp);\n+\t\treturn -1;\n+\t}\n+\n+\t/* Remove entry */\n+\tTAILQ_REMOVE(&p->arp_entries, entry, node);\n+\tp->n_arp_entries--;\n+\trte_free(entry);\n+\n+\t/* Free response */\n+\tapp_msg_free(app, rsp);\n+\n+\treturn 0;\n }\n \n-struct app_core_routing_message_handle_params {\n-\tstruct rte_ring *ring_req;\n-\tstruct rte_ring *ring_resp;\n-\tstruct rte_pipeline *p;\n-\tuint32_t *port_out_id;\n-\tuint32_t routing_table_id;\n-\tuint32_t arp_table_id;\n-};\n+int\n+app_pipeline_routing_add_default_arp_entry(struct app_params *app,\n+\t\tuint32_t pipeline_id,\n+\t\tuint32_t port_id)\n+{\n+\tstruct pipeline_routing *p;\n \n-static void\n-app_message_handle(struct app_core_routing_message_handle_params *params);\n+\tstruct pipeline_routing_arp_add_default_msg_req *req;\n+\tstruct pipeline_routing_arp_add_default_msg_rsp *rsp;\n+\n+\tp = app_pipeline_data_fe(app, pipeline_id);\n+\tif (p == NULL)\n+\t\treturn -EINVAL;\n+\n+\t/* Allocate and write request */\n+\treq = app_msg_alloc(app);\n+\tif (req == NULL)\n+\t\treturn -1;\n+\n+\treq->type = PIPELINE_MSG_REQ_CUSTOM;\n+\treq->subtype = PIPELINE_ROUTING_MSG_REQ_ARP_ADD_DEFAULT;\n+\treq->port_id = port_id;\n+\n+\t/* Send request and wait for response */\n+\trsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT);\n+\tif (rsp == NULL)\n+\t\treturn -1;\n+\n+\t/* Read response and write entry */\n+\tif (rsp->status || rsp->entry_ptr == NULL) {\n+\t\tapp_msg_free(app, rsp);\n+\t\treturn -1;\n+\t}\n+\n+\tp->default_arp_entry_port_id = port_id;\n+\tp->default_arp_entry_ptr = rsp->entry_ptr;\n+\n+\t/* Commit entry */\n+\tp->default_arp_entry_present = 1;\n+\n+\t/* Free response */\n+\tapp_msg_free(app, rsp);\n+\n+\treturn 0;\n+}\n+\n+int\n+app_pipeline_routing_delete_default_arp_entry(struct app_params *app,\n+\tuint32_t pipeline_id)\n+{\n+\tstruct pipeline_routing *p;\n+\n+\tstruct pipeline_routing_arp_delete_default_msg_req *req;\n+\tstruct pipeline_routing_arp_delete_default_msg_rsp *rsp;\n+\n+\tp = app_pipeline_data_fe(app, pipeline_id);\n+\tif (p == NULL)\n+\t\treturn -EINVAL;\n+\n+\t/* Allocate and write request */\n+\treq = app_msg_alloc(app);\n+\tif (req == NULL)\n+\t\treturn -ENOMEM;\n+\n+\treq->type = PIPELINE_MSG_REQ_CUSTOM;\n+\treq->subtype = PIPELINE_ROUTING_MSG_REQ_ARP_DEL_DEFAULT;\n+\n+\t/* Send request and wait for response */\n+\trsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT);\n+\tif (rsp == NULL)\n+\t\treturn -ETIMEDOUT;\n+\n+\t/* Read response and write entry */\n+\tif (rsp->status) {\n+\t\tapp_msg_free(app, rsp);\n+\t\treturn -rsp->status;\n+\t}\n+\n+\t/* Commit entry */\n+\tp->default_arp_entry_present = 0;\n+\n+\t/* Free response */\n+\tapp_msg_free(app, rsp);\n+\n+\treturn 0;\n+}\n+\n+static int\n+app_pipeline_routing_ls(struct app_params *app, uint32_t pipeline_id)\n+{\n+\tstruct pipeline_routing *p;\n+\tstruct app_pipeline_routing_entry *it;\n \n-void\n-app_main_loop_pipeline_routing(void) {\n-\tstruct rte_pipeline_params pipeline_params = {\n-\t\t.name = \"pipeline\",\n-\t\t.socket_id = rte_socket_id(),\n-\t};\n+\tp = app_pipeline_data_fe(app, pipeline_id);\n+\tif (p == NULL)\n+\t\treturn -EINVAL;\n \n-\tstruct rte_pipeline *p;\n-\tuint32_t port_in_id[APP_MAX_PORTS];\n-\tuint32_t port_out_id[APP_MAX_PORTS];\n-\tuint32_t routing_table_id, arp_table_id;\n-\tuint32_t i;\n+\tTAILQ_FOREACH(it, &p->routes, node)\n+\t\tprint_route(it);\n \n-\tuint32_t core_id = rte_lcore_id();\n-\tstruct app_core_params *core_params = app_get_core_params(core_id);\n-\tstruct app_core_routing_message_handle_params mh_params;\n+\tif (p->default_route_present)\n+\t\tprintf(\"Default route: port %u (entry ptr = %p)\\n\",\n+\t\t\t\tp->default_route_port_id,\n+\t\t\t\tp->default_route_entry_ptr);\n+\telse\n+\t\tprintf(\"Default: DROP\\n\"); /* FIXME: msg OK ? */\n \n-\tif ((core_params == NULL) || (core_params->core_type != APP_CORE_RT))\n-\t\trte_panic(\"Core %u misconfiguration\\n\", core_id);\n+\treturn 0;\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+{\n+\tstruct pipeline_routing *p;\n \n-\tRTE_LOG(INFO, USER1, \"Core %u is doing routing\\n\", core_id);\n+\tstruct pipeline_routing_route_add_msg_req *req;\n+\tstruct pipeline_routing_route_add_msg_rsp *rsp;\n \n-\t/* Pipeline configuration */\n-\tp = rte_pipeline_create(&pipeline_params);\n+\tstruct app_pipeline_routing_entry *entry;\n+\n+\tint new_entry;\n+\n+\tp = app_pipeline_data_fe(app, pipeline_id);\n+\t/* Check input arguments */\n \tif (p == NULL)\n-\t\trte_panic(\"Unable to configure the pipeline\\n\");\n-\n-\t/* Input port configuration */\n-\tfor (i = 0; i < app.n_ports; i++) {\n-\t\tstruct rte_port_ring_reader_params port_ring_params = {\n-\t\t\t.ring = app.rings[core_params->swq_in[i]],\n-\t\t};\n-\n-\t\tstruct rte_pipeline_port_in_params port_params = {\n-\t\t\t.ops = &rte_port_ring_reader_ops,\n-\t\t\t.arg_create = (void *) &port_ring_params,\n-\t\t\t.f_action = NULL,\n-\t\t\t.arg_ah = NULL,\n-\t\t\t.burst_size = app.bsz_swq_rd,\n-\t\t};\n-\n-\t\tif (rte_pipeline_port_in_create(p, &port_params,\n-\t\t\t&port_in_id[i]))\n-\t\t\trte_panic(\"Unable to configure input port for \"\n-\t\t\t\t\"ring %d\\n\", i);\n+\t\treturn -EINVAL;\n+\n+\t/* Find existing rule or allocate new rule */\n+\tentry = app_pipeline_routing_find_route(p, key);\n+\tnew_entry = (entry == NULL);\n+\tif (entry == NULL) {\n+\t\tentry = rte_malloc(NULL, sizeof(*entry), RTE_CACHE_LINE_SIZE);\n+\n+\t\tif (entry == NULL)\n+\t\t\treturn -1;\n \t}\n \n-\t/* Output port configuration */\n-\tfor (i = 0; i < app.n_ports; i++) {\n-\t\tstruct rte_port_ring_writer_params port_ring_params = {\n-\t\t\t.ring = app.rings[core_params->swq_out[i]],\n-\t\t\t.tx_burst_sz = app.bsz_swq_wr,\n-\t\t};\n-\n-\t\tstruct rte_pipeline_port_out_params port_params = {\n-\t\t\t.ops = &rte_port_ring_writer_ops,\n-\t\t\t.arg_create = (void *) &port_ring_params,\n-\t\t\t.f_action = NULL,\n-\t\t\t.f_action_bulk = NULL,\n-\t\t\t.arg_ah = NULL,\n-\t\t};\n-\n-\t\tif (rte_pipeline_port_out_create(p, &port_params,\n-\t\t\t&port_out_id[i]))\n-\t\t\trte_panic(\"Unable to configure output port for \"\n-\t\t\t\t\"ring %d\\n\", i);\n+\t/* Allocate and write request */\n+\treq = app_msg_alloc(app);\n+\tif (req == NULL) {\n+\t\tif (new_entry)\n+\t\t\trte_free(entry);\n+\t\treturn -1;\n \t}\n \n-\t/* Routing table configuration */\n-\t{\n-\t\tstruct rte_table_lpm_params table_lpm_params = {\n-\t\t\t.n_rules = app.max_routing_rules,\n-\t\t\t.entry_unique_size =\n-\t\t\t\tsizeof(struct app_routing_table_entry),\n-\t\t\t.offset = __builtin_offsetof(struct app_pkt_metadata,\n-\t\t\t\tflow_key.ip_dst),\n-\t\t};\n-\n-\t\tstruct rte_pipeline_table_params table_params = {\n-\t\t\t.ops = &rte_table_lpm_ops,\n-\t\t\t.arg_create = &table_lpm_params,\n-\t\t\t.f_action_hit = app_routing_table_ah,\n-\t\t\t.f_action_miss = NULL,\n-\t\t\t.arg_ah = NULL,\n-\t\t\t.action_data_size =\n-\t\t\t\tsizeof(struct app_routing_table_entry) -\n-\t\t\t\tsizeof(struct rte_pipeline_table_entry),\n-\t\t};\n-\n-\t\tif (rte_pipeline_table_create(p, &table_params,\n-\t\t\t&routing_table_id))\n-\t\t\trte_panic(\"Unable to configure the LPM table\\n\");\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+\n+\trsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT);\n+\tif (rsp == NULL) {\n+\t\tif (new_entry)\n+\t\t\trte_free(entry);\n+\t\treturn -1;\n \t}\n \n-\t/* ARP table configuration */\n-\t{\n-\t\tstruct rte_table_hash_key8_lru_params table_arp_params = {\n-\t\t\t.n_entries = app.max_arp_rules,\n-\t\t\t.f_hash = app_arp_table_hash,\n-\t\t\t.seed = 0,\n-\t\t\t.signature_offset = 0, /* Unused */\n-\t\t\t.key_offset = __builtin_offsetof(\n-\t\t\t\tstruct app_pkt_metadata, arp_key),\n-\t\t};\n-\n-\t\tstruct rte_pipeline_table_params table_params = {\n-\t\t\t.ops = &rte_table_hash_key8_lru_dosig_ops,\n-\t\t\t.arg_create = &table_arp_params,\n-\t\t\t.f_action_hit = app_arp_table_ah,\n-\t\t\t.f_action_miss = NULL,\n-\t\t\t.arg_ah = NULL,\n-\t\t\t.action_data_size = sizeof(struct app_arp_table_entry) -\n-\t\t\t\tsizeof(struct rte_pipeline_table_entry),\n-\t\t};\n-\n-\t\tif (rte_pipeline_table_create(p, &table_params, &arp_table_id))\n-\t\t\trte_panic(\"Unable to configure the ARP table\\n\");\n+\t/* Read response and write entry */\n+\tif (rsp->status || (rsp->entry_ptr == NULL)) {\n+\t\tapp_msg_free(app, rsp);\n+\t\tif (new_entry)\n+\t\t\trte_free(entry);\n+\t\treturn -1;\n+\t}\n+\n+\tmemcpy(&entry->key, key, sizeof(*key));\n+\tmemcpy(&entry->params, route_params, sizeof(*route_params));\n+\tentry->entry_ptr = rsp->entry_ptr;\n+\n+\t/* Commit entry */\n+\tif (new_entry) {\n+\t\tTAILQ_INSERT_TAIL(&p->routes, entry, node);\n+\t\tp->n_arp_entries++;\n+\t}\n+\n+\tprint_route(entry);\n+\n+\t/* Message buffer free */\n+\tapp_msg_free(app, rsp);\n+\treturn 0;\n+}\n+\n+int\n+app_pipeline_routing_delete_route(struct app_params *app,\n+\tuint32_t pipeline_id,\n+\tstruct pipeline_routing_route_key *key)\n+{\n+\tstruct pipeline_routing *p;\n+\n+\tstruct pipeline_routing_route_delete_msg_req *req;\n+\tstruct pipeline_routing_route_delete_msg_rsp *rsp;\n+\n+\tstruct app_pipeline_routing_entry *entry;\n+\n+\tp = app_pipeline_data_fe(app, pipeline_id);\n+\tif (p == NULL)\n+\t\treturn -EINVAL;\n+\n+\t/* Find rule */\n+\tentry = app_pipeline_routing_find_route(p, key);\n+\tif (entry == NULL)\n+\t\treturn 0;\n+\n+\t/* Allocate and write request */\n+\treq = app_msg_alloc(app);\n+\tif (req == NULL)\n+\t\treturn -1;\n+\n+\treq->type = PIPELINE_MSG_REQ_CUSTOM;\n+\treq->subtype = PIPELINE_ROUTING_MSG_REQ_ROUTE_DEL;\n+\tmemcpy(&req->key, key, sizeof(*key));\n+\n+\n+\trsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT);\n+\tif (rsp == NULL)\n+\t\treturn -1;\n+\n+\trsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT);\n+\tif (rsp == NULL)\n+\t\treturn -1;\n+\n+\t/* Read response */\n+\tif (rsp->status) {\n+\t\tapp_msg_free(app, rsp);\n+\t\treturn -1;\n+\t}\n+\n+\t/* Remove route */\n+\tTAILQ_REMOVE(&p->routes, entry, node);\n+\tp->n_routes--;\n+\n+\trte_free(entry);\n+\n+\t/* Free response */\n+\tapp_msg_free(app, rsp);\n+\n+\treturn 0;\n+}\n+\n+int\n+app_pipeline_routing_add_default_route(struct app_params *app,\n+\tuint32_t pipeline_id,\n+\tuint32_t port_id)\n+{\n+\tstruct pipeline_routing *p;\n+\n+\tstruct pipeline_routing_route_add_default_msg_req *req;\n+\tstruct pipeline_routing_route_add_default_msg_rsp *rsp;\n+\n+\tp = app_pipeline_data_fe(app, pipeline_id);\n+\tif (p == NULL)\n+\t\treturn -EINVAL;\n+\n+\t/* Allocate and write request */\n+\treq = app_msg_alloc(app);\n+\tif (req == NULL)\n+\t\treturn -1;\n+\n+\treq->type = PIPELINE_MSG_REQ_CUSTOM;\n+\treq->subtype = PIPELINE_ROUTING_MSG_REQ_ROUTE_ADD_DEFAULT;\n+\treq->port_id = port_id;\n+\n+\t/* Send request and wait for response */\n+\trsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT);\n+\tif (rsp == NULL)\n+\t\treturn -1;\n+\n+\t/* Read response and write route */\n+\tif (rsp->status || (rsp->entry_ptr == NULL)) {\n+\t\tapp_msg_free(app, rsp);\n+\t\treturn -1;\n \t}\n \n-\t/* Interconnecting ports and tables */\n-\tfor (i = 0; i < app.n_ports; i++) {\n-\t\tif (rte_pipeline_port_in_connect_to_table(p, port_in_id[i],\n-\t\t\trouting_table_id))\n-\t\t\trte_panic(\"Unable to connect input port %u to \"\n-\t\t\t\t\"table %u\\n\", port_in_id[i],  routing_table_id);\n+\tp->default_route_port_id = port_id;\n+\tp->default_route_entry_ptr = rsp->entry_ptr;\n+\n+\t/* Commit route */\n+\tp->default_route_present = 1;\n+\n+\t/* Free response */\n+\tapp_msg_free(app, rsp);\n+\n+\treturn 0;\n+}\n+\n+int\n+app_pipeline_routing_delete_default_route(struct app_params *app,\n+\tuint32_t pipeline_id)\n+{\n+\tstruct pipeline_routing *p;\n+\n+\tstruct pipeline_routing_arp_delete_default_msg_req *req;\n+\tstruct pipeline_routing_arp_delete_default_msg_rsp *rsp;\n+\n+\tp = app_pipeline_data_fe(app, pipeline_id);\n+\tif (p == NULL)\n+\t\treturn -EINVAL;\n+\n+\t/* Allocate and write request */\n+\treq = app_msg_alloc(app);\n+\tif (req == NULL)\n+\t\treturn -1;\n+\n+\treq->type = PIPELINE_MSG_REQ_CUSTOM;\n+\treq->subtype = PIPELINE_ROUTING_MSG_REQ_ROUTE_DEL_DEFAULT;\n+\n+\t/* Send request and wait for response */\n+\trsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT);\n+\tif (rsp == NULL)\n+\t\treturn -1;\n+\n+\t/* Read response and write route */\n+\tif (rsp->status) {\n+\t\tapp_msg_free(app, rsp);\n+\t\treturn -1;\n \t}\n \n-\t/* Enable input ports */\n-\tfor (i = 0; i < app.n_ports; i++)\n-\t\tif (rte_pipeline_port_in_enable(p, port_in_id[i]))\n-\t\t\trte_panic(\"Unable to enable input port %u\\n\",\n-\t\t\t\tport_in_id[i]);\n-\n-\t/* Check pipeline consistency */\n-\tif (rte_pipeline_check(p) < 0)\n-\t\trte_panic(\"Pipeline consistency check failed\\n\");\n-\n-\t/* Message handling */\n-\tmh_params.ring_req =\n-\t\tapp_get_ring_req(app_get_first_core_id(APP_CORE_RT));\n-\tmh_params.ring_resp =\n-\t\tapp_get_ring_resp(app_get_first_core_id(APP_CORE_RT));\n-\tmh_params.p = p;\n-\tmh_params.port_out_id = port_out_id;\n-\tmh_params.routing_table_id = routing_table_id;\n-\tmh_params.arp_table_id = arp_table_id;\n-\n-\t/* Run-time */\n-\tfor (i = 0; ; i++) {\n-\t\trte_pipeline_run(p);\n-\n-\t\tif ((i & APP_FLUSH) == 0) {\n-\t\t\trte_pipeline_flush(p);\n-\t\t\tapp_message_handle(&mh_params);\n+\t/* Commit route */\n+\tp->default_route_present = 0;\n+\n+\t/* Free response */\n+\tapp_msg_free(app, rsp);\n+\n+\treturn 0;\n+}\n+\n+/* CLI */\n+\n+/* *** Routing - Add *** */\n+struct cmd_route_add_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+\tuint8_t depth;\n+\tuint8_t port;\n+\tcmdline_ipaddr_t nh_ip;\n+};\n+\n+static void\n+cmd_route_add_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 app_params *app = data;\n+\tstruct pipeline_routing_route_key key;\n+\tstruct app_pipeline_routing_route_params rt_params;\n+\tuint32_t netmask;\n+\n+\tint status;\n+\n+\tAPP_CHECK(params->ip.family == AF_INET,\n+\t\t\t\"BUG: only IPv4 is supported for now.\\n\");\n+\tif ((params->depth == 0) || (params->depth > 32)) {\n+\t\t\tprintf(\"Illegal value for depth parameter (%u)\\n\",\n+\t\t\t\tparams->depth);\n+\t\t\treturn;\n \t\t}\n+\n+\tnetmask = (~0) << (32 - params->depth);\n+\n+\t/* Create route */\n+\tif (params->ip.family == AF_INET) {\n+\t\tkey.type = PIPELINE_ROUTING_ROUTE_IPV4;\n+\t\tkey.key.ipv4.ip = rte_bswap32((uint32_t) params->ip.addr.ipv4.s_addr)\n+\t\t\t\t& netmask;\n+\t\tkey.key.ipv4.depth = params->depth;\n+\t} else\n+\t\tAPP_CHECK(0, \"IPv6 not implemented yet\");\n+\n+\trt_params.flags = 0; /* FIXME: ? */\n+\trt_params.port_id = params->port;\n+\trt_params.ip = rte_bswap32((uint32_t) params->nh_ip.addr.ipv4.s_addr);\n+\tstatus = app_pipeline_routing_add_route(app, params->p, &key, &rt_params);\n+\n+\tif (status != 0) {\n+\t\tprintf(\"Command failed\\n\");\n+\t\treturn;\n \t}\n }\n \n-void\n-app_message_handle(struct app_core_routing_message_handle_params *params)\n+static cmdline_parse_token_string_t cmd_route_add_p_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_route_add_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+\n+static cmdline_parse_token_string_t cmd_route_add_route_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_route_add_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+\t\"add\");\n+\n+static cmdline_parse_token_ipaddr_t cmd_route_add_ip =\n+\tTOKEN_IPADDR_INITIALIZER(struct cmd_route_add_result, ip);\n+\n+static cmdline_parse_token_num_t cmd_route_add_depth =\n+\tTOKEN_NUM_INITIALIZER(struct cmd_route_add_result, depth, UINT8);\n+\n+static cmdline_parse_token_num_t cmd_route_add_port =\n+\tTOKEN_NUM_INITIALIZER(struct cmd_route_add_result, port, UINT8);\n+\n+static cmdline_parse_token_ipaddr_t cmd_route_add_nh_ip =\n+\tTOKEN_IPADDR_INITIALIZER(struct cmd_route_add_result, nh_ip);\n+\n+static cmdline_parse_inst_t cmd_route_add = {\n+\t.f = cmd_route_add_parsed,\n+\t.data = NULL,\n+\t.help_str = \"Route add\",\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\tNULL,\n+\t},\n+};\n+\n+/* *** Routing - Add Default *** */\n+struct cmd_route_add_default_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_fixed_string_t default_string;\n+\tuint8_t port;\n+};\n+\n+static void\n+cmd_route_add_default_parsed(\n+\tvoid *parsed_result,\n+\t__attribute__((unused)) struct cmdline *cl,\n+\tvoid *data)\n {\n-\tstruct rte_ring *ring_req = params->ring_req;\n-\tstruct rte_ring *ring_resp;\n-\tvoid *msg;\n-\tstruct app_msg_req *req;\n-\tstruct app_msg_resp *resp;\n-\tstruct rte_pipeline *p;\n-\tuint32_t *port_out_id;\n-\tuint32_t routing_table_id, arp_table_id;\n-\tint result;\n-\n-\t/* Read request message */\n-\tresult = rte_ring_sc_dequeue(ring_req, &msg);\n-\tif (result != 0)\n+\tstruct cmd_route_add_default_result *params = parsed_result;\n+\tstruct app_params *app = data;\n+\tint status;\n+\n+\tstatus = app_pipeline_routing_add_default_route(app, params->p,\n+\t\t\tparams->port);\n+\n+\tif (status != 0) {\n+\t\tprintf(\"Command failed\\n\");\n \t\treturn;\n+\t}\n+}\n \n-\tring_resp = params->ring_resp;\n-\tp = params->p;\n-\tport_out_id = params->port_out_id;\n-\trouting_table_id = params->routing_table_id;\n-\tarp_table_id = params->arp_table_id;\n-\n-\t/* Handle request */\n-\treq = (struct app_msg_req *)rte_ctrlmbuf_data((struct rte_mbuf *)msg);\n-\tswitch (req->type) {\n-\tcase APP_MSG_REQ_PING:\n-\t{\n-\t\tresult = 0;\n-\t\tbreak;\n+static cmdline_parse_token_string_t cmd_route_add_default_p_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_route_add_default_result, p_string,\n+\t\"p\");\n+\n+static cmdline_parse_token_num_t cmd_route_add_default_p =\n+\tTOKEN_NUM_INITIALIZER(struct cmd_route_add_default_result, p, UINT32);\n+\n+cmdline_parse_token_string_t cmd_route_add_default_route_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_route_add_default_result, route_string,\n+\t\"route\");\n+\n+cmdline_parse_token_string_t cmd_route_add_default_add_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_route_add_default_result, add_string,\n+\t\"add\");\n+\n+cmdline_parse_token_string_t cmd_route_add_default_default_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_route_add_default_result,\n+\tdefault_string, \"default\");\n+\n+cmdline_parse_token_num_t cmd_route_add_default_port =\n+\tTOKEN_NUM_INITIALIZER(struct cmd_route_add_default_result, port, UINT8);\n+\n+cmdline_parse_inst_t cmd_route_add_default = {\n+\t.f = cmd_route_add_default_parsed,\n+\t.data = NULL,\n+\t.help_str = \"Set the default route\",\n+\t.tokens = {\n+\t\t(void *)&cmd_route_add_default_p_string,\n+\t\t(void *)&cmd_route_add_default_p,\n+\t\t(void *)&cmd_route_add_default_route_string,\n+\t\t(void *)&cmd_route_add_default_add_string,\n+\t\t(void *)&cmd_route_add_default_default_string,\n+\t\t(void *)&cmd_route_add_default_port,\n+\t\tNULL,\n+\t},\n+};\n+\n+/* *** Routing - Del *** */\n+struct cmd_route_del_result {\n+\tcmdline_fixed_string_t p_string;\n+\tuint32_t p;\n+\tcmdline_fixed_string_t route_string;\n+\tcmdline_fixed_string_t del_string;\n+\tcmdline_ipaddr_t ip;\n+\tuint8_t depth;\n+};\n+\n+static void\n+cmd_route_del_parsed(\n+\tvoid *parsed_result,\n+\t__rte_unused struct cmdline *cl,\n+\tvoid *data)\n+{\n+\tstruct cmd_route_del_result *params = parsed_result;\n+\tstruct app_params *app = data;\n+\tstruct pipeline_routing_route_key key;\n+\tuint32_t netmask;\n+\n+\tint status;\n+\n+\tAPP_CHECK(params->ip.family == AF_INET,\n+\t\t\t\"BUG: only IPv4 is supported for now.\\n\");\n+\tif ((params->depth == 0) || (params->depth > 32)) {\n+\t\tprintf(\"Illegal value for depth parameter (%u)\\n\",\n+\t\t\tparams->depth);\n+\t\treturn;\n \t}\n \n-\tcase APP_MSG_REQ_RT_ADD:\n-\t{\n-\t\tstruct app_routing_table_entry entry = {\n-\t\t\t.head = {\n-\t\t\t\t.action = RTE_PIPELINE_ACTION_TABLE,\n-\t\t\t\t{.table_id = arp_table_id},\n-\t\t\t},\n-\t\t\t.nh_ip = req->routing_add.nh_ip,\n-\t\t\t.nh_iface = port_out_id[req->routing_add.port],\n-\t\t};\n-\n-\t\tstruct rte_table_lpm_key key = {\n-\t\t\t.ip = req->routing_add.ip,\n-\t\t\t.depth = req->routing_add.depth,\n-\t\t};\n-\n-\t\tstruct rte_pipeline_table_entry *entry_ptr;\n-\n-\t\tint key_found;\n-\n-\t\tresult = rte_pipeline_table_entry_add(p, routing_table_id, &key,\n-\t\t\t(struct rte_pipeline_table_entry *) &entry, &key_found,\n-\t\t\t&entry_ptr);\n-\t\tbreak;\n+\tnetmask = (~0) << (32 - params->depth);\n+\n+\t/* Create route */\n+\tif (params->ip.family == AF_INET) {\n+\t\tkey.type = PIPELINE_ROUTING_ROUTE_IPV4;\n+\t\tkey.key.ipv4.ip = rte_bswap32((uint32_t) params->ip.addr.ipv4.s_addr)\n+\t\t\t\t& netmask;\n+\t\tkey.key.ipv4.depth = params->depth;\n+\t} else\n+\t\tAPP_CHECK(0, \"IPv6 not implemented yet\");\n+\n+\tstatus = app_pipeline_routing_delete_route(app, params->p, &key);\n+\n+\tif (status != 0) {\n+\t\tprintf(\"Command failed\\n\");\n+\t\treturn;\n \t}\n+}\n \n-\tcase APP_MSG_REQ_RT_DEL:\n-\t{\n-\t\tstruct rte_table_lpm_key key = {\n-\t\t\t.ip = req->routing_del.ip,\n-\t\t\t.depth = req->routing_del.depth,\n-\t\t};\n+static cmdline_parse_token_string_t cmd_route_del_p_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_route_del_result, p_string,\n+\t\"p\");\n+\n+static cmdline_parse_token_num_t cmd_route_del_p =\n+\tTOKEN_NUM_INITIALIZER(struct cmd_route_del_result, p, UINT32);\n+\n+static cmdline_parse_token_string_t cmd_route_del_route_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_route_del_result, route_string,\n+\t\"route\");\n+\n+static cmdline_parse_token_string_t cmd_route_del_del_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_route_del_result, del_string,\n+\t\"del\");\n+\n+static cmdline_parse_token_ipaddr_t cmd_route_del_ip =\n+\tTOKEN_IPADDR_INITIALIZER(struct cmd_route_del_result, ip);\n+\n+static cmdline_parse_token_num_t cmd_route_del_depth =\n+\tTOKEN_NUM_INITIALIZER(struct cmd_route_del_result, depth, UINT8);\n+\n+static cmdline_parse_inst_t cmd_route_del = {\n+\t.f = cmd_route_del_parsed,\n+\t.data = NULL,\n+\t.help_str = \"Route delete\",\n+\t.tokens = {\n+\t\t(void *)&cmd_route_del_p_string,\n+\t\t(void *)&cmd_route_del_p,\n+\t\t(void *)&cmd_route_del_route_string,\n+\t\t(void *)&cmd_route_del_del_string,\n+\t\t(void *)&cmd_route_del_ip,\n+\t\t(void *)&cmd_route_del_depth,\n+\t\tNULL,\n+\t},\n+};\n \n-\t\tint key_found;\n+/* *** Routing - Del default *** */\n+struct cmd_route_del_default_result {\n+\tcmdline_fixed_string_t p_string;\n+\tuint32_t p;\n+\tcmdline_fixed_string_t route_string;\n+\tcmdline_fixed_string_t del_string;\n+\tcmdline_fixed_string_t default_string;\n+\tuint8_t out_iface;\n+};\n+\n+static void\n+cmd_route_del_default_parsed(\n+\t__rte_unused void *parsed_result,\n+\t__rte_unused struct cmdline *cl,\n+\t__rte_unused void *data)\n+{\n+\tstruct cmd_route_del_default_result *params = parsed_result;\n+\tstruct app_params *app = data;\n+\tint status;\n \n-\t\tresult = rte_pipeline_table_entry_delete(p, routing_table_id,\n-\t\t\t&key, &key_found, NULL);\n-\t\tbreak;\n+\tstatus = app_pipeline_routing_add_default_route(app, params->p,\n+\t\t\tparams->out_iface);\n+\n+\tif (status != 0) {\n+\t\tprintf(\"Command failed\\n\");\n+\t\treturn;\n \t}\n+}\n \n-\tcase APP_MSG_REQ_ARP_ADD:\n-\t{\n+static cmdline_parse_token_string_t cmd_route_del_default_p_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_route_del_default_result, p_string,\n+\t\"p\");\n+\n+static cmdline_parse_token_num_t cmd_route_del_default_p =\n+\tTOKEN_NUM_INITIALIZER(struct cmd_route_del_default_result, p, UINT32);\n+\n+static cmdline_parse_token_string_t cmd_route_del_default_route_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_route_del_default_result, route_string,\n+\t\"route\");\n+\n+static cmdline_parse_token_string_t cmd_route_del_default_del_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_route_del_default_result, del_string,\n+\t\"del\");\n+\n+static cmdline_parse_token_string_t cmd_route_del_default_default_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_route_del_default_result,\n+\tdefault_string, \"default\");\n+\n+\n+static cmdline_parse_inst_t cmd_route_del_default = {\n+\t.f = cmd_route_del_default_parsed,\n+\t.data = NULL,\n+\t.help_str = \"Route delete\",\n+\t.tokens = {\n+\t\t(void *)&cmd_route_del_default_p_string,\n+\t\t(void *)&cmd_route_del_default_p,\n+\t\t(void *)&cmd_route_del_default_route_string,\n+\t\t(void *)&cmd_route_del_default_del_string,\n+\t\t(void *)&cmd_route_del_default_default_string,\n+\t\tNULL,\n+\t},\n+};\n \n-\t\tstruct app_arp_table_entry entry = {\n-\t\t\t.head = {\n-\t\t\t\t.action = RTE_PIPELINE_ACTION_PORT,\n-\t\t\t\t{.port_id =\n-\t\t\t\t\tport_out_id[req->arp_add.out_iface]},\n-\t\t\t},\n-\t\t\t.nh_arp = req->arp_add.nh_arp,\n-\t\t};\n+/* *** Routing - List *** */\n+struct cmd_route_ls_result {\n+\tcmdline_fixed_string_t p_string;\n+\tuint32_t p;\n+\tcmdline_fixed_string_t route_string;\n+\tcmdline_fixed_string_t ls_string;\n+};\n \n-\t\tstruct app_arp_key arp_key = {\n-\t\t\t.nh_ip = req->arp_add.nh_ip,\n-\t\t\t.nh_iface = port_out_id[req->arp_add.out_iface],\n-\t\t};\n+static void\n+cmd_route_ls_parsed(\n+\tvoid *parsed_result,\n+\t__rte_unused struct cmdline *cl,\n+\tvoid *data)\n+{\n+\tstruct cmd_route_ls_result *params = parsed_result;\n+\tstruct app_params *app = data;\n+\tint status;\n \n-\t\tstruct rte_pipeline_table_entry *entry_ptr;\n+\tstatus = app_pipeline_routing_ls(app, params->p);\n \n-\t\tint key_found;\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_ls_p_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_route_ls_result, p_string, \"p\");\n+\n+static cmdline_parse_token_num_t cmd_route_ls_p =\n+\tTOKEN_NUM_INITIALIZER(struct cmd_route_ls_result, p, UINT32);\n+\n+static cmdline_parse_token_string_t cmd_route_ls_route_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_route_ls_result,\n+\troute_string, \"route\");\n+\n+static cmdline_parse_token_string_t cmd_route_ls_ls_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_route_ls_result, ls_string,\n+\t\"ls\");\n+\n+static cmdline_parse_inst_t cmd_route_ls = {\n+\t.f = cmd_route_ls_parsed,\n+\t.data = NULL,\n+\t.help_str = \"Route list\",\n+\t.tokens = {\n+\t\t(void *)&cmd_route_ls_p_string,\n+\t\t(void *)&cmd_route_ls_p,\n+\t\t(void *)&cmd_route_ls_route_string,\n+\t\t(void *)&cmd_route_ls_ls_string,\n+\t\tNULL,\n+\t},\n+};\n+\n+/* *** ARP - Add *** */\n+struct cmd_arp_add_result {\n+\tcmdline_fixed_string_t p_string;\n+\tuint32_t p;\n+\tcmdline_fixed_string_t arp_string;\n+\tcmdline_fixed_string_t add_string;\n+\tuint8_t out_iface;\n+\tcmdline_ipaddr_t nh_ip;\n+\tstruct ether_addr nh_arp;\n+\n+};\n+\n+static void\n+cmd_arp_add_parsed(\n+\tvoid *parsed_result,\n+\t__rte_unused struct cmdline *cl,\n+\tvoid *data)\n+{\n+\tstruct cmd_arp_add_result *params = parsed_result;\n+\tstruct app_params *app = data;\n+\n+\tstruct pipeline_routing_arp_key key;\n+\tint status;\n+\n+\tAPP_CHECK(params->nh_ip.family == AF_INET,\n+\t\t\t\"BUG: only IPv4 is supported for now.\\n\");\n+\n+\tkey.key.ipv4.port_id = params->out_iface;\n+\tkey.key.ipv4.ip = rte_cpu_to_be_32(params->nh_ip.addr.ipv4.s_addr);\n \n-\t\tresult = rte_pipeline_table_entry_add(p, arp_table_id, &arp_key,\n-\t\t\t(struct rte_pipeline_table_entry *) &entry, &key_found,\n-\t\t\t&entry_ptr);\n-\t\tbreak;\n+\tstatus = app_pipeline_routing_add_arp_entry(app, params->p, &key,\n+\t\t\t&params->nh_arp);\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_arp_add_p_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_arp_add_result, p_string,\n+\t\"p\");\n+\n+static cmdline_parse_token_num_t cmd_arp_add_p =\n+\tTOKEN_NUM_INITIALIZER(struct cmd_arp_add_result, p, UINT32);\n+\n+static cmdline_parse_token_string_t cmd_arp_add_arp_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_arp_add_result, arp_string, \"arp\");\n+\n+static cmdline_parse_token_string_t cmd_arp_add_add_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_arp_add_result, add_string, \"add\");\n+\n+static cmdline_parse_token_num_t cmd_arp_add_out_iface =\n+\tTOKEN_NUM_INITIALIZER(struct cmd_arp_add_result, out_iface, UINT8);\n+\n+static cmdline_parse_token_ipaddr_t cmd_arp_add_nh_ip =\n+\tTOKEN_IPV4_INITIALIZER(struct cmd_arp_add_result, nh_ip);\n+\n+static cmdline_parse_token_etheraddr_t cmd_arp_add_nh_arp =\n+\tTOKEN_ETHERADDR_INITIALIZER(struct cmd_arp_add_result, nh_arp);\n+\n+static cmdline_parse_inst_t cmd_arp_add = {\n+\t.f = cmd_arp_add_parsed,\n+\t.data = NULL,\n+\t.help_str = \"ARP add\",\n+\t.tokens = {\n+\t\t(void *)&cmd_arp_add_p_string,\n+\t\t(void *)&cmd_arp_add_p,\n+\t\t(void *)&cmd_arp_add_arp_string,\n+\t\t(void *)&cmd_arp_add_add_string,\n+\t\t(void *)&cmd_arp_add_out_iface,\n+\t\t(void *)&cmd_arp_add_nh_ip,\n+\t\t(void *)&cmd_arp_add_nh_arp,\n+\t\tNULL,\n+\t},\n+};\n+\n+/* *** ARP - Add default *** */\n+struct cmd_arp_add_default_result {\n+\tcmdline_fixed_string_t p_string;\n+\tuint32_t p;\n+\tcmdline_fixed_string_t arp_string;\n+\tcmdline_fixed_string_t del_string;\n+\tcmdline_fixed_string_t default_string;\n+\tuint8_t out_iface;\n+};\n+\n+static void\n+cmd_arp_add_default_parsed(\n+\t__rte_unused void *parsed_result,\n+\t__rte_unused struct cmdline *cl,\n+\t__rte_unused void *data)\n+{\n+\tstruct cmd_arp_add_default_result *params = parsed_result;\n+\tstruct app_params *app = data;\n+\n+\tint status;\n+\n+\tstatus = app_pipeline_routing_add_default_arp_entry(app, params->p,\n+\t\t\tparams->out_iface);\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_arp_add_default_p_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_arp_add_default_result, p_string,\n+\t\"p\");\n+\n+static cmdline_parse_token_num_t cmd_arp_add_default_p =\n+\tTOKEN_NUM_INITIALIZER(struct cmd_arp_add_default_result, p, UINT32);\n+\n+static cmdline_parse_token_string_t cmd_arp_add_default_arp_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_arp_add_default_result, arp_string,\n+\t\"arp\");\n+\n+static cmdline_parse_token_string_t cmd_arp_add_default_add_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_arp_add_default_result, del_string,\n+\t\"del\");\n+\n+static cmdline_parse_token_string_t cmd_arp_add_default_default_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_arp_add_default_result, default_string,\n+\t\"default\");\n+\n+static cmdline_parse_token_num_t cmd_arp_add_default_out_iface =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_arp_add_default_result, out_iface,\n+\tUINT8);\n+\n+static cmdline_parse_inst_t cmd_arp_add_default = {\n+\t.f = cmd_arp_add_default_parsed,\n+\t.data = NULL,\n+\t.help_str = \"ARP add default\",\n+\t.tokens = {\n+\t\t(void *)&cmd_arp_add_default_p_string,\n+\t\t(void *)&cmd_arp_add_default_p,\n+\t\t(void *)&cmd_arp_add_default_arp_string,\n+\t\t(void *)&cmd_arp_add_default_add_string,\n+\t\t(void *)&cmd_arp_add_default_default_string,\n+\t\t(void *)&cmd_arp_add_default_out_iface,\n+\t\tNULL,\n+\t},\n+};\n+\n+/* *** ARP - Del *** */\n+struct cmd_arp_del_result {\n+\tcmdline_fixed_string_t p_string;\n+\tuint32_t p;\n+\tcmdline_fixed_string_t arp_string;\n+\tcmdline_fixed_string_t del_string;\n+\tuint8_t out_iface;\n+\tcmdline_ipaddr_t nh_ip;\n+};\n+\n+static void\n+cmd_arp_del_parsed(\n+\tvoid *parsed_result,\n+\t__rte_unused struct cmdline *cl,\n+\tvoid *data)\n+{\n+\tstruct cmd_arp_del_result *params = parsed_result;\n+\tstruct app_params *app = data;\n+\n+\tstruct pipeline_routing_arp_key key;\n+\tint status;\n \n-\tcase APP_MSG_REQ_ARP_DEL:\n-\t{\n-\t\tstruct app_arp_key arp_key = {\n-\t\t\t.nh_ip = req->arp_del.nh_ip,\n-\t\t\t.nh_iface = port_out_id[req->arp_del.out_iface],\n-\t\t};\n+\tAPP_CHECK(params->nh_ip.family != AF_INET,\n+\t\t\t\"BUG: only IPv4 is supported for now.\\n\");\n \n-\t\tint key_found;\n+\tkey.key.ipv4.ip = rte_cpu_to_be_32(params->nh_ip.addr.ipv4.s_addr);\n+\tkey.key.ipv4.port_id = params->out_iface;\n \n-\t\tresult = rte_pipeline_table_entry_delete(p, arp_table_id,\n-\t\t\t&arp_key, &key_found, NULL);\n-\t\tbreak;\n+\tstatus = app_pipeline_routing_delete_arp_entry(app, params->p, &key);\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_arp_del_p_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_arp_del_result, p_string,\n+\t\"p\");\n+\n+static cmdline_parse_token_num_t cmd_arp_del_p =\n+\tTOKEN_NUM_INITIALIZER(struct cmd_arp_del_result, p, UINT32);\n+\n+static cmdline_parse_token_string_t cmd_arp_del_arp_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_arp_del_result, arp_string, \"arp\");\n+\n+static cmdline_parse_token_string_t cmd_arp_del_del_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_arp_del_result, del_string, \"del\");\n+\n+static cmdline_parse_token_num_t cmd_arp_del_out_iface =\n+\tTOKEN_NUM_INITIALIZER(struct cmd_arp_del_result, out_iface, UINT8);\n+\n+static cmdline_parse_token_ipaddr_t cmd_arp_del_nh_ip =\n+\tTOKEN_IPV4_INITIALIZER(struct cmd_arp_del_result, nh_ip);\n+\n+static cmdline_parse_inst_t cmd_arp_del = {\n+\t.f = cmd_arp_del_parsed,\n+\t.data = NULL,\n+\t.help_str = \"ARP delete\",\n+\t.tokens = {\n+\t\t(void *)&cmd_arp_del_p_string,\n+\t\t(void *)&cmd_arp_del_p,\n+\t\t(void *)&cmd_arp_del_arp_string,\n+\t\t(void *)&cmd_arp_del_del_string,\n+\t\t(void *)&cmd_arp_del_out_iface,\n+\t\t(void *)&cmd_arp_del_nh_ip,\n+\t\tNULL,\n+\t},\n+};\n+\n+/* *** ARP - Del default *** */\n+struct cmd_arp_del_default_result {\n+\tcmdline_fixed_string_t p_string;\n+\tuint32_t p;\n+\tcmdline_fixed_string_t arp_string;\n+\tcmdline_fixed_string_t del_string;\n+\tcmdline_fixed_string_t default_string;\n+};\n+\n+static void\n+cmd_arp_del_default_parsed(\n+\tvoid *parsed_result,\n+\t__rte_unused struct cmdline *cl,\n+\tvoid *data)\n+{\n+\tstruct cmd_arp_del_default_result *params = parsed_result;\n+\tstruct app_params *app = data;\n+\n+\tint status;\n \n-\tdefault:\n-\t\trte_panic(\"RT Unrecognized message type (%u)\\n\", req->type);\n+\tstatus = app_pipeline_routing_delete_default_arp_entry(app, params->p);\n+\n+\tif (status != 0) {\n+\t\tprintf(\"Command failed\\n\");\n+\t\treturn;\n \t}\n+}\n \n-\t/* Fill in response message */\n-\tresp = (struct app_msg_resp *)rte_ctrlmbuf_data((struct rte_mbuf *)msg);\n-\tresp->result = result;\n+static cmdline_parse_token_string_t cmd_arp_del_default_p_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_arp_del_default_result, p_string,\n+\t\"p\");\n+\n+static cmdline_parse_token_num_t cmd_arp_del_default_p =\n+\tTOKEN_NUM_INITIALIZER(struct cmd_arp_del_default_result, p, UINT32);\n+\n+static cmdline_parse_token_string_t cmd_arp_del_default_arp_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_arp_del_default_result, arp_string,\n+\t\"arp\");\n+\n+static cmdline_parse_token_string_t cmd_arp_del_default_del_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_arp_del_default_result, del_string,\n+\t\"del\");\n+\n+static cmdline_parse_token_string_t cmd_arp_del_default_default_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_arp_del_default_result, default_string,\n+\t\"default\");\n+\n+static cmdline_parse_inst_t cmd_arp_del_default = {\n+\t.f = cmd_arp_del_default_parsed,\n+\t.data = NULL,\n+\t.help_str = \"ARP delete default\",\n+\t.tokens = {\n+\t\t(void *)&cmd_arp_del_default_p_string,\n+\t\t(void *)&cmd_arp_del_default_p,\n+\t\t(void *)&cmd_arp_del_default_arp_string,\n+\t\t(void *)&cmd_arp_del_default_del_string,\n+\t\t(void *)&cmd_arp_del_default_default_string,\n+\t\tNULL,\n+\t},\n+};\n \n-\t/* Send response */\n-\tdo {\n-\t\tresult = rte_ring_sp_enqueue(ring_resp, msg);\n-\t} while (result == -ENOBUFS);\n+/* *** ARP - Print *** */\n+struct cmd_arp_ls_result {\n+\tcmdline_fixed_string_t p_string;\n+\tuint32_t p;\n+\tcmdline_fixed_string_t arp_string;\n+\tcmdline_fixed_string_t ls_string;\n+};\n+\n+static void\n+cmd_arp_ls_parsed(\n+\tvoid *parsed_result,\n+\t__rte_unused struct cmdline *cl,\n+\tvoid *data)\n+{\n+\tstruct cmd_arp_ls_result *params = parsed_result;\n+\tstruct app_params *app = data;\n+\tstruct pipeline_routing *p;\n+\n+\tp = app_pipeline_data_fe(app, params->p);\n+\tif (p == NULL)\n+\t\treturn;\n+\n+\tapp_pipeline_routing_arp_ls(app, params->p);\n }\n+\n+static cmdline_parse_token_string_t cmd_arp_ls_p_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_arp_ls_result, p_string,\n+\t\"p\");\n+\n+static cmdline_parse_token_num_t cmd_arp_ls_p =\n+\tTOKEN_NUM_INITIALIZER(struct cmd_arp_ls_result, p, UINT32);\n+\n+static cmdline_parse_token_string_t cmd_arp_ls_arp_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_arp_ls_result, arp_string,\n+\t\"arp\");\n+\n+static cmdline_parse_token_string_t cmd_arp_ls_ls_string =\n+\tTOKEN_STRING_INITIALIZER(struct cmd_arp_ls_result, ls_string,\n+\t\"ls\");\n+\n+static cmdline_parse_inst_t cmd_arp_ls = {\n+\t.f = cmd_arp_ls_parsed,\n+\t.data = NULL,\n+\t.help_str = \"ARP list\",\n+\t.tokens = {\n+\t\t(void *)&cmd_arp_ls_p_string,\n+\t\t(void *)&cmd_arp_ls_p,\n+\t\t(void *)&cmd_arp_ls_arp_string,\n+\t\t(void *)&cmd_arp_ls_ls_string,\n+\t\tNULL,\n+\t},\n+};\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_del,\n+\t(cmdline_parse_inst_t *)&cmd_route_add_default,\n+\t(cmdline_parse_inst_t *)&cmd_route_del_default,\n+\t(cmdline_parse_inst_t *)&cmd_route_ls,\n+\t(cmdline_parse_inst_t *)&cmd_arp_add,\n+\t(cmdline_parse_inst_t *)&cmd_arp_del,\n+\t(cmdline_parse_inst_t *)&cmd_arp_add_default,\n+\t(cmdline_parse_inst_t *)&cmd_arp_del_default,\n+\t(cmdline_parse_inst_t *)&cmd_arp_ls,\n+\tNULL,\n+};\n+\n+static struct pipeline_fe_ops pipeline_routing_fe_ops = {\n+\t.f_init = pipeline_routing_init,\n+\t.f_free = app_pipeline_routing_free,\n+\t.cmds = pipeline_cmds,\n+};\n+\n+struct pipeline_type pipeline_routing = {\n+\t.name = \"ROUTING\",\n+\t.ops = &pipeline_routing_ops,\n+\t.fe_ops = &pipeline_routing_fe_ops,\n+};\ndiff --git a/examples/ip_pipeline/pipeline/pipeline_routing.h b/examples/ip_pipeline/pipeline/pipeline_routing.h\nnew file mode 100644\nindex 0000000..c5892d8\n--- /dev/null\n+++ b/examples/ip_pipeline/pipeline/pipeline_routing.h\n@@ -0,0 +1,99 @@\n+/*-\n+ *   BSD LICENSE\n+ *\n+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.\n+ *   All rights reserved.\n+ *\n+ *   Redistribution and use in source and binary forms, with or without\n+ *   modification, are permitted provided that the following conditions\n+ *   are met:\n+ *\n+ *     * Redistributions of source code must retain the above copyright\n+ *       notice, this list of conditions and the following disclaimer.\n+ *     * Redistributions in binary form must reproduce the above copyright\n+ *       notice, this list of conditions and the following disclaimer in\n+ *       the documentation and/or other materials provided with the\n+ *       distribution.\n+ *     * Neither the name of Intel Corporation nor the names of its\n+ *       contributors may be used to endorse or promote products derived\n+ *       from this software without specific prior written permission.\n+ *\n+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n+ *   \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+ */\n+\n+#ifndef __INCLUDE_PIPELINE_ROUTING_H__\n+#define __INCLUDE_PIPELINE_ROUTING_H__\n+\n+#include \"pipeline.h\"\n+#include \"pipeline_routing_ops.h\"\n+\n+/*\n+ * Route\n+ */\n+\n+struct app_pipeline_routing_route_params {\n+\tenum pipeline_routing_route_flags 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+\n+int\n+app_pipeline_routing_delete_route(struct app_params *app,\n+\tuint32_t pipeline_id,\n+\tstruct pipeline_routing_route_key *key);\n+\n+int\n+app_pipeline_routing_add_default_route(struct app_params *app,\n+\tuint32_t pipeline_id,\n+\tuint32_t port_id);\n+\n+int\n+app_pipeline_routing_delete_default_route(struct app_params *app,\n+\tuint32_t pipeline_id);\n+\n+/*\n+ * ARP\n+ */\n+\n+int\n+app_pipeline_routing_add_arp_entry(struct app_params *app,\n+\tuint32_t pipeline_id,\n+\tstruct pipeline_routing_arp_key *key,\n+\tstruct ether_addr *macaddr);\n+\n+int\n+app_pipeline_routing_delete_arp_entry(struct app_params *app,\n+\tuint32_t pipeline_id,\n+\tstruct pipeline_routing_arp_key *key);\n+\n+int\n+app_pipeline_routing_add_default_arp_entry(struct app_params *app,\n+\tuint32_t pipeline_id,\n+\tuint32_t port_id);\n+\n+int\n+app_pipeline_routing_delete_default_arp_entry(struct app_params *app,\n+\tuint32_t pipeline_id);\n+\n+/*\n+ * Pipeline type\n+ */\n+extern struct pipeline_type pipeline_routing;\n+\n+#endif\ndiff --git a/examples/ip_pipeline/pipeline/pipeline_routing_ops.c b/examples/ip_pipeline/pipeline/pipeline_routing_ops.c\nnew file mode 100644\nindex 0000000..4a29502\n--- /dev/null\n+++ b/examples/ip_pipeline/pipeline/pipeline_routing_ops.c\n@@ -0,0 +1,978 @@\n+/*-\n+ *   BSD LICENSE\n+ *\n+ *   Copyright(c) 2010-2015 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 <stdio.h>\n+#include <stdlib.h>\n+#include <stdint.h>\n+#include <string.h>\n+#include <unistd.h>\n+\n+#include <rte_common.h>\n+#include <rte_log.h>\n+#include <rte_malloc.h>\n+#include <rte_ip.h>\n+#include <rte_byteorder.h>\n+#include <rte_table_lpm.h>\n+#include <rte_table_hash.h>\n+#include <rte_pipeline.h>\n+\n+#include \"pipeline_common_ops.h\"\n+#include \"pipeline_routing_ops.h\"\n+\n+struct pipeline_routing {\n+\tstruct pipeline p;\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 n_arp_entries_ext;\n+\tuint32_t ip_da_offset;\n+\tuint32_t arp_key_offset;\n+} __rte_cache_aligned;\n+\n+static void *\n+pipeline_routing_msg_req_custom_handler(struct pipeline *p, void *msg);\n+\n+static pipeline_msg_req_handler handlers[] = {\n+\t[PIPELINE_MSG_REQ_PING] = pipeline_msg_req_ping_handler,\n+\t[PIPELINE_MSG_REQ_STATS_PORT_IN] = pipeline_msg_req_stats_port_in_handler,\n+\t[PIPELINE_MSG_REQ_STATS_PORT_OUT] = pipeline_msg_req_stats_port_out_handler,\n+\t[PIPELINE_MSG_REQ_STATS_TABLE] = pipeline_msg_req_stats_table_handler,\n+\t[PIPELINE_MSG_REQ_PORT_IN_ENABLE] = pipeline_msg_req_port_in_enable_handler,\n+\t[PIPELINE_MSG_REQ_PORT_IN_DISABLE] = pipeline_msg_req_port_in_disable_handler,\n+\t[PIPELINE_MSG_REQ_CUSTOM] = pipeline_routing_msg_req_custom_handler,\n+};\n+\n+static void *\n+pipeline_routing_msg_req_route_add_handler(struct pipeline *p, void *msg);\n+\n+static void *\n+pipeline_routing_msg_req_route_del_handler(struct pipeline *p, void *msg);\n+\n+static void *\n+pipeline_routing_msg_req_route_add_default_handler(struct pipeline *p, void *msg);\n+\n+static void *\n+pipeline_routing_msg_req_route_del_default_handler(struct pipeline *p, void *msg);\n+\n+static void *\n+pipeline_routing_msg_req_arp_add_handler(struct pipeline *p, void *msg);\n+\n+static void *\n+pipeline_routing_msg_req_arp_del_handler(struct pipeline *p, void *msg);\n+\n+static void *\n+pipeline_routing_msg_req_arp_add_default_handler(struct pipeline *p, void *msg);\n+\n+static void *\n+pipeline_routing_msg_req_arp_del_default_handler(struct pipeline *p, void *msg);\n+\n+static pipeline_msg_req_handler custom_handlers[] = {\n+\t[PIPELINE_ROUTING_MSG_REQ_ROUTE_ADD] = pipeline_routing_msg_req_route_add_handler,\n+\t[PIPELINE_ROUTING_MSG_REQ_ROUTE_DEL] = pipeline_routing_msg_req_route_del_handler,\n+\t[PIPELINE_ROUTING_MSG_REQ_ROUTE_ADD_DEFAULT] = pipeline_routing_msg_req_route_add_default_handler,\n+\t[PIPELINE_ROUTING_MSG_REQ_ROUTE_DEL_DEFAULT] = pipeline_routing_msg_req_route_del_default_handler,\n+\t[PIPELINE_ROUTING_MSG_REQ_ARP_ADD] = pipeline_routing_msg_req_arp_add_handler,\n+\t[PIPELINE_ROUTING_MSG_REQ_ARP_DEL] = pipeline_routing_msg_req_arp_del_handler,\n+\t[PIPELINE_ROUTING_MSG_REQ_ARP_ADD_DEFAULT] = pipeline_routing_msg_req_arp_add_default_handler,\n+\t[PIPELINE_ROUTING_MSG_REQ_ARP_DEL_DEFAULT] = pipeline_routing_msg_req_arp_del_default_handler,\n+};\n+\n+/*\n+ * Routing table\n+ */\n+struct routing_table_entry {\n+\tstruct rte_pipeline_table_entry head;\n+\tenum pipeline_routing_route_flags flags;\n+\tuint32_t port_id; /* Output port ID */\n+\tuint32_t ip; /* IP address for the next hop (only valid for remote routes) */\n+};\n+\n+static inline void\n+pkt_work_routing(\n+\tstruct pipeline_routing *p_rt,\n+\tstruct rte_mbuf *pkt,\n+\tstruct routing_table_entry *entry)\n+{\n+\tstruct pipeline_routing_arp_key_ipv4 *arp_key = \n+\t\t(struct pipeline_routing_arp_key_ipv4 *) RTE_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\t\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+}\n+\n+static inline void\n+pkt4_work_routing(\n+\tstruct pipeline_routing *p_rt,\n+\tstruct rte_mbuf *pkt0,\n+\tstruct rte_mbuf *pkt1,\n+\tstruct rte_mbuf *pkt2,\n+\tstruct rte_mbuf *pkt3,\n+\tstruct routing_table_entry *entry0,\n+\tstruct routing_table_entry *entry1,\n+\tstruct routing_table_entry *entry2,\n+\tstruct routing_table_entry *entry3)\n+{\n+\tstruct pipeline_routing_arp_key_ipv4 *arp_key0 = \n+\t\t(struct pipeline_routing_arp_key_ipv4 *) RTE_MBUF_METADATA_UINT8_PTR(pkt0, p_rt->arp_key_offset);\n+\tstruct pipeline_routing_arp_key_ipv4 *arp_key1 = \n+\t\t(struct pipeline_routing_arp_key_ipv4 *) RTE_MBUF_METADATA_UINT8_PTR(pkt1, p_rt->arp_key_offset);\n+\tstruct pipeline_routing_arp_key_ipv4 *arp_key2 = \n+\t\t(struct pipeline_routing_arp_key_ipv4 *) RTE_MBUF_METADATA_UINT8_PTR(pkt2, p_rt->arp_key_offset);\n+\tstruct pipeline_routing_arp_key_ipv4 *arp_key3 = \n+\t\t(struct pipeline_routing_arp_key_ipv4 *) RTE_MBUF_METADATA_UINT8_PTR(pkt3, p_rt->arp_key_offset);\n+\n+\tuint32_t ip0 = RTE_MBUF_METADATA_UINT32(pkt0, p_rt->ip_da_offset);\n+\tuint32_t ip1 = RTE_MBUF_METADATA_UINT32(pkt1, p_rt->ip_da_offset);\n+\tuint32_t ip2 = RTE_MBUF_METADATA_UINT32(pkt2, p_rt->ip_da_offset);\n+\tuint32_t ip3 = RTE_MBUF_METADATA_UINT32(pkt3, p_rt->ip_da_offset);\n+\t\t\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+\n+\tarp_key0->ip = entry0->ip;\n+\tif (entry0->flags & PIPELINE_ROUTING_ROUTE_LOCAL)\n+\t\tarp_key0->ip = ip0;\n+\tarp_key1->ip = entry1->ip;\n+\tif (entry1->flags & PIPELINE_ROUTING_ROUTE_LOCAL)\n+\t\tarp_key1->ip = ip1;\n+\tarp_key2->ip = entry2->ip;\n+\tif (entry2->flags & PIPELINE_ROUTING_ROUTE_LOCAL)\n+\t\tarp_key2->ip = ip2;\n+\tarp_key3->ip = entry3->ip;\n+\tif (entry3->flags & PIPELINE_ROUTING_ROUTE_LOCAL)\n+\t\tarp_key3->ip = ip3;\n+}\n+\n+static int\n+routing_table_ah_hit(\n+\tstruct rte_mbuf **pkts,\n+\tuint64_t *pkts_mask,\n+\tstruct rte_pipeline_table_entry **entries,\n+\tvoid *arg)\n+{\n+\tstruct pipeline_routing *p_rt = arg;\n+\tuint64_t pkts_in_mask = *pkts_mask;\n+\n+\tif ((pkts_in_mask & (pkts_in_mask + 1)) == 0) {\n+\t\tuint64_t n_pkts = __builtin_popcountll(pkts_in_mask);\n+\t\tuint32_t i;\n+\n+\t\tfor (i = 0; i < (n_pkts & 0x3); i += 4) {\n+\t\t\tstruct rte_mbuf *pkt0 = pkts[i];\n+\t\t\tstruct rte_mbuf *pkt1 = pkts[i + 1];\n+\t\t\tstruct rte_mbuf *pkt2 = pkts[i + 2];\n+\t\t\tstruct rte_mbuf *pkt3 = pkts[i + 3];\n+\n+\t\t\tstruct routing_table_entry *e0 =\n+\t\t\t\t(struct routing_table_entry *) entries[i];\n+\t\t\tstruct routing_table_entry *e1 =\n+\t\t\t\t(struct routing_table_entry *) entries[i + 1];\n+\t\t\tstruct routing_table_entry *e2 =\n+\t\t\t\t(struct routing_table_entry *) entries[i + 2];\n+\t\t\tstruct routing_table_entry *e3 =\n+\t\t\t\t(struct routing_table_entry *) entries[i + 3];\n+\n+\t\t\tpkt4_work_routing(p_rt, pkt0, pkt1, pkt2, pkt3, e0, e1, e2, e3);\n+\t\t}\n+\n+\t\tfor ( ; i < n_pkts; i++) {\n+\t\t\tstruct rte_mbuf *pkt = pkts[i];\n+\t\t\tstruct routing_table_entry *e =\n+\t\t\t\t(struct routing_table_entry *) entries[i];\n+\n+\t\t\tpkt_work_routing(p_rt, pkt, e);\n+\t\t}\n+\t} else\n+\t\tfor ( ; pkts_in_mask; ) {\n+\t\t\tstruct rte_mbuf *pkt;\n+\t\t\tstruct routing_table_entry *e;\n+\t\t\tuint64_t pkt_mask;\n+\t\t\tuint32_t packet_index;\n+\n+\t\t\tpacket_index = __builtin_ctzll(pkts_in_mask);\n+\t\t\tpkt_mask = 1LLU << packet_index;\n+\t\t\tpkts_in_mask &= ~pkt_mask;\n+\n+\t\t\tpkt = pkts[packet_index];\n+\t\t\te = (struct routing_table_entry *)\n+\t\t\t\tentries[packet_index];\n+\t\t\tpkt_work_routing(p_rt, pkt, e);\n+\t\t}\n+\n+\treturn 0;\n+}\n+\n+/*\n+ * ARP table\n+ */\n+struct arp_table_entry {\n+\tstruct rte_pipeline_table_entry head;\n+\tuint64_t macaddr;\n+};\n+\n+static uint64_t arp_table_hash(\n+\tvoid *key,\n+\t__rte_unused uint32_t key_size,\n+\t__rte_unused uint64_t seed)\n+{\n+\tuint32_t *k = (uint32_t *) key;\n+\n+\treturn k[1];\n+}\n+\n+static inline void\n+pkt_work_arp(\n+\t__rte_unused struct pipeline_routing *p_rt,\n+\tstruct rte_mbuf *pkt,\n+\tstruct arp_table_entry *entry)\n+{\n+\t/* Read: pkt buffer - mbuf */\n+\tuint8_t *raw = rte_pktmbuf_mtod(pkt, uint8_t *);\n+\n+\t/* Read: table entry */\n+\tuint64_t mac_addr_dst = entry->macaddr;\n+\tuint64_t mac_addr_src = 0;\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+}\n+\n+static inline void\n+pkt4_work_arp(\n+\t__rte_unused struct pipeline_routing *p_rt,\n+\tstruct rte_mbuf *pkt0,\n+\tstruct rte_mbuf *pkt1,\n+\tstruct rte_mbuf *pkt2,\n+\tstruct rte_mbuf *pkt3,\n+\tstruct arp_table_entry *entry0,\n+\tstruct arp_table_entry *entry1,\n+\tstruct arp_table_entry *entry2,\n+\tstruct arp_table_entry *entry3)\n+{\n+\t/* Read: pkt buffer - mbuf */\n+\tuint8_t *raw0 = rte_pktmbuf_mtod(pkt0, uint8_t *);\n+\tuint8_t *raw1 = rte_pktmbuf_mtod(pkt1, uint8_t *);\n+\tuint8_t *raw2 = rte_pktmbuf_mtod(pkt2, uint8_t *);\n+\tuint8_t *raw3 = rte_pktmbuf_mtod(pkt3, 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+}\n+\n+static int\n+arp_table_ah_hit(\n+\tstruct rte_mbuf **pkts,\n+\tuint64_t *pkts_mask,\n+\tstruct rte_pipeline_table_entry **entries,\n+\t__rte_unused void *arg)\n+{\n+\tstruct pipeline_routing *p_rt = arg;\n+\tuint64_t pkts_in_mask = *pkts_mask;\n+\n+\tif ((pkts_in_mask & (pkts_in_mask + 1)) == 0) {\n+\t\tuint64_t n_pkts = __builtin_popcountll(pkts_in_mask);\n+\t\tuint32_t i;\n+\n+\t\tfor (i = 0; i < (n_pkts & 0x3); i += 4) {\n+\t\t\tstruct rte_mbuf *pkt0 = pkts[i];\n+\t\t\tstruct rte_mbuf *pkt1 = pkts[i + 1];\n+\t\t\tstruct rte_mbuf *pkt2 = pkts[i + 2];\n+\t\t\tstruct rte_mbuf *pkt3 = pkts[i + 3];\n+\n+\t\t\tstruct arp_table_entry *e0 =\n+\t\t\t\t(struct arp_table_entry *) entries[i];\n+\t\t\tstruct arp_table_entry *e1 =\n+\t\t\t\t(struct arp_table_entry *) entries[i + 1];\n+\t\t\tstruct arp_table_entry *e2 =\n+\t\t\t\t(struct arp_table_entry *) entries[i + 2];\n+\t\t\tstruct arp_table_entry *e3 =\n+\t\t\t\t(struct arp_table_entry *) entries[i + 3];\n+\n+\t\t\tpkt4_work_arp(p_rt, pkt0, pkt1, pkt2, pkt3, e0, e1, e2, e3);\n+\t\t}\n+\n+\t\tfor ( ; i < n_pkts; i++) {\n+\t\t\tstruct rte_mbuf *pkt = pkts[i];\n+\t\t\tstruct arp_table_entry *e =\n+\t\t\t\t(struct arp_table_entry *) entries[i];\n+\n+\t\t\tpkt_work_arp(p_rt, pkt, e);\n+\t\t}\n+\t} else\n+\t\tfor ( ; pkts_in_mask; ) {\n+\t\t\tstruct rte_mbuf *pkt;\n+\t\t\tstruct arp_table_entry *e;\n+\t\t\tuint64_t pkt_mask;\n+\t\t\tuint32_t packet_index;\n+\n+\t\t\tpacket_index = __builtin_ctzll(pkts_in_mask);\n+\t\t\tpkt_mask = 1LLU << packet_index;\n+\t\t\tpkts_in_mask &= ~pkt_mask;\n+\n+\t\t\tpkt = pkts[packet_index];\n+\t\t\te = (struct arp_table_entry *)\n+\t\t\t\tentries[packet_index];\n+\t\t\tpkt_work_arp(p_rt, pkt, e);\n+\t\t}\n+\n+\treturn 0;\n+}\n+\n+static int\n+pipeline_routing_parse_args(struct pipeline_routing *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 n_arp_entries_ext_present = 0;\n+\tuint32_t ip_da_offset_present = 0;\n+\tuint32_t arp_key_offset_present = 0;\n+\tuint32_t i;\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+\n+\t\t/* n_routes */\n+\t\tif (strcmp(arg_name, \"n_routes\") == 0) {\n+\t\t\tif (n_routes_present)\n+\t\t\t\treturn -1;\n+\t\t\tn_routes_present = 1;\n+\n+\t\t\tp->n_routes = atoi(arg_value);\n+\t\t\tif (p->n_routes == 0)\n+\t\t\t\treturn -1;\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->n_arp_entries = atoi(arg_value);\n+\t\t\tif (p->n_arp_entries == 0)\n+\t\t\t\treturn -1;\n+\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\t/* n_arp_entries_ext */\n+\t\tif (strcmp(arg_name, \"n_arp_entries_ext\") == 0) {\n+\t\t\tif (n_arp_entries_ext_present)\n+\t\t\t\treturn -1;\n+\t\t\tn_arp_entries_ext_present = 1;\n+\n+\t\t\tp->n_arp_entries_ext = atoi(arg_value);\n+\t\t\tif (p->n_arp_entries_ext == 0)\n+\t\t\t\treturn -1;\n+\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\t\treturn -1;\n+\t\t\tip_da_offset_present = 1;\n+\n+\t\t\tp->ip_da_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\t\treturn -1;\n+\t\t\tarp_key_offset_present = 1;\n+\n+\t\t\tp->arp_key_offset = atoi(arg_value);\n+\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\t/* any other */\n+\t\treturn -1;\n+\t}\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(n_arp_entries_ext_present == 0) ||\n+\t\t(ip_da_offset_present == 0) ||\n+\t\t(n_arp_entries_present && (arp_key_offset_present == 0)))\n+\t\treturn -1;\n+\n+\treturn 0;\n+}\n+\n+static void *\n+pipeline_routing_init(struct pipeline_params *params,\n+\t__rte_unused void *arg)\n+{\n+\tstruct pipeline *p;\n+\tstruct pipeline_routing *p_rt;\n+\tuint32_t size, i;\n+\n+\t/* Check input arguments */\n+\tif ((params == NULL) ||\n+\t\t(params->n_ports_in == 0) ||\n+\t\t(params->n_ports_out == 0))\n+\t\treturn NULL;\n+\n+\t/* Memory allocation */\n+\tsize = RTE_CACHE_LINE_ROUNDUP(sizeof(struct pipeline_routing));\n+\tp = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);\n+\tp_rt = (struct pipeline_routing *) p;\n+\tif (p == NULL)\n+\t\treturn NULL;\n+\n+\tstrcpy(p->name, params->name);\n+\n+\t/* Parse arguments */\n+\tif (pipeline_routing_parse_args(p_rt, params))\n+\t\treturn NULL;\n+\n+\t/* Pipeline */\n+\t{\n+\t\tstruct rte_pipeline_params pipeline_params = {\n+\t\t\t.name = params->name,\n+\t\t\t.socket_id = params->socket_id,\n+\t\t\t.offset_port_id = 0,\n+\t\t};\n+\n+\t\tp->p = rte_pipeline_create(&pipeline_params);\n+\t\tif (p->p == NULL) {\n+\t\t\trte_free(p);\n+\t\t\treturn NULL;\n+\t\t}\n+\t}\n+\n+\t/* Input ports */\n+\tp->n_ports_in = params->n_ports_in;\n+\tfor (i = 0; i < p->n_ports_in; i++) {\n+\t\tstruct rte_pipeline_port_in_params port_params = {\n+\t\t\t.ops = pipeline_port_in_params_get_ops(&params->port_in[i]),\n+\t\t\t.arg_create = pipeline_port_in_params_convert(&params->port_in[i]),\n+\t\t\t.f_action = NULL,\n+\t\t\t.arg_ah = NULL,\n+\t\t\t.burst_size = params->port_in[i].burst_size,\n+\t\t};\n+\n+\t\tint status = rte_pipeline_port_in_create(p->p,\n+\t\t\t&port_params,\n+\t\t\t&p->port_in_id[i]);\n+\n+\t\tif (status) {\n+\t\t\trte_pipeline_free(p->p);\n+\t\t\trte_free(p);\n+\t\t\treturn NULL;\n+\t\t}\n+\t}\n+\n+\t/* Output ports */\n+\tp->n_ports_out = params->n_ports_out;\n+\tfor (i = 0; i < p->n_ports_out; i++) {\n+\t\tstruct rte_pipeline_port_out_params port_params = {\n+\t\t\t.ops = pipeline_port_out_params_get_ops(&params->port_out[i]),\n+\t\t\t.arg_create = pipeline_port_out_params_convert(&params->port_out[i]),\n+\t\t\t.f_action = NULL,\n+\t\t\t.f_action_bulk = NULL,\n+\t\t\t.arg_ah = NULL,\n+\t\t};\n+\n+\t\tint status = rte_pipeline_port_out_create(p->p,\n+\t\t\t&port_params,\n+\t\t\t&p->port_out_id[i]);\n+\n+\t\tif (status) {\n+\t\t\trte_pipeline_free(p->p);\n+\t\t\trte_free(p);\n+\t\t\treturn NULL;\n+\t\t}\n+\t}\n+\n+\t/* Routing table */\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.entry_unique_size = sizeof(struct routing_table_entry),\n+\t\t\t.offset = p_rt->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_miss = NULL,\n+\t\t\t\t.arg_ah = p_rt,\n+\t\t\t\t.action_data_size = \n+\t\t\t\t\tsizeof(struct routing_table_entry) -\n+\t\t\t\t\tsizeof(struct rte_pipeline_table_entry),\n+\t\t\t};\n+\n+\t\tint status;\n+\n+\t\tstatus = rte_pipeline_table_create(p->p,\n+\t\t\t&table_params,\n+\t\t\t&p->table_id[0]);\n+\n+\t\tif (status) {\n+\t\t\trte_pipeline_free(p->p);\n+\t\t\trte_free(p);\n+\t\t\treturn NULL;\n+\t\t}\n+\t}\n+\n+\t/* ARP table configuration */\n+\tif (p_rt->n_arp_entries) {\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_ext,\n+\t\t\t.f_hash = arp_table_hash,\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};\n+\n+\t\tstruct rte_pipeline_table_params table_params = {\n+\t\t\t.ops = &rte_table_hash_key8_ext_dosig_ops,\n+\t\t\t.arg_create = &table_arp_params,\n+\t\t\t.f_action_hit = arp_table_ah_hit,\n+\t\t\t.f_action_miss = NULL,\n+\t\t\t.arg_ah = p_rt,\n+\t\t\t.action_data_size = sizeof(struct arp_table_entry) -\n+\t\t\t\tsizeof(struct rte_pipeline_table_entry),\n+\t\t};\n+\n+\t\tint status;\n+\n+\t\tstatus = rte_pipeline_table_create(p->p,\n+\t\t\t&table_params,\n+\t\t\t&p->table_id[1]);\n+\n+\t\tif (status) {\n+\t\t\trte_pipeline_free(p->p);\n+\t\t\trte_free(p);\n+\t\t\treturn NULL;\n+\t\t}\n+\n+\t\tp->n_tables ++;\n+\t}\n+\n+\t/* Connecting input ports to tables */\n+\tfor (i = 0; i < p->n_ports_in; i++) {\n+\t\tint status = rte_pipeline_port_in_connect_to_table(p->p,\n+\t\t\tp->port_in_id[i],\n+\t\t\tp->table_id[0]);\n+\n+\t\tif (status) {\n+\t\t\trte_pipeline_free(p->p);\n+\t\t\trte_free(p);\n+\t\t\treturn NULL;\n+\t\t}\n+\t}\n+\n+\t/* Enable input ports */\n+\tfor (i = 0; i < p->n_ports_in; i++) {\n+\t\tint status = rte_pipeline_port_in_enable(p->p,\n+\t\t\tp->port_in_id[i]);\n+\n+\t\tif (status) {\n+\t\t\trte_pipeline_free(p->p);\n+\t\t\trte_free(p);\n+\t\t\treturn NULL;\n+\t\t}\n+\t}\n+\n+\t/* Check pipeline consistency */\n+\tif (rte_pipeline_check(p->p) < 0) {\n+\t\trte_pipeline_free(p->p);\n+\t\trte_free(p);\n+\t\treturn NULL;\n+\t}\n+\n+\t/* Message queues */\n+\tp->n_msgq = params->n_msgq;\n+\tfor (i = 0; i < p->n_msgq; i++)\n+\t\tp->msgq_in[i] = params->msgq_in[i];\n+\tfor (i = 0; i < p->n_msgq; i++)\n+\t\tp->msgq_out[i] = params->msgq_out[i];\n+\n+\t/* Message handlers */\n+\tmemcpy(p->handlers, handlers, sizeof(p->handlers));\n+\tmemcpy(p_rt->custom_handlers,\n+\t\tcustom_handlers,\n+\t\tsizeof(p_rt->custom_handlers));\n+\n+\treturn p;\n+}\n+\n+static int\n+pipeline_routing_free(void *pipeline)\n+{\n+\tstruct pipeline *p = (struct pipeline *) pipeline;\n+\n+\t/* Check input arguments */\n+\tif (p == NULL)\n+\t\treturn -1;\n+\n+\t/* Free resources */\n+\trte_pipeline_free(p->p);\n+\trte_free(p);\n+\treturn 0;\n+}\n+\n+static int\n+pipeline_routing_track(void *pipeline,\n+\t__rte_unused uint32_t port_in,\n+\tuint32_t *port_out)\n+{\n+\tstruct pipeline *p = (struct pipeline *) pipeline;\n+\n+\t/* Check input arguments */\n+\tif ((p == NULL) ||\n+\t\t(port_in >= p->n_ports_in) ||\n+\t\t(port_out == NULL))\n+\t\treturn -1;\n+\n+\tif (p->n_ports_in == 1) {\n+\t\t*port_out = 0;\n+\t\treturn 0;\n+\t}\n+\n+\treturn -1;\n+}\n+\n+static int\n+pipeline_routing_timer(void *pipeline)\n+{\n+\tstruct pipeline *p = (struct pipeline *) pipeline;\n+\n+\tpipeline_msg_req_handle(p);\n+\trte_pipeline_flush(p->p);\n+\n+\treturn 0;\n+}\n+\n+void *\n+pipeline_routing_msg_req_custom_handler(struct pipeline *p,\n+\tvoid *msg)\n+{\n+\tstruct pipeline_routing *p_rt = (struct pipeline_routing *) p;\n+\tstruct pipeline_custom_msg_req *req = msg;\n+\tpipeline_msg_req_handler f_handle;\n+\n+\tf_handle = (req->subtype < PIPELINE_ROUTING_MSG_REQS)?\n+\t\tp_rt->custom_handlers[req->subtype] :\n+\t\tpipeline_msg_req_invalid_handler;\n+\n+\tif (f_handle == NULL)\n+\t\tf_handle = pipeline_msg_req_invalid_handler;\n+\n+\treturn f_handle(p, req);\n+}\n+\n+void *\n+pipeline_routing_msg_req_route_add_handler(struct pipeline *p, void *msg)\n+{\n+\tstruct pipeline_routing_route_add_msg_req *req = msg;\n+\tstruct pipeline_routing_route_add_msg_rsp *rsp = msg;\n+\n+\tstruct rte_table_lpm_key key = {\n+\t\t.ip = req->key.key.ipv4.ip,\n+\t\t.depth = req->key.key.ipv4.depth,\n+\t};\n+\n+\tstruct routing_table_entry entry = {\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 = req->ip,\n+\t};\n+\n+\tif (req->key.type != PIPELINE_ROUTING_ROUTE_IPV4) {\n+\t\trsp->status = -1;\n+\t\treturn rsp;\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\t&rsp->key_found,\n+\t\t(struct rte_pipeline_table_entry **) &rsp->entry_ptr);\n+\n+\tRTE_LOG(INFO, USER1, \"%s Back-End: Key %s\\n\",\n+\t\tp->name,\n+\t\t(rsp->key_found)? \"found\" : \"not found\");\n+\n+\treturn rsp;\n+}\n+\n+void *\n+pipeline_routing_msg_req_route_del_handler(struct pipeline *p, void *msg)\n+{\n+\tstruct pipeline_routing_route_delete_msg_req *req = msg;\n+\tstruct pipeline_routing_route_delete_msg_rsp *rsp = msg;\n+\n+\tstruct rte_table_lpm_key key = {\n+\t\t.ip = req->key.key.ipv4.ip,\n+\t\t.depth = req->key.key.ipv4.depth,\n+\t};\n+\n+\tif (req->key.type != PIPELINE_ROUTING_ROUTE_IPV4) {\n+\t\trsp->status = -1;\n+\t\treturn rsp;\n+\t}\n+\n+\trsp->status = rte_pipeline_table_entry_delete(p->p,\n+\t\tp->table_id[0],\n+\t\t&key,\n+\t\t&rsp->key_found,\n+\t\tNULL);\n+\n+\tRTE_LOG(INFO, USER1, \"%s Back-End: Key %s\\n\",\n+\t\tp->name,\n+\t\t(rsp->key_found)? \"found\" : \"not found\");\n+\n+\treturn rsp;\n+}\n+\n+void *\n+pipeline_routing_msg_req_route_add_default_handler(struct pipeline *p, void *msg)\n+{\n+\tstruct pipeline_routing_route_add_default_msg_req *req = msg;\n+\tstruct pipeline_routing_route_add_default_msg_rsp *rsp = msg;\n+\n+\tstruct routing_table_entry default_entry = {\n+\t\t.head = {\n+\t\t\t.action = RTE_PIPELINE_ACTION_PORT,\n+\t\t\t{.port_id = p->port_out_id[req->port_id]},\n+\t\t},\n+\n+\t\t.flags = 0,\n+\t\t.port_id = 0,\n+\t\t.ip = 0,\n+\t};\n+\n+\trsp->status = rte_pipeline_table_default_entry_add(p->p,\n+\t\tp->table_id[0],\n+\t\t(struct rte_pipeline_table_entry *) &default_entry,\n+\t\t(struct rte_pipeline_table_entry **) &rsp->entry_ptr);\n+\n+\treturn rsp;\n+}\n+\n+void *\n+pipeline_routing_msg_req_route_del_default_handler(struct pipeline *p, void *msg)\n+{\n+\tstruct pipeline_routing_route_delete_default_msg_rsp *rsp = msg;\n+\n+\trsp->status = rte_pipeline_table_default_entry_delete(p->p,\n+\t\tp->table_id[0],\n+\t\tNULL);\n+\n+\treturn rsp;\n+}\n+\n+void *\n+pipeline_routing_msg_req_arp_add_handler(struct pipeline *p, void *msg)\n+{\n+\tstruct pipeline_routing_arp_add_msg_req *req = msg;\n+\tstruct pipeline_routing_arp_add_msg_rsp *rsp = msg;\n+\n+\tstruct pipeline_routing_arp_key key = {\n+\t\t.type = PIPELINE_ROUTING_ARP_IPV4,\n+\t\t.key = {\n+\t\t\t.ipv4 = {\n+\t\t\t\t.port_id = req->key.key.ipv4.port_id,\n+\t\t\t\t.ip = req->key.key.ipv4.ip,\n+\t\t\t},\n+\t\t},\n+\t};\n+\n+\tstruct arp_table_entry entry = {\n+\t\t.head = {\n+\t\t\t.action = RTE_PIPELINE_ACTION_PORT,\n+\t\t\t{.port_id = p->port_out_id[req->key.key.ipv4.port_id]},\n+\t\t},\n+\n+\t\t.macaddr = 0,\n+\t};\n+\n+\tif (req->key.type != PIPELINE_ROUTING_ARP_IPV4) {\n+\t\trsp->status = -1;\n+\t\treturn rsp;\n+\t}\n+\n+\t*((struct ether_addr *) &entry.macaddr) = req->macaddr;\n+\n+\trsp->status = rte_pipeline_table_entry_add(p->p,\n+\t\tp->table_id[1],\n+\t\t&key.key.ipv4,\n+\t\t(struct rte_pipeline_table_entry *) &entry,\n+\t\t&rsp->key_found,\n+\t\t(struct rte_pipeline_table_entry **) &rsp->entry_ptr);\n+\n+\tRTE_LOG(INFO, USER1, \"%s Back-End: Key %s\\n\",\n+\t\tp->name,\n+\t\t(rsp->key_found)? \"found\" : \"not found\");\n+\n+\treturn rsp;\n+}\n+\n+void *\n+pipeline_routing_msg_req_arp_del_handler(struct pipeline *p, void *msg)\n+{\n+\tstruct pipeline_routing_arp_delete_msg_req *req = msg;\n+\tstruct pipeline_routing_arp_delete_msg_rsp *rsp = msg;\n+\n+\tstruct pipeline_routing_arp_key key = {\n+\t\t.type = PIPELINE_ROUTING_ARP_IPV4,\n+\t\t.key = {\n+\t\t\t.ipv4 = {\n+\t\t\t\t.port_id = req->key.key.ipv4.port_id,\n+\t\t\t\t.ip = req->key.key.ipv4.ip,\n+\t\t\t},\n+\t\t},\n+\t};\n+\n+\tif (req->key.type != PIPELINE_ROUTING_ARP_IPV4) {\n+\t\trsp->status = -1;\n+\t\treturn rsp;\n+\t}\n+\n+\trsp->status = rte_pipeline_table_entry_delete(p->p,\n+\t\tp->table_id[1],\n+\t\t&key,\n+\t\t&rsp->key_found,\n+\t\tNULL);\n+\n+\tRTE_LOG(INFO, USER1, \"%s Back-End: Key %s\\n\",\n+\t\tp->name,\n+\t\t(rsp->key_found)? \"found\" : \"not found\");\n+\n+\treturn rsp;\n+}\n+\n+void *\n+pipeline_routing_msg_req_arp_add_default_handler(struct pipeline *p, void *msg)\n+{\n+\tstruct pipeline_routing_arp_add_default_msg_req *req = msg;\n+\tstruct pipeline_routing_arp_add_default_msg_rsp *rsp = msg;\n+\n+\tstruct arp_table_entry default_entry = {\n+\t\t.head = {\n+\t\t\t.action = RTE_PIPELINE_ACTION_PORT,\n+\t\t\t{.port_id = p->port_out_id[req->port_id]},\n+\t\t},\n+\n+\t\t.macaddr = 0,\n+\t};\n+\n+\trsp->status = rte_pipeline_table_default_entry_add(p->p,\n+\t\tp->table_id[1],\n+\t\t(struct rte_pipeline_table_entry *) &default_entry,\n+\t\t(struct rte_pipeline_table_entry **) &rsp->entry_ptr);\n+\n+\treturn rsp;\n+}\n+\n+void *\n+pipeline_routing_msg_req_arp_del_default_handler(struct pipeline *p, void *msg)\n+{\n+\tstruct pipeline_routing_arp_delete_default_msg_rsp *rsp = msg;\n+\n+\trsp->status = rte_pipeline_table_default_entry_delete(p->p,\n+\t\tp->table_id[1],\n+\t\tNULL);\n+\n+\treturn rsp;\n+}\n+\n+struct pipeline_ops pipeline_routing_ops = {\n+\t\t.f_init = pipeline_routing_init,\n+\t\t.f_free = pipeline_routing_free,\n+\t\t.f_run = NULL,\n+\t\t.f_timer = pipeline_routing_timer,\n+\t\t.f_track = pipeline_routing_track,\n+};\ndiff --git a/examples/ip_pipeline/pipeline/pipeline_routing_ops.h b/examples/ip_pipeline/pipeline/pipeline_routing_ops.h\nnew file mode 100644\nindex 0000000..303b562\n--- /dev/null\n+++ b/examples/ip_pipeline/pipeline/pipeline_routing_ops.h\n@@ -0,0 +1,231 @@\n+/*-\n+ *   BSD LICENSE\n+ *\n+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.\n+ *   All rights reserved.\n+ *\n+ *   Redistribution and use in source and binary forms, with or without\n+ *   modification, are permitted provided that the following conditions\n+ *   are met:\n+ *\n+ *     * Redistributions of source code must retain the above copyright\n+ *       notice, this list of conditions and the following disclaimer.\n+ *     * Redistributions in binary form must reproduce the above copyright\n+ *       notice, this list of conditions and the following disclaimer in\n+ *       the documentation and/or other materials provided with the\n+ *       distribution.\n+ *     * Neither the name of Intel Corporation nor the names of its\n+ *       contributors may be used to endorse or promote products derived\n+ *       from this software without specific prior written permission.\n+ *\n+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n+ *   \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+ */\n+\n+#ifndef __INCLUDE_PIPELINE_ROUTING_OPS_H__\n+#define __INCLUDE_PIPELINE_ROUTING_OPS_H__\n+\n+#include <rte_ether.h>\n+\n+#include \"pipeline_common_ops.h\"\n+#include \"pipeline_ops.h\"\n+\n+/*\n+ * Route\n+ */\n+enum pipeline_routing_route_key_type {\n+\tPIPELINE_ROUTING_ROUTE_IPV4,\n+};\n+\n+struct pipeline_routing_route_key_ipv4 {\n+\tuint32_t ip;\n+\tuint8_t depth;\n+};\n+\n+struct pipeline_routing_route_key {\n+\tenum pipeline_routing_route_key_type type;\n+\tunion {\n+\t\tstruct pipeline_routing_route_key_ipv4 ipv4;\n+\t} key;\n+};\n+\n+enum pipeline_routing_route_flags {\n+\tPIPELINE_ROUTING_ROUTE_LOCAL = 1 << 0, /* 0 = remote; 1 = local */\n+};\n+\n+/*\n+ * ARP\n+ */\n+enum pipeline_routing_arp_key_type {\n+\tPIPELINE_ROUTING_ARP_IPV4,\n+};\n+\n+struct pipeline_routing_arp_key_ipv4 {\n+\tuint32_t port_id;\n+\tuint32_t ip;\n+};\n+\n+struct pipeline_routing_arp_key {\n+\tenum pipeline_routing_arp_key_type type;\n+\tunion {\n+\t\tstruct pipeline_routing_arp_key_ipv4 ipv4;\n+\t} key;\n+};\n+\n+/*\n+ * Messages\n+ */\n+enum pipeline_routing_msg_req_type {\n+\tPIPELINE_ROUTING_MSG_REQ_ROUTE_ADD,\n+\tPIPELINE_ROUTING_MSG_REQ_ROUTE_DEL,\n+\tPIPELINE_ROUTING_MSG_REQ_ROUTE_ADD_DEFAULT,\n+\tPIPELINE_ROUTING_MSG_REQ_ROUTE_DEL_DEFAULT,\n+\tPIPELINE_ROUTING_MSG_REQ_ARP_ADD,\n+\tPIPELINE_ROUTING_MSG_REQ_ARP_DEL,\n+\tPIPELINE_ROUTING_MSG_REQ_ARP_ADD_DEFAULT,\n+\tPIPELINE_ROUTING_MSG_REQ_ARP_DEL_DEFAULT,\n+\tPIPELINE_ROUTING_MSG_REQS\n+};\n+\n+/*\n+ * MSG ROUTE ADD\n+ */\n+struct pipeline_routing_route_add_msg_req {\n+\tenum pipeline_msg_req_type type;\n+\tenum pipeline_routing_msg_req_type subtype;\n+\n+\t/* key */\n+\tstruct pipeline_routing_route_key key;\n+\n+\t/* data */\n+\tenum pipeline_routing_route_flags flags;\n+\tuint32_t port_id; /* Output port ID */\n+\tuint32_t ip; /* IP address for the next hop (only valid for remote routes) */\n+};\n+\n+struct pipeline_routing_route_add_msg_rsp {\n+\tint status;\n+\tint key_found;\n+\tvoid *entry_ptr;\n+};\n+\n+/*\n+ * MSG ROUTE DELETE\n+ */\n+struct pipeline_routing_route_delete_msg_req {\n+\tenum pipeline_msg_req_type type;\n+\tenum pipeline_routing_msg_req_type subtype;\n+\n+\t/* key */\n+\tstruct pipeline_routing_route_key key;\n+};\n+\n+struct pipeline_routing_route_delete_msg_rsp {\n+\tint status;\n+\tint key_found;\n+};\n+\n+/*\n+ * MSG ROUTE ADD DEFAULT\n+ */\n+struct pipeline_routing_route_add_default_msg_req {\n+\tenum pipeline_msg_req_type type;\n+\tenum pipeline_routing_msg_req_type subtype;\n+\n+\t/* data */\n+\tuint32_t port_id;\n+};\n+\n+struct pipeline_routing_route_add_default_msg_rsp {\n+\tint status;\n+\tvoid *entry_ptr;\n+};\n+\n+/*\n+ * MSG ROUTE DELETE DEFAULT\n+ */\n+struct pipeline_routing_route_delete_default_msg_req {\n+\tenum pipeline_msg_req_type type;\n+\tenum pipeline_routing_msg_req_type subtype;\n+};\n+\n+struct pipeline_routing_route_delete_default_msg_rsp {\n+\tint status;\n+};\n+\n+/*\n+ * MSG ARP ADD\n+ */\n+struct pipeline_routing_arp_add_msg_req {\n+\tenum pipeline_msg_req_type type;\n+\tenum pipeline_routing_msg_req_type subtype;\n+\n+\t/* key */\n+\tstruct pipeline_routing_arp_key key;\n+\n+\t/* data */\n+\tstruct ether_addr macaddr;\n+};\n+\n+struct pipeline_routing_arp_add_msg_rsp {\n+\tint status;\n+\tint key_found;\n+\tvoid *entry_ptr;\n+};\n+\n+/*\n+ * MSG ARP DELETE\n+ */\n+struct pipeline_routing_arp_delete_msg_req {\n+\tenum pipeline_msg_req_type type;\n+\tenum pipeline_routing_msg_req_type subtype;\n+\n+\t/* key */\n+\tstruct pipeline_routing_arp_key key;\n+};\n+\n+struct pipeline_routing_arp_delete_msg_rsp {\n+\tint status;\n+\tint key_found;\n+};\n+\n+/*\n+ * MSG ARP ADD DEFAULT\n+ */\n+struct pipeline_routing_arp_add_default_msg_req {\n+\tenum pipeline_msg_req_type type;\n+\tenum pipeline_routing_msg_req_type subtype;\n+\n+\t/* data */\n+\tuint32_t port_id;\n+};\n+\n+struct pipeline_routing_arp_add_default_msg_rsp {\n+\tint status;\n+\tvoid *entry_ptr;\n+};\n+\n+/*\n+ * MSG ARP DELETE DEFAULT\n+ */\n+struct pipeline_routing_arp_delete_default_msg_req {\n+\tenum pipeline_msg_req_type type;\n+\tenum pipeline_routing_msg_req_type subtype;\n+};\n+\n+struct pipeline_routing_arp_delete_default_msg_rsp {\n+\tint status;\n+};\n+\n+extern struct pipeline_ops pipeline_routing_ops;\n+\n+#endif\n",
    "prefixes": [
        "dpdk-dev",
        "10/11"
    ]
}