All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/11] ip_pipeline: ip_pipeline application enhancements
@ 2015-05-29 15:43 Maciej Gajdzica
  2015-05-29 15:43 ` [PATCH 01/11] ip_pipeline: add parsing for config files with new syntax Maciej Gajdzica
                   ` (11 more replies)
  0 siblings, 12 replies; 16+ messages in thread
From: Maciej Gajdzica @ 2015-05-29 15:43 UTC (permalink / raw)
  To: dev

This patchset enhances functionality of ip_pipeline application. New config
file syntax is introduced, so parser is changed. Changed structure of the
application. Now every global variable is stored in app_struct in app.h.
Syntax of pipeline cli commands was changed. Implementation of cli commands
for every pipeline is moved to the separate file.


Maciej Gajdzica (11):
  ip_pipeline: add parsing for config files with new syntax
  ip_pipeline: added config checks
  ip_pipeline: modified init to match new params struct
  ip_pipeline: moved pipelines to separate folder
  ip_pipeline: added master pipeline
  ip_pipeline: added application thread
  ip_pipeline: moved config files to separate folder
  ip_pipeline: added new implementation of passthrough pipeline
  ip_pipeline: added new implementation of firewall pipeline
  ip_pipeline: added new implementation of routing pipeline
  ip_pipeline: added new implementation of flow classification pipeline

 examples/ip_pipeline/Makefile                      |   35 +-
 examples/ip_pipeline/app.h                         |  586 ++++++
 examples/ip_pipeline/cmdline.c                     | 1976 -------------------
 examples/ip_pipeline/config.c                      |  419 ----
 examples/ip_pipeline/config/ip_pipeline.cfg        |    9 +
 examples/ip_pipeline/config/ip_pipeline.sh         |    1 +
 examples/ip_pipeline/config_check.c                |  617 ++++++
 examples/ip_pipeline/config_parse.c                | 2071 ++++++++++++++++++++
 examples/ip_pipeline/cpu_core_map.c                |  465 +++++
 examples/ip_pipeline/cpu_core_map.h                |   69 +
 examples/ip_pipeline/init.c                        | 1509 ++++++++++----
 examples/ip_pipeline/ip_pipeline.cfg               |   56 -
 examples/ip_pipeline/ip_pipeline.sh                |   18 -
 examples/ip_pipeline/main.c                        |  137 +-
 examples/ip_pipeline/main.h                        |  298 ---
 examples/ip_pipeline/pipeline.h                    |   79 +
 examples/ip_pipeline/pipeline/pipeline_common.c    |  412 ++++
 examples/ip_pipeline/pipeline/pipeline_common.h    |  241 +++
 .../ip_pipeline/pipeline/pipeline_common_ops.c     |  205 ++
 .../ip_pipeline/pipeline/pipeline_common_ops.h     |  150 ++
 examples/ip_pipeline/pipeline/pipeline_firewall.c  |  934 +++++++++
 examples/ip_pipeline/pipeline/pipeline_firewall.h  |   63 +
 .../ip_pipeline/pipeline/pipeline_firewall_ops.c   |  538 +++++
 .../ip_pipeline/pipeline/pipeline_firewall_ops.h   |  139 ++
 .../pipeline/pipeline_flow_classification.c        | 1621 +++++++++++++++
 .../pipeline/pipeline_flow_classification.h        |   41 +
 .../pipeline/pipeline_flow_classification_ops.c    |  559 ++++++
 .../pipeline/pipeline_flow_classification_ops.h    |  150 ++
 examples/ip_pipeline/pipeline/pipeline_master.c    |  870 ++++++++
 examples/ip_pipeline/pipeline/pipeline_master.h    |   41 +
 .../ip_pipeline/pipeline/pipeline_master_ops.c     |  136 ++
 .../ip_pipeline/pipeline/pipeline_master_ops.h     |   41 +
 .../ip_pipeline/pipeline/pipeline_passthrough.c    |   47 +
 .../ip_pipeline/pipeline/pipeline_passthrough.h    |   41 +
 .../pipeline/pipeline_passthrough_ops.c            |  275 +++
 .../pipeline/pipeline_passthrough_ops.h            |   41 +
 examples/ip_pipeline/pipeline/pipeline_routing.c   | 1426 ++++++++++++++
 examples/ip_pipeline/pipeline/pipeline_routing.h   |   99 +
 .../ip_pipeline/pipeline/pipeline_routing_ops.c    |  978 +++++++++
 .../ip_pipeline/pipeline/pipeline_routing_ops.h    |  231 +++
 examples/ip_pipeline/pipeline_firewall.c           |  313 ---
 .../ip_pipeline/pipeline_flow_classification.c     |  306 ---
 examples/ip_pipeline/pipeline_ipv4_frag.c          |  184 --
 examples/ip_pipeline/pipeline_ipv4_ras.c           |  181 --
 examples/ip_pipeline/pipeline_ops.h                |  247 +++
 examples/ip_pipeline/pipeline_passthrough.c        |  213 --
 examples/ip_pipeline/pipeline_routing.c            |  474 -----
 examples/ip_pipeline/pipeline_rx.c                 |  385 ----
 examples/ip_pipeline/pipeline_tx.c                 |  283 ---
 examples/ip_pipeline/thread.c                      |  105 +
 50 files changed, 14648 insertions(+), 5667 deletions(-)
 create mode 100644 examples/ip_pipeline/app.h
 delete mode 100644 examples/ip_pipeline/cmdline.c
 delete mode 100644 examples/ip_pipeline/config.c
 create mode 100644 examples/ip_pipeline/config/ip_pipeline.cfg
 create mode 100644 examples/ip_pipeline/config/ip_pipeline.sh
 create mode 100644 examples/ip_pipeline/config_check.c
 create mode 100644 examples/ip_pipeline/config_parse.c
 create mode 100644 examples/ip_pipeline/cpu_core_map.c
 create mode 100644 examples/ip_pipeline/cpu_core_map.h
 delete mode 100644 examples/ip_pipeline/ip_pipeline.cfg
 delete mode 100644 examples/ip_pipeline/ip_pipeline.sh
 delete mode 100644 examples/ip_pipeline/main.h
 create mode 100644 examples/ip_pipeline/pipeline.h
 create mode 100644 examples/ip_pipeline/pipeline/pipeline_common.c
 create mode 100644 examples/ip_pipeline/pipeline/pipeline_common.h
 create mode 100644 examples/ip_pipeline/pipeline/pipeline_common_ops.c
 create mode 100644 examples/ip_pipeline/pipeline/pipeline_common_ops.h
 create mode 100644 examples/ip_pipeline/pipeline/pipeline_firewall.c
 create mode 100644 examples/ip_pipeline/pipeline/pipeline_firewall.h
 create mode 100644 examples/ip_pipeline/pipeline/pipeline_firewall_ops.c
 create mode 100644 examples/ip_pipeline/pipeline/pipeline_firewall_ops.h
 create mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_classification.c
 create mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_classification.h
 create mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_classification_ops.c
 create mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_classification_ops.h
 create mode 100644 examples/ip_pipeline/pipeline/pipeline_master.c
 create mode 100644 examples/ip_pipeline/pipeline/pipeline_master.h
 create mode 100644 examples/ip_pipeline/pipeline/pipeline_master_ops.c
 create mode 100644 examples/ip_pipeline/pipeline/pipeline_master_ops.h
 create mode 100644 examples/ip_pipeline/pipeline/pipeline_passthrough.c
 create mode 100644 examples/ip_pipeline/pipeline/pipeline_passthrough.h
 create mode 100644 examples/ip_pipeline/pipeline/pipeline_passthrough_ops.c
 create mode 100644 examples/ip_pipeline/pipeline/pipeline_passthrough_ops.h
 create mode 100644 examples/ip_pipeline/pipeline/pipeline_routing.c
 create mode 100644 examples/ip_pipeline/pipeline/pipeline_routing.h
 create mode 100644 examples/ip_pipeline/pipeline/pipeline_routing_ops.c
 create mode 100644 examples/ip_pipeline/pipeline/pipeline_routing_ops.h
 delete mode 100644 examples/ip_pipeline/pipeline_firewall.c
 delete mode 100644 examples/ip_pipeline/pipeline_flow_classification.c
 delete mode 100644 examples/ip_pipeline/pipeline_ipv4_frag.c
 delete mode 100644 examples/ip_pipeline/pipeline_ipv4_ras.c
 create mode 100644 examples/ip_pipeline/pipeline_ops.h
 delete mode 100644 examples/ip_pipeline/pipeline_passthrough.c
 delete mode 100644 examples/ip_pipeline/pipeline_routing.c
 delete mode 100644 examples/ip_pipeline/pipeline_rx.c
 delete mode 100644 examples/ip_pipeline/pipeline_tx.c
 create mode 100644 examples/ip_pipeline/thread.c

-- 
1.7.9.5

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH 01/11] ip_pipeline: add parsing for config files with new syntax
  2015-05-29 15:43 [PATCH 00/11] ip_pipeline: ip_pipeline application enhancements Maciej Gajdzica
@ 2015-05-29 15:43 ` Maciej Gajdzica
  2015-06-01 13:34   ` Stephen Hemminger
  2015-05-29 15:43 ` [PATCH 02/11] ip_pipeline: added config checks Maciej Gajdzica
                   ` (10 subsequent siblings)
  11 siblings, 1 reply; 16+ messages in thread
From: Maciej Gajdzica @ 2015-05-29 15:43 UTC (permalink / raw)
  To: dev

New syntax of config files is needed for ip_pipeline example
enhancements. Some old files are temporarily disabled in the Makefile.
It is part of a bigger change.

Signed-off-by: Pawel Wodkowski <pawelx.wodkowski@intel.com>
---
 examples/ip_pipeline/Makefile       |   27 +-
 examples/ip_pipeline/app.h          |  586 ++++++++++
 examples/ip_pipeline/config.c       |  419 -------
 examples/ip_pipeline/config_parse.c | 2071 +++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/cpu_core_map.c |  465 ++++++++
 examples/ip_pipeline/cpu_core_map.h |   69 ++
 examples/ip_pipeline/main.c         |  130 +--
 examples/ip_pipeline/main.h         |  298 -----
 examples/ip_pipeline/pipeline.h     |   79 ++
 examples/ip_pipeline/pipeline_ops.h |  247 +++++
 10 files changed, 3539 insertions(+), 852 deletions(-)
 create mode 100644 examples/ip_pipeline/app.h
 delete mode 100644 examples/ip_pipeline/config.c
 create mode 100644 examples/ip_pipeline/config_parse.c
 create mode 100644 examples/ip_pipeline/cpu_core_map.c
 create mode 100644 examples/ip_pipeline/cpu_core_map.h
 delete mode 100644 examples/ip_pipeline/main.h
 create mode 100644 examples/ip_pipeline/pipeline.h
 create mode 100644 examples/ip_pipeline/pipeline_ops.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index e70fdc7..2f224cc 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -43,20 +43,21 @@ APP = ip_pipeline
 
 # all source are stored in SRCS-y
 SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) := main.c
-SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += config.c
-SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += init.c
-SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += cmdline.c
-SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_rx.c
-SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_tx.c
-SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_flow_classification.c
-SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_routing.c
-SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_passthrough.c
-SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_ipv4_frag.c
-SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_ipv4_ras.c
+SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += config_parse.c
+#SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += init.c
+SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += cpu_core_map.c
+#SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += cmdline.c
+#SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_rx.c
+#SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_tx.c
+#SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_flow_classification.c
+#SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_routing.c
+#SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_passthrough.c
+#SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_ipv4_frag.c
+#SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_ipv4_ras.c
 
-ifeq ($(CONFIG_RTE_LIBRTE_ACL),y)
-SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_firewall.c
-endif
+#ifeq ($(CONFIG_RTE_LIBRTE_ACL),y)
+#SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_firewall.c
+#endif
 
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
diff --git a/examples/ip_pipeline/app.h b/examples/ip_pipeline/app.h
new file mode 100644
index 0000000..9ff7454
--- /dev/null
+++ b/examples/ip_pipeline/app.h
@@ -0,0 +1,586 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __INCLUDE_APP_H__
+#define __INCLUDE_APP_H__
+
+#include <stdint.h>
+#include <string.h>
+
+#include <rte_mempool.h>
+#include <rte_ring.h>
+#include <rte_sched.h>
+#include <cmdline_parse.h>
+
+#include <rte_ethdev.h>
+
+#include "cpu_core_map.h"
+#include "pipeline.h"
+
+#define	APP_CHECK(exp, fmt, ...)    do {            \
+	if (!(exp)) {                                   \
+		fprintf( stderr, fmt "\n", ## __VA_ARGS__); \
+		abort();                                    \
+	}                                               \
+} while (0)
+
+#ifndef APP_APPNAME_SIZE
+#define APP_APPNAME_SIZE                         256
+#endif
+
+#ifndef APP_FILE_NAME_SIZE
+#define APP_FILE_NAME_SIZE                       256
+#endif
+
+#define APP_MAX_PIPELINE_ARGS                    PIPELINE_MAX_ARGS
+
+#define APP_PARAM_NAME_SIZE                      PIPELINE_NAME_SIZE
+
+#ifndef APP_MAX_SCHED_SUBPORTS
+#define APP_MAX_SCHED_SUBPORTS                   8
+#endif
+
+#ifndef APP_MAX_SCHED_PIPES
+#define APP_MAX_SCHED_PIPES                      4096
+#endif
+
+#ifndef APP_EAL_ARG_BUFFER_SIZE
+#define APP_EAL_ARG_BUFFER_SIZE                  1024
+#endif
+
+#ifndef APP_EAL_ARGC
+#define APP_EAL_ARGC                             16
+#endif
+
+#ifndef APP_MAX_MEMPOOLS
+#define APP_MAX_MEMPOOLS                         8
+#endif
+
+#ifndef APP_MAX_LINKS
+#define APP_MAX_LINKS                            16
+#endif
+
+#ifndef APP_LINK_MAX_HWQ_IN
+#define APP_LINK_MAX_HWQ_IN                      64
+#endif
+
+#ifndef APP_LINK_MAX_HWQ_OUT
+#define APP_LINK_MAX_HWQ_OUT                     64
+#endif
+
+#define APP_MAX_HWQ_IN                      APP_MAX_LINKS * APP_LINK_MAX_HWQ_IN
+
+#define APP_MAX_HWQ_OUT                     APP_MAX_LINKS * APP_LINK_MAX_HWQ_OUT
+
+#ifndef APP_MAX_PKTQ_SWQ
+#define APP_MAX_PKTQ_SWQ                         256
+#endif
+
+#define APP_MAX_PKTQ_TM                          APP_MAX_LINKS
+
+#ifndef APP_MAX_PKTQ_SOURCE
+#define APP_MAX_PKTQ_SOURCE                      16
+#endif
+
+#ifndef APP_MAX_PKTQ_SINK
+#define APP_MAX_PKTQ_SINK                        16
+#endif
+
+#ifndef APP_MAX_MSGQ
+#define APP_MAX_MSGQ                             64
+#endif
+
+#ifndef APP_MAX_PIPELINES
+#define APP_MAX_PIPELINES                        64
+#endif
+
+#ifndef APP_MAX_THREAD_PIPELINES
+#define APP_MAX_THREAD_PIPELINES                 16
+#endif
+
+#ifndef APP_PIPELINE_TYPE_SIZE
+#define APP_PIPELINE_TYPE_SIZE                   64
+#endif
+
+#define APP_MAX_PIPELINE_PKTQ_IN                 PIPELINE_MAX_PORT_IN
+#define APP_MAX_PIPELINE_PKTQ_OUT                PIPELINE_MAX_PORT_OUT
+#define APP_MAX_PIPELINE_MSGQ_IN                 PIPELINE_MAX_MSGQ_IN
+#define APP_MAX_PIPELINE_MSGQ_OUT                PIPELINE_MAX_MSGQ_OUT
+
+#ifndef APP_MAX_PIPELINE_TYPES
+#define APP_MAX_PIPELINE_TYPES                   64
+#endif
+
+#ifndef APP_MAX_THREADS
+#define APP_MAX_THREADS                          RTE_MAX_LCORE
+#endif
+
+#ifndef APP_MAX_CMDS
+#define APP_MAX_CMDS                             64
+#endif
+
+#define APP_PARAM_VALID(obj) ((obj)->name[0] != '\0')
+
+#define APP_PARAM_COUNT(obj_array, n_objs)                      \
+{                                                               \
+	size_t i;                                                   \
+	                                                            \
+	n_objs = 0;                                                 \
+	for (i = 0; i < RTE_DIM(obj_array); i++)                    \
+		if (APP_PARAM_VALID(&((obj_array)[i])))                 \
+			n_objs ++;                                          \
+}
+
+/**
+ * Find object of name *name* in *obj_array* which is constant size array of
+ * elements that have field *name*.
+ *
+ * @param obj_array
+ *  Constant size array
+ * @param name
+ *  name of object to find.
+ * @return
+ *  Pointer to object in *obj_array* or NULL if not found.
+ */
+#define APP_PARAM_FIND(obj_array, key)                          \
+({                                                              \
+	ssize_t obj_idx;                                            \
+	const ssize_t obj_count = RTE_DIM(obj_array);               \
+                                                                \
+	for (obj_idx = 0; obj_idx < obj_count; obj_idx++) {         \
+		if (!APP_PARAM_VALID(&((obj_array)[obj_idx])))          \
+			continue;                                           \
+			                                                    \
+		if (strcmp(key, (obj_array)[obj_idx].name) == 0)        \
+			break;                                              \
+	}                                                           \
+	obj_idx < obj_count ? obj_idx : -ENOENT;                    \
+})
+
+#define APP_PARAM_FIND_BY_ID(obj_array, prefix, id, obj)        \
+do {                                                            \
+	char name[APP_PARAM_NAME_SIZE];                             \
+	ssize_t pos;                                                \
+	                                                            \
+	sprintf(name, prefix "%u", id);                             \
+	pos = APP_PARAM_FIND(obj_array, name);                      \
+	obj = (pos < 0)? NULL : &((obj_array)[pos]);                \
+} while (0)
+
+#define APP_PARAM_GET_ID(obj, prefix, id)                       \
+do                                                              \
+	sscanf(obj->name, prefix "%u", &id);                        \
+while (0)                                                       \
+
+/**
+ * Set name of first free slot in *obj_array* to *obj_name*, which makes it
+ * valid. If object already exist return index to existing object.
+ *
+ * @param obj_array
+ *  Constant size array of objects.
+ * @param obj_name
+ *  Name of ne object.
+ * @return
+ *  ssize_t - Index to object or negative error code:
+ *  -EINVAL *name* is too long
+ *  -ENOMEM no free slot found.
+ */
+#define APP_PARAM_ADD(obj_array, obj_name)                         \
+({                                                                 \
+	ssize_t obj_idx;                                               \
+	ssize_t ret;                                                   \
+	const ssize_t obj_count = RTE_DIM(obj_array);                  \
+	                                                               \
+	obj_idx = APP_PARAM_FIND(obj_array, obj_name);                 \
+	if (obj_idx < 0) {                                             \
+		for (obj_idx = 0; obj_idx < obj_count; obj_idx++) {        \
+			if (!APP_PARAM_VALID(&((obj_array)[obj_idx])))         \
+				break;                                             \
+		}                                                          \
+	                                                               \
+		if (obj_idx < obj_count) {                                 \
+			ret = snprintf((obj_array)[obj_idx].name,              \
+					RTE_DIM((obj_array)[obj_idx].name),            \
+					"%s", obj_name);                               \
+			if (ret > (ssize_t)RTE_DIM((obj_array)[obj_idx].name)) \
+				obj_idx = -EINVAL;                                 \
+		} else                                                     \
+			obj_idx = -ENOMEM;                                     \
+	}                                                              \
+	obj_idx;                                                       \
+})
+
+
+#define APP_HWQ_IN_IDX(link, q) ((link) * APP_LINK_MAX_HWQ_IN + (q))
+#define APP_HWQ_OUT_IDX(link, q) ((link) * APP_LINK_MAX_HWQ_OUT + (q))
+
+#define APP_HWQ_IN_LINK_ID(id) (id / APP_LINK_MAX_HWQ_IN)
+#define APP_HWQ_IN_QUEUE_ID(id) (id % APP_LINK_MAX_HWQ_IN)
+
+#define APP_HWQ_OUT_LINK_ID(id) (id / APP_LINK_MAX_HWQ_OUT)
+#define APP_HWQ_OUT_QUEUE_ID(id) (id % APP_LINK_MAX_HWQ_OUT)
+
+
+struct app_mempool_params {
+	char name[APP_PARAM_NAME_SIZE];
+	uint32_t parsed; /* Used to check if object was parsed or only referenced */
+	uint32_t buffer_size;
+	uint32_t pool_size;
+	uint32_t cache_size;
+	uint32_t cpu_socket_id;
+};
+
+struct app_link_params {
+	char name[APP_PARAM_NAME_SIZE];
+	uint32_t parsed; /* Used to check if object was parsed or only referenced */
+	uint32_t pmd_id; /* Generated based on port mask */
+	uint32_t arp_q; /* 0 = Disabled (packets go to default queue 0) */
+	uint32_t tcp_syn_local_q; /* 0 = Disabled (packets go to default queue 0) */
+	uint32_t ip_local_q; /* 0 = Disabled (packets go to default queue 0) */
+	uint32_t tcp_local_q; /* 0 = Disabled (packets go to default queue 0) */
+	uint32_t udp_local_q; /* 0 = Disabled (packets go to default queue 0) */
+	uint32_t sctp_local_q; /* 0 = Disabled (packets go to default queue 0) */
+	uint32_t state; /* DOWN = 0, UP = 1 */
+	uint32_t ip; /* 0 = Invalid */
+	uint32_t depth; /* Valid only when IP is valid */
+	uint64_t mac_addr; /* Read from HW */
+
+	struct rte_eth_conf conf;
+	uint8_t promisc;
+};
+
+struct app_pktq_hwq_in_params {
+	char name[APP_PARAM_NAME_SIZE];
+	uint32_t parsed; /* Used to check if object was parsed or only referenced */
+	uint32_t mempool_id; /* Position in the app->mempool_params */
+	uint32_t size;
+	uint32_t burst;
+
+	struct rte_eth_rxconf conf;
+};
+
+struct app_pktq_hwq_out_params {
+	char name[APP_PARAM_NAME_SIZE];
+	uint32_t parsed; /* Used to check if object was parsed or only referenced */
+	uint32_t size;
+	uint32_t burst;
+	uint32_t dropless;
+	uint64_t n_retries;
+	struct rte_eth_txconf conf;
+};
+
+struct app_pktq_swq_params {
+	char name[APP_PARAM_NAME_SIZE];
+	uint32_t parsed; /* Used to check if object was parsed or only referenced */
+	uint32_t size;
+	uint32_t burst_read;
+	uint32_t burst_write;
+	uint32_t dropless;
+	uint64_t n_retries;
+	uint32_t cpu_socket_id;
+};
+
+struct app_pktq_tm_params {
+	char name[APP_PARAM_NAME_SIZE];
+	uint32_t parsed; /* Used to check if object was parsed or only referenced */
+	char file_name[APP_FILE_NAME_SIZE];
+	struct rte_sched_port_params sched_port_params;
+	struct rte_sched_subport_params
+		sched_subport_params[APP_MAX_SCHED_SUBPORTS];
+	struct rte_sched_pipe_params
+		sched_pipe_profiles[RTE_SCHED_PIPE_PROFILES_PER_PORT];
+	int sched_pipe_to_profile[APP_MAX_SCHED_SUBPORTS * APP_MAX_SCHED_PIPES];
+	uint32_t burst_read;
+	uint32_t burst_write;
+};
+
+struct app_pktq_source_params {
+	char name[APP_PARAM_NAME_SIZE];
+	uint32_t parsed; /* Used to check if object was parsed or only referenced */
+	uint32_t mempool_id; /* Position in the app->mempool_params array */
+	uint32_t burst;
+};
+
+struct app_pktq_sink_params {
+	char name[APP_PARAM_NAME_SIZE];
+	uint8_t parsed; /* Used to check if object was parsed or only referenced */
+};
+
+struct app_msgq_params {
+	char name[APP_PARAM_NAME_SIZE];
+	uint32_t parsed; /* Used to check if object was parsed or only referenced */
+	uint32_t size;
+	uint32_t cpu_socket_id;
+};
+
+enum app_pktq_in_type {
+	APP_PKTQ_IN_HWQ,
+	APP_PKTQ_IN_SWQ,
+	APP_PKTQ_IN_TM,
+	APP_PKTQ_IN_SOURCE,
+};
+
+struct app_pktq_in_params {
+	enum app_pktq_in_type type;
+	uint32_t id; /* Position in the appropriate app array */
+};
+
+enum app_pktq_out_type {
+	APP_PKTQ_OUT_HWQ,
+	APP_PKTQ_OUT_SWQ,
+	APP_PKTQ_OUT_TM,
+	APP_PKTQ_OUT_SINK,
+};
+
+struct app_pktq_out_params {
+	enum app_pktq_out_type type;
+	uint32_t id; /* Position in the appropriate app array */
+};
+
+struct app_pipeline_params {
+	char name[APP_PARAM_NAME_SIZE];
+	uint8_t parsed;
+
+	char type[APP_PIPELINE_TYPE_SIZE];
+
+	uint32_t socket_id;
+	uint32_t core_id;
+	uint32_t hyper_th_id;
+
+	struct app_pktq_in_params pktq_in[APP_MAX_PIPELINE_PKTQ_IN];
+	struct app_pktq_out_params pktq_out[APP_MAX_PIPELINE_PKTQ_OUT];
+	uint32_t msgq_in[APP_MAX_PIPELINE_MSGQ_IN];
+	uint32_t msgq_out[APP_MAX_PIPELINE_MSGQ_OUT];
+
+	uint32_t n_pktq_in;
+	uint32_t n_pktq_out;
+	uint32_t n_msgq_in;
+	uint32_t n_msgq_out;
+
+	uint32_t timer_period;
+
+	char *args_name[APP_MAX_PIPELINE_ARGS];
+	char *args_value[APP_MAX_PIPELINE_ARGS];
+	uint32_t n_args;
+};
+
+struct app_pipeline_data {
+	void *be;
+	void *fe;
+	uint64_t timer_period;
+};
+
+struct app_thread_pipeline_data {
+	void *be;
+	pipeline_op_run f_run;
+	pipeline_op_timer f_timer;
+	uint64_t timer_period;
+	uint64_t deadline;
+};
+
+struct app_thread_data {
+	struct app_thread_pipeline_data regular[APP_MAX_THREAD_PIPELINES];
+	struct app_thread_pipeline_data custom[APP_MAX_THREAD_PIPELINES];
+
+	uint32_t n_regular;
+	uint32_t n_custom;
+
+	uint64_t deadline;
+};
+
+struct app_params {
+	/* Config */
+	char app_name[APP_APPNAME_SIZE];
+	char config_file[APP_FILE_NAME_SIZE];
+	char script_file[APP_FILE_NAME_SIZE];
+
+	char *eal_argv[1 + APP_EAL_ARGC];
+	int eal_argc;
+
+	uint64_t port_mask;
+
+	struct app_mempool_params mempool_params[APP_MAX_MEMPOOLS];
+	struct app_link_params link_params[APP_MAX_LINKS];
+	struct app_pktq_hwq_in_params hwq_in_params[APP_MAX_HWQ_IN];
+	struct app_pktq_hwq_out_params hwq_out_params[APP_MAX_HWQ_OUT];
+	struct app_pktq_swq_params swq_params[APP_MAX_PKTQ_SWQ];
+	struct app_pktq_tm_params tm_params[APP_MAX_PKTQ_TM];
+	struct app_pktq_source_params source_params[APP_MAX_PKTQ_SOURCE];
+	struct app_pktq_sink_params sink_params[APP_MAX_PKTQ_SINK];
+	struct app_msgq_params msgq_params[APP_MAX_MSGQ];
+	struct app_pipeline_params pipeline_params[APP_MAX_PIPELINES];
+
+	uint32_t n_mempools;
+	uint32_t n_links;
+	uint32_t n_pktq_hwq_in;
+	uint32_t n_pktq_hwq_out;
+	uint32_t n_pktq_swq;
+	uint32_t n_pktq_tm;
+	uint32_t n_pktq_source;
+	uint32_t n_pktq_sink;
+	uint32_t n_msgq;
+	uint32_t n_pipelines;
+
+	/* Init */
+	struct cpu_core_map *core_map;
+	uint64_t core_mask;
+	struct rte_mempool *mempool[APP_MAX_MEMPOOLS];
+	struct rte_ring *swq[APP_MAX_PKTQ_SWQ];
+	struct rte_sched_port *tm[APP_MAX_PKTQ_TM];
+	struct rte_ring *msgq[APP_MAX_MSGQ];
+	struct pipeline_type pipeline_type[APP_MAX_PIPELINE_TYPES];
+	struct app_pipeline_data pipeline_data[APP_MAX_PIPELINES];
+	struct app_thread_data thread_data[APP_MAX_THREADS];
+	cmdline_parse_ctx_t cmds[APP_MAX_CMDS + 1];
+
+	uint32_t n_pipeline_types;
+	uint32_t n_cmds;
+};
+
+static inline uint32_t
+app_n_hwq_in_get(struct app_params *app, uint32_t link_id)
+{
+	uint32_t max_hwq_in = 0;
+	uint32_t i;
+
+	for (i = 0; i < APP_LINK_MAX_HWQ_IN; i++) {
+		struct app_pktq_hwq_in_params *p = &app->hwq_in_params[i];
+		uint32_t rxq_link_id, rxq_queue_id;
+
+		if (!APP_PARAM_VALID(p))
+			continue;
+
+		sscanf(p->name, "RXQ%u.%u", &rxq_link_id, &rxq_queue_id);
+		if (rxq_link_id != link_id)
+			continue;
+
+		max_hwq_in++;
+	}
+
+	return max_hwq_in;
+}
+
+static inline uint32_t
+app_n_hwq_out_get(struct app_params *app, uint32_t link_id)
+{
+	uint32_t max_hwq_out = 0;
+	uint32_t i;
+
+	for (i = 0; i < APP_LINK_MAX_HWQ_OUT; i++) {
+		struct app_pktq_hwq_out_params *p = &app->hwq_out_params[i];
+		uint32_t txq_link_id, txq_queue_id;
+
+		if (!APP_PARAM_VALID(p))
+			continue;
+
+		sscanf(p->name, "TXQ%u.%u", &txq_link_id, &txq_queue_id);
+		if (txq_link_id != link_id)
+			continue;
+
+		max_hwq_out++;
+	}
+
+	return max_hwq_out;
+}
+
+static inline struct app_link_params *
+app_get_link_for_rxq(struct app_params *app, struct app_pktq_hwq_in_params *p)
+{
+	char link_name[APP_PARAM_NAME_SIZE];
+	ssize_t link_param_idx;
+	uint32_t rxq_link_id, rxq_queue_id;
+
+	sscanf(p->name, "RXQ%u.%u", &rxq_link_id, &rxq_queue_id);
+	sprintf(link_name, "LINK%u", rxq_link_id);
+	link_param_idx = APP_PARAM_FIND(app->link_params, link_name);
+	APP_CHECK((link_param_idx >= 0),
+		"Cannot find %s for %s", link_name, p->name);
+
+	return &app->link_params[link_param_idx];
+}
+
+static inline struct app_link_params *
+app_get_link_for_txq(struct app_params *app, struct app_pktq_hwq_out_params *p)
+{
+	char link_name[APP_PARAM_NAME_SIZE];
+	ssize_t link_param_idx;
+	uint32_t txq_link_id, txq_queue_id;
+
+	sscanf(p->name, "TXQ%u.%u", &txq_link_id, &txq_queue_id);
+	sprintf(link_name, "LINK%u", txq_link_id);
+	link_param_idx = APP_PARAM_FIND(app->link_params, link_name);
+	APP_CHECK((link_param_idx >= 0),
+		"Cannot find %s for %s", link_name, p->name);
+
+	return &app->link_params[link_param_idx];
+}
+
+static inline struct app_link_params *
+app_get_link_for_tm(struct app_params *app, struct app_pktq_tm_params *p_tm)
+{
+	char link_name[APP_PARAM_NAME_SIZE];
+	uint32_t link_id;
+	ssize_t link_param_idx;
+
+	sscanf(p_tm->name, "TM%u", &link_id);
+	sprintf(link_name, "LINK%u", link_id);
+	link_param_idx = APP_PARAM_FIND(app->link_params, link_name);
+	APP_CHECK((link_param_idx >=0),
+		"Cannot find %s for %s", link_name, p_tm->name);
+
+	return &app->link_params[link_param_idx];
+}
+
+int app_config_init(struct app_params *app);
+
+int app_config_args(struct app_params *app, int argc, char **argv);
+
+int app_config_parse(struct app_params *app, const char *file_name);
+
+void app_config_save(struct app_params *app, const char *file_name);
+
+int app_config_check(struct app_params *app);
+
+int app_init(struct app_params *app);
+
+int app_thread(void *arg);
+
+int app_pipeline_type_register(struct app_params *app, struct pipeline_type *ptype);
+
+struct pipeline_type *app_pipeline_type_find(struct app_params *app, char *name);
+
+void app_link_up_internal(struct app_params *app, struct app_link_params *cp);
+
+void app_link_down_internal(struct app_params *app, struct app_link_params *cp);
+
+#endif
diff --git a/examples/ip_pipeline/config.c b/examples/ip_pipeline/config.c
deleted file mode 100644
index 9414a7b..0000000
--- a/examples/ip_pipeline/config.c
+++ /dev/null
@@ -1,419 +0,0 @@
-/*-
- *   BSD LICENSE
- *
- *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
- *   All rights reserved.
- *
- *   Redistribution and use in source and binary forms, with or without
- *   modification, are permitted provided that the following conditions
- *   are met:
- *
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in
- *       the documentation and/or other materials provided with the
- *       distribution.
- *     * Neither the name of Intel Corporation nor the names of its
- *       contributors may be used to endorse or promote products derived
- *       from this software without specific prior written permission.
- *
- *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <inttypes.h>
-#include <sys/types.h>
-#include <string.h>
-#include <sys/queue.h>
-#include <stdarg.h>
-#include <errno.h>
-#include <getopt.h>
-
-#include <rte_common.h>
-#include <rte_byteorder.h>
-#include <rte_log.h>
-#include <rte_memory.h>
-#include <rte_memcpy.h>
-#include <rte_memzone.h>
-#include <rte_eal.h>
-#include <rte_per_lcore.h>
-#include <rte_launch.h>
-#include <rte_atomic.h>
-#include <rte_cycles.h>
-#include <rte_prefetch.h>
-#include <rte_lcore.h>
-#include <rte_per_lcore.h>
-#include <rte_branch_prediction.h>
-#include <rte_interrupts.h>
-#include <rte_pci.h>
-#include <rte_random.h>
-#include <rte_debug.h>
-#include <rte_ether.h>
-#include <rte_ethdev.h>
-#include <rte_ring.h>
-#include <rte_mempool.h>
-#include <rte_mbuf.h>
-#include <rte_ip.h>
-#include <rte_tcp.h>
-#include <rte_lpm.h>
-#include <rte_lpm6.h>
-#include <rte_string_fns.h>
-#include <rte_cfgfile.h>
-
-#include "main.h"
-
-struct app_params app;
-
-static const char usage[] =
-	"Usage: %s EAL_OPTIONS-- -p PORT_MASK [-f CONFIG_FILE]\n";
-
-void
-app_print_usage(char *prgname)
-{
-	printf(usage, prgname);
-}
-
-const char *
-app_core_type_id_to_string(enum app_core_type id)
-{
-	switch (id) {
-	case APP_CORE_NONE: return "NONE";
-	case APP_CORE_MASTER: return "MASTER";
-	case APP_CORE_RX: return "RX";
-	case APP_CORE_TX: return "TX";
-	case APP_CORE_PT: return "PT";
-	case APP_CORE_FC: return "FC";
-	case APP_CORE_FW: return "FW";
-	case APP_CORE_RT: return "RT";
-	case APP_CORE_TM: return "TM";
-	case APP_CORE_IPV4_FRAG: return "IPV4_FRAG";
-	case APP_CORE_IPV4_RAS: return "IPV4_RAS";
-	default: return NULL;
-	}
-}
-
-int
-app_core_type_string_to_id(const char *string, enum app_core_type *id)
-{
-	if (strcmp(string, "NONE") == 0) {
-		*id = APP_CORE_NONE;
-		return 0;
-	}
-	if (strcmp(string, "MASTER") == 0) {
-		*id = APP_CORE_MASTER;
-		return 0;
-	}
-	if (strcmp(string, "RX") == 0) {
-		*id = APP_CORE_RX;
-		return 0;
-	}
-	if (strcmp(string, "TX") == 0) {
-		*id = APP_CORE_TX;
-		return 0;
-	}
-	if (strcmp(string, "PT") == 0) {
-		*id = APP_CORE_PT;
-		return 0;
-	}
-	if (strcmp(string, "FC") == 0) {
-		*id = APP_CORE_FC;
-		return 0;
-	}
-	if (strcmp(string, "FW") == 0) {
-		*id = APP_CORE_FW;
-		return 0;
-	}
-	if (strcmp(string, "RT") == 0) {
-		*id = APP_CORE_RT;
-		return 0;
-	}
-	if (strcmp(string, "TM") == 0) {
-		*id = APP_CORE_TM;
-		return 0;
-	}
-	if (strcmp(string, "IPV4_FRAG") == 0) {
-		*id = APP_CORE_IPV4_FRAG;
-		return 0;
-	}
-	if (strcmp(string, "IPV4_RAS") == 0) {
-		*id = APP_CORE_IPV4_RAS;
-		return 0;
-	}
-
-	return -1;
-}
-
-static uint64_t
-app_get_core_mask(void)
-{
-	uint64_t core_mask = 0;
-	uint32_t i;
-
-	for (i = 0; i < RTE_MAX_LCORE; i++) {
-		if (rte_lcore_is_enabled(i) == 0)
-			continue;
-
-		core_mask |= 1LLU << i;
-	}
-
-	return core_mask;
-}
-
-static int
-app_install_coremask(uint64_t core_mask)
-{
-	uint32_t n_cores, i;
-
-	for (n_cores = 0, i = 0; i < RTE_MAX_LCORE; i++)
-		if (app.cores[i].core_type != APP_CORE_NONE)
-			n_cores++;
-
-	if (n_cores != app.n_cores) {
-		rte_panic("Number of cores in COREMASK should be %u instead "
-			"of %u\n", n_cores, app.n_cores);
-		return -1;
-	}
-
-	for (i = 0; i < RTE_MAX_LCORE; i++) {
-		uint32_t core_id;
-
-		if (app.cores[i].core_type == APP_CORE_NONE)
-			continue;
-
-		core_id = __builtin_ctzll(core_mask);
-		core_mask &= ~(1LLU << core_id);
-
-		app.cores[i].core_id = core_id;
-	}
-
-	return 0;
-}
-static int
-app_install_cfgfile(const char *file_name)
-{
-	struct rte_cfgfile *file;
-	uint32_t n_cores, i;
-
-	memset(app.cores, 0, sizeof(app.cores));
-
-	if (file_name[0] == '\0')
-		return -1;
-
-	file = rte_cfgfile_load(file_name, 0);
-	if (file == NULL) {
-		rte_panic("Config file %s not found\n", file_name);
-		return -1;
-	}
-
-	n_cores = (uint32_t) rte_cfgfile_num_sections(file, "core",
-		strnlen("core", 5));
-	if (n_cores < app.n_cores) {
-		rte_panic("Config file parse error: not enough cores specified "
-			"(%u cores missing)\n", app.n_cores - n_cores);
-		return -1;
-	}
-	if (n_cores > app.n_cores) {
-		rte_panic("Config file parse error: too many cores specified "
-			"(%u cores too many)\n", n_cores - app.n_cores);
-		return -1;
-	}
-
-	for (i = 0; i < n_cores; i++) {
-		struct app_core_params *p = &app.cores[i];
-		char section_name[16];
-		const char *entry;
-		uint32_t j;
-
-		/* [core X] */
-		snprintf(section_name, sizeof(section_name), "core %u", i);
-		if (!rte_cfgfile_has_section(file, section_name)) {
-			rte_panic("Config file parse error: core IDs are not "
-				"sequential (core %u missing)\n", i);
-			return -1;
-		}
-
-		/* type */
-		entry = rte_cfgfile_get_entry(file, section_name, "type");
-		if (!entry) {
-			rte_panic("Config file parse error: core %u type not "
-				"defined\n", i);
-			return -1;
-		}
-		if ((app_core_type_string_to_id(entry, &p->core_type) != 0) ||
-		    (p->core_type == APP_CORE_NONE)) {
-			rte_panic("Config file parse error: core %u type "
-				"error\n", i);
-			return -1;
-		}
-
-		/* queues in */
-		entry = rte_cfgfile_get_entry(file, section_name, "queues in");
-		if (!entry) {
-			rte_panic("Config file parse error: core %u queues in "
-				"not defined\n", i);
-			return -1;
-		}
-
-		for (j = 0; (j < APP_MAX_SWQ_PER_CORE) && (entry != NULL);
-			j++) {
-			char *next;
-
-			p->swq_in[j] =  (uint32_t) strtol(entry, &next, 10);
-			if (next == entry)
-				break;
-			entry = next;
-		}
-
-		if ((j != APP_MAX_SWQ_PER_CORE) || (*entry != '\0')) {
-			rte_panic("Config file parse error: core %u queues in "
-				"error\n", i);
-			return -1;
-		}
-
-		/* queues out */
-		entry = rte_cfgfile_get_entry(file, section_name, "queues out");
-		if (!entry) {
-			rte_panic("Config file parse error: core %u queues out "
-				"not defined\n", i);
-			return -1;
-		}
-
-		for (j = 0; (j < APP_MAX_SWQ_PER_CORE) && (entry != NULL);
-			j++) {
-			char *next;
-
-			p->swq_out[j] =  (uint32_t) strtol(entry, &next, 10);
-			if (next == entry)
-				break;
-			entry = next;
-		}
-		if ((j != APP_MAX_SWQ_PER_CORE) || (*entry != '\0')) {
-			rte_panic("Config file parse error: core %u queues out "
-				"error\n", i);
-			return -1;
-		}
-	}
-
-	rte_cfgfile_close(file);
-
-	return 0;
-}
-
-void app_cores_config_print(void)
-{
-	uint32_t i;
-
-	for (i = 0; i < RTE_MAX_LCORE; i++) {
-		struct app_core_params *p = &app.cores[i];
-		uint32_t j;
-
-		if (app.cores[i].core_type == APP_CORE_NONE)
-			continue;
-
-		printf("---> core %u: id = %u type = %6s [", i, p->core_id,
-			app_core_type_id_to_string(p->core_type));
-		for (j = 0; j < APP_MAX_SWQ_PER_CORE; j++)
-			printf("%2d ", (int) p->swq_in[j]);
-
-		printf("] [");
-		for (j = 0; j < APP_MAX_SWQ_PER_CORE; j++)
-			printf("%2d ", (int) p->swq_out[j]);
-
-		printf("]\n");
-	}
-}
-
-static int
-app_install_port_mask(const char *arg)
-{
-	char *end = NULL;
-	uint64_t port_mask;
-	uint32_t i;
-
-	if (arg[0] == '\0')
-		return -1;
-
-	port_mask = strtoul(arg, &end, 16);
-	if ((end == NULL) || (*end != '\0'))
-		return -2;
-
-	if (port_mask == 0)
-		return -3;
-
-	app.n_ports = 0;
-	for (i = 0; i < 64; i++) {
-		if ((port_mask & (1LLU << i)) == 0)
-			continue;
-
-		if (app.n_ports >= APP_MAX_PORTS)
-			return -4;
-
-		app.ports[app.n_ports] = i;
-		app.n_ports++;
-	}
-
-	if (!rte_is_power_of_2(app.n_ports))
-		return -5;
-
-	return 0;
-}
-
-int
-app_parse_args(int argc, char **argv)
-{
-	int opt, ret;
-	char **argvopt;
-	int option_index;
-	char *prgname = argv[0];
-	static struct option lgopts[] = {
-		{NULL, 0, 0, 0}
-	};
-	uint64_t core_mask = app_get_core_mask();
-
-	app.n_cores = __builtin_popcountll(core_mask);
-
-	argvopt = argv;
-	while ((opt = getopt_long(argc, argvopt, "p:f:", lgopts,
-			&option_index)) != EOF) {
-		switch (opt) {
-		case 'p':
-			if (app_install_port_mask(optarg) != 0)
-				rte_panic("PORT_MASK should specify a number "
-					"of ports that is power of 2 less or "
-					"equal to %u\n", APP_MAX_PORTS);
-			break;
-
-		case 'f':
-			app_install_cfgfile(optarg);
-			break;
-
-		default:
-			return -1;
-		}
-	}
-
-	app_install_coremask(core_mask);
-
-	app_cores_config_print();
-
-	if (optind >= 0)
-		argv[optind - 1] = prgname;
-
-	ret = optind - 1;
-	optind = 0; /* reset getopt lib */
-
-	return ret;
-}
diff --git a/examples/ip_pipeline/config_parse.c b/examples/ip_pipeline/config_parse.c
new file mode 100644
index 0000000..d6242da
--- /dev/null
+++ b/examples/ip_pipeline/config_parse.c
@@ -0,0 +1,2071 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <getopt.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include <rte_errno.h>
+#include <rte_cfgfile.h>
+#include <rte_string_fns.h>
+
+#include "app.h"
+
+/**
+ * Default config values
+ **/
+
+#define DEFAULT_CONFIG_FILE                      "./config/ip_pipeline.cfg"
+
+static const struct app_mempool_params mempool_params_default = {
+	.parsed = 0,
+	.buffer_size = 2048 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM,
+	.pool_size = 32 * 1024,
+	.cache_size = 256,
+	.cpu_socket_id = 0,
+};
+
+static const struct app_link_params link_params_default = {
+	.parsed = 0,
+	.pmd_id = 0,
+	.arp_q = 0,
+	.tcp_syn_local_q = 0,
+	.ip_local_q = 0,
+	.tcp_local_q = 0,
+	.udp_local_q = 0,
+	.sctp_local_q = 0,
+	.state = 0,
+	.ip = 0,
+	.depth = 0,
+	.mac_addr = 0,
+
+	.conf = {
+		.link_speed = 0,
+		.link_duplex = 0,
+		.rxmode = {
+			.mq_mode = ETH_MQ_RX_NONE,
+
+			.header_split   = 0, /* Header split */
+			.hw_ip_checksum = 0, /* IP checksum offload */
+			.hw_vlan_filter = 0, /* VLAN filtering */
+			.hw_vlan_strip  = 0, /* VLAN strip */
+			.hw_vlan_extend = 0, /* Extended VLAN */
+			.jumbo_frame    = 0, /* Jumbo frame support */
+			.hw_strip_crc   = 0, /* CRC strip by HW */
+			.enable_scatter = 0, /* Scattered packets RX handler */
+
+			.max_rx_pkt_len = 9000, /* Jumbo frame max packet length */
+			.split_hdr_size = 0, /* Header split buffer size */
+		},
+		.txmode = {
+			.mq_mode = ETH_MQ_TX_NONE,
+		},
+		.lpbk_mode = 0,
+	},
+
+	.promisc = 1,
+};
+
+static const struct app_pktq_hwq_in_params default_hwq_in_params = {
+	.parsed = 0,
+	.mempool_id = 0,
+	.size = 128,
+	.burst = 32,
+
+	.conf = {
+		.rx_thresh = {
+				.pthresh = 8,
+				.hthresh = 8,
+				.wthresh = 4,
+		},
+		.rx_free_thresh = 64,
+		.rx_drop_en = 0,
+		.rx_deferred_start = 0,
+	}
+};
+
+static const struct app_pktq_hwq_out_params default_hwq_out_params = {
+	.parsed = 0,
+	.size = 512,
+	.burst = 32,
+	.dropless = 0,
+	.n_retries = 0,
+
+	.conf = {
+		.tx_thresh = {
+			.pthresh = 36,
+			.hthresh = 0,
+			.wthresh = 0,
+		},
+		.tx_rs_thresh = 0,
+		.tx_free_thresh = 0,
+		.txq_flags = ETH_TXQ_FLAGS_NOMULTSEGS | ETH_TXQ_FLAGS_NOOFFLOADS,
+		.tx_deferred_start = 0,
+	}
+};
+
+static const struct app_pktq_swq_params default_swq_params = {
+	.parsed = 0,
+	.size = 256,
+	.burst_read = 32,
+	.burst_write = 32,
+	.dropless = 0,
+	.n_retries = 0,
+	.cpu_socket_id = 0,
+};
+
+struct app_pktq_tm_params default_tm_params = {
+	.parsed = 0,
+	.burst_read = 64,
+	.burst_write = 32,
+};
+
+struct app_pktq_source_params default_source_params = {
+	.parsed = 0,
+	.mempool_id = 0,
+	.burst = 32,
+};
+
+struct app_pktq_sink_params default_sink_params = {
+	.parsed = 0,
+};
+
+struct app_msgq_params default_msgq_params = {
+	.parsed = 0,
+	.size = 64,
+	.cpu_socket_id = 0,
+};
+
+struct app_pipeline_params default_pipeline_params = {
+	.parsed = 0,
+	.socket_id = 0,
+	.core_id = 0,
+	.hyper_th_id = 0,
+	.n_pktq_in = 0,
+	.n_pktq_out = 0,
+	.n_msgq_in = 0,
+	.n_msgq_out = 0,
+	.timer_period = 1,
+	.n_args = 0,
+};
+
+static const char app_usage[] =
+	"Usage: %s [-f CONFIG_FILE] [-s SCRIPT_FILE] -p PORT_MASK \n"
+	"\n"
+	"Arguments:\n"
+	"\t-f CONFIG_FILE: Default config file is " DEFAULT_CONFIG_FILE "\n"
+	"\t-p PORT_MASK: Mask of NIC port IDs in hexadecimal format\n"
+	"\t-s SCRIPT_FILE: No CLI script file is run when not specified\n"
+	"\n";
+
+static void
+app_print_usage(char *prgname)
+{
+	rte_exit(0, app_usage, prgname);
+}
+
+#define skip_white_spaces(pos)  \
+({                              \
+	__typeof__(pos) _p = (pos); \
+	for ( ; isspace(*_p); _p++) \
+		;                       \
+	_p;                         \
+})
+
+#define PARSER_IMPLICIT_PARAM_ADD_CHECK(result, section_name) \
+do {                                                                        \
+	APP_CHECK(result != -EINVAL,                                            \
+			"CFG: [%s] name too long", section_name);                       \
+	APP_CHECK(result != -ENOMEM,                                            \
+			"CFG: [%s] too much sections", section_name);                   \
+	APP_CHECK(result >= 0,                                                  \
+			"CFG: [%s] Unknown error while adding '%s'", section_name,      \
+				section_name);                                              \
+} while (0)
+
+#define PARSER_PARAM_ADD_CHECK(result, params_array, section_name)      \
+do {                                                                    \
+	APP_CHECK((result != -EINVAL),                                      \
+			"CFG: [%s] name too long", section_name);                   \
+	APP_CHECK((result != -ENOMEM),                                      \
+			"CFG: [%s] too much sections", section_name);               \
+	APP_CHECK(((result >= 0) && (params_array)[result].parsed == 0),    \
+			"CFG: [%s] duplicate section", section_name);               \
+	APP_CHECK((result >= 0),                                            \
+			"CFG: [%s] Unknown error while adding '%s'", section_name,  \
+				section_name);                                          \
+} while (0)
+
+static int
+parser_read_arg_bool(const char *p)
+{
+	int val;
+	p = skip_white_spaces(p);
+	if (strstr(p, "yes") == p) {
+		val = 1;
+		p += 3;
+	} else if (strstr(p, "no") == p) {
+		val = 0;
+		p += 2;
+	} else
+		return -EINVAL;
+
+	p = skip_white_spaces(p);
+	if (*p != '\0')
+		return -EINVAL;
+
+	return val;
+}
+
+static const struct rte_cfgfile_entry2 **
+parser_get_section_entries(struct rte_cfgfile *cfg, const char *sect_name)
+{
+	const struct rte_cfgfile_entry2 **entries;
+	int ent_cnt, ret;
+
+	ent_cnt = rte_cfgfile_section_num_entries(cfg, sect_name);
+	APP_CHECK(ent_cnt > 0, "CFG: [%s] not entires (res=%d)", sect_name, -ent_cnt);
+
+	entries = malloc((ent_cnt + 1) * sizeof(struct rte_cfgfile_entry2 *));
+	APP_CHECK(entries != NULL, "CFG: [%s] Out of memory", sect_name);
+
+	ret = rte_cfgfile_section_entries_v21(cfg, sect_name, entries, ent_cnt);
+	APP_CHECK(ret == ent_cnt, "CFG: [%s] failed to get entries", sect_name);
+
+	entries[ent_cnt] = NULL;
+	return entries;
+}
+
+static int
+parser_read_uint64(uint64_t *value, const char *p)
+{
+	char *next;
+	uint64_t val;
+
+	p = skip_white_spaces(p);
+	if (!isdigit(*p))
+		return -EINVAL;
+
+	val = strtoul(p, &next, 10);
+	if (p == next)
+		return -EINVAL;
+
+	p = next;
+	switch (*p) {
+	case 'T':
+		val *= 1024ULL;
+		/* fall trought */
+	case 'G':
+		val *= 1024ULL;
+		/* fall trought */
+	case 'M':
+		val *= 1024ULL;
+		/* fall trought */
+	case 'k':
+	case 'K':
+		val *= 1024ULL;
+		p++;
+		break;
+	}
+
+	p = skip_white_spaces(p);
+	if (*p != '\0')
+		return -EINVAL;
+
+	*value = val;
+	return 0;
+}
+
+static int
+parser_read_uint32(uint32_t *value, const char *p)
+{
+	uint64_t val = 0;
+	int ret = parser_read_uint64(&val, p);
+
+	if (ret < 0)
+		return ret;
+	else if (val > UINT32_MAX)
+		return -ERANGE;
+
+	*value = val;
+	return 0;
+}
+
+static int
+parse_pipeline_core(uint32_t *socket, uint32_t *core, uint32_t *ht,
+		const char *entry)
+{
+	size_t num_len;
+	char num[8];
+
+	uint32_t s = 0, c = 0, h = 0, val;
+	uint8_t s_parsed = 0, c_parsed = 0, h_parsed = 0;
+	const char *next = skip_white_spaces(entry);
+	char type;
+
+	/* Expect <CORE> or [sX][cY][h]. At least one parameter is required. */
+	while (*next != '\0') {
+		/* If everything parsed nothing should left */
+		if (s_parsed && c_parsed && h_parsed)
+			return -EINVAL;
+
+		type = *next;
+		switch(type) {
+		case 's':
+		case 'S':
+			if (s_parsed)
+				return -EINVAL;
+			s_parsed = 1;
+			next++;
+			break;
+		case 'c':
+		case 'C':
+			if (c_parsed)
+				return -EINVAL;
+			c_parsed = 1;
+			next++;
+			break;
+		case 'h':
+		case 'H':
+			if (h_parsed)
+				return -EINVAL;
+			h_parsed = 1;
+			next++;
+			break;
+		default:
+			/* If it start from digit it must be only core id. */
+			if (!isdigit(*next) || s_parsed || c_parsed || h_parsed)
+				return -EINVAL;
+
+			type = 'C';
+		}
+
+		for (num_len = 0; *next != '\0'; next++, num_len++) {
+			if (num_len == RTE_DIM(num))
+				return -EINVAL;
+
+			if (!isdigit(*next))
+				break;
+
+			num[num_len] = *next;
+		}
+
+		if (num_len == 0 && type != 'h')
+			return -EINVAL;
+
+		num[num_len] = '\0';
+		val = strtol(num, NULL, 10);
+
+		h = 0;
+		switch(type) {
+			case 's':
+			case 'S':
+				s = val;
+				break;
+			case 'c':
+			case 'C':
+				c = val;
+				if (type == 'C' && *next != '\0')
+					return -EINVAL;
+
+				break;
+			case 'h':
+			case 'H':
+				h = 1;
+				break;
+		}
+	}
+
+	*socket = s;
+	*core = c;
+	*ht = h;
+	return 0;
+}
+
+static size_t
+skip_digits(const char *src)
+{
+	size_t i;
+
+	for (i = 0; isdigit(src[i]); i++)
+		;
+
+	return i;
+}
+
+static int
+validate_name(const char *name, const char *prefix, int num)
+{
+	size_t i, j;
+
+	for( i = 0; name[i] != '\0' && prefix[i] != '\0'; i++) {
+		if (name[i] != prefix[i])
+			return -1;
+	}
+
+	if (prefix[i] != '\0')
+		return -1;
+
+	if (!num) {
+		if (name[i] != '\0')
+			return -1;
+		else
+			return 0;
+	}
+
+	if (num == 2) {
+		j = skip_digits(&name[i]);
+		i += j;
+		if (j == 0 || name[i] != '.')
+			return -1;
+		i ++;
+	}
+
+	if (num == 1) {
+		j = skip_digits(&name[i]);
+		i += j;
+		if (j == 0 || name[i] != '\0')
+			return -1;
+	}
+
+	return 0;
+}
+
+static int
+parse_pipeline_pktq_in(struct app_params *app,
+		struct app_pipeline_params *p, const char *value)
+{
+	const char *next = value;
+	char *end;
+	char name[APP_PARAM_NAME_SIZE];
+	size_t name_len;
+
+	while (*next != '\0') {
+		enum app_pktq_in_type type;
+		int id;
+
+		end = strchr(next, ' ');
+		if (!end)
+			name_len = strlen(next);
+		else
+			name_len = end - next;
+
+		if (name_len == 0 || name_len == sizeof(name))
+			return -EINVAL;
+
+		strncpy(name, next, name_len);
+		name[name_len] = '\0';
+		next += name_len;
+		if (*next != '\0')
+			next++;
+
+		if (validate_name(name, "RXQ", 2) == 0) {
+			type = APP_PKTQ_IN_HWQ;
+			id = APP_PARAM_ADD(app->hwq_in_params, name);
+		} else if (validate_name(name, "SWQ", 1) == 0) {
+			type = APP_PKTQ_IN_SWQ;
+			id = APP_PARAM_ADD(app->swq_params, name);
+		} else if (validate_name(name, "TM", 1) == 0) {
+			type = APP_PKTQ_IN_TM;
+			id = APP_PARAM_ADD(app->tm_params, name);
+		} else if (validate_name(name, "SOURCE", 1) == 0) {
+			type = APP_PKTQ_IN_SOURCE;
+			id = APP_PARAM_ADD(app->source_params, name);
+		} else
+			return -EINVAL;
+
+		if (id < 0)
+			return id;
+
+		p->pktq_in[p->n_pktq_in].type = type;
+		p->pktq_in[p->n_pktq_in].id = (uint32_t) id;
+		p->n_pktq_in++;
+	}
+
+	return 0;
+}
+
+static int
+parse_pipeline_pktq_out(struct app_params *app,
+		struct app_pipeline_params *p, const char *value)
+{
+	const char *next = value;
+	char *end;
+	char name[APP_PARAM_NAME_SIZE];
+	size_t name_len;
+
+	while (*next != '\0') {
+		enum app_pktq_out_type type;
+		int id;
+
+		end = strchr(next, ' ');
+		if (!end)
+			name_len = strlen(next);
+		else
+			name_len = end - next;
+
+		if (name_len == 0 || name_len == sizeof(name))
+			return -EINVAL;
+
+		strncpy(name, next, name_len);
+		name[name_len] = '\0';
+		next += name_len;
+		if (*next != '\0')
+			next++;
+
+		if (validate_name(name, "TXQ", 2) == 0) {
+			type = APP_PKTQ_OUT_HWQ;
+			id = APP_PARAM_ADD(app->hwq_out_params, name);
+		} else if (validate_name(name, "SWQ", 1) == 0) {
+			type = APP_PKTQ_OUT_SWQ;
+			id = APP_PARAM_ADD(app->swq_params, name);
+		} else if (validate_name(name, "TM", 1) == 0) {
+			type = APP_PKTQ_OUT_TM;
+			id = APP_PARAM_ADD(app->tm_params, name);
+		} else if (validate_name(name, "SINK", 1) == 0) {
+			type = APP_PKTQ_OUT_SINK;
+			id = APP_PARAM_ADD(app->sink_params, name);
+		} else
+			return -EINVAL;
+
+		if (id < 0)
+			return id;
+
+		p->pktq_out[p->n_pktq_out].type = type;
+		p->pktq_out[p->n_pktq_out].id = id;
+		p->n_pktq_out++;
+	}
+
+	return 0;
+}
+
+static int
+parse_pipeline_msgq_in(struct app_params *app,
+		struct app_pipeline_params *p, const char *value)
+{
+	const char *next = value;
+	char *end;
+	char name[APP_PARAM_NAME_SIZE];
+	size_t name_len;
+	ssize_t idx;
+
+	while (*next != '\0') {
+		end = strchr(next, ' ');
+		if (!end)
+			name_len = strlen(next);
+		else
+			name_len = end - next;
+
+		if (name_len == 0 || name_len == sizeof(name))
+			return -EINVAL;
+
+		strncpy(name, next, name_len);
+		name[name_len] = '\0';
+		next += name_len;
+		if (*next != '\0')
+			next++;
+
+		if (validate_name(name, "MSGQ", 1) == 0) {
+			idx = APP_PARAM_ADD(app->msgq_params, name);
+		} else
+			return -EINVAL;
+
+		if (idx < 0)
+			return idx;
+
+		p->msgq_in[p->n_msgq_in] = idx;
+		p->n_msgq_in++;
+	}
+
+	return 0;
+}
+
+static int
+parse_pipeline_msgq_out(struct app_params *app,
+		struct app_pipeline_params *p, const char *value)
+{
+	const char *next = value;
+	char *end;
+	char name[APP_PARAM_NAME_SIZE];
+	size_t name_len;
+	ssize_t idx;
+
+	while (*next != '\0') {
+		end = strchr(next, ' ');
+		if (!end)
+			name_len = strlen(next);
+		else
+			name_len = end - next;
+
+		if (name_len == 0 || name_len == sizeof(name))
+			return -EINVAL;
+
+		strncpy(name, next, name_len);
+		name[name_len] = '\0';
+		next += name_len;
+		if (*next != '\0')
+			next++;
+
+		if (validate_name(name, "MSGQ", 1) == 0) {
+			idx = APP_PARAM_ADD(app->msgq_params, name);
+		} else
+			return -EINVAL;
+
+		if (idx < 0)
+			return idx;
+
+		p->msgq_out[p->n_msgq_out] = idx;
+		p->n_msgq_out++;
+	}
+
+	return 0;
+}
+
+
+static void
+parse_pipeline(struct app_params *app, const char *sect_name,
+		struct rte_cfgfile *cfg)
+{
+	int ret, i;
+	char name[CFG_NAME_LEN];
+	ssize_t param_idx;
+
+	const struct rte_cfgfile_entry2 **entries, *ent;
+	struct app_pipeline_params *param;
+
+	entries = parser_get_section_entries(cfg, sect_name);
+
+	param_idx = APP_PARAM_ADD(app->pipeline_params, sect_name);
+	PARSER_PARAM_ADD_CHECK(param_idx, app->pipeline_params, sect_name);
+
+	param = &app->pipeline_params[param_idx];
+	param->parsed = 1;
+
+	for (i = 0; entries[i] != NULL; i++) {
+		ent = entries[i];
+
+		if (strcmp(ent->name, "type") == 0) {
+			ret = snprintf(param->type, RTE_DIM(param->type), "%s", ent->value);
+			if (ret > 0 && ret < (int)RTE_DIM(param->type))
+				ret = 0;
+			else
+				ret = -EINVAL;
+		}
+		else if(strcmp(ent->name, "core") == 0)
+			ret = parse_pipeline_core(&param->socket_id, &param->core_id,
+					&param->hyper_th_id, ent->value);
+		else if(strcmp(ent->name, "pktq_in") == 0)
+			ret = parse_pipeline_pktq_in(app, param, ent->value);
+		else if(strcmp(ent->name, "pktq_out") == 0)
+			ret = parse_pipeline_pktq_out(app, param, ent->value);
+		else if(strcmp(ent->name, "msgq_in") == 0)
+			ret = parse_pipeline_msgq_in(app, param, ent->value);
+		else if(strcmp(ent->name, "msgq_out") == 0)
+			ret = parse_pipeline_msgq_out(app, param, ent->value);
+		else if(strcmp(ent->name, "timer_period") == 0)
+			ret = parser_read_uint32(&param->timer_period, ent->value);
+		else {
+			param->args_name[param->n_args] = strdup(ent->name);
+			param->args_value[param->n_args] = strdup(ent->value);
+
+			APP_CHECK((param->args_name[param->n_args] != NULL) &&
+				(param->args_value[param->n_args] != NULL),
+				"CFG: [%s] out of memory", sect_name);
+
+			param->n_args++;
+			ret = 0;
+		}
+
+		APP_CHECK(ret == 0, "CFG: [%s] entry '%s': Invalid value '%s'\n",
+				sect_name, ent->name, ent->value);
+	}
+
+	snprintf(name, sizeof(name), "MSGQ-REQ-%s", sect_name);
+	param_idx = APP_PARAM_ADD(app->msgq_params, name);
+	PARSER_IMPLICIT_PARAM_ADD_CHECK(param_idx, name);
+	app->msgq_params[param_idx].cpu_socket_id = param->socket_id;
+	param->msgq_in[param->n_msgq_in++] = param_idx;
+
+	snprintf(name, sizeof(name), "MSGQ-RSP-%s", sect_name);
+	param_idx = APP_PARAM_ADD(app->msgq_params, name);
+	PARSER_IMPLICIT_PARAM_ADD_CHECK(param_idx, name);
+	app->msgq_params[param_idx].cpu_socket_id = param->socket_id;
+	param->msgq_out[param->n_msgq_out++] = param_idx;
+
+	snprintf(name, sizeof(name), "MSGQ-REQ-CORE-s%" PRIu32 "c%" PRIu32 "%s",
+		param->socket_id,
+		param->core_id,
+		(param->hyper_th_id) ? "h" : "");
+	param_idx = APP_PARAM_ADD(app->msgq_params, name);
+	PARSER_IMPLICIT_PARAM_ADD_CHECK(param_idx, name);
+	app->msgq_params[param_idx].cpu_socket_id = param->socket_id;
+
+	snprintf(name, sizeof(name), "MSGQ-RSP-CORE-s%" PRIu32 "c%" PRIu32 "%s",
+		param->socket_id,
+		param->core_id,
+		(param->hyper_th_id) ? "h" : "");
+	param_idx = APP_PARAM_ADD(app->msgq_params, name);
+	PARSER_IMPLICIT_PARAM_ADD_CHECK(param_idx, name);
+	app->msgq_params[param_idx].cpu_socket_id = param->socket_id;
+
+	free(entries);
+}
+
+static void
+parse_mempool(struct app_params *app, const char *sect_name,
+		struct rte_cfgfile *cfg)
+{
+	int ret, i;
+	ssize_t param_idx;
+
+	const struct rte_cfgfile_entry2 **entries, *ent;
+	struct app_mempool_params *param;
+
+	entries = parser_get_section_entries(cfg, sect_name);
+
+	param_idx = APP_PARAM_ADD(app->mempool_params, sect_name);
+	PARSER_PARAM_ADD_CHECK(param_idx, app->mempool_params, sect_name);
+
+	param = &app->mempool_params[param_idx];
+	param->parsed = 1;
+
+	for (i = 0; entries[i] != NULL; i++) {
+		ent = entries[i];
+
+		ret = -ESRCH;
+		if (strcmp(ent->name, "buffer_size") == 0)
+			ret = parser_read_uint32(&param->buffer_size, ent->value);
+		else if(strcmp(ent->name, "pool_size") == 0)
+			ret = parser_read_uint32(&param->pool_size, ent->value);
+		else if(strcmp(ent->name, "cache_size") == 0)
+			ret = parser_read_uint32(&param->cache_size, ent->value);
+		else if(strcmp(ent->name, "cpu") == 0)
+			ret = parser_read_uint32(&param->cpu_socket_id, ent->value);
+
+		APP_CHECK(ret != -ESRCH, "CFG: [%s] entry '%s': unknown entry\n",
+				sect_name, ent->name);
+		APP_CHECK(ret == 0, "CFG: [%s] entry '%s': Invalid value '%s'\n",
+				sect_name, ent->name, ent->value);
+	}
+
+	free(entries);
+}
+
+static void
+parse_link(struct app_params *app, const char *sect_name,
+		struct rte_cfgfile *cfg)
+{
+	int ret, i;
+	ssize_t param_idx;
+
+	const struct rte_cfgfile_entry2 **entries, *ent;
+	struct app_link_params *param;
+
+	entries = parser_get_section_entries(cfg, sect_name);
+
+	param_idx = APP_PARAM_ADD(app->link_params, sect_name);
+	PARSER_PARAM_ADD_CHECK(param_idx, app->link_params, sect_name);
+
+	param = &app->link_params[param_idx];
+	param->parsed = 1;
+
+	for (i = 0; entries[i] != NULL; i++) {
+		ent = entries[i];
+
+		ret = -ESRCH;
+		if (strcmp(ent->name, "arp_q") == 0)
+			ret = parser_read_uint32(&param->arp_q, ent->value);
+		else if(strcmp(ent->name, "ip_local_q") == 0)
+			ret = parser_read_uint32(&param->ip_local_q, ent->value);
+		else if(strcmp(ent->name, "tcp_local_q") == 0)
+			ret = parser_read_uint32(&param->tcp_local_q, ent->value);
+		else if(strcmp(ent->name, "udp_local_q") == 0)
+			ret = parser_read_uint32(&param->udp_local_q, ent->value);
+		else if(strcmp(ent->name, "sctp_local_q") == 0)
+			ret = parser_read_uint32(&param->sctp_local_q, ent->value);
+
+		APP_CHECK(ret != -ESRCH, "CFG: [%s] entry '%s': unknown entry\n",
+				sect_name, ent->name);
+		APP_CHECK(ret == 0, "CFG: [%s] entry '%s': Invalid value '%s'\n",
+				sect_name, ent->name, ent->value);
+	}
+
+	free(entries);
+}
+
+static void
+parse_rxq(struct app_params *app, const char *sect_name,
+		struct rte_cfgfile *cfg)
+{
+	int ret, i;
+	ssize_t param_idx;
+
+	const struct rte_cfgfile_entry2 **entries, *ent;
+	struct app_pktq_hwq_in_params *param;
+
+	entries = parser_get_section_entries(cfg, sect_name);
+
+	param_idx = APP_PARAM_ADD(app->hwq_in_params, sect_name);
+	PARSER_PARAM_ADD_CHECK(param_idx, app->hwq_in_params, sect_name);
+
+	param = &app->hwq_in_params[param_idx];
+	param->parsed = 1;
+
+	for (i = 0; entries[i] != NULL; i++) {
+		ent = entries[i];
+
+		ret = -ESRCH;
+		if (strcmp(ent->name, "mempool") == 0) {
+			ssize_t idx;
+
+			APP_CHECK((validate_name(ent->value, "MEMPOOL", 1) == 0),
+				"CFG: [%s] entry '%s': invalid mempool\n", sect_name, ent->name);
+
+			idx = APP_PARAM_ADD(app->mempool_params, ent->value);
+			PARSER_IMPLICIT_PARAM_ADD_CHECK(idx, sect_name);
+			param->mempool_id = idx;
+			ret = 0;
+		} else if(strcmp(ent->name, "size") == 0)
+			ret = parser_read_uint32(&param->size, ent->value);
+		else if(strcmp(ent->name, "burst") == 0)
+			ret = parser_read_uint32(&param->burst, ent->value);
+
+		APP_CHECK(ret != -ESRCH, "CFG: [%s] entry '%s': unknown entry\n",
+				sect_name, ent->name);
+		APP_CHECK(ret == 0, "CFG: [%s] entry '%s': Invalid value '%s'\n",
+				sect_name, ent->name, ent->value);
+	}
+
+	free(entries);
+}
+
+static void
+parse_txq(struct app_params *app, const char *sect_name,
+		struct rte_cfgfile *cfg)
+{
+	int ret, i;
+	ssize_t param_idx;
+
+	const struct rte_cfgfile_entry2 **entries, *ent;
+	struct app_pktq_hwq_out_params *param;
+
+	entries = parser_get_section_entries(cfg, sect_name);
+
+	param_idx = APP_PARAM_ADD(app->hwq_out_params, sect_name);
+	PARSER_PARAM_ADD_CHECK(param_idx, app->hwq_out_params, sect_name);
+
+	param = &app->hwq_out_params[param_idx];
+	param->parsed = 1;
+
+	for (i = 0; entries[i] != NULL; i++) {
+		ent = entries[i];
+
+		ret = -ESRCH;
+		if(strcmp(ent->name, "size") == 0)
+			ret = parser_read_uint32(&param->size, ent->value);
+		else if (strcmp(ent->name, "burst") == 0)
+			ret = parser_read_uint32(&param->burst, ent->value);
+		else if(strcmp(ent->name, "dropless") == 0) {
+			ret = parser_read_arg_bool(ent->value);
+			if (ret >= 0) {
+				param->dropless = ret;
+				ret = 0;
+			}
+		}
+
+		APP_CHECK(ret != -ESRCH, "CFG: [%s] entry '%s': unknown entry\n",
+				sect_name, ent->name);
+		APP_CHECK(ret == 0, "CFG: [%s] entry '%s': Invalid value '%s'\n",
+				sect_name, ent->name, ent->value);
+	}
+
+	free(entries);
+}
+
+static void
+parse_swq(struct app_params *app, const char *sect_name,
+		struct rte_cfgfile *cfg)
+{
+	int ret, i;
+	ssize_t param_idx;
+
+	const struct rte_cfgfile_entry2 **entries, *ent;
+	struct app_pktq_swq_params *param;
+
+	entries = parser_get_section_entries(cfg, sect_name);
+
+	param_idx = APP_PARAM_ADD(app->swq_params, sect_name);
+	PARSER_PARAM_ADD_CHECK(param_idx, app->swq_params, sect_name);
+
+	param = &app->swq_params[param_idx];
+	param->parsed = 1;
+
+	for (i = 0; entries[i] != NULL; i++) {
+		ent = entries[i];
+
+		ret = -ESRCH;
+		if(strcmp(ent->name, "size") == 0)
+			ret = parser_read_uint32(&param->size, ent->value);
+		else if (strcmp(ent->name, "burst_read") == 0)
+			ret = parser_read_uint32(&param->burst_read, ent->value);
+		else if (strcmp(ent->name, "burst_write") == 0)
+			ret = parser_read_uint32(&param->burst_write, ent->value);
+		else if(strcmp(ent->name, "dropless") == 0) {
+			ret = parser_read_arg_bool(ent->value);
+			if (ret >= 0) {
+				param->dropless = ret;
+				ret = 0;
+			}
+		} else if(strcmp(ent->name, "n_retries") == 0)
+			ret = parser_read_uint64(&param->n_retries, ent->value);
+		else if(strcmp(ent->name, "cpu") == 0)
+			ret = parser_read_uint32(&param->cpu_socket_id, ent->value);
+
+		APP_CHECK(ret != -ESRCH, "CFG: [%s] entry '%s': unknown entry\n",
+				sect_name, ent->name);
+		APP_CHECK(ret == 0, "CFG: [%s] entry '%s': Invalid value '%s'\n",
+				sect_name, ent->name, ent->value);
+	}
+
+	free(entries);
+}
+
+static int
+tm_cfgfile_load_sched_port(
+	struct rte_cfgfile *file,
+	struct rte_sched_port_params *port_params)
+{
+	const char *entry;
+	int j;
+
+	entry = rte_cfgfile_get_entry(file, "port", "frame overhead");
+	if (entry)
+		port_params->frame_overhead = (uint32_t)atoi(entry);
+
+	entry = rte_cfgfile_get_entry(file, "port", "number of subports per port");
+	if (entry)
+		port_params->n_subports_per_port = (uint32_t)atoi(entry);
+
+	entry = rte_cfgfile_get_entry(file, "port", "number of pipes per subport");
+	if (entry)
+		port_params->n_pipes_per_subport = (uint32_t)atoi(entry);
+
+	entry = rte_cfgfile_get_entry(file, "port", "queue sizes");
+	if (entry) {
+		char *next;
+
+		for(j = 0; j < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; j++) {
+			port_params->qsize[j] = (uint16_t)strtol(entry, &next, 10);
+			if (next == NULL)
+				break;
+			entry = next;
+		}
+	}
+
+#ifdef RTE_SCHED_RED
+	for (j = 0; j < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; j++) {
+		char str[32];
+
+		/* Parse WRED min thresholds */
+		snprintf(str, sizeof(str), "tc %d wred min", j);
+		entry = rte_cfgfile_get_entry(file, "red", str);
+		if (entry) {
+			char *next;
+			int k;
+			/* for each packet colour (green, yellow, red) */
+			for (k = 0; k < e_RTE_METER_COLORS; k++) {
+				port_params->red_params[j][k].min_th
+					= (uint16_t)strtol(entry, &next, 10);
+				if (next == NULL)
+					break;
+				entry = next;
+			}
+		}
+
+		/* Parse WRED max thresholds */
+		snprintf(str, sizeof(str), "tc %d wred max", j);
+		entry = rte_cfgfile_get_entry(file, "red", str);
+		if (entry) {
+			char *next;
+			int k;
+			/* for each packet colour (green, yellow, red) */
+			for (k = 0; k < e_RTE_METER_COLORS; k++) {
+				port_params->red_params[j][k].max_th
+					= (uint16_t)strtol(entry, &next, 10);
+				if (next == NULL)
+					break;
+				entry = next;
+			}
+		}
+
+		/* Parse WRED inverse mark probabilities */
+		snprintf(str, sizeof(str), "tc %d wred inv prob", j);
+		entry = rte_cfgfile_get_entry(file, "red", str);
+		if (entry) {
+			char *next;
+			int k;
+			/* for each packet colour (green, yellow, red) */
+			for (k = 0; k < e_RTE_METER_COLORS; k++) {
+				port_params->red_params[j][k].maxp_inv
+					= (uint8_t)strtol(entry, &next, 10);
+
+				if (next == NULL)
+					break;
+				entry = next;
+			}
+		}
+
+		/* Parse WRED EWMA filter weights */
+		snprintf(str, sizeof(str), "tc %d wred weight", j);
+		entry = rte_cfgfile_get_entry(file, "red", str);
+		if (entry) {
+			char *next;
+			int k;
+			/* for each packet colour (green, yellow, red) */
+			for (k = 0; k < e_RTE_METER_COLORS; k++) {
+				port_params->red_params[j][k].wq_log2
+					= (uint8_t)strtol(entry, &next, 10);
+				if (next == NULL)
+					break;
+				entry = next;
+			}
+		}
+	}
+#endif /* RTE_SCHED_RED */
+
+	return 0;
+}
+
+static int
+tm_cfgfile_load_sched_pipe(
+	struct rte_cfgfile *file,
+	struct rte_sched_port_params *port_params,
+	struct rte_sched_pipe_params *pipe_params)
+{
+	int i, j;
+	char *next;
+	const char *entry;
+	int profiles;
+
+	profiles = rte_cfgfile_num_sections(file,
+		"pipe profile", sizeof("pipe profile") - 1);
+	port_params->n_pipe_profiles = profiles;
+
+	for (j = 0; j < profiles; j++) {
+		char pipe_name[32];
+		snprintf(pipe_name, sizeof(pipe_name), "pipe profile %d", j);
+
+		entry = rte_cfgfile_get_entry(file, pipe_name, "tb rate");
+		if (entry)
+			pipe_params[j].tb_rate = (uint32_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(file, pipe_name, "tb size");
+		if (entry)
+			pipe_params[j].tb_size = (uint32_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(file, pipe_name, "tc period");
+		if (entry)
+			pipe_params[j].tc_period = (uint32_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(file, pipe_name, "tc 0 rate");
+		if (entry)
+			pipe_params[j].tc_rate[0] = (uint32_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(file, pipe_name, "tc 1 rate");
+		if (entry)
+			pipe_params[j].tc_rate[1] = (uint32_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(file, pipe_name, "tc 2 rate");
+		if (entry)
+			pipe_params[j].tc_rate[2] = (uint32_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(file, pipe_name, "tc 3 rate");
+		if (entry)
+			pipe_params[j].tc_rate[3] = (uint32_t)atoi(entry);
+
+#ifdef RTE_SCHED_SUBPORT_TC_OV
+		entry = rte_cfgfile_get_entry(file, pipe_name,
+			"tc 3 oversubscription weight");
+		if (entry)
+			pipe_params[j].tc_ov_weight = (uint8_t)atoi(entry);
+#endif
+
+		entry = rte_cfgfile_get_entry(file, pipe_name, "tc 0 wrr weights");
+		if (entry) {
+			for(i = 0; i < RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS; i++) {
+				pipe_params[j].wrr_weights[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE*0 + i] =
+					(uint8_t)strtol(entry, &next, 10);
+				if (next == NULL)
+					break;
+				entry = next;
+			}
+		}
+		entry = rte_cfgfile_get_entry(file, pipe_name, "tc 1 wrr weights");
+		if (entry) {
+			for(i = 0; i < RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS; i++) {
+				pipe_params[j].wrr_weights[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE*1 + i] =
+					(uint8_t)strtol(entry, &next, 10);
+				if (next == NULL)
+					break;
+				entry = next;
+			}
+		}
+		entry = rte_cfgfile_get_entry(file, pipe_name, "tc 2 wrr weights");
+		if (entry) {
+			for(i = 0; i < RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS; i++) {
+				pipe_params[j].wrr_weights[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE*2 + i] =
+					(uint8_t)strtol(entry, &next, 10);
+				if (next == NULL)
+					break;
+				entry = next;
+			}
+		}
+		entry = rte_cfgfile_get_entry(file, pipe_name, "tc 3 wrr weights");
+		if (entry) {
+			for(i = 0; i < RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS; i++) {
+				pipe_params[j].wrr_weights[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE*3 + i] =
+					(uint8_t)strtol(entry, &next, 10);
+				if (next == NULL)
+					break;
+				entry = next;
+			}
+		}
+	}
+	return 0;
+}
+
+static int
+tm_cfgfile_load_sched_subport(
+	struct rte_cfgfile *file,
+	struct rte_sched_subport_params *subport_params,
+	int *pipe_to_profile)
+{
+	const char *entry;
+	int i, j, k;
+
+	for (i = 0; i < APP_MAX_SCHED_SUBPORTS; i++) {
+		char sec_name[CFG_NAME_LEN];
+		snprintf(sec_name, sizeof(sec_name), "subport %d", i);
+
+		if (rte_cfgfile_has_section(file, sec_name)) {
+			entry = rte_cfgfile_get_entry(file, sec_name, "tb rate");
+			if (entry)
+				subport_params[i].tb_rate = (uint32_t)atoi(entry);
+
+			entry = rte_cfgfile_get_entry(file, sec_name, "tb size");
+			if (entry)
+				subport_params[i].tb_size = (uint32_t)atoi(entry);
+
+			entry = rte_cfgfile_get_entry(file, sec_name, "tc period");
+			if (entry)
+				subport_params[i].tc_period = (uint32_t)atoi(entry);
+
+			entry = rte_cfgfile_get_entry(file, sec_name, "tc 0 rate");
+			if (entry)
+				subport_params[i].tc_rate[0] = (uint32_t)atoi(entry);
+
+			entry = rte_cfgfile_get_entry(file, sec_name, "tc 1 rate");
+			if (entry)
+				subport_params[i].tc_rate[1] = (uint32_t)atoi(entry);
+
+			entry = rte_cfgfile_get_entry(file, sec_name, "tc 2 rate");
+			if (entry)
+				subport_params[i].tc_rate[2] = (uint32_t)atoi(entry);
+
+			entry = rte_cfgfile_get_entry(file, sec_name, "tc 3 rate");
+			if (entry)
+				subport_params[i].tc_rate[3] = (uint32_t)atoi(entry);
+
+			int n_entries = rte_cfgfile_section_num_entries(file, sec_name);
+			const struct rte_cfgfile_entry2 *entries[n_entries];
+
+			rte_cfgfile_section_entries_v21(file, sec_name, entries, n_entries);
+
+			for (j = 0; j < n_entries; j++) {
+				if (strncmp("pipe", entries[j]->name, sizeof("pipe") - 1) == 0) {
+					int profile;
+					char *tokens[2] = {NULL, NULL};
+					int n_tokens;
+					int begin, end;
+					char name[CFG_NAME_LEN];
+
+					profile = atoi(entries[j]->value);
+					strncpy(name, entries[j]->name, sizeof(name));
+					n_tokens = rte_strsplit(&name[sizeof("pipe")],
+							strnlen(name, CFG_NAME_LEN), tokens, 2, '-');
+
+					begin =  atoi(tokens[0]);
+					if (n_tokens == 2)
+						end = atoi(tokens[1]);
+					else
+						end = begin;
+
+					if (end >= APP_MAX_SCHED_PIPES || begin > end)
+						return -1;
+
+					for (k = begin; k <= end; k++) {
+						char profile_name[CFG_NAME_LEN];
+
+						snprintf(profile_name, sizeof(profile_name),
+								"pipe profile %d", profile);
+						if (rte_cfgfile_has_section(file, profile_name))
+							pipe_to_profile[i * APP_MAX_SCHED_PIPES + k] = profile;
+						else
+							rte_exit(EXIT_FAILURE, "Wrong pipe profile %s\n",
+									entries[j]->value);
+					}
+				}
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int
+tm_cfgfile_load(struct app_pktq_tm_params *tm)
+{
+	struct rte_cfgfile *file;
+	uint32_t mtu, i;
+
+	mtu = tm->sched_port_params.mtu;
+	memset(tm->sched_subport_params, 0, sizeof(tm->sched_subport_params));
+	memset(tm->sched_pipe_profiles, 0, sizeof(tm->sched_pipe_profiles));
+	memset(&tm->sched_port_params, 0, sizeof(tm->sched_pipe_profiles));
+	for (i = 0; i < APP_MAX_SCHED_SUBPORTS * APP_MAX_SCHED_PIPES; i++)
+		tm->sched_pipe_to_profile[i] = -1;
+
+	tm->sched_port_params.pipe_profiles = &tm->sched_pipe_profiles[0];
+	tm->sched_port_params.mtu = mtu;
+
+	if (tm->file_name[0] == '\0')
+		return -1;
+
+	file = rte_cfgfile_load(tm->file_name, 0);
+	if (file == NULL)
+		return -1;
+
+	tm_cfgfile_load_sched_port(file, &tm->sched_port_params);
+	tm_cfgfile_load_sched_subport(file, tm->sched_subport_params, tm->sched_pipe_to_profile);
+	tm_cfgfile_load_sched_pipe(file, &tm->sched_port_params, tm->sched_pipe_profiles);
+
+	rte_cfgfile_close(file);
+	return 0;
+}
+
+static void
+parse_tm(struct app_params *app, const char *sect_name,
+		struct rte_cfgfile *cfg)
+{
+	int ret, i;
+	ssize_t param_idx;
+
+	const struct rte_cfgfile_entry2 **entries, *ent;
+	struct app_pktq_tm_params *param;
+
+	entries = parser_get_section_entries(cfg, sect_name);
+
+	param_idx = APP_PARAM_ADD(app->tm_params, sect_name);
+	PARSER_PARAM_ADD_CHECK(param_idx, app->tm_params, sect_name);
+
+	param = &app->tm_params[param_idx];
+	param->parsed = 1;
+
+	for (i = 0; entries[i] != NULL; i++) {
+		ent = entries[i];
+
+		ret = -ESRCH;
+		if(strcmp(ent->name, "cfg") == 0) {
+			int status;
+
+			ret = 0;
+			status = snprintf(param->file_name,
+				sizeof(param->file_name), "%s", ent->value);
+			if (status >= (int) sizeof(param->file_name))
+				ret = -EINVAL;
+			else {
+				status = tm_cfgfile_load(param);
+				if (status)
+					ret = -EBADF;
+			}
+		} else if (strcmp(ent->name, "burst_read") == 0)
+			ret = parser_read_uint32(&param->burst_read, ent->value);
+		else if (strcmp(ent->name, "burst_write") == 0)
+			ret = parser_read_uint32(&param->burst_write, ent->value);
+
+		APP_CHECK(ret != -ESRCH, "CFG: [%s] entry '%s': unknown entry\n",
+				sect_name, ent->name);
+		APP_CHECK(ret != -EBADF, "CFG: [%s] entry '%s': TM cfg parse error '%s'\n",
+				sect_name, ent->name, ent->value);
+		APP_CHECK(ret == 0, "CFG: [%s] entry '%s': Invalid value '%s'\n",
+				sect_name, ent->name, ent->value);
+	}
+
+	free(entries);
+}
+
+static void
+parse_source(struct app_params *app, const char *sect_name,
+		struct rte_cfgfile *cfg)
+{
+	int ret, i;
+	ssize_t param_idx;
+
+	const struct rte_cfgfile_entry2 **entries, *ent;
+	struct app_pktq_source_params *param;
+
+	entries = parser_get_section_entries(cfg, sect_name);
+
+	param_idx = APP_PARAM_ADD(app->source_params, sect_name);
+	PARSER_PARAM_ADD_CHECK(param_idx, app->source_params, sect_name);
+
+	param = &app->source_params[param_idx];
+	param->parsed = 1;
+
+	for (i = 0; entries[i] != NULL; i++) {
+		ent = entries[i];
+
+		ret = -ESRCH;
+		if (strcmp(ent->name, "mempool") == 0) {
+			ssize_t idx;
+
+			APP_CHECK((validate_name(ent->value, "MEMPOOL", 1) == 0),
+				"CFG: [%s] entry '%s': invalid mempool\n", sect_name, ent->name);
+
+			idx = APP_PARAM_ADD(app->mempool_params, ent->value);
+			PARSER_IMPLICIT_PARAM_ADD_CHECK(idx, sect_name);
+			param->mempool_id = idx;
+			ret = 0;
+		} else if (strcmp(ent->name, "burst") == 0)
+			ret = parser_read_uint32(&param->burst, ent->value);
+
+		APP_CHECK(ret != -ESRCH, "CFG: [%s] entry '%s': unknown entry\n",
+				sect_name, ent->name);
+		APP_CHECK(ret == 0, "CFG: [%s] entry '%s': Invalid value '%s'\n",
+				sect_name, ent->name, ent->value);
+	}
+
+	free(entries);
+}
+
+static void
+parse_msgq_req_pipeline(struct app_params *app, const char *sect_name,
+		struct rte_cfgfile *cfg)
+{
+	int ret, i;
+	ssize_t param_idx;
+
+	const struct rte_cfgfile_entry2 **entries, *ent;
+	struct app_msgq_params *param;
+
+	entries = parser_get_section_entries(cfg, sect_name);
+
+	param_idx = APP_PARAM_ADD(app->msgq_params, sect_name);
+	PARSER_PARAM_ADD_CHECK(param_idx, app->msgq_params, sect_name);
+
+	param = &app->msgq_params[param_idx];
+	param->parsed = 1;
+
+	for (i = 0; entries[i] != NULL; i++) {
+		ent = entries[i];
+
+		ret = -ESRCH;
+		if(strcmp(ent->name, "size") == 0)
+			ret = parser_read_uint32(&param->size, ent->value);
+
+		APP_CHECK(ret != -ESRCH, "CFG: [%s] entry '%s': unknown entry\n",
+				sect_name, ent->name);
+		APP_CHECK(ret == 0, "CFG: [%s] entry '%s': Invalid value '%s'\n",
+				sect_name, ent->name, ent->value);
+	}
+
+	free(entries);
+}
+
+static void
+parse_msgq_rsp_pipeline(struct app_params *app, const char *sect_name,
+		struct rte_cfgfile *cfg)
+{
+	int ret, i;
+	ssize_t param_idx;
+
+	const struct rte_cfgfile_entry2 **entries, *ent;
+	struct app_msgq_params *param;
+
+	entries = parser_get_section_entries(cfg, sect_name);
+
+	param_idx = APP_PARAM_ADD(app->msgq_params, sect_name);
+	PARSER_PARAM_ADD_CHECK(param_idx, app->msgq_params, sect_name);
+
+	param = &app->msgq_params[param_idx];
+	param->parsed = 1;
+
+	for (i = 0; entries[i] != NULL; i++) {
+		ent = entries[i];
+
+		ret = -ESRCH;
+		if(strcmp(ent->name, "size") == 0)
+			ret = parser_read_uint32(&param->size, ent->value);
+
+		APP_CHECK(ret != -ESRCH, "CFG: [%s] entry '%s': unknown entry\n",
+				sect_name, ent->name);
+		APP_CHECK(ret == 0, "CFG: [%s] entry '%s': Invalid value '%s'\n",
+				sect_name, ent->name, ent->value);
+	}
+
+	free(entries);
+}
+
+static void
+parse_msgq(struct app_params *app, const char *sect_name,
+		struct rte_cfgfile *cfg)
+{
+	int ret, i;
+	ssize_t param_idx;
+
+	const struct rte_cfgfile_entry2 **entries, *ent;
+	struct app_msgq_params *param;
+
+	entries = parser_get_section_entries(cfg, sect_name);
+
+	param_idx = APP_PARAM_ADD(app->msgq_params, sect_name);
+	PARSER_PARAM_ADD_CHECK(param_idx, app->msgq_params, sect_name);
+
+	param = &app->msgq_params[param_idx];
+	param->parsed = 1;
+
+	for (i = 0; entries[i] != NULL; i++) {
+		ent = entries[i];
+
+		ret = -ESRCH;
+		if(strcmp(ent->name, "size") == 0)
+			ret = parser_read_uint32(&param->size, ent->value);
+		else if(strcmp(ent->name, "cpu") == 0)
+			ret = parser_read_uint32(&param->cpu_socket_id, ent->value);
+
+		APP_CHECK(ret != -ESRCH, "CFG: [%s] entry '%s': unknown entry\n",
+				sect_name, ent->name);
+		APP_CHECK(ret == 0, "CFG: [%s] entry '%s': Invalid value '%s'\n",
+				sect_name, ent->name, ent->value);
+	}
+
+	free(entries);
+}
+
+struct config_section {
+	const char prefix[CFG_NAME_LEN];
+	int numbers;
+	void (*load)(struct app_params *p, const char *sect_name,
+			struct rte_cfgfile *cfg);
+};
+
+static const struct config_section cfg_file_scheme[] = {
+		{ "PIPELINE",          1, parse_pipeline },
+		{ "MEMPOOL",           1, parse_mempool },
+		{ "LINK",              1, parse_link },
+		{ "RXQ",               2, parse_rxq },
+		{ "TXQ",               2, parse_txq },
+		{ "SWQ",               1, parse_swq },
+		{ "TM",                1, parse_tm },
+		{ "SOURCE",            1, parse_source },
+		{ "MSGQ-REQ-PIPELINE", 1, parse_msgq_req_pipeline },
+		{ "MSGQ-RSP-PIPELINE", 1, parse_msgq_rsp_pipeline },
+		{ "MSGQ",              1, parse_msgq },
+
+};
+
+static void
+create_implicit_mempools(struct app_params *app)
+{
+	ssize_t idx;
+
+	idx = APP_PARAM_ADD(app->mempool_params, "MEMPOOL0");
+	PARSER_IMPLICIT_PARAM_ADD_CHECK(idx, "start-up");
+}
+
+static void
+parse_port_mask(struct app_params *app, uint64_t port_mask)
+{
+	uint32_t pmd_id, link_id;
+
+	link_id = 0;
+	for (pmd_id = 0; pmd_id < RTE_MAX_ETHPORTS; pmd_id++) {
+		char name[APP_PARAM_NAME_SIZE];
+		ssize_t idx;
+
+		if ((port_mask & (1LLU << pmd_id)) == 0)
+			continue;
+
+		snprintf(name, sizeof(name), "LINK%u", link_id);
+		idx = APP_PARAM_ADD(app->link_params, name);
+		PARSER_IMPLICIT_PARAM_ADD_CHECK(idx, name);
+
+		app->link_params[idx].pmd_id = pmd_id;
+		link_id ++;
+	}
+}
+
+int
+app_config_parse(struct app_params *app, const char *file_name)
+{
+	char config_file_out[APP_FILE_NAME_SIZE];
+
+	char **sect_names;
+	struct rte_cfgfile *cfg;
+
+	const struct config_section *sch_s;
+	int i, j, sect_count;
+
+	create_implicit_mempools(app);
+
+	parse_port_mask(app, app->port_mask);
+
+	cfg = rte_cfgfile_load(file_name, 0);
+	APP_CHECK(cfg != NULL, "Unable to load config file %s", file_name);
+
+	sect_count = rte_cfgfile_num_sections(cfg, NULL, 0);
+	sect_names = malloc(sect_count * sizeof(char *));
+	for (i = 0; i < sect_count; i++)
+		sect_names[i] = malloc(CFG_NAME_LEN);
+
+	rte_cfgfile_sections(cfg, sect_names, sect_count);
+
+	for (i = 0; i < sect_count; i++) {
+		int len, cfg_name_len;
+
+		cfg_name_len = strlen(sect_names[i]);
+
+		/* Find section type */
+		for (j = 0; j < (int)RTE_DIM(cfg_file_scheme); j++) {
+			sch_s = &cfg_file_scheme[j];
+			len = strlen(sch_s->prefix);
+
+			if (cfg_name_len < len)
+				continue;
+
+			/* After section name we expect only '\0' or digit or digit dot
+			 * digit so protect against false matching ex:
+			 * if shc_s if sch_s->name is "ABC"
+			 * cfg_sect_name "ABC0.0" match but
+			 * cfg_sect_name is "ABCDEF" does not match
+			 */
+			if (sect_names[i][len] != '\0' && !isdigit(sect_names[i][len]))
+				continue;
+
+			if (strncmp(sch_s->prefix, sect_names[i], len) == 0)
+				break;
+		}
+
+		APP_CHECK(j < (int)RTE_DIM(cfg_file_scheme), "Unknown section %s",
+				sect_names[i]);
+
+		APP_CHECK(validate_name(sect_names[i], sch_s->prefix, sch_s->numbers) == 0,
+				"Invalid section name '%s'", sect_names[i]);
+
+		sch_s->load(app, sect_names[i], cfg);
+	}
+
+	for (i = 0; i < sect_count; i++)
+		free(sect_names[i]);
+
+	free(sect_names);
+
+	rte_cfgfile_close(cfg);
+
+	snprintf(config_file_out, APP_FILE_NAME_SIZE, "%s.out", app->config_file);
+	app_config_save(app, config_file_out);
+
+	APP_PARAM_COUNT(app->mempool_params, app->n_mempools);
+	APP_PARAM_COUNT(app->link_params, app->n_links);
+	APP_PARAM_COUNT(app->hwq_in_params, app->n_pktq_hwq_in);
+	APP_PARAM_COUNT(app->hwq_out_params, app->n_pktq_hwq_out);
+	APP_PARAM_COUNT(app->swq_params, app->n_pktq_swq);
+	APP_PARAM_COUNT(app->tm_params, app->n_pktq_tm);
+	APP_PARAM_COUNT(app->source_params, app->n_pktq_source);
+	APP_PARAM_COUNT(app->sink_params, app->n_pktq_sink);
+	APP_PARAM_COUNT(app->msgq_params, app->n_msgq);
+	APP_PARAM_COUNT(app->pipeline_params, app->n_pipelines);
+
+	return 0;
+}
+
+static void
+save_mempool_params(struct app_params *app, FILE *f)
+{
+	struct app_mempool_params *p;
+	size_t i, count;
+
+	count = RTE_DIM(app->mempool_params);
+	for (i = 0; i < count; i++) {
+		p = &app->mempool_params[i];
+		if (!APP_PARAM_VALID(p))
+			continue;
+
+		fprintf(f, "[%s]\n", p->name);
+		fprintf(f, "%s = %" PRIu32 "\n", "buffer_size", p->buffer_size);
+		fprintf(f, "%s = %" PRIu32 "\n", "pool_size", p->pool_size);
+		fprintf(f, "%s = %" PRIu32 "\n", "cache_size", p->cache_size);
+		fprintf(f, "%s = %" PRIu32 "\n", "cpu", p->cpu_socket_id);
+
+		fputc('\n', f);
+	}
+}
+
+static void
+save_links_params(struct app_params *app, FILE *f)
+{
+	struct app_link_params *p;
+	size_t i, count;
+
+	count = RTE_DIM(app->link_params);
+	for (i = 0; i < count; i++) {
+		p = &app->link_params[i];
+		if (!APP_PARAM_VALID(p))
+			continue;
+
+		fprintf(f, "[%s]\n", p->name);
+		fprintf(f, "; %s = %" PRIu32 "\n", "pmd_id", p->pmd_id);
+		fprintf(f, "%s = %" PRIu32 "\n", "arp_q", p->arp_q);
+		fprintf(f, "%s = %" PRIu32 "\n", "tcp_syn_local_q", p->arp_q);
+		fprintf(f, "%s = %" PRIu32 "\n", "ip_local_q", p->ip_local_q);
+		fprintf(f, "%s = %" PRIu32 "\n", "tcp_local_q", p->tcp_local_q);
+		fprintf(f, "%s = %" PRIu32 "\n", "udp_local_q", p->udp_local_q);
+		fprintf(f, "%s = %" PRIu32 "\n", "sctp_local_q", p->sctp_local_q);
+
+		fputc('\n', f);
+	}
+}
+
+static void
+save_rxq_params(struct app_params *app, FILE *f)
+{
+	struct app_pktq_hwq_in_params *p;
+	size_t i, count;
+
+	count = RTE_DIM(app->hwq_in_params);
+	for (i = 0; i < count; i++) {
+		p = &app->hwq_in_params[i];
+		if (!APP_PARAM_VALID(p))
+			continue;
+
+		fprintf(f, "[%s]\n", p->name);
+		fprintf(f, "%s = %s\n", "mempool", app->mempool_params[p->mempool_id].name);
+		fprintf(f, "%s = %" PRIu32 "\n", "size", p->size);
+		fprintf(f, "%s = %" PRIu32 "\n", "burst", p->burst);
+
+		fputc('\n', f);
+	}
+}
+
+static void
+save_txq_params(struct app_params *app, FILE *f)
+{
+	struct app_pktq_hwq_out_params *p;
+	size_t i, count;
+
+	count = RTE_DIM(app->hwq_out_params);
+	for (i = 0; i < count; i++) {
+		p = &app->hwq_out_params[i];
+		if (!APP_PARAM_VALID(p))
+			continue;
+
+		fprintf(f, "[%s]\n", p->name);
+		fprintf(f, "%s = %" PRIu32 "\n", "size", p->size);
+		fprintf(f, "%s = %" PRIu32 "\n", "burst", p->burst);
+		fprintf(f, "%s = %s\n", "dropless", p->dropless ? "yes" : "no");
+
+		fputc('\n', f);
+	}
+}
+
+static void
+save_swq_params(struct app_params *app, FILE *f)
+{
+	struct app_pktq_swq_params *p;
+	size_t i, count;
+
+	count = RTE_DIM(app->swq_params);
+	for (i = 0; i < count; i++) {
+		p = &app->swq_params[i];
+		if (!APP_PARAM_VALID(p))
+			continue;
+
+		fprintf(f, "[%s]\n", p->name);
+		fprintf(f, "%s = %" PRIu32 "\n", "size", p->size);
+		fprintf(f, "%s = %" PRIu32 "\n", "burst_read", p->burst_read);
+		fprintf(f, "%s = %" PRIu32 "\n", "burst_write", p->burst_write);
+		fprintf(f, "%s = %s\n", "dropless", p->dropless ? "yes" : "no");
+		fprintf(f, "%s = %" PRIu64 "\n", "n_retries", p->n_retries);
+		fprintf(f, "%s = %" PRIu32 "\n", "cpu", p->cpu_socket_id);
+
+		fputc('\n', f);
+	}
+}
+
+static void
+save_tm_params(struct app_params *app, FILE *f)
+{
+	struct app_pktq_tm_params *p;
+	size_t i, count;
+
+	count = RTE_DIM(app->tm_params);
+	for (i = 0; i < count; i++) {
+		p = &app->tm_params[i];
+		if (!APP_PARAM_VALID(p))
+			continue;
+
+		fprintf(f, "[%s]\n", p->name);
+		fprintf(f, "%s = %s\n", "cfg", p->file_name);
+		fprintf(f, "%s = %u\n", "burst_read", p->burst_read);
+		fprintf(f, "%s = %u\n", "burst_write", p->burst_write);
+
+		fputc('\n', f);
+	}
+}
+
+static void
+save_source_params(struct app_params *app, FILE *f)
+{
+	struct app_pktq_source_params *p;
+	size_t i, count;
+
+	count = RTE_DIM(app->source_params);
+	for (i = 0; i < count; i++) {
+		p = &app->source_params[i];
+		if (!APP_PARAM_VALID(p))
+			continue;
+
+		fprintf(f, "[%s]\n", p->name);
+		fprintf(f, "%s = %s\n", "mempool", app->mempool_params[p->mempool_id].name);
+		fprintf(f, "%s = %u\n", "burst", p->burst);
+		fputc('\n', f);
+	}
+}
+
+static void
+save_msgq_params(struct app_params *app, FILE *f)
+{
+	struct app_msgq_params *p;
+	size_t i, count;
+
+	count = RTE_DIM(app->msgq_params);
+	for (i = 0; i < count; i++) {
+		p = &app->msgq_params[i];
+		if (!APP_PARAM_VALID(p))
+			continue;
+
+		fprintf(f, "[%s]\n", p->name);
+		fprintf(f, "%s = %" PRIu32 "\n", "size", p->size);
+		fprintf(f, "%s = %" PRIu32 "\n", "cpu", p->cpu_socket_id);
+
+		fputc('\n', f);
+	}
+}
+
+static void
+save_pipeline_params(struct app_params *app, FILE *f)
+{
+	size_t i, count;
+
+	count = RTE_DIM(app->pipeline_params);
+	for (i = 0; i < count; i++) {
+		struct app_pipeline_params *p = &app->pipeline_params[i];
+
+		if (!APP_PARAM_VALID(p))
+			continue;
+
+		/* section name */
+		fprintf(f, "[%s]\n", p->name);
+
+		/* type */
+		fprintf(f, "type = %s\n", p->type);
+
+		/* core */
+		fprintf(f, "core = s%uc%u%s\n",
+			p->socket_id,
+			p->core_id,
+			(p->hyper_th_id)? "h" : "");
+
+		/* pktq_in */
+		if (p->n_pktq_in) {
+			uint32_t j;
+
+			fprintf(f, "pktq_in =");
+			for (j = 0; j < p->n_pktq_in; j++) {
+				struct app_pktq_in_params *pp = &p->pktq_in[j];
+				char *name;
+
+				switch (pp->type) {
+				case APP_PKTQ_IN_HWQ:
+					name = app->hwq_in_params[pp->id].name;
+					break;
+				case APP_PKTQ_IN_SWQ:
+					name = app->swq_params[pp->id].name;
+					break;
+				case APP_PKTQ_IN_TM:
+					name = app->tm_params[pp->id].name;
+					break;
+				case APP_PKTQ_IN_SOURCE:
+					name = app->source_params[pp->id].name;
+					break;
+				default:
+					APP_CHECK(0, "Error\n");
+				}
+
+				fprintf(f, " %s", name);
+			}
+			fprintf(f, "\n");
+		}
+
+		/* pktq_in */
+		if (p->n_pktq_out) {
+			uint32_t j;
+
+			fprintf(f, "pktq_out =");
+			for (j = 0; j < p->n_pktq_out; j++) {
+				struct app_pktq_out_params *pp = &p->pktq_out[j];
+				char *name;
+
+				switch (pp->type) {
+				case APP_PKTQ_OUT_HWQ:
+					name = app->hwq_out_params[pp->id].name;
+					break;
+				case APP_PKTQ_OUT_SWQ:
+					name = app->swq_params[pp->id].name;
+					break;
+				case APP_PKTQ_OUT_TM:
+					name = app->tm_params[pp->id].name;
+					break;
+				case APP_PKTQ_OUT_SINK:
+					name = app->sink_params[pp->id].name;
+					break;
+				default:
+					APP_CHECK(0, "Error\n");
+				}
+
+				fprintf(f, " %s", name);
+			}
+			fprintf(f, "\n");
+		}
+
+		/* msgq_in */
+		if (p->n_msgq_in) {
+			uint32_t j;
+
+			fprintf(f, "msgq_in =");
+			for (j = 0; j < p->n_msgq_in; j++) {
+				uint32_t id = p->msgq_in[j];
+				char *name = app->msgq_params[id].name;
+
+				fprintf(f, " %s", name);
+			}
+			fprintf(f, "\n");
+		}
+
+		/* msgq_out */
+		if (p->n_msgq_in) {
+			uint32_t j;
+
+			fprintf(f, "msgq_out =");
+			for (j = 0; j < p->n_msgq_out; j++) {
+				uint32_t id = p->msgq_out[j];
+				char *name = app->msgq_params[id].name;
+
+				fprintf(f, " %s", name);
+			}
+			fprintf(f, "\n");
+		}
+
+		/* timer_period */
+		fprintf(f, "timer_period = %u\n", p->timer_period);
+
+		/* args */
+		if (p->n_args) {
+			uint32_t j;
+
+			for (j = 0; j < p->n_args; j++)
+				fprintf(f, "%s = %s\n", p->args_name[j], p->args_value[j]);
+		}
+
+		fprintf(f, "\n");
+	}
+}
+
+void
+app_config_save(struct app_params *app, const char *file_name)
+{
+	FILE *file = fopen(file_name, "w");
+
+	APP_CHECK(file != NULL, "Failed to save config to file '%s'", file_name);
+
+	save_pipeline_params(app, file);
+	save_mempool_params(app, file);
+	save_links_params(app, file);
+	save_rxq_params(app, file);
+	save_txq_params(app, file);
+	save_swq_params(app, file);
+	save_tm_params(app, file);
+	save_source_params(app, file);
+	save_msgq_params(app, file);
+
+	fclose(file);
+}
+
+int
+app_config_init(struct app_params *app)
+{
+	size_t i;
+
+	memset(app, 0, sizeof(struct app_params));
+
+	strcpy(app->config_file, DEFAULT_CONFIG_FILE);
+
+	for (i = 0; i < RTE_DIM(app->mempool_params); i++)
+		memcpy(&app->mempool_params[i], &mempool_params_default,
+				sizeof(struct app_mempool_params));
+
+	for (i = 0; i < RTE_DIM(app->link_params); i++)
+		memcpy(&app->link_params[i], &link_params_default,
+				sizeof(struct app_link_params));
+
+	for (i = 0; i < RTE_DIM(app->hwq_in_params); i++)
+		memcpy(&app->hwq_in_params[i], &default_hwq_in_params,
+				sizeof(default_hwq_in_params));
+
+	for (i = 0; i < RTE_DIM(app->hwq_out_params); i++)
+		memcpy(&app->hwq_out_params[i], &default_hwq_out_params,
+				sizeof(default_hwq_out_params));
+
+	for (i = 0; i < RTE_DIM(app->swq_params); i++)
+		memcpy(&app->swq_params[i], &default_swq_params,
+				sizeof(default_swq_params));
+
+	for (i = 0; i < RTE_DIM(app->tm_params); i++)
+		memcpy(&app->tm_params[i], &default_tm_params,
+				sizeof(default_tm_params));
+
+	for (i = 0; i < RTE_DIM(app->source_params); i++)
+		memcpy(&app->source_params[i], &default_source_params,
+				sizeof(default_source_params));
+
+	for (i = 0; i < RTE_DIM(app->sink_params); i++)
+		memcpy(&app->sink_params[i], &default_sink_params,
+				sizeof(default_sink_params));
+
+	for (i = 0; i < RTE_DIM(app->msgq_params); i++)
+		memcpy(&app->msgq_params[i], &default_msgq_params,
+				sizeof(default_msgq_params));
+
+	for (i = 0; i < RTE_DIM(app->pipeline_params); i++)
+		memcpy(&app->pipeline_params[i], &default_pipeline_params,
+				sizeof(default_pipeline_params));
+
+	return 0;
+}
+
+int
+app_config_args(struct app_params *app, int argc, char **argv)
+{
+	int opt;
+	int option_index, p_present, f_present, s_present;
+	int scaned = 0;
+
+	static struct option lgopts[] = {
+		{NULL, 0, 0, 0}
+	};
+
+	/* Copy application name */
+	strncpy(app->app_name, argv[0], APP_APPNAME_SIZE - 1);
+
+	p_present = 0;
+	f_present = 0;
+	s_present = 0;
+
+	while ((opt = getopt_long(argc, argv, "f:s:p:", lgopts,
+			&option_index)) != EOF) {
+		switch (opt) {
+		case 'p':
+			if (sscanf(optarg, "%" SCNx64 "%n", &app->port_mask, &scaned) != 1 ||
+				(size_t) scaned != strlen(optarg))
+				rte_panic("Error: PORT_MASK is not a hexadecimal integer\n");
+
+			if (app->port_mask == 0)
+				rte_panic("Error: PORT_MASK is null\n");
+
+			if (p_present)
+				rte_panic("Error: PORT_MASK is provided more than once\n");
+
+			p_present = 1;
+			break;
+
+		case 'f':
+			snprintf(app->config_file, sizeof(app->config_file), "%s", optarg);
+
+			if (!strlen(app->config_file))
+				rte_panic("Error: Config file name is null\n");
+
+			if (f_present)
+				rte_panic("Error: Config file is provided more than once\n");
+
+			f_present = 1;
+			break;
+
+		case 's':
+			snprintf(app->script_file, sizeof(app->script_file), "%s", optarg);
+
+			if (!strlen(app->script_file))
+				rte_panic("Error: Script file name is null\n");
+
+			if (s_present)
+				rte_panic("Error: Script file is provided more than once\n");
+
+			s_present = 1;
+			break;
+
+		default:
+			app_print_usage(argv[0]);
+		}
+	}
+
+	optind = 0; /* reset getopt lib */
+
+	/* Check that mandatory args have been provided */
+	if (!p_present)
+		rte_panic("Error: PORT_MASK is not provided\n");
+
+	return 0;
+}
diff --git a/examples/ip_pipeline/cpu_core_map.c b/examples/ip_pipeline/cpu_core_map.c
new file mode 100644
index 0000000..0d83879
--- /dev/null
+++ b/examples/ip_pipeline/cpu_core_map.c
@@ -0,0 +1,465 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <rte_lcore.h>
+
+#include "cpu_core_map.h"
+
+struct cpu_core_map {
+	uint32_t n_max_sockets;
+	uint32_t n_max_cores_per_socket;
+	uint32_t n_max_ht_per_core;
+	uint32_t n_sockets;
+	uint32_t n_cores_per_socket;
+	uint32_t n_ht_per_core;
+	int map[0];
+};
+
+static inline uint32_t
+cpu_core_map_pos(struct cpu_core_map *map,
+	uint32_t socket_id,
+	uint32_t core_id,
+	uint32_t ht_id)
+{
+	return (socket_id * map->n_max_cores_per_socket + core_id) * map->n_max_ht_per_core + ht_id;
+}
+
+static int
+cpu_core_map_compute_eal(struct cpu_core_map *map);
+
+static int
+cpu_core_map_compute_linux(struct cpu_core_map *map);
+
+static int
+cpu_core_map_compute_and_check(struct cpu_core_map *map);
+
+struct cpu_core_map *
+cpu_core_map_init(uint32_t n_max_sockets,
+	uint32_t n_max_cores_per_socket,
+	uint32_t n_max_ht_per_core,
+	uint32_t eal_initialized)
+{
+	uint32_t map_size, map_mem_size, i;
+	struct cpu_core_map *map;
+	int status;
+	
+	/* Check input arguments */
+	if ((n_max_sockets == 0) ||
+		(n_max_cores_per_socket == 0) ||
+		(n_max_ht_per_core == 0))
+		return NULL;
+
+	/* Memory allocation */
+	map_size = n_max_sockets * n_max_cores_per_socket * n_max_ht_per_core;
+	map_mem_size = sizeof(struct cpu_core_map) + map_size * sizeof(int);
+	map = (struct cpu_core_map *) malloc(map_mem_size);
+	if (map == NULL)
+		return NULL;
+
+	/* Initialization */
+	map->n_max_sockets = n_max_sockets;
+	map->n_max_cores_per_socket = n_max_cores_per_socket;
+	map->n_max_ht_per_core = n_max_ht_per_core;
+	map->n_sockets = 0;
+	map->n_cores_per_socket = 0;
+	map->n_ht_per_core = 0;
+
+	for (i = 0; i < map_size; i++)
+		map->map[i] = -1;
+
+	status = (eal_initialized)?
+		cpu_core_map_compute_eal(map) :
+		cpu_core_map_compute_linux(map);
+
+	if (status) {
+		free(map);
+		return NULL;
+	}
+
+	status = cpu_core_map_compute_and_check(map);
+	if (status) {
+		free(map);
+		return NULL;
+	}
+	
+	return map;
+}
+
+int
+cpu_core_map_compute_eal(struct cpu_core_map *map)
+{
+	uint32_t socket_id, core_id, ht_id;
+
+	/* Compute map */
+	for (socket_id = 0; socket_id < map->n_max_sockets; socket_id++) {
+		uint32_t n_detected, core_id_contig;
+		int lcore_id;
+
+		n_detected = 0;
+		for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
+			struct lcore_config *p = &lcore_config[lcore_id];
+			
+			if ((p->detected) && (p->socket_id == socket_id))
+				n_detected ++;
+		}
+
+		core_id_contig = 0;
+
+		for (core_id = 0; n_detected ; core_id++) {
+			ht_id = 0;
+
+			for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
+				struct lcore_config *p = &lcore_config[lcore_id];
+				
+				if ((p->detected) && 
+					(p->socket_id == socket_id) &&
+					(p->core_id == core_id)) {
+					uint32_t pos = cpu_core_map_pos(map, socket_id, core_id_contig, ht_id);
+
+					map->map[pos] = lcore_id;
+					ht_id ++;
+					n_detected --;
+				}
+			}
+			
+			if (ht_id) {
+				core_id_contig ++;
+				if (core_id_contig == map->n_max_cores_per_socket)
+					return -1;
+			}
+		}		
+	}
+	
+	return 0;
+}
+
+int
+cpu_core_map_compute_and_check(struct cpu_core_map *map)
+{
+	uint32_t socket_id, core_id, ht_id;
+
+	/* Compute n_ht_per_core, n_cores_per_socket, n_sockets */
+	for (ht_id = 0; ht_id < map->n_max_ht_per_core; ht_id++) {
+		if (map->map[ht_id] == -1)
+			break;
+		
+		map->n_ht_per_core ++;
+	}
+	
+	if (map->n_ht_per_core == 0)
+		return -1;
+	
+	for (core_id = 0; core_id < map->n_max_cores_per_socket; core_id++) {
+		uint32_t pos = core_id * map->n_max_ht_per_core;
+
+		if (map->map[pos] == -1)
+			break;
+		
+		map->n_cores_per_socket ++;
+	}
+
+	if (map->n_cores_per_socket == 0)
+		return -1;
+	
+	for (socket_id = 0; socket_id < map->n_max_sockets; socket_id++) {
+		uint32_t pos = socket_id * map->n_max_cores_per_socket * map->n_max_ht_per_core;
+		
+		if (map->map[pos] == -1)
+			break;
+			
+		map->n_sockets ++;
+	}
+
+	if (map->n_sockets == 0)
+		return -1;
+
+	/* Check that each socket has exactly the same number of cores 
+	and that each core has exactly the same number of hyper-threads */
+	for (socket_id = 0; socket_id < map->n_sockets; socket_id++) {
+		for (core_id = 0; core_id < map->n_cores_per_socket; core_id++)
+			for (ht_id = 0; ht_id < map->n_max_ht_per_core; ht_id++) {
+				uint32_t pos = (socket_id * map->n_max_cores_per_socket + core_id) * map->n_max_ht_per_core + ht_id;
+				
+				if (((ht_id < map->n_ht_per_core) && (map->map[pos] == -1)) ||
+					((ht_id >= map->n_ht_per_core) && (map->map[pos] != -1)))
+					return -1;
+			}
+		
+		for ( ; core_id < map->n_max_cores_per_socket; core_id++)
+			for (ht_id = 0; ht_id < map->n_max_ht_per_core; ht_id++) {
+				uint32_t pos = cpu_core_map_pos(map, socket_id, core_id, ht_id);
+
+				if (map->map[pos] != -1)
+					return -1;
+			}
+	}
+
+	return 0;
+}
+
+#define FILE_LINUX_CPU_N_LCORES \
+	"/sys/devices/system/cpu/present"
+
+static int
+cpu_core_map_get_n_lcores_linux(void)
+{
+	char buffer[64], *string;
+	FILE* fd;
+
+	fd = fopen(FILE_LINUX_CPU_N_LCORES, "r");
+	if (fd == NULL)
+		return -1;
+	
+	if (fgets(buffer, sizeof(buffer), fd) == NULL) {
+		fclose(fd);
+		return -1;
+	}
+
+	fclose(fd);
+
+	string = index(buffer, '-');
+	if (string == NULL)
+		return -1;
+
+	return (atoi(++string) + 1);
+}
+
+#define FILE_LINUX_CPU_CORE_ID \
+	"/sys/devices/system/cpu/cpu%u/topology/core_id"
+
+static int
+cpu_core_map_get_core_id_linux(int lcore_id)
+{
+	char buffer[64];
+	FILE* fd;
+	int core_id;
+
+	snprintf(buffer, sizeof(buffer), FILE_LINUX_CPU_CORE_ID, lcore_id);
+	fd = fopen(buffer, "r");
+	if (fd == NULL)
+		return -1;
+	
+	if (fgets(buffer, sizeof(buffer), fd) == NULL) {
+		fclose(fd);
+		return -1;
+	}
+
+	fclose(fd);
+
+	core_id = atoi(buffer);
+	return core_id;
+}
+
+#define FILE_LINUX_CPU_SOCKET_ID \
+	"/sys/devices/system/cpu/cpu%u/topology/physical_package_id"
+
+static int
+cpu_core_map_get_socket_id_linux(int lcore_id)
+{
+	char buffer[64];
+	FILE* fd;
+	int socket_id;
+
+	snprintf(buffer, sizeof(buffer), FILE_LINUX_CPU_SOCKET_ID, lcore_id);
+	fd = fopen(buffer, "r");
+	if (fd == NULL)
+		return -1;
+
+	if (fgets(buffer, sizeof(buffer), fd) == NULL) {
+		fclose(fd);
+		return -1;
+	}
+
+	fclose(fd);
+
+	socket_id = atoi(buffer);
+	return socket_id;
+}
+
+int
+cpu_core_map_compute_linux(struct cpu_core_map *map)
+{
+	uint32_t socket_id, core_id, ht_id;
+	int n_lcores;
+
+	n_lcores = cpu_core_map_get_n_lcores_linux();
+	if (n_lcores <= 0)
+		return -1;
+
+	/* Compute map */
+	for (socket_id = 0; socket_id < map->n_max_sockets; socket_id++) {
+		uint32_t n_detected, core_id_contig;
+		int lcore_id;
+
+		n_detected = 0;
+		for (lcore_id = 0; lcore_id < n_lcores; lcore_id++) {
+			int lcore_socket_id = cpu_core_map_get_socket_id_linux(lcore_id);
+			if (lcore_socket_id < 0)
+				return -1;
+
+			if (((uint32_t) lcore_socket_id) == socket_id)
+				n_detected ++;
+		}
+
+		core_id_contig = 0;
+
+		for (core_id = 0; n_detected ; core_id++) {
+			ht_id = 0;
+
+			for (lcore_id = 0; lcore_id < n_lcores; lcore_id++) {
+				int lcore_socket_id = cpu_core_map_get_socket_id_linux(lcore_id);
+				if (lcore_socket_id < 0)
+					return -1;
+
+				int lcore_core_id = cpu_core_map_get_core_id_linux(lcore_id);
+				if (lcore_core_id < 0)
+					return -1;
+
+				if ((((uint32_t) lcore_socket_id) == socket_id) &&
+					(((uint32_t) lcore_core_id) == core_id)) {
+					uint32_t pos = cpu_core_map_pos(map, socket_id, core_id_contig, ht_id);
+
+					map->map[pos] = lcore_id;
+					ht_id ++;
+					n_detected --;
+				}
+			}
+			
+			if (ht_id) {
+				core_id_contig ++;
+				if (core_id_contig == map->n_max_cores_per_socket)
+					return -1;
+			}
+		}
+	}
+
+	return 0;
+}
+
+void
+cpu_core_map_print(struct cpu_core_map *map)
+{
+#if 1
+	uint32_t socket_id, core_id, ht_id;
+
+	if (map == NULL)
+		return;
+
+	for (socket_id = 0; socket_id < map->n_sockets; socket_id++) {
+		printf("Socket %u:\n", socket_id);
+		
+		for (core_id = 0; core_id < map->n_cores_per_socket; core_id++) {
+			printf("[%2u] = [", core_id);
+			
+			for (ht_id = 0; ht_id < map->n_ht_per_core; ht_id++) {
+				int lcore_id = cpu_core_map_get_lcore_id(map, socket_id, core_id, ht_id);
+				//uint32_t core_id_noncontig = lcore_config[lcore_id].core_id;
+				uint32_t core_id_noncontig = cpu_core_map_get_core_id_linux(lcore_id);
+
+				printf(" %2d (%2u) ", lcore_id, core_id_noncontig);
+			}
+			
+			printf("]\n");
+		}
+	}
+#else
+	uint32_t size, i;
+
+	if (map == NULL)
+		return;
+
+	size = map->n_max_sockets * map->n_max_cores_per_socket * map->n_max_ht_per_core;
+	printf("(n_sockets = %u, n_cores_per_socket = %u, n_ht_per_core = %u) [",
+		map->n_sockets, map->n_cores_per_socket, map->n_ht_per_core);
+	for (i = 0; i < size; i++)
+		printf("%d  ", map->map[i]);
+	printf("]\n");
+#endif
+}
+
+uint32_t
+cpu_core_map_get_n_sockets(struct cpu_core_map *map)
+{
+	if (map == NULL)
+		return 0;
+
+	return map->n_sockets;
+}
+
+uint32_t
+cpu_core_map_get_n_cores_per_socket(struct cpu_core_map *map)
+{
+	if (map == NULL)
+		return 0;
+
+	return map->n_cores_per_socket;
+}
+
+uint32_t
+cpu_core_map_get_n_ht_per_core(struct cpu_core_map *map)
+{
+	if (map == NULL)
+		return 0;
+
+	return map->n_ht_per_core;
+}
+
+int
+cpu_core_map_get_lcore_id(struct cpu_core_map *map,
+	uint32_t socket_id,
+	uint32_t core_id,
+	uint32_t ht_id)
+{
+	uint32_t pos;
+
+	if ((map == NULL) ||
+		(socket_id >= map->n_sockets) ||
+		(core_id >= map->n_cores_per_socket) ||
+		(ht_id >= map->n_ht_per_core))
+		return -1;
+
+	pos = cpu_core_map_pos(map, socket_id, core_id, ht_id);
+
+	return map->map[pos];
+}
+
+void
+cpu_core_map_free(struct cpu_core_map *map)
+{
+	if (map)
+		free(map);
+}
diff --git a/examples/ip_pipeline/cpu_core_map.h b/examples/ip_pipeline/cpu_core_map.h
new file mode 100644
index 0000000..5c2ec72
--- /dev/null
+++ b/examples/ip_pipeline/cpu_core_map.h
@@ -0,0 +1,69 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __INCLUDE_CPU_CORE_MAP_H__
+#define __INCLUDE_CPU_CORE_MAP_H__
+
+#include <stdio.h>
+
+#include <rte_lcore.h>
+
+struct cpu_core_map;
+
+struct cpu_core_map *
+cpu_core_map_init(uint32_t n_max_sockets,
+	uint32_t n_max_cores_per_socket,
+	uint32_t n_max_ht_per_core,
+	uint32_t eal_initialized);
+
+uint32_t
+cpu_core_map_get_n_sockets(struct cpu_core_map *map);
+
+uint32_t
+cpu_core_map_get_n_cores_per_socket(struct cpu_core_map *map);
+
+uint32_t
+cpu_core_map_get_n_ht_per_core(struct cpu_core_map *map);
+
+int
+cpu_core_map_get_lcore_id(struct cpu_core_map *map,
+	uint32_t socket_id,
+	uint32_t core_id,
+	uint32_t ht_id);
+
+void cpu_core_map_print(struct cpu_core_map *map);
+
+void
+cpu_core_map_free(struct cpu_core_map *map);
+
+#endif
diff --git a/examples/ip_pipeline/main.c b/examples/ip_pipeline/main.c
index eb750b6..a2d7ef0 100644
--- a/examples/ip_pipeline/main.c
+++ b/examples/ip_pipeline/main.c
@@ -1,7 +1,7 @@
 /*-
  *   BSD LICENSE
  *
- *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
  *   All rights reserved.
  *
  *   Redistribution and use in source and binary forms, with or without
@@ -31,135 +31,21 @@
  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <inttypes.h>
-#include <sys/types.h>
-#include <string.h>
-#include <sys/queue.h>
-#include <stdarg.h>
-#include <errno.h>
-#include <getopt.h>
-#include <unistd.h>
+#include "app.h"
 
-#include <rte_common.h>
-#include <rte_byteorder.h>
-#include <rte_log.h>
-#include <rte_memory.h>
-#include <rte_memcpy.h>
-#include <rte_memzone.h>
-#include <rte_eal.h>
-#include <rte_per_lcore.h>
-#include <rte_launch.h>
-#include <rte_atomic.h>
-#include <rte_cycles.h>
-#include <rte_prefetch.h>
-#include <rte_lcore.h>
-#include <rte_per_lcore.h>
-#include <rte_branch_prediction.h>
-#include <rte_interrupts.h>
-#include <rte_pci.h>
-#include <rte_random.h>
-#include <rte_debug.h>
-#include <rte_ether.h>
-#include <rte_ethdev.h>
-#include <rte_ring.h>
-#include <rte_mempool.h>
-#include <rte_mbuf.h>
-#include <rte_ip.h>
-#include <rte_tcp.h>
-#include <rte_lpm.h>
-#include <rte_lpm6.h>
-
-#include "main.h"
+static struct app_params app;
 
 int
 main(int argc, char **argv)
 {
-	int ret;
-
-	/* Init EAL */
-	ret = rte_eal_init(argc, argv);
-	if (ret < 0)
-		return -1;
-	argc -= ret;
-	argv += ret;
+	rte_openlog_stream(stderr);
 
-	/* Parse application arguments (after the EAL ones) */
-	ret = app_parse_args(argc, argv);
-	if (ret < 0) {
-		app_print_usage(argv[0]);
-		return -1;
-	}
+	/* Config */
+	app_config_init(&app);
 
-	/* Init */
-	app_init();
+	app_config_args(&app, argc, argv);
 
-	/* Launch per-lcore init on every lcore */
-	rte_eal_mp_remote_launch(app_lcore_main_loop, NULL, CALL_MASTER);
+	app_config_parse(&app, app.config_file);
 
 	return 0;
 }
-
-int
-app_lcore_main_loop(__attribute__((unused)) void *arg)
-{
-	uint32_t core_id, i;
-
-	core_id = rte_lcore_id();
-
-	for (i = 0; i < app.n_cores; i++) {
-		struct app_core_params *p = &app.cores[i];
-
-		if (p->core_id != core_id)
-			continue;
-
-		switch (p->core_type) {
-		case APP_CORE_MASTER:
-			app_ping();
-			app_main_loop_cmdline();
-			return 0;
-		case APP_CORE_RX:
-			app_main_loop_pipeline_rx();
-			/* app_main_loop_rx(); */
-			return 0;
-		case APP_CORE_TX:
-			app_main_loop_pipeline_tx();
-			/* app_main_loop_tx(); */
-			return 0;
-		case APP_CORE_PT:
-			/* app_main_loop_pipeline_passthrough(); */
-			app_main_loop_passthrough();
-			return 0;
-		case APP_CORE_FC:
-			app_main_loop_pipeline_flow_classification();
-			return 0;
-		case APP_CORE_FW:
-		case APP_CORE_RT:
-			app_main_loop_pipeline_routing();
-			return 0;
-
-#ifdef RTE_LIBRTE_ACL
-			app_main_loop_pipeline_firewall();
-			return 0;
-#else
-			rte_exit(EXIT_FAILURE, "ACL not present in build\n");
-#endif
-
-		case APP_CORE_IPV4_FRAG:
-			app_main_loop_pipeline_ipv4_frag();
-			return 0;
-		case APP_CORE_IPV4_RAS:
-			app_main_loop_pipeline_ipv4_ras();
-			return 0;
-
-		default:
-			rte_panic("%s: Invalid core type for core %u\n",
-				__func__, i);
-		}
-	}
-
-	rte_panic("%s: Algorithmic error\n", __func__);
-	return -1;
-}
diff --git a/examples/ip_pipeline/main.h b/examples/ip_pipeline/main.h
deleted file mode 100644
index 6085aaa..0000000
--- a/examples/ip_pipeline/main.h
+++ /dev/null
@@ -1,298 +0,0 @@
-/*-
- *   BSD LICENSE
- *
- *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
- *   All rights reserved.
- *
- *   Redistribution and use in source and binary forms, with or without
- *   modification, are permitted provided that the following conditions
- *   are met:
- *
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in
- *       the documentation and/or other materials provided with the
- *       distribution.
- *     * Neither the name of Intel Corporation nor the names of its
- *       contributors may be used to endorse or promote products derived
- *       from this software without specific prior written permission.
- *
- *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef _MAIN_H_
-#define _MAIN_H_
-
-#include <stdint.h>
-
-#include <rte_mempool.h>
-#include <rte_mbuf.h>
-#include <rte_ring.h>
-#include <rte_ethdev.h>
-
-#ifdef RTE_LIBRTE_ACL
-#include <rte_table_acl.h>
-#endif
-
-struct app_flow_key {
-	union {
-		struct {
-			uint8_t ttl; /* needs to be set to 0 */
-			uint8_t proto;
-			uint16_t header_checksum; /* needs to be set to 0 */
-			uint32_t ip_src;
-		};
-		uint64_t slab0;
-	};
-
-	union {
-		struct {
-			uint32_t ip_dst;
-			uint16_t port_src;
-			uint16_t port_dst;
-		};
-		uint64_t slab1;
-	};
-} __attribute__((__packed__));
-
-struct app_arp_key {
-	uint32_t nh_ip;
-	uint32_t nh_iface;
-} __attribute__((__packed__));
-
-struct app_pkt_metadata {
-	uint32_t signature;
-	uint8_t reserved1[28];
-
-	struct app_flow_key flow_key;
-
-	struct app_arp_key arp_key;
-	struct ether_addr nh_arp;
-
-	uint8_t reserved3[2];
-} __attribute__((__packed__));
-
-#ifndef APP_MBUF_ARRAY_SIZE
-#define APP_MBUF_ARRAY_SIZE            256
-#endif
-
-struct app_mbuf_array {
-	struct rte_mbuf *array[APP_MBUF_ARRAY_SIZE];
-	uint32_t n_mbufs;
-};
-
-#ifndef APP_MAX_PORTS
-#define APP_MAX_PORTS                  4
-#endif
-
-#ifndef APP_MAX_SWQ_PER_CORE
-#define APP_MAX_SWQ_PER_CORE           8
-#endif
-
-#define APP_SWQ_INVALID                ((uint32_t)(-1))
-
-#define APP_SWQ_IN_REQ                 (APP_MAX_SWQ_PER_CORE - 1)
-
-#define APP_SWQ_OUT_RESP               (APP_MAX_SWQ_PER_CORE - 1)
-
-enum app_core_type {
-	APP_CORE_NONE = 0, /* Unused */
-	APP_CORE_MASTER,   /* Management */
-	APP_CORE_RX,       /* Reception */
-	APP_CORE_TX,       /* Transmission */
-	APP_CORE_PT,       /* Pass-through */
-	APP_CORE_FC,       /* Flow Classification */
-	APP_CORE_FW,       /* Firewall */
-	APP_CORE_RT,       /* Routing */
-	APP_CORE_TM,       /* Traffic Management */
-	APP_CORE_IPV4_FRAG,/* IPv4 Fragmentation */
-	APP_CORE_IPV4_RAS, /* IPv4 Reassembly */
-};
-
-struct app_core_params {
-	uint32_t core_id;
-	enum app_core_type core_type;
-
-	/* SWQ map */
-	uint32_t swq_in[APP_MAX_SWQ_PER_CORE];
-	uint32_t swq_out[APP_MAX_SWQ_PER_CORE];
-} __rte_cache_aligned;
-
-struct app_params {
-	/* CPU cores */
-	struct app_core_params cores[RTE_MAX_LCORE];
-	uint32_t n_cores;
-
-	/* Ports*/
-	uint32_t ports[APP_MAX_PORTS];
-	uint32_t n_ports;
-	uint32_t rsz_hwq_rx;
-	uint32_t rsz_hwq_tx;
-	uint32_t bsz_hwq_rd;
-	uint32_t bsz_hwq_wr;
-	struct rte_eth_conf port_conf;
-	struct rte_eth_rxconf rx_conf;
-	struct rte_eth_txconf tx_conf;
-
-	/* SW Queues (SWQs) */
-	struct rte_ring **rings;
-	uint32_t rsz_swq;
-	uint32_t bsz_swq_rd;
-	uint32_t bsz_swq_wr;
-
-	/* Buffer pool */
-	struct rte_mempool *pool;
-	struct rte_mempool *indirect_pool;
-	uint32_t pool_buffer_size;
-	uint32_t pool_size;
-	uint32_t pool_cache_size;
-
-	/* Message buffer pool */
-	struct rte_mempool *msg_pool;
-	uint32_t msg_pool_buffer_size;
-	uint32_t msg_pool_size;
-	uint32_t msg_pool_cache_size;
-
-	/* Rule tables */
-	uint32_t max_arp_rules;
-	uint32_t max_routing_rules;
-	uint32_t max_firewall_rules;
-	uint32_t max_flow_rules;
-
-	/* Processing */
-	uint32_t ether_hdr_pop_push;
-} __rte_cache_aligned;
-
-extern struct app_params app;
-
-const char *app_core_type_id_to_string(enum app_core_type id);
-int app_core_type_string_to_id(const char *string, enum app_core_type *id);
-void app_cores_config_print(void);
-
-void app_check_core_params(void);
-struct app_core_params *app_get_core_params(uint32_t core_id);
-uint32_t app_get_first_core_id(enum app_core_type core_type);
-struct rte_ring *app_get_ring_req(uint32_t core_id);
-struct rte_ring *app_get_ring_resp(uint32_t core_id);
-
-int app_parse_args(int argc, char **argv);
-void app_print_usage(char *prgname);
-void app_init(void);
-void app_ping(void);
-int app_lcore_main_loop(void *arg);
-
-/* Hash functions */
-uint64_t test_hash(void *key, uint32_t key_size, uint64_t seed);
-uint32_t rte_jhash2_16(uint32_t *k, uint32_t initval);
-#if defined(__x86_64__)
-uint32_t rte_aeshash_16(uint64_t *k, uint64_t seed);
-uint32_t rte_crchash_16(uint64_t *k, uint64_t seed);
-#endif
-
-/* I/O with no pipeline */
-void app_main_loop_rx(void);
-void app_main_loop_tx(void);
-void app_main_loop_passthrough(void);
-
-/* Pipeline */
-void app_main_loop_pipeline_rx(void);
-void app_main_loop_pipeline_rx_frag(void);
-void app_main_loop_pipeline_tx(void);
-void app_main_loop_pipeline_tx_ras(void);
-void app_main_loop_pipeline_flow_classification(void);
-void app_main_loop_pipeline_firewall(void);
-void app_main_loop_pipeline_routing(void);
-void app_main_loop_pipeline_passthrough(void);
-void app_main_loop_pipeline_ipv4_frag(void);
-void app_main_loop_pipeline_ipv4_ras(void);
-
-/* Command Line Interface (CLI) */
-void app_main_loop_cmdline(void);
-
-/* Messages */
-enum app_msg_req_type {
-	APP_MSG_REQ_PING,
-	APP_MSG_REQ_FC_ADD,
-	APP_MSG_REQ_FC_DEL,
-	APP_MSG_REQ_FC_ADD_ALL,
-	APP_MSG_REQ_FW_ADD,
-	APP_MSG_REQ_FW_DEL,
-	APP_MSG_REQ_RT_ADD,
-	APP_MSG_REQ_RT_DEL,
-	APP_MSG_REQ_ARP_ADD,
-	APP_MSG_REQ_ARP_DEL,
-	APP_MSG_REQ_RX_PORT_ENABLE,
-	APP_MSG_REQ_RX_PORT_DISABLE,
-};
-
-struct app_msg_req {
-	enum app_msg_req_type type;
-	union {
-		struct {
-			uint32_t ip;
-			uint8_t depth;
-			uint8_t port;
-			uint32_t nh_ip;
-		} routing_add;
-		struct {
-			uint32_t ip;
-			uint8_t depth;
-		} routing_del;
-		struct {
-			uint8_t out_iface;
-			uint32_t nh_ip;
-			struct ether_addr nh_arp;
-		} arp_add;
-		struct {
-			uint8_t out_iface;
-			uint32_t nh_ip;
-		} arp_del;
-		struct {
-			union {
-				uint8_t key_raw[16];
-				struct app_flow_key key;
-			};
-			uint8_t port;
-		} flow_classif_add;
-		struct {
-			union {
-				uint8_t key_raw[16];
-				struct app_flow_key key;
-			};
-		} flow_classif_del;
-#ifdef RTE_LIBRTE_ACL
-		struct {
-			struct rte_table_acl_rule_add_params add_params;
-			uint8_t port;
-		} firewall_add;
-		struct {
-			struct rte_table_acl_rule_delete_params delete_params;
-		} firewall_del;
-#endif
-		struct {
-			uint8_t port;
-		} rx_up;
-		struct {
-			uint8_t port;
-		} rx_down;
-	};
-};
-
-struct app_msg_resp {
-	int result;
-};
-
-#define APP_FLUSH 0xFF
-
-#endif /* _MAIN_H_ */
diff --git a/examples/ip_pipeline/pipeline.h b/examples/ip_pipeline/pipeline.h
new file mode 100644
index 0000000..de85f82
--- /dev/null
+++ b/examples/ip_pipeline/pipeline.h
@@ -0,0 +1,79 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __INCLUDE_PIPELINE_H__
+#define __INCLUDE_PIPELINE_H__
+
+#include <cmdline_parse.h>
+
+#include "pipeline_ops.h"
+
+typedef void* (*pipeline_fe_op_init)(struct pipeline_params *params, void *arg);
+
+typedef int (*pipeline_fe_op_free)(void *pipeline);
+
+struct pipeline_fe_ops {
+	pipeline_fe_op_init f_init;
+	pipeline_fe_op_free f_free;
+	cmdline_parse_ctx_t *cmds;
+};
+
+struct pipeline_type {
+	const char *name;
+	
+	/* pipeline back-end */
+	struct pipeline_ops *ops;
+	
+	/* pipeline front-end */
+	struct pipeline_fe_ops *fe_ops;
+};
+
+static inline uint32_t
+pipeline_type_cmds_count(struct pipeline_type *ptype)
+{
+	cmdline_parse_ctx_t *cmds;
+	uint32_t n_cmds;
+
+	if (ptype->fe_ops == NULL)
+		return 0;
+
+	cmds = ptype->fe_ops->cmds;
+	if (cmds == NULL)
+		return 0;
+
+	for (n_cmds = 0; cmds[n_cmds]; n_cmds++);
+
+	return n_cmds;
+}
+
+#endif
diff --git a/examples/ip_pipeline/pipeline_ops.h b/examples/ip_pipeline/pipeline_ops.h
new file mode 100644
index 0000000..ae98dc7
--- /dev/null
+++ b/examples/ip_pipeline/pipeline_ops.h
@@ -0,0 +1,247 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __INCLUDE_PIPELINE_OPS_H__
+#define __INCLUDE_PIPELINE_OPS_H__
+
+#include <rte_port_ethdev.h>
+#include <rte_port_ring.h>
+#include <rte_port_frag.h>
+#include <rte_port_ras.h>
+#include <rte_port_sched.h>
+#include <rte_port_source_sink.h>
+#include <rte_pipeline.h>
+
+enum pipeline_port_in_type {
+	PIPELINE_PORT_IN_ETHDEV_READER,
+	PIPELINE_PORT_IN_RING_READER,
+	PIPELINE_PORT_IN_RING_READER_IPV4_FRAG,
+	PIPELINE_PORT_IN_RING_READER_IPV6_FRAG,
+	PIPELINE_PORT_IN_SCHED_READER,
+	PIPELINE_PORT_IN_SOURCE,
+};
+
+struct pipeline_port_in_params {
+	enum pipeline_port_in_type type;
+	union {
+		struct rte_port_ethdev_reader_params ethdev;
+		struct rte_port_ring_reader_params ring;
+		struct rte_port_ring_reader_ipv4_frag_params ring_ipv4_frag;
+		struct rte_port_ring_reader_ipv6_frag_params ring_ipv6_frag;
+		struct rte_port_sched_reader_params sched;
+		struct rte_port_source_params source;
+	} params;
+	uint32_t burst_size;
+};
+
+static inline void *
+pipeline_port_in_params_convert(struct pipeline_port_in_params  *p)
+{
+	switch (p->type) {
+	case PIPELINE_PORT_IN_ETHDEV_READER:
+		return (void *) &p->params.ethdev;
+	case PIPELINE_PORT_IN_RING_READER:
+		return (void *) &p->params.ring;
+	case PIPELINE_PORT_IN_RING_READER_IPV4_FRAG:
+		return (void *) &p->params.ring_ipv4_frag;
+	case PIPELINE_PORT_IN_RING_READER_IPV6_FRAG:
+		return (void *) &p->params.ring_ipv6_frag;
+	case PIPELINE_PORT_IN_SCHED_READER:
+		return (void *) &p->params.sched;
+	case PIPELINE_PORT_IN_SOURCE:
+		return (void *) &p->params.source;
+	default:
+		return NULL;
+	}
+}
+
+static inline struct rte_port_in_ops *
+pipeline_port_in_params_get_ops(struct pipeline_port_in_params  *p)
+{
+	switch (p->type) {
+	case PIPELINE_PORT_IN_ETHDEV_READER:
+		return &rte_port_ethdev_reader_ops;
+	case PIPELINE_PORT_IN_RING_READER:
+		return &rte_port_ring_reader_ops;
+	case PIPELINE_PORT_IN_RING_READER_IPV4_FRAG:
+		return &rte_port_ring_reader_ipv4_frag_ops;
+	case PIPELINE_PORT_IN_RING_READER_IPV6_FRAG:
+		return &rte_port_ring_reader_ipv6_frag_ops;
+	case PIPELINE_PORT_IN_SCHED_READER:
+		return &rte_port_sched_reader_ops;
+	case PIPELINE_PORT_IN_SOURCE:
+		return &rte_port_source_ops;
+	default:
+		return NULL;
+	}
+}
+
+enum pipeline_port_out_type {
+	PIPELINE_PORT_OUT_ETHDEV_WRITER,
+	PIPELINE_PORT_OUT_ETHDEV_WRITER_NODROP,
+	PIPELINE_PORT_OUT_RING_WRITER,
+	PIPELINE_PORT_OUT_RING_WRITER_NODROP,
+	PIPELINE_PORT_OUT_RING_WRITER_IPV4_RAS,
+	PIPELINE_PORT_OUT_RING_WRITER_IPV6_RAS,
+	PIPELINE_PORT_OUT_SCHED_WRITER,
+	PIPELINE_PORT_OUT_SINK,
+};
+
+struct pipeline_port_out_params {
+	enum pipeline_port_out_type type;
+	union {
+		struct rte_port_ethdev_writer_params ethdev;
+		struct rte_port_ethdev_writer_nodrop_params ethdev_nodrop;
+		struct rte_port_ring_writer_params ring;
+		struct rte_port_ring_writer_nodrop_params ring_nodrop;
+		struct rte_port_ring_writer_ipv4_ras_params ring_ipv4_ras;
+		struct rte_port_ring_writer_ipv6_ras_params ring_ipv6_ras;
+		struct rte_port_sched_writer_params sched;
+	} params;
+};
+
+static inline void *
+pipeline_port_out_params_convert(struct pipeline_port_out_params  *p)
+{
+	switch (p->type) {
+	case PIPELINE_PORT_OUT_ETHDEV_WRITER:
+		return (void *) &p->params.ethdev;
+	case PIPELINE_PORT_OUT_ETHDEV_WRITER_NODROP:
+		return (void *) &p->params.ethdev_nodrop;
+	case PIPELINE_PORT_OUT_RING_WRITER:
+		return (void *) &p->params.ring;
+	case PIPELINE_PORT_OUT_RING_WRITER_NODROP:
+		return (void *) &p->params.ring_nodrop;
+	case PIPELINE_PORT_OUT_RING_WRITER_IPV4_RAS:
+		return (void *) &p->params.ring_ipv4_ras;
+	case PIPELINE_PORT_OUT_RING_WRITER_IPV6_RAS:
+		return (void *) &p->params.ring_ipv6_ras;
+	case PIPELINE_PORT_OUT_SCHED_WRITER:
+		return (void *) &p->params.sched;
+	case PIPELINE_PORT_OUT_SINK:
+	default:
+		return NULL;
+	}
+}
+
+static inline void *
+pipeline_port_out_params_get_ops(struct pipeline_port_out_params  *p)
+{
+	switch (p->type) {
+	case PIPELINE_PORT_OUT_ETHDEV_WRITER:
+		return &rte_port_ethdev_writer_ops;
+	case PIPELINE_PORT_OUT_ETHDEV_WRITER_NODROP:
+		return &rte_port_ethdev_writer_nodrop_ops;
+	case PIPELINE_PORT_OUT_RING_WRITER:
+		return &rte_port_ring_writer_ops;
+	case PIPELINE_PORT_OUT_RING_WRITER_NODROP:
+		return &rte_port_ring_writer_nodrop_ops;
+	case PIPELINE_PORT_OUT_RING_WRITER_IPV4_RAS:
+		return &rte_port_ring_writer_ipv4_ras_ops;
+	case PIPELINE_PORT_OUT_RING_WRITER_IPV6_RAS:
+		return &rte_port_ring_writer_ipv6_ras_ops;
+	case PIPELINE_PORT_OUT_SCHED_WRITER:
+		return &rte_port_sched_writer_ops;
+	case PIPELINE_PORT_OUT_SINK:
+		return &rte_port_sink_ops;
+	default:
+		return NULL;
+	}
+}
+
+#ifndef PIPELINE_NAME_SIZE
+#define PIPELINE_NAME_SIZE                       32
+#endif
+
+#ifndef PIPELINE_MAX_PORT_IN
+#define PIPELINE_MAX_PORT_IN                     16
+#endif
+
+#ifndef PIPELINE_MAX_PORT_OUT
+#define PIPELINE_MAX_PORT_OUT                    16
+#endif
+
+#ifndef PIPELINE_MAX_TABLES
+#define PIPELINE_MAX_TABLES                      16
+#endif
+
+#ifndef PIPELINE_MAX_MSGQ_IN
+#define PIPELINE_MAX_MSGQ_IN                     16
+#endif
+
+#ifndef PIPELINE_MAX_MSGQ_OUT
+#define PIPELINE_MAX_MSGQ_OUT                    16
+#endif
+
+#ifndef PIPELINE_MAX_ARGS
+#define PIPELINE_MAX_ARGS                        32
+#endif
+
+struct pipeline_params {
+	char name[PIPELINE_NAME_SIZE];
+
+	struct pipeline_port_in_params port_in[PIPELINE_MAX_PORT_IN];
+	struct pipeline_port_out_params port_out[PIPELINE_MAX_PORT_OUT];
+	struct rte_ring *msgq_in[PIPELINE_MAX_MSGQ_IN];
+	struct rte_ring *msgq_out[PIPELINE_MAX_MSGQ_OUT];
+
+	uint32_t n_ports_in;
+	uint32_t n_ports_out;
+	uint32_t n_msgq;
+
+	int socket_id;
+
+	char *args_name[PIPELINE_MAX_ARGS];
+	char *args_value[PIPELINE_MAX_ARGS];
+	uint32_t n_args;
+};
+
+typedef void* (*pipeline_op_init)(struct pipeline_params *params, void *arg);
+
+typedef int (*pipeline_op_free)(void *pipeline);
+
+typedef int (*pipeline_op_run)(void *pipeline);
+
+typedef int (*pipeline_op_timer)(void *pipeline);
+
+typedef int (*pipeline_op_track)(void *pipeline, uint32_t port_in, uint32_t *port_out);
+
+struct pipeline_ops {
+	pipeline_op_init f_init;
+	pipeline_op_free f_free;
+	pipeline_op_run f_run;
+	pipeline_op_timer f_timer;
+	pipeline_op_track f_track;
+};
+
+#endif
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 02/11] ip_pipeline: added config checks
  2015-05-29 15:43 [PATCH 00/11] ip_pipeline: ip_pipeline application enhancements Maciej Gajdzica
  2015-05-29 15:43 ` [PATCH 01/11] ip_pipeline: add parsing for config files with new syntax Maciej Gajdzica
@ 2015-05-29 15:43 ` Maciej Gajdzica
  2015-05-29 15:43 ` [PATCH 03/11] ip_pipeline: modified init to match new params struct Maciej Gajdzica
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Maciej Gajdzica @ 2015-05-29 15:43 UTC (permalink / raw)
  To: dev

After loading configuration from a file, data integrity is checked.

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/Makefile       |    1 +
 examples/ip_pipeline/config_check.c |  617 +++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/main.c         |    2 +
 3 files changed, 620 insertions(+)
 create mode 100644 examples/ip_pipeline/config_check.c

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index 2f224cc..c893952 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -44,6 +44,7 @@ APP = ip_pipeline
 # all source are stored in SRCS-y
 SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) := main.c
 SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += config_parse.c
+SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += config_check.c
 #SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += init.c
 SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += cpu_core_map.c
 #SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += cmdline.c
diff --git a/examples/ip_pipeline/config_check.c b/examples/ip_pipeline/config_check.c
new file mode 100644
index 0000000..bf400f4
--- /dev/null
+++ b/examples/ip_pipeline/config_check.c
@@ -0,0 +1,617 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+
+#include "app.h"
+
+
+static uint32_t
+app_link_get_n_hwq_in(struct app_params *app, uint32_t link_id)
+{
+	uint32_t hwq_id_max = 0, i;
+
+	for (i = 0; i < APP_LINK_MAX_HWQ_IN; i++) {
+		struct app_pktq_hwq_in_params *p = &app->hwq_in_params[APP_HWQ_IN_IDX(link_id, i)];
+
+		if (APP_PARAM_VALID(p))
+			hwq_id_max++;
+	}
+
+	return hwq_id_max;
+}
+
+static uint32_t
+app_link_get_n_hwq_out(struct app_params *app, uint32_t link_id)
+{
+	uint32_t hwq_id_max = 0, i;
+
+	for (i = 0; i < APP_LINK_MAX_HWQ_OUT; i++) {
+		struct app_pktq_hwq_out_params *p = &app->hwq_out_params[link_id
+				* APP_LINK_MAX_HWQ_OUT + i];
+
+		if (APP_PARAM_VALID(p))
+			hwq_id_max++;
+	}
+
+	return hwq_id_max;
+}
+
+static uint32_t
+app_link_get_hwq_in_readers(uint32_t link_id, uint32_t hwq_id)
+{
+	uint32_t j, n;	
+	
+	for (n = 0, j = 0; j < APP_MAX_LINKS * APP_LINK_MAX_HWQ_IN; j++) {
+	
+		uint32_t linkId = j / APP_MAX_LINKS;
+		uint32_t q_id = j % APP_MAX_LINKS;
+		
+		if ((linkId == link_id) &&
+			(q_id == hwq_id))
+			
+			n++;
+	}
+	
+	return n;
+}
+
+static uint32_t
+app_link_get_hwq_out_writers(uint32_t link_id, uint32_t hwq_id)
+{
+	uint32_t j, n;		
+	
+	for (n = 0, j = 0; j < APP_MAX_LINKS * APP_LINK_MAX_HWQ_OUT; j++) {
+	
+		uint32_t linkId = j / APP_MAX_LINKS;
+		uint32_t q_id = j % APP_MAX_LINKS;
+		
+		if ((linkId == link_id) &&
+			(q_id == hwq_id))
+			
+			n++;
+	}
+
+	return n;
+}
+
+
+static uint32_t
+app_pipeline_hwq_in_get_n(struct app_params *app, uint32_t hwq_id)
+{
+	uint32_t i, j, n;
+	
+	for (n = 0, i = 0; i < app->n_pipelines; i++) {
+	
+		if (!APP_PARAM_VALID(&app->pipeline_params[i]))
+			continue;
+
+		for (j = 0; j < app->pipeline_params[i].n_pktq_in; j++) {
+		
+			if ((app->pipeline_params[i].pktq_in[j].type == APP_PKTQ_IN_HWQ) &&
+				(app->pipeline_params[i].pktq_in[j].id == hwq_id))
+				n++;
+		}
+	}
+	return n;
+}
+
+static uint32_t
+app_pipeline_hwq_out_get_n(struct app_params *app, uint32_t hwq_id)
+{
+	uint32_t i, j, n;
+	
+	for (n = 0, i = 0; i < app->n_pipelines; i++) {
+	
+		if (!APP_PARAM_VALID(&app->pipeline_params[i]))
+			continue;
+
+		for (j = 0; j < app->pipeline_params[i].n_pktq_out; j++) {
+		
+			if ((app->pipeline_params[i].pktq_out[j].type == APP_PKTQ_OUT_HWQ) &&
+				(app->pipeline_params[i].pktq_out[j].id == hwq_id))
+				n++;
+		}
+	}
+	return n;
+}
+
+
+static uint32_t
+app_swq_in_get_readers(struct app_params *app, uint32_t swq_id)
+{
+	uint32_t i, j, n;
+	
+	for (n = 0, i = 0; i < app->n_pipelines; i++) {
+		
+		if (!APP_PARAM_VALID(&app->pipeline_params[i]))
+			continue;
+		
+		for (j = 0; j < app->pipeline_params[i].n_pktq_in; j++) {
+		
+			if ((app->pipeline_params[i].pktq_in[j].type == APP_PKTQ_IN_SWQ) &&
+				(app->pipeline_params[i].pktq_in[j].id == swq_id))
+				n++;
+		}
+	}
+	return n;
+}
+
+static uint32_t
+app_swq_out_get_writers(struct app_params *app, uint32_t swq_id)
+{
+	uint32_t i, j, n;
+	
+	for (n = 0, i = 0; i < app->n_pipelines; i++) {
+		
+		if (!APP_PARAM_VALID(&app->pipeline_params[i]))
+			continue;
+		
+		for (j = 0; j < app->pipeline_params[i].n_pktq_out; j++) {
+		
+			if ((app->pipeline_params[i].pktq_out[j].type == APP_PKTQ_OUT_SWQ) &&
+				(app->pipeline_params[i].pktq_out[j].id == swq_id))
+				n++;
+		}
+	}
+	return n;
+}
+
+
+static uint32_t
+app_cpu_socket_count(void)
+{
+	uint32_t n_lcores = rte_lcore_count();
+	uint32_t lcore_id, cpu_socket_id_max = 0;
+	
+	for (lcore_id = 0; lcore_id < n_lcores; lcore_id++) {
+		uint32_t cpu_socket_id = rte_lcore_to_socket_id(lcore_id);
+		
+		if (cpu_socket_id > cpu_socket_id_max)
+			cpu_socket_id_max = cpu_socket_id;
+	}
+	return (cpu_socket_id_max + 1);
+}
+
+static uint32_t
+app_mempool_cpu_socket_id(uint32_t mempool_socket_id) {
+
+	uint32_t i,n;
+	uint32_t n_cpu_socket = app_cpu_socket_count();
+	
+	for (n=0, i = 0; i < n_cpu_socket; i++) {
+	
+		if(mempool_socket_id == i)
+		n++;
+	}
+	return n;
+}
+
+static uint32_t
+app_swq_cpu_socket_id(uint32_t swq_socket_id) {
+
+	uint32_t i,n;
+	uint32_t n_cpu_socket = app_cpu_socket_count();
+	
+	for (n=0, i = 0; i < n_cpu_socket; i++) {
+	
+		if(swq_socket_id == i)
+			n++;
+	}
+	return n;
+}
+
+static void
+check_mempools_params(struct app_params *app){
+
+	uint32_t i;
+	
+	/* Valid CPU socket ID */
+	for (i = 0; i < app->n_mempools; i++) {
+		struct app_mempool_params *mempool= &app->mempool_params[i];
+		uint32_t p = app_mempool_cpu_socket_id (mempool->cpu_socket_id);	
+		if (p == 0)
+		    rte_panic("Mempool %u is allocated on invalid CPU socket\n",
+				i);
+	}
+}
+
+static void
+check_port_mask(struct app_params *app)
+{
+	if (app->port_mask == 0)
+		rte_panic("There are no ports to use.\n");
+}
+
+#define CHECK_LINKS_PARAMS_QUEUE(queue, max) \
+		APP_CHECK(link->queue <= max, \
+		"Link %u: %s = %d out of defined queue range %d - %d", \
+			i, # queue, link->queue, 0, max)
+
+
+static void
+check_links_params(struct app_params *app) {
+
+	uint32_t i;
+	
+	for (i = 0; i< app->n_links; i++) {
+		struct app_link_params *link= &app->link_params[i];
+		uint32_t n_hwq_in;
+
+		if (!APP_PARAM_VALID(link))
+			continue;
+
+		/* link filter queues */
+		n_hwq_in = app_link_get_n_hwq_in(app, i);
+
+		if (n_hwq_in > 0) {
+			CHECK_LINKS_PARAMS_QUEUE(arp_q, n_hwq_in - 1);
+			CHECK_LINKS_PARAMS_QUEUE(ip_local_q, n_hwq_in - 1);
+			CHECK_LINKS_PARAMS_QUEUE(tcp_local_q, n_hwq_in - 1);
+			CHECK_LINKS_PARAMS_QUEUE(udp_local_q, n_hwq_in - 1);
+			CHECK_LINKS_PARAMS_QUEUE(sctp_local_q, n_hwq_in - 1);
+			CHECK_LINKS_PARAMS_QUEUE(arp_q, n_hwq_in - 1);
+		}
+	}
+
+}
+#undef CHECK_LINKS_PARAMS_QUEUE
+
+static void
+check_links_contiguous_id(struct app_params *app) {
+
+	uint32_t i = 0;
+	int status = 0;
+	
+	/* All link id contiguous */
+	for (i = 0; i< app->n_links; i++) {
+
+		struct app_link_params *link= &app->link_params[i];
+
+		if (status == 0) {
+			if (!APP_PARAM_VALID(link))
+				status = 1;
+		} else {
+			if (APP_PARAM_VALID(link))
+				rte_panic("Link %u isn't contiguous\n", i);
+		}
+	}
+}
+
+static void
+check_link_hwq_read_write(struct app_params *app) {
+
+	uint32_t i;
+	for (i = 0; i< app->n_links; i++) {
+		uint32_t n_hwq_in, n_hwq_out, j;
+
+		if (!APP_PARAM_VALID(&app->link_params[i]))
+			continue;
+
+		n_hwq_in = app_link_get_n_hwq_in(app, i);
+		n_hwq_out = app_link_get_n_hwq_out(app, i);
+
+		for (j = 0; j < n_hwq_in; j++) {
+			uint32_t p = app_link_get_hwq_in_readers(i, j);
+
+			if (p == 0)
+				rte_panic("Link %u: HWQ in %u has no reader\n",
+					i, j);
+			if (p > 1)
+				rte_panic("Link %u: HWQ in %u has more than "
+					"one reader\n", i, j);
+		}
+		for (j = 0; j < n_hwq_out; j++) {
+			uint32_t p = app_link_get_hwq_out_writers(i, j);
+
+			if (p == 0)
+				rte_panic("Link %u: HWQ in %u has no writer\n",
+					i, j);
+			if (p > 1)
+				rte_panic("Link %u: HWQ in %u has more than\n"
+					"one writer\n", i, j);
+		}
+	}
+}
+
+static void
+check_hwq_in_params(struct app_params *app){
+	
+	uint32_t i;
+	
+	for (i = 0; i< app->n_pktq_hwq_in; i++) {
+
+		if (!APP_PARAM_VALID(&app->hwq_in_params[i]))
+			continue;
+	
+		uint32_t memId= app->hwq_in_params[i].mempool_id;
+		
+		if(!APP_PARAM_VALID(&app->mempool_params[memId]))
+			rte_panic("HWQ in %u has invalid mempool ",
+					 i);
+					 
+		/* Size - power of 2. */
+		if((app->hwq_in_params[i].size <=0) && 
+		  (rte_is_power_of_2(app->hwq_in_params[i].size) == 0))
+			rte_panic("HWQ in %u has invalid size\n ",
+					 i);
+					 
+		/* Burst Size is than queue Size */
+		if((app->hwq_in_params[i].burst > app->hwq_in_params[i].size))
+			rte_panic("HWQ in %u has burst size greater than Queue Size\n",
+					 i);
+	}
+}
+static void
+check_hwq_in_contiguous_id(struct app_params *app)
+{
+	uint32_t i;
+	int status = 0;
+	
+	for (i = 0; i < app->n_pktq_hwq_in; i++) {
+
+		if (status == 0) {
+			if (!APP_PARAM_VALID(&app->hwq_in_params[i]))
+					status = 1;
+		} else {
+			if (APP_PARAM_VALID(&app->hwq_in_params[i]))
+				rte_panic("HWQ in %u is't not contiguous \n",
+						i);
+		}
+	}
+}
+static void
+check_hwq_in_pipeline(struct app_params *app)
+{
+	uint32_t i, n;
+
+	for (i = 0; i< app->n_pktq_hwq_in; i++) {
+		if (!APP_PARAM_VALID(&app->hwq_in_params[i]))
+			continue;
+
+		n =	app_pipeline_hwq_in_get_n(app, i);
+		if(n == 0)
+			rte_panic("HWQ in %u isn't consistent with pipeline entry\n",
+				   i);
+		if(n > 1)
+			rte_panic("HWQ in %u has more than one reader\n",
+				   i);
+	}
+}
+
+static void
+check_hwq_out_params(struct app_params *app){
+
+	uint32_t i;
+			
+	for (i = 0; i< app->n_pktq_hwq_out; i++) {
+
+		if (!APP_PARAM_VALID(&app->hwq_out_params[i]))
+			continue;
+	
+		/* HWQ Size - power of 2 */ 
+		if((app->hwq_out_params[i].size <= 0) && 
+			(rte_is_power_of_2(app->hwq_out_params[i].size) == 0))
+				rte_panic("HWQ out %u has invalid size ",
+						i);
+	
+		/* Burst Size is than queue Size  */
+		if(app->hwq_out_params[i].burst > app->hwq_out_params[i].size)
+				rte_panic("HWQ out %u has burst size greater than Queue Size ",
+						i);
+	}
+}
+
+static void
+check_hwq_out_contiguous_id(struct app_params *app)
+{
+	uint32_t i;
+	int status = 0;
+	
+	for (i = 0; i < app->n_pktq_hwq_out; i++) {
+
+		if (status == 0) {
+			if (!APP_PARAM_VALID(&app->hwq_out_params[i]))
+					status = 1;
+		} else {
+			if (APP_PARAM_VALID(&app->hwq_out_params[i]))
+				rte_panic("HWQ out %u is't not contiguous \n",
+						i);
+		}
+	}
+}
+
+static void
+check_hwq_out_pipeline(struct app_params *app)
+{
+	uint32_t i, n;
+	
+	for (i = 0; i< app->n_pktq_hwq_out; i++) {
+
+		if (!APP_PARAM_VALID(&app->hwq_out_params[i]))
+			continue;
+	
+		n =	app_pipeline_hwq_out_get_n(app, i);
+		if (n == 0)
+			rte_panic("HWQ out %u isn't consistent with pipeline entry ",
+				   i);
+		if (n > 1)
+			rte_panic("HWQ out %u has more than one writer ",
+				   i);	
+	}				   
+}
+
+static void
+check_swq_params(struct app_params *app){
+
+	uint32_t i;
+	
+	for (i = 0; i< app->n_pktq_swq; i++) {
+	
+		/* Check swq size - power of 2. */ 
+		if ((app->swq_params[i].size <= 0) ||
+			(rte_is_power_of_2(app->swq_params[i].size) == 0))
+			rte_panic("SWQ %u: has invalid size\n",
+					i);
+		
+		/* Burst Size is greater than queue Size */ 		
+		if ((app->swq_params[i].burst_read > app->swq_params[i].size))
+			rte_panic("SWQ %u: has burst read size greater than Queue Size\n",
+					i);
+		if ((app->swq_params[i].burst_write > app->swq_params[i].size))
+			rte_panic("SWQ %u: has burst write size greater than Queue Size\n",
+					i);
+				
+		/* CPU socket ID is valid */ 
+		struct app_pktq_swq_params *swq= &app->swq_params[i];
+		
+		uint32_t p = app_swq_cpu_socket_id (swq->cpu_socket_id);	
+		if (p == 0)
+			rte_panic("SWQ %u is allocated on invalid CPU socket\n",
+				i);
+	}			
+}
+
+static void
+check_swq_contiguous_id(struct app_params *app){
+
+	uint32_t i;
+	int status = 0;
+	
+	for (i = 0; i < app->n_pktq_swq; i++) {
+
+		if (status == 0) {
+			if (!APP_PARAM_VALID(&app->swq_params[i]))
+					status = 1;
+		} else {
+			if (APP_PARAM_VALID(&app->swq_params[i]))
+				rte_panic("SWQ %u is't not contiguous \n",
+						i);
+		}
+	}	
+}
+
+static void
+check_swq_read_write(struct app_params *app){
+
+	uint32_t i, n;
+	
+	for (i = 0; i< app->n_pktq_swq; i++) {
+		
+		/* Readers */
+		n = app_swq_in_get_readers(app, i);
+		
+		if (n == 0)
+			rte_panic("SWQ %u has no reader\n", i);
+		if (n > 1)
+			rte_panic("SWQ %u has more than one reader\n", i);
+	
+		/* Writers */
+		n = app_swq_out_get_writers(app, i);
+
+		if (n == 0)
+			rte_panic("SWQ %u has no writer\n", i);
+		if (n > 1)
+			rte_panic("SWQ %u has more than one writer\n", i);
+	}
+}
+
+static void
+check_tm_params(struct app_params *app){
+
+	uint32_t i;
+		
+	for (i = 0; i< app->n_pktq_tm; i++) {
+		uint32_t linkId;
+		sscanf(app->tm_params[i].name, "TM%u", &linkId);
+
+		if(!APP_PARAM_VALID(&app->link_params[linkId]))
+			rte_panic("TM %u index is not matching with link\n", i);
+	}
+}
+
+static void
+check_source_params(struct app_params *app){
+
+	uint32_t i;
+		
+	for (i = 0; i< app->n_pktq_source; i++) {
+	
+		uint32_t memId =app->source_params[i].mempool_id;
+		
+		if (!APP_PARAM_VALID(&app->mempool_params[memId]))
+			rte_panic("Source %u doesn't have valid mempool\n", i);
+	}
+}
+
+
+int
+app_config_check(struct app_params *app)
+{
+	/* Mempool */
+	check_mempools_params(app);
+	
+	/* NIC/Links */
+	check_port_mask(app);
+	
+	/* Links parameters  */
+	check_links_params(app);	
+	check_links_contiguous_id(app);
+	check_link_hwq_read_write(app);
+	
+	/* HWQ In */	
+	check_hwq_in_params(app);
+	check_hwq_in_contiguous_id(app);
+	check_hwq_in_pipeline(app);
+
+	/* HWQ Out */
+	check_hwq_out_params(app);
+	check_hwq_out_contiguous_id(app);
+	check_hwq_out_pipeline(app);
+	
+	/* SWQ Checks */
+	check_swq_params(app);	
+	check_swq_contiguous_id(app);	
+	check_swq_read_write(app);
+
+	/* TM Checks */
+	check_tm_params(app);
+	
+	/* Source Checks */
+	check_source_params(app);
+	
+		
+	return 0;
+}
+
+
diff --git a/examples/ip_pipeline/main.c b/examples/ip_pipeline/main.c
index a2d7ef0..612eea9 100644
--- a/examples/ip_pipeline/main.c
+++ b/examples/ip_pipeline/main.c
@@ -47,5 +47,7 @@ main(int argc, char **argv)
 
 	app_config_parse(&app, app.config_file);
 
+	app_config_check(&app);
+
 	return 0;
 }
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 03/11] ip_pipeline: modified init to match new params struct
  2015-05-29 15:43 [PATCH 00/11] ip_pipeline: ip_pipeline application enhancements Maciej Gajdzica
  2015-05-29 15:43 ` [PATCH 01/11] ip_pipeline: add parsing for config files with new syntax Maciej Gajdzica
  2015-05-29 15:43 ` [PATCH 02/11] ip_pipeline: added config checks Maciej Gajdzica
@ 2015-05-29 15:43 ` Maciej Gajdzica
  2015-05-29 15:43 ` [PATCH 04/11] ip_pipeline: moved pipelines to separate folder Maciej Gajdzica
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Maciej Gajdzica @ 2015-05-29 15:43 UTC (permalink / raw)
  To: dev

After changes in config parser, app params struct is changed and
requires modifications in initialization procedures.

Signed-off-by: Maciej Gajdzica <maciejx.t.gajdzica@intel.com>
---
 examples/ip_pipeline/Makefile |    2 +-
 examples/ip_pipeline/init.c   | 1498 +++++++++++++++++++++++++++++------------
 examples/ip_pipeline/main.c   |    3 +
 3 files changed, 1073 insertions(+), 430 deletions(-)

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index c893952..443f7e4 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -45,7 +45,7 @@ APP = ip_pipeline
 SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) := main.c
 SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += config_parse.c
 SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += config_check.c
-#SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += init.c
+SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += init.c
 SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += cpu_core_map.c
 #SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += cmdline.c
 #SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_rx.c
diff --git a/examples/ip_pipeline/init.c b/examples/ip_pipeline/init.c
index d79762f..77d5f07 100644
--- a/examples/ip_pipeline/init.c
+++ b/examples/ip_pipeline/init.c
@@ -1,7 +1,7 @@
 /*-
  *   BSD LICENSE
  *
- *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
  *   All rights reserved.
  *
  *   Redistribution and use in source and binary forms, with or without
@@ -32,561 +32,1201 @@
  */
 
 #include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <inttypes.h>
-#include <sys/types.h>
 #include <string.h>
-#include <sys/queue.h>
-#include <stdarg.h>
-#include <errno.h>
-#include <getopt.h>
-
-#include <rte_common.h>
-#include <rte_byteorder.h>
-#include <rte_log.h>
-#include <rte_memory.h>
-#include <rte_memcpy.h>
-#include <rte_memzone.h>
-#include <rte_eal.h>
-#include <rte_per_lcore.h>
-#include <rte_launch.h>
-#include <rte_atomic.h>
+
 #include <rte_cycles.h>
-#include <rte_prefetch.h>
-#include <rte_lcore.h>
-#include <rte_per_lcore.h>
-#include <rte_branch_prediction.h>
-#include <rte_interrupts.h>
-#include <rte_pci.h>
-#include <rte_random.h>
-#include <rte_debug.h>
-#include <rte_ether.h>
 #include <rte_ethdev.h>
-#include <rte_ring.h>
-#include <rte_mempool.h>
-#include <rte_malloc.h>
-#include <rte_mbuf.h>
-#include <rte_string_fns.h>
+#include <rte_ether.h>
 #include <rte_ip.h>
-#include <rte_tcp.h>
-#include <rte_lpm.h>
-#include <rte_lpm6.h>
-
-#include "main.h"
-
-#define NA                             APP_SWQ_INVALID
-
-struct app_params app = {
-	/* CPU cores */
-	.cores = {
-	{0, APP_CORE_MASTER, {15, 16, 17, NA, NA, NA, NA, NA},
-		{12, 13, 14, NA, NA, NA, NA, NA} },
-	{0, APP_CORE_RX,     {NA, NA, NA, NA, NA, NA, NA, 12},
-		{ 0,  1,  2,  3, NA, NA, NA, 15} },
-	{0, APP_CORE_FC,     { 0,  1,  2,  3, NA, NA, NA, 13},
-		{ 4,  5,  6,  7, NA, NA, NA, 16} },
-	{0, APP_CORE_RT,     { 4,  5,  6,  7, NA, NA, NA, 14},
-		{ 8,  9, 10, 11, NA, NA, NA, 17} },
-	{0, APP_CORE_TX,     { 8,  9, 10, 11, NA, NA, NA, NA},
-		{NA, NA, NA, NA, NA, NA, NA, NA} },
-	},
-
-	/* Ports*/
-	.n_ports = APP_MAX_PORTS,
-	.rsz_hwq_rx = 128,
-	.rsz_hwq_tx = 512,
-	.bsz_hwq_rd = 64,
-	.bsz_hwq_wr = 64,
-
-	.port_conf = {
-		.rxmode = {
-			.split_hdr_size = 0,
-			.header_split   = 0, /* Header Split disabled */
-			.hw_ip_checksum = 1, /* IP checksum offload enabled */
-			.hw_vlan_filter = 0, /* VLAN filtering disabled */
-			.jumbo_frame    = 1, /* Jumbo Frame Support enabled */
-			.max_rx_pkt_len = 9000, /* Jumbo Frame MAC pkt length */
-			.hw_strip_crc   = 0, /* CRC stripped by hardware */
-		},
-		.rx_adv_conf = {
-			.rss_conf = {
-				.rss_key = NULL,
-				.rss_hf = ETH_RSS_IP,
-			},
-		},
-		.txmode = {
-			.mq_mode = ETH_MQ_TX_NONE,
-		},
-	},
-
-	.rx_conf = {
-		.rx_thresh = {
-			.pthresh = 8,
-			.hthresh = 8,
-			.wthresh = 4,
-		},
-		.rx_free_thresh = 64,
-		.rx_drop_en = 0,
-	},
-
-	.tx_conf = {
-		.tx_thresh = {
-			.pthresh = 36,
-			.hthresh = 0,
-			.wthresh = 0,
-		},
-		.tx_free_thresh = 0,
-		.tx_rs_thresh = 0,
-	},
-
-	/* SWQs */
-	.rsz_swq = 128,
-	.bsz_swq_rd = 64,
-	.bsz_swq_wr = 64,
-
-	/* Buffer pool */
-	.pool_buffer_size = RTE_MBUF_DEFAULT_BUF_SIZE,
-	.pool_size = 32 * 1024,
-	.pool_cache_size = 256,
-
-	/* Message buffer pool */
-	.msg_pool_buffer_size = 256,
-	.msg_pool_size = 1024,
-	.msg_pool_cache_size = 64,
-
-	/* Rule tables */
-	.max_arp_rules = 1 << 10,
-	.max_firewall_rules = 1 << 5,
-	.max_routing_rules = 1 << 24,
-	.max_flow_rules = 1 << 24,
-
-	/* Application processing */
-	.ether_hdr_pop_push = 0,
-};
-
-struct app_core_params *
-app_get_core_params(uint32_t core_id)
+#include <rte_eal.h>
+#include <rte_malloc.h>
+
+#include "app.h"
+#include "pipeline.h"
+
+#define APP_NAME_SIZE	32
+
+static void
+app_init_core_map(struct app_params *app)
 {
+	RTE_LOG(INFO, USER1, "Creating CPU core map ...\n");
+	app->core_map = cpu_core_map_init(4, 32, 4, 0);
+
+	if (app->core_map == NULL)
+		rte_panic("Cannot create CPU core map\n");
+
+	cpu_core_map_print(app->core_map);
+}
+
+static void
+app_init_core_mask(struct app_params *app)
+{
+	uint64_t mask = 0;
 	uint32_t i;
 
-	for (i = 0; i < RTE_MAX_LCORE; i++) {
-		struct app_core_params *p = &app.cores[i];
+	for (i = 0; i < APP_MAX_PIPELINES; i++) {
+		struct app_pipeline_params *p = &app->pipeline_params[i];
+		int lcore_id;
 
-		if (p->core_id != core_id)
+		if (!APP_PARAM_VALID(&app->pipeline_params[i]))
 			continue;
 
-		return p;
+		lcore_id = cpu_core_map_get_lcore_id(app->core_map,
+			p->socket_id, p->core_id, p->hyper_th_id);
+
+		if (lcore_id < 0)
+			rte_panic("Cannot create CPU core mask\n");
+
+		mask |= 1LLU << lcore_id;
 	}
 
-	return NULL;
+	app->core_mask = mask;
+	RTE_LOG(INFO, USER1, "CPU core mask = 0x%016lx\n", app->core_mask);
 }
 
-static uint32_t
-app_get_n_swq_in(void)
+static void
+app_init_eal(struct app_params *app)
 {
-	uint32_t max_swq_id = 0, i, j;
+	char buffer[32];
+	int status;
+	app->eal_argc = 0;
 
-	for (i = 0; i < RTE_MAX_LCORE; i++) {
-		struct app_core_params *p = &app.cores[i];
+	app->eal_argv[app->eal_argc++] = strdup(app->app_name);
 
-		if (p->core_type == APP_CORE_NONE)
-			continue;
+	snprintf(buffer, sizeof(buffer), "-c %lx", app->core_mask);
+	app->eal_argv[app->eal_argc++] = strdup(buffer);
 
-		for (j = 0; j < APP_MAX_SWQ_PER_CORE; j++) {
-			uint32_t swq_id = p->swq_in[j];
+	snprintf(buffer, sizeof(buffer), "-n 4");
+	app->eal_argv[app->eal_argc++] = strdup(buffer);
 
-			if ((swq_id != APP_SWQ_INVALID) &&
-				(swq_id > max_swq_id))
-				max_swq_id = swq_id;
-		}
-	}
+	snprintf(buffer, sizeof(buffer), "--");
+	app->eal_argv[app->eal_argc++] = strdup(buffer);
 
-	return (1 + max_swq_id);
+	status = rte_eal_init(app->eal_argc, app->eal_argv);
+	if (status < 0)
+		rte_panic("EAL init error\n");
 }
 
-static uint32_t
-app_get_n_swq_out(void)
+static void
+app_init_mempool(struct app_params *app)
 {
-	uint32_t max_swq_id = 0, i, j;
+	int i;
 
-	for (i = 0; i < RTE_MAX_LCORE; i++) {
-		struct app_core_params *p = &app.cores[i];
+	for (i = 0; i < APP_MAX_MEMPOOLS; i++) {
+		struct app_mempool_params *p = &app->mempool_params[i];
 
-		if (p->core_type == APP_CORE_NONE)
+		if (!APP_PARAM_VALID(p))
 			continue;
 
-		for (j = 0; j < APP_MAX_SWQ_PER_CORE; j++) {
-			uint32_t swq_id = p->swq_out[j];
-
-			if ((swq_id != APP_SWQ_INVALID) &&
-				(swq_id > max_swq_id))
-				max_swq_id = swq_id;
-		}
+		RTE_LOG(INFO, USER1, "Creating %s ...\n", p->name);
+		app->mempool[i] = rte_mempool_create(
+				p->name,
+				p->pool_size,
+				p->buffer_size,
+				p->cache_size,
+				sizeof(struct rte_pktmbuf_pool_private),
+				rte_pktmbuf_pool_init, NULL,
+				rte_pktmbuf_init, NULL,
+				p->cpu_socket_id,
+				0);
+
+		if (app->mempool[i] == NULL)
+			rte_panic("Cannot create mempool\n");
 	}
+}
 
-	return (1 + max_swq_id);
+static inline int
+app_link_filter_arp_add(struct app_link_params *link)
+{
+	struct rte_eth_ethertype_filter filter = {
+			.ether_type = ETHER_TYPE_ARP,
+			.flags = 0,
+			.queue = link->arp_q,
+	};
+
+	return rte_eth_dev_filter_ctrl(link->pmd_id, RTE_ETH_FILTER_ETHERTYPE,
+			RTE_ETH_FILTER_ADD, &filter);
 }
 
-static uint32_t
-app_get_swq_in_count(uint32_t swq_id)
+static inline int
+app_link_filter_arp_del(struct app_link_params *link)
 {
-	uint32_t n, i;
+	struct rte_eth_ethertype_filter filter = {
+			.ether_type = ETHER_TYPE_ARP,
+			.flags = 0,
+			.queue = link->arp_q,
+	};
+
+	return rte_eth_dev_filter_ctrl(link->pmd_id, RTE_ETH_FILTER_ETHERTYPE,
+			RTE_ETH_FILTER_DELETE, &filter);
+}
 
-	for (n = 0, i = 0; i < RTE_MAX_LCORE; i++) {
-		struct app_core_params *p = &app.cores[i];
-		uint32_t j;
+static inline int
+app_link_filter_tcp_syn_add(struct app_link_params *link)
+{
+	struct rte_eth_syn_filter filter = {
+			.hig_pri = 1,
+			.queue = link->tcp_syn_local_q,
+	};
 
-		if (p->core_type == APP_CORE_NONE)
-			continue;
+	return rte_eth_dev_filter_ctrl(link->pmd_id, RTE_ETH_FILTER_SYN,
+			RTE_ETH_FILTER_ADD, &filter);
+}
 
-		for (j = 0; j < APP_MAX_SWQ_PER_CORE; j++)
-			if (p->swq_in[j] == swq_id)
-				n++;
-	}
+static inline int
+app_link_filter_tcp_syn_del(struct app_link_params *link)
+{
+	struct rte_eth_syn_filter filter = {
+			.hig_pri = 1,
+			.queue = link->tcp_syn_local_q,
+	};
 
-	return n;
+	return rte_eth_dev_filter_ctrl(link->pmd_id, RTE_ETH_FILTER_SYN,
+			RTE_ETH_FILTER_DELETE, &filter);
 }
 
-static uint32_t
-app_get_swq_out_count(uint32_t swq_id)
+static inline int
+app_link_filter_ip_add(struct app_link_params *l1, struct app_link_params *l2)
 {
-	uint32_t n, i;
+	struct rte_eth_ntuple_filter filter = {
+			.flags = RTE_5TUPLE_FLAGS,
+			.dst_ip = rte_bswap32(l2->ip),
+			.dst_ip_mask = 0, /* Enable */
+			.src_ip = 0,
+			.src_ip_mask = 1, /* Disable */
+			.dst_port = 0,
+			.dst_port_mask = 1, /* Disable */
+			.src_port = 0,
+			.src_port_mask = 1, /* Disable */
+			.proto = 0,
+			.proto_mask = 1, /* Disable */
+			.tcp_flags = 0,
+			.priority = 1, /* Lowest */
+			.queue = l1->ip_local_q,
+	};
+
+	return rte_eth_dev_filter_ctrl(l1->pmd_id, RTE_ETH_FILTER_NTUPLE,
+			RTE_ETH_FILTER_ADD, &filter);
+}
 
-	for (n = 0, i = 0; i < RTE_MAX_LCORE; i++) {
-		struct app_core_params *p = &app.cores[i];
-		uint32_t j;
+static inline int
+app_link_filter_ip_del(struct app_link_params *l1, struct app_link_params *l2)
+{
+	struct rte_eth_ntuple_filter filter = {
+			.flags = RTE_5TUPLE_FLAGS,
+			.dst_ip = rte_bswap32(l2->ip),
+			.dst_ip_mask = 0, /* Enable */
+			.src_ip = 0,
+			.src_ip_mask = 1, /* Disable */
+			.dst_port = 0,
+			.dst_port_mask = 1, /* Disable */
+			.src_port = 0,
+			.src_port_mask = 1, /* Disable */
+			.proto = 0,
+			.proto_mask = 1, /* Disable */
+			.tcp_flags = 0,
+			.priority = 1, /* Lowest */
+			.queue = l1->ip_local_q,
+	};
+
+	return rte_eth_dev_filter_ctrl(l1->pmd_id, RTE_ETH_FILTER_NTUPLE,
+			RTE_ETH_FILTER_DELETE, &filter);
+}
 
-		if (p->core_type == APP_CORE_NONE)
-			continue;
+static inline int
+app_link_filter_tcp_add(struct app_link_params *l1, struct app_link_params *l2)
+{
+	struct rte_eth_ntuple_filter filter = {
+			.flags = RTE_5TUPLE_FLAGS,
+			.dst_ip = rte_bswap32(l2->ip),
+			.dst_ip_mask = 0, /* Enable */
+			.src_ip = 0,
+			.src_ip_mask = 1, /* Disable */
+			.dst_port = 0,
+			.dst_port_mask = 1, /* Disable */
+			.src_port = 0,
+			.src_port_mask = 1, /* Disable */
+			.proto = IPPROTO_TCP,
+			.proto_mask = 0, /* Enable */
+			.tcp_flags = 0,
+			.priority = 2, /* Higher priority than IP */
+			.queue = l1->tcp_local_q,
+	};
+
+	return rte_eth_dev_filter_ctrl(l1->pmd_id, RTE_ETH_FILTER_NTUPLE,
+			RTE_ETH_FILTER_ADD, &filter);
+}
 
-		for (j = 0; j < APP_MAX_SWQ_PER_CORE; j++)
-			if (p->swq_out[j] == swq_id)
-				n++;
-	}
+static inline int
+app_link_filter_tcp_del(struct app_link_params *l1, struct app_link_params *l2)
+{
+	struct rte_eth_ntuple_filter filter = {
+			.flags = RTE_5TUPLE_FLAGS,
+			.dst_ip = rte_bswap32(l2->ip),
+			.dst_ip_mask = 0, /* Enable */
+			.src_ip = 0,
+			.src_ip_mask = 1, /* Disable */
+			.dst_port = 0,
+			.dst_port_mask = 1, /* Disable */
+			.src_port = 0,
+			.src_port_mask = 1, /* Disable */
+			.proto = IPPROTO_TCP,
+			.proto_mask = 0, /* Enable */
+			.tcp_flags = 0,
+			.priority = 2, /* Higher priority than IP */
+			.queue = l1->tcp_local_q,
+	};
+
+	return rte_eth_dev_filter_ctrl(l1->pmd_id, RTE_ETH_FILTER_NTUPLE,
+			RTE_ETH_FILTER_DELETE, &filter);
+}
 
-	return n;
+static inline int
+app_link_filter_udp_add(struct app_link_params *l1, struct app_link_params *l2)
+{
+	struct rte_eth_ntuple_filter filter = {
+			.flags = RTE_5TUPLE_FLAGS,
+			.dst_ip = rte_bswap32(l2->ip),
+			.dst_ip_mask = 0, /* Enable */
+			.src_ip = 0,
+			.src_ip_mask = 1, /* Disable */
+			.dst_port = 0,
+			.dst_port_mask = 1, /* Disable */
+			.src_port = 0,
+			.src_port_mask = 1, /* Disable */
+			.proto = IPPROTO_UDP,
+			.proto_mask = 0, /* Enable */
+			.tcp_flags = 0,
+			.priority = 2, /* Higher priority than IP */
+			.queue = l1->udp_local_q,
+	};
+
+	return rte_eth_dev_filter_ctrl(l1->pmd_id, RTE_ETH_FILTER_NTUPLE,
+			RTE_ETH_FILTER_ADD, &filter);
+}
+
+static inline int
+app_link_filter_udp_del(struct app_link_params *l1, struct app_link_params *l2)
+{
+	struct rte_eth_ntuple_filter filter = {
+			.flags = RTE_5TUPLE_FLAGS,
+			.dst_ip = rte_bswap32(l2->ip),
+			.dst_ip_mask = 0, /* Enable */
+			.src_ip = 0,
+			.src_ip_mask = 1, /* Disable */
+			.dst_port = 0,
+			.dst_port_mask = 1, /* Disable */
+			.src_port = 0,
+			.src_port_mask = 1, /* Disable */
+			.proto = IPPROTO_UDP,
+			.proto_mask = 0, /* Enable */
+			.tcp_flags = 0,
+			.priority = 2, /* Higher priority than IP */
+			.queue = l1->udp_local_q,
+	};
+
+	return rte_eth_dev_filter_ctrl(l1->pmd_id, RTE_ETH_FILTER_NTUPLE,
+			RTE_ETH_FILTER_DELETE, &filter);
+}
+
+static inline int
+app_link_filter_sctp_add(struct app_link_params *l1, struct app_link_params *l2)
+{
+	struct rte_eth_ntuple_filter filter = {
+			.flags = RTE_5TUPLE_FLAGS,
+			.dst_ip = rte_bswap32(l2->ip),
+			.dst_ip_mask = 0, /* Enable */
+			.src_ip = 0,
+			.src_ip_mask = 1, /* Disable */
+			.dst_port = 0,
+			.dst_port_mask = 1, /* Disable */
+			.src_port = 0,
+			.src_port_mask = 1, /* Disable */
+			.proto = IPPROTO_SCTP,
+			.proto_mask = 0, /* Enable */
+			.tcp_flags = 0,
+			.priority = 2, /* Higher priority than IP */
+			.queue = l1->sctp_local_q,
+	};
+
+	return rte_eth_dev_filter_ctrl(l1->pmd_id, RTE_ETH_FILTER_NTUPLE,
+			RTE_ETH_FILTER_ADD, &filter);
+}
+
+static inline int
+app_link_filter_sctp_del(struct app_link_params *l1, struct app_link_params *l2)
+{
+	struct rte_eth_ntuple_filter filter = {
+			.flags = RTE_5TUPLE_FLAGS,
+			.dst_ip = rte_bswap32(l2->ip),
+			.dst_ip_mask = 0, /* Enable */
+			.src_ip = 0,
+			.src_ip_mask = 1, /* Disable */
+			.dst_port = 0,
+			.dst_port_mask = 1, /* Disable */
+			.src_port = 0,
+			.src_port_mask = 1, /* Disable */
+			.proto = IPPROTO_SCTP,
+			.proto_mask = 0, /* Enable */
+			.tcp_flags = 0,
+			.priority = 2, /* Higher priority than IP */
+			.queue = l1->sctp_local_q,
+	};
+
+	return rte_eth_dev_filter_ctrl(l1->pmd_id, RTE_ETH_FILTER_NTUPLE,
+			RTE_ETH_FILTER_DELETE, &filter);
 }
 
 void
-app_check_core_params(void)
+app_link_up_internal(struct app_params *app, struct app_link_params *cp)
 {
-	uint32_t n_swq_in = app_get_n_swq_in();
-	uint32_t n_swq_out = app_get_n_swq_out();
-	uint32_t i;
+	int status;
+	uint32_t link_id, i;
+
+	sscanf(cp->name, "LINK%u", &link_id);
+
+	/* Mark port as UP */
+	cp->state = 1;
 
-	/* Check that range of SW queues is contiguous and each SW queue has
-	   exactly one reader and one writer */
-	if (n_swq_in != n_swq_out)
-		rte_panic("Number of input SW queues is not equal to the "
-			"number of output SW queues\n");
+	/* Start port */
+	status = rte_eth_dev_start(cp->pmd_id);
+	if (status < 0)
+		rte_panic("Cannot start LINK%u (%u) (error %d)\n",
+			link_id, cp->pmd_id, status);
 
-	for (i = 0; i < n_swq_in; i++) {
-		uint32_t n = app_get_swq_in_count(i);
+	/* Apply ARP filter for current port */
+	if (cp->arp_q != 0) {
+		status = app_link_filter_arp_add(cp);
 
-		if (n == 0)
-			rte_panic("SW queue %u has no reader\n", i);
+		RTE_LOG(INFO, USER1, "LINK%u (%u): Adding ARP filter "
+			"(queue = %u)\n",
+			link_id, cp->pmd_id, cp->arp_q);
 
-		if (n > 1)
-			rte_panic("SW queue %u has more than one reader\n", i);
+		if (status)
+			rte_panic("LINK%u (%u): Error while adding ARP filter "
+				"(queue = %u) (%d)\n",
+				link_id, cp->pmd_id, cp->arp_q, status);
 	}
 
-	for (i = 0; i < n_swq_out; i++) {
-		uint32_t n = app_get_swq_out_count(i);
+	/* Apply TCP SYN filter for current port */
+	if (cp->tcp_syn_local_q != 0) {
+		status = app_link_filter_tcp_syn_add(cp);
 
-		if (n == 0)
-			rte_panic("SW queue %u has no writer\n", i);
+		RTE_LOG(INFO, USER1, "Port %u (%u): Adding TCP SYN filter "
+			"(queue = %u)\n",
+			link_id, cp->pmd_id, cp->tcp_syn_local_q);
 
-		if (n > 1)
-			rte_panic("SW queue %u has more than one writer\n", i);
+		if (status)
+			rte_panic("Port %u (%u): Error while adding TCP SYN filter "
+				"(queue = %u) (%d)\n",
+				link_id, cp->pmd_id, cp->tcp_syn_local_q, status);
 	}
 
-	/* Check the request and response queues are valid */
-	for (i = 0; i < RTE_MAX_LCORE; i++) {
-		struct app_core_params *p = &app.cores[i];
-		uint32_t ring_id_req, ring_id_resp;
+	/* For each port that is currently UP, add filters for current port */
+	if (cp->ip != 0) {
+		for (i = 0; i < APP_MAX_LINKS; i++) {
+			struct app_link_params *p = &app->link_params[i];
+
+			if (!APP_PARAM_VALID(p))
+				continue;
+
+			/* Skip ports that are DOWN */
+			if (p->state == 0) {
+				continue;
+			}
+
+			/* IP */
+			if (p->ip_local_q != 0) {
+				status = app_link_filter_ip_add(p, cp);
+
+				RTE_LOG(INFO, USER1, "LINK%u (%u): Adding IP filter "
+					"(queue= %u, IP = 0x%08x)\n",
+					i, p->pmd_id, p->ip_local_q, cp->ip);
+
+				if (status)
+					rte_panic("LINK%u (%u): Error while adding IP filter "
+						"(queue= %u, IP = 0x%08x) (%d)\n",
+						i, p->pmd_id, p->ip_local_q, cp->ip, status);
+			}
+
+			/* TCP */
+			if (p->tcp_local_q != 0) {
+				status = app_link_filter_tcp_add(p, cp);
+
+				RTE_LOG(INFO, USER1, "LINK%u (%u): Adding TCP filter "
+					"(queue = %u, IP = 0x%08x)\n",
+					i, p->pmd_id, p->tcp_local_q, cp->ip);
+
+				if (status)
+					rte_panic("LINK%u (%u): Error while adding TCP filter "
+						"(queue = %u, IP = 0x%08x) (%d)\n",
+						i, p->pmd_id, p->tcp_local_q, cp->ip, status);
+			}
+
+			/* UDP */
+			if (p->udp_local_q != 0) {
+				status = app_link_filter_udp_add(p, cp);
+
+				RTE_LOG(INFO, USER1, "LINK%u (%u): Adding UDP filter "
+					"(queue = %u, IP = 0x%08x)\n",
+					i, p->pmd_id, p->udp_local_q, cp->ip);
+
+				if (status)
+					rte_panic("LINK%u (%u): Error while adding UDP filter "
+						"(queue = %u, IP = 0x%08x) (%d)\n",
+						i, p->pmd_id, p->udp_local_q, cp->ip, status);
+			}
+
+			/* SCTP */
+			if (p->sctp_local_q != 0) {
+				status = app_link_filter_sctp_add(p, cp);
+
+				RTE_LOG(INFO, USER1, "LINK%u (%u): Adding SCTP filter "
+					"(queue = %u, IP = 0x%08x)\n",
+					i, p->pmd_id, p->sctp_local_q, cp->ip);
+
+				if (status)
+					rte_panic("LINK%u (%u): Error while adding SCTP filter "
+						"(queue = %u, IP = 0x%08x) (%d)\n",
+						i, p->pmd_id, p->sctp_local_q, cp->ip, status);
+			}
+		}
+	}
+
+	/* For current port, add filters for each port that is UP */
+	for (i = 0; i < APP_MAX_LINKS; i++) {
+		struct app_link_params *p = &app->link_params[i];
+		int status;
+
+		if (!APP_PARAM_VALID(p))
+			continue;
 
-		if ((p->core_type != APP_CORE_FC) &&
-		    (p->core_type != APP_CORE_FW) &&
-			(p->core_type != APP_CORE_RT)) {
+		/* Skip current port and ports that are DOWN */
+		if ((i == link_id) || (p->state == 0) || (p->ip == 0)) {
 			continue;
 		}
 
-		ring_id_req = p->swq_in[APP_SWQ_IN_REQ];
-		if (ring_id_req == APP_SWQ_INVALID)
-			rte_panic("Core %u of type %u has invalid request "
-				"queue ID\n", p->core_id, p->core_type);
+		/* IP */
+		if (cp->ip_local_q != 0) {
+			status = app_link_filter_ip_add(cp, p);
 
-		ring_id_resp = p->swq_out[APP_SWQ_OUT_RESP];
-		if (ring_id_resp == APP_SWQ_INVALID)
-			rte_panic("Core %u of type %u has invalid response "
-				"queue ID\n", p->core_id, p->core_type);
-	}
+			RTE_LOG(INFO, USER1, "LINK%u (%u): Adding IP filter "
+				"(queue= %u, IP = 0x%08x)\n",
+				link_id, cp->pmd_id, cp->ip_local_q, p->ip);
 
-	return;
-}
+			if (status)
+				rte_panic("LINK%u (%u): Error while adding IP filter "
+					"(queue= %u, IP = 0x%08x) (%d)\n",
+					link_id, cp->pmd_id, cp->ip_local_q, p->ip, status);
+		}
 
-uint32_t
-app_get_first_core_id(enum app_core_type core_type)
-{
-	uint32_t i;
+		/* TCP */
+		if (cp->tcp_local_q != 0) {
+			status = app_link_filter_tcp_add(cp, p);
 
-	for (i = 0; i < RTE_MAX_LCORE; i++) {
-		struct app_core_params *p = &app.cores[i];
+			RTE_LOG(INFO, USER1, "LINK%u (%u): Adding TCP filter "
+				"(queue = %u, IP = 0x%08x)\n",
+				link_id, cp->pmd_id, cp->tcp_local_q, p->ip);
 
-		if (p->core_type == core_type)
-			return p->core_id;
-	}
+			if (status)
+				rte_panic("LINK%u (%u): Error while adding TCP filter "
+					"(queue = %u, IP = 0x%08x) (%d)\n",
+					link_id, cp->pmd_id, cp->tcp_local_q, p->ip, status);
+		}
 
-	return RTE_MAX_LCORE;
-}
+		/* UDP */
+		if (cp->udp_local_q != 0) {
+			status = app_link_filter_udp_add(cp, p);
 
-struct rte_ring *
-app_get_ring_req(uint32_t core_id)
-{
-	struct app_core_params *p = app_get_core_params(core_id);
-	uint32_t ring_req_id = p->swq_in[APP_SWQ_IN_REQ];
+			RTE_LOG(INFO, USER1, "LINK%u (%u): Adding UDP filter "
+				"(queue = %u, IP = 0x%08x)\n",
+				link_id, cp->pmd_id, cp->udp_local_q, p->ip);
+
+			if (status)
+				rte_panic("LINK%u (%u): Error while adding UDP filter "
+					"(queue = %u, IP = 0x%08x) (%d)\n",
+					link_id, cp->pmd_id, cp->udp_local_q, p->ip, status);
+		}
+
+		/* SCTP */
+		if (cp->sctp_local_q != 0) {
+			status = app_link_filter_sctp_add(cp, p);
 
-	return app.rings[ring_req_id];
+			RTE_LOG(INFO, USER1, "LINK%u (%u): Adding SCTP filter "
+				"(queue = %u, IP = 0x%08x)\n",
+				link_id, cp->pmd_id, cp->sctp_local_q, p->ip);
+
+			if (status)
+				rte_panic("LINK%u (%u): Error while adding SCTP filter "
+					"(queue = %u, IP = 0x%08x) (%d)\n",
+					link_id, cp->pmd_id, cp->sctp_local_q, p->ip, status);
+		}
+	}
 }
 
-struct rte_ring *
-app_get_ring_resp(uint32_t core_id)
+void
+app_link_down_internal(struct app_params *app, struct app_link_params *cp)
 {
-	struct app_core_params *p = app_get_core_params(core_id);
-	uint32_t ring_resp_id = p->swq_out[APP_SWQ_OUT_RESP];
+	uint32_t link_id, i;
+	int status;
+
+	sscanf(cp->name, "LINK%u", &link_id);
+
+	/* Mark link_id as DOWN */
+	cp->state = 0;
+
+	/* Stop link_id */
+	rte_eth_dev_stop(cp->pmd_id);
+
+	/* Return if IP of current link_id is not valid */
+	if (cp->ip == 0)
+		return;
+
+	/* For each link_id that is currently UP, remove filters for current port */
+	for (i = 0; i < APP_MAX_LINKS; i ++) {
+		struct app_link_params *p = &app->link_params[i];
+
+		if (!APP_PARAM_VALID(p))
+			continue;
+
+		/* Skip ports that are down */
+		if (p->state == 0) {
+			continue;
+		}
+
+		/* IP */
+		if (p->ip_local_q != 0) {
+			status = app_link_filter_ip_del(p, cp);
+
+			RTE_LOG(INFO, USER1, "LINK%u (%u): Deleting IP filter "
+				"(queue = %u)\n",
+				i, p->pmd_id, p->ip_local_q);
+
+			if (status)
+				rte_panic("LINK%u (%u): Error while deleting IP filter "
+					"(queue = %u) (%d)\n",
+					i, p->pmd_id, p->ip_local_q, status);
+		}
+
+		/* TCP */
+		if (p->tcp_local_q != 0) {
+			status = app_link_filter_tcp_del(p, cp);
+
+			RTE_LOG(INFO, USER1, "LINK%u (%u): Deleting TCP filter "
+				"(queue = %u)\n",
+				i, p->pmd_id, p->tcp_local_q);
+
+			if (status)
+				rte_panic("LINK%u (%u): Error while deleting TCP filter "
+					"(queue = %u) (%d)\n",
+					i, p->pmd_id, p->tcp_local_q, status);
+		}
+
+		/* UDP */
+		if (p->udp_local_q != 0) {
+			status = app_link_filter_udp_del(p, cp);
+
+			RTE_LOG(INFO, USER1, "LINK%u (%u): Deleting UDP filter "
+				"(queue = %u)\n",
+				i, p->pmd_id, p->udp_local_q);
 
-	return app.rings[ring_resp_id];
+			if (status)
+				rte_panic("LINK%u (%u): Error while deleting UDP filter "
+					"(queue = %u) (%d)\n",
+					i, p->pmd_id, p->udp_local_q, status);
+		}
+
+		/* SCTP */
+		if (p->sctp_local_q != 0) {
+			status = app_link_filter_sctp_del(p, cp);
+
+			RTE_LOG(INFO, USER1, "LINK%u (%u): Deleting SCTP filter "
+				"(queue = %u)\n",
+				i, p->pmd_id, p->sctp_local_q);
+
+			if (status)
+				rte_panic("LINK%u (%u): Error while deleting SCTP filter "
+					"(queue = %u) (%d)\n",
+					i, p->pmd_id, p->sctp_local_q, status);
+		}
+	}
 }
 
 static void
-app_init_mbuf_pools(void)
+app_check_link(struct app_params *app)
 {
-	/* Init the buffer pool */
-	RTE_LOG(INFO, USER1, "Creating the mbuf pool ...\n");
-	app.pool = rte_pktmbuf_pool_create("mempool", app.pool_size,
-		app.pool_cache_size, 0, app.pool_buffer_size, rte_socket_id());
-	if (app.pool == NULL)
-		rte_panic("Cannot create mbuf pool\n");
-
-	/* Init the indirect buffer pool */
-	RTE_LOG(INFO, USER1, "Creating the indirect mbuf pool ...\n");
-	app.indirect_pool = rte_pktmbuf_pool_create("indirect mempool",
-		app.pool_size, app.pool_cache_size,
-		sizeof(struct app_pkt_metadata), 0, rte_socket_id());
-	if (app.indirect_pool == NULL)
-		rte_panic("Cannot create mbuf pool\n");
-
-	/* Init the message buffer pool */
-	RTE_LOG(INFO, USER1, "Creating the message pool ...\n");
-	app.msg_pool = rte_mempool_create(
-		"mempool msg",
-		app.msg_pool_size,
-		app.msg_pool_buffer_size,
-		app.msg_pool_cache_size,
-		0,
-		NULL, NULL,
-		rte_ctrlmbuf_init, NULL,
-		rte_socket_id(),
-		0);
-	if (app.msg_pool == NULL)
-		rte_panic("Cannot create message pool\n");
+	uint32_t all_links_up, i;
+
+	all_links_up = 1;
+
+	for (i = 0; i < APP_MAX_LINKS; i++) {
+		struct rte_eth_link link_params;
+		uint32_t link;
+
+		if (!APP_PARAM_VALID(&app->link_params[i]))
+			continue;
+
+		link = app->link_params[i].pmd_id;
+		memset(&link_params, 0, sizeof(link_params));
+		rte_eth_link_get(link, &link_params);
+		RTE_LOG(INFO, USER1, "LINK%u (%u) (%u Gbps) %s\n",
+			i,
+			link,
+			link_params.link_speed / 1000,
+			link_params.link_status ? "UP" : "DOWN");
+
+		if (link_params.link_status == 0)
+			all_links_up = 0;
+	}
+
+	if (all_links_up == 0)
+		rte_panic("Some NIC ports are DOWN\n");
 }
 
 static void
-app_init_rings(void)
+app_init_link(struct app_params *app)
 {
-	uint32_t n_swq, i;
+	uint32_t i;
 
-	n_swq = app_get_n_swq_in();
-	RTE_LOG(INFO, USER1, "Initializing %u SW rings ...\n", n_swq);
+	for (i = 0; i < APP_MAX_LINKS; i++) {
+		struct app_link_params *p_link = &app->link_params[i];
+		uint32_t link_id, n_hwq_in ,n_hwq_out;
+		int ret, j;
 
-	app.rings = rte_malloc_socket(NULL, n_swq * sizeof(struct rte_ring *),
-		RTE_CACHE_LINE_SIZE, rte_socket_id());
-	if (app.rings == NULL)
-		rte_panic("Cannot allocate memory to store ring pointers\n");
+		if (!APP_PARAM_VALID(p_link))
+			continue;
 
-	for (i = 0; i < n_swq; i++) {
-		struct rte_ring *ring;
-		char name[32];
+		sscanf(p_link->name, "LINK%u", &link_id);
+		n_hwq_in = app_n_hwq_in_get(app, link_id);
+		n_hwq_out = app_n_hwq_out_get(app, link_id);
 
-		snprintf(name, sizeof(name), "app_ring_%u", i);
+		RTE_LOG(INFO, USER1, "Initializing %s (%u) "
+			"(%u RXQ, %u TXQ) ...\n",
+			p_link->name,
+			p_link->pmd_id,
+			n_hwq_in,
+			n_hwq_out);
 
-		ring = rte_ring_create(
-			name,
-			app.rsz_swq,
-			rte_socket_id(),
-			RING_F_SP_ENQ | RING_F_SC_DEQ);
+		/* LINK */
+		ret = rte_eth_dev_configure(
+			p_link->pmd_id,
+			n_hwq_in,
+			n_hwq_out,
+			&p_link->conf);
+		if (ret < 0)
+			rte_panic("%s (%d): init error (%d)\n",
+				p_link->name, p_link->pmd_id, ret);
+
+		rte_eth_macaddr_get(p_link->pmd_id,
+			(struct ether_addr *) &p_link->mac_addr);
+
+		if (p_link->promisc)
+			rte_eth_promiscuous_enable(p_link->pmd_id);
+
+		/* RXQ */
+		for (j = 0; j < APP_MAX_HWQ_IN; j++) {
+			struct app_pktq_hwq_in_params *p_rxq = &app->hwq_in_params[j];
+			uint32_t rxq_link_id, rxq_queue_id;
+
+			if (!APP_PARAM_VALID(p_rxq))
+				continue;
+
+			sscanf(p_rxq->name, "RXQ%u.%u",
+				&rxq_link_id, &rxq_queue_id);
+			if (rxq_link_id != link_id)
+				continue;
+
+			ret = rte_eth_rx_queue_setup(
+				p_link->pmd_id,
+				rxq_queue_id,
+				p_rxq->size,
+				rte_eth_dev_socket_id(p_link->pmd_id),
+				&p_rxq->conf,
+				app->mempool[p_rxq->mempool_id]);
+			if (ret < 0)
+				rte_panic("%s (%u): %s init error (%d)\n",
+					p_link->name,
+					p_link->pmd_id,
+					p_rxq->name,
+					ret);
+		}
 
-		if (ring == NULL)
-			rte_panic("Cannot create ring %u\n", i);
+		/* TXQ */
+		for (j = 0; j < APP_MAX_HWQ_OUT; j++) {
+			struct app_pktq_hwq_out_params *p_txq = &app->hwq_out_params[j];
+			uint32_t txq_link_id, txq_queue_id;
+
+			if (!APP_PARAM_VALID(p_txq))
+				continue;
+
+			sscanf(p_txq->name, "TXQ%u.%u",
+				&txq_link_id, &txq_queue_id);
+			if (txq_link_id != link_id)
+				continue;
+
+			ret = rte_eth_tx_queue_setup(
+				p_link->pmd_id,
+				txq_queue_id,
+				p_txq->size,
+				rte_eth_dev_socket_id(p_link->pmd_id),
+				&p_txq->conf);
+			if (ret < 0)
+				rte_panic("%s (%u): %s init error (%d)\n",
+					p_link->name,
+					p_link->pmd_id,
+					p_txq->name,
+					ret);
+		}
 
-		app.rings[i] = ring;
+		/* LINK UP */
+		app_link_up_internal(app, p_link);
 	}
+
+	app_check_link(app);
 }
 
 static void
-app_ports_check_link(void)
+app_init_swq(struct app_params *app)
 {
-	uint32_t all_ports_up, i;
+	int i;
 
-	all_ports_up = 1;
+	for (i = 0; i < APP_MAX_PKTQ_SWQ; i++) {
+		struct app_pktq_swq_params *p = &app->swq_params[i];
 
-	for (i = 0; i < app.n_ports; i++) {
-		struct rte_eth_link link;
-		uint32_t port;
+		if (!APP_PARAM_VALID(p))
+			continue;
 
-		port = app.ports[i];
-		memset(&link, 0, sizeof(link));
-		rte_eth_link_get_nowait(port, &link);
-		RTE_LOG(INFO, USER1, "Port %u (%u Gbps) %s\n",
-			port,
-			link.link_speed / 1000,
-			link.link_status ? "UP" : "DOWN");
+		RTE_LOG(INFO, USER1, "Initializing %s...\n", p->name);
+		app->swq[i] = rte_ring_create(
+				p->name,
+				p->size,
+				p->cpu_socket_id,
+				RING_F_SP_ENQ | RING_F_SC_DEQ);
 
-		if (link.link_status == 0)
-			all_ports_up = 0;
+		if (app->swq[i] == NULL)
+			rte_panic("%s init error\n", p->name);
 	}
+}
 
-	if (all_ports_up == 0)
-		rte_panic("Some NIC ports are DOWN\n");
+static void
+app_init_tm(struct app_params *app)
+{
+	uint32_t i;
+
+	for (i = 0; i < APP_MAX_PKTQ_TM; i++) {
+		struct app_pktq_tm_params *p_tm = &app->tm_params[i];
+		struct app_link_params *p_link;
+		struct rte_eth_link link_eth_params;
+		struct rte_sched_port *sched;
+		uint32_t n_subports, subport_id;
+		int status;
+
+		if (!APP_PARAM_VALID(p_tm))
+			continue;
+
+		p_link = app_get_link_for_tm(app, p_tm);
+		/* LINK */
+		rte_eth_link_get(p_link->pmd_id, &link_eth_params);
+
+		/* TM */
+		p_tm->sched_port_params.name = p_tm->name;
+		p_tm->sched_port_params.socket = rte_eth_dev_socket_id(p_link->pmd_id);
+		p_tm->sched_port_params.rate =
+			(uint64_t) link_eth_params.link_speed * 1000 * 1000 / 8;
+		p_tm->sched_port_params.mtu = ETHER_MTU;
+
+		sched = rte_sched_port_config(&p_tm->sched_port_params);
+		if (sched == NULL)
+			rte_panic("%s init error\n", p_tm->name);
+		app->tm[i] = sched;
+
+		/* Subport */
+		n_subports = p_tm->sched_port_params.n_subports_per_port;
+		for (subport_id = 0; subport_id < n_subports; subport_id ++) {
+			uint32_t n_pipes_per_subport, pipe_id;
+
+			status = rte_sched_subport_config(sched,
+				subport_id,
+				&p_tm->sched_subport_params[subport_id]);
+			if (status)
+				rte_panic("%s subport %u init error (%d)\n",
+					p_tm->name, subport_id, status);
+
+			/* Pipe */
+			n_pipes_per_subport =
+					p_tm->sched_port_params.n_pipes_per_subport;
+			for (pipe_id = 0; pipe_id < n_pipes_per_subport; pipe_id++) {
+				int profile_id = p_tm->sched_pipe_to_profile[subport_id
+								* APP_MAX_SCHED_PIPES + pipe_id];
+
+				if (profile_id == -1)
+					continue;
+
+				status = rte_sched_pipe_config(sched, subport_id,
+					pipe_id, profile_id);
+				if (status)
+					rte_panic("%s subport %u pipe %u "
+						"(profile %d) init error (%d)\n",
+						p_tm->name, subport_id, pipe_id, profile_id, status);
+			}
+		}
+	}
 }
 
 static void
-app_init_ports(void)
+app_init_msgq(struct app_params *app)
+{
+	int i;
+
+	for (i = 0; i < APP_MAX_MSGQ; i++) {
+		struct app_msgq_params *p = &app->msgq_params[i];
+
+		if (!APP_PARAM_VALID(p))
+			continue;
+
+		RTE_LOG(INFO, USER1, "Creating %s ...\n", p->name);
+		app->msgq[i] = rte_ring_create(
+				p->name,
+				p->size,
+				p->cpu_socket_id,
+				RING_F_SP_ENQ | RING_F_SC_DEQ);
+
+		if (app->msgq[i] == NULL)
+			rte_panic("%s init error\n", p->name);
+	}
+}
+
+static void app_pipeline_params_get(struct app_params *app,
+	struct app_pipeline_params *p_in,
+	struct pipeline_params *p_out)
 {
 	uint32_t i;
 
-	/* Init NIC ports, then start the ports */
-	for (i = 0; i < app.n_ports; i++) {
-		uint32_t port;
-		int ret;
+	strcpy(p_out->name, p_in->name);
 
-		port = app.ports[i];
-		RTE_LOG(INFO, USER1, "Initializing NIC port %u ...\n", port);
+	p_out->socket_id = (int) p_in->socket_id;
 
-		/* Init port */
-		ret = rte_eth_dev_configure(
-			port,
-			1,
-			1,
-			&app.port_conf);
-		if (ret < 0)
-			rte_panic("Cannot init NIC port %u (%d)\n", port, ret);
-		rte_eth_promiscuous_enable(port);
-
-		/* Init RX queues */
-		ret = rte_eth_rx_queue_setup(
-			port,
-			0,
-			app.rsz_hwq_rx,
-			rte_eth_dev_socket_id(port),
-			&app.rx_conf,
-			app.pool);
-		if (ret < 0)
-			rte_panic("Cannot init RX for port %u (%d)\n",
-				(uint32_t) port, ret);
-
-		/* Init TX queues */
-		ret = rte_eth_tx_queue_setup(
-			port,
-			0,
-			app.rsz_hwq_tx,
-			rte_eth_dev_socket_id(port),
-			&app.tx_conf);
-		if (ret < 0)
-			rte_panic("Cannot init TX for port %u (%d)\n", port,
-				ret);
+	/* pktq_in */
+	p_out->n_ports_in = p_in->n_pktq_in;
+	for (i = 0; i < p_in->n_pktq_in; i++) {
+		struct app_pktq_in_params *in = &p_in->pktq_in[i];
+		struct pipeline_port_in_params *out = &p_out->port_in[i];
 
-		/* Start port */
-		ret = rte_eth_dev_start(port);
-		if (ret < 0)
-			rte_panic("Cannot start port %u (%d)\n", port, ret);
+		switch (in->type) {
+		case APP_PKTQ_IN_HWQ:
+		{
+			struct app_pktq_hwq_in_params *p_hwq_in = &app->hwq_in_params[in->id];
+			struct app_link_params *p_link = app_get_link_for_rxq(app, p_hwq_in);
+			uint32_t rxq_link_id, rxq_queue_id;
+
+			sscanf(p_hwq_in->name, "RXQ%u.%u", &rxq_link_id, &rxq_queue_id);
+
+			out->type = PIPELINE_PORT_IN_ETHDEV_READER;
+			out->params.ethdev.port_id = p_link->pmd_id;
+			out->params.ethdev.queue_id = rxq_queue_id;
+			out->burst_size = p_hwq_in->burst;
+			break;
+		}
+		case APP_PKTQ_IN_SWQ:
+			out->type = PIPELINE_PORT_IN_RING_READER;
+			out->params.ring.ring = app->swq[in->id];
+			out->burst_size = app->swq_params[in->id].burst_read;
+			/* What about frag and ras ports? */
+			break;
+		case APP_PKTQ_IN_TM:
+			out->type = PIPELINE_PORT_IN_SCHED_READER;
+			out->params.sched.sched = app->tm[in->id];
+			out->burst_size = app->tm_params[in->id].burst_read;
+			break;
+		case APP_PKTQ_IN_SOURCE:
+			out->type = PIPELINE_PORT_IN_SOURCE;
+			out->params.source.mempool = app->mempool[in->id];
+			out->burst_size = app->source_params[in->id].burst;
+			break;
+		default:
+			break;
+		}
 	}
 
-	app_ports_check_link();
-}
+	/* pktq_out */
+	p_out->n_ports_out = p_in->n_pktq_out;
+	for (i = 0; i < p_in->n_pktq_out; i++) {
+		struct app_pktq_out_params *in = &p_in->pktq_out[i];
+		struct pipeline_port_out_params *out = &p_out->port_out[i];
+
+		switch (in->type) {
+		case APP_PKTQ_OUT_HWQ:
+		{
+			struct app_pktq_hwq_out_params *p_hwq_out = &app->hwq_out_params[in->id];
+			struct app_link_params *p_link = app_get_link_for_txq(app, p_hwq_out);
+			uint32_t txq_link_id, txq_queue_id;
+
+			sscanf(p_hwq_out->name, "TXQ%u.%u", &txq_link_id, &txq_queue_id);
+
+			if (p_hwq_out->dropless == 0) {
+				struct rte_port_ethdev_writer_params *params = &out->params.ethdev;
+
+				out->type = PIPELINE_PORT_OUT_ETHDEV_WRITER;
+				params->port_id = p_link->pmd_id;
+				params->queue_id = txq_queue_id;
+				params->tx_burst_sz = app->hwq_out_params[in->id].burst;
+			}
+			else {
+				struct rte_port_ethdev_writer_nodrop_params *params =
+						&out->params.ethdev_nodrop;
+
+				out->type = PIPELINE_PORT_OUT_ETHDEV_WRITER_NODROP;
+				params->port_id = p_link->pmd_id;
+				params->queue_id = txq_queue_id;
+				params->tx_burst_sz = p_hwq_out->burst;
+				params->n_retries = p_hwq_out->n_retries;
+			}
+			break;
+		}
+		case APP_PKTQ_OUT_SWQ:
+			if (app->swq_params[in->id].dropless == 0) {
+				struct rte_port_ring_writer_params *params = &out->params.ring;
+
+				out->type = PIPELINE_PORT_OUT_RING_WRITER;
+				params->ring = app->swq[in->id];
+				params->tx_burst_sz = app->swq_params[in->id].burst_write;
+			}
+			else {
+				struct rte_port_ring_writer_nodrop_params *params =
+						&out->params.ring_nodrop;
+
+				out->type = PIPELINE_PORT_OUT_RING_WRITER_NODROP;
+				params->ring = app->swq[in->id];
+				params->tx_burst_sz = app->swq_params[in->id].burst_write;
+				params->n_retries = app->swq_params[in->id].n_retries;
+			}
+			/* What about frag and ras ports? */
+			break;
+		case APP_PKTQ_OUT_TM: {
+			struct rte_port_sched_writer_params *params = &out->params.sched;
+
+			out->type = PIPELINE_PORT_OUT_SCHED_WRITER;
+			params->sched = app->tm[in->id];
+			params->tx_burst_sz = app->tm_params[in->id].burst_write;
+			break;
+		}
+		case APP_PKTQ_OUT_SINK:
+			out->type = PIPELINE_PORT_OUT_SINK;
+			break;
+		default:
+			break;
+		}
+	}
 
-#define APP_PING_TIMEOUT_SEC                               5
+	/* msgq */
+	p_out->n_msgq = p_in->n_msgq_in;
 
-void
-app_ping(void)
-{
-	unsigned i;
-	uint64_t timestamp, diff_tsc;
+	for (i = 0; i < p_in->n_msgq_in; i++)
+		p_out->msgq_in[i] = app->msgq[p_in->msgq_in[i]];
 
-	const uint64_t timeout = rte_get_tsc_hz() * APP_PING_TIMEOUT_SEC;
+	for (i = 0; i < p_in->n_msgq_out; i++)
+		p_out->msgq_out[i] = app->msgq[p_in->msgq_out[i]];
 
-	for (i = 0; i < RTE_MAX_LCORE; i++) {
-		struct app_core_params *p = &app.cores[i];
-		struct rte_ring *ring_req, *ring_resp;
-		void *msg;
-		struct app_msg_req *req;
-		int status;
+	/* args */
+	p_out->n_args = p_in->n_args;
+	for (i = 0; i < p_in->n_args; i++){
+		p_out->args_name[i] = p_in->args_name[i];
+		p_out->args_value[i] = p_in->args_value[i];
+	}
+}
 
-		if ((p->core_type != APP_CORE_FC) &&
-		    (p->core_type != APP_CORE_FW) &&
-			(p->core_type != APP_CORE_RT) &&
-			(p->core_type != APP_CORE_RX))
+static void
+app_init_pipelines(struct app_params *app)
+{
+	uint32_t p_id;
+
+	for (p_id = 0; p_id < APP_MAX_PIPELINES; p_id++) {
+		struct app_pipeline_params *params = &app->pipeline_params[p_id];
+		struct app_pipeline_data *data = &app->pipeline_data[p_id];
+		struct pipeline_type *ptype;
+		struct pipeline_params pp;
+
+		if (!APP_PARAM_VALID(params))
 			continue;
 
-		ring_req = app_get_ring_req(p->core_id);
-		ring_resp = app_get_ring_resp(p->core_id);
-
-		/* Fill request message */
-		msg = (void *)rte_ctrlmbuf_alloc(app.msg_pool);
-		if (msg == NULL)
-			rte_panic("Unable to allocate new message\n");
-
-		req = (struct app_msg_req *)
-				rte_ctrlmbuf_data((struct rte_mbuf *)msg);
-		req->type = APP_MSG_REQ_PING;
-
-		/* Send request */
-		do {
-			status = rte_ring_sp_enqueue(ring_req, msg);
-		} while (status == -ENOBUFS);
-
-		/* Wait for response */
-		timestamp = rte_rdtsc();
-		do {
-			status = rte_ring_sc_dequeue(ring_resp, &msg);
-			diff_tsc = rte_rdtsc() - timestamp;
-
-			if (unlikely(diff_tsc > timeout))
-				rte_panic("Core %u of type %d does not respond "
-					"to requests\n", p->core_id,
-					p->core_type);
-		} while (status != 0);
-
-		/* Free message buffer */
-		rte_ctrlmbuf_free(msg);
+		RTE_LOG(INFO, USER1, "Initializing %s ...\n", params->name);
+
+		ptype = app_pipeline_type_find(app, params->type);
+		if (ptype == NULL)
+			rte_panic("Init error: Unknown pipeline type \"%s\"\n", params->type);
+
+		app_pipeline_params_get(app, params, &pp);
+
+		/* Back-end */
+		data->be = NULL;
+		if (ptype->ops->f_init) {
+			data->be = ptype->ops->f_init(&pp, (void *) app);
+
+			if (data->be == NULL)
+				rte_panic("Pipeline instance \"%s\" back-end init error\n", params->name);
+		}
+
+		/* Front-end */
+		data->fe = NULL;
+		if (ptype->fe_ops->f_init) {
+			data->fe = ptype->fe_ops->f_init(&pp, (void *) app);
+
+			if (data->fe == NULL)
+				rte_panic("Pipeline instance \"%s\" front-end init error\n", params->name);
+		}
+
+		data->timer_period = (rte_get_tsc_hz() * params->timer_period) / 1000;
 	}
 }
 
 static void
-app_init_etc(void)
+app_init_threads(struct app_params *app)
 {
-	if ((app_get_first_core_id(APP_CORE_IPV4_FRAG) != RTE_MAX_LCORE) ||
-		(app_get_first_core_id(APP_CORE_IPV4_RAS) != RTE_MAX_LCORE)) {
-		RTE_LOG(INFO, USER1,
-			"Activating the Ethernet header pop/push ...\n");
-		app.ether_hdr_pop_push = 1;
+	uint64_t time = rte_get_tsc_cycles();
+	uint32_t p_id;
+
+	for (p_id = 0; p_id < APP_MAX_PIPELINES; p_id++) {
+		struct app_pipeline_params *params = &app->pipeline_params[p_id];
+		struct app_pipeline_data *data = &app->pipeline_data[p_id];
+		struct pipeline_type *ptype;
+		struct app_thread_data *t;
+		struct app_thread_pipeline_data *p;
+		int lcore_id;
+
+		if (!APP_PARAM_VALID(params))
+			continue;
+
+		lcore_id = cpu_core_map_get_lcore_id(app->core_map,
+			params->socket_id,
+			params->core_id,
+			params->hyper_th_id);
+
+		if (lcore_id < 0)
+			rte_panic("Invalid core s%uc%u%s\n",
+				params->socket_id,
+				params->core_id,
+				(params->hyper_th_id)? "h" : "");
+
+		t = &app->thread_data[lcore_id];
+
+		ptype = app_pipeline_type_find(app, params->type);
+		if (ptype == NULL)
+			rte_panic("Init error: Unknown pipeline type \"%s\"\n", params->type);
+
+		p = (ptype->ops->f_run == NULL)?
+			&t->regular[t->n_regular] :
+			&t->custom[t->n_custom];
+
+		p->be = data->be;
+		p->f_run = ptype->ops->f_run;
+		p->f_timer = ptype->ops->f_timer;
+		p->timer_period = data->timer_period;
+		p->deadline = time + data->timer_period;
+
+		if (ptype->ops->f_run == NULL)
+			t->n_regular ++;
+		else
+			t->n_custom ++;
 	}
 }
 
-void
-app_init(void)
+int app_init(struct app_params *app)
+{
+	app_init_core_map(app);
+	app_init_core_mask(app);
+
+	app_init_eal(app);
+	app_init_mempool(app);
+	app_init_link(app);
+	app_init_swq(app);
+	app_init_tm(app);
+	app_init_msgq(app);
+
+	app_init_pipelines(app);
+	app_init_threads(app);
+
+	return 0;
+}
+
+static int
+app_pipeline_type_cmd_push(struct app_params *app, struct pipeline_type *ptype)
+{
+	cmdline_parse_ctx_t *cmds;
+	uint32_t n_cmds, i;
+
+	/* Check input arguments */
+	if ((app == NULL) ||
+		(ptype == NULL))
+		return -EINVAL;
+
+	n_cmds = pipeline_type_cmds_count(ptype);
+	if (n_cmds == 0)
+		return 0;
+
+	cmds = ptype->fe_ops->cmds;
+
+	/* Check for available slots in the application commands array */
+	if (n_cmds > APP_MAX_CMDS - app->n_cmds)
+		return -ENOMEM;
+
+	/* Push pipeline commands into the application */
+	memcpy(&app->cmds[app->n_cmds],
+		cmds,
+		n_cmds * sizeof(cmdline_parse_ctx_t *));
+
+	for (i = 0; i < n_cmds; i++)
+		app->cmds[app->n_cmds + i]->data = app;
+
+	app->n_cmds += n_cmds;
+	app->cmds[app->n_cmds] = NULL;
+
+	return 0;
+}
+
+int
+app_pipeline_type_register(struct app_params *app, struct pipeline_type *ptype)
 {
-	if ((sizeof(struct app_pkt_metadata) % RTE_CACHE_LINE_SIZE) != 0)
-		rte_panic("Application pkt meta-data size mismatch\n");
+	uint32_t n_cmds, i;
+
+	/* Check input arguments */
+	if ((app == NULL) ||
+		(ptype == NULL) ||
+		(ptype->name == NULL) ||
+		(strlen(ptype->name) == 0) ||
+		(ptype->ops->f_init == NULL))
+		return -EINVAL;
+
+	/* Check for duplicate entry */
+	for (i = 0; i < app->n_pipeline_types; i++)
+		if (strcmp(app->pipeline_type[i].name ,ptype->name) == 0)
+			return -EEXIST;
+
+	/* Check for resource availability */
+	n_cmds = pipeline_type_cmds_count(ptype);
+	if ((app->n_pipeline_types == APP_MAX_PIPELINE_TYPES) ||
+		(n_cmds > APP_MAX_CMDS - app->n_cmds))
+		return -ENOMEM;
+
+	/* Copy pipeline type */
+	memcpy(&app->pipeline_type[app->n_pipeline_types++],
+		ptype,
+		sizeof(struct pipeline_type));
+
+	/* Copy CLI commands */
+	if (n_cmds)
+		app_pipeline_type_cmd_push(app, ptype);
+
+	return 0;
+}
 
-	app_check_core_params();
+struct
+pipeline_type *app_pipeline_type_find(struct app_params *app, char *name)
+{
+	uint32_t i;
 
-	app_init_mbuf_pools();
-	app_init_rings();
-	app_init_ports();
-	app_init_etc();
+	for (i = 0; i < app->n_pipeline_types; i++)
+		if (strcmp(app->pipeline_type[i].name, name) == 0)
+			return &app->pipeline_type[i];
 
-	RTE_LOG(INFO, USER1, "Initialization completed\n");
+	return NULL;
 }
diff --git a/examples/ip_pipeline/main.c b/examples/ip_pipeline/main.c
index 612eea9..ef68c86 100644
--- a/examples/ip_pipeline/main.c
+++ b/examples/ip_pipeline/main.c
@@ -49,5 +49,8 @@ main(int argc, char **argv)
 
 	app_config_check(&app);
 
+	/* Init */
+	app_init(&app);
+
 	return 0;
 }
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 04/11] ip_pipeline: moved pipelines to separate folder
  2015-05-29 15:43 [PATCH 00/11] ip_pipeline: ip_pipeline application enhancements Maciej Gajdzica
                   ` (2 preceding siblings ...)
  2015-05-29 15:43 ` [PATCH 03/11] ip_pipeline: modified init to match new params struct Maciej Gajdzica
@ 2015-05-29 15:43 ` Maciej Gajdzica
  2015-05-29 15:43 ` [PATCH 05/11] ip_pipeline: added master pipeline Maciej Gajdzica
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Maciej Gajdzica @ 2015-05-29 15:43 UTC (permalink / raw)
  To: dev

Moved pipelines to separate folder, removed not needed pipelines and
modified Makefile to match that change.

Signed-off-by: Maciej Gajdzica <maciejx.t.gajdzica@intel.com>
---
 examples/ip_pipeline/Makefile                      |    9 +-
 examples/ip_pipeline/pipeline/pipeline_firewall.c  |  313 +++++++++++++
 .../pipeline/pipeline_flow_classification.c        |  306 +++++++++++++
 .../ip_pipeline/pipeline/pipeline_passthrough.c    |  213 +++++++++
 examples/ip_pipeline/pipeline/pipeline_routing.c   |  474 ++++++++++++++++++++
 examples/ip_pipeline/pipeline_firewall.c           |  313 -------------
 .../ip_pipeline/pipeline_flow_classification.c     |  306 -------------
 examples/ip_pipeline/pipeline_ipv4_frag.c          |  184 --------
 examples/ip_pipeline/pipeline_ipv4_ras.c           |  181 --------
 examples/ip_pipeline/pipeline_passthrough.c        |  213 ---------
 examples/ip_pipeline/pipeline_routing.c            |  474 --------------------
 examples/ip_pipeline/pipeline_rx.c                 |  385 ----------------
 examples/ip_pipeline/pipeline_tx.c                 |  283 ------------
 13 files changed, 1314 insertions(+), 2340 deletions(-)
 create mode 100644 examples/ip_pipeline/pipeline/pipeline_firewall.c
 create mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_classification.c
 create mode 100644 examples/ip_pipeline/pipeline/pipeline_passthrough.c
 create mode 100644 examples/ip_pipeline/pipeline/pipeline_routing.c
 delete mode 100644 examples/ip_pipeline/pipeline_firewall.c
 delete mode 100644 examples/ip_pipeline/pipeline_flow_classification.c
 delete mode 100644 examples/ip_pipeline/pipeline_ipv4_frag.c
 delete mode 100644 examples/ip_pipeline/pipeline_ipv4_ras.c
 delete mode 100644 examples/ip_pipeline/pipeline_passthrough.c
 delete mode 100644 examples/ip_pipeline/pipeline_routing.c
 delete mode 100644 examples/ip_pipeline/pipeline_rx.c
 delete mode 100644 examples/ip_pipeline/pipeline_tx.c

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index 443f7e4..9a1e19a 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -36,11 +36,17 @@ endif
 # Default target, can be overridden by command line or environment
 RTE_TARGET ?= x86_64-native-linuxapp-gcc
 
+DIRS-(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline
+
 include $(RTE_SDK)/mk/rte.vars.mk
 
 # binary name
 APP = ip_pipeline
 
+VPATH += $(SRCDIR)/pipeline
+
+INC += $(wildcard *.h) $(wildcard pipeline/*.h)
+
 # all source are stored in SRCS-y
 SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) := main.c
 SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += config_parse.c
@@ -60,7 +66,8 @@ SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += cpu_core_map.c
 #SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_firewall.c
 #endif
 
+CFLAGS += -I$(SRCDIR) -I$(SRCDIR)/pipeline
 CFLAGS += -O3
-CFLAGS += $(WERROR_FLAGS)
+CFLAGS += $(WERROR_FLAGS) -Wno-error=unused-function -Wno-error=unused-variable
 
 include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/examples/ip_pipeline/pipeline/pipeline_firewall.c b/examples/ip_pipeline/pipeline/pipeline_firewall.c
new file mode 100644
index 0000000..b70260e
--- /dev/null
+++ b/examples/ip_pipeline/pipeline/pipeline_firewall.c
@@ -0,0 +1,313 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#include <rte_malloc.h>
+#include <rte_log.h>
+#include <rte_ethdev.h>
+#include <rte_ether.h>
+#include <rte_ip.h>
+#include <rte_byteorder.h>
+
+#include <rte_port_ring.h>
+#include <rte_table_acl.h>
+#include <rte_pipeline.h>
+
+#include "main.h"
+
+struct app_core_firewall_message_handle_params {
+	struct rte_ring *ring_req;
+	struct rte_ring *ring_resp;
+
+	struct rte_pipeline *p;
+	uint32_t *port_out_id;
+	uint32_t table_id;
+};
+
+static void
+app_message_handle(struct app_core_firewall_message_handle_params *params);
+
+enum {
+	PROTO_FIELD_IPV4,
+	SRC_FIELD_IPV4,
+	DST_FIELD_IPV4,
+	SRCP_FIELD_IPV4,
+	DSTP_FIELD_IPV4,
+	NUM_FIELDS_IPV4
+};
+
+struct rte_acl_field_def ipv4_field_formats[NUM_FIELDS_IPV4] = {
+	{
+		.type = RTE_ACL_FIELD_TYPE_BITMASK,
+		.size = sizeof(uint8_t),
+		.field_index = PROTO_FIELD_IPV4,
+		.input_index = PROTO_FIELD_IPV4,
+		.offset = sizeof(struct ether_hdr) +
+			offsetof(struct ipv4_hdr, next_proto_id),
+	},
+	{
+		.type = RTE_ACL_FIELD_TYPE_MASK,
+		.size = sizeof(uint32_t),
+		.field_index = SRC_FIELD_IPV4,
+		.input_index = SRC_FIELD_IPV4,
+		.offset = sizeof(struct ether_hdr) +
+			offsetof(struct ipv4_hdr, src_addr),
+	},
+	{
+		.type = RTE_ACL_FIELD_TYPE_MASK,
+		.size = sizeof(uint32_t),
+		.field_index = DST_FIELD_IPV4,
+		.input_index = DST_FIELD_IPV4,
+		.offset = sizeof(struct ether_hdr) +
+			offsetof(struct ipv4_hdr, dst_addr),
+	},
+	{
+		.type = RTE_ACL_FIELD_TYPE_RANGE,
+		.size = sizeof(uint16_t),
+		.field_index = SRCP_FIELD_IPV4,
+		.input_index = SRCP_FIELD_IPV4,
+		.offset = sizeof(struct ether_hdr) + sizeof(struct ipv4_hdr),
+	},
+	{
+		.type = RTE_ACL_FIELD_TYPE_RANGE,
+		.size = sizeof(uint16_t),
+		.field_index = DSTP_FIELD_IPV4,
+		.input_index = SRCP_FIELD_IPV4,
+		.offset = sizeof(struct ether_hdr) + sizeof(struct ipv4_hdr) +
+			sizeof(uint16_t),
+	},
+};
+
+void
+app_main_loop_pipeline_firewall(void) {
+	struct rte_pipeline_params pipeline_params = {
+		.name = "pipeline",
+		.socket_id = rte_socket_id(),
+	};
+
+	struct rte_pipeline *p;
+	uint32_t port_in_id[APP_MAX_PORTS];
+	uint32_t port_out_id[APP_MAX_PORTS];
+	uint32_t table_id;
+	uint32_t i;
+
+	uint32_t core_id = rte_lcore_id();
+	struct app_core_params *core_params = app_get_core_params(core_id);
+	struct app_core_firewall_message_handle_params mh_params;
+
+	if ((core_params == NULL) || (core_params->core_type != APP_CORE_FW))
+		rte_panic("Core %u misconfiguration\n", core_id);
+
+	RTE_LOG(INFO, USER1, "Core %u is doing firewall\n", core_id);
+
+	/* Pipeline configuration */
+	p = rte_pipeline_create(&pipeline_params);
+	if (p == NULL)
+		rte_panic("Unable to configure the pipeline\n");
+
+	/* Input port configuration */
+	for (i = 0; i < app.n_ports; i++) {
+		struct rte_port_ring_reader_params port_ring_params = {
+			.ring = app.rings[core_params->swq_in[i]],
+		};
+
+		struct rte_pipeline_port_in_params port_params = {
+			.ops = &rte_port_ring_reader_ops,
+			.arg_create = (void *) &port_ring_params,
+			.f_action = NULL,
+			.arg_ah = NULL,
+			.burst_size = app.bsz_swq_rd,
+		};
+
+		if (rte_pipeline_port_in_create(p, &port_params,
+			&port_in_id[i]))
+			rte_panic("Unable to configure input port for "
+				"ring %d\n", i);
+	}
+
+	/* Output port configuration */
+	for (i = 0; i < app.n_ports; i++) {
+		struct rte_port_ring_writer_params port_ring_params = {
+			.ring = app.rings[core_params->swq_out[i]],
+			.tx_burst_sz = app.bsz_swq_wr,
+		};
+
+		struct rte_pipeline_port_out_params port_params = {
+			.ops = &rte_port_ring_writer_ops,
+			.arg_create = (void *) &port_ring_params,
+			.f_action = NULL,
+			.f_action_bulk = NULL,
+			.arg_ah = NULL,
+		};
+
+		if (rte_pipeline_port_out_create(p, &port_params,
+			&port_out_id[i]))
+			rte_panic("Unable to configure output port for "
+				"ring %d\n", i);
+	}
+
+	/* Table configuration */
+	{
+		struct rte_table_acl_params table_acl_params = {
+			.name = "test", /* unique identifier for acl contexts */
+			.n_rules = app.max_firewall_rules,
+			.n_rule_fields = DIM(ipv4_field_formats),
+		};
+
+		struct rte_pipeline_table_params table_params = {
+			.ops = &rte_table_acl_ops,
+			.arg_create = &table_acl_params,
+			.f_action_hit = NULL,
+			.f_action_miss = NULL,
+			.arg_ah = NULL,
+			.action_data_size = 0,
+		};
+
+		memcpy(table_acl_params.field_format, ipv4_field_formats,
+			sizeof(ipv4_field_formats));
+
+		if (rte_pipeline_table_create(p, &table_params, &table_id))
+			rte_panic("Unable to configure the ACL table\n");
+	}
+
+	/* Interconnecting ports and tables */
+	for (i = 0; i < app.n_ports; i++)
+		if (rte_pipeline_port_in_connect_to_table(p, port_in_id[i],
+			table_id))
+			rte_panic("Unable to connect input port %u to "
+				"table %u\n", port_in_id[i],  table_id);
+
+	/* Enable input ports */
+	for (i = 0; i < app.n_ports; i++)
+		if (rte_pipeline_port_in_enable(p, port_in_id[i]))
+			rte_panic("Unable to enable input port %u\n",
+				port_in_id[i]);
+
+	/* Check pipeline consistency */
+	if (rte_pipeline_check(p) < 0)
+		rte_panic("Pipeline consistency check failed\n");
+
+	/* Message handling */
+	mh_params.ring_req = app_get_ring_req(
+		app_get_first_core_id(APP_CORE_FW));
+	mh_params.ring_resp = app_get_ring_resp(
+		app_get_first_core_id(APP_CORE_FW));
+	mh_params.p = p;
+	mh_params.port_out_id = port_out_id;
+	mh_params.table_id = table_id;
+
+	/* Run-time */
+	for (i = 0; ; i++) {
+		rte_pipeline_run(p);
+
+		if ((i & APP_FLUSH) == 0) {
+			rte_pipeline_flush(p);
+			app_message_handle(&mh_params);
+		}
+	}
+}
+
+void
+app_message_handle(struct app_core_firewall_message_handle_params *params)
+{
+	struct rte_ring *ring_req = params->ring_req;
+	struct rte_ring *ring_resp;
+	struct rte_mbuf *msg;
+	struct app_msg_req *req;
+	struct app_msg_resp *resp;
+	struct rte_pipeline *p;
+	uint32_t *port_out_id;
+	uint32_t table_id;
+	int result;
+
+	/* Read request message */
+	result = rte_ring_sc_dequeue(ring_req, (void **) &msg);
+	if (result != 0)
+		return;
+
+	ring_resp = params->ring_resp;
+	p = params->p;
+	port_out_id = params->port_out_id;
+	table_id = params->table_id;
+
+	/* Handle request */
+	req = (struct app_msg_req *)rte_ctrlmbuf_data(msg);
+	switch (req->type) {
+	case APP_MSG_REQ_PING:
+	{
+		result = 0;
+		break;
+	}
+
+	case APP_MSG_REQ_FW_ADD:
+	{
+		struct rte_pipeline_table_entry entry = {
+			.action = RTE_PIPELINE_ACTION_PORT,
+			{.port_id = port_out_id[req->firewall_add.port]},
+		};
+
+		struct rte_pipeline_table_entry *entry_ptr;
+
+		int key_found;
+
+		result = rte_pipeline_table_entry_add(p, table_id,
+			&req->firewall_add.add_params, &entry, &key_found,
+			&entry_ptr);
+		break;
+	}
+
+	case APP_MSG_REQ_FW_DEL:
+	{
+		int key_found;
+
+		result = rte_pipeline_table_entry_delete(p, table_id,
+			&req->firewall_del.delete_params, &key_found, NULL);
+		break;
+	}
+
+	default:
+		rte_panic("FW unrecognized message type (%u)\n", req->type);
+	}
+
+	/* Fill in response message */
+	resp = (struct app_msg_resp *)rte_ctrlmbuf_data(msg);
+	resp->result = result;
+
+	/* Send response */
+	do {
+		result = rte_ring_sp_enqueue(ring_resp, (void *) msg);
+	} while (result == -ENOBUFS);
+}
diff --git a/examples/ip_pipeline/pipeline/pipeline_flow_classification.c b/examples/ip_pipeline/pipeline/pipeline_flow_classification.c
new file mode 100644
index 0000000..cc0cbf1
--- /dev/null
+++ b/examples/ip_pipeline/pipeline/pipeline_flow_classification.c
@@ -0,0 +1,306 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#include <rte_malloc.h>
+#include <rte_log.h>
+#include <rte_ethdev.h>
+#include <rte_ether.h>
+#include <rte_ip.h>
+#include <rte_byteorder.h>
+
+#include <rte_port_ring.h>
+#include <rte_table_hash.h>
+#include <rte_pipeline.h>
+
+#include "main.h"
+
+struct app_core_fc_message_handle_params {
+	struct rte_ring *ring_req;
+	struct rte_ring *ring_resp;
+
+	struct rte_pipeline *p;
+	uint32_t *port_out_id;
+	uint32_t table_id;
+};
+
+static void
+app_message_handle(struct app_core_fc_message_handle_params *params);
+
+static int app_flow_classification_table_init(
+	struct rte_pipeline *p,
+	uint32_t *port_out_id,
+	uint32_t table_id)
+{
+	struct app_flow_key flow_key;
+	uint32_t i;
+
+	/* Add entries to tables */
+	for (i = 0; i < (1 << 24); i++) {
+		struct rte_pipeline_table_entry entry = {
+			.action = RTE_PIPELINE_ACTION_PORT,
+			{.port_id = port_out_id[i & (app.n_ports - 1)]},
+		};
+		struct rte_pipeline_table_entry *entry_ptr;
+		int key_found, status;
+
+		flow_key.ttl = 0;
+		flow_key.proto = 6; /* TCP */
+		flow_key.header_checksum = 0;
+		flow_key.ip_src = 0;
+		flow_key.ip_dst = rte_bswap32(i);
+		flow_key.port_src = 0;
+		flow_key.port_dst = 0;
+
+		status = rte_pipeline_table_entry_add(p, table_id,
+			(void *) &flow_key, &entry, &key_found, &entry_ptr);
+		if (status < 0)
+			rte_panic("Unable to add entry to table %u (%d)\n",
+				table_id, status);
+	}
+
+	return 0;
+}
+
+void
+app_main_loop_pipeline_flow_classification(void) {
+	struct rte_pipeline_params pipeline_params = {
+		.name = "pipeline",
+		.socket_id = rte_socket_id(),
+	};
+
+	struct rte_pipeline *p;
+	uint32_t port_in_id[APP_MAX_PORTS];
+	uint32_t port_out_id[APP_MAX_PORTS];
+	uint32_t table_id;
+	uint32_t i;
+
+	uint32_t core_id = rte_lcore_id();
+	struct app_core_params *core_params = app_get_core_params(core_id);
+	struct app_core_fc_message_handle_params mh_params;
+
+	if ((core_params == NULL) || (core_params->core_type != APP_CORE_FC))
+		rte_panic("Core %u misconfiguration\n", core_id);
+
+	RTE_LOG(INFO, USER1, "Core %u is doing flow classification "
+		"(pipeline with hash table, 16-byte key, LRU)\n", core_id);
+
+	/* Pipeline configuration */
+	p = rte_pipeline_create(&pipeline_params);
+	if (p == NULL)
+		rte_panic("Unable to configure the pipeline\n");
+
+	/* Input port configuration */
+	for (i = 0; i < app.n_ports; i++) {
+		struct rte_port_ring_reader_params port_ring_params = {
+			.ring = app.rings[core_params->swq_in[i]],
+		};
+
+		struct rte_pipeline_port_in_params port_params = {
+			.ops = &rte_port_ring_reader_ops,
+			.arg_create = (void *) &port_ring_params,
+			.f_action = NULL,
+			.arg_ah = NULL,
+			.burst_size = app.bsz_swq_rd,
+		};
+
+		if (rte_pipeline_port_in_create(p, &port_params,
+			&port_in_id[i]))
+			rte_panic("Unable to configure input port for "
+				"ring %d\n", i);
+	}
+
+	/* Output port configuration */
+	for (i = 0; i < app.n_ports; i++) {
+		struct rte_port_ring_writer_params port_ring_params = {
+			.ring = app.rings[core_params->swq_out[i]],
+			.tx_burst_sz = app.bsz_swq_wr,
+		};
+
+		struct rte_pipeline_port_out_params port_params = {
+			.ops = &rte_port_ring_writer_ops,
+			.arg_create = (void *) &port_ring_params,
+			.f_action = NULL,
+			.f_action_bulk = NULL,
+			.arg_ah = NULL,
+		};
+
+		if (rte_pipeline_port_out_create(p, &port_params,
+			&port_out_id[i]))
+			rte_panic("Unable to configure output port for "
+				"ring %d\n", i);
+	}
+
+	/* Table configuration */
+	{
+		struct rte_table_hash_key16_lru_params table_hash_params = {
+			.n_entries = 1 << 24,
+			.signature_offset = __builtin_offsetof(
+				struct app_pkt_metadata, signature),
+			.key_offset = __builtin_offsetof(
+				struct app_pkt_metadata, flow_key),
+			.f_hash = test_hash,
+			.seed = 0,
+		};
+
+		struct rte_pipeline_table_params table_params = {
+			.ops = &rte_table_hash_key16_lru_ops,
+			.arg_create = &table_hash_params,
+			.f_action_hit = NULL,
+			.f_action_miss = NULL,
+			.arg_ah = NULL,
+			.action_data_size = 0,
+		};
+
+		if (rte_pipeline_table_create(p, &table_params, &table_id))
+			rte_panic("Unable to configure the hash table\n");
+	}
+
+	/* Interconnecting ports and tables */
+	for (i = 0; i < app.n_ports; i++)
+		if (rte_pipeline_port_in_connect_to_table(p, port_in_id[i],
+			table_id))
+			rte_panic("Unable to connect input port %u to "
+				"table %u\n", port_in_id[i],  table_id);
+
+	/* Enable input ports */
+	for (i = 0; i < app.n_ports; i++)
+		if (rte_pipeline_port_in_enable(p, port_in_id[i]))
+			rte_panic("Unable to enable input port %u\n",
+				port_in_id[i]);
+
+	/* Check pipeline consistency */
+	if (rte_pipeline_check(p) < 0)
+		rte_panic("Pipeline consistency check failed\n");
+
+	/* Message handling */
+	mh_params.ring_req = app_get_ring_req(
+		app_get_first_core_id(APP_CORE_FC));
+	mh_params.ring_resp = app_get_ring_resp(
+		app_get_first_core_id(APP_CORE_FC));
+	mh_params.p = p;
+	mh_params.port_out_id = port_out_id;
+	mh_params.table_id = table_id;
+
+	/* Run-time */
+	for (i = 0; ; i++) {
+		rte_pipeline_run(p);
+
+		if ((i & APP_FLUSH) == 0) {
+			rte_pipeline_flush(p);
+			app_message_handle(&mh_params);
+		}
+	}
+}
+
+void
+app_message_handle(struct app_core_fc_message_handle_params *params)
+{
+	struct rte_ring *ring_req = params->ring_req;
+	struct rte_ring *ring_resp;
+	void *msg;
+	struct app_msg_req *req;
+	struct app_msg_resp *resp;
+	struct rte_pipeline *p;
+	uint32_t *port_out_id;
+	uint32_t table_id;
+	int result;
+
+	/* Read request message */
+	result = rte_ring_sc_dequeue(ring_req, &msg);
+	if (result != 0)
+		return;
+
+	ring_resp = params->ring_resp;
+	p = params->p;
+	port_out_id = params->port_out_id;
+	table_id = params->table_id;
+
+	/* Handle request */
+	req = (struct app_msg_req *)rte_ctrlmbuf_data((struct rte_mbuf *)msg);
+	switch (req->type) {
+	case APP_MSG_REQ_PING:
+	{
+		result = 0;
+		break;
+	}
+
+	case APP_MSG_REQ_FC_ADD_ALL:
+	{
+		result = app_flow_classification_table_init(p, port_out_id,
+			table_id);
+		break;
+	}
+
+	case APP_MSG_REQ_FC_ADD:
+	{
+		struct rte_pipeline_table_entry entry = {
+			.action = RTE_PIPELINE_ACTION_PORT,
+			{.port_id = port_out_id[req->flow_classif_add.port]},
+		};
+
+		struct rte_pipeline_table_entry *entry_ptr;
+
+		int key_found;
+
+		result = rte_pipeline_table_entry_add(p, table_id,
+			req->flow_classif_add.key_raw, &entry, &key_found,
+			&entry_ptr);
+		break;
+	}
+
+	case APP_MSG_REQ_FC_DEL:
+	{
+		int key_found;
+
+		result = rte_pipeline_table_entry_delete(p, table_id,
+			req->flow_classif_add.key_raw, &key_found, NULL);
+		break;
+	}
+
+	default:
+		rte_panic("FC Unrecognized message type (%u)\n", req->type);
+	}
+
+	/* Fill in response message */
+	resp = (struct app_msg_resp *)rte_ctrlmbuf_data((struct rte_mbuf *)msg);
+	resp->result = result;
+
+	/* Send response */
+	do {
+		result = rte_ring_sp_enqueue(ring_resp, msg);
+	} while (result == -ENOBUFS);
+}
diff --git a/examples/ip_pipeline/pipeline/pipeline_passthrough.c b/examples/ip_pipeline/pipeline/pipeline_passthrough.c
new file mode 100644
index 0000000..948b2c1
--- /dev/null
+++ b/examples/ip_pipeline/pipeline/pipeline_passthrough.c
@@ -0,0 +1,213 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#include <rte_malloc.h>
+#include <rte_log.h>
+
+#include <rte_port_ring.h>
+#include <rte_table_stub.h>
+#include <rte_pipeline.h>
+
+#include "main.h"
+
+void
+app_main_loop_pipeline_passthrough(void) {
+	struct rte_pipeline_params pipeline_params = {
+		.name = "pipeline",
+		.socket_id = rte_socket_id(),
+	};
+
+	struct rte_pipeline *p;
+	uint32_t port_in_id[APP_MAX_PORTS];
+	uint32_t port_out_id[APP_MAX_PORTS];
+	uint32_t table_id[APP_MAX_PORTS];
+	uint32_t i;
+
+	uint32_t core_id = rte_lcore_id();
+	struct app_core_params *core_params = app_get_core_params(core_id);
+
+	if ((core_params == NULL) || (core_params->core_type != APP_CORE_PT))
+		rte_panic("Core %u misconfiguration\n", core_id);
+
+	RTE_LOG(INFO, USER1, "Core %u is doing pass-through\n", core_id);
+
+	/* Pipeline configuration */
+	p = rte_pipeline_create(&pipeline_params);
+	if (p == NULL)
+		rte_panic("%s: Unable to configure the pipeline\n", __func__);
+
+	/* Input port configuration */
+	for (i = 0; i < app.n_ports; i++) {
+		struct rte_port_ring_reader_params port_ring_params = {
+			.ring = app.rings[core_params->swq_in[i]],
+		};
+
+		struct rte_pipeline_port_in_params port_params = {
+			.ops = &rte_port_ring_reader_ops,
+			.arg_create = (void *) &port_ring_params,
+			.f_action = NULL,
+			.arg_ah = NULL,
+			.burst_size = app.bsz_swq_rd,
+		};
+
+		if (rte_pipeline_port_in_create(p, &port_params,
+			&port_in_id[i])) {
+			rte_panic("%s: Unable to configure input port for "
+				"ring %d\n", __func__, i);
+		}
+	}
+
+	/* Output port configuration */
+	for (i = 0; i < app.n_ports; i++) {
+		struct rte_port_ring_writer_params port_ring_params = {
+			.ring = app.rings[core_params->swq_out[i]],
+			.tx_burst_sz = app.bsz_swq_wr,
+		};
+
+		struct rte_pipeline_port_out_params port_params = {
+			.ops = &rte_port_ring_writer_ops,
+			.arg_create = (void *) &port_ring_params,
+			.f_action = NULL,
+			.f_action_bulk = NULL,
+			.arg_ah = NULL,
+		};
+
+		if (rte_pipeline_port_out_create(p, &port_params,
+			&port_out_id[i])) {
+			rte_panic("%s: Unable to configure output port for "
+				"ring %d\n", __func__, i);
+		}
+	}
+
+	/* Table configuration */
+	for (i = 0; i < app.n_ports; i++) {
+		struct rte_pipeline_table_params table_params = {
+			.ops = &rte_table_stub_ops,
+			.arg_create = NULL,
+			.f_action_hit = NULL,
+			.f_action_miss = NULL,
+			.arg_ah = NULL,
+			.action_data_size = 0,
+		};
+
+		if (rte_pipeline_table_create(p, &table_params, &table_id[i]))
+			rte_panic("%s: Unable to configure table %u\n",
+				__func__, i);
+	}
+
+	/* Interconnecting ports and tables */
+	for (i = 0; i < app.n_ports; i++) {
+		if (rte_pipeline_port_in_connect_to_table(p, port_in_id[i],
+			table_id[i])) {
+			rte_panic("%s: Unable to connect input port %u to "
+				"table %u\n", __func__, port_in_id[i],
+				table_id[i]);
+		}
+	}
+
+	/* Add entries to tables */
+	for (i = 0; i < app.n_ports; i++) {
+		struct rte_pipeline_table_entry default_entry = {
+			.action = RTE_PIPELINE_ACTION_PORT,
+			{.port_id = port_out_id[i]},
+		};
+
+		struct rte_pipeline_table_entry *default_entry_ptr;
+
+		if (rte_pipeline_table_default_entry_add(p, table_id[i],
+			&default_entry, &default_entry_ptr))
+			rte_panic("%s: Unable to add default entry to "
+				"table %u\n", __func__, table_id[i]);
+	}
+
+	/* Enable input ports */
+	for (i = 0; i < app.n_ports; i++)
+		if (rte_pipeline_port_in_enable(p, port_in_id[i]))
+			rte_panic("Unable to enable input port %u\n",
+				port_in_id[i]);
+
+	/* Check pipeline consistency */
+	if (rte_pipeline_check(p) < 0)
+		rte_panic("%s: Pipeline consistency check failed\n", __func__);
+
+	/* Run-time */
+	for (i = 0; ; i++) {
+		rte_pipeline_run(p);
+
+		if ((i & APP_FLUSH) == 0)
+			rte_pipeline_flush(p);
+	}
+}
+
+void
+app_main_loop_passthrough(void) {
+	struct app_mbuf_array *m;
+	uint32_t i;
+
+	uint32_t core_id = rte_lcore_id();
+	struct app_core_params *core_params = app_get_core_params(core_id);
+
+	if ((core_params == NULL) || (core_params->core_type != APP_CORE_PT))
+		rte_panic("Core %u misconfiguration\n", core_id);
+
+	RTE_LOG(INFO, USER1, "Core %u is doing pass-through (no pipeline)\n",
+		core_id);
+
+	m = rte_malloc_socket(NULL, sizeof(struct app_mbuf_array),
+		RTE_CACHE_LINE_SIZE, rte_socket_id());
+	if (m == NULL)
+		rte_panic("%s: cannot allocate buffer space\n", __func__);
+
+	for (i = 0; ; i = ((i + 1) & (app.n_ports - 1))) {
+		int ret;
+
+		ret = rte_ring_sc_dequeue_bulk(
+			app.rings[core_params->swq_in[i]],
+			(void **) m->array,
+			app.bsz_swq_rd);
+
+		if (ret == -ENOENT)
+			continue;
+
+		do {
+			ret = rte_ring_sp_enqueue_bulk(
+				app.rings[core_params->swq_out[i]],
+				(void **) m->array,
+				app.bsz_swq_wr);
+		} while (ret < 0);
+	}
+}
diff --git a/examples/ip_pipeline/pipeline/pipeline_routing.c b/examples/ip_pipeline/pipeline/pipeline_routing.c
new file mode 100644
index 0000000..b1ce624
--- /dev/null
+++ b/examples/ip_pipeline/pipeline/pipeline_routing.c
@@ -0,0 +1,474 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#include <rte_malloc.h>
+#include <rte_log.h>
+#include <rte_ethdev.h>
+#include <rte_ether.h>
+#include <rte_ip.h>
+#include <rte_byteorder.h>
+
+#include <rte_port_ring.h>
+#include <rte_table_lpm.h>
+#include <rte_table_hash.h>
+#include <rte_pipeline.h>
+
+#include "main.h"
+
+#include <unistd.h>
+
+struct app_routing_table_entry {
+	struct rte_pipeline_table_entry head;
+	uint32_t nh_ip;
+	uint32_t nh_iface;
+};
+
+struct app_arp_table_entry {
+	struct rte_pipeline_table_entry head;
+	struct ether_addr nh_arp;
+};
+
+static inline void
+app_routing_table_write_metadata(
+	struct rte_mbuf *pkt,
+	struct app_routing_table_entry *entry)
+{
+	struct app_pkt_metadata *c =
+		(struct app_pkt_metadata *) RTE_MBUF_METADATA_UINT8_PTR(pkt, 0);
+
+	c->arp_key.nh_ip = entry->nh_ip;
+	c->arp_key.nh_iface = entry->nh_iface;
+}
+
+static int
+app_routing_table_ah(
+	struct rte_mbuf **pkts,
+	uint64_t *pkts_mask,
+	struct rte_pipeline_table_entry **entries,
+	__attribute__((unused)) void *arg)
+{
+	uint64_t pkts_in_mask = *pkts_mask;
+
+	if ((pkts_in_mask & (pkts_in_mask + 1)) == 0) {
+		uint64_t n_pkts = __builtin_popcountll(pkts_in_mask);
+		uint32_t i;
+
+		for (i = 0; i < n_pkts; i++) {
+			struct rte_mbuf *m = pkts[i];
+			struct app_routing_table_entry *a =
+				(struct app_routing_table_entry *) entries[i];
+
+			app_routing_table_write_metadata(m, a);
+		}
+	} else
+		for ( ; pkts_in_mask; ) {
+			struct rte_mbuf *m;
+			struct app_routing_table_entry *a;
+			uint64_t pkt_mask;
+			uint32_t packet_index;
+
+			packet_index = __builtin_ctzll(pkts_in_mask);
+			pkt_mask = 1LLU << packet_index;
+			pkts_in_mask &= ~pkt_mask;
+
+			m = pkts[packet_index];
+			a = (struct app_routing_table_entry *)
+				entries[packet_index];
+			app_routing_table_write_metadata(m, a);
+		}
+
+	return 0;
+}
+
+static inline void
+app_arp_table_write_metadata(
+	struct rte_mbuf *pkt,
+	struct app_arp_table_entry *entry)
+{
+	struct app_pkt_metadata *c =
+		(struct app_pkt_metadata *) RTE_MBUF_METADATA_UINT8_PTR(pkt, 0);
+	ether_addr_copy(&entry->nh_arp, &c->nh_arp);
+}
+
+static int
+app_arp_table_ah(
+	struct rte_mbuf **pkts,
+	uint64_t *pkts_mask,
+	struct rte_pipeline_table_entry **entries,
+	__attribute__((unused)) void *arg)
+{
+	uint64_t pkts_in_mask = *pkts_mask;
+
+	if ((pkts_in_mask & (pkts_in_mask + 1)) == 0) {
+		uint64_t n_pkts = __builtin_popcountll(pkts_in_mask);
+		uint32_t i;
+
+		for (i = 0; i < n_pkts; i++) {
+			struct rte_mbuf *m = pkts[i];
+			struct app_arp_table_entry *a =
+				(struct app_arp_table_entry *) entries[i];
+
+			app_arp_table_write_metadata(m, a);
+		}
+	} else {
+		for ( ; pkts_in_mask; ) {
+			struct rte_mbuf *m;
+			struct app_arp_table_entry *a;
+			uint64_t pkt_mask;
+			uint32_t packet_index;
+
+			packet_index = __builtin_ctzll(pkts_in_mask);
+			pkt_mask = 1LLU << packet_index;
+			pkts_in_mask &= ~pkt_mask;
+
+			m = pkts[packet_index];
+			a = (struct app_arp_table_entry *)
+				entries[packet_index];
+			app_arp_table_write_metadata(m, a);
+		}
+	}
+
+	return 0;
+}
+
+static uint64_t app_arp_table_hash(
+	void *key,
+	__attribute__((unused)) uint32_t key_size,
+	__attribute__((unused)) uint64_t seed)
+{
+	uint32_t *k = (uint32_t *) key;
+
+	return k[1];
+}
+
+struct app_core_routing_message_handle_params {
+	struct rte_ring *ring_req;
+	struct rte_ring *ring_resp;
+	struct rte_pipeline *p;
+	uint32_t *port_out_id;
+	uint32_t routing_table_id;
+	uint32_t arp_table_id;
+};
+
+static void
+app_message_handle(struct app_core_routing_message_handle_params *params);
+
+void
+app_main_loop_pipeline_routing(void) {
+	struct rte_pipeline_params pipeline_params = {
+		.name = "pipeline",
+		.socket_id = rte_socket_id(),
+	};
+
+	struct rte_pipeline *p;
+	uint32_t port_in_id[APP_MAX_PORTS];
+	uint32_t port_out_id[APP_MAX_PORTS];
+	uint32_t routing_table_id, arp_table_id;
+	uint32_t i;
+
+	uint32_t core_id = rte_lcore_id();
+	struct app_core_params *core_params = app_get_core_params(core_id);
+	struct app_core_routing_message_handle_params mh_params;
+
+	if ((core_params == NULL) || (core_params->core_type != APP_CORE_RT))
+		rte_panic("Core %u misconfiguration\n", core_id);
+
+	RTE_LOG(INFO, USER1, "Core %u is doing routing\n", core_id);
+
+	/* Pipeline configuration */
+	p = rte_pipeline_create(&pipeline_params);
+	if (p == NULL)
+		rte_panic("Unable to configure the pipeline\n");
+
+	/* Input port configuration */
+	for (i = 0; i < app.n_ports; i++) {
+		struct rte_port_ring_reader_params port_ring_params = {
+			.ring = app.rings[core_params->swq_in[i]],
+		};
+
+		struct rte_pipeline_port_in_params port_params = {
+			.ops = &rte_port_ring_reader_ops,
+			.arg_create = (void *) &port_ring_params,
+			.f_action = NULL,
+			.arg_ah = NULL,
+			.burst_size = app.bsz_swq_rd,
+		};
+
+		if (rte_pipeline_port_in_create(p, &port_params,
+			&port_in_id[i]))
+			rte_panic("Unable to configure input port for "
+				"ring %d\n", i);
+	}
+
+	/* Output port configuration */
+	for (i = 0; i < app.n_ports; i++) {
+		struct rte_port_ring_writer_params port_ring_params = {
+			.ring = app.rings[core_params->swq_out[i]],
+			.tx_burst_sz = app.bsz_swq_wr,
+		};
+
+		struct rte_pipeline_port_out_params port_params = {
+			.ops = &rte_port_ring_writer_ops,
+			.arg_create = (void *) &port_ring_params,
+			.f_action = NULL,
+			.f_action_bulk = NULL,
+			.arg_ah = NULL,
+		};
+
+		if (rte_pipeline_port_out_create(p, &port_params,
+			&port_out_id[i]))
+			rte_panic("Unable to configure output port for "
+				"ring %d\n", i);
+	}
+
+	/* Routing table configuration */
+	{
+		struct rte_table_lpm_params table_lpm_params = {
+			.n_rules = app.max_routing_rules,
+			.entry_unique_size =
+				sizeof(struct app_routing_table_entry),
+			.offset = __builtin_offsetof(struct app_pkt_metadata,
+				flow_key.ip_dst),
+		};
+
+		struct rte_pipeline_table_params table_params = {
+			.ops = &rte_table_lpm_ops,
+			.arg_create = &table_lpm_params,
+			.f_action_hit = app_routing_table_ah,
+			.f_action_miss = NULL,
+			.arg_ah = NULL,
+			.action_data_size =
+				sizeof(struct app_routing_table_entry) -
+				sizeof(struct rte_pipeline_table_entry),
+		};
+
+		if (rte_pipeline_table_create(p, &table_params,
+			&routing_table_id))
+			rte_panic("Unable to configure the LPM table\n");
+	}
+
+	/* ARP table configuration */
+	{
+		struct rte_table_hash_key8_lru_params table_arp_params = {
+			.n_entries = app.max_arp_rules,
+			.f_hash = app_arp_table_hash,
+			.seed = 0,
+			.signature_offset = 0, /* Unused */
+			.key_offset = __builtin_offsetof(
+				struct app_pkt_metadata, arp_key),
+		};
+
+		struct rte_pipeline_table_params table_params = {
+			.ops = &rte_table_hash_key8_lru_dosig_ops,
+			.arg_create = &table_arp_params,
+			.f_action_hit = app_arp_table_ah,
+			.f_action_miss = NULL,
+			.arg_ah = NULL,
+			.action_data_size = sizeof(struct app_arp_table_entry) -
+				sizeof(struct rte_pipeline_table_entry),
+		};
+
+		if (rte_pipeline_table_create(p, &table_params, &arp_table_id))
+			rte_panic("Unable to configure the ARP table\n");
+	}
+
+	/* Interconnecting ports and tables */
+	for (i = 0; i < app.n_ports; i++) {
+		if (rte_pipeline_port_in_connect_to_table(p, port_in_id[i],
+			routing_table_id))
+			rte_panic("Unable to connect input port %u to "
+				"table %u\n", port_in_id[i],  routing_table_id);
+	}
+
+	/* Enable input ports */
+	for (i = 0; i < app.n_ports; i++)
+		if (rte_pipeline_port_in_enable(p, port_in_id[i]))
+			rte_panic("Unable to enable input port %u\n",
+				port_in_id[i]);
+
+	/* Check pipeline consistency */
+	if (rte_pipeline_check(p) < 0)
+		rte_panic("Pipeline consistency check failed\n");
+
+	/* Message handling */
+	mh_params.ring_req =
+		app_get_ring_req(app_get_first_core_id(APP_CORE_RT));
+	mh_params.ring_resp =
+		app_get_ring_resp(app_get_first_core_id(APP_CORE_RT));
+	mh_params.p = p;
+	mh_params.port_out_id = port_out_id;
+	mh_params.routing_table_id = routing_table_id;
+	mh_params.arp_table_id = arp_table_id;
+
+	/* Run-time */
+	for (i = 0; ; i++) {
+		rte_pipeline_run(p);
+
+		if ((i & APP_FLUSH) == 0) {
+			rte_pipeline_flush(p);
+			app_message_handle(&mh_params);
+		}
+	}
+}
+
+void
+app_message_handle(struct app_core_routing_message_handle_params *params)
+{
+	struct rte_ring *ring_req = params->ring_req;
+	struct rte_ring *ring_resp;
+	void *msg;
+	struct app_msg_req *req;
+	struct app_msg_resp *resp;
+	struct rte_pipeline *p;
+	uint32_t *port_out_id;
+	uint32_t routing_table_id, arp_table_id;
+	int result;
+
+	/* Read request message */
+	result = rte_ring_sc_dequeue(ring_req, &msg);
+	if (result != 0)
+		return;
+
+	ring_resp = params->ring_resp;
+	p = params->p;
+	port_out_id = params->port_out_id;
+	routing_table_id = params->routing_table_id;
+	arp_table_id = params->arp_table_id;
+
+	/* Handle request */
+	req = (struct app_msg_req *)rte_ctrlmbuf_data((struct rte_mbuf *)msg);
+	switch (req->type) {
+	case APP_MSG_REQ_PING:
+	{
+		result = 0;
+		break;
+	}
+
+	case APP_MSG_REQ_RT_ADD:
+	{
+		struct app_routing_table_entry entry = {
+			.head = {
+				.action = RTE_PIPELINE_ACTION_TABLE,
+				{.table_id = arp_table_id},
+			},
+			.nh_ip = req->routing_add.nh_ip,
+			.nh_iface = port_out_id[req->routing_add.port],
+		};
+
+		struct rte_table_lpm_key key = {
+			.ip = req->routing_add.ip,
+			.depth = req->routing_add.depth,
+		};
+
+		struct rte_pipeline_table_entry *entry_ptr;
+
+		int key_found;
+
+		result = rte_pipeline_table_entry_add(p, routing_table_id, &key,
+			(struct rte_pipeline_table_entry *) &entry, &key_found,
+			&entry_ptr);
+		break;
+	}
+
+	case APP_MSG_REQ_RT_DEL:
+	{
+		struct rte_table_lpm_key key = {
+			.ip = req->routing_del.ip,
+			.depth = req->routing_del.depth,
+		};
+
+		int key_found;
+
+		result = rte_pipeline_table_entry_delete(p, routing_table_id,
+			&key, &key_found, NULL);
+		break;
+	}
+
+	case APP_MSG_REQ_ARP_ADD:
+	{
+
+		struct app_arp_table_entry entry = {
+			.head = {
+				.action = RTE_PIPELINE_ACTION_PORT,
+				{.port_id =
+					port_out_id[req->arp_add.out_iface]},
+			},
+			.nh_arp = req->arp_add.nh_arp,
+		};
+
+		struct app_arp_key arp_key = {
+			.nh_ip = req->arp_add.nh_ip,
+			.nh_iface = port_out_id[req->arp_add.out_iface],
+		};
+
+		struct rte_pipeline_table_entry *entry_ptr;
+
+		int key_found;
+
+		result = rte_pipeline_table_entry_add(p, arp_table_id, &arp_key,
+			(struct rte_pipeline_table_entry *) &entry, &key_found,
+			&entry_ptr);
+		break;
+	}
+
+	case APP_MSG_REQ_ARP_DEL:
+	{
+		struct app_arp_key arp_key = {
+			.nh_ip = req->arp_del.nh_ip,
+			.nh_iface = port_out_id[req->arp_del.out_iface],
+		};
+
+		int key_found;
+
+		result = rte_pipeline_table_entry_delete(p, arp_table_id,
+			&arp_key, &key_found, NULL);
+		break;
+	}
+
+	default:
+		rte_panic("RT Unrecognized message type (%u)\n", req->type);
+	}
+
+	/* Fill in response message */
+	resp = (struct app_msg_resp *)rte_ctrlmbuf_data((struct rte_mbuf *)msg);
+	resp->result = result;
+
+	/* Send response */
+	do {
+		result = rte_ring_sp_enqueue(ring_resp, msg);
+	} while (result == -ENOBUFS);
+}
diff --git a/examples/ip_pipeline/pipeline_firewall.c b/examples/ip_pipeline/pipeline_firewall.c
deleted file mode 100644
index b70260e..0000000
--- a/examples/ip_pipeline/pipeline_firewall.c
+++ /dev/null
@@ -1,313 +0,0 @@
-/*-
- *   BSD LICENSE
- *
- *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
- *   All rights reserved.
- *
- *   Redistribution and use in source and binary forms, with or without
- *   modification, are permitted provided that the following conditions
- *   are met:
- *
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in
- *       the documentation and/or other materials provided with the
- *       distribution.
- *     * Neither the name of Intel Corporation nor the names of its
- *       contributors may be used to endorse or promote products derived
- *       from this software without specific prior written permission.
- *
- *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-
-#include <rte_malloc.h>
-#include <rte_log.h>
-#include <rte_ethdev.h>
-#include <rte_ether.h>
-#include <rte_ip.h>
-#include <rte_byteorder.h>
-
-#include <rte_port_ring.h>
-#include <rte_table_acl.h>
-#include <rte_pipeline.h>
-
-#include "main.h"
-
-struct app_core_firewall_message_handle_params {
-	struct rte_ring *ring_req;
-	struct rte_ring *ring_resp;
-
-	struct rte_pipeline *p;
-	uint32_t *port_out_id;
-	uint32_t table_id;
-};
-
-static void
-app_message_handle(struct app_core_firewall_message_handle_params *params);
-
-enum {
-	PROTO_FIELD_IPV4,
-	SRC_FIELD_IPV4,
-	DST_FIELD_IPV4,
-	SRCP_FIELD_IPV4,
-	DSTP_FIELD_IPV4,
-	NUM_FIELDS_IPV4
-};
-
-struct rte_acl_field_def ipv4_field_formats[NUM_FIELDS_IPV4] = {
-	{
-		.type = RTE_ACL_FIELD_TYPE_BITMASK,
-		.size = sizeof(uint8_t),
-		.field_index = PROTO_FIELD_IPV4,
-		.input_index = PROTO_FIELD_IPV4,
-		.offset = sizeof(struct ether_hdr) +
-			offsetof(struct ipv4_hdr, next_proto_id),
-	},
-	{
-		.type = RTE_ACL_FIELD_TYPE_MASK,
-		.size = sizeof(uint32_t),
-		.field_index = SRC_FIELD_IPV4,
-		.input_index = SRC_FIELD_IPV4,
-		.offset = sizeof(struct ether_hdr) +
-			offsetof(struct ipv4_hdr, src_addr),
-	},
-	{
-		.type = RTE_ACL_FIELD_TYPE_MASK,
-		.size = sizeof(uint32_t),
-		.field_index = DST_FIELD_IPV4,
-		.input_index = DST_FIELD_IPV4,
-		.offset = sizeof(struct ether_hdr) +
-			offsetof(struct ipv4_hdr, dst_addr),
-	},
-	{
-		.type = RTE_ACL_FIELD_TYPE_RANGE,
-		.size = sizeof(uint16_t),
-		.field_index = SRCP_FIELD_IPV4,
-		.input_index = SRCP_FIELD_IPV4,
-		.offset = sizeof(struct ether_hdr) + sizeof(struct ipv4_hdr),
-	},
-	{
-		.type = RTE_ACL_FIELD_TYPE_RANGE,
-		.size = sizeof(uint16_t),
-		.field_index = DSTP_FIELD_IPV4,
-		.input_index = SRCP_FIELD_IPV4,
-		.offset = sizeof(struct ether_hdr) + sizeof(struct ipv4_hdr) +
-			sizeof(uint16_t),
-	},
-};
-
-void
-app_main_loop_pipeline_firewall(void) {
-	struct rte_pipeline_params pipeline_params = {
-		.name = "pipeline",
-		.socket_id = rte_socket_id(),
-	};
-
-	struct rte_pipeline *p;
-	uint32_t port_in_id[APP_MAX_PORTS];
-	uint32_t port_out_id[APP_MAX_PORTS];
-	uint32_t table_id;
-	uint32_t i;
-
-	uint32_t core_id = rte_lcore_id();
-	struct app_core_params *core_params = app_get_core_params(core_id);
-	struct app_core_firewall_message_handle_params mh_params;
-
-	if ((core_params == NULL) || (core_params->core_type != APP_CORE_FW))
-		rte_panic("Core %u misconfiguration\n", core_id);
-
-	RTE_LOG(INFO, USER1, "Core %u is doing firewall\n", core_id);
-
-	/* Pipeline configuration */
-	p = rte_pipeline_create(&pipeline_params);
-	if (p == NULL)
-		rte_panic("Unable to configure the pipeline\n");
-
-	/* Input port configuration */
-	for (i = 0; i < app.n_ports; i++) {
-		struct rte_port_ring_reader_params port_ring_params = {
-			.ring = app.rings[core_params->swq_in[i]],
-		};
-
-		struct rte_pipeline_port_in_params port_params = {
-			.ops = &rte_port_ring_reader_ops,
-			.arg_create = (void *) &port_ring_params,
-			.f_action = NULL,
-			.arg_ah = NULL,
-			.burst_size = app.bsz_swq_rd,
-		};
-
-		if (rte_pipeline_port_in_create(p, &port_params,
-			&port_in_id[i]))
-			rte_panic("Unable to configure input port for "
-				"ring %d\n", i);
-	}
-
-	/* Output port configuration */
-	for (i = 0; i < app.n_ports; i++) {
-		struct rte_port_ring_writer_params port_ring_params = {
-			.ring = app.rings[core_params->swq_out[i]],
-			.tx_burst_sz = app.bsz_swq_wr,
-		};
-
-		struct rte_pipeline_port_out_params port_params = {
-			.ops = &rte_port_ring_writer_ops,
-			.arg_create = (void *) &port_ring_params,
-			.f_action = NULL,
-			.f_action_bulk = NULL,
-			.arg_ah = NULL,
-		};
-
-		if (rte_pipeline_port_out_create(p, &port_params,
-			&port_out_id[i]))
-			rte_panic("Unable to configure output port for "
-				"ring %d\n", i);
-	}
-
-	/* Table configuration */
-	{
-		struct rte_table_acl_params table_acl_params = {
-			.name = "test", /* unique identifier for acl contexts */
-			.n_rules = app.max_firewall_rules,
-			.n_rule_fields = DIM(ipv4_field_formats),
-		};
-
-		struct rte_pipeline_table_params table_params = {
-			.ops = &rte_table_acl_ops,
-			.arg_create = &table_acl_params,
-			.f_action_hit = NULL,
-			.f_action_miss = NULL,
-			.arg_ah = NULL,
-			.action_data_size = 0,
-		};
-
-		memcpy(table_acl_params.field_format, ipv4_field_formats,
-			sizeof(ipv4_field_formats));
-
-		if (rte_pipeline_table_create(p, &table_params, &table_id))
-			rte_panic("Unable to configure the ACL table\n");
-	}
-
-	/* Interconnecting ports and tables */
-	for (i = 0; i < app.n_ports; i++)
-		if (rte_pipeline_port_in_connect_to_table(p, port_in_id[i],
-			table_id))
-			rte_panic("Unable to connect input port %u to "
-				"table %u\n", port_in_id[i],  table_id);
-
-	/* Enable input ports */
-	for (i = 0; i < app.n_ports; i++)
-		if (rte_pipeline_port_in_enable(p, port_in_id[i]))
-			rte_panic("Unable to enable input port %u\n",
-				port_in_id[i]);
-
-	/* Check pipeline consistency */
-	if (rte_pipeline_check(p) < 0)
-		rte_panic("Pipeline consistency check failed\n");
-
-	/* Message handling */
-	mh_params.ring_req = app_get_ring_req(
-		app_get_first_core_id(APP_CORE_FW));
-	mh_params.ring_resp = app_get_ring_resp(
-		app_get_first_core_id(APP_CORE_FW));
-	mh_params.p = p;
-	mh_params.port_out_id = port_out_id;
-	mh_params.table_id = table_id;
-
-	/* Run-time */
-	for (i = 0; ; i++) {
-		rte_pipeline_run(p);
-
-		if ((i & APP_FLUSH) == 0) {
-			rte_pipeline_flush(p);
-			app_message_handle(&mh_params);
-		}
-	}
-}
-
-void
-app_message_handle(struct app_core_firewall_message_handle_params *params)
-{
-	struct rte_ring *ring_req = params->ring_req;
-	struct rte_ring *ring_resp;
-	struct rte_mbuf *msg;
-	struct app_msg_req *req;
-	struct app_msg_resp *resp;
-	struct rte_pipeline *p;
-	uint32_t *port_out_id;
-	uint32_t table_id;
-	int result;
-
-	/* Read request message */
-	result = rte_ring_sc_dequeue(ring_req, (void **) &msg);
-	if (result != 0)
-		return;
-
-	ring_resp = params->ring_resp;
-	p = params->p;
-	port_out_id = params->port_out_id;
-	table_id = params->table_id;
-
-	/* Handle request */
-	req = (struct app_msg_req *)rte_ctrlmbuf_data(msg);
-	switch (req->type) {
-	case APP_MSG_REQ_PING:
-	{
-		result = 0;
-		break;
-	}
-
-	case APP_MSG_REQ_FW_ADD:
-	{
-		struct rte_pipeline_table_entry entry = {
-			.action = RTE_PIPELINE_ACTION_PORT,
-			{.port_id = port_out_id[req->firewall_add.port]},
-		};
-
-		struct rte_pipeline_table_entry *entry_ptr;
-
-		int key_found;
-
-		result = rte_pipeline_table_entry_add(p, table_id,
-			&req->firewall_add.add_params, &entry, &key_found,
-			&entry_ptr);
-		break;
-	}
-
-	case APP_MSG_REQ_FW_DEL:
-	{
-		int key_found;
-
-		result = rte_pipeline_table_entry_delete(p, table_id,
-			&req->firewall_del.delete_params, &key_found, NULL);
-		break;
-	}
-
-	default:
-		rte_panic("FW unrecognized message type (%u)\n", req->type);
-	}
-
-	/* Fill in response message */
-	resp = (struct app_msg_resp *)rte_ctrlmbuf_data(msg);
-	resp->result = result;
-
-	/* Send response */
-	do {
-		result = rte_ring_sp_enqueue(ring_resp, (void *) msg);
-	} while (result == -ENOBUFS);
-}
diff --git a/examples/ip_pipeline/pipeline_flow_classification.c b/examples/ip_pipeline/pipeline_flow_classification.c
deleted file mode 100644
index cc0cbf1..0000000
--- a/examples/ip_pipeline/pipeline_flow_classification.c
+++ /dev/null
@@ -1,306 +0,0 @@
-/*-
- *   BSD LICENSE
- *
- *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
- *   All rights reserved.
- *
- *   Redistribution and use in source and binary forms, with or without
- *   modification, are permitted provided that the following conditions
- *   are met:
- *
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in
- *       the documentation and/or other materials provided with the
- *       distribution.
- *     * Neither the name of Intel Corporation nor the names of its
- *       contributors may be used to endorse or promote products derived
- *       from this software without specific prior written permission.
- *
- *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-
-#include <rte_malloc.h>
-#include <rte_log.h>
-#include <rte_ethdev.h>
-#include <rte_ether.h>
-#include <rte_ip.h>
-#include <rte_byteorder.h>
-
-#include <rte_port_ring.h>
-#include <rte_table_hash.h>
-#include <rte_pipeline.h>
-
-#include "main.h"
-
-struct app_core_fc_message_handle_params {
-	struct rte_ring *ring_req;
-	struct rte_ring *ring_resp;
-
-	struct rte_pipeline *p;
-	uint32_t *port_out_id;
-	uint32_t table_id;
-};
-
-static void
-app_message_handle(struct app_core_fc_message_handle_params *params);
-
-static int app_flow_classification_table_init(
-	struct rte_pipeline *p,
-	uint32_t *port_out_id,
-	uint32_t table_id)
-{
-	struct app_flow_key flow_key;
-	uint32_t i;
-
-	/* Add entries to tables */
-	for (i = 0; i < (1 << 24); i++) {
-		struct rte_pipeline_table_entry entry = {
-			.action = RTE_PIPELINE_ACTION_PORT,
-			{.port_id = port_out_id[i & (app.n_ports - 1)]},
-		};
-		struct rte_pipeline_table_entry *entry_ptr;
-		int key_found, status;
-
-		flow_key.ttl = 0;
-		flow_key.proto = 6; /* TCP */
-		flow_key.header_checksum = 0;
-		flow_key.ip_src = 0;
-		flow_key.ip_dst = rte_bswap32(i);
-		flow_key.port_src = 0;
-		flow_key.port_dst = 0;
-
-		status = rte_pipeline_table_entry_add(p, table_id,
-			(void *) &flow_key, &entry, &key_found, &entry_ptr);
-		if (status < 0)
-			rte_panic("Unable to add entry to table %u (%d)\n",
-				table_id, status);
-	}
-
-	return 0;
-}
-
-void
-app_main_loop_pipeline_flow_classification(void) {
-	struct rte_pipeline_params pipeline_params = {
-		.name = "pipeline",
-		.socket_id = rte_socket_id(),
-	};
-
-	struct rte_pipeline *p;
-	uint32_t port_in_id[APP_MAX_PORTS];
-	uint32_t port_out_id[APP_MAX_PORTS];
-	uint32_t table_id;
-	uint32_t i;
-
-	uint32_t core_id = rte_lcore_id();
-	struct app_core_params *core_params = app_get_core_params(core_id);
-	struct app_core_fc_message_handle_params mh_params;
-
-	if ((core_params == NULL) || (core_params->core_type != APP_CORE_FC))
-		rte_panic("Core %u misconfiguration\n", core_id);
-
-	RTE_LOG(INFO, USER1, "Core %u is doing flow classification "
-		"(pipeline with hash table, 16-byte key, LRU)\n", core_id);
-
-	/* Pipeline configuration */
-	p = rte_pipeline_create(&pipeline_params);
-	if (p == NULL)
-		rte_panic("Unable to configure the pipeline\n");
-
-	/* Input port configuration */
-	for (i = 0; i < app.n_ports; i++) {
-		struct rte_port_ring_reader_params port_ring_params = {
-			.ring = app.rings[core_params->swq_in[i]],
-		};
-
-		struct rte_pipeline_port_in_params port_params = {
-			.ops = &rte_port_ring_reader_ops,
-			.arg_create = (void *) &port_ring_params,
-			.f_action = NULL,
-			.arg_ah = NULL,
-			.burst_size = app.bsz_swq_rd,
-		};
-
-		if (rte_pipeline_port_in_create(p, &port_params,
-			&port_in_id[i]))
-			rte_panic("Unable to configure input port for "
-				"ring %d\n", i);
-	}
-
-	/* Output port configuration */
-	for (i = 0; i < app.n_ports; i++) {
-		struct rte_port_ring_writer_params port_ring_params = {
-			.ring = app.rings[core_params->swq_out[i]],
-			.tx_burst_sz = app.bsz_swq_wr,
-		};
-
-		struct rte_pipeline_port_out_params port_params = {
-			.ops = &rte_port_ring_writer_ops,
-			.arg_create = (void *) &port_ring_params,
-			.f_action = NULL,
-			.f_action_bulk = NULL,
-			.arg_ah = NULL,
-		};
-
-		if (rte_pipeline_port_out_create(p, &port_params,
-			&port_out_id[i]))
-			rte_panic("Unable to configure output port for "
-				"ring %d\n", i);
-	}
-
-	/* Table configuration */
-	{
-		struct rte_table_hash_key16_lru_params table_hash_params = {
-			.n_entries = 1 << 24,
-			.signature_offset = __builtin_offsetof(
-				struct app_pkt_metadata, signature),
-			.key_offset = __builtin_offsetof(
-				struct app_pkt_metadata, flow_key),
-			.f_hash = test_hash,
-			.seed = 0,
-		};
-
-		struct rte_pipeline_table_params table_params = {
-			.ops = &rte_table_hash_key16_lru_ops,
-			.arg_create = &table_hash_params,
-			.f_action_hit = NULL,
-			.f_action_miss = NULL,
-			.arg_ah = NULL,
-			.action_data_size = 0,
-		};
-
-		if (rte_pipeline_table_create(p, &table_params, &table_id))
-			rte_panic("Unable to configure the hash table\n");
-	}
-
-	/* Interconnecting ports and tables */
-	for (i = 0; i < app.n_ports; i++)
-		if (rte_pipeline_port_in_connect_to_table(p, port_in_id[i],
-			table_id))
-			rte_panic("Unable to connect input port %u to "
-				"table %u\n", port_in_id[i],  table_id);
-
-	/* Enable input ports */
-	for (i = 0; i < app.n_ports; i++)
-		if (rte_pipeline_port_in_enable(p, port_in_id[i]))
-			rte_panic("Unable to enable input port %u\n",
-				port_in_id[i]);
-
-	/* Check pipeline consistency */
-	if (rte_pipeline_check(p) < 0)
-		rte_panic("Pipeline consistency check failed\n");
-
-	/* Message handling */
-	mh_params.ring_req = app_get_ring_req(
-		app_get_first_core_id(APP_CORE_FC));
-	mh_params.ring_resp = app_get_ring_resp(
-		app_get_first_core_id(APP_CORE_FC));
-	mh_params.p = p;
-	mh_params.port_out_id = port_out_id;
-	mh_params.table_id = table_id;
-
-	/* Run-time */
-	for (i = 0; ; i++) {
-		rte_pipeline_run(p);
-
-		if ((i & APP_FLUSH) == 0) {
-			rte_pipeline_flush(p);
-			app_message_handle(&mh_params);
-		}
-	}
-}
-
-void
-app_message_handle(struct app_core_fc_message_handle_params *params)
-{
-	struct rte_ring *ring_req = params->ring_req;
-	struct rte_ring *ring_resp;
-	void *msg;
-	struct app_msg_req *req;
-	struct app_msg_resp *resp;
-	struct rte_pipeline *p;
-	uint32_t *port_out_id;
-	uint32_t table_id;
-	int result;
-
-	/* Read request message */
-	result = rte_ring_sc_dequeue(ring_req, &msg);
-	if (result != 0)
-		return;
-
-	ring_resp = params->ring_resp;
-	p = params->p;
-	port_out_id = params->port_out_id;
-	table_id = params->table_id;
-
-	/* Handle request */
-	req = (struct app_msg_req *)rte_ctrlmbuf_data((struct rte_mbuf *)msg);
-	switch (req->type) {
-	case APP_MSG_REQ_PING:
-	{
-		result = 0;
-		break;
-	}
-
-	case APP_MSG_REQ_FC_ADD_ALL:
-	{
-		result = app_flow_classification_table_init(p, port_out_id,
-			table_id);
-		break;
-	}
-
-	case APP_MSG_REQ_FC_ADD:
-	{
-		struct rte_pipeline_table_entry entry = {
-			.action = RTE_PIPELINE_ACTION_PORT,
-			{.port_id = port_out_id[req->flow_classif_add.port]},
-		};
-
-		struct rte_pipeline_table_entry *entry_ptr;
-
-		int key_found;
-
-		result = rte_pipeline_table_entry_add(p, table_id,
-			req->flow_classif_add.key_raw, &entry, &key_found,
-			&entry_ptr);
-		break;
-	}
-
-	case APP_MSG_REQ_FC_DEL:
-	{
-		int key_found;
-
-		result = rte_pipeline_table_entry_delete(p, table_id,
-			req->flow_classif_add.key_raw, &key_found, NULL);
-		break;
-	}
-
-	default:
-		rte_panic("FC Unrecognized message type (%u)\n", req->type);
-	}
-
-	/* Fill in response message */
-	resp = (struct app_msg_resp *)rte_ctrlmbuf_data((struct rte_mbuf *)msg);
-	resp->result = result;
-
-	/* Send response */
-	do {
-		result = rte_ring_sp_enqueue(ring_resp, msg);
-	} while (result == -ENOBUFS);
-}
diff --git a/examples/ip_pipeline/pipeline_ipv4_frag.c b/examples/ip_pipeline/pipeline_ipv4_frag.c
deleted file mode 100644
index e799206..0000000
--- a/examples/ip_pipeline/pipeline_ipv4_frag.c
+++ /dev/null
@@ -1,184 +0,0 @@
-/*-
- *   BSD LICENSE
- *
- *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
- *   All rights reserved.
- *
- *   Redistribution and use in source and binary forms, with or without
- *   modification, are permitted provided that the following conditions
- *   are met:
- *
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in
- *       the documentation and/or other materials provided with the
- *       distribution.
- *     * Neither the name of Intel Corporation nor the names of its
- *       contributors may be used to endorse or promote products derived
- *       from this software without specific prior written permission.
- *
- *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-
-#include <rte_common.h>
-#include <rte_byteorder.h>
-#include <rte_log.h>
-#include <rte_malloc.h>
-#include <rte_ethdev.h>
-#include <rte_mbuf.h>
-#include <rte_ether.h>
-#include <rte_ip.h>
-
-#include <rte_port_ethdev.h>
-#include <rte_port_ring.h>
-#include <rte_port_frag.h>
-#include <rte_table_stub.h>
-#include <rte_pipeline.h>
-
-#include "main.h"
-
-void
-app_main_loop_pipeline_ipv4_frag(void) {
-	struct rte_pipeline *p;
-	uint32_t port_in_id[APP_MAX_PORTS];
-	uint32_t port_out_id[APP_MAX_PORTS];
-	uint32_t table_id[APP_MAX_PORTS];
-	uint32_t i;
-
-	uint32_t core_id = rte_lcore_id();
-	struct app_core_params *core_params = app_get_core_params(core_id);
-
-	if ((core_params == NULL) ||
-		(core_params->core_type != APP_CORE_IPV4_FRAG))
-		rte_panic("Core %u misconfiguration\n", core_id);
-
-	RTE_LOG(INFO, USER1, "Core %u is doing IPv4 fragmentation\n", core_id);
-
-	/* Pipeline configuration */
-	struct rte_pipeline_params pipeline_params = {
-		.name = "pipeline",
-		.socket_id = rte_socket_id(),
-	};
-
-	p = rte_pipeline_create(&pipeline_params);
-	if (p == NULL)
-		rte_panic("%s: Unable to configure the pipeline\n", __func__);
-
-	/* Input port configuration */
-	for (i = 0; i < app.n_ports; i++) {
-		struct rte_port_ring_reader_ipv4_frag_params
-			port_frag_params = {
-			.ring = app.rings[core_params->swq_in[i]],
-			.mtu = 1500,
-			.metadata_size = sizeof(struct app_pkt_metadata),
-			.pool_direct = app.pool,
-			.pool_indirect = app.indirect_pool,
-		};
-
-		struct rte_pipeline_port_in_params port_params = {
-			.ops = &rte_port_ring_reader_ipv4_frag_ops,
-			.arg_create = (void *) &port_frag_params,
-			.f_action = NULL,
-			.arg_ah = NULL,
-			.burst_size = app.bsz_swq_rd,
-		};
-
-		if (rte_pipeline_port_in_create(p, &port_params,
-			&port_in_id[i]))
-			rte_panic("%s: Unable to configure input port %i\n",
-				__func__, i);
-	}
-
-	/* Output port configuration */
-	for (i = 0; i < app.n_ports; i++) {
-		struct rte_port_ring_writer_params port_ring_params = {
-			.ring = app.rings[core_params->swq_out[i]],
-			.tx_burst_sz = app.bsz_swq_wr,
-		};
-
-		struct rte_pipeline_port_out_params port_params = {
-			.ops = &rte_port_ring_writer_ops,
-			.arg_create = (void *) &port_ring_params,
-			.f_action = NULL,
-			.f_action_bulk = NULL,
-			.arg_ah = NULL,
-		};
-
-		if (rte_pipeline_port_out_create(p, &port_params,
-			&port_out_id[i]))
-			rte_panic("%s: Unable to configure output port %i\n",
-				__func__, i);
-	}
-
-	/* Table configuration */
-	for (i = 0; i < app.n_ports; i++) {
-		struct rte_pipeline_table_params table_params = {
-			.ops = &rte_table_stub_ops,
-			.arg_create = NULL,
-			.f_action_hit = NULL,
-			.f_action_miss = NULL,
-			.arg_ah = NULL,
-			.action_data_size = 0,
-		};
-
-		if (rte_pipeline_table_create(p, &table_params, &table_id[i]))
-			rte_panic("%s: Unable to configure table %u\n",
-				__func__, table_id[i]);
-	}
-
-	/* Interconnecting ports and tables */
-	for (i = 0; i < app.n_ports; i++)
-		if (rte_pipeline_port_in_connect_to_table(p, port_in_id[i],
-			table_id[i]))
-			rte_panic("%s: Unable to connect input port %u to "
-				"table %u\n", __func__, port_in_id[i],
-				table_id[i]);
-
-	/* Add entries to tables */
-	for (i = 0; i < app.n_ports; i++) {
-		struct rte_pipeline_table_entry default_entry = {
-			.action = RTE_PIPELINE_ACTION_PORT,
-			{.port_id = port_out_id[i]},
-		};
-
-		struct rte_pipeline_table_entry *default_entry_ptr;
-
-		if (rte_pipeline_table_default_entry_add(p, table_id[i],
-			&default_entry, &default_entry_ptr))
-			rte_panic("%s: Unable to add default entry to "
-				"table %u\n", __func__, table_id[i]);
-	}
-
-	/* Enable input ports */
-	for (i = 0; i < app.n_ports; i++)
-		if (rte_pipeline_port_in_enable(p, port_in_id[i]))
-			rte_panic("Unable to enable input port %u\n",
-				port_in_id[i]);
-
-	/* Check pipeline consistency */
-	if (rte_pipeline_check(p) < 0)
-		rte_panic("%s: Pipeline consistency check failed\n", __func__);
-
-	/* Run-time */
-	for (i = 0; ; i++) {
-		rte_pipeline_run(p);
-
-		if ((i & APP_FLUSH) == 0)
-			rte_pipeline_flush(p);
-	}
-}
diff --git a/examples/ip_pipeline/pipeline_ipv4_ras.c b/examples/ip_pipeline/pipeline_ipv4_ras.c
deleted file mode 100644
index 2d6611c..0000000
--- a/examples/ip_pipeline/pipeline_ipv4_ras.c
+++ /dev/null
@@ -1,181 +0,0 @@
-/*-
- *   BSD LICENSE
- *
- *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
- *   All rights reserved.
- *
- *   Redistribution and use in source and binary forms, with or without
- *   modification, are permitted provided that the following conditions
- *   are met:
- *
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in
- *       the documentation and/or other materials provided with the
- *       distribution.
- *     * Neither the name of Intel Corporation nor the names of its
- *       contributors may be used to endorse or promote products derived
- *       from this software without specific prior written permission.
- *
- *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-
-#include <rte_common.h>
-#include <rte_byteorder.h>
-#include <rte_log.h>
-#include <rte_malloc.h>
-#include <rte_ethdev.h>
-#include <rte_mbuf.h>
-#include <rte_ether.h>
-#include <rte_ip.h>
-
-#include <rte_port_ethdev.h>
-#include <rte_port_ring.h>
-#include <rte_port_ras.h>
-#include <rte_table_stub.h>
-#include <rte_pipeline.h>
-
-#include "main.h"
-
-void
-app_main_loop_pipeline_ipv4_ras(void) {
-	struct rte_pipeline *p;
-	uint32_t port_in_id[APP_MAX_PORTS];
-	uint32_t port_out_id[APP_MAX_PORTS];
-	uint32_t table_id[APP_MAX_PORTS];
-	uint32_t i;
-
-	uint32_t core_id = rte_lcore_id();
-	struct app_core_params *core_params = app_get_core_params(core_id);
-
-	if ((core_params == NULL) ||
-		(core_params->core_type != APP_CORE_IPV4_RAS)) {
-		rte_panic("Core %u misconfiguration\n", core_id);
-	}
-
-	RTE_LOG(INFO, USER1, "Core %u is doing IPv4 reassembly\n", core_id);
-
-	/* Pipeline configuration */
-	struct rte_pipeline_params pipeline_params = {
-		.name = "pipeline",
-		.socket_id = rte_socket_id(),
-	};
-
-	p = rte_pipeline_create(&pipeline_params);
-	if (p == NULL)
-		rte_panic("%s: Unable to configure the pipeline\n", __func__);
-
-	/* Input port configuration */
-	for (i = 0; i < app.n_ports; i++) {
-		struct rte_port_ring_reader_params port_ring_params = {
-			.ring = app.rings[core_params->swq_in[i]],
-		};
-
-		struct rte_pipeline_port_in_params port_params = {
-			.ops = &rte_port_ring_reader_ops,
-			.arg_create = (void *) &port_ring_params,
-			.f_action = NULL,
-			.arg_ah = NULL,
-			.burst_size = app.bsz_swq_rd,
-		};
-
-		if (rte_pipeline_port_in_create(p, &port_params,
-			&port_in_id[i]))
-			rte_panic("%s: Unable to configure input port %i\n",
-				__func__, i);
-	}
-
-	/* Output port configuration */
-	for (i = 0; i < app.n_ports; i++) {
-		struct rte_port_ring_writer_params port_ring_ipv4_ras_params = {
-			.ring = app.rings[core_params->swq_out[i]],
-			.tx_burst_sz = app.bsz_swq_wr,
-		};
-
-		struct rte_pipeline_port_out_params port_params = {
-			.ops = &rte_port_ring_writer_ipv4_ras_ops,
-			.arg_create = (void *) &port_ring_ipv4_ras_params,
-			.f_action = NULL,
-			.f_action_bulk = NULL,
-			.arg_ah = NULL,
-		};
-
-		if (rte_pipeline_port_out_create(p, &port_params,
-			&port_out_id[i]))
-			rte_panic("%s: Unable to configure output port %i\n",
-				__func__, i);
-	}
-
-	/* Table configuration */
-	for (i = 0; i < app.n_ports; i++) {
-		struct rte_pipeline_table_params table_params = {
-			.ops = &rte_table_stub_ops,
-			.arg_create = NULL,
-			.f_action_hit = NULL,
-			.f_action_miss = NULL,
-			.arg_ah = NULL,
-			.action_data_size = 0,
-		};
-
-		if (rte_pipeline_table_create(p, &table_params, &table_id[i]))
-			rte_panic("%s: Unable to configure table %u\n",
-				__func__, table_id[i]);
-	}
-
-	/* Interconnecting ports and tables */
-	for (i = 0; i < app.n_ports; i++)
-		if (rte_pipeline_port_in_connect_to_table(p, port_in_id[i],
-			table_id[i]))
-			rte_panic("%s: Unable to connect input port %u to "
-				"table %u\n", __func__, port_in_id[i],
-				table_id[i]);
-
-	/* Add entries to tables */
-	for (i = 0; i < app.n_ports; i++) {
-		struct rte_pipeline_table_entry default_entry = {
-			.action = RTE_PIPELINE_ACTION_PORT,
-			{.port_id = port_out_id[i]},
-		};
-
-		struct rte_pipeline_table_entry *default_entry_ptr;
-
-		if (rte_pipeline_table_default_entry_add(p, table_id[i],
-			&default_entry,
-			&default_entry_ptr))
-			rte_panic("%s: Unable to add default entry to "
-				"table %u\n", __func__, table_id[i]);
-	}
-
-	/* Enable input ports */
-	for (i = 0; i < app.n_ports; i++)
-		if (rte_pipeline_port_in_enable(p, port_in_id[i]))
-			rte_panic("Unable to enable input port %u\n",
-				port_in_id[i]);
-
-	/* Check pipeline consistency */
-	if (rte_pipeline_check(p) < 0)
-		rte_panic("%s: Pipeline consistency check failed\n", __func__);
-
-	/* Run-time */
-	for (i = 0; ; i++) {
-		rte_pipeline_run(p);
-
-		if ((i & APP_FLUSH) == 0)
-			rte_pipeline_flush(p);
-	}
-}
diff --git a/examples/ip_pipeline/pipeline_passthrough.c b/examples/ip_pipeline/pipeline_passthrough.c
deleted file mode 100644
index 948b2c1..0000000
--- a/examples/ip_pipeline/pipeline_passthrough.c
+++ /dev/null
@@ -1,213 +0,0 @@
-/*-
- *   BSD LICENSE
- *
- *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
- *   All rights reserved.
- *
- *   Redistribution and use in source and binary forms, with or without
- *   modification, are permitted provided that the following conditions
- *   are met:
- *
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in
- *       the documentation and/or other materials provided with the
- *       distribution.
- *     * Neither the name of Intel Corporation nor the names of its
- *       contributors may be used to endorse or promote products derived
- *       from this software without specific prior written permission.
- *
- *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-
-#include <rte_malloc.h>
-#include <rte_log.h>
-
-#include <rte_port_ring.h>
-#include <rte_table_stub.h>
-#include <rte_pipeline.h>
-
-#include "main.h"
-
-void
-app_main_loop_pipeline_passthrough(void) {
-	struct rte_pipeline_params pipeline_params = {
-		.name = "pipeline",
-		.socket_id = rte_socket_id(),
-	};
-
-	struct rte_pipeline *p;
-	uint32_t port_in_id[APP_MAX_PORTS];
-	uint32_t port_out_id[APP_MAX_PORTS];
-	uint32_t table_id[APP_MAX_PORTS];
-	uint32_t i;
-
-	uint32_t core_id = rte_lcore_id();
-	struct app_core_params *core_params = app_get_core_params(core_id);
-
-	if ((core_params == NULL) || (core_params->core_type != APP_CORE_PT))
-		rte_panic("Core %u misconfiguration\n", core_id);
-
-	RTE_LOG(INFO, USER1, "Core %u is doing pass-through\n", core_id);
-
-	/* Pipeline configuration */
-	p = rte_pipeline_create(&pipeline_params);
-	if (p == NULL)
-		rte_panic("%s: Unable to configure the pipeline\n", __func__);
-
-	/* Input port configuration */
-	for (i = 0; i < app.n_ports; i++) {
-		struct rte_port_ring_reader_params port_ring_params = {
-			.ring = app.rings[core_params->swq_in[i]],
-		};
-
-		struct rte_pipeline_port_in_params port_params = {
-			.ops = &rte_port_ring_reader_ops,
-			.arg_create = (void *) &port_ring_params,
-			.f_action = NULL,
-			.arg_ah = NULL,
-			.burst_size = app.bsz_swq_rd,
-		};
-
-		if (rte_pipeline_port_in_create(p, &port_params,
-			&port_in_id[i])) {
-			rte_panic("%s: Unable to configure input port for "
-				"ring %d\n", __func__, i);
-		}
-	}
-
-	/* Output port configuration */
-	for (i = 0; i < app.n_ports; i++) {
-		struct rte_port_ring_writer_params port_ring_params = {
-			.ring = app.rings[core_params->swq_out[i]],
-			.tx_burst_sz = app.bsz_swq_wr,
-		};
-
-		struct rte_pipeline_port_out_params port_params = {
-			.ops = &rte_port_ring_writer_ops,
-			.arg_create = (void *) &port_ring_params,
-			.f_action = NULL,
-			.f_action_bulk = NULL,
-			.arg_ah = NULL,
-		};
-
-		if (rte_pipeline_port_out_create(p, &port_params,
-			&port_out_id[i])) {
-			rte_panic("%s: Unable to configure output port for "
-				"ring %d\n", __func__, i);
-		}
-	}
-
-	/* Table configuration */
-	for (i = 0; i < app.n_ports; i++) {
-		struct rte_pipeline_table_params table_params = {
-			.ops = &rte_table_stub_ops,
-			.arg_create = NULL,
-			.f_action_hit = NULL,
-			.f_action_miss = NULL,
-			.arg_ah = NULL,
-			.action_data_size = 0,
-		};
-
-		if (rte_pipeline_table_create(p, &table_params, &table_id[i]))
-			rte_panic("%s: Unable to configure table %u\n",
-				__func__, i);
-	}
-
-	/* Interconnecting ports and tables */
-	for (i = 0; i < app.n_ports; i++) {
-		if (rte_pipeline_port_in_connect_to_table(p, port_in_id[i],
-			table_id[i])) {
-			rte_panic("%s: Unable to connect input port %u to "
-				"table %u\n", __func__, port_in_id[i],
-				table_id[i]);
-		}
-	}
-
-	/* Add entries to tables */
-	for (i = 0; i < app.n_ports; i++) {
-		struct rte_pipeline_table_entry default_entry = {
-			.action = RTE_PIPELINE_ACTION_PORT,
-			{.port_id = port_out_id[i]},
-		};
-
-		struct rte_pipeline_table_entry *default_entry_ptr;
-
-		if (rte_pipeline_table_default_entry_add(p, table_id[i],
-			&default_entry, &default_entry_ptr))
-			rte_panic("%s: Unable to add default entry to "
-				"table %u\n", __func__, table_id[i]);
-	}
-
-	/* Enable input ports */
-	for (i = 0; i < app.n_ports; i++)
-		if (rte_pipeline_port_in_enable(p, port_in_id[i]))
-			rte_panic("Unable to enable input port %u\n",
-				port_in_id[i]);
-
-	/* Check pipeline consistency */
-	if (rte_pipeline_check(p) < 0)
-		rte_panic("%s: Pipeline consistency check failed\n", __func__);
-
-	/* Run-time */
-	for (i = 0; ; i++) {
-		rte_pipeline_run(p);
-
-		if ((i & APP_FLUSH) == 0)
-			rte_pipeline_flush(p);
-	}
-}
-
-void
-app_main_loop_passthrough(void) {
-	struct app_mbuf_array *m;
-	uint32_t i;
-
-	uint32_t core_id = rte_lcore_id();
-	struct app_core_params *core_params = app_get_core_params(core_id);
-
-	if ((core_params == NULL) || (core_params->core_type != APP_CORE_PT))
-		rte_panic("Core %u misconfiguration\n", core_id);
-
-	RTE_LOG(INFO, USER1, "Core %u is doing pass-through (no pipeline)\n",
-		core_id);
-
-	m = rte_malloc_socket(NULL, sizeof(struct app_mbuf_array),
-		RTE_CACHE_LINE_SIZE, rte_socket_id());
-	if (m == NULL)
-		rte_panic("%s: cannot allocate buffer space\n", __func__);
-
-	for (i = 0; ; i = ((i + 1) & (app.n_ports - 1))) {
-		int ret;
-
-		ret = rte_ring_sc_dequeue_bulk(
-			app.rings[core_params->swq_in[i]],
-			(void **) m->array,
-			app.bsz_swq_rd);
-
-		if (ret == -ENOENT)
-			continue;
-
-		do {
-			ret = rte_ring_sp_enqueue_bulk(
-				app.rings[core_params->swq_out[i]],
-				(void **) m->array,
-				app.bsz_swq_wr);
-		} while (ret < 0);
-	}
-}
diff --git a/examples/ip_pipeline/pipeline_routing.c b/examples/ip_pipeline/pipeline_routing.c
deleted file mode 100644
index b1ce624..0000000
--- a/examples/ip_pipeline/pipeline_routing.c
+++ /dev/null
@@ -1,474 +0,0 @@
-/*-
- *   BSD LICENSE
- *
- *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
- *   All rights reserved.
- *
- *   Redistribution and use in source and binary forms, with or without
- *   modification, are permitted provided that the following conditions
- *   are met:
- *
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in
- *       the documentation and/or other materials provided with the
- *       distribution.
- *     * Neither the name of Intel Corporation nor the names of its
- *       contributors may be used to endorse or promote products derived
- *       from this software without specific prior written permission.
- *
- *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-
-#include <rte_malloc.h>
-#include <rte_log.h>
-#include <rte_ethdev.h>
-#include <rte_ether.h>
-#include <rte_ip.h>
-#include <rte_byteorder.h>
-
-#include <rte_port_ring.h>
-#include <rte_table_lpm.h>
-#include <rte_table_hash.h>
-#include <rte_pipeline.h>
-
-#include "main.h"
-
-#include <unistd.h>
-
-struct app_routing_table_entry {
-	struct rte_pipeline_table_entry head;
-	uint32_t nh_ip;
-	uint32_t nh_iface;
-};
-
-struct app_arp_table_entry {
-	struct rte_pipeline_table_entry head;
-	struct ether_addr nh_arp;
-};
-
-static inline void
-app_routing_table_write_metadata(
-	struct rte_mbuf *pkt,
-	struct app_routing_table_entry *entry)
-{
-	struct app_pkt_metadata *c =
-		(struct app_pkt_metadata *) RTE_MBUF_METADATA_UINT8_PTR(pkt, 0);
-
-	c->arp_key.nh_ip = entry->nh_ip;
-	c->arp_key.nh_iface = entry->nh_iface;
-}
-
-static int
-app_routing_table_ah(
-	struct rte_mbuf **pkts,
-	uint64_t *pkts_mask,
-	struct rte_pipeline_table_entry **entries,
-	__attribute__((unused)) void *arg)
-{
-	uint64_t pkts_in_mask = *pkts_mask;
-
-	if ((pkts_in_mask & (pkts_in_mask + 1)) == 0) {
-		uint64_t n_pkts = __builtin_popcountll(pkts_in_mask);
-		uint32_t i;
-
-		for (i = 0; i < n_pkts; i++) {
-			struct rte_mbuf *m = pkts[i];
-			struct app_routing_table_entry *a =
-				(struct app_routing_table_entry *) entries[i];
-
-			app_routing_table_write_metadata(m, a);
-		}
-	} else
-		for ( ; pkts_in_mask; ) {
-			struct rte_mbuf *m;
-			struct app_routing_table_entry *a;
-			uint64_t pkt_mask;
-			uint32_t packet_index;
-
-			packet_index = __builtin_ctzll(pkts_in_mask);
-			pkt_mask = 1LLU << packet_index;
-			pkts_in_mask &= ~pkt_mask;
-
-			m = pkts[packet_index];
-			a = (struct app_routing_table_entry *)
-				entries[packet_index];
-			app_routing_table_write_metadata(m, a);
-		}
-
-	return 0;
-}
-
-static inline void
-app_arp_table_write_metadata(
-	struct rte_mbuf *pkt,
-	struct app_arp_table_entry *entry)
-{
-	struct app_pkt_metadata *c =
-		(struct app_pkt_metadata *) RTE_MBUF_METADATA_UINT8_PTR(pkt, 0);
-	ether_addr_copy(&entry->nh_arp, &c->nh_arp);
-}
-
-static int
-app_arp_table_ah(
-	struct rte_mbuf **pkts,
-	uint64_t *pkts_mask,
-	struct rte_pipeline_table_entry **entries,
-	__attribute__((unused)) void *arg)
-{
-	uint64_t pkts_in_mask = *pkts_mask;
-
-	if ((pkts_in_mask & (pkts_in_mask + 1)) == 0) {
-		uint64_t n_pkts = __builtin_popcountll(pkts_in_mask);
-		uint32_t i;
-
-		for (i = 0; i < n_pkts; i++) {
-			struct rte_mbuf *m = pkts[i];
-			struct app_arp_table_entry *a =
-				(struct app_arp_table_entry *) entries[i];
-
-			app_arp_table_write_metadata(m, a);
-		}
-	} else {
-		for ( ; pkts_in_mask; ) {
-			struct rte_mbuf *m;
-			struct app_arp_table_entry *a;
-			uint64_t pkt_mask;
-			uint32_t packet_index;
-
-			packet_index = __builtin_ctzll(pkts_in_mask);
-			pkt_mask = 1LLU << packet_index;
-			pkts_in_mask &= ~pkt_mask;
-
-			m = pkts[packet_index];
-			a = (struct app_arp_table_entry *)
-				entries[packet_index];
-			app_arp_table_write_metadata(m, a);
-		}
-	}
-
-	return 0;
-}
-
-static uint64_t app_arp_table_hash(
-	void *key,
-	__attribute__((unused)) uint32_t key_size,
-	__attribute__((unused)) uint64_t seed)
-{
-	uint32_t *k = (uint32_t *) key;
-
-	return k[1];
-}
-
-struct app_core_routing_message_handle_params {
-	struct rte_ring *ring_req;
-	struct rte_ring *ring_resp;
-	struct rte_pipeline *p;
-	uint32_t *port_out_id;
-	uint32_t routing_table_id;
-	uint32_t arp_table_id;
-};
-
-static void
-app_message_handle(struct app_core_routing_message_handle_params *params);
-
-void
-app_main_loop_pipeline_routing(void) {
-	struct rte_pipeline_params pipeline_params = {
-		.name = "pipeline",
-		.socket_id = rte_socket_id(),
-	};
-
-	struct rte_pipeline *p;
-	uint32_t port_in_id[APP_MAX_PORTS];
-	uint32_t port_out_id[APP_MAX_PORTS];
-	uint32_t routing_table_id, arp_table_id;
-	uint32_t i;
-
-	uint32_t core_id = rte_lcore_id();
-	struct app_core_params *core_params = app_get_core_params(core_id);
-	struct app_core_routing_message_handle_params mh_params;
-
-	if ((core_params == NULL) || (core_params->core_type != APP_CORE_RT))
-		rte_panic("Core %u misconfiguration\n", core_id);
-
-	RTE_LOG(INFO, USER1, "Core %u is doing routing\n", core_id);
-
-	/* Pipeline configuration */
-	p = rte_pipeline_create(&pipeline_params);
-	if (p == NULL)
-		rte_panic("Unable to configure the pipeline\n");
-
-	/* Input port configuration */
-	for (i = 0; i < app.n_ports; i++) {
-		struct rte_port_ring_reader_params port_ring_params = {
-			.ring = app.rings[core_params->swq_in[i]],
-		};
-
-		struct rte_pipeline_port_in_params port_params = {
-			.ops = &rte_port_ring_reader_ops,
-			.arg_create = (void *) &port_ring_params,
-			.f_action = NULL,
-			.arg_ah = NULL,
-			.burst_size = app.bsz_swq_rd,
-		};
-
-		if (rte_pipeline_port_in_create(p, &port_params,
-			&port_in_id[i]))
-			rte_panic("Unable to configure input port for "
-				"ring %d\n", i);
-	}
-
-	/* Output port configuration */
-	for (i = 0; i < app.n_ports; i++) {
-		struct rte_port_ring_writer_params port_ring_params = {
-			.ring = app.rings[core_params->swq_out[i]],
-			.tx_burst_sz = app.bsz_swq_wr,
-		};
-
-		struct rte_pipeline_port_out_params port_params = {
-			.ops = &rte_port_ring_writer_ops,
-			.arg_create = (void *) &port_ring_params,
-			.f_action = NULL,
-			.f_action_bulk = NULL,
-			.arg_ah = NULL,
-		};
-
-		if (rte_pipeline_port_out_create(p, &port_params,
-			&port_out_id[i]))
-			rte_panic("Unable to configure output port for "
-				"ring %d\n", i);
-	}
-
-	/* Routing table configuration */
-	{
-		struct rte_table_lpm_params table_lpm_params = {
-			.n_rules = app.max_routing_rules,
-			.entry_unique_size =
-				sizeof(struct app_routing_table_entry),
-			.offset = __builtin_offsetof(struct app_pkt_metadata,
-				flow_key.ip_dst),
-		};
-
-		struct rte_pipeline_table_params table_params = {
-			.ops = &rte_table_lpm_ops,
-			.arg_create = &table_lpm_params,
-			.f_action_hit = app_routing_table_ah,
-			.f_action_miss = NULL,
-			.arg_ah = NULL,
-			.action_data_size =
-				sizeof(struct app_routing_table_entry) -
-				sizeof(struct rte_pipeline_table_entry),
-		};
-
-		if (rte_pipeline_table_create(p, &table_params,
-			&routing_table_id))
-			rte_panic("Unable to configure the LPM table\n");
-	}
-
-	/* ARP table configuration */
-	{
-		struct rte_table_hash_key8_lru_params table_arp_params = {
-			.n_entries = app.max_arp_rules,
-			.f_hash = app_arp_table_hash,
-			.seed = 0,
-			.signature_offset = 0, /* Unused */
-			.key_offset = __builtin_offsetof(
-				struct app_pkt_metadata, arp_key),
-		};
-
-		struct rte_pipeline_table_params table_params = {
-			.ops = &rte_table_hash_key8_lru_dosig_ops,
-			.arg_create = &table_arp_params,
-			.f_action_hit = app_arp_table_ah,
-			.f_action_miss = NULL,
-			.arg_ah = NULL,
-			.action_data_size = sizeof(struct app_arp_table_entry) -
-				sizeof(struct rte_pipeline_table_entry),
-		};
-
-		if (rte_pipeline_table_create(p, &table_params, &arp_table_id))
-			rte_panic("Unable to configure the ARP table\n");
-	}
-
-	/* Interconnecting ports and tables */
-	for (i = 0; i < app.n_ports; i++) {
-		if (rte_pipeline_port_in_connect_to_table(p, port_in_id[i],
-			routing_table_id))
-			rte_panic("Unable to connect input port %u to "
-				"table %u\n", port_in_id[i],  routing_table_id);
-	}
-
-	/* Enable input ports */
-	for (i = 0; i < app.n_ports; i++)
-		if (rte_pipeline_port_in_enable(p, port_in_id[i]))
-			rte_panic("Unable to enable input port %u\n",
-				port_in_id[i]);
-
-	/* Check pipeline consistency */
-	if (rte_pipeline_check(p) < 0)
-		rte_panic("Pipeline consistency check failed\n");
-
-	/* Message handling */
-	mh_params.ring_req =
-		app_get_ring_req(app_get_first_core_id(APP_CORE_RT));
-	mh_params.ring_resp =
-		app_get_ring_resp(app_get_first_core_id(APP_CORE_RT));
-	mh_params.p = p;
-	mh_params.port_out_id = port_out_id;
-	mh_params.routing_table_id = routing_table_id;
-	mh_params.arp_table_id = arp_table_id;
-
-	/* Run-time */
-	for (i = 0; ; i++) {
-		rte_pipeline_run(p);
-
-		if ((i & APP_FLUSH) == 0) {
-			rte_pipeline_flush(p);
-			app_message_handle(&mh_params);
-		}
-	}
-}
-
-void
-app_message_handle(struct app_core_routing_message_handle_params *params)
-{
-	struct rte_ring *ring_req = params->ring_req;
-	struct rte_ring *ring_resp;
-	void *msg;
-	struct app_msg_req *req;
-	struct app_msg_resp *resp;
-	struct rte_pipeline *p;
-	uint32_t *port_out_id;
-	uint32_t routing_table_id, arp_table_id;
-	int result;
-
-	/* Read request message */
-	result = rte_ring_sc_dequeue(ring_req, &msg);
-	if (result != 0)
-		return;
-
-	ring_resp = params->ring_resp;
-	p = params->p;
-	port_out_id = params->port_out_id;
-	routing_table_id = params->routing_table_id;
-	arp_table_id = params->arp_table_id;
-
-	/* Handle request */
-	req = (struct app_msg_req *)rte_ctrlmbuf_data((struct rte_mbuf *)msg);
-	switch (req->type) {
-	case APP_MSG_REQ_PING:
-	{
-		result = 0;
-		break;
-	}
-
-	case APP_MSG_REQ_RT_ADD:
-	{
-		struct app_routing_table_entry entry = {
-			.head = {
-				.action = RTE_PIPELINE_ACTION_TABLE,
-				{.table_id = arp_table_id},
-			},
-			.nh_ip = req->routing_add.nh_ip,
-			.nh_iface = port_out_id[req->routing_add.port],
-		};
-
-		struct rte_table_lpm_key key = {
-			.ip = req->routing_add.ip,
-			.depth = req->routing_add.depth,
-		};
-
-		struct rte_pipeline_table_entry *entry_ptr;
-
-		int key_found;
-
-		result = rte_pipeline_table_entry_add(p, routing_table_id, &key,
-			(struct rte_pipeline_table_entry *) &entry, &key_found,
-			&entry_ptr);
-		break;
-	}
-
-	case APP_MSG_REQ_RT_DEL:
-	{
-		struct rte_table_lpm_key key = {
-			.ip = req->routing_del.ip,
-			.depth = req->routing_del.depth,
-		};
-
-		int key_found;
-
-		result = rte_pipeline_table_entry_delete(p, routing_table_id,
-			&key, &key_found, NULL);
-		break;
-	}
-
-	case APP_MSG_REQ_ARP_ADD:
-	{
-
-		struct app_arp_table_entry entry = {
-			.head = {
-				.action = RTE_PIPELINE_ACTION_PORT,
-				{.port_id =
-					port_out_id[req->arp_add.out_iface]},
-			},
-			.nh_arp = req->arp_add.nh_arp,
-		};
-
-		struct app_arp_key arp_key = {
-			.nh_ip = req->arp_add.nh_ip,
-			.nh_iface = port_out_id[req->arp_add.out_iface],
-		};
-
-		struct rte_pipeline_table_entry *entry_ptr;
-
-		int key_found;
-
-		result = rte_pipeline_table_entry_add(p, arp_table_id, &arp_key,
-			(struct rte_pipeline_table_entry *) &entry, &key_found,
-			&entry_ptr);
-		break;
-	}
-
-	case APP_MSG_REQ_ARP_DEL:
-	{
-		struct app_arp_key arp_key = {
-			.nh_ip = req->arp_del.nh_ip,
-			.nh_iface = port_out_id[req->arp_del.out_iface],
-		};
-
-		int key_found;
-
-		result = rte_pipeline_table_entry_delete(p, arp_table_id,
-			&arp_key, &key_found, NULL);
-		break;
-	}
-
-	default:
-		rte_panic("RT Unrecognized message type (%u)\n", req->type);
-	}
-
-	/* Fill in response message */
-	resp = (struct app_msg_resp *)rte_ctrlmbuf_data((struct rte_mbuf *)msg);
-	resp->result = result;
-
-	/* Send response */
-	do {
-		result = rte_ring_sp_enqueue(ring_resp, msg);
-	} while (result == -ENOBUFS);
-}
diff --git a/examples/ip_pipeline/pipeline_rx.c b/examples/ip_pipeline/pipeline_rx.c
deleted file mode 100644
index 383f1a9..0000000
--- a/examples/ip_pipeline/pipeline_rx.c
+++ /dev/null
@@ -1,385 +0,0 @@
-/*-
- *   BSD LICENSE
- *
- *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
- *   All rights reserved.
- *
- *   Redistribution and use in source and binary forms, with or without
- *   modification, are permitted provided that the following conditions
- *   are met:
- *
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in
- *       the documentation and/or other materials provided with the
- *       distribution.
- *     * Neither the name of Intel Corporation nor the names of its
- *       contributors may be used to endorse or promote products derived
- *       from this software without specific prior written permission.
- *
- *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <rte_common.h>
-#include <rte_byteorder.h>
-#include <rte_log.h>
-#include <rte_malloc.h>
-#include <rte_ethdev.h>
-#include <rte_mbuf.h>
-#include <rte_ether.h>
-#include <rte_ip.h>
-#include <rte_jhash.h>
-
-#include <rte_port_ethdev.h>
-#include <rte_port_ring.h>
-#include <rte_table_stub.h>
-#include <rte_pipeline.h>
-
-
-#include "main.h"
-
-struct app_core_rx_message_handle_params {
-	struct rte_ring *ring_req;
-	struct rte_ring *ring_resp;
-
-	struct rte_pipeline *p;
-	uint32_t *port_in_id;
-};
-
-static void
-app_message_handle(struct app_core_rx_message_handle_params *params);
-
-static int
-app_pipeline_rx_port_in_action_handler(struct rte_mbuf **pkts, uint32_t n,
-	uint64_t *pkts_mask, void *arg);
-
-void
-app_main_loop_pipeline_rx(void) {
-	struct rte_pipeline *p;
-	uint32_t port_in_id[APP_MAX_PORTS];
-	uint32_t port_out_id[APP_MAX_PORTS];
-	uint32_t table_id[APP_MAX_PORTS];
-	uint32_t i;
-
-	uint32_t core_id = rte_lcore_id();
-	struct app_core_params *core_params = app_get_core_params(core_id);
-	struct app_core_rx_message_handle_params mh_params;
-
-	if ((core_params == NULL) || (core_params->core_type != APP_CORE_RX))
-		rte_panic("Core %u misconfiguration\n", core_id);
-
-	RTE_LOG(INFO, USER1, "Core %u is doing RX\n", core_id);
-
-	/* Pipeline configuration */
-	struct rte_pipeline_params pipeline_params = {
-		.name = "pipeline",
-		.socket_id = rte_socket_id(),
-	};
-
-	p = rte_pipeline_create(&pipeline_params);
-	if (p == NULL)
-		rte_panic("%s: Unable to configure the pipeline\n", __func__);
-
-	/* Input port configuration */
-	for (i = 0; i < app.n_ports; i++) {
-		struct rte_port_ethdev_reader_params port_ethdev_params = {
-			.port_id = app.ports[i],
-			.queue_id = 0,
-		};
-
-		struct rte_pipeline_port_in_params port_params = {
-			.ops = &rte_port_ethdev_reader_ops,
-			.arg_create = (void *) &port_ethdev_params,
-			.f_action = app_pipeline_rx_port_in_action_handler,
-			.arg_ah = NULL,
-			.burst_size = app.bsz_hwq_rd,
-		};
-
-		if (rte_pipeline_port_in_create(p, &port_params,
-			&port_in_id[i]))
-			rte_panic("%s: Unable to configure input port for "
-				"port %d\n", __func__, app.ports[i]);
-	}
-
-	/* Output port configuration */
-	for (i = 0; i < app.n_ports; i++) {
-		struct rte_port_ring_writer_params port_ring_params = {
-			.ring = app.rings[core_params->swq_out[i]],
-			.tx_burst_sz = app.bsz_swq_wr,
-		};
-
-		struct rte_pipeline_port_out_params port_params = {
-			.ops = &rte_port_ring_writer_ops,
-			.arg_create = (void *) &port_ring_params,
-			.f_action = NULL,
-			.f_action_bulk = NULL,
-			.arg_ah = NULL,
-		};
-
-		if (rte_pipeline_port_out_create(p, &port_params,
-			&port_out_id[i]))
-			rte_panic("%s: Unable to configure output port for "
-				"ring RX %i\n", __func__, i);
-	}
-
-	/* Table configuration */
-	for (i = 0; i < app.n_ports; i++) {
-		struct rte_pipeline_table_params table_params = {
-			.ops = &rte_table_stub_ops,
-			.arg_create = NULL,
-			.f_action_hit = NULL,
-			.f_action_miss = NULL,
-			.arg_ah = NULL,
-			.action_data_size = 0,
-		};
-
-		if (rte_pipeline_table_create(p, &table_params, &table_id[i]))
-			rte_panic("%s: Unable to configure table %u\n",
-				__func__, table_id[i]);
-	}
-
-	/* Interconnecting ports and tables */
-	for (i = 0; i < app.n_ports; i++)
-		if (rte_pipeline_port_in_connect_to_table(p, port_in_id[i],
-			table_id[i]))
-			rte_panic("%s: Unable to connect input port %u to "
-				"table %u\n", __func__, port_in_id[i],
-				table_id[i]);
-
-	/* Add entries to tables */
-	for (i = 0; i < app.n_ports; i++) {
-		struct rte_pipeline_table_entry default_entry = {
-			.action = RTE_PIPELINE_ACTION_PORT,
-			{.port_id = port_out_id[i]},
-		};
-
-		struct rte_pipeline_table_entry *default_entry_ptr;
-
-		if (rte_pipeline_table_default_entry_add(p, table_id[i],
-			&default_entry, &default_entry_ptr))
-			rte_panic("%s: Unable to add default entry to "
-				"table %u\n", __func__, table_id[i]);
-	}
-
-	/* Enable input ports */
-	for (i = 0; i < app.n_ports; i++)
-		if (rte_pipeline_port_in_enable(p, port_in_id[i]))
-			rte_panic("Unable to enable input port %u\n",
-				port_in_id[i]);
-
-	/* Check pipeline consistency */
-	if (rte_pipeline_check(p) < 0)
-		rte_panic("%s: Pipeline consistency check failed\n", __func__);
-
-	/* Message handling */
-	mh_params.ring_req =
-		app_get_ring_req(app_get_first_core_id(APP_CORE_RX));
-	mh_params.ring_resp =
-		app_get_ring_resp(app_get_first_core_id(APP_CORE_RX));
-	mh_params.p = p;
-	mh_params.port_in_id = port_in_id;
-
-	/* Run-time */
-	for (i = 0; ; i++) {
-		rte_pipeline_run(p);
-
-		if ((i & APP_FLUSH) == 0) {
-			rte_pipeline_flush(p);
-			app_message_handle(&mh_params);
-		}
-	}
-}
-
-uint64_t test_hash(
-	void *key,
-	__attribute__((unused)) uint32_t key_size,
-	__attribute__((unused)) uint64_t seed)
-{
-	struct app_flow_key *flow_key = (struct app_flow_key *) key;
-	uint32_t ip_dst = rte_be_to_cpu_32(flow_key->ip_dst);
-	uint64_t signature = (ip_dst & 0x00FFFFFFLLU) >> 2;
-
-	return signature;
-}
-
-uint32_t
-rte_jhash2_16(uint32_t *k, uint32_t initval)
-{
-	uint32_t a, b, c;
-
-	a = b = RTE_JHASH_GOLDEN_RATIO;
-	c = initval;
-
-	a += k[0];
-	b += k[1];
-	c += k[2];
-	__rte_jhash_mix(a, b, c);
-
-	c += 16; /* length in bytes */
-	a += k[3]; /* Remaining word */
-
-	__rte_jhash_mix(a, b, c);
-
-	return c;
-}
-
-static inline void
-app_pkt_metadata_fill(struct rte_mbuf *m)
-{
-	uint8_t *m_data = rte_pktmbuf_mtod(m, uint8_t *);
-	struct app_pkt_metadata *c =
-		(struct app_pkt_metadata *) RTE_MBUF_METADATA_UINT8_PTR(m, 0);
-	struct ipv4_hdr *ip_hdr =
-		(struct ipv4_hdr *) &m_data[sizeof(struct ether_hdr)];
-	uint64_t *ipv4_hdr_slab = (uint64_t *) ip_hdr;
-
-	/* TTL and Header Checksum are set to 0 */
-	c->flow_key.slab0 = ipv4_hdr_slab[1] & 0xFFFFFFFF0000FF00LLU;
-	c->flow_key.slab1 = ipv4_hdr_slab[2];
-	c->signature = test_hash((void *) &c->flow_key, 0, 0);
-
-	/* Pop Ethernet header */
-	if (app.ether_hdr_pop_push) {
-		rte_pktmbuf_adj(m, (uint16_t)sizeof(struct ether_hdr));
-		m->l2_len = 0;
-		m->l3_len = sizeof(struct ipv4_hdr);
-	}
-}
-
-int
-app_pipeline_rx_port_in_action_handler(
-	struct rte_mbuf **pkts,
-	uint32_t n,
-	uint64_t *pkts_mask,
-	__rte_unused void *arg)
-{
-	uint32_t i;
-
-	for (i = 0; i < n; i++) {
-		struct rte_mbuf *m = pkts[i];
-
-		app_pkt_metadata_fill(m);
-	}
-
-	*pkts_mask = (~0LLU) >> (64 - n);
-
-	return 0;
-}
-
-void
-app_main_loop_rx(void) {
-	struct app_mbuf_array *ma;
-	uint32_t i, j;
-	int ret;
-
-	uint32_t core_id = rte_lcore_id();
-	struct app_core_params *core_params = app_get_core_params(core_id);
-
-	if ((core_params == NULL) || (core_params->core_type != APP_CORE_RX))
-		rte_panic("Core %u misconfiguration\n", core_id);
-
-	RTE_LOG(INFO, USER1, "Core %u is doing RX (no pipeline)\n", core_id);
-
-	ma = rte_malloc_socket(NULL, sizeof(struct app_mbuf_array),
-		RTE_CACHE_LINE_SIZE, rte_socket_id());
-	if (ma == NULL)
-		rte_panic("%s: cannot allocate buffer space\n", __func__);
-
-	for (i = 0; ; i = ((i + 1) & (app.n_ports - 1))) {
-		uint32_t n_mbufs;
-
-		n_mbufs = rte_eth_rx_burst(
-			app.ports[i],
-			0,
-			ma->array,
-			app.bsz_hwq_rd);
-
-		if (n_mbufs == 0)
-			continue;
-
-		for (j = 0; j < n_mbufs; j++) {
-			struct rte_mbuf *m = ma->array[j];
-
-			app_pkt_metadata_fill(m);
-		}
-
-		do {
-			ret = rte_ring_sp_enqueue_bulk(
-				app.rings[core_params->swq_out[i]],
-				(void **) ma->array,
-				n_mbufs);
-		} while (ret < 0);
-	}
-}
-
-void
-app_message_handle(struct app_core_rx_message_handle_params *params)
-{
-	struct rte_ring *ring_req = params->ring_req;
-	struct rte_ring *ring_resp;
-	void *msg;
-	struct app_msg_req *req;
-	struct app_msg_resp *resp;
-	struct rte_pipeline *p;
-	uint32_t *port_in_id;
-	int result;
-
-	/* Read request message */
-	result = rte_ring_sc_dequeue(ring_req, &msg);
-	if (result != 0)
-		return;
-
-	ring_resp = params->ring_resp;
-	p = params->p;
-	port_in_id = params->port_in_id;
-
-	/* Handle request */
-	req = (struct app_msg_req *)rte_ctrlmbuf_data((struct rte_mbuf *)msg);
-	switch (req->type) {
-	case APP_MSG_REQ_PING:
-	{
-		result = 0;
-		break;
-	}
-
-	case APP_MSG_REQ_RX_PORT_ENABLE:
-	{
-		result = rte_pipeline_port_in_enable(p,
-			port_in_id[req->rx_up.port]);
-		break;
-	}
-
-	case APP_MSG_REQ_RX_PORT_DISABLE:
-	{
-		result = rte_pipeline_port_in_disable(p,
-			port_in_id[req->rx_down.port]);
-		break;
-	}
-
-	default:
-		rte_panic("RX Unrecognized message type (%u)\n", req->type);
-	}
-
-	/* Fill in response message */
-	resp = (struct app_msg_resp *)rte_ctrlmbuf_data((struct rte_mbuf *)msg);
-	resp->result = result;
-
-	/* Send response */
-	do {
-		result = rte_ring_sp_enqueue(ring_resp, msg);
-	} while (result == -ENOBUFS);
-}
diff --git a/examples/ip_pipeline/pipeline_tx.c b/examples/ip_pipeline/pipeline_tx.c
deleted file mode 100644
index 0077c12..0000000
--- a/examples/ip_pipeline/pipeline_tx.c
+++ /dev/null
@@ -1,283 +0,0 @@
-/*-
- *   BSD LICENSE
- *
- *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
- *   All rights reserved.
- *
- *   Redistribution and use in source and binary forms, with or without
- *   modification, are permitted provided that the following conditions
- *   are met:
- *
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in
- *       the documentation and/or other materials provided with the
- *       distribution.
- *     * Neither the name of Intel Corporation nor the names of its
- *       contributors may be used to endorse or promote products derived
- *       from this software without specific prior written permission.
- *
- *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-
-#include <rte_common.h>
-#include <rte_byteorder.h>
-#include <rte_log.h>
-#include <rte_malloc.h>
-#include <rte_ethdev.h>
-#include <rte_mbuf.h>
-#include <rte_ether.h>
-#include <rte_ip.h>
-
-#include <rte_port_ethdev.h>
-#include <rte_port_ring.h>
-#include <rte_table_stub.h>
-#include <rte_pipeline.h>
-
-#include "main.h"
-
-static struct ether_addr local_ether_addr = {
-	.addr_bytes = {0, 1, 2, 3, 4, 5},
-};
-
-static inline void
-app_pkt_metadata_flush(struct rte_mbuf *pkt)
-{
-	struct app_pkt_metadata *pkt_meta = (struct app_pkt_metadata *)
-		RTE_MBUF_METADATA_UINT8_PTR(pkt, 0);
-	struct ether_hdr *ether_hdr = (struct ether_hdr *)
-		rte_pktmbuf_prepend(pkt, (uint16_t) sizeof(struct ether_hdr));
-
-	ether_addr_copy(&pkt_meta->nh_arp, &ether_hdr->d_addr);
-	ether_addr_copy(&local_ether_addr, &ether_hdr->s_addr);
-	ether_hdr->ether_type = rte_bswap16(ETHER_TYPE_IPv4);
-	pkt->l2_len = sizeof(struct ether_hdr);
-}
-
-static int
-app_pipeline_tx_port_in_action_handler(
-	struct rte_mbuf **pkts,
-	uint32_t n,
-	uint64_t *pkts_mask,
-	__rte_unused void *arg)
-{
-	uint32_t i;
-
-	for (i = 0; i < n; i++) {
-		struct rte_mbuf *m = pkts[i];
-
-		app_pkt_metadata_flush(m);
-	}
-
-	*pkts_mask = (~0LLU) >> (64 - n);
-
-	return 0;
-}
-
-void
-app_main_loop_pipeline_tx(void) {
-	struct rte_pipeline *p;
-	uint32_t port_in_id[APP_MAX_PORTS];
-	uint32_t port_out_id[APP_MAX_PORTS];
-	uint32_t table_id[APP_MAX_PORTS];
-	uint32_t i;
-
-	uint32_t core_id = rte_lcore_id();
-	struct app_core_params *core_params = app_get_core_params(core_id);
-
-	if ((core_params == NULL) || (core_params->core_type != APP_CORE_TX))
-		rte_panic("Core %u misconfiguration\n", core_id);
-
-	RTE_LOG(INFO, USER1, "Core %u is doing TX\n", core_id);
-
-	/* Pipeline configuration */
-	struct rte_pipeline_params pipeline_params = {
-		.name = "pipeline",
-		.socket_id = rte_socket_id(),
-	};
-
-	p = rte_pipeline_create(&pipeline_params);
-	if (p == NULL)
-		rte_panic("%s: Unable to configure the pipeline\n", __func__);
-
-	/* Input port configuration */
-	for (i = 0; i < app.n_ports; i++) {
-		struct rte_port_ring_reader_params port_ring_params = {
-			.ring = app.rings[core_params->swq_in[i]],
-		};
-
-		struct rte_pipeline_port_in_params port_params = {
-			.ops = &rte_port_ring_reader_ops,
-			.arg_create = (void *) &port_ring_params,
-			.f_action = (app.ether_hdr_pop_push) ?
-				app_pipeline_tx_port_in_action_handler : NULL,
-			.arg_ah = NULL,
-			.burst_size = app.bsz_swq_rd,
-		};
-
-		if (rte_pipeline_port_in_create(p, &port_params,
-			&port_in_id[i])) {
-			rte_panic("%s: Unable to configure input port for "
-				"ring TX %i\n", __func__, i);
-		}
-	}
-
-	/* Output port configuration */
-	for (i = 0; i < app.n_ports; i++) {
-		struct rte_port_ethdev_writer_params port_ethdev_params = {
-			.port_id = app.ports[i],
-			.queue_id = 0,
-			.tx_burst_sz = app.bsz_hwq_wr,
-		};
-
-		struct rte_pipeline_port_out_params port_params = {
-			.ops = &rte_port_ethdev_writer_ops,
-			.arg_create = (void *) &port_ethdev_params,
-			.f_action = NULL,
-			.f_action_bulk = NULL,
-			.arg_ah = NULL,
-		};
-
-		if (rte_pipeline_port_out_create(p, &port_params,
-			&port_out_id[i])) {
-			rte_panic("%s: Unable to configure output port for "
-				"port %d\n", __func__, app.ports[i]);
-		}
-	}
-
-	/* Table configuration */
-	for (i = 0; i < app.n_ports; i++) {
-		struct rte_pipeline_table_params table_params = {
-			.ops = &rte_table_stub_ops,
-			.arg_create = NULL,
-			.f_action_hit = NULL,
-			.f_action_miss = NULL,
-			.arg_ah = NULL,
-			.action_data_size = 0,
-		};
-
-		if (rte_pipeline_table_create(p, &table_params, &table_id[i])) {
-			rte_panic("%s: Unable to configure table %u\n",
-				__func__, table_id[i]);
-		}
-	}
-
-	/* Interconnecting ports and tables */
-	for (i = 0; i < app.n_ports; i++)
-		if (rte_pipeline_port_in_connect_to_table(p, port_in_id[i],
-			table_id[i]))
-			rte_panic("%s: Unable to connect input port %u to "
-				"table %u\n", __func__, port_in_id[i],
-				table_id[i]);
-
-	/* Add entries to tables */
-	for (i = 0; i < app.n_ports; i++) {
-		struct rte_pipeline_table_entry default_entry = {
-			.action = RTE_PIPELINE_ACTION_PORT,
-			{.port_id = port_out_id[i]},
-		};
-
-		struct rte_pipeline_table_entry *default_entry_ptr;
-
-		if (rte_pipeline_table_default_entry_add(p, table_id[i],
-			&default_entry, &default_entry_ptr))
-			rte_panic("%s: Unable to add default entry to "
-				"table %u\n", __func__, table_id[i]);
-	}
-
-	/* Enable input ports */
-	for (i = 0; i < app.n_ports; i++)
-		if (rte_pipeline_port_in_enable(p, port_in_id[i]))
-			rte_panic("Unable to enable input port %u\n",
-				port_in_id[i]);
-
-	/* Check pipeline consistency */
-	if (rte_pipeline_check(p) < 0)
-		rte_panic("%s: Pipeline consistency check failed\n", __func__);
-
-	/* Run-time */
-	for (i = 0; ; i++) {
-		rte_pipeline_run(p);
-
-		if ((i & APP_FLUSH) == 0)
-			rte_pipeline_flush(p);
-	}
-}
-
-void
-app_main_loop_tx(void) {
-	struct app_mbuf_array *m[APP_MAX_PORTS];
-	uint32_t i;
-
-	uint32_t core_id = rte_lcore_id();
-	struct app_core_params *core_params = app_get_core_params(core_id);
-
-	if ((core_params == NULL) || (core_params->core_type != APP_CORE_TX))
-		rte_panic("Core %u misconfiguration\n", core_id);
-
-	RTE_LOG(INFO, USER1, "Core %u is doing TX (no pipeline)\n", core_id);
-
-	for (i = 0; i < APP_MAX_PORTS; i++) {
-		m[i] = rte_malloc_socket(NULL, sizeof(struct app_mbuf_array),
-			RTE_CACHE_LINE_SIZE, rte_socket_id());
-		if (m[i] == NULL)
-			rte_panic("%s: Cannot allocate buffer space\n",
-				__func__);
-	}
-
-	for (i = 0; ; i = ((i + 1) & (app.n_ports - 1))) {
-		uint32_t n_mbufs, n_pkts;
-		int ret;
-
-		n_mbufs = m[i]->n_mbufs;
-
-		ret = rte_ring_sc_dequeue_bulk(
-			app.rings[core_params->swq_in[i]],
-			(void **) &m[i]->array[n_mbufs],
-			app.bsz_swq_rd);
-
-		if (ret == -ENOENT)
-			continue;
-
-		n_mbufs += app.bsz_swq_rd;
-
-		if (n_mbufs < app.bsz_hwq_wr) {
-			m[i]->n_mbufs = n_mbufs;
-			continue;
-		}
-
-		n_pkts = rte_eth_tx_burst(
-			app.ports[i],
-			0,
-			m[i]->array,
-			n_mbufs);
-
-		if (n_pkts < n_mbufs) {
-			uint32_t k;
-
-			for (k = n_pkts; k < n_mbufs; k++) {
-				struct rte_mbuf *pkt_to_free;
-
-				pkt_to_free = m[i]->array[k];
-				rte_pktmbuf_free(pkt_to_free);
-			}
-		}
-
-		m[i]->n_mbufs = 0;
-	}
-}
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 05/11] ip_pipeline: added master pipeline
  2015-05-29 15:43 [PATCH 00/11] ip_pipeline: ip_pipeline application enhancements Maciej Gajdzica
                   ` (3 preceding siblings ...)
  2015-05-29 15:43 ` [PATCH 04/11] ip_pipeline: moved pipelines to separate folder Maciej Gajdzica
@ 2015-05-29 15:43 ` Maciej Gajdzica
  2015-05-29 15:43 ` [PATCH 06/11] ip_pipeline: added application thread Maciej Gajdzica
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Maciej Gajdzica @ 2015-05-29 15:43 UTC (permalink / raw)
  To: dev

Master pipeline is responsible for command line handling and
communicationg with all other pipelines via message queues. Removed
cmdline.c file, as its functionality will be split over multiple
pipeline files.

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/Makefile                      |    6 +-
 examples/ip_pipeline/cmdline.c                     | 1976 --------------------
 examples/ip_pipeline/init.c                        |    3 +
 examples/ip_pipeline/pipeline/pipeline_common.c    |  412 ++++
 examples/ip_pipeline/pipeline/pipeline_common.h    |  241 +++
 .../ip_pipeline/pipeline/pipeline_common_ops.c     |  205 ++
 .../ip_pipeline/pipeline/pipeline_common_ops.h     |  150 ++
 examples/ip_pipeline/pipeline/pipeline_master.c    |  870 +++++++++
 examples/ip_pipeline/pipeline/pipeline_master.h    |   41 +
 .../ip_pipeline/pipeline/pipeline_master_ops.c     |  136 ++
 .../ip_pipeline/pipeline/pipeline_master_ops.h     |   41 +
 11 files changed, 2104 insertions(+), 1977 deletions(-)
 delete mode 100644 examples/ip_pipeline/cmdline.c
 create mode 100644 examples/ip_pipeline/pipeline/pipeline_common.c
 create mode 100644 examples/ip_pipeline/pipeline/pipeline_common.h
 create mode 100644 examples/ip_pipeline/pipeline/pipeline_common_ops.c
 create mode 100644 examples/ip_pipeline/pipeline/pipeline_common_ops.h
 create mode 100644 examples/ip_pipeline/pipeline/pipeline_master.c
 create mode 100644 examples/ip_pipeline/pipeline/pipeline_master.h
 create mode 100644 examples/ip_pipeline/pipeline/pipeline_master_ops.c
 create mode 100644 examples/ip_pipeline/pipeline/pipeline_master_ops.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index 9a1e19a..6269be1 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -53,7 +53,11 @@ SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += config_parse.c
 SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += config_check.c
 SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += init.c
 SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += cpu_core_map.c
-#SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += cmdline.c
+
+SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_common_ops.c
+SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_common.c
+SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_master_ops.c
+SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_master.c
 #SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_rx.c
 #SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_tx.c
 #SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_flow_classification.c
diff --git a/examples/ip_pipeline/cmdline.c b/examples/ip_pipeline/cmdline.c
deleted file mode 100644
index 3173fd0..0000000
--- a/examples/ip_pipeline/cmdline.c
+++ /dev/null
@@ -1,1976 +0,0 @@
-/*-
- *   BSD LICENSE
- *
- *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
- *   All rights reserved.
- *
- *   Redistribution and use in source and binary forms, with or without
- *   modification, are permitted provided that the following conditions
- *   are met:
- *
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in
- *       the documentation and/or other materials provided with the
- *       distribution.
- *     * Neither the name of Intel Corporation nor the names of its
- *       contributors may be used to endorse or promote products derived
- *       from this software without specific prior written permission.
- *
- *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stdio.h>
-#include <termios.h>
-#include <inttypes.h>
-#include <string.h>
-#include <netinet/in.h>
-#include <fcntl.h>
-#include <unistd.h>
-
-#include <rte_ether.h>
-#include <rte_byteorder.h>
-#include <rte_ring.h>
-#include <rte_mbuf.h>
-#include <rte_malloc.h>
-#include <rte_string_fns.h>
-#include <cmdline_rdline.h>
-#include <cmdline_parse.h>
-#include <cmdline_parse_num.h>
-#include <cmdline_parse_string.h>
-#include <cmdline_parse_ipaddr.h>
-#include <cmdline_parse_etheraddr.h>
-#include <cmdline_socket.h>
-#include <cmdline.h>
-
-#include "main.h"
-
-#define IS_RULE_PRESENT(res, rule_key, table, type)			\
-do {									\
-	struct app_rule *it;						\
-									\
-	(res) = NULL;							\
-	TAILQ_FOREACH(it, &table, entries) {				\
-		if (memcmp(&rule_key, &it->type.key, sizeof(rule_key)) == 0) {\
-			(res) = it;					\
-			break;						\
-		}							\
-	}								\
-} while (0)
-
-/* Rules */
-static void
-app_init_rule_tables(void);
-
-TAILQ_HEAD(linked_list, app_rule) arp_table, routing_table, firewall_table,
-	flow_table;
-
-uint32_t n_arp_rules;
-uint32_t n_routing_rules;
-uint32_t n_firewall_rules;
-uint32_t n_flow_rules;
-
-struct app_arp_rule {
-	struct {
-		uint8_t out_iface;
-		uint32_t nh_ip;
-	} key;
-
-	struct ether_addr nh_arp;
-};
-
-struct app_routing_rule {
-	struct {
-		uint32_t ip;
-		uint8_t depth;
-	} key;
-
-	uint8_t port;
-	uint32_t nh_ip;
-};
-
-struct app_firewall_rule {
-	struct {
-		uint32_t src_ip;
-		uint32_t src_ip_mask;
-		uint32_t dst_ip;
-		uint32_t dst_ip_mask;
-		uint16_t src_port_from;
-		uint16_t src_port_to;
-		uint16_t dst_port_from;
-		uint16_t dst_port_to;
-		uint8_t proto;
-		uint8_t proto_mask;
-	} key;
-
-	int32_t priority;
-	uint8_t port;
-};
-
-struct app_flow_rule {
-	struct {
-		uint32_t src_ip;
-		uint32_t dst_ip;
-		uint16_t src_port;
-		uint16_t dst_port;
-		uint8_t proto;
-	} key;
-
-	uint8_t port;
-};
-
-struct app_rule {
-	union {
-		struct app_arp_rule arp;
-		struct app_routing_rule routing;
-		struct app_firewall_rule firewall;
-		struct app_flow_rule flow;
-	};
-
-	TAILQ_ENTRY(app_rule) entries;
-};
-
-/* Initialization */
-static void
-app_init_rule_tables(void)
-{
-	TAILQ_INIT(&arp_table);
-	TAILQ_INIT(&routing_table);
-	TAILQ_INIT(&firewall_table);
-	TAILQ_INIT(&flow_table);
-
-	n_arp_rules = 0;
-	n_routing_rules = 0;
-	n_firewall_rules = 0;
-	n_flow_rules = 0;
-}
-
-/* Printing */
-static void
-print_arp_rule(struct app_arp_rule rule)
-{
-	printf("(Iface = %u, Address = %u.%u.%u.%u) => "
-		"HWaddress = %02x:%02x:%02x:%02x:%02x:%02x\n",
-		rule.key.out_iface,
-		(rule.key.nh_ip >> 24) & 0xFF,
-		(rule.key.nh_ip >> 16) & 0xFF,
-		(rule.key.nh_ip >> 8) & 0xFF,
-		rule.key.nh_ip & 0xFF,
-
-		rule.nh_arp.addr_bytes[0],
-		rule.nh_arp.addr_bytes[1],
-		rule.nh_arp.addr_bytes[2],
-		rule.nh_arp.addr_bytes[3],
-		rule.nh_arp.addr_bytes[4],
-		rule.nh_arp.addr_bytes[5]);
-}
-
-static void
-print_routing_rule(struct app_routing_rule rule)
-{
-	printf("IP Prefix = %u.%u.%u.%u/%u => "
-		"(Iface = %u, Gateway = %u.%u.%u.%u)\n",
-		(rule.key.ip >> 24) & 0xFF,
-		(rule.key.ip >> 16) & 0xFF,
-		(rule.key.ip >> 8) & 0xFF,
-		rule.key.ip & 0xFF,
-
-		rule.key.depth,
-		rule.port,
-
-		(rule.nh_ip >> 24) & 0xFF,
-		(rule.nh_ip >> 16) & 0xFF,
-		(rule.nh_ip >> 8) & 0xFF,
-		rule.nh_ip & 0xFF);
-}
-
-#ifdef RTE_LIBRTE_ACL
-
-static void
-print_firewall_rule(struct app_firewall_rule rule)
-{
-	printf("Priority %d: (IP Src = %u.%u.%u.%u/%u, "
-		"IP Dst = %u.%u.%u.%u/%u, "
-		"Port Src = %u-%u, Port Dst = %u-%u, Proto = %u (%u)) => "
-		"Port = %u\n",
-		rule.priority,
-
-		(rule.key.src_ip >> 24) & 0xFF,
-		(rule.key.src_ip >> 16) & 0xFF,
-		(rule.key.src_ip >> 8) & 0xFF,
-		rule.key.src_ip & 0xFF,
-		rule.key.src_ip_mask,
-
-		(rule.key.dst_ip >> 24) & 0xFF,
-		(rule.key.dst_ip >> 16) & 0xFF,
-		(rule.key.dst_ip >> 8) & 0xFF,
-		rule.key.dst_ip & 0xFF,
-		rule.key.dst_ip_mask,
-
-		rule.key.src_port_from,
-		rule.key.src_port_to,
-		rule.key.dst_port_from,
-		rule.key.dst_port_to,
-		rule.key.proto,
-		rule.key.proto_mask,
-		rule.port);
-}
-
-#endif
-
-static void
-print_flow_rule(struct app_flow_rule rule)
-{
-	printf("(IP Src = %u.%u.%u.%u, IP Dst = %u.%u.%u.%u, Port Src = %u, "
-		"Port Dst = %u, Proto = %u) => Port = %u\n",
-		(rule.key.src_ip >> 24) & 0xFF,
-		(rule.key.src_ip >> 16) & 0xFF,
-		(rule.key.src_ip >> 8) & 0xFF,
-		rule.key.src_ip & 0xFF,
-
-		(rule.key.dst_ip >> 24) & 0xFF,
-		(rule.key.dst_ip >> 16) & 0xFF,
-		(rule.key.dst_ip >> 8) & 0xFF,
-		rule.key.dst_ip  & 0xFF,
-
-		rule.key.src_port,
-		rule.key.dst_port,
-		(uint32_t) rule.key.proto,
-		rule.port);
-}
-
-/* Commands */
-
-/* *** Run file (script) *** */
-struct cmd_run_file_result {
-	cmdline_fixed_string_t run_string;
-	char file_path[100];
-};
-
-static void
-cmd_run_file_parsed(
-	void *parsed_result,
-	struct cmdline *cl,
-	__attribute__((unused)) void *data)
-{
-	struct cmd_run_file_result *params = parsed_result;
-	struct cmdline *file_cl;
-	int fd;
-
-	fd = open(params->file_path, O_RDONLY, 0);
-	if (fd < 0) {
-		printf("Illegal value for file path (%s)\n", params->file_path);
-		return;
-	}
-
-	file_cl = cmdline_new(cl->ctx, "", fd, 1);
-	cmdline_interact(file_cl);
-	close(fd);
-}
-
-cmdline_parse_token_string_t cmd_run_file_run_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_run_file_result, run_string, "run");
-
-cmdline_parse_token_string_t cmd_run_file_file_path =
-	TOKEN_STRING_INITIALIZER(struct cmd_run_file_result, file_path, NULL);
-
-cmdline_parse_inst_t cmd_run_file = {
-	.f = cmd_run_file_parsed,
-	.data = NULL,
-	.help_str = "Run commands from file",
-	.tokens = {
-		(void *)&cmd_run_file_run_string,
-		(void *)&cmd_run_file_file_path,
-		NULL,
-	},
-};
-
-/* *** Link - Enable *** */
-struct cmd_link_enable_result {
-	cmdline_fixed_string_t link_string;
-	uint8_t port;
-	cmdline_fixed_string_t up_string;
-};
-
-static void
-cmd_link_enable_parsed(
-	void *parsed_result,
-	__attribute__((unused)) struct cmdline *cl,
-	__attribute__((unused)) void *data)
-{
-	struct cmd_link_enable_result *params = parsed_result;
-	void *msg;
-	struct app_msg_req *req;
-	struct app_msg_resp *resp;
-	int status;
-
-	uint32_t core_id = app_get_first_core_id(APP_CORE_RX);
-
-	if (core_id == RTE_MAX_LCORE) {
-		printf("RX core not preformed by any CPU core\n");
-		return;
-	}
-
-	struct rte_ring *ring_req = app_get_ring_req(core_id);
-	struct rte_ring *ring_resp = app_get_ring_resp(core_id);
-
-	/* Check params */
-	if (params->port >= app.n_ports) {
-		printf("Illegal value for port parameter (%u)\n", params->port);
-		return;
-	}
-
-	printf("Enabling port %d\n", params->port);
-
-	/* Allocate message buffer */
-	msg = (void *)rte_ctrlmbuf_alloc(app.msg_pool);
-	if (msg == NULL)
-		rte_panic("Unable to allocate new message\n");
-
-	/* Fill request message */
-	req = (struct app_msg_req *)rte_ctrlmbuf_data((struct rte_mbuf *)msg);
-	req->type = APP_MSG_REQ_RX_PORT_ENABLE;
-	req->rx_up.port = params->port;
-
-	/* Send request */
-	do {
-		status = rte_ring_sp_enqueue(ring_req, msg);
-	} while (status == -ENOBUFS);
-
-	/* Wait for response */
-	do {
-		status = rte_ring_sc_dequeue(ring_resp, &msg);
-	} while (status != 0);
-	resp = (struct app_msg_resp *)rte_ctrlmbuf_data((struct rte_mbuf *)msg);
-	/* Check response */
-	if (resp->result != 0)
-		printf("Request LINK_UP failed (%u)\n", resp->result);
-
-	/* Free message buffer */
-	rte_ctrlmbuf_free(msg);
-}
-
-cmdline_parse_token_string_t cmd_link_enable_link_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_link_enable_result, link_string,
-	"link");
-
-cmdline_parse_token_num_t cmd_link_enable_port =
-	TOKEN_NUM_INITIALIZER(struct cmd_link_enable_result, port, UINT8);
-
-cmdline_parse_token_string_t cmd_link_enable_up_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_link_enable_result, up_string,
-	"up");
-
-cmdline_parse_inst_t cmd_link_enable = {
-	.f = cmd_link_enable_parsed,
-	.data = NULL,
-	.help_str = "Link down",
-	.tokens = {
-		(void *)&cmd_link_enable_link_string,
-		(void *)&cmd_link_enable_port,
-		(void *)&cmd_link_enable_up_string,
-		NULL,
-	},
-};
-
-/* *** Link - Disable *** */
-struct cmd_link_disable_result {
-	cmdline_fixed_string_t link_string;
-	uint8_t port;
-	cmdline_fixed_string_t down_string;
-};
-
-static void
-cmd_link_disable_parsed(
-	void *parsed_result,
-	__attribute__((unused)) struct cmdline *cl,
-	__attribute__((unused)) void *data)
-{
-	struct cmd_link_disable_result *params = parsed_result;
-	struct app_msg_req *req;
-	struct app_msg_resp *resp;
-	void *msg;
-	int status;
-
-	uint32_t core_id = app_get_first_core_id(APP_CORE_RX);
-
-	if (core_id == RTE_MAX_LCORE) {
-		printf("RX not performed by any CPU core\n");
-		return;
-	}
-
-	struct rte_ring *ring_req = app_get_ring_req(core_id);
-	struct rte_ring *ring_resp = app_get_ring_resp(core_id);
-
-	/* Check params */
-	if (params->port >= app.n_ports) {
-		printf("Illegal value for port parameter (%u)\n", params->port);
-		return;
-	}
-
-	printf("Disabling port %d\n", params->port);
-
-	/* Allocate message buffer */
-	msg = rte_ctrlmbuf_alloc(app.msg_pool);
-	if (msg == NULL)
-		rte_panic("Unable to allocate new message\n");
-
-	/* Fill request message */
-	req = (struct app_msg_req *)rte_ctrlmbuf_data((struct rte_mbuf *)msg);
-	req->type = APP_MSG_REQ_RX_PORT_DISABLE;
-	req->rx_down.port = params->port;
-
-	/* Send request */
-	do {
-		status = rte_ring_sp_enqueue(ring_req, msg);
-	} while (status == -ENOBUFS);
-
-	/* Wait for response */
-	do {
-		status = rte_ring_sc_dequeue(ring_resp, &msg);
-	} while (status != 0);
-	resp = (struct app_msg_resp *)rte_ctrlmbuf_data((struct rte_mbuf *)msg);
-
-	/* Check response */
-	if (resp->result != 0)
-		printf("Request LINK_DOWN failed (%u)\n", resp->result);
-
-	/* Free message buffer */
-	rte_ctrlmbuf_free((struct rte_mbuf *)msg);
-}
-
-cmdline_parse_token_string_t cmd_link_disable_link_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_link_disable_result, link_string,
-	"link");
-
-cmdline_parse_token_num_t cmd_link_disable_port =
-	TOKEN_NUM_INITIALIZER(struct cmd_link_disable_result, port, UINT8);
-
-cmdline_parse_token_string_t cmd_link_disable_down_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_link_disable_result, down_string,
-	"down");
-
-cmdline_parse_inst_t cmd_link_disable = {
-	.f = cmd_link_disable_parsed,
-	.data = NULL,
-	.help_str = "Link up",
-	.tokens = {
-		(void *)&cmd_link_disable_link_string,
-		(void *)&cmd_link_disable_port,
-		(void *)&cmd_link_disable_down_string,
-		NULL,
-	},
-};
-
-
-/* *** ARP - Add *** */
-struct cmd_arp_add_result {
-	cmdline_fixed_string_t arp_string;
-	cmdline_fixed_string_t add_string;
-	uint8_t out_iface;
-	cmdline_ipaddr_t nh_ip;
-	struct ether_addr nh_arp;
-
-};
-
-static void
-cmd_arp_add_parsed(
-	void *parsed_result,
-	__attribute__((unused)) struct cmdline *cl,
-	__attribute__((unused)) void *data)
-{
-	struct cmd_arp_add_result *params = parsed_result;
-	struct app_rule rule, *old_rule;
-	struct app_msg_req *req;
-	struct app_msg_resp *resp;
-	void *msg;
-	int status;
-
-	uint32_t core_id = app_get_first_core_id(APP_CORE_RT);
-
-	if (core_id == RTE_MAX_LCORE) {
-		printf("ARP not performed by any CPU core\n");
-		return;
-	}
-
-	struct rte_ring *ring_req = app_get_ring_req(core_id);
-	struct rte_ring *ring_resp = app_get_ring_resp(core_id);
-
-	/* Check params */
-	if (params->out_iface >= app.n_ports) {
-		printf("Illegal value for output interface parameter (%u)\n",
-			params->out_iface);
-		return;
-	}
-
-	/* Create rule */
-	memset(&rule, 0, sizeof(rule));
-	rule.arp.key.out_iface = params->out_iface;
-	rule.arp.key.nh_ip =
-		rte_bswap32((uint32_t) params->nh_ip.addr.ipv4.s_addr);
-	rule.arp.nh_arp = params->nh_arp;
-
-	/* Check rule existence */
-	IS_RULE_PRESENT(old_rule, rule.arp.key, arp_table, arp);
-	if ((old_rule == NULL) && (n_arp_rules == app.max_arp_rules)) {
-		printf("ARP table is full.\n");
-		return;
-	}
-
-	printf("Adding ARP entry: ");
-	print_arp_rule(rule.arp);
-
-	/* Allocate message buffer */
-	msg = (void *)rte_ctrlmbuf_alloc(app.msg_pool);
-	if (msg == NULL)
-		rte_panic("Unable to allocate new message\n");
-
-	/* Fill request message */
-	req = (struct app_msg_req *)rte_ctrlmbuf_data((struct rte_mbuf *)msg);
-	req->type = APP_MSG_REQ_ARP_ADD;
-	req->arp_add.out_iface = rule.arp.key.out_iface;
-	req->arp_add.nh_ip = rule.arp.key.nh_ip;
-	req->arp_add.nh_arp = rule.arp.nh_arp;
-
-	/* Send request */
-	do {
-		status = rte_ring_sp_enqueue(ring_req, msg);
-	} while (status == -ENOBUFS);
-
-	/* Wait for response */
-	do {
-		status = rte_ring_sc_dequeue(ring_resp, &msg);
-	} while (status != 0);
-	resp = (struct app_msg_resp *)rte_ctrlmbuf_data((struct rte_mbuf *)msg);
-
-	/* Check response */
-	if (resp->result != 0)
-		printf("Request ARP_ADD failed (%u)\n", resp->result);
-	else {
-		if (old_rule == NULL) {
-			struct app_rule *new_rule = (struct app_rule *)
-				rte_zmalloc_socket("CLI",
-				sizeof(struct app_rule),
-				RTE_CACHE_LINE_SIZE,
-				rte_socket_id());
-
-			if (new_rule == NULL)
-				rte_panic("Unable to allocate new rule\n");
-
-			memcpy(new_rule, &rule, sizeof(rule));
-			TAILQ_INSERT_TAIL(&arp_table, new_rule, entries);
-			n_arp_rules++;
-		} else
-			old_rule->arp.nh_arp = rule.arp.nh_arp;
-	}
-
-	/* Free message buffer */
-	rte_ctrlmbuf_free((struct rte_mbuf *) msg);
-}
-
-cmdline_parse_token_string_t cmd_arp_add_arp_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_add_result, arp_string, "arp");
-
-cmdline_parse_token_string_t cmd_arp_add_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_add_result, add_string, "add");
-
-cmdline_parse_token_num_t cmd_arp_add_out_iface =
-	TOKEN_NUM_INITIALIZER(struct cmd_arp_add_result, out_iface, UINT8);
-
-cmdline_parse_token_ipaddr_t cmd_arp_add_nh_ip =
-	TOKEN_IPADDR_INITIALIZER(struct cmd_arp_add_result, nh_ip);
-
-cmdline_parse_token_etheraddr_t cmd_arp_add_nh_arp =
-	TOKEN_ETHERADDR_INITIALIZER(struct cmd_arp_add_result, nh_arp);
-
-cmdline_parse_inst_t cmd_arp_add = {
-	.f = cmd_arp_add_parsed,
-	.data = NULL,
-	.help_str = "ARP add",
-	.tokens = {
-		(void *)&cmd_arp_add_arp_string,
-		(void *)&cmd_arp_add_add_string,
-		(void *)&cmd_arp_add_out_iface,
-		(void *)&cmd_arp_add_nh_ip,
-		(void *)&cmd_arp_add_nh_arp,
-		NULL,
-	},
-	};
-
-/* *** ARP - Del *** */
-struct cmd_arp_del_result {
-	cmdline_fixed_string_t arp_string;
-	cmdline_fixed_string_t del_string;
-	uint8_t out_iface;
-	cmdline_ipaddr_t nh_ip;
-};
-
-static void
-cmd_arp_del_parsed(
-	void *parsed_result,
-	__attribute__((unused)) struct cmdline *cl,
-	__attribute__((unused)) void *data)
-{
-	struct cmd_arp_del_result *params = parsed_result;
-	struct app_rule rule, *old_rule;
-	struct app_msg_req *req;
-	struct app_msg_resp *resp;
-	void *msg;
-	int status;
-
-	uint32_t core_id = app_get_first_core_id(APP_CORE_RT);
-
-	if (core_id == RTE_MAX_LCORE) {
-		printf("ARP not performed by any CPU core\n");
-		return;
-	}
-
-	struct rte_ring *ring_req = app_get_ring_req(core_id);
-	struct rte_ring *ring_resp = app_get_ring_resp(core_id);
-
-	/* Check params */
-	if (params->out_iface > app.n_ports) {
-		printf("Illegal value for output interface parameter (%u)\n",
-			params->out_iface);
-		return;
-	}
-
-	/* Create rule */
-	memset(&rule, 0, sizeof(rule));
-	rule.arp.key.out_iface = params->out_iface;
-	rule.arp.key.nh_ip =
-		rte_bswap32((uint32_t) params->nh_ip.addr.ipv4.s_addr);
-
-	/* Check rule existence */
-	IS_RULE_PRESENT(old_rule, rule.arp.key, arp_table, arp);
-	if (old_rule == NULL)
-		return;
-
-	printf("Deleting ARP entry: ");
-	print_arp_rule(old_rule->arp);
-
-	/* Allocate message buffer */
-	msg = (void *)rte_ctrlmbuf_alloc(app.msg_pool);
-	if (msg == NULL)
-		rte_panic("Unable to allocate new message\n");
-
-	/* Fill request message */
-	req = (struct app_msg_req *)rte_ctrlmbuf_data((struct rte_mbuf *)msg);
-	req->type = APP_MSG_REQ_ARP_DEL;
-	req->arp_del.out_iface = rule.arp.key.out_iface;
-	req->arp_del.nh_ip = rule.arp.key.nh_ip;
-
-	/* Send request */
-	do {
-		status = rte_ring_sp_enqueue(ring_req, msg);
-	} while (status == -ENOBUFS);
-
-	/* Wait for response */
-	do {
-		status = rte_ring_sc_dequeue(ring_resp, &msg);
-	} while (status != 0);
-	resp = (struct app_msg_resp *)rte_ctrlmbuf_data((struct rte_mbuf *)msg);
-
-	/* Check response */
-	if (resp->result != 0)
-		printf("Request ARP_DEL failed (%u)\n", resp->result);
-	else {
-		TAILQ_REMOVE(&arp_table, old_rule, entries);
-		n_arp_rules--;
-		rte_free(old_rule);
-	}
-
-	/* Free message buffer */
-	rte_ctrlmbuf_free((struct rte_mbuf *) msg);
-}
-
-cmdline_parse_token_string_t cmd_arp_del_arp_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_del_result, arp_string, "arp");
-
-cmdline_parse_token_string_t cmd_arp_del_del_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_del_result, del_string, "del");
-
-cmdline_parse_token_num_t cmd_arp_del_out_iface =
-	TOKEN_NUM_INITIALIZER(struct cmd_arp_del_result, out_iface, UINT8);
-
-cmdline_parse_token_ipaddr_t cmd_arp_del_nh_ip =
-	TOKEN_IPADDR_INITIALIZER(struct cmd_arp_del_result, nh_ip);
-
-cmdline_parse_inst_t cmd_arp_del = {
-	.f = cmd_arp_del_parsed,
-	.data = NULL,
-	.help_str = "ARP delete",
-	.tokens = {
-		(void *)&cmd_arp_del_arp_string,
-		(void *)&cmd_arp_del_del_string,
-		(void *)&cmd_arp_del_out_iface,
-		(void *)&cmd_arp_del_nh_ip,
-		NULL,
-	},
-};
-
-/* *** ARP - Print *** */
-struct cmd_arp_print_result {
-	cmdline_fixed_string_t arp_string;
-	cmdline_fixed_string_t print_string;
-};
-
-static void
-cmd_arp_print_parsed(
-	__attribute__((unused)) void *parsed_result,
-	__attribute__((unused)) struct cmdline *cl,
-	__attribute__((unused)) void *data)
-{
-	struct app_rule *it;
-
-	TAILQ_FOREACH(it, &arp_table, entries) {
-		print_arp_rule(it->arp);
-	}
-}
-
-cmdline_parse_token_string_t cmd_arp_print_arp_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_print_result, arp_string,
-	"arp");
-
-cmdline_parse_token_string_t cmd_arp_print_print_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_print_result, print_string,
-	"ls");
-
-cmdline_parse_inst_t cmd_arp_print = {
-	.f = cmd_arp_print_parsed,
-	.data = NULL,
-	.help_str = "ARP list",
-	.tokens = {
-		(void *)&cmd_arp_print_arp_string,
-		(void *)&cmd_arp_print_print_string,
-		NULL,
-	},
-};
-
-/* *** Routing - Add *** */
-struct cmd_route_add_result {
-	cmdline_fixed_string_t route_string;
-	cmdline_fixed_string_t add_string;
-	cmdline_ipaddr_t ip;
-	uint8_t depth;
-	uint8_t port;
-	cmdline_ipaddr_t nh_ip;
-};
-
-static void
-cmd_route_add_parsed(
-	void *parsed_result,
-	__attribute__((unused)) struct cmdline *cl,
-	__attribute__((unused)) void *data)
-{
-	struct cmd_route_add_result *params = parsed_result;
-	struct app_rule rule, *old_rule;
-	struct app_msg_req *req;
-	struct app_msg_resp *resp;
-	void *msg;
-	int status;
-
-	uint32_t core_id = app_get_first_core_id(APP_CORE_RT);
-
-	if (core_id == RTE_MAX_LCORE) {
-		printf("Routing not performed by any CPU core\n");
-		return;
-	}
-
-	struct rte_ring *ring_req = app_get_ring_req(core_id);
-	struct rte_ring *ring_resp = app_get_ring_resp(core_id);
-
-	/* Check params */
-	if ((params->depth == 0) || (params->depth > 32)) {
-		printf("Illegal value for depth parameter (%u)\n",
-			params->depth);
-		return;
-	}
-
-	if (params->port >= app.n_ports) {
-		printf("Illegal value for port parameter (%u)\n", params->port);
-		return;
-	}
-
-	/* Create rule */
-	memset(&rule, 0, sizeof(rule));
-	rule.routing.key.ip = rte_bswap32((uint32_t)
-		params->ip.addr.ipv4.s_addr);
-	rule.routing.key.depth = params->depth;
-	rule.routing.port = params->port;
-	rule.routing.nh_ip =
-		rte_bswap32((uint32_t) params->nh_ip.addr.ipv4.s_addr);
-
-	/* Check rule existence */
-	IS_RULE_PRESENT(old_rule, rule.routing.key, routing_table, routing);
-	if ((old_rule == NULL) && (n_routing_rules == app.max_routing_rules)) {
-		printf("Routing table is full.\n");
-		return;
-	}
-
-	printf("Adding route: ");
-	print_routing_rule(rule.routing);
-
-	/* Allocate message buffer */
-	msg = (void *)rte_ctrlmbuf_alloc(app.msg_pool);
-	if (msg == NULL)
-		rte_panic("Unable to allocate new message\n");
-
-	/* Fill request message */
-	req = (struct app_msg_req *)rte_ctrlmbuf_data((struct rte_mbuf *)msg);
-	req->type = APP_MSG_REQ_RT_ADD;
-	req->routing_add.ip = rule.routing.key.ip;
-	req->routing_add.depth = rule.routing.key.depth;
-	req->routing_add.port = rule.routing.port;
-	req->routing_add.nh_ip = rule.routing.nh_ip;
-
-	/* Send request */
-	do {
-		status = rte_ring_sp_enqueue(ring_req, msg);
-	} while (status == -ENOBUFS);
-
-	/* Wait for response */
-	do {
-		status = rte_ring_sc_dequeue(ring_resp, &msg);
-	} while (status != 0);
-	resp = (struct app_msg_resp *)rte_ctrlmbuf_data((struct rte_mbuf *)msg);
-
-	/* Check response */
-	if (resp->result != 0)
-		printf("Request ROUTE_ADD failed (%u)\n", resp->result);
-	else {
-		if (old_rule == NULL) {
-			struct app_rule *new_rule = (struct app_rule *)
-				rte_zmalloc_socket("CLI",
-				sizeof(struct app_rule),
-				RTE_CACHE_LINE_SIZE,
-				rte_socket_id());
-
-			if (new_rule == NULL)
-				rte_panic("Unable to allocate new rule\n");
-
-			memcpy(new_rule, &rule, sizeof(rule));
-			TAILQ_INSERT_TAIL(&routing_table, new_rule, entries);
-			n_routing_rules++;
-		} else {
-			old_rule->routing.port = rule.routing.port;
-			old_rule->routing.nh_ip = rule.routing.nh_ip;
-		}
-	}
-
-	/* Free message buffer */
-	rte_ctrlmbuf_free((struct rte_mbuf *) msg);
-}
-
-cmdline_parse_token_string_t cmd_route_add_route_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add_result, route_string,
-	"route");
-
-cmdline_parse_token_string_t cmd_route_add_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_add_result, add_string,
-	"add");
-
-cmdline_parse_token_ipaddr_t cmd_route_add_ip =
-	TOKEN_IPADDR_INITIALIZER(struct cmd_route_add_result, ip);
-
-cmdline_parse_token_num_t cmd_route_add_depth =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add_result, depth, UINT8);
-
-cmdline_parse_token_num_t cmd_route_add_port =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_add_result, port, UINT8);
-
-cmdline_parse_token_ipaddr_t cmd_route_add_nh_ip =
-	TOKEN_IPADDR_INITIALIZER(struct cmd_route_add_result, nh_ip);
-
-cmdline_parse_inst_t cmd_route_add = {
-	.f = cmd_route_add_parsed,
-	.data = NULL,
-	.help_str = "Route add",
-	.tokens = {
-		(void *)&cmd_route_add_route_string,
-		(void *)&cmd_route_add_add_string,
-		(void *)&cmd_route_add_ip,
-		(void *)&cmd_route_add_depth,
-		(void *)&cmd_route_add_port,
-		(void *)&cmd_route_add_nh_ip,
-		NULL,
-	},
-};
-
-/* *** Routing - Del *** */
-struct cmd_route_del_result {
-	cmdline_fixed_string_t route_string;
-	cmdline_fixed_string_t del_string;
-	cmdline_ipaddr_t ip;
-	uint8_t depth;
-};
-
-static void
-cmd_route_del_parsed(
-	void *parsed_result,
-	__attribute__((unused)) struct cmdline *cl,
-	__attribute__((unused)) void *data)
-{
-	struct cmd_route_del_result *params = parsed_result;
-	struct app_rule rule, *old_rule;
-	struct app_msg_req *req;
-	struct app_msg_resp *resp;
-	void *msg;
-	int status;
-
-	uint32_t core_id = app_get_first_core_id(APP_CORE_RT);
-
-	if (core_id == RTE_MAX_LCORE) {
-		printf("Routing not performed by any CPU core\n");
-		return;
-	}
-
-	struct rte_ring *ring_req = app_get_ring_req(core_id);
-	struct rte_ring *ring_resp = app_get_ring_resp(core_id);
-
-	/* Check params */
-	if ((params->depth == 0) || (params->depth > 32)) {
-		printf("Illegal value for depth parameter (%u)\n",
-			params->depth);
-		return;
-	}
-
-	/* Create rule */
-	memset(&rule, 0, sizeof(rule));
-	rule.routing.key.ip = rte_bswap32((uint32_t)
-		params->ip.addr.ipv4.s_addr);
-	rule.routing.key.depth = params->depth;
-
-	/* Check rule existence */
-	IS_RULE_PRESENT(old_rule, rule.routing.key, routing_table, routing);
-	if (old_rule == NULL)
-		return;
-
-	printf("Deleting route: ");
-	print_routing_rule(old_rule->routing);
-
-	/* Allocate message buffer */
-	msg = (void *)rte_ctrlmbuf_alloc(app.msg_pool);
-	if (msg == NULL)
-		rte_panic("Unable to allocate new message\n");
-
-	/* Fill request message */
-	req = (struct app_msg_req *)rte_ctrlmbuf_data((struct rte_mbuf *)msg);
-	req->type = APP_MSG_REQ_RT_DEL;
-	req->routing_del.ip = rule.routing.key.ip;
-	req->routing_del.depth = rule.routing.key.depth;
-
-	/* Send request */
-	do {
-		status = rte_ring_sp_enqueue(ring_req, msg);
-	} while (status == -ENOBUFS);
-
-	/* Wait for response */
-	do {
-		status = rte_ring_sc_dequeue(ring_resp, &msg);
-	} while (status != 0);
-	resp = (struct app_msg_resp *)rte_ctrlmbuf_data((struct rte_mbuf *)msg);
-
-	/* Check response */
-	if (resp->result != 0)
-		printf("Request ROUTE_DEL failed %u)\n", resp->result);
-	else {
-		TAILQ_REMOVE(&routing_table, old_rule, entries);
-		rte_free(old_rule);
-		n_routing_rules--;
-	}
-
-	/* Free message buffer */
-	rte_ctrlmbuf_free((struct rte_mbuf *)msg);
-}
-
-cmdline_parse_token_string_t cmd_route_del_route_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_del_result, route_string,
-	"route");
-
-cmdline_parse_token_string_t cmd_route_del_del_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_del_result, del_string,
-	"del");
-
-cmdline_parse_token_ipaddr_t cmd_route_del_ip =
-	TOKEN_IPADDR_INITIALIZER(struct cmd_route_del_result, ip);
-
-cmdline_parse_token_num_t cmd_route_del_depth =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_del_result, depth, UINT8);
-
-cmdline_parse_inst_t cmd_route_del = {
-	.f = cmd_route_del_parsed,
-	.data = NULL,
-	.help_str = "Route delete",
-	.tokens = {
-		(void *)&cmd_route_del_route_string,
-		(void *)&cmd_route_del_del_string,
-		(void *)&cmd_route_del_ip,
-		(void *)&cmd_route_del_depth,
-		NULL,
-	},
-};
-
-/* *** Routing - Print *** */
-struct cmd_routing_print_result {
-	cmdline_fixed_string_t routing_string;
-	cmdline_fixed_string_t print_string;
-};
-
-static void
-cmd_routing_print_parsed(
-	__attribute__((unused)) void *parsed_result,
-	__attribute__((unused)) struct cmdline *cl,
-	__attribute__((unused)) void *data)
-{
-	struct app_rule *it;
-
-	TAILQ_FOREACH(it, &routing_table, entries) {
-		print_routing_rule(it->routing);
-	}
-}
-
-cmdline_parse_token_string_t cmd_routing_print_routing_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_routing_print_result,
-	routing_string, "route");
-
-cmdline_parse_token_string_t cmd_routing_print_print_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_routing_print_result, print_string,
-	"ls");
-
-cmdline_parse_inst_t cmd_routing_print = {
-	.f = cmd_routing_print_parsed,
-	.data = NULL,
-	.help_str = "Route list",
-	.tokens = {
-		(void *)&cmd_routing_print_routing_string,
-		(void *)&cmd_routing_print_print_string,
-		NULL,
-	},
-};
-
-#ifdef RTE_LIBRTE_ACL
-
-/* *** Firewall - Add *** */
-struct cmd_firewall_add_result {
-	cmdline_fixed_string_t firewall_string;
-	cmdline_fixed_string_t add_string;
-	int32_t priority;
-	cmdline_ipaddr_t src_ip;
-	uint32_t src_ip_mask;
-	cmdline_ipaddr_t dst_ip;
-	uint32_t dst_ip_mask;
-	uint16_t src_port_from;
-	uint16_t src_port_to;
-	uint16_t dst_port_from;
-	uint16_t dst_port_to;
-	uint8_t proto;
-	uint8_t proto_mask;
-	uint8_t port;
-};
-
-static void
-cmd_firewall_add_parsed(
-	void *parsed_result,
-	__attribute__((unused)) struct cmdline *cl,
-	__attribute__((unused)) void *data)
-{
-	struct cmd_firewall_add_result *params = parsed_result;
-	struct app_rule rule, *old_rule, *new_rule = NULL;
-	struct rte_mbuf *msg;
-	struct app_msg_req *req;
-	struct app_msg_resp *resp;
-	int status;
-
-	uint32_t core_id = app_get_first_core_id(APP_CORE_FW);
-
-	if (core_id == RTE_MAX_LCORE) {
-		printf("Firewall not performed by any CPU core\n");
-		return;
-	}
-
-	struct rte_ring *ring_req = app_get_ring_req(core_id);
-	struct rte_ring *ring_resp = app_get_ring_resp(core_id);
-
-	/* Check params */
-	if (params->port >= app.n_ports) {
-		printf("Illegal value for port parameter (%u)\n", params->port);
-		return;
-	}
-
-	/* Create rule */
-	memset(&rule, 0, sizeof(rule));
-	rule.firewall.priority = params->priority;
-	rule.firewall.key.src_ip =
-		rte_bswap32((uint32_t)params->src_ip.addr.ipv4.s_addr);
-	rule.firewall.key.src_ip_mask = params->src_ip_mask;
-	rule.firewall.key.dst_ip =
-		rte_bswap32((uint32_t)params->dst_ip.addr.ipv4.s_addr);
-	rule.firewall.key.dst_ip_mask = params->dst_ip_mask;
-	rule.firewall.key.src_port_from = params->src_port_from;
-	rule.firewall.key.src_port_to = params->src_port_to;
-	rule.firewall.key.dst_port_from = params->dst_port_from;
-	rule.firewall.key.dst_port_to = params->dst_port_to;
-	rule.firewall.key.proto = params->proto;
-	rule.firewall.key.proto_mask = params->proto_mask;
-	rule.firewall.port = params->port;
-
-	/* Check rule existence */
-	IS_RULE_PRESENT(old_rule, rule.firewall.key, firewall_table, firewall);
-	if ((old_rule == NULL) &&
-		(n_firewall_rules == app.max_firewall_rules)) {
-		printf("Firewall table is full.\n");
-		return;
-	}
-
-	printf("Adding firewall rule: ");
-	print_firewall_rule(rule.firewall);
-
-	/* Allocate message buffer */
-	msg = rte_ctrlmbuf_alloc(app.msg_pool);
-	if (msg == NULL)
-		rte_panic("Unable to allocate new message\n");
-
-	/* if we need a new rule structure, allocate it before we go further */
-	if (old_rule == NULL) {
-		new_rule = rte_zmalloc_socket("CLI", sizeof(struct app_rule),
-				RTE_CACHE_LINE_SIZE, rte_socket_id());
-		if (new_rule == NULL) {
-			printf("Cannot allocate memory for new rule\n");
-			rte_ctrlmbuf_free(msg);
-			return;
-		}
-	}
-
-
-	/* Fill request message */
-	req = (struct app_msg_req *)rte_ctrlmbuf_data(msg);
-	req->type = APP_MSG_REQ_FW_ADD;
-	req->firewall_add.add_params.priority = rule.firewall.priority;
-	req->firewall_add.add_params.field_value[1].value.u32 =
-		rule.firewall.key.src_ip;
-	req->firewall_add.add_params.field_value[1].mask_range.u32 =
-		rule.firewall.key.src_ip_mask;
-	req->firewall_add.add_params.field_value[2].value.u32 =
-		rule.firewall.key.dst_ip;
-	req->firewall_add.add_params.field_value[2].mask_range.u32 =
-		rule.firewall.key.dst_ip_mask;
-	req->firewall_add.add_params.field_value[3].value.u16 =
-		rule.firewall.key.src_port_from;
-	req->firewall_add.add_params.field_value[3].mask_range.u16 =
-		rule.firewall.key.src_port_to;
-	req->firewall_add.add_params.field_value[4].value.u16 =
-		rule.firewall.key.dst_port_from;
-	req->firewall_add.add_params.field_value[4].mask_range.u16 =
-		rule.firewall.key.dst_port_to;
-	req->firewall_add.add_params.field_value[0].value.u8 =
-		rule.firewall.key.proto;
-	req->firewall_add.add_params.field_value[0].mask_range.u8 =
-		rule.firewall.key.proto_mask;
-	req->firewall_add.port = rule.firewall.port;
-
-	/* Send request */
-	do {
-		status = rte_ring_sp_enqueue(ring_req, (void *) msg);
-	} while (status == -ENOBUFS);
-
-	/* Wait for response */
-	do {
-		status = rte_ring_sc_dequeue(ring_resp, (void **) &msg);
-	} while (status != 0);
-	resp = (struct app_msg_resp *)rte_ctrlmbuf_data(msg);
-
-	/* Check response */
-	if (resp->result != 0)
-		printf("Request FIREWALL_ADD failed (%u)\n", resp->result);
-	else {
-		if (old_rule == NULL) {
-			memcpy(new_rule, &rule, sizeof(rule));
-			TAILQ_INSERT_TAIL(&firewall_table, new_rule, entries);
-			n_firewall_rules++;
-		} else {
-			old_rule->firewall.priority = rule.firewall.priority;
-			old_rule->firewall.port = rule.firewall.port;
-		}
-	}
-
-	/* Free message buffer */
-	rte_ctrlmbuf_free(msg);
-}
-
-cmdline_parse_token_string_t cmd_firewall_add_firewall_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_add_result,
-	firewall_string, "firewall");
-
-cmdline_parse_token_string_t cmd_firewall_add_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_add_result, add_string,
-	"add");
-
-cmdline_parse_token_num_t cmd_firewall_add_priority =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_result, priority, INT32);
-
-cmdline_parse_token_ipaddr_t cmd_firewall_add_src_ip =
-	TOKEN_IPADDR_INITIALIZER(struct cmd_firewall_add_result, src_ip);
-cmdline_parse_token_num_t cmd_firewall_add_src_ip_mask =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_result, src_ip_mask,
-	UINT32);
-
-cmdline_parse_token_ipaddr_t cmd_firewall_add_dst_ip =
-	TOKEN_IPADDR_INITIALIZER(struct cmd_firewall_add_result, dst_ip);
-cmdline_parse_token_num_t cmd_firewall_add_dst_ip_mask =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_result, dst_ip_mask,
-	UINT32);
-
-cmdline_parse_token_num_t cmd_firewall_add_src_port_from =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_result, src_port_from,
-	UINT16);
-cmdline_parse_token_num_t cmd_firewall_add_src_port_to =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_result, src_port_to,
-	UINT16);
-
-cmdline_parse_token_num_t cmd_firewall_add_dst_port_from =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_result, dst_port_from,
-	UINT16);
-cmdline_parse_token_num_t cmd_firewall_add_dst_port_to =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_result, dst_port_to,
-	UINT16);
-
-cmdline_parse_token_num_t cmd_firewall_add_proto =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_result, proto, UINT8);
-cmdline_parse_token_num_t cmd_firewall_add_proto_mask =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_result, proto_mask,
-	UINT8);
-cmdline_parse_token_num_t cmd_firewall_add_port =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_result, port, UINT8);
-
-cmdline_parse_inst_t cmd_firewall_add = {
-	.f = cmd_firewall_add_parsed,
-	.data = NULL,
-	.help_str = "Firewall rule add",
-	.tokens = {
-		(void *)&cmd_firewall_add_firewall_string,
-		(void *)&cmd_firewall_add_add_string,
-		(void *)&cmd_firewall_add_priority,
-		(void *)&cmd_firewall_add_src_ip,
-		(void *)&cmd_firewall_add_src_ip_mask,
-		(void *)&cmd_firewall_add_dst_ip,
-		(void *)&cmd_firewall_add_dst_ip_mask,
-		(void *)&cmd_firewall_add_src_port_from,
-		(void *)&cmd_firewall_add_src_port_to,
-		(void *)&cmd_firewall_add_dst_port_from,
-		(void *)&cmd_firewall_add_dst_port_to,
-		(void *)&cmd_firewall_add_proto,
-		(void *)&cmd_firewall_add_proto_mask,
-		(void *)&cmd_firewall_add_port,
-		NULL,
-	},
-};
-
-/* *** firewall - Del *** */
-struct cmd_firewall_del_result {
-	cmdline_fixed_string_t firewall_string;
-	cmdline_fixed_string_t del_string;
-	cmdline_ipaddr_t src_ip;
-	uint32_t src_ip_mask;
-	cmdline_ipaddr_t dst_ip;
-	uint32_t dst_ip_mask;
-	uint16_t src_port_from;
-	uint16_t src_port_to;
-	uint16_t dst_port_from;
-	uint16_t dst_port_to;
-	uint8_t proto;
-	uint8_t proto_mask;
-};
-
-static void
-cmd_firewall_del_parsed(
-	void *parsed_result,
-	__attribute__((unused)) struct cmdline *cl,
-	__attribute__((unused)) void *data)
-{
-	struct cmd_firewall_del_result *params = parsed_result;
-	struct app_rule rule, *old_rule;
-	struct rte_mbuf *msg;
-	struct app_msg_req *req;
-	struct app_msg_resp *resp;
-	int status;
-
-	uint32_t core_id = app_get_first_core_id(APP_CORE_FW);
-
-	if (core_id == RTE_MAX_LCORE) {
-		printf("Firewall not performed by any CPU core\n");
-		return;
-	}
-
-	struct rte_ring *ring_req = app_get_ring_req(core_id);
-	struct rte_ring *ring_resp = app_get_ring_resp(core_id);
-
-	/* Check params */
-
-	/* Create rule */
-	memset(&rule, 0, sizeof(rule));
-	rule.firewall.key.src_ip =
-		rte_bswap32((uint32_t) params->src_ip.addr.ipv4.s_addr);
-	rule.firewall.key.src_ip_mask = params->src_ip_mask;
-	rule.firewall.key.dst_ip =
-		rte_bswap32((uint32_t) params->dst_ip.addr.ipv4.s_addr);
-	rule.firewall.key.dst_ip_mask = params->dst_ip_mask;
-	rule.firewall.key.src_port_from = params->src_port_from;
-	rule.firewall.key.src_port_to = params->src_port_to;
-	rule.firewall.key.dst_port_from = params->dst_port_from;
-	rule.firewall.key.dst_port_to = params->dst_port_to;
-	rule.firewall.key.proto = params->proto;
-	rule.firewall.key.proto_mask = params->proto_mask;
-
-	/* Check rule existence */
-	IS_RULE_PRESENT(old_rule, rule.firewall.key, firewall_table, firewall);
-	if (old_rule == NULL)
-		return;
-
-	printf("Deleting firewall rule: ");
-	print_firewall_rule(old_rule->firewall);
-
-	/* Allocate message buffer */
-	msg = rte_ctrlmbuf_alloc(app.msg_pool);
-	if (msg == NULL)
-		rte_panic("Unable to allocate new message\n");
-
-	/* Fill request message */
-	req = (struct app_msg_req *)rte_ctrlmbuf_data(msg);
-	memset(&req->firewall_del, 0, sizeof(req->firewall_del));
-	req->type = APP_MSG_REQ_FW_DEL;
-	req->firewall_del.delete_params.field_value[1].value.u32 =
-		rule.firewall.key.src_ip;
-	req->firewall_del.delete_params.field_value[1].mask_range.u32 =
-		rule.firewall.key.src_ip_mask;
-	req->firewall_del.delete_params.field_value[2].value.u32 =
-		rule.firewall.key.dst_ip;
-	req->firewall_del.delete_params.field_value[2].mask_range.u32 =
-		rule.firewall.key.dst_ip_mask;
-	req->firewall_del.delete_params.field_value[3].value.u16 =
-		rule.firewall.key.src_port_from;
-	req->firewall_del.delete_params.field_value[3].mask_range.u16 =
-		rule.firewall.key.src_port_to;
-	req->firewall_del.delete_params.field_value[4].value.u16 =
-		rule.firewall.key.dst_port_from;
-	req->firewall_del.delete_params.field_value[4].mask_range.u16 =
-		rule.firewall.key.dst_port_to;
-	req->firewall_del.delete_params.field_value[0].value.u8 =
-		rule.firewall.key.proto;
-	req->firewall_del.delete_params.field_value[0].mask_range.u8 =
-		rule.firewall.key.proto_mask;
-
-	/* Send request */
-	do {
-		status = rte_ring_sp_enqueue(ring_req, (void *) msg);
-	} while (status == -ENOBUFS);
-
-	/* Wait for response */
-	do {
-		status = rte_ring_sc_dequeue(ring_resp, (void **) &msg);
-	} while (status != 0);
-	resp = (struct app_msg_resp *)rte_ctrlmbuf_data(msg);
-
-	/* Check response */
-	if (resp->result != 0)
-		printf("Request FIREWALL_DEL failed %u)\n", resp->result);
-	else {
-		TAILQ_REMOVE(&firewall_table, old_rule, entries);
-		rte_free(old_rule);
-		n_firewall_rules--;
-	}
-
-	/* Free message buffer */
-	rte_ctrlmbuf_free(msg);
-}
-
-cmdline_parse_token_string_t cmd_firewall_del_firewall_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_del_result,
-	firewall_string, "firewall");
-
-cmdline_parse_token_string_t cmd_firewall_del_del_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_del_result, del_string,
-	"del");
-
-cmdline_parse_token_ipaddr_t cmd_firewall_del_src_ip =
-	TOKEN_IPADDR_INITIALIZER(struct cmd_firewall_del_result, src_ip);
-cmdline_parse_token_num_t cmd_firewall_del_src_ip_mask =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_del_result, src_ip_mask,
-	UINT32);
-
-cmdline_parse_token_ipaddr_t cmd_firewall_del_dst_ip =
-	TOKEN_IPADDR_INITIALIZER(struct cmd_firewall_del_result, dst_ip);
-cmdline_parse_token_num_t cmd_firewall_del_dst_ip_mask =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_del_result, dst_ip_mask,
-	UINT32);
-
-cmdline_parse_token_num_t cmd_firewall_del_src_port_from =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_del_result, src_port_from,
-	UINT16);
-cmdline_parse_token_num_t cmd_firewall_del_src_port_to =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_del_result, src_port_to,
-	UINT16);
-
-cmdline_parse_token_num_t cmd_firewall_del_dst_port_from =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_del_result, dst_port_from,
-	UINT16);
-cmdline_parse_token_num_t cmd_firewall_del_dst_port_to =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_del_result, dst_port_to,
-	UINT16);
-
-cmdline_parse_token_num_t cmd_firewall_del_proto =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_del_result, proto, UINT8);
-cmdline_parse_token_num_t cmd_firewall_del_proto_mask =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_del_result, proto_mask,
-	UINT8);
-
-cmdline_parse_inst_t cmd_firewall_del = {
-	.f = cmd_firewall_del_parsed,
-	.data = NULL,
-	.help_str = "Firewall rule delete",
-	.tokens = {
-		(void *)&cmd_firewall_del_firewall_string,
-		(void *)&cmd_firewall_del_del_string,
-		(void *)&cmd_firewall_del_src_ip,
-		(void *)&cmd_firewall_del_src_ip_mask,
-		(void *)&cmd_firewall_del_dst_ip,
-		(void *)&cmd_firewall_del_dst_ip_mask,
-		(void *)&cmd_firewall_del_src_port_from,
-		(void *)&cmd_firewall_del_src_port_to,
-		(void *)&cmd_firewall_del_dst_port_from,
-		(void *)&cmd_firewall_del_dst_port_to,
-		(void *)&cmd_firewall_del_proto,
-		(void *)&cmd_firewall_del_proto_mask,
-		NULL,
-	},
-};
-
-/* *** Firewall - Print *** */
-struct cmd_firewall_print_result {
-	cmdline_fixed_string_t firewall_string;
-	cmdline_fixed_string_t print_string;
-};
-
-static void
-cmd_firewall_print_parsed(
-	__attribute__((unused)) void *parsed_result,
-	__attribute__((unused)) struct cmdline *cl,
-	__attribute__((unused)) void *data)
-{
-	struct app_rule *it;
-
-	TAILQ_FOREACH(it, &firewall_table, entries) {
-		print_firewall_rule(it->firewall);
-	}
-}
-
-cmdline_parse_token_string_t cmd_firewall_print_firewall_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_print_result,
-	firewall_string, "firewall");
-
-cmdline_parse_token_string_t cmd_firewall_print_print_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_print_result, print_string,
-	"ls");
-
-cmdline_parse_inst_t cmd_firewall_print = {
-	.f = cmd_firewall_print_parsed,
-	.data = NULL,
-	.help_str = "Firewall rules list",
-	.tokens = {
-		(void *)&cmd_firewall_print_firewall_string,
-		(void *)&cmd_firewall_print_print_string,
-		NULL,
-	},
-};
-
-#endif
-
-/* *** Flow Classification - Add All *** */
-struct cmd_flow_add_all_result {
-	cmdline_fixed_string_t flow_string;
-	cmdline_fixed_string_t add_string;
-	cmdline_fixed_string_t all_string;
-};
-
-static void
-cmd_flow_add_all_parsed(
-	__attribute__((unused)) void *parsed_result,
-	__attribute__((unused)) struct cmdline *cl,
-	__attribute__((unused)) void *data)
-{
-	struct app_msg_req *req;
-	struct app_msg_resp *resp;
-	void *msg;
-	int status;
-
-	struct rte_ring *ring_req =
-		app_get_ring_req(app_get_first_core_id(APP_CORE_FC));
-	struct rte_ring *ring_resp =
-		app_get_ring_resp(app_get_first_core_id(APP_CORE_FC));
-
-	/* Allocate message buffer */
-	msg = (void *)rte_ctrlmbuf_alloc(app.msg_pool);
-	if (msg == NULL)
-		rte_panic("Unable to allocate new message\n");
-
-	/* Fill request message */
-	req = (struct app_msg_req *)rte_ctrlmbuf_data((struct rte_mbuf *)msg);
-	memset(req, 0, sizeof(struct app_msg_req));
-
-	req->type = APP_MSG_REQ_FC_ADD_ALL;
-
-	/* Send request */
-	do {
-		status = rte_ring_sp_enqueue(ring_req, msg);
-	} while (status == -ENOBUFS);
-
-	/* Wait for response */
-	do {
-		status = rte_ring_sc_dequeue(ring_resp, &msg);
-	} while (status != 0);
-	resp = (struct app_msg_resp *)rte_ctrlmbuf_data((struct rte_mbuf *)msg);
-
-	/* Check response */
-	if (resp->result != 0)
-		printf("Request FLOW_ADD_ALL failed (%u)\n", resp->result);
-
-	/* Free message buffer */
-	rte_ctrlmbuf_free((struct rte_mbuf *)msg);
-}
-
-cmdline_parse_token_string_t cmd_flow_add_all_flow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_flow_add_all_result, flow_string,
-	"flow");
-
-cmdline_parse_token_string_t cmd_flow_add_all_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_flow_add_all_result, add_string,
-	"add");
-
-cmdline_parse_token_string_t cmd_flow_add_all_all_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_flow_add_all_result, all_string,
-	"all");
-
-cmdline_parse_inst_t cmd_flow_add_all = {
-	.f = cmd_flow_add_all_parsed,
-	.data = NULL,
-	.help_str = "Flow table initialization based on hard-coded rule",
-	.tokens = {
-		(void *)&cmd_flow_add_all_flow_string,
-		(void *)&cmd_flow_add_all_add_string,
-		(void *)&cmd_flow_add_all_all_string,
-		NULL,
-	},
-};
-
-/* *** Flow Classification - Add *** */
-struct cmd_flow_add_result {
-	cmdline_fixed_string_t flow_string;
-	cmdline_fixed_string_t add_string;
-	cmdline_ipaddr_t src_ip;
-	cmdline_ipaddr_t dst_ip;
-	uint16_t src_port;
-	uint16_t dst_port;
-	uint8_t proto;
-	uint8_t port;
-};
-
-static void
-cmd_flow_add_parsed(
-	void *parsed_result,
-	__attribute__((unused)) struct cmdline *cl,
-	__attribute__((unused)) void *data)
-{
-	struct cmd_flow_add_result *params = parsed_result;
-	struct app_rule rule, *old_rule;
-	struct app_msg_req *req;
-	struct app_msg_resp *resp;
-	void *msg;
-	int status;
-
-	uint32_t core_id = app_get_first_core_id(APP_CORE_FC);
-
-	if (core_id == RTE_MAX_LCORE) {
-		printf("Flow classification not performed by any CPU core\n");
-		return;
-	}
-
-	struct rte_ring *ring_req = app_get_ring_req(core_id);
-	struct rte_ring *ring_resp = app_get_ring_resp(core_id);
-
-	/* Check params */
-	if (params->port >= app.n_ports) {
-		printf("Illegal value for port parameter (%u)\n", params->port);
-		return;
-	}
-
-	/* Create rule */
-	memset(&rule, 0, sizeof(rule));
-	rule.flow.key.src_ip =
-		rte_bswap32((uint32_t)params->src_ip.addr.ipv4.s_addr);
-	rule.flow.key.dst_ip =
-		rte_bswap32((uint32_t)params->dst_ip.addr.ipv4.s_addr);
-	rule.flow.key.src_port = params->src_port;
-	rule.flow.key.dst_port = params->dst_port;
-	rule.flow.key.proto = params->proto;
-	rule.flow.port = params->port;
-
-	/* Check rule existence */
-	IS_RULE_PRESENT(old_rule, rule.flow.key, flow_table, flow);
-	if ((old_rule == NULL) && (n_flow_rules == app.max_flow_rules)) {
-		printf("Flow table is full.\n");
-		return;
-	}
-
-	printf("Adding flow: ");
-	print_flow_rule(rule.flow);
-
-	/* Allocate message buffer */
-	msg = (void *)rte_ctrlmbuf_alloc(app.msg_pool);
-	if (msg == NULL)
-		rte_panic("Unable to allocate new message\n");
-
-	/* Fill request message */
-	req = (struct app_msg_req *)rte_ctrlmbuf_data((struct rte_mbuf *)msg);
-	memset(req, 0, sizeof(struct app_msg_req));
-
-	req->type = APP_MSG_REQ_FC_ADD;
-	req->flow_classif_add.key.ip_src = rte_bswap32(rule.flow.key.src_ip);
-	req->flow_classif_add.key.ip_dst = rte_bswap32(rule.flow.key.dst_ip);
-	req->flow_classif_add.key.port_src =
-		rte_bswap16(rule.flow.key.src_port);
-	req->flow_classif_add.key.port_dst =
-		rte_bswap16(rule.flow.key.dst_port);
-	req->flow_classif_add.key.proto = rule.flow.key.proto;
-	req->flow_classif_add.port = rule.flow.port;
-
-	/* Send request */
-	do {
-		status = rte_ring_sp_enqueue(ring_req, msg);
-	} while (status == -ENOBUFS);
-
-	/* Wait for response */
-	do {
-		status = rte_ring_sc_dequeue(ring_resp, &msg);
-	} while (status != 0);
-	resp = (struct app_msg_resp *)rte_ctrlmbuf_data((struct rte_mbuf *)msg);
-
-	/* Check response */
-	if (resp->result != 0)
-		printf("Request FLOW_ADD failed (%u)\n", resp->result);
-	else {
-		if (old_rule == NULL) {
-			struct app_rule *new_rule = (struct app_rule *)
-				rte_zmalloc_socket("CLI",
-				sizeof(struct app_rule),
-				RTE_CACHE_LINE_SIZE,
-				rte_socket_id());
-
-			if (new_rule == NULL)
-				rte_panic("Unable to allocate new rule\n");
-
-			memcpy(new_rule, &rule, sizeof(rule));
-			TAILQ_INSERT_TAIL(&flow_table, new_rule, entries);
-			n_flow_rules++;
-		} else
-			old_rule->flow.port = rule.flow.port;
-	}
-
-	/* Free message buffer */
-	rte_ctrlmbuf_free((struct rte_mbuf *)msg);
-}
-
-cmdline_parse_token_string_t cmd_flow_add_flow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_flow_add_result, flow_string,
-	"flow");
-
-cmdline_parse_token_string_t cmd_flow_add_add_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_flow_add_result, add_string, "add");
-
-cmdline_parse_token_ipaddr_t cmd_flow_add_src_ip =
-	TOKEN_IPADDR_INITIALIZER(struct cmd_flow_add_result, src_ip);
-
-cmdline_parse_token_ipaddr_t cmd_flow_add_dst_ip =
-	TOKEN_IPADDR_INITIALIZER(struct cmd_flow_add_result, dst_ip);
-
-cmdline_parse_token_num_t cmd_flow_add_src_port =
-	TOKEN_NUM_INITIALIZER(struct cmd_flow_add_result, src_port, UINT16);
-
-cmdline_parse_token_num_t cmd_flow_add_dst_port =
-	TOKEN_NUM_INITIALIZER(struct cmd_flow_add_result, dst_port, UINT16);
-
-cmdline_parse_token_num_t cmd_flow_add_proto =
-	TOKEN_NUM_INITIALIZER(struct cmd_flow_add_result, proto, UINT8);
-
-cmdline_parse_token_num_t cmd_flow_add_port =
-	TOKEN_NUM_INITIALIZER(struct cmd_flow_add_result, port, UINT8);
-
-cmdline_parse_inst_t cmd_flow_add = {
-	.f = cmd_flow_add_parsed,
-	.data = NULL,
-	.help_str = "Flow add",
-	.tokens = {
-		(void *)&cmd_flow_add_flow_string,
-		(void *)&cmd_flow_add_add_string,
-		(void *)&cmd_flow_add_src_ip,
-		(void *)&cmd_flow_add_dst_ip,
-		(void *)&cmd_flow_add_src_port,
-		(void *)&cmd_flow_add_dst_port,
-		(void *)&cmd_flow_add_proto,
-		(void *)&cmd_flow_add_port,
-		NULL,
-	},
-};
-
-/* *** Flow Classification - Del *** */
-struct cmd_flow_del_result {
-	cmdline_fixed_string_t flow_string;
-	cmdline_fixed_string_t del_string;
-	cmdline_ipaddr_t src_ip;
-	cmdline_ipaddr_t dst_ip;
-	uint16_t src_port;
-	uint16_t dst_port;
-	uint8_t proto;
-};
-
-static void
-cmd_flow_del_parsed(
-	void *parsed_result,
-	__attribute__((unused)) struct cmdline *cl,
-	__attribute__((unused)) void *data)
-{
-	struct cmd_flow_del_result *params = parsed_result;
-	struct app_rule rule, *old_rule;
-	struct app_msg_req *req;
-	struct app_msg_resp *resp;
-	void *msg;
-	int status;
-
-	uint32_t core_id = app_get_first_core_id(APP_CORE_FC);
-
-	if (core_id == RTE_MAX_LCORE) {
-		printf("Flow classification not performed by any CPU core.\n");
-		return;
-	}
-
-	struct rte_ring *ring_req = app_get_ring_req(core_id);
-	struct rte_ring *ring_resp = app_get_ring_resp(core_id);
-
-	/* Create rule */
-	memset(&rule, 0, sizeof(rule));
-	rule.flow.key.src_ip =
-		rte_bswap32((uint32_t)params->src_ip.addr.ipv4.s_addr);
-	rule.flow.key.dst_ip =
-		rte_bswap32((uint32_t)params->dst_ip.addr.ipv4.s_addr);
-	rule.flow.key.src_port = params->src_port;
-	rule.flow.key.dst_port = params->dst_port;
-	rule.flow.key.proto = params->proto;
-
-	/* Check rule existence */
-	IS_RULE_PRESENT(old_rule, rule.flow.key, flow_table, flow);
-	if (old_rule == NULL)
-		return;
-
-	printf("Deleting flow: ");
-	print_flow_rule(old_rule->flow);
-
-	/* Allocate message buffer */
-	msg = (void *)rte_ctrlmbuf_alloc(app.msg_pool);
-	if (msg == NULL)
-		rte_panic("Unable to allocate new message\n");
-
-	/* Fill request message */
-	req = (struct app_msg_req *)rte_ctrlmbuf_data((struct rte_mbuf *)msg);
-	memset(req, 0, sizeof(struct app_msg_req));
-
-	req->type = APP_MSG_REQ_FC_DEL;
-	req->flow_classif_del.key.ip_src = rte_bswap32(rule.flow.key.src_ip);
-	req->flow_classif_del.key.ip_dst = rte_bswap32(rule.flow.key.dst_ip);
-	req->flow_classif_del.key.port_src =
-		rte_bswap32(rule.flow.key.src_port);
-	req->flow_classif_del.key.port_dst =
-		rte_bswap32(rule.flow.key.dst_port);
-	req->flow_classif_del.key.proto = rule.flow.key.proto;
-
-	/* Send request */
-	do {
-		status = rte_ring_sp_enqueue(ring_req, msg);
-	} while (status == -ENOBUFS);
-
-	/* Wait for response */
-	do {
-		status = rte_ring_sc_dequeue(ring_resp, &msg);
-	} while (status != 0);
-	resp = (struct app_msg_resp *)rte_ctrlmbuf_data((struct rte_mbuf *)msg);
-
-	/* Check response */
-	if (resp->result != 0)
-		printf("Request FLOW_DEL failed (%u)\n", resp->result);
-	else {
-		TAILQ_REMOVE(&flow_table, old_rule, entries);
-		rte_free(old_rule);
-		n_flow_rules--;
-	}
-
-	/* Free message buffer */
-	rte_ctrlmbuf_free((struct rte_mbuf *)msg);
-}
-
-cmdline_parse_token_string_t cmd_flow_del_flow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_flow_del_result, flow_string,
-	"flow");
-
-cmdline_parse_token_string_t cmd_flow_del_del_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_flow_del_result, del_string, "del");
-
-cmdline_parse_token_ipaddr_t cmd_flow_del_src_ip =
-	TOKEN_IPADDR_INITIALIZER(struct cmd_flow_del_result, src_ip);
-
-cmdline_parse_token_ipaddr_t cmd_flow_del_dst_ip =
-	TOKEN_IPADDR_INITIALIZER(struct cmd_flow_del_result, dst_ip);
-
-cmdline_parse_token_num_t cmd_flow_del_src_port =
-	TOKEN_NUM_INITIALIZER(struct cmd_flow_del_result, src_port, UINT16);
-
-cmdline_parse_token_num_t cmd_flow_del_dst_port =
-	TOKEN_NUM_INITIALIZER(struct cmd_flow_del_result, dst_port, UINT16);
-
-cmdline_parse_token_num_t cmd_flow_del_proto =
-	TOKEN_NUM_INITIALIZER(struct cmd_flow_del_result, proto, UINT8);
-
-cmdline_parse_inst_t cmd_flow_del = {
-	.f = cmd_flow_del_parsed,
-	.data = NULL,
-	.help_str = "Flow delete",
-	.tokens = {
-		(void *)&cmd_flow_del_flow_string,
-		(void *)&cmd_flow_del_del_string,
-		(void *)&cmd_flow_del_src_ip,
-		(void *)&cmd_flow_del_dst_ip,
-		(void *)&cmd_flow_del_src_port,
-		(void *)&cmd_flow_del_dst_port,
-		(void *)&cmd_flow_del_proto,
-		NULL,
-	},
-};
-
-/* *** Flow Classification - Print *** */
-struct cmd_flow_print_result {
-	cmdline_fixed_string_t flow_string;
-	cmdline_fixed_string_t print_string;
-};
-
-static void
-cmd_flow_print_parsed(
-	__attribute__((unused)) void *parsed_result,
-	__attribute__((unused)) struct cmdline *cl,
-	__attribute__((unused)) void *data)
-{
-	struct app_rule *it;
-
-	TAILQ_FOREACH(it, &flow_table, entries) {
-		print_flow_rule(it->flow);
-	}
-}
-
-cmdline_parse_token_string_t cmd_flow_print_flow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_flow_print_result, flow_string,
-	"flow");
-
-cmdline_parse_token_string_t cmd_flow_print_print_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_flow_print_result, print_string,
-	"ls");
-
-cmdline_parse_inst_t cmd_flow_print = {
-	.f = cmd_flow_print_parsed,
-	.data = NULL,
-	.help_str = "Flow list",
-	.tokens = {
-		(void *)&cmd_flow_print_flow_string,
-		(void *)&cmd_flow_print_print_string,
-		NULL,
-	},
-};
-
-/* *** QUIT *** */
-struct cmd_quit_result {
-	cmdline_fixed_string_t quit;
-};
-
-static void cmd_quit_parsed(__attribute__((unused)) void *parsed_result,
-		struct cmdline *cl,
-		__attribute__((unused)) void *data)
-{
-	cmdline_quit(cl);
-}
-
-cmdline_parse_token_string_t cmd_quit_quit =
-		TOKEN_STRING_INITIALIZER(struct cmd_quit_result, quit, "quit");
-
-cmdline_parse_inst_t cmd_quit = {
-	.f = cmd_quit_parsed,
-	.data = NULL,
-	.help_str = "Exit application",
-	.tokens = {
-		(void *)&cmd_quit_quit,
-		NULL,
-	},
-};
-
-/* List of commands */
-cmdline_parse_ctx_t main_ctx[] = {
-	(cmdline_parse_inst_t *)&cmd_flow_add,
-	(cmdline_parse_inst_t *)&cmd_flow_del,
-	(cmdline_parse_inst_t *)&cmd_flow_add_all,
-	(cmdline_parse_inst_t *)&cmd_flow_print,
-#ifdef RTE_LIBRTE_ACL
-	(cmdline_parse_inst_t *)&cmd_firewall_add,
-	(cmdline_parse_inst_t *)&cmd_firewall_del,
-	(cmdline_parse_inst_t *)&cmd_firewall_print,
-#endif
-	(cmdline_parse_inst_t *)&cmd_route_add,
-	(cmdline_parse_inst_t *)&cmd_route_del,
-	(cmdline_parse_inst_t *)&cmd_routing_print,
-	(cmdline_parse_inst_t *)&cmd_arp_add,
-	(cmdline_parse_inst_t *)&cmd_arp_del,
-	(cmdline_parse_inst_t *)&cmd_arp_print,
-	(cmdline_parse_inst_t *)&cmd_run_file,
-	(cmdline_parse_inst_t *)&cmd_link_enable,
-	(cmdline_parse_inst_t *)&cmd_link_disable,
-	(cmdline_parse_inst_t *)&cmd_quit,
-	NULL,
-};
-
-/* Main loop */
-void
-app_main_loop_cmdline(void)
-{
-	struct cmdline *cl;
-	uint32_t core_id = rte_lcore_id();
-
-	RTE_LOG(INFO, USER1, "Core %u is running the command line interface\n",
-		core_id);
-
-	n_arp_rules = 0;
-	n_routing_rules = 0;
-	n_firewall_rules = 0;
-	n_flow_rules = 0;
-
-	app_init_rule_tables();
-
-	cl = cmdline_stdin_new(main_ctx, "pipeline> ");
-	if (cl == NULL)
-		return;
-	cmdline_interact(cl);
-	cmdline_stdin_exit(cl);
-}
diff --git a/examples/ip_pipeline/init.c b/examples/ip_pipeline/init.c
index 77d5f07..b066476 100644
--- a/examples/ip_pipeline/init.c
+++ b/examples/ip_pipeline/init.c
@@ -43,6 +43,7 @@
 
 #include "app.h"
 #include "pipeline.h"
+#include "pipeline_master.h"
 
 #define APP_NAME_SIZE	32
 
@@ -1142,6 +1143,8 @@ int app_init(struct app_params *app)
 	app_init_tm(app);
 	app_init_msgq(app);
 
+	app_pipeline_type_register(app, &pipeline_master);
+
 	app_init_pipelines(app);
 	app_init_threads(app);
 
diff --git a/examples/ip_pipeline/pipeline/pipeline_common.c b/examples/ip_pipeline/pipeline/pipeline_common.c
new file mode 100644
index 0000000..09bcc9a
--- /dev/null
+++ b/examples/ip_pipeline/pipeline/pipeline_common.c
@@ -0,0 +1,412 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <rte_ring.h>
+#include <rte_malloc.h>
+
+#include "pipeline_ops.h"
+#include "pipeline_common_ops.h"
+#include "pipeline.h"
+#include "pipeline_common.h"
+
+int
+app_pipeline_ping(struct app_params *app,
+	uint32_t pipeline_id)
+{
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	int status = 0;
+
+	/* Check input arguments */
+	if ((app == NULL) ||
+		(pipeline_id >= app->n_pipelines))
+		return -1;
+
+	/* Message buffer allocation */
+	req = app_msg_alloc(app);
+	if (req == NULL)
+		return -1;
+
+	/* Fill in request */
+	req->type = PIPELINE_MSG_REQ_PING;
+
+	/* Send request and wait for response */
+	rsp = app_msg_send_recv(app, pipeline_id, req, 1);
+	if (rsp == NULL)
+		return -1;
+
+	/* Check response */
+	status = rsp->status;
+
+	/* Message buffer free */
+	app_msg_free(app, rsp);
+
+	return status;
+}
+
+int
+app_pipeline_stats_port_in(struct app_params *app,
+	uint32_t pipeline_id,
+	uint32_t port_id,
+	struct rte_pipeline_port_in_stats *stats)
+{
+	struct pipeline_stats_msg_req *req;
+	struct pipeline_stats_port_in_msg_rsp *rsp;
+	struct app_pipeline_params *p;
+	int status = 0;
+
+	/* Check input arguments */
+	if ((app == NULL) ||
+		(pipeline_id >= app->n_pipelines) ||
+		(stats == NULL))
+		return -1;
+	
+	p = &app->pipeline_params[pipeline_id];
+	if (port_id >= p->n_pktq_in)
+		return -1;
+
+	/* Message buffer allocation */
+	req = app_msg_alloc(app);
+	if (req == NULL)
+		return -1;
+
+	/* Fill in request */
+	req->type = PIPELINE_MSG_REQ_STATS_PORT_IN;
+	req->id = port_id;
+
+	/* Send request and wait for response */
+	rsp = (struct pipeline_stats_port_in_msg_rsp *)
+		app_msg_send_recv(app, pipeline_id, req, 1);
+	if (rsp == NULL)
+		return -1;
+
+	/* Check response */
+	status = rsp->status;
+	memcpy(stats, &rsp->stats, sizeof(rsp->stats));
+	
+	/* Message buffer free */
+	app_msg_free(app, rsp);
+
+	return status;
+}
+
+int
+app_pipeline_stats_port_out(struct app_params *app,
+	uint32_t pipeline_id,
+	uint32_t port_id,
+	struct rte_pipeline_port_out_stats *stats)
+{
+	struct pipeline_stats_msg_req *req;
+	struct pipeline_stats_port_out_msg_rsp *rsp;
+	struct app_pipeline_params *p;
+	int status = 0;
+
+	/* Check input arguments */
+	if ((app == NULL) ||
+		(pipeline_id >= app->n_pipelines) ||
+		(stats == NULL))
+		return -1;
+	
+	p = &app->pipeline_params[pipeline_id];
+	if (port_id >= p->n_pktq_out)
+		return -1;
+
+	/* Message buffer allocation */
+	req = app_msg_alloc(app);
+	if (req == NULL)
+		return -1;
+
+	/* Fill in request */
+	req->type = PIPELINE_MSG_REQ_STATS_PORT_OUT;
+	req->id = port_id;
+
+	/* Send request and wait for response */
+	rsp = app_msg_send_recv(app, pipeline_id, req, 1);
+	if (rsp == NULL)
+		return -1;
+
+	/* Check response */
+	status = rsp->status;
+	memcpy(stats, &rsp->stats, sizeof(rsp->stats));
+	
+	/* Message buffer free */
+	app_msg_free(app, rsp);
+
+	return status;
+}
+
+int
+app_pipeline_stats_table(struct app_params *app,
+	uint32_t pipeline_id,
+	uint32_t table_id,
+	struct rte_pipeline_table_stats *stats)
+{
+	struct pipeline_stats_msg_req *req;
+	struct pipeline_stats_table_msg_rsp *rsp;
+	int status = 0;
+
+	/* Check input arguments */
+	if ((app == NULL) ||
+		(pipeline_id >= app->n_pipelines) ||
+		(stats == NULL))
+		return -1;
+
+	/* Message buffer allocation */
+	req = app_msg_alloc(app);
+	if (req == NULL)
+		return -1;
+
+	/* Fill in request */
+	req->type = PIPELINE_MSG_REQ_STATS_TABLE;
+	req->id = table_id;
+
+	/* Send request and wait for response */
+	rsp = app_msg_send_recv(app, pipeline_id, req, 1);
+	if (rsp == NULL)
+		return -1;
+
+	/* Check response */
+	status = rsp->status;
+	memcpy(stats, &rsp->stats, sizeof(rsp->stats));
+	
+	/* Message buffer free */
+	app_msg_free(app, rsp);
+
+	return status;
+}
+
+int
+app_pipeline_port_in_enable(struct app_params *app,
+	uint32_t pipeline_id,
+	uint32_t port_id)
+{
+	struct pipeline_port_in_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	struct app_pipeline_params *p;
+	int status = 0;
+
+	/* Check input arguments */
+	if ((app == NULL) ||
+		(pipeline_id >= app->n_pipelines))
+		return -1;
+	
+	p = &app->pipeline_params[pipeline_id];
+	if (port_id >= p->n_pktq_in)
+		return -1;
+
+	/* Message buffer allocation */
+	req = app_msg_alloc(app);
+	if (req == NULL)
+		return -1;
+
+	/* Fill in request */
+	req->type = PIPELINE_MSG_REQ_PORT_IN_ENABLE;
+	req->port_id = port_id;
+
+	/* Send request and wait for response */
+	rsp = app_msg_send_recv(app, pipeline_id, req, 1);
+	if (rsp == NULL)
+		return -1;
+
+	/* Check response */
+	status = rsp->status;
+	
+	/* Message buffer free */
+	app_msg_free(app, rsp);
+
+	return status;
+}
+
+int
+app_pipeline_port_in_disable(struct app_params *app,
+	uint32_t pipeline_id,
+	uint32_t port_id)
+{
+	struct pipeline_port_in_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	struct app_pipeline_params *p;
+	int status = 0;
+
+	/* Check input arguments */
+	if ((app == NULL) ||
+		(pipeline_id >= app->n_pipelines))
+		return -1;
+
+	p = &app->pipeline_params[pipeline_id];
+	if (port_id >= p->n_pktq_in)
+		return -1;
+
+	/* Message buffer allocation */
+	req = app_msg_alloc(app);
+	if (req == NULL)
+		return -1;
+
+	/* Fill in request */
+	req->type = PIPELINE_MSG_REQ_PORT_IN_DISABLE;
+	req->port_id = port_id;
+
+	/* Send request and wait for response */
+	rsp = app_msg_send_recv(app, pipeline_id, req, 1);
+	if (rsp == NULL)
+		return -1;
+
+	/* Check response */
+	status = rsp->status;
+	
+	/* Message buffer free */
+	app_msg_free(app, rsp);
+
+	return status;
+}
+
+int
+app_link_config(struct app_params *app,
+	uint32_t link_id,
+	uint32_t ip,
+	uint32_t depth)
+{
+	struct app_link_params *p;
+	uint32_t i, netmask, host, bcast;
+	int status = 0;
+	
+	/* Check input arguments */
+	if (app == NULL)
+		return -1;
+
+	if (link_id >= app->n_links) {
+		RTE_LOG(ERR, USER1, "LINK%u is not a valid link\n", link_id);
+		return -1;
+	}
+
+	if ((depth == 0) || (depth > 32)) {
+		RTE_LOG(ERR, USER1, "Illegal value for depth parameter (%u)\n", depth);
+		return -1;
+	}
+
+	netmask = (~0) << (32 - depth);
+	host = ip & netmask;
+	bcast = host | (~netmask);
+	
+	if ((ip == 0) ||
+		(ip == UINT32_MAX) ||
+		(ip == host) ||
+		(ip == bcast)) {
+		RTE_LOG(ERR, USER1, "Illegal IP address\n");
+		return -1;
+	}
+
+	for (i = 0; i < app->n_links; i++) {
+		uint32_t id;
+
+		p = &app->link_params[i];
+		APP_PARAM_GET_ID(p, "LINK", id);
+		
+		if (link_id == id)
+			continue;
+
+		if (p->ip == ip) {
+			RTE_LOG(ERR, USER1, "%s is already assigned this IP address\n", p->name);
+			return -1;
+		}
+	}
+
+	APP_PARAM_FIND_BY_ID(app->link_params, "LINK", link_id, p);
+	if (p->state) {
+		RTE_LOG(ERR, USER1, "%s is UP, please bring it DOWN first\n", p->name);
+		return -1;
+	}
+
+	/* Save link parameters */
+	p->ip = ip;
+	p->depth = depth;		
+
+	return status;
+}
+
+int
+app_link_up(struct app_params *app,
+	uint32_t link_id)
+{
+	struct app_link_params *p;
+	int status = 0;
+	
+	/* Check input arguments */
+	if (app == NULL)
+		return -1;
+
+	if (link_id >= app->n_links) {
+		RTE_LOG(ERR, USER1, "LINK%u is not a valid link\n", link_id);
+		return -1;
+	}
+
+	APP_PARAM_FIND_BY_ID(app->link_params, "LINK", link_id, p);
+
+	/* Check link state */
+	if (p->state) {
+		RTE_LOG(ERR, USER1,"%s is already UP\n", p->name);
+		return 0;
+	}
+
+	app_link_up_internal(app, p);
+
+	return status;
+}
+
+int
+app_link_down(struct app_params *app,
+	uint32_t link_id)
+{
+	struct app_link_params *p;
+	int status =0;
+	
+	/* Check input arguments */
+	if (app == NULL)
+		return -1;
+
+	if (link_id >= app->n_links) {
+		RTE_LOG(ERR, USER1,"LINK%u is not a valid link\n", link_id);
+		return -1;
+	}
+
+	APP_PARAM_FIND_BY_ID(app->link_params, "LINK", link_id, p);
+	
+	/* Check link state */
+	if (p->state == 0) {
+		RTE_LOG(ERR, USER1,"%s is already DOWN\n", p->name);
+		return 0;
+	}
+
+	app_link_down_internal(app, p);
+
+	return status;
+}
diff --git a/examples/ip_pipeline/pipeline/pipeline_common.h b/examples/ip_pipeline/pipeline/pipeline_common.h
new file mode 100644
index 0000000..d1ded0a
--- /dev/null
+++ b/examples/ip_pipeline/pipeline/pipeline_common.h
@@ -0,0 +1,241 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __INCLUDE_PIPELINE_COMMON_H__
+#define __INCLUDE_PIPELINE_COMMON_H__
+
+#include <rte_common.h>
+#include <rte_cycles.h>
+#include <rte_malloc.h>
+#include <cmdline_parse.h>
+
+#include "pipeline_common_ops.h"
+#include "pipeline.h"
+#include "app.h"
+
+static inline struct app_pipeline_data *
+app_pipeline_data(struct app_params *app, uint32_t id)
+{
+	struct app_pipeline_params *params;
+
+	APP_CHECK(app != NULL, "BUG: %s(): app == NULL", __func__);
+
+	APP_PARAM_FIND_BY_ID(app->pipeline_params, "PIPELINE", id, params);
+
+	if (params == NULL) {
+		printf("Pipeline %" PRIu32 " not found\n", id);
+		return NULL;
+	}
+
+	return &app->pipeline_data[params - app->pipeline_params];
+}
+
+static inline void *
+app_pipeline_data_fe(struct app_params *app, uint32_t id)
+{
+	struct app_pipeline_data *pipeline_data;
+
+	pipeline_data = app_pipeline_data(app, id);
+
+	if (pipeline_data == NULL)
+		return NULL;
+
+	return pipeline_data->fe;
+}
+
+static inline struct rte_ring *
+app_pipeline_msgq_in_get(struct app_params *app,
+	uint32_t pipeline_id)
+{	
+	char msgq_name[APP_PARAM_NAME_SIZE];
+	struct app_pipeline_params *p = &app->pipeline_params[pipeline_id];
+	uint32_t i;
+
+	sprintf(msgq_name, "MSGQ-REQ-PIPELINE%u", pipeline_id);
+	
+	for (i = 0; i < p->n_msgq_in; i++){
+		uint32_t msgq_id = p->msgq_in[i];
+		struct app_msgq_params *p_msgq = &app->msgq_params[msgq_id];
+		struct rte_ring *r = app->msgq[msgq_id];
+		
+		if (strcmp(p_msgq->name, msgq_name) == 0)
+			return r;
+	}
+
+	APP_CHECK(1, "%s not found\n", msgq_name);
+	return NULL;
+}
+
+static inline struct rte_ring *
+app_pipeline_msgq_out_get(struct app_params *app,
+	uint32_t pipeline_id)
+{
+	char msgq_name[APP_PARAM_NAME_SIZE];
+	struct app_pipeline_params *p = &app->pipeline_params[pipeline_id];
+	uint32_t i;
+
+	sprintf(msgq_name, "MSGQ-RSP-PIPELINE%u", pipeline_id);
+	
+	for (i = 0; i < p->n_msgq_out; i++){
+		uint32_t msgq_id = p->msgq_out[i];
+		struct app_msgq_params *p_msgq = &app->msgq_params[msgq_id];
+		struct rte_ring *r = app->msgq[msgq_id];
+		
+		if (strcmp(p_msgq->name, msgq_name) == 0)
+			return r;
+	}
+
+	APP_CHECK(1, "%s not found\n", msgq_name);
+	return NULL;
+}
+
+static inline void *
+app_msg_alloc(__rte_unused struct app_params *app)
+{
+	return rte_malloc(NULL, 2048, RTE_CACHE_LINE_SIZE);
+}
+
+static inline void
+app_msg_free(__rte_unused struct app_params *app,
+	void *msg)
+{
+	rte_free(msg);
+}
+
+static inline void
+app_msg_send(struct app_params *app,
+	uint32_t pipeline_id,
+	void *msg)
+{
+	struct rte_ring *r = app_pipeline_msgq_in_get(app, pipeline_id);
+	int status;
+
+	do {
+		status = rte_ring_sp_enqueue(r, msg);
+	} while (status == -ENOBUFS);
+}
+
+static inline void *
+app_msg_recv(struct app_params *app,
+	uint32_t pipeline_id)
+{
+	struct rte_ring *r = app_pipeline_msgq_out_get(app, pipeline_id);
+	void *msg;
+	int status = rte_ring_sc_dequeue(r, &msg);
+
+	if (status != 0)
+		return NULL;
+
+	return msg;
+}
+
+static inline void *
+app_msg_send_recv(struct app_params *app,
+	uint32_t pipeline_id,
+	void *msg,
+	uint32_t timeout_ms)
+{
+	struct rte_ring *r_req = app_pipeline_msgq_in_get(app, pipeline_id);
+	struct rte_ring *r_rsp = app_pipeline_msgq_out_get(app, pipeline_id);
+	uint64_t hz = rte_get_tsc_hz();
+	void *msg_recv;
+	uint64_t deadline;
+	int status;
+
+	/* send */
+	do {
+		status = rte_ring_sp_enqueue(r_req, (void *) msg);
+	} while (status == -ENOBUFS);
+
+	/* recv */
+	deadline = (timeout_ms)?
+		(rte_rdtsc() + ((hz * timeout_ms) / 1000)) :
+		UINT64_MAX;
+
+	do {
+		if (rte_rdtsc() > deadline)
+			return NULL;
+
+		status = rte_ring_sc_dequeue(r_rsp, &msg_recv);
+	} while (status != 0);
+
+	return msg_recv;
+}
+
+int
+app_pipeline_ping(struct app_params *app,
+	uint32_t pipeline_id);
+
+int
+app_pipeline_stats_port_in(struct app_params *app,
+	uint32_t pipeline_id,
+	uint32_t port_id,
+	struct rte_pipeline_port_in_stats *stats);
+
+int
+app_pipeline_stats_port_out(struct app_params *app,
+	uint32_t pipeline_id,
+	uint32_t port_id,
+	struct rte_pipeline_port_out_stats *stats);
+
+int
+app_pipeline_stats_table(struct app_params *app,
+	uint32_t pipeline_id,
+	uint32_t table_id,
+	struct rte_pipeline_table_stats *stats);
+
+int
+app_pipeline_port_in_enable(struct app_params *app,
+	uint32_t pipeline_id,
+	uint32_t port_id);
+
+int
+app_pipeline_port_in_disable(struct app_params *app,
+	uint32_t pipeline_id,
+	uint32_t port_id);
+
+int
+app_link_config(struct app_params *app,
+	uint32_t link_id,
+	uint32_t ip,
+	uint32_t depth);
+
+int
+app_link_up(struct app_params *app,
+	uint32_t link_id);
+
+int
+app_link_down(struct app_params *app,
+	uint32_t link_id);
+
+#endif
diff --git a/examples/ip_pipeline/pipeline/pipeline_common_ops.c b/examples/ip_pipeline/pipeline/pipeline_common_ops.c
new file mode 100644
index 0000000..0624172
--- /dev/null
+++ b/examples/ip_pipeline/pipeline/pipeline_common_ops.c
@@ -0,0 +1,205 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <rte_common.h>
+#include <rte_ring.h>
+#include <rte_malloc.h>
+
+#include "pipeline_ops.h"
+#include "pipeline_common_ops.h"
+
+void *
+pipeline_msg_req_ping_handler(__rte_unused struct pipeline *p,
+	void *msg)
+{
+	struct pipeline_msg_rsp *rsp = msg;
+
+	rsp->status = 0; /* OK */
+
+	return rsp;
+}
+
+void *
+pipeline_msg_req_stats_port_in_handler(__rte_unused struct pipeline *p,
+	void *msg)
+{
+	struct pipeline_stats_msg_req *req = msg;
+	struct pipeline_stats_port_in_msg_rsp *rsp = msg;
+	uint32_t port_id;
+
+	/* Check request */
+	if (req->id >= p->n_ports_in){
+		rsp->status = -1;
+		return rsp;
+	}
+	port_id = p->port_in_id[req->id];
+
+	/* Process request */
+	rsp->status = rte_pipeline_port_in_stats_read(p->p,
+		port_id,
+		&rsp->stats,
+		1);
+
+	return rsp;
+}
+
+void *
+pipeline_msg_req_stats_port_out_handler(__rte_unused struct pipeline *p,
+	void *msg)
+{
+	struct pipeline_stats_msg_req *req = msg;
+	struct pipeline_stats_port_out_msg_rsp *rsp = msg;
+	uint32_t port_id;
+
+	/* Check request */
+	if (req->id >= p->n_ports_out){
+		rsp->status = -1;
+		return rsp;
+	}
+	port_id = p->port_out_id[req->id];
+
+	/* Process request */
+	rsp->status = rte_pipeline_port_out_stats_read(p->p,
+		port_id,
+		&rsp->stats,
+		1);
+
+	return rsp;
+}
+
+void *
+pipeline_msg_req_stats_table_handler(__rte_unused struct pipeline *p,
+	void *msg)
+{
+	struct pipeline_stats_msg_req *req = msg;
+	struct pipeline_stats_table_msg_rsp *rsp = msg;
+	uint32_t table_id;
+
+	/* Check request */
+	if (req->id >= p->n_tables){
+		rsp->status = -1;
+		return rsp;
+	}
+	table_id = p->table_id[req->id];
+
+	/* Process request */
+	rsp->status = rte_pipeline_table_stats_read(p->p,
+		table_id,
+		&rsp->stats,
+		1);
+
+	return rsp;
+}
+
+void *
+pipeline_msg_req_port_in_enable_handler(__rte_unused struct pipeline *p,
+	void *msg)
+{
+	struct pipeline_port_in_msg_req *req = msg;
+	struct pipeline_msg_rsp *rsp = msg;
+	uint32_t port_id;
+
+	/* Check request */
+	if (req->port_id >= p->n_ports_in){
+		rsp->status = -1;
+		return rsp;
+	}
+	port_id = p->port_in_id[req->port_id];
+
+	/* Process request */
+	rsp->status = rte_pipeline_port_in_enable(p->p,
+		port_id);
+
+	return rsp;
+}
+
+void *
+pipeline_msg_req_port_in_disable_handler(__rte_unused struct pipeline *p,
+	void *msg)
+{
+	struct pipeline_port_in_msg_req *req = msg;
+	struct pipeline_msg_rsp *rsp = msg;
+	uint32_t port_id;
+
+	/* Check request */
+	if (req->port_id >= p->n_ports_in){
+		rsp->status = -1;
+		return rsp;
+	}
+	port_id = p->port_in_id[req->port_id];
+
+	/* Process request */
+	rsp->status = rte_pipeline_port_in_disable(p->p,
+		port_id);
+
+	return rsp;
+}
+
+void *
+pipeline_msg_req_invalid_handler(__rte_unused struct pipeline *p,
+	void *msg)
+{
+	struct pipeline_msg_rsp *rsp = msg;
+
+	rsp->status = -1; /* Error */
+
+	return rsp;
+}
+
+int
+pipeline_msg_req_handle(struct pipeline *p)
+{
+	uint32_t msgq_id;
+
+	for (msgq_id = 0; msgq_id < p->n_msgq; msgq_id++) {
+		for ( ; ; ) {
+			struct pipeline_msg_req *req;
+			pipeline_msg_req_handler f_handle;
+
+			req = pipeline_msg_recv(p, msgq_id);
+			if (req == NULL)
+				break;
+
+			f_handle = (req->type < PIPELINE_MSG_REQS)?
+				p->handlers[req->type] :
+				pipeline_msg_req_invalid_handler;
+
+			if (f_handle == NULL)
+				f_handle = pipeline_msg_req_invalid_handler;
+
+			pipeline_msg_send(p, msgq_id, f_handle(p, (void *) req));
+		}
+	}
+
+	return 0;
+}
diff --git a/examples/ip_pipeline/pipeline/pipeline_common_ops.h b/examples/ip_pipeline/pipeline/pipeline_common_ops.h
new file mode 100644
index 0000000..7181483
--- /dev/null
+++ b/examples/ip_pipeline/pipeline/pipeline_common_ops.h
@@ -0,0 +1,150 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __INCLUDE_PIPELINE_COMMON_OPS_H__
+#define __INCLUDE_PIPELINE_COMMON_OPS_H__
+
+#include <rte_common.h>
+#include <rte_ring.h>
+#include <rte_pipeline.h>
+
+#include "pipeline_ops.h"
+
+struct pipeline;
+
+enum pipeline_msg_req_type {
+	PIPELINE_MSG_REQ_PING = 0,
+	PIPELINE_MSG_REQ_STATS_PORT_IN,
+	PIPELINE_MSG_REQ_STATS_PORT_OUT,
+	PIPELINE_MSG_REQ_STATS_TABLE,
+	PIPELINE_MSG_REQ_PORT_IN_ENABLE,
+	PIPELINE_MSG_REQ_PORT_IN_DISABLE,
+	PIPELINE_MSG_REQ_CUSTOM,
+	PIPELINE_MSG_REQS
+};
+
+typedef void *(*pipeline_msg_req_handler)(struct pipeline *p, void *msg);
+
+struct pipeline {
+	struct rte_pipeline *p;
+	uint32_t port_in_id[PIPELINE_MAX_PORT_IN];
+	uint32_t port_out_id[PIPELINE_MAX_PORT_OUT];
+	uint32_t table_id[PIPELINE_MAX_TABLES];
+	struct rte_ring *msgq_in[PIPELINE_MAX_MSGQ_IN];
+	struct rte_ring *msgq_out[PIPELINE_MAX_MSGQ_OUT];
+
+	uint32_t n_ports_in;
+	uint32_t n_ports_out;
+	uint32_t n_tables;
+	uint32_t n_msgq;
+
+	pipeline_msg_req_handler handlers[PIPELINE_MSG_REQS];
+	char name[PIPELINE_NAME_SIZE];
+};
+
+static inline void *
+pipeline_msg_recv(struct pipeline *p,
+	uint32_t msgq_id)
+{
+	struct rte_ring *r = p->msgq_in[msgq_id];
+	void *msg;
+	int status = rte_ring_sc_dequeue(r, &msg);
+
+	if (status != 0)
+		return NULL;
+
+	return msg;
+}
+
+static inline void
+pipeline_msg_send(struct pipeline *p,
+	uint32_t msgq_id,
+	void *msg)
+{
+	struct rte_ring *r = p->msgq_out[msgq_id];
+	int status;
+
+	do {
+		status = rte_ring_sp_enqueue(r, msg);
+	} while (status == -ENOBUFS);
+}
+
+struct pipeline_msg_req {
+	enum pipeline_msg_req_type type;
+};
+
+struct pipeline_stats_msg_req {
+	enum pipeline_msg_req_type type;
+	uint32_t id;
+};
+
+struct pipeline_port_in_msg_req {
+	enum pipeline_msg_req_type type;
+	uint32_t port_id;
+};
+
+struct pipeline_custom_msg_req {
+	enum pipeline_msg_req_type type;
+	uint32_t subtype;
+};
+
+struct pipeline_msg_rsp {
+	int status;
+};
+
+struct pipeline_stats_port_in_msg_rsp {
+	int status;
+	struct rte_pipeline_port_in_stats stats;
+};
+
+struct pipeline_stats_port_out_msg_rsp {
+	int status;
+	struct rte_pipeline_port_out_stats stats;
+};
+
+struct pipeline_stats_table_msg_rsp {
+	int status;
+	struct rte_pipeline_table_stats stats;
+};
+
+void *pipeline_msg_req_ping_handler(struct pipeline *p, void *msg);
+void *pipeline_msg_req_stats_port_in_handler(struct pipeline *p, void *msg);
+void *pipeline_msg_req_stats_port_out_handler(struct pipeline *p, void *msg);
+void *pipeline_msg_req_stats_table_handler(struct pipeline *p, void *msg);
+void *pipeline_msg_req_port_in_enable_handler(struct pipeline *p, void *msg);
+void *pipeline_msg_req_port_in_disable_handler(struct pipeline *p, void *msg);
+void *pipeline_msg_req_invalid_handler(struct pipeline *p, void *msg);
+
+int pipeline_msg_req_handle(struct pipeline *p);
+
+#endif
diff --git a/examples/ip_pipeline/pipeline/pipeline_master.c b/examples/ip_pipeline/pipeline/pipeline_master.c
new file mode 100644
index 0000000..ee14948
--- /dev/null
+++ b/examples/ip_pipeline/pipeline/pipeline_master.c
@@ -0,0 +1,870 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <cmdline_rdline.h>
+#include <cmdline_parse.h>
+#include <cmdline_parse_num.h>
+#include <cmdline_parse_string.h>
+#include <cmdline_parse_ipaddr.h>
+#include <cmdline_parse_etheraddr.h>
+#include <cmdline_socket.h>
+#include <cmdline.h> 
+
+#include "app.h"
+#include "pipeline_common.h"
+#include "pipeline_master_ops.h"
+#include "pipeline_master.h"
+
+/*
+ * run
+ */
+
+static void
+app_run_file(
+	cmdline_parse_ctx_t *ctx,
+	const char *file_name)
+{
+	struct cmdline *file_cl;
+
+	int fd = open(file_name, O_RDONLY);
+	if (fd < 0) {
+		printf("Cannot open file \"%s\"\n", file_name);
+		return;
+	}
+
+	file_cl = cmdline_new(ctx, "", fd, 1);
+	cmdline_interact(file_cl);
+	close(fd);
+}
+
+struct cmd_run_file_result {
+	cmdline_fixed_string_t run_string;
+	char file_name[APP_FILE_NAME_SIZE];
+};
+
+static void
+cmd_run_parsed(
+	void *parsed_result,
+	struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_run_file_result *params = parsed_result;
+
+	app_run_file(cl->ctx, params->file_name);
+}
+
+cmdline_parse_token_string_t cmd_run_run_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_run_file_result, run_string, "run");
+
+cmdline_parse_token_string_t cmd_run_file_name =
+	TOKEN_STRING_INITIALIZER(struct cmd_run_file_result, file_name, NULL);
+
+cmdline_parse_inst_t cmd_run = {
+	.f = cmd_run_parsed,
+	.data = NULL,
+	.help_str = "Run CLI script file",
+	.tokens = {
+		(void *) &cmd_run_run_string,
+		(void *) &cmd_run_file_name,
+		NULL,
+	},
+};
+
+/*
+ * quit
+ */
+
+struct cmd_quit_result {
+	cmdline_fixed_string_t quit;
+};
+
+static void
+cmd_quit_parsed(
+	__rte_unused void *parsed_result,
+	struct cmdline *cl,
+	__rte_unused void *data)
+{
+	cmdline_quit(cl);
+}
+
+static cmdline_parse_token_string_t cmd_quit_quit =
+	TOKEN_STRING_INITIALIZER(struct cmd_quit_result, quit, "quit");
+
+static cmdline_parse_inst_t cmd_quit = {
+	.f = cmd_quit_parsed,
+	.data = NULL,
+	.help_str = "Quit",
+	.tokens = {
+		(void *) &cmd_quit_quit,
+		NULL,
+	},
+};
+
+/* 
+ * link config
+ */
+
+static void 
+print_link_info(struct app_link_params *p)
+{
+	struct rte_eth_stats stats;
+	struct ether_addr *mac_addr;
+	uint32_t netmask =(~0) << (32 - p->depth);
+ 	uint32_t host = p->ip & netmask;
+	uint32_t bcast = host | (~netmask);
+
+	memset(&stats, 0, sizeof(stats));
+	rte_eth_stats_get(p->pmd_id, &stats);
+
+	mac_addr = (struct ether_addr *) &p->mac_addr;
+	
+	printf("%s: flags=<%s>\n", 
+		p->name,
+		(p->state)? "UP" : "DOWN");
+
+	if (p->ip)
+		printf("\tinet %u.%u.%u.%u  netmask %u.%u.%u.%u broadcast %u.%u.%u.%u\n",
+			(p->ip >> 24) & 0xFF,
+			(p->ip >> 16) & 0xFF,
+			(p->ip >> 8) & 0xFF,
+			p->ip & 0xFF,
+			(netmask >> 24) & 0xFF,
+			(netmask >> 16) & 0xFF,
+			(netmask >> 8) & 0xFF,
+			netmask & 0xFF,
+			(bcast >> 24) & 0xFF,
+			(bcast >> 16) & 0xFF,
+			(bcast >> 8) & 0xFF,
+			bcast & 0xFF);
+
+	printf("\tether %02x:%02x:%02x:%02x:%02x:%02x\n",
+		mac_addr->addr_bytes[0],
+		mac_addr->addr_bytes[1],
+		mac_addr->addr_bytes[2],
+		mac_addr->addr_bytes[3],
+		mac_addr->addr_bytes[4],
+		mac_addr->addr_bytes[5]);
+
+	printf("\tRX packets %" PRIu64 
+		"  bytes %" PRIu64
+		"\n",
+		stats.ipackets,
+		stats.ibytes);
+
+	printf("\tRX mcast %" PRIu64
+		"  fdirmatch %" PRIu64
+		"  fdirmiss %" PRIu64
+		"  lb-packets %" PRIu64
+		"  lb-bytes %" PRIu64
+		"  xon %" PRIu64
+		"  xoff %" PRIu64 "\n",
+		stats.imcasts,
+		stats.fdirmatch,
+		stats.fdirmiss,
+		stats.ilbpackets,
+		stats.ilbbytes,
+		stats.rx_pause_xon,
+		stats.rx_pause_xoff);
+
+	printf("\tRX errors %" PRIu64
+		"  missed %" PRIu64
+		"  badcrc %" PRIu64
+		"  badlen %" PRIu64
+		"  no-mbuf %" PRIu64
+		"\n",
+		stats.ierrors,
+		stats.imissed,
+		stats.ibadcrc,
+		stats.ibadlen,
+		stats.rx_nombuf);
+
+	printf("\tTX packets %" PRIu64
+		"  bytes %" PRIu64 "\n", 
+		stats.opackets, 
+		stats.obytes);
+
+	printf("\tTX lb-packets %" PRIu64
+		"  lb-bytes %" PRIu64
+		"  xon %" PRIu64
+		"  xoff %" PRIu64
+		"\n",
+		stats.olbpackets,
+		stats.olbbytes,
+		stats.tx_pause_xon,
+		stats.tx_pause_xoff);
+
+	printf("\tTX errors %" PRIu64
+		"\n",
+		stats.oerrors);
+
+	printf("\n");
+}
+
+struct cmd_link_config_result {
+	cmdline_fixed_string_t link_string;
+	uint32_t link_id;
+	cmdline_fixed_string_t config_string;
+	cmdline_ipaddr_t ip;
+	uint32_t depth;
+};
+
+static void
+cmd_link_config_parsed(
+	void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	 void *data)
+{
+	struct cmd_link_config_result *params = parsed_result;
+	struct app_params *app = data;
+	int status;
+
+	uint32_t link_id = params->link_id;
+	uint32_t ip  = rte_bswap32((uint32_t) params->ip.addr.ipv4.s_addr);
+	uint32_t depth = params->depth;
+
+	status = app_link_config(app, link_id, ip, depth);
+	if(status)
+		printf("link config failed\n");
+	else {
+		struct app_link_params *p;
+
+		APP_PARAM_FIND_BY_ID(app->link_params, "LINK", link_id, p);
+		print_link_info(p);
+	}
+}
+
+cmdline_parse_token_string_t cmd_link_config_link_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_link_config_result, link_string, "link");
+
+cmdline_parse_token_num_t cmd_link_config_link_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_link_config_result, link_id, UINT32);
+
+cmdline_parse_token_string_t cmd_link_config_config_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_link_config_result, config_string, "config");
+
+cmdline_parse_token_ipaddr_t cmd_link_config_ip =
+	TOKEN_IPADDR_INITIALIZER(struct cmd_link_config_result, ip);
+
+cmdline_parse_token_num_t cmd_link_config_depth =
+	TOKEN_NUM_INITIALIZER(struct cmd_link_config_result, depth, UINT32);
+
+cmdline_parse_inst_t cmd_link_config = {
+	.f = cmd_link_config_parsed,
+	.data = NULL,
+	.help_str = "Link configuration",
+	.tokens = {
+		(void *)&cmd_link_config_link_string,
+		(void *)&cmd_link_config_link_id,
+		(void *)&cmd_link_config_config_string,
+		(void *)&cmd_link_config_ip,
+		(void *)&cmd_link_config_depth,
+		NULL,
+	},
+};
+
+/* 
+ * link up
+ */
+
+struct cmd_link_up_result {
+	cmdline_fixed_string_t link_string;
+	uint32_t link_id;
+	cmdline_fixed_string_t up_string;
+};
+
+static void
+cmd_link_up_parsed(
+	void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	void *data)
+{
+	struct cmd_link_up_result *params = parsed_result;
+	struct app_params *app = data;
+	int status;
+
+	status = app_link_up(app, params->link_id);
+	if(status != 0)
+		printf("link up failed \n");
+	else {
+		struct app_link_params *p;
+
+		APP_PARAM_FIND_BY_ID(app->link_params, "LINK", params->link_id, p);
+		print_link_info(p);
+	}
+}
+
+cmdline_parse_token_string_t cmd_link_up_link_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_link_up_result, link_string, "link");
+
+cmdline_parse_token_num_t cmd_link_up_link_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_link_up_result, link_id, UINT32);
+
+cmdline_parse_token_string_t cmd_link_up_up_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_link_up_result, up_string, "up");
+
+cmdline_parse_inst_t cmd_link_up = {
+	.f = cmd_link_up_parsed,
+	.data = NULL,
+	.help_str = "Link UP",
+	.tokens = {
+		(void *)&cmd_link_up_link_string,
+		(void *)&cmd_link_up_link_id,
+		(void *)&cmd_link_up_up_string,
+		NULL,
+	},
+};
+
+/*
+ * link down
+ */
+
+struct cmd_link_down_result {
+	cmdline_fixed_string_t link_string;
+	uint32_t link_id;
+	cmdline_fixed_string_t down_string;
+};
+
+static void
+cmd_link_down_parsed(
+	void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	void *data)
+{
+	struct cmd_link_down_result *params = parsed_result;
+	struct app_params *app = data;	
+	int status;
+	
+	status = app_link_down(app, params->link_id);
+	if(status != 0)
+		printf("link down failed\n");
+	else {
+		struct app_link_params *p;
+
+		APP_PARAM_FIND_BY_ID(app->link_params, "LINK", params->link_id, p);
+		print_link_info(p);
+	}
+}
+
+cmdline_parse_token_string_t cmd_link_down_link_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_link_down_result, link_string, "link");
+
+cmdline_parse_token_num_t cmd_link_down_link_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_link_down_result, link_id, UINT32);
+
+cmdline_parse_token_string_t cmd_link_down_down_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_link_down_result, down_string, "down");
+
+cmdline_parse_inst_t cmd_link_down = {
+	.f = cmd_link_down_parsed,
+	.data = NULL,
+	.help_str = "Link DOWN",
+	.tokens = {
+		(void *) &cmd_link_down_link_string,
+		(void *) &cmd_link_down_link_id,
+		(void *) &cmd_link_down_down_string,
+		NULL,
+	},
+};
+
+/*
+ * link ls
+ */
+
+struct cmd_link_ls_result {
+	cmdline_fixed_string_t link_string;
+	cmdline_fixed_string_t ls_string;
+};
+
+static void
+cmd_link_ls_parsed(
+	__attribute__((unused)) void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	 void *data)
+{
+	struct app_params *app = data;
+	uint32_t link_id;
+
+	for (link_id = 0; link_id < app->n_links; link_id++) {
+		struct app_link_params *p;
+
+		APP_PARAM_FIND_BY_ID(app->link_params, "LINK", link_id, p);
+		print_link_info(p);
+	}
+}
+
+cmdline_parse_token_string_t cmd_link_ls_link_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_link_ls_result, link_string, "link");
+
+cmdline_parse_token_string_t cmd_link_ls_ls_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_link_ls_result, ls_string, "ls");
+
+cmdline_parse_inst_t cmd_link_ls = {
+	.f = cmd_link_ls_parsed,
+	.data = NULL,
+	.help_str = "Link list",
+	.tokens = {
+		(void *)&cmd_link_ls_link_string,
+		(void *)&cmd_link_ls_ls_string,
+		NULL,
+	},
+};
+
+/* 
+ * ping 
+ */
+
+struct cmd_ping_result {
+	cmdline_fixed_string_t p_string;
+	uint32_t pipeline_id;
+	cmdline_fixed_string_t ping_string;
+};
+
+static void
+cmd_ping_parsed(
+	void *parsed_result,
+	__rte_unused struct cmdline *cl,
+	void *data)
+{
+	struct cmd_ping_result *params = parsed_result;
+	struct app_params *app = data;
+	int status;
+
+	status = app_pipeline_ping(app,	params->pipeline_id);
+	if(status != 0)
+		printf("ping failed\n");
+}
+
+cmdline_parse_token_string_t cmd_ping_p_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_ping_result, p_string, "p");
+
+cmdline_parse_token_num_t cmd_ping_pipeline_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_ping_result, pipeline_id, UINT32);
+
+cmdline_parse_token_string_t cmd_ping_ping_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_ping_result, ping_string, "ping");
+
+cmdline_parse_inst_t cmd_ping = {
+	.f = cmd_ping_parsed,
+	.data = NULL,
+	.help_str = "Ping pipeline instance",
+	.tokens = {
+		(void *) &cmd_ping_p_string,
+		(void *) &cmd_ping_pipeline_id,
+		(void *) &cmd_ping_ping_string,
+		NULL,
+	},
+};
+
+/*
+ * stats port in
+ */
+
+struct cmd_stats_port_in_result {
+	cmdline_fixed_string_t p_string;
+	uint32_t pipeline_id;
+	cmdline_fixed_string_t stats_string;
+	cmdline_fixed_string_t port_string;
+	cmdline_fixed_string_t in_string;
+	uint32_t port_in_id;
+	
+};
+static void
+cmd_stats_port_in_parsed(
+	void *parsed_result,
+	__rte_unused struct cmdline *cl,
+	void *data)
+{
+	struct cmd_stats_port_in_result *params = parsed_result;
+	struct app_params *app = data;
+	struct rte_pipeline_port_in_stats stats;
+	int status;
+	
+	status = app_pipeline_stats_port_in(app,
+			params->pipeline_id,
+			params->port_in_id,
+			&stats);
+
+	if(status != 0) {
+		printf("stats port in failed\n");
+		return;
+	}
+	
+	/* Display stats */
+	printf("Pipeline %u port IN %u stats:\n",
+		params->pipeline_id, params->port_in_id);
+	printf("Pkts in: %lu\n", stats.stats.n_pkts_in);
+	printf("Pkts in dropped: %lu\n", stats.stats.n_pkts_drop);
+	printf("Pkts in dropped by port action handler: %lu\n", stats.n_pkts_dropped_by_ah);
+}
+
+cmdline_parse_token_string_t cmd_stats_port_in_p_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_stats_port_in_result, p_string, "p");
+
+cmdline_parse_token_num_t cmd_stats_port_in_pipeline_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_stats_port_in_result, pipeline_id, UINT32);
+
+cmdline_parse_token_string_t cmd_stats_port_in_stats_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_stats_port_in_result, stats_string, "stats");
+
+cmdline_parse_token_string_t cmd_stats_port_in_port_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_stats_port_in_result, port_string, "port");
+
+cmdline_parse_token_string_t cmd_stats_port_in_in_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_stats_port_in_result, in_string, "in");
+
+	cmdline_parse_token_num_t cmd_stats_port_in_port_in_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_stats_port_in_result, port_in_id, UINT32);
+
+cmdline_parse_inst_t cmd_stats_port_in = {
+	.f = cmd_stats_port_in_parsed,
+	.data = NULL,
+	.help_str = "Stats for pipeline input port",
+	.tokens = {
+		(void *) &cmd_stats_port_in_p_string,
+		(void *) &cmd_stats_port_in_pipeline_id,
+		(void *) &cmd_stats_port_in_stats_string,
+		(void *) &cmd_stats_port_in_port_string,
+		(void *) &cmd_stats_port_in_in_string,
+		(void *) &cmd_stats_port_in_port_in_id,
+		NULL,
+	},
+};
+
+/*
+ * stats port out
+ */
+
+struct cmd_stats_port_out_result {
+	cmdline_fixed_string_t p_string;
+	uint32_t pipeline_id;
+	cmdline_fixed_string_t stats_string;
+	cmdline_fixed_string_t port_string;
+	cmdline_fixed_string_t out_string;
+	uint32_t port_out_id;
+};
+
+static void
+cmd_stats_port_out_parsed(
+	void *parsed_result,
+	__rte_unused struct cmdline *cl,
+	void *data)
+{
+	
+	struct cmd_stats_port_out_result *params = parsed_result;
+	struct app_params *app = data;
+	struct rte_pipeline_port_out_stats stats;
+	int status;
+	
+	status = app_pipeline_stats_port_out(app,
+			params->pipeline_id,
+			params->port_out_id,
+			&stats);
+
+	if(status != 0) {
+		printf("stats port out failed\n");
+		return;
+	}
+
+	/* Display stats */
+	printf("Pipeline %u port out %u stats:\n", params->port_out_id, params->pipeline_id);
+	printf("Pkts in: %lu\n", stats.stats.n_pkts_in);
+	printf("Pkts in dropped: %lu\n", stats.stats.n_pkts_drop);
+	printf("Pkts in dropped by port action handler: %lu\n", stats.n_pkts_dropped_by_ah);	
+}	
+
+cmdline_parse_token_string_t cmd_stats_port_out_p_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_stats_port_out_result, p_string,
+	"p");
+
+cmdline_parse_token_num_t cmd_stats_port_out_pipeline_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_stats_port_out_result, pipeline_id, UINT32);
+
+cmdline_parse_token_string_t cmd_stats_port_out_stats_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_stats_port_out_result, stats_string, "stats");
+
+cmdline_parse_token_string_t cmd_stats_port_out_port_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_stats_port_out_result, port_string, "port");
+
+cmdline_parse_token_string_t cmd_stats_port_out_out_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_stats_port_out_result, out_string, "out");
+
+cmdline_parse_token_num_t cmd_stats_port_out_port_out_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_stats_port_out_result, port_out_id, UINT32);
+
+cmdline_parse_inst_t cmd_stats_port_out = {
+	.f = cmd_stats_port_out_parsed,
+	.data = NULL,
+	.help_str = "Stats for pipeline output port",
+	.tokens = {
+		(void *) &cmd_stats_port_out_p_string,
+		(void *) &cmd_stats_port_out_pipeline_id,
+		(void *) &cmd_stats_port_out_stats_string,
+		(void *) &cmd_stats_port_out_port_string,
+		(void *) &cmd_stats_port_out_out_string,
+		(void *) &cmd_stats_port_out_port_out_id,
+		NULL,
+	},
+};
+
+/*
+ * stats table
+ */
+
+struct cmd_stats_table_result {
+	cmdline_fixed_string_t p_string;
+	uint32_t pipeline_id;
+	cmdline_fixed_string_t stats_string;
+	cmdline_fixed_string_t table_string;
+	uint32_t table_id;
+};
+
+static void
+cmd_stats_table_parsed(
+	void *parsed_result,
+	__rte_unused struct cmdline *cl,
+	void *data)
+{
+	struct cmd_stats_table_result *params = parsed_result;
+	struct app_params *app = data;
+	struct rte_pipeline_table_stats stats;
+	int status;
+
+	status = app_pipeline_stats_table(app,
+			params->pipeline_id,
+			params->table_id,
+			&stats);
+
+	if(status != 0) {
+		printf("stats table failed\n");
+		return;
+	}
+
+	/* Display stats */
+	printf("Pipeline %u table %u stats:\n", params->table_id, params->pipeline_id);
+	printf("Pkts in: %lu\n", stats.stats.n_pkts_in);
+	printf("Pkts in with lookup miss: %lu\n", stats.stats.n_pkts_lookup_miss);
+	printf("Pkts in dropped on lookup hit: %lu\n", stats.n_pkts_dropped_lkp_hit);
+	printf("Pkts in dropped on lookup hit by AH: %lu\n", stats.n_pkts_dropped_by_lkp_hit_ah);
+	printf("Pkts in dropped on lookup miss: %lu\n", stats.n_pkts_dropped_lkp_miss);
+	printf("Pkts in dropped on lookup miss by AH: %lu\n", stats.n_pkts_dropped_by_lkp_miss_ah);
+}
+
+cmdline_parse_token_string_t cmd_stats_table_p_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_stats_table_result, p_string, "p");
+
+cmdline_parse_token_num_t cmd_stats_table_pipeline_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_stats_table_result, pipeline_id, UINT32);
+
+cmdline_parse_token_string_t cmd_stats_table_stats_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_stats_table_result, stats_string, "stats");
+
+cmdline_parse_token_string_t cmd_stats_table_table_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_stats_table_result, table_string, "table");
+
+cmdline_parse_token_num_t cmd_stats_table_table_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_stats_table_result, table_id, UINT32);
+
+cmdline_parse_inst_t cmd_stats_table = {
+	.f = cmd_stats_table_parsed,
+	.data = NULL,
+	.help_str = "Stats for pipeline table",
+	.tokens = {
+		(void *) &cmd_stats_table_p_string,
+		(void *) &cmd_stats_table_pipeline_id,
+		(void *) &cmd_stats_table_stats_string,
+		(void *) &cmd_stats_table_table_string,
+		(void *) &cmd_stats_table_table_id,
+		NULL,
+	},
+};	
+ 
+/*
+ * port in enable
+ */
+
+struct cmd_port_in_enable_result {
+	cmdline_fixed_string_t p_string;
+	uint32_t pipeline_id;
+	cmdline_fixed_string_t port_string;
+	cmdline_fixed_string_t in_string;
+	uint32_t port_in_id;
+	cmdline_fixed_string_t enable_string;
+};
+
+static void
+cmd_port_in_enable_parsed(
+	void *parsed_result,
+	__rte_unused struct cmdline *cl,
+	void *data)
+{
+	struct cmd_port_in_enable_result *params = parsed_result;
+	struct app_params *app = data;
+	int status;
+
+	status = app_pipeline_port_in_enable(app,
+			params->pipeline_id,
+			params->port_in_id);
+
+	if(status != 0)
+		printf("port in enable failed\n");
+}
+	
+cmdline_parse_token_string_t cmd_port_in_enable_p_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_port_in_enable_result, p_string, "p");
+
+cmdline_parse_token_num_t cmd_port_in_enable_pipeline_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_port_in_enable_result, pipeline_id, UINT32);
+
+cmdline_parse_token_string_t cmd_port_in_enable_port_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_port_in_enable_result, port_string,
+	"port");
+
+cmdline_parse_token_string_t cmd_port_in_enable_in_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_port_in_enable_result, in_string, "in");
+	
+cmdline_parse_token_num_t cmd_port_in_enable_port_in_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_port_in_enable_result, port_in_id, UINT32);
+	
+cmdline_parse_token_string_t cmd_port_in_enable_enable_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_port_in_enable_result, enable_string, "enable");
+
+cmdline_parse_inst_t cmd_port_in_enable = {
+	.f = cmd_port_in_enable_parsed,
+	.data = NULL,
+	.help_str = "Pipeline input port enable",
+	.tokens = {
+		(void *) &cmd_port_in_enable_p_string,
+		(void *) &cmd_port_in_enable_pipeline_id,
+		(void *) &cmd_port_in_enable_port_string,
+		(void *) &cmd_port_in_enable_in_string,
+		(void *) &cmd_port_in_enable_port_in_id,
+		(void *) &cmd_port_in_enable_enable_string,
+		NULL,
+	},
+};	
+
+/*
+ * port in disable
+ */
+
+struct cmd_port_in_disable_result {
+	cmdline_fixed_string_t p_string;
+	uint32_t pipeline_id;
+	cmdline_fixed_string_t port_string;
+	cmdline_fixed_string_t in_string;
+	uint32_t port_in_id;
+	cmdline_fixed_string_t disable_string;
+};
+
+static void
+cmd_port_in_disable_parsed(
+	void *parsed_result,
+	__rte_unused struct cmdline *cl,
+	void *data)
+{
+	struct cmd_port_in_disable_result *params = parsed_result;
+	struct app_params *app = data;
+	int status;
+	
+	status = app_pipeline_port_in_disable(app,
+			params->pipeline_id,
+			params->port_in_id);
+
+	if(status != 0)
+		printf("port in disable failed\n");
+}
+
+cmdline_parse_token_string_t cmd_port_in_disable_p_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_port_in_disable_result, p_string, "p");
+
+cmdline_parse_token_num_t cmd_port_in_disable_pipeline_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_port_in_disable_result, pipeline_id, UINT32);
+
+cmdline_parse_token_string_t cmd_port_in_disable_port_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_port_in_disable_result, port_string, "port");
+	
+cmdline_parse_token_string_t cmd_port_in_disable_in_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_port_in_disable_result, in_string, "in");
+
+cmdline_parse_token_num_t cmd_port_in_disable_port_in_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_port_in_disable_result, port_in_id, UINT32);
+	
+cmdline_parse_token_string_t cmd_port_in_disable_disable_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_port_in_disable_result, disable_string, "disable");	
+
+cmdline_parse_inst_t cmd_port_in_disable = {
+	.f = cmd_port_in_disable_parsed,
+	.data = NULL,
+	.help_str = "Pipeline input port disable",
+	.tokens = {
+		(void *) &cmd_port_in_disable_p_string,
+		(void *) &cmd_port_in_disable_pipeline_id,
+		(void *) &cmd_port_in_disable_port_string,
+		(void *) &cmd_port_in_disable_in_string,
+		(void *) &cmd_port_in_disable_port_in_id,
+		(void *) &cmd_port_in_disable_disable_string,
+		NULL,
+	},
+};
+
+static cmdline_parse_ctx_t pipeline_cmds[] = {
+	(cmdline_parse_inst_t *) &cmd_run,
+	(cmdline_parse_inst_t *) &cmd_quit,
+	(cmdline_parse_inst_t *) &cmd_ping,
+	(cmdline_parse_inst_t *) &cmd_stats_port_in,
+	(cmdline_parse_inst_t *) &cmd_stats_port_out,
+	(cmdline_parse_inst_t *) &cmd_stats_table,
+	(cmdline_parse_inst_t *) &cmd_port_in_enable,
+	(cmdline_parse_inst_t *) &cmd_port_in_disable,
+	(cmdline_parse_inst_t *) &cmd_link_config,
+	(cmdline_parse_inst_t *) &cmd_link_up,
+	(cmdline_parse_inst_t *) &cmd_link_down,
+	(cmdline_parse_inst_t *) &cmd_link_ls,
+	NULL,
+};
+
+static struct pipeline_fe_ops pipeline_master_fe_ops = {
+	.f_init = NULL,
+	.f_free = NULL,
+	.cmds = pipeline_cmds,
+};
+
+struct pipeline_type pipeline_master = {
+	.name = "MASTER",
+	.ops = &pipeline_master_ops,
+	.fe_ops = &pipeline_master_fe_ops,
+};
diff --git a/examples/ip_pipeline/pipeline/pipeline_master.h b/examples/ip_pipeline/pipeline/pipeline_master.h
new file mode 100644
index 0000000..3fe3030
--- /dev/null
+++ b/examples/ip_pipeline/pipeline/pipeline_master.h
@@ -0,0 +1,41 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __INCLUDE_PIPELINE_MASTER_H__
+#define __INCLUDE_PIPELINE_MASTER_H__
+
+#include "pipeline.h"
+
+extern struct pipeline_type pipeline_master;
+
+#endif
diff --git a/examples/ip_pipeline/pipeline/pipeline_master_ops.c b/examples/ip_pipeline/pipeline/pipeline_master_ops.c
new file mode 100644
index 0000000..8e0bf1b
--- /dev/null
+++ b/examples/ip_pipeline/pipeline/pipeline_master_ops.c
@@ -0,0 +1,136 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <rte_common.h>
+#include <rte_malloc.h>
+
+#include <cmdline_parse.h>
+#include <cmdline_parse_string.h>
+#include <cmdline_socket.h>
+#include <cmdline.h>
+
+#include "app.h"
+#include "pipeline_master_ops.h"
+
+struct pipeline_master {
+	struct cmdline *cl;
+};
+
+static void*
+pipeline_init(__rte_unused struct pipeline_params *params, void *arg)
+{
+	struct app_params *app = (struct app_params *) arg;
+	struct pipeline_master *p;
+	uint32_t size;
+
+	/* Check input arguments */
+	if ((params == NULL) ||
+		(app == 0))
+		return NULL;
+
+	/* Memory allocation */
+	size = RTE_CACHE_LINE_ROUNDUP(sizeof(struct pipeline_master));
+	p = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
+	if (p == NULL)
+		return NULL;
+
+	p->cl = cmdline_stdin_new(app->cmds, "pipeline> ");
+	if (p->cl == NULL) {
+		rte_free(p);
+		return NULL;
+	}
+
+	if (strlen(app->script_file)) {
+		int fd = open(app->script_file, O_RDONLY);
+
+		if (fd < 0)
+			printf("Cannot open CLI script file \"%s\"\n", app->script_file);
+		else {
+			printf("Running CLI script file \"%s\" ...\n", app->script_file);
+			struct cmdline *file_cl = cmdline_new(p->cl->ctx, "", fd, 1);
+			cmdline_interact(file_cl);
+			close(fd);
+		}
+	}
+
+	return (void *) p;
+}
+
+static int
+pipeline_free(void *pipeline)
+{
+	struct pipeline_master *p = (struct pipeline_master *) pipeline;
+
+	if (p == NULL)
+		return -EINVAL;
+
+	cmdline_stdin_exit(p->cl);
+	rte_free(p);
+
+	return 0;
+}
+
+static int
+pipeline_run(void *pipeline)
+{
+	struct pipeline_master *p = (struct pipeline_master *) pipeline;
+	int status;
+
+	status = cmdline_poll(p->cl);
+	if (status < 0)
+		rte_panic("CLI poll error (%d)\n", status);
+	else if(status == RDLINE_EXITED) {
+		cmdline_stdin_exit(p->cl);
+		rte_exit(0, "Bye!\n");
+	}
+
+	return 0;
+}
+
+static int
+pipeline_timer(__rte_unused void *pipeline)
+{
+	//printf("Master timer\n");
+	return 0;
+}
+
+struct pipeline_ops pipeline_master_ops = {
+		.f_init = pipeline_init,
+		.f_free = pipeline_free,
+		.f_run = pipeline_run,
+		.f_timer = pipeline_timer,
+		.f_track = NULL,
+};
diff --git a/examples/ip_pipeline/pipeline/pipeline_master_ops.h b/examples/ip_pipeline/pipeline/pipeline_master_ops.h
new file mode 100644
index 0000000..86c1e31
--- /dev/null
+++ b/examples/ip_pipeline/pipeline/pipeline_master_ops.h
@@ -0,0 +1,41 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __INCLUDE_PIPELINE_MASTER_OPS_H__
+#define __INCLUDE_PIPELINE_MASTER_OPS_H__
+
+#include "pipeline_ops.h"
+
+extern struct pipeline_ops pipeline_master_ops;
+
+#endif
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 06/11] ip_pipeline: added application thread
  2015-05-29 15:43 [PATCH 00/11] ip_pipeline: ip_pipeline application enhancements Maciej Gajdzica
                   ` (4 preceding siblings ...)
  2015-05-29 15:43 ` [PATCH 05/11] ip_pipeline: added master pipeline Maciej Gajdzica
@ 2015-05-29 15:43 ` Maciej Gajdzica
  2015-05-29 15:43 ` [PATCH 07/11] ip_pipeline: moved config files to separate folder Maciej Gajdzica
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Maciej Gajdzica @ 2015-05-29 15:43 UTC (permalink / raw)
  To: dev

Application thread runs pipelines on assigned cores.

Signed-off-by: Maciej Gajdzica <maciejx.t.gajdzica@intel.com>
---
 examples/ip_pipeline/Makefile |    1 +
 examples/ip_pipeline/main.c   |    6 +++
 examples/ip_pipeline/thread.c |  105 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 112 insertions(+)
 create mode 100644 examples/ip_pipeline/thread.c

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index 6269be1..db677ec 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -52,6 +52,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) := main.c
 SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += config_parse.c
 SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += config_check.c
 SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += init.c
+SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += thread.c
 SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += cpu_core_map.c
 
 SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_common_ops.c
diff --git a/examples/ip_pipeline/main.c b/examples/ip_pipeline/main.c
index ef68c86..862e2f2 100644
--- a/examples/ip_pipeline/main.c
+++ b/examples/ip_pipeline/main.c
@@ -52,5 +52,11 @@ main(int argc, char **argv)
 	/* Init */
 	app_init(&app);
 
+	/* Run-time */
+	rte_eal_mp_remote_launch(
+		app_thread,
+		(void *) &app,
+		CALL_MASTER);
+
 	return 0;
 }
diff --git a/examples/ip_pipeline/thread.c b/examples/ip_pipeline/thread.c
new file mode 100644
index 0000000..f850a36
--- /dev/null
+++ b/examples/ip_pipeline/thread.c
@@ -0,0 +1,105 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <rte_cycles.h>
+#include <rte_pipeline.h>
+
+#include "pipeline_common_ops.h"
+#include "app.h"
+
+int app_thread(void *arg)
+{
+	struct app_params *app = (struct app_params *) arg;
+	uint32_t core_id = rte_lcore_id(), i, j;
+	struct app_thread_data *t = &app->thread_data[core_id];
+
+	for (i = 0; ; i++) {
+		/* Run regular pipelines */
+		for (j = 0; j < t->n_regular; j++){
+			struct app_thread_pipeline_data *data = &t->regular[j];
+			struct pipeline *p = data->be;
+
+			rte_pipeline_run(p->p);
+		}
+
+		/* Run custom pipelines */
+		for (j = 0; j < t->n_custom; j++){
+			struct app_thread_pipeline_data *data = &t->custom[j];
+
+			data->f_run(data->be);
+		}
+
+		/* Timer */
+		if ((i & 0xF) == 0) {
+			uint64_t time = rte_get_tsc_cycles();
+			uint64_t t_deadline = UINT64_MAX;
+			
+			if (time < t->deadline)
+				continue;
+
+			/* Timer for regular pipelines */
+			for (j = 0; j < t->n_regular; j++){
+				struct app_thread_pipeline_data *data = &t->regular[j];
+				uint64_t p_deadline = data->deadline;
+
+				if (p_deadline <= time) {
+					data->f_timer(data->be);
+					p_deadline = time + data->timer_period;
+					data->deadline = p_deadline;
+				}
+
+				if (p_deadline < t_deadline)
+					t_deadline = p_deadline;
+			}
+
+			/* Timer for custom pipelines */
+			for (j = 0; j < t->n_custom; j++){
+				struct app_thread_pipeline_data *data = &t->custom[j];
+				uint64_t p_deadline = data->deadline;
+
+				if (p_deadline <= time) {
+					data->f_timer(data->be);
+					p_deadline = time + data->timer_period;
+					data->deadline = p_deadline;
+				}
+
+				if (p_deadline < t_deadline)
+					t_deadline = p_deadline;
+			}
+
+			t->deadline = t_deadline;
+		}
+	}
+
+	return 0;
+}
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 07/11] ip_pipeline: moved config files to separate folder
  2015-05-29 15:43 [PATCH 00/11] ip_pipeline: ip_pipeline application enhancements Maciej Gajdzica
                   ` (5 preceding siblings ...)
  2015-05-29 15:43 ` [PATCH 06/11] ip_pipeline: added application thread Maciej Gajdzica
@ 2015-05-29 15:43 ` Maciej Gajdzica
  2015-05-29 15:43 ` [PATCH 08/11] ip_pipeline: added new implementation of passthrough pipeline Maciej Gajdzica
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Maciej Gajdzica @ 2015-05-29 15:43 UTC (permalink / raw)
  To: dev

Created new folder for config(.cfg) and script(.sh) files.

Signed-off-by: Maciej Gajdzica <maciejx.t.gajdzica@intel.com>
---
 examples/ip_pipeline/config/ip_pipeline.cfg |    9 +++++
 examples/ip_pipeline/config/ip_pipeline.sh  |    1 +
 examples/ip_pipeline/ip_pipeline.cfg        |   56 ---------------------------
 examples/ip_pipeline/ip_pipeline.sh         |   18 ---------
 4 files changed, 10 insertions(+), 74 deletions(-)
 create mode 100644 examples/ip_pipeline/config/ip_pipeline.cfg
 create mode 100644 examples/ip_pipeline/config/ip_pipeline.sh
 delete mode 100644 examples/ip_pipeline/ip_pipeline.cfg
 delete mode 100644 examples/ip_pipeline/ip_pipeline.sh

diff --git a/examples/ip_pipeline/config/ip_pipeline.cfg b/examples/ip_pipeline/config/ip_pipeline.cfg
new file mode 100644
index 0000000..9e7e7e4
--- /dev/null
+++ b/examples/ip_pipeline/config/ip_pipeline.cfg
@@ -0,0 +1,9 @@
+[PIPELINE0]
+type = MASTER
+core = 0
+
+[PIPELINE1]
+type = PASS-THROUGH
+core = s0c1
+pktq_in = RXQ0.0 RXQ1.0
+pktq_out = TXQ0.0 TXQ1.0
\ No newline at end of file
diff --git a/examples/ip_pipeline/config/ip_pipeline.sh b/examples/ip_pipeline/config/ip_pipeline.sh
new file mode 100644
index 0000000..f1ff544
--- /dev/null
+++ b/examples/ip_pipeline/config/ip_pipeline.sh
@@ -0,0 +1 @@
+p 1 ping
\ No newline at end of file
diff --git a/examples/ip_pipeline/ip_pipeline.cfg b/examples/ip_pipeline/ip_pipeline.cfg
deleted file mode 100644
index 428830d..0000000
--- a/examples/ip_pipeline/ip_pipeline.cfg
+++ /dev/null
@@ -1,56 +0,0 @@
-;   BSD LICENSE
-;
-;   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
-;   All rights reserved.
-;
-;   Redistribution and use in source and binary forms, with or without
-;   modification, are permitted provided that the following conditions
-;   are met:
-;
-;     * Redistributions of source code must retain the above copyright
-;       notice, this list of conditions and the following disclaimer.
-;     * Redistributions in binary form must reproduce the above copyright
-;       notice, this list of conditions and the following disclaimer in
-;       the documentation and/or other materials provided with the
-;       distribution.
-;     * Neither the name of Intel Corporation nor the names of its
-;       contributors may be used to endorse or promote products derived
-;       from this software without specific prior written permission.
-;
-;   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-;   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-;   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-;   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-;   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-;   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-;   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-;   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-;   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-;   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-;   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-; Core configuration
-[core 0]
-type = MASTER
-queues in  = 15 16 17 -1 -1 -1 -1 -1
-queues out = 12 13 14 -1 -1 -1 -1 -1
-
-[core 1]
-type = RX
-queues in  = -1 -1 -1 -1 -1 -1 -1 12
-queues out =  0  1  2  3 -1 -1 -1 15
-
-[core 2]
-type = FC
-queues in  =  0  1  2  3 -1 -1 -1 13
-queues out =  4  5  6  7 -1 -1 -1 16
-
-[core 3]
-type = RT
-queues in  =  4  5  6  7 -1 -1 -1 14
-queues out =  8  9 10 11 -1 -1 -1 17
-
-[core 4]
-type = TX
-queues in  =  8  9 10 11 -1 -1 -1 -1
-queues out = -1 -1 -1 -1 -1 -1 -1 -1
diff --git a/examples/ip_pipeline/ip_pipeline.sh b/examples/ip_pipeline/ip_pipeline.sh
deleted file mode 100644
index c3419ca..0000000
--- a/examples/ip_pipeline/ip_pipeline.sh
+++ /dev/null
@@ -1,18 +0,0 @@
-#Address Resolution Protocol (ARP) Table
-#arp add iface ipaddr macaddr
-arp add 0 0.0.0.1 0a:0b:0c:0d:0e:0f
-arp add 1 0.128.0.1 1a:1b:1c:1d:1e:1f
-
-#Routing Table
-#route add ipaddr prefixlen iface gateway
-route add 0.0.0.0 9 0 0.0.0.1
-route add 0.128.0.0 9 1 0.128.0.1
-
-#Flow Table
-flow add all
-#flow add 0.0.0.0 1.2.3.4 0 0 6 0
-#flow add 10.11.12.13 0.0.0.0 0 0 6 1
-
-#Firewall
-#firewall add 1 0.0.0.0 0 0.0.0.0 9 0 65535 0 65535 6 0xf 0
-#firewall add 1 0.0.0.0 0 0.128.0.0 9 0 65535 0 65535 6 0xf 1
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 08/11] ip_pipeline: added new implementation of passthrough pipeline
  2015-05-29 15:43 [PATCH 00/11] ip_pipeline: ip_pipeline application enhancements Maciej Gajdzica
                   ` (6 preceding siblings ...)
  2015-05-29 15:43 ` [PATCH 07/11] ip_pipeline: moved config files to separate folder Maciej Gajdzica
@ 2015-05-29 15:43 ` Maciej Gajdzica
  2015-05-29 15:43 ` [PATCH 09/11] ip_pipeline: added new implementation of firewall pipeline Maciej Gajdzica
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Maciej Gajdzica @ 2015-05-29 15:43 UTC (permalink / raw)
  To: dev

Passthrough pipeline implementation is split to two files.
pipeline_passthrough.c file handles front-end functions (cli commands
parsing) pipeline_passthrough_ops.c contains implementation of functions
done by pipeline (back-end).

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/Makefile                      |    7 +-
 examples/ip_pipeline/init.c                        |    2 +
 .../ip_pipeline/pipeline/pipeline_passthrough.c    |  192 +-------------
 .../ip_pipeline/pipeline/pipeline_passthrough.h    |   41 +++
 .../pipeline/pipeline_passthrough_ops.c            |  275 ++++++++++++++++++++
 .../pipeline/pipeline_passthrough_ops.h            |   41 +++
 6 files changed, 374 insertions(+), 184 deletions(-)
 create mode 100644 examples/ip_pipeline/pipeline/pipeline_passthrough.h
 create mode 100644 examples/ip_pipeline/pipeline/pipeline_passthrough_ops.c
 create mode 100644 examples/ip_pipeline/pipeline/pipeline_passthrough_ops.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index db677ec..fc845ce 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -59,13 +59,10 @@ SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_common_ops.c
 SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_common.c
 SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_master_ops.c
 SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_master.c
-#SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_rx.c
-#SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_tx.c
+SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_passthrough_ops.c
+SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_passthrough.c
 #SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_flow_classification.c
 #SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_routing.c
-#SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_passthrough.c
-#SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_ipv4_frag.c
-#SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_ipv4_ras.c
 
 #ifeq ($(CONFIG_RTE_LIBRTE_ACL),y)
 #SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_firewall.c
diff --git a/examples/ip_pipeline/init.c b/examples/ip_pipeline/init.c
index b066476..22b2c77 100644
--- a/examples/ip_pipeline/init.c
+++ b/examples/ip_pipeline/init.c
@@ -44,6 +44,7 @@
 #include "app.h"
 #include "pipeline.h"
 #include "pipeline_master.h"
+#include "pipeline_passthrough.h"
 
 #define APP_NAME_SIZE	32
 
@@ -1144,6 +1145,7 @@ int app_init(struct app_params *app)
 	app_init_msgq(app);
 
 	app_pipeline_type_register(app, &pipeline_master);
+	app_pipeline_type_register(app, &pipeline_passthrough);
 
 	app_init_pipelines(app);
 	app_init_threads(app);
diff --git a/examples/ip_pipeline/pipeline/pipeline_passthrough.c b/examples/ip_pipeline/pipeline/pipeline_passthrough.c
index 948b2c1..e39de32 100644
--- a/examples/ip_pipeline/pipeline/pipeline_passthrough.c
+++ b/examples/ip_pipeline/pipeline/pipeline_passthrough.c
@@ -1,7 +1,7 @@
 /*-
  *   BSD LICENSE
  *
- *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
  *   All rights reserved.
  *
  *   Redistribution and use in source and binary forms, with or without
@@ -31,183 +31,17 @@
  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
+#include "pipeline_passthrough_ops.h"
+#include "pipeline_passthrough.h"
 
-#include <rte_malloc.h>
-#include <rte_log.h>
+static struct pipeline_fe_ops pipeline_passthrough_fe_ops = {
+	.f_init = NULL,
+	.f_free = NULL,
+	.cmds = NULL,
+};
 
-#include <rte_port_ring.h>
-#include <rte_table_stub.h>
-#include <rte_pipeline.h>
-
-#include "main.h"
-
-void
-app_main_loop_pipeline_passthrough(void) {
-	struct rte_pipeline_params pipeline_params = {
-		.name = "pipeline",
-		.socket_id = rte_socket_id(),
-	};
-
-	struct rte_pipeline *p;
-	uint32_t port_in_id[APP_MAX_PORTS];
-	uint32_t port_out_id[APP_MAX_PORTS];
-	uint32_t table_id[APP_MAX_PORTS];
-	uint32_t i;
-
-	uint32_t core_id = rte_lcore_id();
-	struct app_core_params *core_params = app_get_core_params(core_id);
-
-	if ((core_params == NULL) || (core_params->core_type != APP_CORE_PT))
-		rte_panic("Core %u misconfiguration\n", core_id);
-
-	RTE_LOG(INFO, USER1, "Core %u is doing pass-through\n", core_id);
-
-	/* Pipeline configuration */
-	p = rte_pipeline_create(&pipeline_params);
-	if (p == NULL)
-		rte_panic("%s: Unable to configure the pipeline\n", __func__);
-
-	/* Input port configuration */
-	for (i = 0; i < app.n_ports; i++) {
-		struct rte_port_ring_reader_params port_ring_params = {
-			.ring = app.rings[core_params->swq_in[i]],
-		};
-
-		struct rte_pipeline_port_in_params port_params = {
-			.ops = &rte_port_ring_reader_ops,
-			.arg_create = (void *) &port_ring_params,
-			.f_action = NULL,
-			.arg_ah = NULL,
-			.burst_size = app.bsz_swq_rd,
-		};
-
-		if (rte_pipeline_port_in_create(p, &port_params,
-			&port_in_id[i])) {
-			rte_panic("%s: Unable to configure input port for "
-				"ring %d\n", __func__, i);
-		}
-	}
-
-	/* Output port configuration */
-	for (i = 0; i < app.n_ports; i++) {
-		struct rte_port_ring_writer_params port_ring_params = {
-			.ring = app.rings[core_params->swq_out[i]],
-			.tx_burst_sz = app.bsz_swq_wr,
-		};
-
-		struct rte_pipeline_port_out_params port_params = {
-			.ops = &rte_port_ring_writer_ops,
-			.arg_create = (void *) &port_ring_params,
-			.f_action = NULL,
-			.f_action_bulk = NULL,
-			.arg_ah = NULL,
-		};
-
-		if (rte_pipeline_port_out_create(p, &port_params,
-			&port_out_id[i])) {
-			rte_panic("%s: Unable to configure output port for "
-				"ring %d\n", __func__, i);
-		}
-	}
-
-	/* Table configuration */
-	for (i = 0; i < app.n_ports; i++) {
-		struct rte_pipeline_table_params table_params = {
-			.ops = &rte_table_stub_ops,
-			.arg_create = NULL,
-			.f_action_hit = NULL,
-			.f_action_miss = NULL,
-			.arg_ah = NULL,
-			.action_data_size = 0,
-		};
-
-		if (rte_pipeline_table_create(p, &table_params, &table_id[i]))
-			rte_panic("%s: Unable to configure table %u\n",
-				__func__, i);
-	}
-
-	/* Interconnecting ports and tables */
-	for (i = 0; i < app.n_ports; i++) {
-		if (rte_pipeline_port_in_connect_to_table(p, port_in_id[i],
-			table_id[i])) {
-			rte_panic("%s: Unable to connect input port %u to "
-				"table %u\n", __func__, port_in_id[i],
-				table_id[i]);
-		}
-	}
-
-	/* Add entries to tables */
-	for (i = 0; i < app.n_ports; i++) {
-		struct rte_pipeline_table_entry default_entry = {
-			.action = RTE_PIPELINE_ACTION_PORT,
-			{.port_id = port_out_id[i]},
-		};
-
-		struct rte_pipeline_table_entry *default_entry_ptr;
-
-		if (rte_pipeline_table_default_entry_add(p, table_id[i],
-			&default_entry, &default_entry_ptr))
-			rte_panic("%s: Unable to add default entry to "
-				"table %u\n", __func__, table_id[i]);
-	}
-
-	/* Enable input ports */
-	for (i = 0; i < app.n_ports; i++)
-		if (rte_pipeline_port_in_enable(p, port_in_id[i]))
-			rte_panic("Unable to enable input port %u\n",
-				port_in_id[i]);
-
-	/* Check pipeline consistency */
-	if (rte_pipeline_check(p) < 0)
-		rte_panic("%s: Pipeline consistency check failed\n", __func__);
-
-	/* Run-time */
-	for (i = 0; ; i++) {
-		rte_pipeline_run(p);
-
-		if ((i & APP_FLUSH) == 0)
-			rte_pipeline_flush(p);
-	}
-}
-
-void
-app_main_loop_passthrough(void) {
-	struct app_mbuf_array *m;
-	uint32_t i;
-
-	uint32_t core_id = rte_lcore_id();
-	struct app_core_params *core_params = app_get_core_params(core_id);
-
-	if ((core_params == NULL) || (core_params->core_type != APP_CORE_PT))
-		rte_panic("Core %u misconfiguration\n", core_id);
-
-	RTE_LOG(INFO, USER1, "Core %u is doing pass-through (no pipeline)\n",
-		core_id);
-
-	m = rte_malloc_socket(NULL, sizeof(struct app_mbuf_array),
-		RTE_CACHE_LINE_SIZE, rte_socket_id());
-	if (m == NULL)
-		rte_panic("%s: cannot allocate buffer space\n", __func__);
-
-	for (i = 0; ; i = ((i + 1) & (app.n_ports - 1))) {
-		int ret;
-
-		ret = rte_ring_sc_dequeue_bulk(
-			app.rings[core_params->swq_in[i]],
-			(void **) m->array,
-			app.bsz_swq_rd);
-
-		if (ret == -ENOENT)
-			continue;
-
-		do {
-			ret = rte_ring_sp_enqueue_bulk(
-				app.rings[core_params->swq_out[i]],
-				(void **) m->array,
-				app.bsz_swq_wr);
-		} while (ret < 0);
-	}
-}
+struct pipeline_type pipeline_passthrough = {
+	.name = "PASS-THROUGH",
+	.ops = &pipeline_passthrough_ops,
+	.fe_ops = &pipeline_passthrough_fe_ops,
+};
diff --git a/examples/ip_pipeline/pipeline/pipeline_passthrough.h b/examples/ip_pipeline/pipeline/pipeline_passthrough.h
new file mode 100644
index 0000000..420a876
--- /dev/null
+++ b/examples/ip_pipeline/pipeline/pipeline_passthrough.h
@@ -0,0 +1,41 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __INCLUDE_PIPELINE_PASSTHROUGH_H__
+#define __INCLUDE_PIPELINE_PASSTHROUGH_H__
+
+#include "pipeline.h"
+
+extern struct pipeline_type pipeline_passthrough;
+
+#endif
diff --git a/examples/ip_pipeline/pipeline/pipeline_passthrough_ops.c b/examples/ip_pipeline/pipeline/pipeline_passthrough_ops.c
new file mode 100644
index 0000000..8f91779
--- /dev/null
+++ b/examples/ip_pipeline/pipeline/pipeline_passthrough_ops.c
@@ -0,0 +1,275 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string.h>
+
+#include <rte_common.h>
+#include <rte_malloc.h>
+#include <rte_table_stub.h>
+
+#include "pipeline_common_ops.h"
+#include "pipeline_passthrough_ops.h"
+
+struct pipeline_passthrough {
+	struct pipeline p;
+} __rte_cache_aligned;
+
+static pipeline_msg_req_handler handlers[] = {
+	[PIPELINE_MSG_REQ_PING] = pipeline_msg_req_ping_handler,
+	[PIPELINE_MSG_REQ_STATS_PORT_IN] = pipeline_msg_req_stats_port_in_handler,
+	[PIPELINE_MSG_REQ_STATS_PORT_OUT] = pipeline_msg_req_stats_port_out_handler,
+	[PIPELINE_MSG_REQ_STATS_TABLE] = pipeline_msg_req_stats_table_handler,
+	[PIPELINE_MSG_REQ_PORT_IN_ENABLE] = pipeline_msg_req_port_in_enable_handler,
+	[PIPELINE_MSG_REQ_PORT_IN_DISABLE] = pipeline_msg_req_port_in_disable_handler,
+	[PIPELINE_MSG_REQ_CUSTOM] = pipeline_msg_req_invalid_handler,
+};
+
+static void*
+pipeline_passthrough_init(struct pipeline_params *params,
+	__rte_unused void *arg)
+{
+	struct pipeline *p;
+	uint32_t size, i;
+
+	/* Check input arguments */
+	if ((params == NULL) ||
+		(params->n_ports_in == 0) ||
+		(params->n_ports_out == 0) ||
+		(params->n_ports_in < params->n_ports_out) ||
+		(params->n_ports_in % params->n_ports_out))
+		return NULL;
+	
+	/* Memory allocation */
+	size = RTE_CACHE_LINE_ROUNDUP(sizeof(struct pipeline_passthrough));
+	p = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
+	if (p == NULL)
+		return NULL;
+
+	/* Pipeline */
+	{
+		struct rte_pipeline_params pipeline_params = {
+			.name = "PASS-THROUGH",
+			.socket_id = params->socket_id,
+			.offset_port_id = 0,
+		};
+
+		p->p = rte_pipeline_create(&pipeline_params);
+		if (p->p == NULL) {
+			rte_free(p);
+			return NULL;
+		}
+	}
+
+	/* Input ports */
+	p->n_ports_in = params->n_ports_in;
+	for (i = 0; i < p->n_ports_in; i++) {
+		struct rte_pipeline_port_in_params port_params = {
+			.ops = pipeline_port_in_params_get_ops(&params->port_in[i]),
+			.arg_create = pipeline_port_in_params_convert(&params->port_in[i]),
+			.f_action = NULL,
+			.arg_ah = NULL,
+			.burst_size = params->port_in[i].burst_size,
+		};
+
+		int status = rte_pipeline_port_in_create(p->p,
+			&port_params,
+			&p->port_in_id[i]);
+
+		if (status) {
+			rte_pipeline_free(p->p);
+			rte_free(p);
+			return NULL;
+		}
+	}
+
+	/* Output ports */
+	p->n_ports_out = params->n_ports_out;
+	for (i = 0; i < p->n_ports_out; i++) {
+		struct rte_pipeline_port_out_params port_params = {
+			.ops = pipeline_port_out_params_get_ops(&params->port_out[i]),
+			.arg_create = pipeline_port_out_params_convert(&params->port_out[i]),
+			.f_action = NULL,
+			.f_action_bulk = NULL,
+			.arg_ah = NULL,
+		};
+
+		int status = rte_pipeline_port_out_create(p->p,
+			&port_params,
+			&p->port_out_id[i]);
+		
+		if (status) {
+			rte_pipeline_free(p->p);
+			rte_free(p);
+			return NULL;
+		}
+	}
+
+	/* Tables */
+	p->n_tables = p->n_ports_in;
+	for (i = 0; i < p->n_ports_in; i++) {
+		struct rte_pipeline_table_params table_params = {
+			.ops = &rte_table_stub_ops,
+			.arg_create = NULL,
+			.f_action_hit = NULL,
+			.f_action_miss = NULL,
+			.arg_ah = NULL,
+			.action_data_size = 0,
+		};
+
+		int status = rte_pipeline_table_create(p->p,
+			&table_params,
+			&p->table_id[i]);
+		
+		
+		if (status) {
+			rte_pipeline_free(p->p);
+			rte_free(p);
+			return NULL;
+		}
+	}
+
+	/* Connecting input ports to tables */
+	for (i = 0; i < p->n_ports_in; i++) {
+		int status = rte_pipeline_port_in_connect_to_table(p->p,
+			p->port_in_id[i],
+			p->table_id[i]);
+
+		if (status) {
+			rte_pipeline_free(p->p);
+			rte_free(p);
+			return NULL;
+		}
+	}
+
+	/* Add entries to tables */
+	for (i = 0; i < p->n_ports_in; i++) {
+		struct rte_pipeline_table_entry default_entry = {
+			.action = RTE_PIPELINE_ACTION_PORT,
+			{.port_id = p->port_out_id[i / (p->n_ports_in / p->n_ports_out)]},
+		};
+
+		
+		struct rte_pipeline_table_entry *default_entry_ptr;
+
+		int status = rte_pipeline_table_default_entry_add(p->p,
+			p->table_id[i],
+			&default_entry,
+			&default_entry_ptr);
+		
+		if (status) {
+			rte_pipeline_free(p->p);
+			rte_free(p);
+			return NULL;
+		}
+	}
+
+	/* Enable input ports */
+	for (i = 0; i < p->n_ports_in; i++) {
+		int status = rte_pipeline_port_in_enable(p->p,
+			p->port_in_id[i]);
+		
+		if (status) {
+			rte_pipeline_free(p->p);
+			rte_free(p);
+			return NULL;
+		}
+	}
+
+	/* Check pipeline consistency */
+	if (rte_pipeline_check(p->p) < 0) {
+		rte_pipeline_free(p->p);
+		rte_free(p);
+		return NULL;
+	}
+	
+	/* Message queues */
+	p->n_msgq = params->n_msgq;
+	for (i = 0; i < p->n_msgq; i++)
+		p->msgq_in[i] = params->msgq_in[i];
+	for (i = 0; i < p->n_msgq; i++)
+		p->msgq_out[i] = params->msgq_out[i];
+	
+	/* Message handlers */
+	memcpy(p->handlers, handlers, sizeof(p->handlers));
+
+	return p;
+}
+
+static int
+pipeline_passthrough_free(void *pipeline)
+{
+	struct pipeline *p = (struct pipeline *) pipeline;
+
+	/* Check input arguments */
+	if (p == NULL)
+		return -1;
+	
+	/* Free resources */
+	rte_pipeline_free(p->p);
+	rte_free(p);
+	return 0;
+}
+
+static int
+pipeline_passthrough_timer(void *pipeline)
+{
+	struct pipeline *p = (struct pipeline *) pipeline;
+
+	pipeline_msg_req_handle(p);
+	rte_pipeline_flush(p->p);
+
+	return 0;
+}
+
+static int
+pipeline_passthrough_track(void *pipeline, uint32_t port_in, uint32_t *port_out)
+{
+	struct pipeline *p = (struct pipeline *) pipeline;
+
+	/* Check input arguments */
+	if ((p == NULL) ||
+		(port_in >= p->n_ports_in) ||
+		(port_out == NULL))
+		return -1;
+	
+	*port_out = port_in / p->n_ports_in;
+	return 0;
+}
+
+struct pipeline_ops pipeline_passthrough_ops = {
+		.f_init = pipeline_passthrough_init,
+		.f_free = pipeline_passthrough_free,
+		.f_run = NULL,
+		.f_timer = pipeline_passthrough_timer,
+		.f_track = pipeline_passthrough_track,
+};
diff --git a/examples/ip_pipeline/pipeline/pipeline_passthrough_ops.h b/examples/ip_pipeline/pipeline/pipeline_passthrough_ops.h
new file mode 100644
index 0000000..8aebb07
--- /dev/null
+++ b/examples/ip_pipeline/pipeline/pipeline_passthrough_ops.h
@@ -0,0 +1,41 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __INCLUDE_PIPELINE_PASSTHROUGH_OPS_H__
+#define __INCLUDE_PIPELINE_PASSTHROUGH_OPS_H__
+
+#include "pipeline_ops.h"
+
+extern struct pipeline_ops pipeline_passthrough_ops;
+
+#endif
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 09/11] ip_pipeline: added new implementation of firewall pipeline
  2015-05-29 15:43 [PATCH 00/11] ip_pipeline: ip_pipeline application enhancements Maciej Gajdzica
                   ` (7 preceding siblings ...)
  2015-05-29 15:43 ` [PATCH 08/11] ip_pipeline: added new implementation of passthrough pipeline Maciej Gajdzica
@ 2015-05-29 15:43 ` Maciej Gajdzica
  2015-05-29 15:43 ` [PATCH 10/11] ip_pipeline: added new implementation of routing pipeline Maciej Gajdzica
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Maciej Gajdzica @ 2015-05-29 15:43 UTC (permalink / raw)
  To: dev

Firewall pipeline implementation is split to two files.
pipeline_firewall.c file handles front-end functions (cli commands
parsing) pipeline_firewall_ops.c contains implementation of functions
done by pipeline (back-end).

Signed-off-by: Daniel Mrzyglod <danielx.t.mrzyglod@intel.com>
---
 examples/ip_pipeline/Makefile                      |    6 +-
 examples/ip_pipeline/init.c                        |    2 +
 examples/ip_pipeline/pipeline/pipeline_firewall.c  | 1099 +++++++++++++++-----
 examples/ip_pipeline/pipeline/pipeline_firewall.h  |   63 ++
 .../ip_pipeline/pipeline/pipeline_firewall_ops.c   |  538 ++++++++++
 .../ip_pipeline/pipeline/pipeline_firewall_ops.h   |  139 +++
 6 files changed, 1604 insertions(+), 243 deletions(-)
 create mode 100644 examples/ip_pipeline/pipeline/pipeline_firewall.h
 create mode 100644 examples/ip_pipeline/pipeline/pipeline_firewall_ops.c
 create mode 100644 examples/ip_pipeline/pipeline/pipeline_firewall_ops.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index fc845ce..0f8b1cc 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -61,13 +61,11 @@ SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_master_ops.c
 SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_master.c
 SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_passthrough_ops.c
 SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_passthrough.c
+SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_firewall_ops.c
+SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_firewall.c
 #SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_flow_classification.c
 #SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_routing.c
 
-#ifeq ($(CONFIG_RTE_LIBRTE_ACL),y)
-#SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_firewall.c
-#endif
-
 CFLAGS += -I$(SRCDIR) -I$(SRCDIR)/pipeline
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS) -Wno-error=unused-function -Wno-error=unused-variable
diff --git a/examples/ip_pipeline/init.c b/examples/ip_pipeline/init.c
index 22b2c77..29d87ae 100644
--- a/examples/ip_pipeline/init.c
+++ b/examples/ip_pipeline/init.c
@@ -45,6 +45,7 @@
 #include "pipeline.h"
 #include "pipeline_master.h"
 #include "pipeline_passthrough.h"
+#include "pipeline_firewall.h"
 
 #define APP_NAME_SIZE	32
 
@@ -1146,6 +1147,7 @@ int app_init(struct app_params *app)
 
 	app_pipeline_type_register(app, &pipeline_master);
 	app_pipeline_type_register(app, &pipeline_passthrough);
+	app_pipeline_type_register(app, &pipeline_firewall);
 
 	app_init_pipelines(app);
 	app_init_threads(app);
diff --git a/examples/ip_pipeline/pipeline/pipeline_firewall.c b/examples/ip_pipeline/pipeline/pipeline_firewall.c
index b70260e..21ae403 100644
--- a/examples/ip_pipeline/pipeline/pipeline_firewall.c
+++ b/examples/ip_pipeline/pipeline/pipeline_firewall.c
@@ -1,7 +1,7 @@
 /*-
  *   BSD LICENSE
  *
- *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
  *   All rights reserved.
  *
  *   Redistribution and use in source and binary forms, with or without
@@ -32,282 +32,903 @@
  */
 
 #include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
+#include <string.h>
+#include <sys/queue.h>
+#include <netinet/in.h>
 
+#include <rte_common.h>
+#include <rte_hexdump.h>
 #include <rte_malloc.h>
-#include <rte_log.h>
-#include <rte_ethdev.h>
-#include <rte_ether.h>
-#include <rte_ip.h>
-#include <rte_byteorder.h>
+#include <cmdline_rdline.h>
+#include <cmdline_parse.h>
+#include <cmdline_parse_num.h>
+#include <cmdline_parse_string.h>
+#include <cmdline_parse_ipaddr.h>
+#include <cmdline_parse_etheraddr.h>
+#include <cmdline_socket.h>
+
+#include "app.h"
+#include "pipeline_firewall_ops.h"
+#include "pipeline_firewall.h"
+#include "pipeline_common.h"
+
+#define MSG_TIMEOUT 1000
+
+struct app_pipeline_firewall_rule {
+	struct pipeline_firewall_key key;
+	int32_t priority;
+	uint32_t port_id;
+	void *entry_ptr;
+
+	TAILQ_ENTRY(app_pipeline_firewall_rule) node;
+};
+
+struct app_pipeline_firewall {
+	/* parameters */
+	uint32_t n_ports_in;
+	uint32_t n_ports_out;
+
+	/* rules */
+	TAILQ_HEAD(, app_pipeline_firewall_rule) rules;
+	uint32_t n_rules;
+	uint32_t default_rule_present;
+	uint32_t default_rule_port_id;
+	void *default_rule_entry_ptr;
+};
 
-#include <rte_port_ring.h>
-#include <rte_table_acl.h>
-#include <rte_pipeline.h>
+static void
+print_firewall_ipv4_rule(struct app_pipeline_firewall_rule *rule)
+{
+	printf("Prio = %d (SA = %u.%u.%u.%u/%u, "
+		"DA = %u.%u.%u.%u/%u, "
+		"SP = %u-%u, "
+		"DP = %u-%u, "
+		"Proto = %u / 0x%x) => "
+		"Port = %u (entry ptr = %p)\n",
+
+		rule->priority,
+
+		(rule->key.key.ipv4_5tuple.src_ip >> 24) & 0xFF,
+		(rule->key.key.ipv4_5tuple.src_ip >> 16) & 0xFF,
+		(rule->key.key.ipv4_5tuple.src_ip >> 8) & 0xFF,
+		rule->key.key.ipv4_5tuple.src_ip & 0xFF,
+		rule->key.key.ipv4_5tuple.src_ip_mask,
+
+		(rule->key.key.ipv4_5tuple.dst_ip >> 24) & 0xFF,
+		(rule->key.key.ipv4_5tuple.dst_ip >> 16) & 0xFF,
+		(rule->key.key.ipv4_5tuple.dst_ip >> 8) & 0xFF,
+		rule->key.key.ipv4_5tuple.dst_ip & 0xFF,
+		rule->key.key.ipv4_5tuple.dst_ip_mask,
+
+		rule->key.key.ipv4_5tuple.src_port_from,
+		rule->key.key.ipv4_5tuple.src_port_to,
+
+		rule->key.key.ipv4_5tuple.dst_port_from,
+		rule->key.key.ipv4_5tuple.dst_port_to,
+
+		rule->key.key.ipv4_5tuple.proto,
+		rule->key.key.ipv4_5tuple.proto_mask,
+
+		rule->port_id,
+		rule->entry_ptr);
+}
 
-#include "main.h"
+static struct app_pipeline_firewall_rule *
+app_pipeline_firewall_rule_find(struct app_pipeline_firewall *p,
+	struct pipeline_firewall_key *key)
+{
+	struct app_pipeline_firewall_rule *r;
 
-struct app_core_firewall_message_handle_params {
-	struct rte_ring *ring_req;
-	struct rte_ring *ring_resp;
+	TAILQ_FOREACH(r, &p->rules, node)
+		if (memcmp(key, &r->key, sizeof(struct pipeline_firewall_key)) == 0)
+			return r;
 
-	struct rte_pipeline *p;
-	uint32_t *port_out_id;
-	uint32_t table_id;
-};
+	return NULL;
+}
 
 static void
-app_message_handle(struct app_core_firewall_message_handle_params *params);
-
-enum {
-	PROTO_FIELD_IPV4,
-	SRC_FIELD_IPV4,
-	DST_FIELD_IPV4,
-	SRCP_FIELD_IPV4,
-	DSTP_FIELD_IPV4,
-	NUM_FIELDS_IPV4
-};
+app_pipeline_firewall_ls(
+	struct app_params *app,
+	uint32_t pipeline_id)
+{
+	struct app_pipeline_params *pipeline_params;
+	struct app_pipeline_data *pipeline_data;
+	struct app_pipeline_firewall *p;
+	struct app_pipeline_firewall_rule *rule;
+	uint32_t n_rules;
+	int priority;
+
+	/* Check input arguments */
+	if (app == NULL)
+		return;
 
-struct rte_acl_field_def ipv4_field_formats[NUM_FIELDS_IPV4] = {
-	{
-		.type = RTE_ACL_FIELD_TYPE_BITMASK,
-		.size = sizeof(uint8_t),
-		.field_index = PROTO_FIELD_IPV4,
-		.input_index = PROTO_FIELD_IPV4,
-		.offset = sizeof(struct ether_hdr) +
-			offsetof(struct ipv4_hdr, next_proto_id),
-	},
-	{
-		.type = RTE_ACL_FIELD_TYPE_MASK,
-		.size = sizeof(uint32_t),
-		.field_index = SRC_FIELD_IPV4,
-		.input_index = SRC_FIELD_IPV4,
-		.offset = sizeof(struct ether_hdr) +
-			offsetof(struct ipv4_hdr, src_addr),
-	},
-	{
-		.type = RTE_ACL_FIELD_TYPE_MASK,
-		.size = sizeof(uint32_t),
-		.field_index = DST_FIELD_IPV4,
-		.input_index = DST_FIELD_IPV4,
-		.offset = sizeof(struct ether_hdr) +
-			offsetof(struct ipv4_hdr, dst_addr),
-	},
-	{
-		.type = RTE_ACL_FIELD_TYPE_RANGE,
-		.size = sizeof(uint16_t),
-		.field_index = SRCP_FIELD_IPV4,
-		.input_index = SRCP_FIELD_IPV4,
-		.offset = sizeof(struct ether_hdr) + sizeof(struct ipv4_hdr),
-	},
-	{
-		.type = RTE_ACL_FIELD_TYPE_RANGE,
-		.size = sizeof(uint16_t),
-		.field_index = DSTP_FIELD_IPV4,
-		.input_index = SRCP_FIELD_IPV4,
-		.offset = sizeof(struct ether_hdr) + sizeof(struct ipv4_hdr) +
-			sizeof(uint16_t),
-	},
-};
+	APP_PARAM_FIND_BY_ID(app->pipeline_params, "PIPELINE", pipeline_id, pipeline_params);
+	if (pipeline_params == NULL)
+		return;
 
-void
-app_main_loop_pipeline_firewall(void) {
-	struct rte_pipeline_params pipeline_params = {
-		.name = "pipeline",
-		.socket_id = rte_socket_id(),
-	};
+	pipeline_data = &app->pipeline_data[pipeline_params - app->pipeline_params];
+	p = pipeline_data->fe;
+
+	n_rules = p->n_rules;
+	for (priority = 0; n_rules; priority++)
+		TAILQ_FOREACH(rule, &p->rules, node)
+			if (rule->priority == priority) {
+				print_firewall_ipv4_rule(rule);
+				n_rules --;
+			}
+
+	if (p->default_rule_present)
+		printf("Default rule: port %u (entry ptr = %p)\n",
+			p->default_rule_port_id,
+			p->default_rule_entry_ptr);
+	else
+		printf("Default rule: DROP\n");
+
+	printf("\n");
+}
 
-	struct rte_pipeline *p;
-	uint32_t port_in_id[APP_MAX_PORTS];
-	uint32_t port_out_id[APP_MAX_PORTS];
-	uint32_t table_id;
-	uint32_t i;
+static void*
+app_pipeline_firewall_init(struct pipeline_params *params,
+	__rte_unused void *arg)
+{
+	struct app_pipeline_firewall *p;
+	uint32_t size;
+
+	/* Check input arguments */
+	if ((params == NULL) ||
+		(params->n_ports_in == 0) ||
+		(params->n_ports_out == 0))
+		return NULL;
+
+	/* Memory allocation */
+	size = RTE_CACHE_LINE_ROUNDUP(sizeof(struct app_pipeline_firewall));
+	p = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
+	if (p == NULL)
+		return NULL;
 
-	uint32_t core_id = rte_lcore_id();
-	struct app_core_params *core_params = app_get_core_params(core_id);
-	struct app_core_firewall_message_handle_params mh_params;
+	/* Initialization */
+	p->n_ports_in = params->n_ports_in;
+	p->n_ports_out = params->n_ports_out;
 
-	if ((core_params == NULL) || (core_params->core_type != APP_CORE_FW))
-		rte_panic("Core %u misconfiguration\n", core_id);
+	TAILQ_INIT(&p->rules);
+	p->n_rules = 0;
+	p->default_rule_present = 0;
+	p->default_rule_port_id = 0;
+	p->default_rule_entry_ptr = NULL;
 
-	RTE_LOG(INFO, USER1, "Core %u is doing firewall\n", core_id);
+	return (void *) p;
+}
 
-	/* Pipeline configuration */
-	p = rte_pipeline_create(&pipeline_params);
+static int
+app_pipeline_firewall_free(void *pipeline)
+{
+	struct app_pipeline_firewall *p = pipeline;
+	struct app_pipeline_firewall_rule *rule;
+
+	/* Check input arguments */
 	if (p == NULL)
-		rte_panic("Unable to configure the pipeline\n");
-
-	/* Input port configuration */
-	for (i = 0; i < app.n_ports; i++) {
-		struct rte_port_ring_reader_params port_ring_params = {
-			.ring = app.rings[core_params->swq_in[i]],
-		};
-
-		struct rte_pipeline_port_in_params port_params = {
-			.ops = &rte_port_ring_reader_ops,
-			.arg_create = (void *) &port_ring_params,
-			.f_action = NULL,
-			.arg_ah = NULL,
-			.burst_size = app.bsz_swq_rd,
-		};
-
-		if (rte_pipeline_port_in_create(p, &port_params,
-			&port_in_id[i]))
-			rte_panic("Unable to configure input port for "
-				"ring %d\n", i);
+		return -1;
+
+	/* Free resources */
+	while (!TAILQ_EMPTY(&p->rules)) {
+		rule = TAILQ_FIRST(&p->rules);
+		TAILQ_REMOVE(&p->rules, rule, node);
+		rte_free(rule);
+	}
+
+	rte_free(p);
+	return 0;
+}
+
+int
+app_pipeline_firewall_add_rule(struct app_params *app,
+	uint32_t pipeline_id,
+	struct pipeline_firewall_key *key,
+	uint32_t priority,
+	uint32_t port_id)
+{
+	struct app_pipeline_params *params;
+	struct app_pipeline_data *data;
+	struct app_pipeline_firewall *p;
+	struct app_pipeline_firewall_rule *rule;
+	struct pipeline_firewall_add_msg_req *req;
+	struct pipeline_firewall_add_msg_rsp *rsp;
+	int new_rule;
+
+	/* Check input arguments */
+	if ((app == NULL) ||
+		(key == NULL) ||
+		(key->type != PIPELINE_FIREWALL_IPV4_5TUPLE))
+		return -1;
+
+	APP_PARAM_FIND_BY_ID(app->pipeline_params, "PIPELINE", pipeline_id, params);
+	if ((params == NULL) ||
+		(port_id >= params->n_pktq_out))
+		return -1;
+	
+	data = &app->pipeline_data[params - app->pipeline_params];
+	p = data->fe;
+
+	/* Find existing rule or allocate new rule */
+	rule = app_pipeline_firewall_rule_find(p, key);
+	new_rule = (rule == NULL);
+	if (rule == NULL) {
+		rule = rte_malloc(NULL, sizeof(*rule), RTE_CACHE_LINE_SIZE);
+
+		if (rule == NULL)
+			return -1;
+	}
+
+	/* Allocate and write request */
+	req = app_msg_alloc(app);
+	if (req == NULL) {
+		if (new_rule)
+			rte_free(rule);
+		return -1;
 	}
 
-	/* Output port configuration */
-	for (i = 0; i < app.n_ports; i++) {
-		struct rte_port_ring_writer_params port_ring_params = {
-			.ring = app.rings[core_params->swq_out[i]],
-			.tx_burst_sz = app.bsz_swq_wr,
-		};
-
-		struct rte_pipeline_port_out_params port_params = {
-			.ops = &rte_port_ring_writer_ops,
-			.arg_create = (void *) &port_ring_params,
-			.f_action = NULL,
-			.f_action_bulk = NULL,
-			.arg_ah = NULL,
-		};
-
-		if (rte_pipeline_port_out_create(p, &port_params,
-			&port_out_id[i]))
-			rte_panic("Unable to configure output port for "
-				"ring %d\n", i);
+	req->type = PIPELINE_MSG_REQ_CUSTOM;
+	req->subtype = PIPELINE_FIREWALL_MSG_REQ_ADD;
+	memcpy(&req->key, key, sizeof(*key));
+	req->priority = priority;
+	req->port_id = port_id;
+
+	/* Send request and wait for response */
+	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT);
+	if (rsp == NULL) {
+		if (new_rule)
+			rte_free(rule);
+		return -1;
 	}
 
-	/* Table configuration */
-	{
-		struct rte_table_acl_params table_acl_params = {
-			.name = "test", /* unique identifier for acl contexts */
-			.n_rules = app.max_firewall_rules,
-			.n_rule_fields = DIM(ipv4_field_formats),
-		};
-
-		struct rte_pipeline_table_params table_params = {
-			.ops = &rte_table_acl_ops,
-			.arg_create = &table_acl_params,
-			.f_action_hit = NULL,
-			.f_action_miss = NULL,
-			.arg_ah = NULL,
-			.action_data_size = 0,
-		};
-
-		memcpy(table_acl_params.field_format, ipv4_field_formats,
-			sizeof(ipv4_field_formats));
-
-		if (rte_pipeline_table_create(p, &table_params, &table_id))
-			rte_panic("Unable to configure the ACL table\n");
+	/* Read response and write rule */
+	if (rsp->status || (rsp->entry_ptr == NULL)){
+		app_msg_free(app, rsp);
+		if (new_rule)
+			rte_free(rule);
+		return -1;
 	}
 
-	/* Interconnecting ports and tables */
-	for (i = 0; i < app.n_ports; i++)
-		if (rte_pipeline_port_in_connect_to_table(p, port_in_id[i],
-			table_id))
-			rte_panic("Unable to connect input port %u to "
-				"table %u\n", port_in_id[i],  table_id);
-
-	/* Enable input ports */
-	for (i = 0; i < app.n_ports; i++)
-		if (rte_pipeline_port_in_enable(p, port_in_id[i]))
-			rte_panic("Unable to enable input port %u\n",
-				port_in_id[i]);
-
-	/* Check pipeline consistency */
-	if (rte_pipeline_check(p) < 0)
-		rte_panic("Pipeline consistency check failed\n");
-
-	/* Message handling */
-	mh_params.ring_req = app_get_ring_req(
-		app_get_first_core_id(APP_CORE_FW));
-	mh_params.ring_resp = app_get_ring_resp(
-		app_get_first_core_id(APP_CORE_FW));
-	mh_params.p = p;
-	mh_params.port_out_id = port_out_id;
-	mh_params.table_id = table_id;
-
-	/* Run-time */
-	for (i = 0; ; i++) {
-		rte_pipeline_run(p);
-
-		if ((i & APP_FLUSH) == 0) {
-			rte_pipeline_flush(p);
-			app_message_handle(&mh_params);
-		}
+	memcpy(&rule->key, key, sizeof(*key));
+	rule->priority = priority;
+	rule->port_id = port_id;
+	rule->entry_ptr = rsp->entry_ptr;
+	
+	/* Commit rule */
+	if (new_rule) {
+		TAILQ_INSERT_TAIL(&p->rules, rule, node);
+		p->n_rules ++;
 	}
+
+	print_firewall_ipv4_rule(rule);
+
+	/* Free response */
+	app_msg_free(app, rsp);
+
+	return 0;
 }
 
-void
-app_message_handle(struct app_core_firewall_message_handle_params *params)
+int
+app_pipeline_firewall_delete_rule(struct app_params *app,
+	uint32_t pipeline_id,
+	struct pipeline_firewall_key *key)
 {
-	struct rte_ring *ring_req = params->ring_req;
-	struct rte_ring *ring_resp;
-	struct rte_mbuf *msg;
-	struct app_msg_req *req;
-	struct app_msg_resp *resp;
-	struct rte_pipeline *p;
-	uint32_t *port_out_id;
-	uint32_t table_id;
-	int result;
-
-	/* Read request message */
-	result = rte_ring_sc_dequeue(ring_req, (void **) &msg);
-	if (result != 0)
-		return;
+	struct app_pipeline_params *params;
+	struct app_pipeline_data *data;
+	struct app_pipeline_firewall *p;
+	struct app_pipeline_firewall_rule *rule;
+	struct pipeline_firewall_del_msg_req *req;
+	struct pipeline_firewall_del_msg_rsp *rsp;
+
+	/* Check input arguments */
+	if ((app == NULL) ||
+		(key == NULL) ||
+		(key->type != PIPELINE_FIREWALL_IPV4_5TUPLE))
+		return -1;
+
+	APP_PARAM_FIND_BY_ID(app->pipeline_params, "PIPELINE", pipeline_id, params);
+	if (params == NULL)
+		return -1;
+	
+	data = &app->pipeline_data[params - app->pipeline_params];
+	p = data->fe;
+
+	/* Find rule */
+	rule = app_pipeline_firewall_rule_find(p, key);
+	if (rule == NULL)
+		return 0;
+
+	/* Allocate and write request */
+	req = app_msg_alloc(app);
+	if (req == NULL)
+		return -1;
+
+	req->type = PIPELINE_MSG_REQ_CUSTOM;
+	req->subtype = PIPELINE_FIREWALL_MSG_REQ_DEL;
+	memcpy(&req->key, key, sizeof(*key));
+
+	/* Send request and wait for response */
+	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	if (rsp->status) {
+		app_msg_free(app, rsp);
+		return -1;
+	}
+
+	/* Remove rule */
+	TAILQ_REMOVE(&p->rules, rule, node);
+	p->n_rules --;
+
+	/* Free response */
+	app_msg_free(app, rsp);
+
+	return 0;
+}
+
+int
+app_pipeline_firewall_add_default_rule(struct app_params *app,
+	uint32_t pipeline_id,
+	uint32_t port_id)
+{
+	struct app_pipeline_params *params;
+	struct app_pipeline_data *data;
+	struct app_pipeline_firewall *p;
+	struct pipeline_firewall_add_default_msg_req *req;
+	struct pipeline_firewall_add_default_msg_rsp *rsp;
+
+	/* Check input arguments */
+	if (app == NULL)
+		return -1;
+		
+	APP_PARAM_FIND_BY_ID(app->pipeline_params, "PIPELINE", pipeline_id, params);
+	if ((params == NULL) ||
+		(port_id >= params->n_pktq_out))
+		return -1;
+
+	data = &app->pipeline_data[params - app->pipeline_params];
+	p = data->fe;
+
+	/* Allocate and write request */
+	req = app_msg_alloc(app);
+	if (req == NULL)
+		return -1;
+
+	req->type = PIPELINE_MSG_REQ_CUSTOM;
+	req->subtype = PIPELINE_FIREWALL_MSG_REQ_ADD_DEFAULT;
+	req->port_id = port_id;
+
+	/* Send request and wait for response */
+	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response and write rule */
+	if (rsp->status || (rsp->entry_ptr == NULL)){
+		app_msg_free(app, rsp);
+		return -1;
+	}
+
+	p->default_rule_port_id = port_id;
+	p->default_rule_entry_ptr = rsp->entry_ptr;
+
+	/* Commit rule */
+	p->default_rule_present = 1;
+
+	/* Free response */
+	app_msg_free(app, rsp);
+
+	return 0;
+}
+
+int
+app_pipeline_firewall_delete_default_rule(struct app_params *app,
+	uint32_t pipeline_id)
+{
+	struct app_pipeline_params *params;
+	struct app_pipeline_data *data;
+	struct app_pipeline_firewall *p;
+	struct pipeline_firewall_del_default_msg_req *req;
+	struct pipeline_firewall_del_default_msg_rsp *rsp;
+
+	/* Check input arguments */
+	if (app == NULL)
+		return -1;
+
+	APP_PARAM_FIND_BY_ID(app->pipeline_params, "PIPELINE", pipeline_id, params);
+	if (params == NULL)
+		return -1;
+
+	data = &app->pipeline_data[params - app->pipeline_params];
+	p = data->fe;
+
+	/* Allocate and write request */
+	req = app_msg_alloc(app);
+	if (req == NULL)
+		return -1;
+
+	req->type = PIPELINE_MSG_REQ_CUSTOM;
+	req->subtype = PIPELINE_FIREWALL_MSG_REQ_DEL_DEFAULT;
+
+	/* Send request and wait for response */
+	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response and write rule */
+	if (rsp->status) {
+		app_msg_free(app, rsp);
+		return -1;
+	}
+
+	/* Commit rule */
+	p->default_rule_present = 0;
+
+	/* Free response */
+	app_msg_free(app, rsp);
 
-	ring_resp = params->ring_resp;
-	p = params->p;
-	port_out_id = params->port_out_id;
-	table_id = params->table_id;
-
-	/* Handle request */
-	req = (struct app_msg_req *)rte_ctrlmbuf_data(msg);
-	switch (req->type) {
-	case APP_MSG_REQ_PING:
-	{
-		result = 0;
-		break;
+	return 0;
+}
+
+/*
+ * p firewall add ipv4
+ */
+
+struct cmd_firewall_add_ipv4_result {
+	cmdline_fixed_string_t p_string;
+	uint32_t pipeline_id;
+	cmdline_fixed_string_t firewall_string;
+	cmdline_fixed_string_t add_string;
+	cmdline_fixed_string_t ipv4_string;
+	int32_t priority;
+	cmdline_ipaddr_t src_ip;
+	uint32_t src_ip_mask;
+	cmdline_ipaddr_t dst_ip;
+	uint32_t dst_ip_mask;
+	uint16_t src_port_from;
+	uint16_t src_port_to;
+	uint16_t dst_port_from;
+	uint16_t dst_port_to;
+	uint8_t proto;
+	uint8_t proto_mask;
+	uint8_t port_id;
+};
+
+static void
+cmd_firewall_add_ipv4_parsed(
+	void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	void *data)
+{
+	struct cmd_firewall_add_ipv4_result *params = parsed_result;
+	struct app_params *app = data;
+	struct pipeline_firewall_key key;
+	int status;
+
+	key.type = PIPELINE_FIREWALL_IPV4_5TUPLE;
+	key.key.ipv4_5tuple.src_ip = rte_bswap32((uint32_t) params->src_ip.addr.ipv4.s_addr);
+	key.key.ipv4_5tuple.src_ip_mask = params->src_ip_mask;
+	key.key.ipv4_5tuple.dst_ip = rte_bswap32((uint32_t) params->dst_ip.addr.ipv4.s_addr);
+	key.key.ipv4_5tuple.dst_ip_mask = params->dst_ip_mask;
+	key.key.ipv4_5tuple.src_port_from = params->src_port_from;
+	key.key.ipv4_5tuple.src_port_to = params->src_port_to;
+	key.key.ipv4_5tuple.dst_port_from = params->dst_port_from;
+	key.key.ipv4_5tuple.dst_port_to = params->dst_port_to;
+	key.key.ipv4_5tuple.proto = params->proto;
+	key.key.ipv4_5tuple.proto_mask = params->proto_mask;
+
+	status = app_pipeline_firewall_add_rule(app,
+		params->pipeline_id,
+		&key,
+		params->priority,
+		params->port_id);
+
+	if(status != 0) {
+		printf("Command failed\n");
+		return;
 	}
+}
+
+cmdline_parse_token_string_t cmd_firewall_add_ipv4_p_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_firewall_add_ipv4_result, p_string, "p");
+
+cmdline_parse_token_num_t cmd_firewall_add_ipv4_pipeline_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_ipv4_result, pipeline_id, UINT32);
+
+cmdline_parse_token_string_t cmd_firewall_add_ipv4_firewall_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_firewall_add_ipv4_result, firewall_string, "firewall");
+
+cmdline_parse_token_string_t cmd_firewall_add_ipv4_add_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_firewall_add_ipv4_result, add_string, "add");
+
+cmdline_parse_token_string_t cmd_firewall_add_ipv4_ipv4_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_firewall_add_ipv4_result, ipv4_string, "ipv4");
+
+cmdline_parse_token_num_t cmd_firewall_add_ipv4_priority =
+	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_ipv4_result, priority, INT32);
+
+cmdline_parse_token_ipaddr_t cmd_firewall_add_ipv4_src_ip =
+	TOKEN_IPADDR_INITIALIZER(struct cmd_firewall_add_ipv4_result, src_ip);
+
+cmdline_parse_token_num_t cmd_firewall_add_ipv4_src_ip_mask =
+	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_ipv4_result, src_ip_mask, UINT32);
 
-	case APP_MSG_REQ_FW_ADD:
-	{
-		struct rte_pipeline_table_entry entry = {
-			.action = RTE_PIPELINE_ACTION_PORT,
-			{.port_id = port_out_id[req->firewall_add.port]},
-		};
+cmdline_parse_token_ipaddr_t cmd_firewall_add_ipv4_dst_ip =
+	TOKEN_IPADDR_INITIALIZER(struct cmd_firewall_add_ipv4_result, dst_ip);
 
-		struct rte_pipeline_table_entry *entry_ptr;
+cmdline_parse_token_num_t cmd_firewall_add_ipv4_dst_ip_mask =
+	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_ipv4_result, dst_ip_mask, UINT32);
 
-		int key_found;
+cmdline_parse_token_num_t cmd_firewall_add_ipv4_src_port_from =
+	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_ipv4_result, src_port_from, UINT16);
 
-		result = rte_pipeline_table_entry_add(p, table_id,
-			&req->firewall_add.add_params, &entry, &key_found,
-			&entry_ptr);
-		break;
+cmdline_parse_token_num_t cmd_firewall_add_ipv4_src_port_to =
+	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_ipv4_result, src_port_to, UINT16);
+
+cmdline_parse_token_num_t cmd_firewall_add_ipv4_dst_port_from =
+	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_ipv4_result, dst_port_from, UINT16);
+
+cmdline_parse_token_num_t cmd_firewall_add_ipv4_dst_port_to =
+	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_ipv4_result, dst_port_to, UINT16);
+
+cmdline_parse_token_num_t cmd_firewall_add_ipv4_proto =
+	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_ipv4_result, proto, UINT8);
+
+cmdline_parse_token_num_t cmd_firewall_add_ipv4_proto_mask =
+	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_ipv4_result, proto_mask, UINT8);
+
+cmdline_parse_token_num_t cmd_firewall_add_ipv4_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_ipv4_result, port_id, UINT8);
+
+cmdline_parse_inst_t cmd_firewall_add_ipv4 = {
+	.f = cmd_firewall_add_ipv4_parsed,
+	.data = NULL,
+	.help_str = "Firewall rule add",
+	.tokens = {
+		(void *) &cmd_firewall_add_ipv4_p_string,
+		(void *) &cmd_firewall_add_ipv4_pipeline_id,
+		(void *) &cmd_firewall_add_ipv4_firewall_string,
+		(void *) &cmd_firewall_add_ipv4_add_string,
+		(void *) &cmd_firewall_add_ipv4_ipv4_string,
+		(void *) &cmd_firewall_add_ipv4_priority,
+		(void *) &cmd_firewall_add_ipv4_src_ip,
+		(void *) &cmd_firewall_add_ipv4_src_ip_mask,
+		(void *) &cmd_firewall_add_ipv4_dst_ip,
+		(void *) &cmd_firewall_add_ipv4_dst_ip_mask,
+		(void *) &cmd_firewall_add_ipv4_src_port_from,
+		(void *) &cmd_firewall_add_ipv4_src_port_to,
+		(void *) &cmd_firewall_add_ipv4_dst_port_from,
+		(void *) &cmd_firewall_add_ipv4_dst_port_to,
+		(void *) &cmd_firewall_add_ipv4_proto,
+		(void *) &cmd_firewall_add_ipv4_proto_mask,
+		(void *) &cmd_firewall_add_ipv4_port_id,
+		NULL,
+	},
+};
+
+/*
+ * p firewall del ipv4
+ */
+
+struct cmd_firewall_del_ipv4_result {
+	cmdline_fixed_string_t p_string;
+	uint32_t pipeline_id;
+	cmdline_fixed_string_t firewall_string;
+	cmdline_fixed_string_t del_string;
+	cmdline_fixed_string_t ipv4_string;
+	cmdline_ipaddr_t src_ip;
+	uint32_t src_ip_mask;
+	cmdline_ipaddr_t dst_ip;
+	uint32_t dst_ip_mask;
+	uint16_t src_port_from;
+	uint16_t src_port_to;
+	uint16_t dst_port_from;
+	uint16_t dst_port_to;
+	uint8_t proto;
+	uint8_t proto_mask;
+};
+
+static void
+cmd_firewall_del_ipv4_parsed(
+	void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	void *data)
+{
+	struct cmd_firewall_del_ipv4_result *params = parsed_result;
+	struct app_params *app = data;
+	struct pipeline_firewall_key key;
+	int status;
+
+	key.type = PIPELINE_FIREWALL_IPV4_5TUPLE;
+	key.key.ipv4_5tuple.src_ip = rte_bswap32((uint32_t) params->src_ip.addr.ipv4.s_addr);
+	key.key.ipv4_5tuple.src_ip_mask = params->src_ip_mask;
+	key.key.ipv4_5tuple.dst_ip = rte_bswap32((uint32_t) params->dst_ip.addr.ipv4.s_addr);
+	key.key.ipv4_5tuple.dst_ip_mask = params->dst_ip_mask;
+	key.key.ipv4_5tuple.src_port_from = params->src_port_from;
+	key.key.ipv4_5tuple.src_port_to = params->src_port_to;
+	key.key.ipv4_5tuple.dst_port_from = params->dst_port_from;
+	key.key.ipv4_5tuple.dst_port_to = params->dst_port_to;
+	key.key.ipv4_5tuple.proto = params->proto;
+	key.key.ipv4_5tuple.proto_mask = params->proto_mask;
+
+	status = app_pipeline_firewall_delete_rule(app,
+		params->pipeline_id,
+		&key);
+
+	if(status != 0) {
+		printf("Command failed\n");
+		return;
 	}
+}
+
+cmdline_parse_token_string_t cmd_firewall_del_ipv4_p_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_firewall_del_ipv4_result, p_string, "p");
+
+cmdline_parse_token_num_t cmd_firewall_del_ipv4_pipeline_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_firewall_del_ipv4_result, pipeline_id, UINT32);
 
-	case APP_MSG_REQ_FW_DEL:
-	{
-		int key_found;
+cmdline_parse_token_string_t cmd_firewall_del_ipv4_firewall_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_firewall_del_ipv4_result, firewall_string, "firewall");
+
+cmdline_parse_token_string_t cmd_firewall_del_ipv4_del_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_firewall_del_ipv4_result, del_string, "del");
+
+cmdline_parse_token_string_t cmd_firewall_del_ipv4_ipv4_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_firewall_del_ipv4_result, ipv4_string, "ipv4");
+
+cmdline_parse_token_ipaddr_t cmd_firewall_del_ipv4_src_ip =
+	TOKEN_IPADDR_INITIALIZER(struct cmd_firewall_del_ipv4_result, src_ip);
+
+cmdline_parse_token_num_t cmd_firewall_del_ipv4_src_ip_mask =
+	TOKEN_NUM_INITIALIZER(struct cmd_firewall_del_ipv4_result, src_ip_mask, UINT32);
+
+cmdline_parse_token_ipaddr_t cmd_firewall_del_ipv4_dst_ip =
+	TOKEN_IPADDR_INITIALIZER(struct cmd_firewall_del_ipv4_result, dst_ip);
+
+cmdline_parse_token_num_t cmd_firewall_del_ipv4_dst_ip_mask =
+	TOKEN_NUM_INITIALIZER(struct cmd_firewall_del_ipv4_result, dst_ip_mask, UINT32);
+
+cmdline_parse_token_num_t cmd_firewall_del_ipv4_src_port_from =
+	TOKEN_NUM_INITIALIZER(struct cmd_firewall_del_ipv4_result, src_port_from, UINT16);
+
+cmdline_parse_token_num_t cmd_firewall_del_ipv4_src_port_to =
+	TOKEN_NUM_INITIALIZER(struct cmd_firewall_del_ipv4_result, src_port_to, UINT16);
+
+cmdline_parse_token_num_t cmd_firewall_del_ipv4_dst_port_from =
+	TOKEN_NUM_INITIALIZER(struct cmd_firewall_del_ipv4_result, dst_port_from, UINT16);
+
+cmdline_parse_token_num_t cmd_firewall_del_ipv4_dst_port_to =
+	TOKEN_NUM_INITIALIZER(struct cmd_firewall_del_ipv4_result, dst_port_to, UINT16);
+
+cmdline_parse_token_num_t cmd_firewall_del_ipv4_proto =
+	TOKEN_NUM_INITIALIZER(struct cmd_firewall_del_ipv4_result, proto, UINT8);
+
+cmdline_parse_token_num_t cmd_firewall_del_ipv4_proto_mask =
+	TOKEN_NUM_INITIALIZER(struct cmd_firewall_del_ipv4_result, proto_mask, UINT8);
+
+cmdline_parse_inst_t cmd_firewall_del_ipv4 = {
+	.f = cmd_firewall_del_ipv4_parsed,
+	.data = NULL,
+	.help_str = "Firewall rule delete",
+	.tokens = {
+		(void *) &cmd_firewall_del_ipv4_p_string,
+		(void *) &cmd_firewall_del_ipv4_pipeline_id,
+		(void *) &cmd_firewall_del_ipv4_firewall_string,
+		(void *) &cmd_firewall_del_ipv4_del_string,
+		(void *) &cmd_firewall_del_ipv4_ipv4_string,
+		(void *) &cmd_firewall_del_ipv4_src_ip,
+		(void *) &cmd_firewall_del_ipv4_src_ip_mask,
+		(void *) &cmd_firewall_del_ipv4_dst_ip,
+		(void *) &cmd_firewall_del_ipv4_dst_ip_mask,
+		(void *) &cmd_firewall_del_ipv4_src_port_from,
+		(void *) &cmd_firewall_del_ipv4_src_port_to,
+		(void *) &cmd_firewall_del_ipv4_dst_port_from,
+		(void *) &cmd_firewall_del_ipv4_dst_port_to,
+		(void *) &cmd_firewall_del_ipv4_proto,
+		(void *) &cmd_firewall_del_ipv4_proto_mask,
+		NULL,
+	},
+};
+
+/*
+ * p firewall add default
+ */
+struct cmd_firewall_add_default_result {
+	cmdline_fixed_string_t p_string;
+	uint32_t pipeline_id;
+	cmdline_fixed_string_t firewall_string;
+	cmdline_fixed_string_t add_string;
+	cmdline_fixed_string_t default_string;
+	uint8_t port_id;
+};
 
-		result = rte_pipeline_table_entry_delete(p, table_id,
-			&req->firewall_del.delete_params, &key_found, NULL);
-		break;
+static void
+cmd_firewall_add_default_parsed(
+	void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	void *data)
+{
+	struct cmd_firewall_add_default_result *params = parsed_result;
+	struct app_params *app = data;
+	int status;
+
+	status = app_pipeline_firewall_add_default_rule(app,
+		params->pipeline_id,
+		params->port_id);
+
+	if(status != 0) {
+		printf("Command failed\n");
+		return;
 	}
+}
+
+cmdline_parse_token_string_t cmd_firewall_add_default_p_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_firewall_add_default_result, p_string, "p");
+
+cmdline_parse_token_num_t cmd_firewall_add_default_pipeline_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_default_result, pipeline_id, UINT32);
+
+cmdline_parse_token_string_t cmd_firewall_add_default_firewall_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_firewall_add_default_result,
+	firewall_string, "firewall");
+
+cmdline_parse_token_string_t cmd_firewall_add_default_add_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_firewall_add_default_result, add_string,
+	"add");
+
+cmdline_parse_token_string_t cmd_firewall_add_default_default_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_firewall_add_default_result, default_string,
+	"default");
+
+cmdline_parse_token_num_t cmd_firewall_add_default_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_firewall_add_default_result, port_id, UINT8);
+
+cmdline_parse_inst_t cmd_firewall_add_default = {
+	.f = cmd_firewall_add_default_parsed,
+	.data = NULL,
+	.help_str = "Firewall default rule add",
+	.tokens = {
+		(void *) &cmd_firewall_add_default_p_string,
+		(void *) &cmd_firewall_add_default_pipeline_id,
+		(void *) &cmd_firewall_add_default_firewall_string,
+		(void *) &cmd_firewall_add_default_add_string,
+		(void *) &cmd_firewall_add_default_default_string,
+		(void *) &cmd_firewall_add_default_port_id,
+		NULL,
+	},
+};
 
-	default:
-		rte_panic("FW unrecognized message type (%u)\n", req->type);
+/*
+ * p firewall del default
+ */
+struct cmd_firewall_del_default_result {
+	cmdline_fixed_string_t p_string;
+	uint32_t pipeline_id;
+	cmdline_fixed_string_t firewall_string;
+	cmdline_fixed_string_t del_string;
+	cmdline_fixed_string_t default_string;
+};
+
+static void
+cmd_firewall_del_default_parsed(
+	void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	void *data)
+{
+	struct cmd_firewall_del_default_result *params = parsed_result;
+	struct app_params *app = data;
+	int status;
+
+	status = app_pipeline_firewall_delete_default_rule(app,
+		params->pipeline_id);
+
+	if(status != 0) {
+		printf("Command failed\n");
+		return;
 	}
+}
 
-	/* Fill in response message */
-	resp = (struct app_msg_resp *)rte_ctrlmbuf_data(msg);
-	resp->result = result;
+cmdline_parse_token_string_t cmd_firewall_del_default_p_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_firewall_del_default_result, p_string, "p");
+
+cmdline_parse_token_num_t cmd_firewall_del_default_pipeline_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_firewall_del_default_result, pipeline_id, UINT32);
+
+cmdline_parse_token_string_t cmd_firewall_del_default_firewall_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_firewall_del_default_result,
+	firewall_string, "firewall");
+
+cmdline_parse_token_string_t cmd_firewall_del_default_del_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_firewall_del_default_result, del_string,
+	"del");
+
+cmdline_parse_token_string_t cmd_firewall_del_default_default_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_firewall_del_default_result, default_string,
+	"default");
+
+cmdline_parse_inst_t cmd_firewall_del_default = {
+	.f = cmd_firewall_del_default_parsed,
+	.data = NULL,
+	.help_str = "Firewall default rule delete",
+	.tokens = {
+		(void *) &cmd_firewall_del_default_p_string,
+		(void *) &cmd_firewall_del_default_pipeline_id,
+		(void *) &cmd_firewall_del_default_firewall_string,
+		(void *) &cmd_firewall_del_default_del_string,
+		(void *) &cmd_firewall_del_default_default_string,
+		NULL,
+	},
+};
+
+/*
+ * p firewall ls
+ */
+
+struct cmd_firewall_ls_result {
+	cmdline_fixed_string_t p_string;
+	uint32_t pipeline_id;
+	cmdline_fixed_string_t firewall_string;
+	cmdline_fixed_string_t ls_string;
+};
+
+static void
+cmd_firewall_ls_parsed(
+	void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	void *data)
+{
+	struct cmd_firewall_ls_result *params = parsed_result;
+	struct app_params *app = data;
 
-	/* Send response */
-	do {
-		result = rte_ring_sp_enqueue(ring_resp, (void *) msg);
-	} while (result == -ENOBUFS);
+	app_pipeline_firewall_ls(app, params->pipeline_id);
 }
+
+cmdline_parse_token_string_t cmd_firewall_ls_p_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_firewall_ls_result, p_string, "p");
+
+cmdline_parse_token_num_t cmd_firewall_ls_pipeline_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_firewall_ls_result, pipeline_id, UINT32);
+
+cmdline_parse_token_string_t cmd_firewall_ls_firewall_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_firewall_ls_result,
+	firewall_string, "firewall");
+
+cmdline_parse_token_string_t cmd_firewall_ls_ls_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_firewall_ls_result, ls_string,
+	"ls");
+
+cmdline_parse_inst_t cmd_firewall_ls = {
+	.f = cmd_firewall_ls_parsed,
+	.data = NULL,
+	.help_str = "Firewall rule list",
+	.tokens = {
+		(void *) &cmd_firewall_ls_p_string,
+		(void *) &cmd_firewall_ls_pipeline_id,
+		(void *) &cmd_firewall_ls_firewall_string,
+		(void *) &cmd_firewall_ls_ls_string,
+		NULL,
+	},
+};
+
+static cmdline_parse_ctx_t pipeline_cmds[] = {
+	(cmdline_parse_inst_t *) &cmd_firewall_add_ipv4,
+	(cmdline_parse_inst_t *) &cmd_firewall_del_ipv4,
+	(cmdline_parse_inst_t *) &cmd_firewall_add_default,
+	(cmdline_parse_inst_t *) &cmd_firewall_del_default,
+	(cmdline_parse_inst_t *) &cmd_firewall_ls,
+	NULL,
+};
+
+static struct pipeline_fe_ops pipeline_firewall_fe_ops = {
+	.f_init = app_pipeline_firewall_init,
+	.f_free = app_pipeline_firewall_free,
+	.cmds = pipeline_cmds,
+};
+
+struct pipeline_type pipeline_firewall = {
+	.name = "FIREWALL",
+	.ops = &pipeline_firewall_ops,
+	.fe_ops = &pipeline_firewall_fe_ops,
+};
diff --git a/examples/ip_pipeline/pipeline/pipeline_firewall.h b/examples/ip_pipeline/pipeline/pipeline_firewall.h
new file mode 100644
index 0000000..a938fa2
--- /dev/null
+++ b/examples/ip_pipeline/pipeline/pipeline_firewall.h
@@ -0,0 +1,63 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __INCLUDE_PIPELINE_FIREWALL_H__
+#define __INCLUDE_PIPELINE_FIREWALL_H__
+
+#include "pipeline.h"
+#include "pipeline_firewall_ops.h"
+
+int
+app_pipeline_firewall_add_rule(struct app_params *app,
+	uint32_t pipeline_id,
+	struct pipeline_firewall_key *key,
+	uint32_t priority,
+	uint32_t port_id);
+
+int
+app_pipeline_firewall_delete_rule(struct app_params *app,
+	uint32_t pipeline_id,
+	struct pipeline_firewall_key *key);
+
+int
+app_pipeline_firewall_add_default_rule(struct app_params *app,
+	uint32_t pipeline_id,
+	uint32_t port_id);
+
+int
+app_pipeline_firewall_delete_default_rule(struct app_params *app,
+	uint32_t pipeline_id);
+
+extern struct pipeline_type pipeline_firewall;
+
+#endif
diff --git a/examples/ip_pipeline/pipeline/pipeline_firewall_ops.c b/examples/ip_pipeline/pipeline/pipeline_firewall_ops.c
new file mode 100644
index 0000000..834330b
--- /dev/null
+++ b/examples/ip_pipeline/pipeline/pipeline_firewall_ops.c
@@ -0,0 +1,538 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string.h>
+
+#include <rte_common.h>
+#include <rte_log.h>
+#include <rte_malloc.h>
+#include <rte_ip.h>
+#include <rte_byteorder.h>
+#include <rte_table_acl.h>
+
+#include "pipeline_common_ops.h"
+#include "pipeline_firewall_ops.h"
+
+struct pipeline_firewall {
+	struct pipeline p;
+	pipeline_msg_req_handler custom_handlers[PIPELINE_FIREWALL_MSG_REQS];
+	
+	uint32_t n_rules;
+} __rte_cache_aligned;
+
+static void *
+pipeline_firewall_msg_req_custom_handler(struct pipeline *p, void *msg);
+
+static pipeline_msg_req_handler handlers[] = {
+	[PIPELINE_MSG_REQ_PING] = pipeline_msg_req_ping_handler,
+	[PIPELINE_MSG_REQ_STATS_PORT_IN] = pipeline_msg_req_stats_port_in_handler,
+	[PIPELINE_MSG_REQ_STATS_PORT_OUT] = pipeline_msg_req_stats_port_out_handler,
+	[PIPELINE_MSG_REQ_STATS_TABLE] = pipeline_msg_req_stats_table_handler,
+	[PIPELINE_MSG_REQ_PORT_IN_ENABLE] = pipeline_msg_req_port_in_enable_handler,
+	[PIPELINE_MSG_REQ_PORT_IN_DISABLE] = pipeline_msg_req_port_in_disable_handler,
+	[PIPELINE_MSG_REQ_CUSTOM] = pipeline_firewall_msg_req_custom_handler,
+};
+
+static void *
+pipeline_firewall_msg_req_add_handler(struct pipeline *p, void *msg);
+
+static void *
+pipeline_firewall_msg_req_del_handler(struct pipeline *p, void *msg);
+
+static void *
+pipeline_firewall_msg_req_add_default_handler(struct pipeline *p, void *msg);
+
+static void *
+pipeline_firewall_msg_req_del_default_handler(struct pipeline *p, void *msg);
+
+static pipeline_msg_req_handler custom_handlers[] = {
+	[PIPELINE_FIREWALL_MSG_REQ_ADD] = pipeline_firewall_msg_req_add_handler,
+	[PIPELINE_FIREWALL_MSG_REQ_DEL] = pipeline_firewall_msg_req_del_handler,
+	[PIPELINE_FIREWALL_MSG_REQ_ADD_DEFAULT] = pipeline_firewall_msg_req_add_default_handler,
+	[PIPELINE_FIREWALL_MSG_REQ_DEL_DEFAULT] = pipeline_firewall_msg_req_del_default_handler,
+};
+
+enum {
+	PROTO_FIELD_IPV4,
+	SRC_FIELD_IPV4,
+	DST_FIELD_IPV4,
+	SRCP_FIELD_IPV4,
+	DSTP_FIELD_IPV4,
+	NUM_FIELDS_IPV4
+};
+
+struct rte_acl_field_def ipv4_field_formats[NUM_FIELDS_IPV4] = {
+	{
+		.type = RTE_ACL_FIELD_TYPE_BITMASK,
+		.size = sizeof(uint8_t),
+		.field_index = PROTO_FIELD_IPV4,
+		.input_index = PROTO_FIELD_IPV4,
+		.offset = sizeof(struct ether_hdr) +
+			offsetof(struct ipv4_hdr, next_proto_id),
+	},
+	{
+		.type = RTE_ACL_FIELD_TYPE_MASK,
+		.size = sizeof(uint32_t),
+		.field_index = SRC_FIELD_IPV4,
+		.input_index = SRC_FIELD_IPV4,
+		.offset = sizeof(struct ether_hdr) +
+			offsetof(struct ipv4_hdr, src_addr),
+	},
+	{
+		.type = RTE_ACL_FIELD_TYPE_MASK,
+		.size = sizeof(uint32_t),
+		.field_index = DST_FIELD_IPV4,
+		.input_index = DST_FIELD_IPV4,
+		.offset = sizeof(struct ether_hdr) +
+			offsetof(struct ipv4_hdr, dst_addr),
+	},
+	{
+		.type = RTE_ACL_FIELD_TYPE_RANGE,
+		.size = sizeof(uint16_t),
+		.field_index = SRCP_FIELD_IPV4,
+		.input_index = SRCP_FIELD_IPV4,
+		.offset = sizeof(struct ether_hdr) + sizeof(struct ipv4_hdr),
+	},
+	{
+		.type = RTE_ACL_FIELD_TYPE_RANGE,
+		.size = sizeof(uint16_t),
+		.field_index = DSTP_FIELD_IPV4,
+		.input_index = DSTP_FIELD_IPV4,
+		.offset = sizeof(struct ether_hdr) + sizeof(struct ipv4_hdr) +
+			sizeof(uint16_t),
+	},
+};
+
+static int
+pipeline_firewall_parse_args(struct pipeline_firewall *p,
+	struct pipeline_params *params)
+{
+	uint32_t n_rules_present = 0;
+	uint32_t pkt_type_present = 0;
+	uint32_t i;
+
+	for (i = 0; i < params->n_args; i++) {
+		char *arg_name = params->args_name[i];
+		char *arg_value = params->args_value[i];
+
+		if (strcmp(arg_name, "n_rules") == 0) {
+			if (n_rules_present)
+				return -1;
+			n_rules_present = 1;
+
+			p->n_rules = atoi(arg_value);
+			continue;
+		}
+
+		if (strcmp(arg_name, "pkt_type") == 0){
+			if (pkt_type_present)
+				return -1;
+			pkt_type_present = 1;
+
+			if (strcmp(arg_value, "ipv4") != 0)
+				return -1;
+
+			continue;
+		}
+
+		return -1;
+	}
+
+	/* Check that mandatory arguments are present */
+	if (n_rules_present == 0)
+		return -1;
+
+	return 0;
+}
+
+static void *
+pipeline_firewall_init(struct pipeline_params *params,
+	__rte_unused void *arg)
+{
+	struct pipeline *p;
+	struct pipeline_firewall *p_fw;
+	uint32_t size, i;
+
+	/* Check input arguments */
+	if ((params == NULL) ||
+		(params->n_ports_in == 0) ||
+		(params->n_ports_out == 0))
+		return NULL;
+
+	/* Memory allocation */
+	size = RTE_CACHE_LINE_ROUNDUP(sizeof(struct pipeline_firewall));
+	p = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
+	p_fw = (struct pipeline_firewall *) p;
+	if (p == NULL)
+		return NULL;
+
+	strcpy(p->name, params->name);
+
+	/* Parse arguments */
+	if (pipeline_firewall_parse_args(p_fw, params))
+		return NULL;
+
+	/* Pipeline */
+	{
+		struct rte_pipeline_params pipeline_params = {
+			.name = params->name,
+			.socket_id = params->socket_id,
+			.offset_port_id = 0,
+		};
+
+		p->p = rte_pipeline_create(&pipeline_params);
+		if (p->p == NULL) {
+			rte_free(p);
+			return NULL;
+		}
+	}
+
+	/* Input ports */
+	p->n_ports_in = params->n_ports_in;
+	for (i = 0; i < p->n_ports_in; i++) {
+		struct rte_pipeline_port_in_params port_params = {
+			.ops = pipeline_port_in_params_get_ops(&params->port_in[i]),
+			.arg_create = pipeline_port_in_params_convert(&params->port_in[i]),
+			.f_action = NULL,
+			.arg_ah = NULL,
+			.burst_size = params->port_in[i].burst_size,
+		};
+
+		int status = rte_pipeline_port_in_create(p->p,
+			&port_params,
+			&p->port_in_id[i]);
+
+		if (status) {
+			rte_pipeline_free(p->p);
+			rte_free(p);
+			return NULL;
+		}
+	}
+
+	/* Output ports */
+	p->n_ports_out = params->n_ports_out;
+	for (i = 0; i < p->n_ports_out; i++) {
+		struct rte_pipeline_port_out_params port_params = {
+			.ops = pipeline_port_out_params_get_ops(&params->port_out[i]),
+			.arg_create = pipeline_port_out_params_convert(&params->port_out[i]),
+			.f_action = NULL,
+			.f_action_bulk = NULL,
+			.arg_ah = NULL,
+		};
+
+		int status = rte_pipeline_port_out_create(p->p,
+			&port_params,
+			&p->port_out_id[i]);
+
+		if (status) {
+			rte_pipeline_free(p->p);
+			rte_free(p);
+			return NULL;
+		}
+	}
+
+	/* Tables */
+	p->n_tables = 1;
+	{
+		struct rte_table_acl_params table_acl_params = {
+			.name = "FIREWALL",
+			.n_rules = p_fw->n_rules,
+			.n_rule_fields = DIM(ipv4_field_formats),
+		};
+
+		struct rte_pipeline_table_params table_params = {
+				.ops = &rte_table_acl_ops,
+				.arg_create = &table_acl_params,
+				.f_action_hit = NULL,
+				.f_action_miss = NULL,
+				.arg_ah = NULL,
+				.action_data_size = 0,
+			};
+
+		int status;
+
+		memcpy(table_acl_params.field_format,
+			ipv4_field_formats,
+			sizeof(ipv4_field_formats));
+
+
+		status = rte_pipeline_table_create(p->p,
+			&table_params,
+			&p->table_id[0]);
+
+		if (status) {
+			rte_pipeline_free(p->p);
+			rte_free(p);
+			return NULL;
+		}
+	}
+
+	/* Connecting input ports to tables */
+	for (i = 0; i < p->n_ports_in; i++) {
+		int status = rte_pipeline_port_in_connect_to_table(p->p,
+			p->port_in_id[i],
+			p->table_id[0]);
+
+		if (status) {
+			rte_pipeline_free(p->p);
+			rte_free(p);
+			return NULL;
+		}
+	}
+
+	/* Enable input ports */
+	for (i = 0; i < p->n_ports_in; i++) {
+		int status = rte_pipeline_port_in_enable(p->p,
+			p->port_in_id[i]);
+
+		if (status) {
+			rte_pipeline_free(p->p);
+			rte_free(p);
+			return NULL;
+		}
+	}
+
+	/* Check pipeline consistency */
+	if (rte_pipeline_check(p->p) < 0) {
+		rte_pipeline_free(p->p);
+		rte_free(p);
+		return NULL;
+	}
+
+	/* Message queues */
+	p->n_msgq = params->n_msgq;
+	for (i = 0; i < p->n_msgq; i++)
+		p->msgq_in[i] = params->msgq_in[i];
+	for (i = 0; i < p->n_msgq; i++)
+		p->msgq_out[i] = params->msgq_out[i];
+
+	/* Message handlers */
+	memcpy(p->handlers, handlers, sizeof(p->handlers));
+	memcpy(p_fw->custom_handlers,
+		custom_handlers,
+		sizeof(p_fw->custom_handlers));
+
+	return p;
+}
+
+static int
+pipeline_firewall_free(void *pipeline)
+{
+	struct pipeline *p = (struct pipeline *) pipeline;
+
+	/* Check input arguments */
+	if (p == NULL)
+		return -1;
+
+	/* Free resources */
+	rte_pipeline_free(p->p);
+	rte_free(p);
+	return 0;
+}
+
+static int
+pipeline_firewall_track(void *pipeline,
+	__rte_unused uint32_t port_in,
+	uint32_t *port_out)
+{
+	struct pipeline *p = (struct pipeline *) pipeline;
+
+	/* Check input arguments */
+	if ((p == NULL) ||
+		(port_in >= p->n_ports_in) ||
+		(port_out == NULL))
+		return -1;
+
+	if (p->n_ports_in == 1) {
+		*port_out = 0;
+		return 0;
+	}
+
+	return -1;
+}
+
+static int
+pipeline_firewall_timer(void *pipeline)
+{
+	struct pipeline *p = (struct pipeline *) pipeline;
+
+	pipeline_msg_req_handle(p);
+	rte_pipeline_flush(p->p);
+
+	return 0;
+}
+
+void *
+pipeline_firewall_msg_req_custom_handler(struct pipeline *p,
+	void *msg)
+{
+	struct pipeline_firewall *p_fw = (struct pipeline_firewall *) p;
+	struct pipeline_custom_msg_req *req = msg;
+	pipeline_msg_req_handler f_handle;
+
+	f_handle = (req->subtype < PIPELINE_FIREWALL_MSG_REQS)?
+		p_fw->custom_handlers[req->subtype] :
+		pipeline_msg_req_invalid_handler;
+
+	if (f_handle == NULL)
+		f_handle = pipeline_msg_req_invalid_handler;
+
+	return f_handle(p, req);
+}
+
+void *
+pipeline_firewall_msg_req_add_handler(struct pipeline *p, void *msg)
+{
+	struct pipeline_firewall_add_msg_req *req = msg;
+	struct pipeline_firewall_add_msg_rsp *rsp = msg;
+
+	struct rte_table_acl_rule_add_params params;
+	struct rte_pipeline_table_entry entry = {
+			.action = RTE_PIPELINE_ACTION_PORT,
+			{.port_id = p->port_out_id[req->port_id]},
+		};
+
+	switch(req->key.type) {
+	case PIPELINE_FIREWALL_IPV4_5TUPLE:
+		params.priority = req->priority;
+		memset(&params.field_value[0], 0, sizeof(params.field_value[0]) * 5);
+		params.field_value[0].value.u8 = req->key.key.ipv4_5tuple.proto;
+		params.field_value[0].mask_range.u8 = req->key.key.ipv4_5tuple.proto_mask;
+		params.field_value[1].value.u32 = req->key.key.ipv4_5tuple.src_ip;
+		params.field_value[1].mask_range.u32 = req->key.key.ipv4_5tuple.src_ip_mask;
+		params.field_value[2].value.u32 = req->key.key.ipv4_5tuple.dst_ip;
+		params.field_value[2].mask_range.u32 = req->key.key.ipv4_5tuple.dst_ip_mask;
+		params.field_value[3].value.u16 = req->key.key.ipv4_5tuple.src_port_from;
+		params.field_value[3].mask_range.u16 = req->key.key.ipv4_5tuple.src_port_to;
+		params.field_value[4].value.u16 = req->key.key.ipv4_5tuple.dst_port_from;
+		params.field_value[4].mask_range.u16 = req->key.key.ipv4_5tuple.dst_port_to;
+		break;
+
+	default:
+		rsp->status = -1; /* Error */
+		return rsp;
+	}
+
+	rsp->status = rte_pipeline_table_entry_add(p->p,
+		p->table_id[0],
+		&params,
+		&entry,
+		&rsp->key_found,
+		(struct rte_pipeline_table_entry **) &rsp->entry_ptr);
+
+	RTE_LOG(INFO, USER1, "%s Back-End: Key %s\n",
+		p->name,
+		(rsp->key_found)? "found" : "not found");
+
+	return rsp;
+}
+
+void *
+pipeline_firewall_msg_req_del_handler(struct pipeline *p, void *msg)
+{
+	struct pipeline_firewall_del_msg_req *req = msg;
+	struct pipeline_firewall_del_msg_rsp *rsp = msg;
+
+	struct rte_table_acl_rule_delete_params params;
+
+	switch(req->key.type) {
+	case PIPELINE_FIREWALL_IPV4_5TUPLE:
+		memset(&params.field_value[0], 0, sizeof(params.field_value[0]) * 5);
+		params.field_value[0].value.u8 = req->key.key.ipv4_5tuple.proto;
+		params.field_value[0].mask_range.u8 = req->key.key.ipv4_5tuple.proto_mask;
+		params.field_value[1].value.u32 = req->key.key.ipv4_5tuple.src_ip;
+		params.field_value[1].mask_range.u32 = req->key.key.ipv4_5tuple.src_ip_mask;
+		params.field_value[2].value.u32 = req->key.key.ipv4_5tuple.dst_ip;
+		params.field_value[2].mask_range.u32 = req->key.key.ipv4_5tuple.dst_ip_mask;
+		params.field_value[3].value.u16 = req->key.key.ipv4_5tuple.src_port_from;
+		params.field_value[3].mask_range.u16 = req->key.key.ipv4_5tuple.src_port_to;
+		params.field_value[4].value.u16 = req->key.key.ipv4_5tuple.dst_port_from;
+		params.field_value[4].mask_range.u16 = req->key.key.ipv4_5tuple.dst_port_to;
+		break;
+
+	default:
+		rsp->status = -1; /* Error */
+		return rsp;
+	}
+
+	rsp->status = rte_pipeline_table_entry_delete(p->p,
+		p->table_id[0],
+		&params,
+		&rsp->key_found,
+		NULL);
+
+	RTE_LOG(INFO, USER1, "%s Back-End: Key %s\n",
+		p->name,
+		(rsp->key_found)? "found" : "not found");
+
+	return rsp;
+}
+
+void *
+pipeline_firewall_msg_req_add_default_handler(struct pipeline *p, void *msg)
+{
+	struct pipeline_firewall_add_default_msg_req *req = msg;
+	struct pipeline_firewall_add_default_msg_rsp *rsp = msg;
+
+	struct rte_pipeline_table_entry default_entry = {
+		.action = RTE_PIPELINE_ACTION_PORT,
+		{.port_id = p->port_out_id[req->port_id]},
+	};
+
+	rsp->status = rte_pipeline_table_default_entry_add(p->p,
+		p->table_id[0],
+		&default_entry,
+		(struct rte_pipeline_table_entry **) &rsp->entry_ptr);
+
+	return rsp;
+}
+
+void *
+pipeline_firewall_msg_req_del_default_handler(struct pipeline *p, void *msg)
+{
+	struct pipeline_firewall_del_default_msg_rsp *rsp = msg;
+
+	rsp->status = rte_pipeline_table_default_entry_delete(p->p,
+		p->table_id[0],
+		NULL);
+
+	return rsp;
+}
+
+struct pipeline_ops pipeline_firewall_ops = {
+		.f_init = pipeline_firewall_init,
+		.f_free = pipeline_firewall_free,
+		.f_run = NULL,
+		.f_timer = pipeline_firewall_timer,
+		.f_track = pipeline_firewall_track,
+};
diff --git a/examples/ip_pipeline/pipeline/pipeline_firewall_ops.h b/examples/ip_pipeline/pipeline/pipeline_firewall_ops.h
new file mode 100644
index 0000000..9882b9f
--- /dev/null
+++ b/examples/ip_pipeline/pipeline/pipeline_firewall_ops.h
@@ -0,0 +1,139 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __INCLUDE_PIPELINE_FIREWALL_OPS_H__
+#define __INCLUDE_PIPELINE_FIREWALL_OPS_H__
+
+#include "pipeline_ops.h"
+#include "pipeline_common.h"
+
+enum pipeline_firewall_key_type {
+	PIPELINE_FIREWALL_IPV4_5TUPLE,
+};
+
+struct pipeline_firewall_key_ipv4_5tuple {
+	uint32_t src_ip;
+	uint32_t src_ip_mask;
+	uint32_t dst_ip;
+	uint32_t dst_ip_mask;
+	uint16_t src_port_from;
+	uint16_t src_port_to;
+	uint16_t dst_port_from;
+	uint16_t dst_port_to;
+	uint8_t proto;
+	uint8_t proto_mask;
+};
+
+struct pipeline_firewall_key {
+	enum pipeline_firewall_key_type type;
+	union {
+		struct pipeline_firewall_key_ipv4_5tuple ipv4_5tuple;
+	} key;
+};
+
+enum pipeline_firewall_msg_req_type {
+	PIPELINE_FIREWALL_MSG_REQ_ADD = 0,
+	PIPELINE_FIREWALL_MSG_REQ_DEL,
+	PIPELINE_FIREWALL_MSG_REQ_ADD_DEFAULT,
+	PIPELINE_FIREWALL_MSG_REQ_DEL_DEFAULT,
+	PIPELINE_FIREWALL_MSG_REQS
+};
+
+/*
+ * MSG ADD
+ */
+struct pipeline_firewall_add_msg_req {
+	enum pipeline_msg_req_type type;
+	enum pipeline_firewall_msg_req_type subtype;
+
+	/* key */
+	struct pipeline_firewall_key key;
+
+	/* data */
+	int32_t priority;
+	uint32_t port_id;
+};
+
+struct pipeline_firewall_add_msg_rsp {
+	int status;
+	int key_found;
+	void *entry_ptr;
+};
+
+/*
+ * MSG DEL
+ */
+struct pipeline_firewall_del_msg_req {
+	enum pipeline_msg_req_type type;
+	enum pipeline_firewall_msg_req_type subtype;
+
+	/* key */
+	struct pipeline_firewall_key key;
+};
+
+struct pipeline_firewall_del_msg_rsp {
+	int status;
+	int key_found;
+};
+
+/*
+ * MSG ADD DEFAULT
+ */
+struct pipeline_firewall_add_default_msg_req {
+	enum pipeline_msg_req_type type;
+	enum pipeline_firewall_msg_req_type subtype;
+
+	/* data */
+	uint32_t port_id;
+};
+
+struct pipeline_firewall_add_default_msg_rsp {
+	int status;
+	void *entry_ptr;
+};
+
+/*
+ * MSG DEL DEFAULT
+ */
+struct pipeline_firewall_del_default_msg_req {
+	enum pipeline_msg_req_type type;
+	enum pipeline_firewall_msg_req_type subtype;
+};
+
+struct pipeline_firewall_del_default_msg_rsp {
+	int status;
+};
+
+extern struct pipeline_ops pipeline_firewall_ops;
+
+#endif
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 10/11] ip_pipeline: added new implementation of routing pipeline
  2015-05-29 15:43 [PATCH 00/11] ip_pipeline: ip_pipeline application enhancements Maciej Gajdzica
                   ` (8 preceding siblings ...)
  2015-05-29 15:43 ` [PATCH 09/11] ip_pipeline: added new implementation of firewall pipeline Maciej Gajdzica
@ 2015-05-29 15:43 ` Maciej Gajdzica
  2015-05-29 15:43 ` [PATCH 11/11] ip_pipeline: added new implementation of flow classification pipeline Maciej Gajdzica
  2015-06-23 13:48 ` [PATCH 00/11] ip_pipeline: ip_pipeline application enhancements Thomas Monjalon
  11 siblings, 0 replies; 16+ messages in thread
From: Maciej Gajdzica @ 2015-05-29 15:43 UTC (permalink / raw)
  To: dev

Routing pipeline implementation is split to two files.
pipeline_routing.c file handles front-end functions (cli commands
parsing) pipeline_routing_ops.c contains implementation of functions
done by pipeline (back-end).

Signed-off-by: Pawel Wodkowski <pawelx.wodkowski@intel.com>
---
 examples/ip_pipeline/Makefile                      |    3 +-
 examples/ip_pipeline/init.c                        |    2 +
 examples/ip_pipeline/pipeline/pipeline_routing.c   | 1660 +++++++++++++++-----
 examples/ip_pipeline/pipeline/pipeline_routing.h   |   99 ++
 .../ip_pipeline/pipeline/pipeline_routing_ops.c    |  978 ++++++++++++
 .../ip_pipeline/pipeline/pipeline_routing_ops.h    |  231 +++
 6 files changed, 2618 insertions(+), 355 deletions(-)
 create mode 100644 examples/ip_pipeline/pipeline/pipeline_routing.h
 create mode 100644 examples/ip_pipeline/pipeline/pipeline_routing_ops.c
 create mode 100644 examples/ip_pipeline/pipeline/pipeline_routing_ops.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index 0f8b1cc..f8c7c5f 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -63,8 +63,9 @@ SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_passthrough_ops.c
 SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_passthrough.c
 SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_firewall_ops.c
 SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_firewall.c
+SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_routing_ops.c
+SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_routing.c
 #SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_flow_classification.c
-#SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_routing.c
 
 CFLAGS += -I$(SRCDIR) -I$(SRCDIR)/pipeline
 CFLAGS += -O3
diff --git a/examples/ip_pipeline/init.c b/examples/ip_pipeline/init.c
index 29d87ae..29caae8 100644
--- a/examples/ip_pipeline/init.c
+++ b/examples/ip_pipeline/init.c
@@ -46,6 +46,7 @@
 #include "pipeline_master.h"
 #include "pipeline_passthrough.h"
 #include "pipeline_firewall.h"
+#include "pipeline_routing.h"
 
 #define APP_NAME_SIZE	32
 
@@ -1148,6 +1149,7 @@ int app_init(struct app_params *app)
 	app_pipeline_type_register(app, &pipeline_master);
 	app_pipeline_type_register(app, &pipeline_passthrough);
 	app_pipeline_type_register(app, &pipeline_firewall);
+	app_pipeline_type_register(app, &pipeline_routing);
 
 	app_init_pipelines(app);
 	app_init_threads(app);
diff --git a/examples/ip_pipeline/pipeline/pipeline_routing.c b/examples/ip_pipeline/pipeline/pipeline_routing.c
index b1ce624..d7dd495 100644
--- a/examples/ip_pipeline/pipeline/pipeline_routing.c
+++ b/examples/ip_pipeline/pipeline/pipeline_routing.c
@@ -1,7 +1,7 @@
 /*-
  *   BSD LICENSE
  *
- *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
  *   All rights reserved.
  *
  *   Redistribution and use in source and binary forms, with or without
@@ -31,444 +31,1396 @@
  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
+#include <cmdline_parse.h>
+#include <cmdline_parse_num.h>
+#include <cmdline_parse_string.h>
+#include <cmdline_parse_ipaddr.h>
+#include <cmdline_parse_etheraddr.h>
 
-#include <rte_malloc.h>
-#include <rte_log.h>
-#include <rte_ethdev.h>
-#include <rte_ether.h>
-#include <rte_ip.h>
-#include <rte_byteorder.h>
+#include "app.h"
+#include "pipeline_routing_ops.h"
+#include "pipeline_routing.h"
 
-#include <rte_port_ring.h>
-#include <rte_table_lpm.h>
-#include <rte_table_hash.h>
-#include <rte_pipeline.h>
+#include "pipeline_common.h"
 
-#include "main.h"
+#define MSG_TIMEOUT 1000
 
-#include <unistd.h>
+struct app_pipeline_routing_arp_entry {
+	struct pipeline_routing_arp_key key;
+	struct ether_addr nh_arp;
+	void *entry_ptr;
 
-struct app_routing_table_entry {
-	struct rte_pipeline_table_entry head;
-	uint32_t nh_ip;
-	uint32_t nh_iface;
+	TAILQ_ENTRY(app_pipeline_routing_arp_entry) node;
 };
 
-struct app_arp_table_entry {
-	struct rte_pipeline_table_entry head;
-	struct ether_addr nh_arp;
+struct app_pipeline_routing_entry {
+	struct pipeline_routing_route_key key;
+	struct app_pipeline_routing_route_params params;
+	void *entry_ptr;
+
+	TAILQ_ENTRY(app_pipeline_routing_entry) node;
+};
+
+struct pipeline_routing {
+	/* parameters */
+	uint32_t n_ports_in;
+	uint32_t n_ports_out;
+
+	/* ARP entries */
+	TAILQ_HEAD(, app_pipeline_routing_arp_entry) arp_entries;
+	uint32_t n_arp_entries;
+
+	uint32_t default_arp_entry_present;
+	uint32_t default_arp_entry_port_id;
+	void *default_arp_entry_ptr;
+
+	/* Routing routes */
+	TAILQ_HEAD(, app_pipeline_routing_entry) routes;
+	uint32_t n_routes;
+
+	uint32_t default_route_present;
+	uint32_t default_route_port_id;
+	void *default_route_entry_ptr;
 };
 
-static inline void
-app_routing_table_write_metadata(
-	struct rte_mbuf *pkt,
-	struct app_routing_table_entry *entry)
+static void *
+pipeline_routing_init(struct pipeline_params *params,
+	__rte_unused void *arg)
 {
-	struct app_pkt_metadata *c =
-		(struct app_pkt_metadata *) RTE_MBUF_METADATA_UINT8_PTR(pkt, 0);
+	struct pipeline_routing *p;
+	uint32_t size;
+
+	/* Check input arguments */
+	if ((params == NULL) ||
+		(params->n_ports_in == 0) ||
+		(params->n_ports_out == 0))
+		return NULL;
+
+	/* Memory allocation */
+	size = RTE_CACHE_LINE_ROUNDUP(sizeof(struct pipeline_routing));
+	p = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
+	if (p == NULL)
+		return NULL;
+
+	/* Initialization */
+	p->n_ports_in = params->n_ports_in;
+	p->n_ports_out = params->n_ports_out;
+
+	TAILQ_INIT(&p->arp_entries);
+	p->n_arp_entries = 0;
 
-	c->arp_key.nh_ip = entry->nh_ip;
-	c->arp_key.nh_iface = entry->nh_iface;
+	TAILQ_INIT(&p->routes);
+	p->n_routes = 0;
+
+	return p;
 }
 
 static int
-app_routing_table_ah(
-	struct rte_mbuf **pkts,
-	uint64_t *pkts_mask,
-	struct rte_pipeline_table_entry **entries,
-	__attribute__((unused)) void *arg)
+app_pipeline_routing_free(void *pipeline)
 {
-	uint64_t pkts_in_mask = *pkts_mask;
+	struct pipeline_routing *p = pipeline;
+	struct app_pipeline_routing_arp_entry *arp_entry;
 
-	if ((pkts_in_mask & (pkts_in_mask + 1)) == 0) {
-		uint64_t n_pkts = __builtin_popcountll(pkts_in_mask);
-		uint32_t i;
+	/* Check input arguments */
+	if (p == NULL)
+		return -1;
+
+	/* Free resources */
+	while (!TAILQ_EMPTY(&p->arp_entries)) {
+		arp_entry = TAILQ_FIRST(&p->arp_entries);
+		TAILQ_REMOVE(&p->arp_entries, arp_entry, node);
+		rte_free(arp_entry);
+	}
+
+	rte_free(p);
+	return 0;
+}
 
-		for (i = 0; i < n_pkts; i++) {
-			struct rte_mbuf *m = pkts[i];
-			struct app_routing_table_entry *a =
-				(struct app_routing_table_entry *) entries[i];
+static struct app_pipeline_routing_arp_entry *
+app_pipeline_routing_find_arp_entry(struct pipeline_routing *p,
+		const struct pipeline_routing_arp_key *key)
+{
+	struct app_pipeline_routing_arp_entry *it, *found;
 
-			app_routing_table_write_metadata(m, a);
+	found = NULL;
+	TAILQ_FOREACH(it, &p->arp_entries, node) {
+		if (memcmp(key, &it->key, sizeof(it->key)) == 0) {
+			found = it;
+			break;
 		}
-	} else
-		for ( ; pkts_in_mask; ) {
-			struct rte_mbuf *m;
-			struct app_routing_table_entry *a;
-			uint64_t pkt_mask;
-			uint32_t packet_index;
-
-			packet_index = __builtin_ctzll(pkts_in_mask);
-			pkt_mask = 1LLU << packet_index;
-			pkts_in_mask &= ~pkt_mask;
-
-			m = pkts[packet_index];
-			a = (struct app_routing_table_entry *)
-				entries[packet_index];
-			app_routing_table_write_metadata(m, a);
+	}
+
+	return found;
+}
+
+static struct app_pipeline_routing_entry *
+app_pipeline_routing_find_route(struct pipeline_routing *p,
+		const struct pipeline_routing_route_key *key)
+{
+	struct app_pipeline_routing_entry *it, *found;
+
+	found = NULL;
+	TAILQ_FOREACH(it, &p->routes, node) {
+		if (memcmp(key, &it->key, sizeof(it->key)) == 0) {
+			found = it;
+			break;
 		}
+	}
 
-	return 0;
+	return found;
 }
 
-static inline void
-app_arp_table_write_metadata(
-	struct rte_mbuf *pkt,
-	struct app_arp_table_entry *entry)
+static void
+print_route(const struct app_pipeline_routing_entry *route)
+{
+	APP_CHECK(route->key.type == PIPELINE_ROUTING_ROUTE_IPV4, "Only IPv6");
+	if (route->key.type == PIPELINE_ROUTING_ROUTE_IPV4) {
+		const struct pipeline_routing_route_key_ipv4 *key =
+				&route->key.key.ipv4;
+
+		printf("IP Prefix = %u.%u.%u.%u/%u => "
+			"(Port = %u, Next Hop = %u.%u.%u.%u)\n",
+			(key->ip >> 24) & 0xFF,
+			(key->ip >> 16) & 0xFF,
+			(key->ip >> 8) & 0xFF,
+			key->ip & 0xFF,
+
+			key->depth,
+			route->params.port_id,
+
+			(route->params.ip >> 24) & 0xFF,
+			(route->params.ip >> 16) & 0xFF,
+			(route->params.ip >> 8) & 0xFF,
+			route->params.ip & 0xFF);
+	}
+
+}
+
+static void
+print_arp_entry(const struct app_pipeline_routing_arp_entry *entry)
 {
-	struct app_pkt_metadata *c =
-		(struct app_pkt_metadata *) RTE_MBUF_METADATA_UINT8_PTR(pkt, 0);
-	ether_addr_copy(&entry->nh_arp, &c->nh_arp);
+	printf("(Port = %u, IP = %u.%u.%u.%u) => "
+		"HWaddress = %02x:%02x:%02x:%02x:%02x:%02x\n",
+		entry->key.key.ipv4.port_id,
+		(entry->key.key.ipv4.ip >> 24) & 0xFF,
+		(entry->key.key.ipv4.ip >> 16) & 0xFF,
+		(entry->key.key.ipv4.ip >> 8) & 0xFF,
+		entry->key.key.ipv4.ip & 0xFF,
+
+		entry->nh_arp.addr_bytes[0],
+		entry->nh_arp.addr_bytes[1],
+		entry->nh_arp.addr_bytes[2],
+		entry->nh_arp.addr_bytes[3],
+		entry->nh_arp.addr_bytes[4],
+		entry->nh_arp.addr_bytes[5]);
 }
 
 static int
-app_arp_table_ah(
-	struct rte_mbuf **pkts,
-	uint64_t *pkts_mask,
-	struct rte_pipeline_table_entry **entries,
-	__attribute__((unused)) void *arg)
+app_pipeline_routing_arp_ls(struct app_params *app, uint32_t pipeline_id)
 {
-	uint64_t pkts_in_mask = *pkts_mask;
+	struct pipeline_routing *p;
+	struct app_pipeline_routing_arp_entry *it;
 
-	if ((pkts_in_mask & (pkts_in_mask + 1)) == 0) {
-		uint64_t n_pkts = __builtin_popcountll(pkts_in_mask);
-		uint32_t i;
+	p = app_pipeline_data_fe(app, pipeline_id);
+	if (p == NULL)
+		return -EINVAL;
 
-		for (i = 0; i < n_pkts; i++) {
-			struct rte_mbuf *m = pkts[i];
-			struct app_arp_table_entry *a =
-				(struct app_arp_table_entry *) entries[i];
+	TAILQ_FOREACH(it, &p->arp_entries, node)
+		print_arp_entry(it);
 
-			app_arp_table_write_metadata(m, a);
-		}
-	} else {
-		for ( ; pkts_in_mask; ) {
-			struct rte_mbuf *m;
-			struct app_arp_table_entry *a;
-			uint64_t pkt_mask;
-			uint32_t packet_index;
-
-			packet_index = __builtin_ctzll(pkts_in_mask);
-			pkt_mask = 1LLU << packet_index;
-			pkts_in_mask &= ~pkt_mask;
-
-			m = pkts[packet_index];
-			a = (struct app_arp_table_entry *)
-				entries[packet_index];
-			app_arp_table_write_metadata(m, a);
-		}
+	if (p->default_arp_entry_present)
+		printf("Default entry: port %u (entry ptr = %p)\n",
+				p->default_arp_entry_port_id,
+				p->default_arp_entry_ptr);
+	else
+		printf("Default: DROP\n"); /* FIXME: msg OK ? */
+
+	return 0;
+}
+
+int
+app_pipeline_routing_add_arp_entry(struct app_params *app, uint32_t pipeline_id,
+		struct pipeline_routing_arp_key *key,
+		struct ether_addr *macaddr)
+{
+	struct pipeline_routing *p;
+
+	struct pipeline_routing_arp_add_msg_req *req;
+	struct pipeline_routing_arp_add_msg_rsp *rsp;
+
+	struct app_pipeline_routing_arp_entry *entry;
+
+	int new_entry;
+
+	p = app_pipeline_data_fe(app, pipeline_id);
+	if (p == NULL)
+		return -EINVAL;
+
+	/* Find existing entry or allocate new */
+	entry = app_pipeline_routing_find_arp_entry(p, key);
+	new_entry = (entry == NULL);
+	if (entry == NULL) {
+		entry = rte_malloc(NULL, sizeof(*entry), RTE_CACHE_LINE_SIZE);
+
+		if (entry == NULL)
+			return -1;
+	}
+
+	/* Message buffer allocation */
+	req = app_msg_alloc(app);
+	if (req == NULL) {
+		if (new_entry)
+			rte_free(entry);
+		return -1;
 	}
 
+	req->type = PIPELINE_MSG_REQ_CUSTOM;
+	req->subtype = PIPELINE_ROUTING_MSG_REQ_ARP_ADD;
+	memcpy(&req->key, key, sizeof(*key));
+	ether_addr_copy(macaddr, &req->macaddr);
+
+	/* Send request and wait for response */
+	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT);
+	if (rsp == NULL) {
+		if (new_entry)
+			rte_free(entry);
+		return -1;
+	}
+
+	/* Read response and write entry */
+	if (rsp->status || rsp->entry_ptr == NULL) {
+		app_msg_free(app, rsp);
+		if (new_entry)
+			rte_free(entry);
+		return -1;
+	}
+
+	memcpy(&entry->key, key, sizeof(*key));
+	ether_addr_copy(macaddr, &entry->nh_arp);
+	entry->entry_ptr = rsp->entry_ptr;
+
+	/* Commit entry */
+	if (new_entry) {
+		TAILQ_INSERT_TAIL(&p->arp_entries, entry, node);
+		p->n_arp_entries++;
+	}
+
+	print_arp_entry(entry);
+
+	/* Message buffer free */
+	app_msg_free(app, rsp);
 	return 0;
 }
 
-static uint64_t app_arp_table_hash(
-	void *key,
-	__attribute__((unused)) uint32_t key_size,
-	__attribute__((unused)) uint64_t seed)
+int
+app_pipeline_routing_delete_arp_entry(struct app_params *app,
+	uint32_t pipeline_id,
+	struct pipeline_routing_arp_key *key)
 {
-	uint32_t *k = (uint32_t *) key;
+	struct pipeline_routing *p;
+
+	struct pipeline_routing_arp_delete_msg_req *req;
+	struct pipeline_routing_arp_delete_msg_rsp *rsp;
+
+	struct app_pipeline_routing_arp_entry *entry;
+
+	p = app_pipeline_data_fe(app, pipeline_id);
+	if (p == NULL)
+		return -EINVAL;
+
+	/* Find rule */
+	entry = app_pipeline_routing_find_arp_entry(p, key);
+	if (entry == NULL)
+		return 0;
+
+	/* Allocate and write request */
+	req = app_msg_alloc(app);
+	if (req == NULL)
+		return -1;
+
+	req->type = PIPELINE_MSG_REQ_CUSTOM;
+	req->subtype = PIPELINE_ROUTING_MSG_REQ_ARP_DEL;
+	memcpy(&req->key, key, sizeof(*key));
+
+
+	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT);
+	if (rsp == NULL)
+		return -1;
+
+	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT);
+	if (rsp == NULL)
+		return -1;
 
-	return k[1];
+	/* Read response */
+	if (rsp->status) {
+		app_msg_free(app, rsp);
+		return -1;
+	}
+
+	/* Remove entry */
+	TAILQ_REMOVE(&p->arp_entries, entry, node);
+	p->n_arp_entries--;
+	rte_free(entry);
+
+	/* Free response */
+	app_msg_free(app, rsp);
+
+	return 0;
 }
 
-struct app_core_routing_message_handle_params {
-	struct rte_ring *ring_req;
-	struct rte_ring *ring_resp;
-	struct rte_pipeline *p;
-	uint32_t *port_out_id;
-	uint32_t routing_table_id;
-	uint32_t arp_table_id;
-};
+int
+app_pipeline_routing_add_default_arp_entry(struct app_params *app,
+		uint32_t pipeline_id,
+		uint32_t port_id)
+{
+	struct pipeline_routing *p;
 
-static void
-app_message_handle(struct app_core_routing_message_handle_params *params);
+	struct pipeline_routing_arp_add_default_msg_req *req;
+	struct pipeline_routing_arp_add_default_msg_rsp *rsp;
+
+	p = app_pipeline_data_fe(app, pipeline_id);
+	if (p == NULL)
+		return -EINVAL;
+
+	/* Allocate and write request */
+	req = app_msg_alloc(app);
+	if (req == NULL)
+		return -1;
+
+	req->type = PIPELINE_MSG_REQ_CUSTOM;
+	req->subtype = PIPELINE_ROUTING_MSG_REQ_ARP_ADD_DEFAULT;
+	req->port_id = port_id;
+
+	/* Send request and wait for response */
+	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response and write entry */
+	if (rsp->status || rsp->entry_ptr == NULL) {
+		app_msg_free(app, rsp);
+		return -1;
+	}
+
+	p->default_arp_entry_port_id = port_id;
+	p->default_arp_entry_ptr = rsp->entry_ptr;
+
+	/* Commit entry */
+	p->default_arp_entry_present = 1;
+
+	/* Free response */
+	app_msg_free(app, rsp);
+
+	return 0;
+}
+
+int
+app_pipeline_routing_delete_default_arp_entry(struct app_params *app,
+	uint32_t pipeline_id)
+{
+	struct pipeline_routing *p;
+
+	struct pipeline_routing_arp_delete_default_msg_req *req;
+	struct pipeline_routing_arp_delete_default_msg_rsp *rsp;
+
+	p = app_pipeline_data_fe(app, pipeline_id);
+	if (p == NULL)
+		return -EINVAL;
+
+	/* Allocate and write request */
+	req = app_msg_alloc(app);
+	if (req == NULL)
+		return -ENOMEM;
+
+	req->type = PIPELINE_MSG_REQ_CUSTOM;
+	req->subtype = PIPELINE_ROUTING_MSG_REQ_ARP_DEL_DEFAULT;
+
+	/* Send request and wait for response */
+	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT);
+	if (rsp == NULL)
+		return -ETIMEDOUT;
+
+	/* Read response and write entry */
+	if (rsp->status) {
+		app_msg_free(app, rsp);
+		return -rsp->status;
+	}
+
+	/* Commit entry */
+	p->default_arp_entry_present = 0;
+
+	/* Free response */
+	app_msg_free(app, rsp);
+
+	return 0;
+}
+
+static int
+app_pipeline_routing_ls(struct app_params *app, uint32_t pipeline_id)
+{
+	struct pipeline_routing *p;
+	struct app_pipeline_routing_entry *it;
 
-void
-app_main_loop_pipeline_routing(void) {
-	struct rte_pipeline_params pipeline_params = {
-		.name = "pipeline",
-		.socket_id = rte_socket_id(),
-	};
+	p = app_pipeline_data_fe(app, pipeline_id);
+	if (p == NULL)
+		return -EINVAL;
 
-	struct rte_pipeline *p;
-	uint32_t port_in_id[APP_MAX_PORTS];
-	uint32_t port_out_id[APP_MAX_PORTS];
-	uint32_t routing_table_id, arp_table_id;
-	uint32_t i;
+	TAILQ_FOREACH(it, &p->routes, node)
+		print_route(it);
 
-	uint32_t core_id = rte_lcore_id();
-	struct app_core_params *core_params = app_get_core_params(core_id);
-	struct app_core_routing_message_handle_params mh_params;
+	if (p->default_route_present)
+		printf("Default route: port %u (entry ptr = %p)\n",
+				p->default_route_port_id,
+				p->default_route_entry_ptr);
+	else
+		printf("Default: DROP\n"); /* FIXME: msg OK ? */
 
-	if ((core_params == NULL) || (core_params->core_type != APP_CORE_RT))
-		rte_panic("Core %u misconfiguration\n", core_id);
+	return 0;
+}
+
+int
+app_pipeline_routing_add_route(struct app_params *app,
+	uint32_t pipeline_id,
+	struct pipeline_routing_route_key *key,
+	struct app_pipeline_routing_route_params *route_params)
+{
+	struct pipeline_routing *p;
 
-	RTE_LOG(INFO, USER1, "Core %u is doing routing\n", core_id);
+	struct pipeline_routing_route_add_msg_req *req;
+	struct pipeline_routing_route_add_msg_rsp *rsp;
 
-	/* Pipeline configuration */
-	p = rte_pipeline_create(&pipeline_params);
+	struct app_pipeline_routing_entry *entry;
+
+	int new_entry;
+
+	p = app_pipeline_data_fe(app, pipeline_id);
+	/* Check input arguments */
 	if (p == NULL)
-		rte_panic("Unable to configure the pipeline\n");
-
-	/* Input port configuration */
-	for (i = 0; i < app.n_ports; i++) {
-		struct rte_port_ring_reader_params port_ring_params = {
-			.ring = app.rings[core_params->swq_in[i]],
-		};
-
-		struct rte_pipeline_port_in_params port_params = {
-			.ops = &rte_port_ring_reader_ops,
-			.arg_create = (void *) &port_ring_params,
-			.f_action = NULL,
-			.arg_ah = NULL,
-			.burst_size = app.bsz_swq_rd,
-		};
-
-		if (rte_pipeline_port_in_create(p, &port_params,
-			&port_in_id[i]))
-			rte_panic("Unable to configure input port for "
-				"ring %d\n", i);
+		return -EINVAL;
+
+	/* Find existing rule or allocate new rule */
+	entry = app_pipeline_routing_find_route(p, key);
+	new_entry = (entry == NULL);
+	if (entry == NULL) {
+		entry = rte_malloc(NULL, sizeof(*entry), RTE_CACHE_LINE_SIZE);
+
+		if (entry == NULL)
+			return -1;
 	}
 
-	/* Output port configuration */
-	for (i = 0; i < app.n_ports; i++) {
-		struct rte_port_ring_writer_params port_ring_params = {
-			.ring = app.rings[core_params->swq_out[i]],
-			.tx_burst_sz = app.bsz_swq_wr,
-		};
-
-		struct rte_pipeline_port_out_params port_params = {
-			.ops = &rte_port_ring_writer_ops,
-			.arg_create = (void *) &port_ring_params,
-			.f_action = NULL,
-			.f_action_bulk = NULL,
-			.arg_ah = NULL,
-		};
-
-		if (rte_pipeline_port_out_create(p, &port_params,
-			&port_out_id[i]))
-			rte_panic("Unable to configure output port for "
-				"ring %d\n", i);
+	/* Allocate and write request */
+	req = app_msg_alloc(app);
+	if (req == NULL) {
+		if (new_entry)
+			rte_free(entry);
+		return -1;
 	}
 
-	/* Routing table configuration */
-	{
-		struct rte_table_lpm_params table_lpm_params = {
-			.n_rules = app.max_routing_rules,
-			.entry_unique_size =
-				sizeof(struct app_routing_table_entry),
-			.offset = __builtin_offsetof(struct app_pkt_metadata,
-				flow_key.ip_dst),
-		};
-
-		struct rte_pipeline_table_params table_params = {
-			.ops = &rte_table_lpm_ops,
-			.arg_create = &table_lpm_params,
-			.f_action_hit = app_routing_table_ah,
-			.f_action_miss = NULL,
-			.arg_ah = NULL,
-			.action_data_size =
-				sizeof(struct app_routing_table_entry) -
-				sizeof(struct rte_pipeline_table_entry),
-		};
-
-		if (rte_pipeline_table_create(p, &table_params,
-			&routing_table_id))
-			rte_panic("Unable to configure the LPM table\n");
+	req->type = PIPELINE_MSG_REQ_CUSTOM;
+	req->subtype = PIPELINE_ROUTING_MSG_REQ_ROUTE_ADD;
+	memcpy(&req->key, key, sizeof(*key));
+	req->flags = route_params->flags;
+	req->port_id = route_params->port_id;
+	req->ip = route_params->ip;
+
+	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT);
+	if (rsp == NULL) {
+		if (new_entry)
+			rte_free(entry);
+		return -1;
 	}
 
-	/* ARP table configuration */
-	{
-		struct rte_table_hash_key8_lru_params table_arp_params = {
-			.n_entries = app.max_arp_rules,
-			.f_hash = app_arp_table_hash,
-			.seed = 0,
-			.signature_offset = 0, /* Unused */
-			.key_offset = __builtin_offsetof(
-				struct app_pkt_metadata, arp_key),
-		};
-
-		struct rte_pipeline_table_params table_params = {
-			.ops = &rte_table_hash_key8_lru_dosig_ops,
-			.arg_create = &table_arp_params,
-			.f_action_hit = app_arp_table_ah,
-			.f_action_miss = NULL,
-			.arg_ah = NULL,
-			.action_data_size = sizeof(struct app_arp_table_entry) -
-				sizeof(struct rte_pipeline_table_entry),
-		};
-
-		if (rte_pipeline_table_create(p, &table_params, &arp_table_id))
-			rte_panic("Unable to configure the ARP table\n");
+	/* Read response and write entry */
+	if (rsp->status || (rsp->entry_ptr == NULL)) {
+		app_msg_free(app, rsp);
+		if (new_entry)
+			rte_free(entry);
+		return -1;
+	}
+
+	memcpy(&entry->key, key, sizeof(*key));
+	memcpy(&entry->params, route_params, sizeof(*route_params));
+	entry->entry_ptr = rsp->entry_ptr;
+
+	/* Commit entry */
+	if (new_entry) {
+		TAILQ_INSERT_TAIL(&p->routes, entry, node);
+		p->n_arp_entries++;
+	}
+
+	print_route(entry);
+
+	/* Message buffer free */
+	app_msg_free(app, rsp);
+	return 0;
+}
+
+int
+app_pipeline_routing_delete_route(struct app_params *app,
+	uint32_t pipeline_id,
+	struct pipeline_routing_route_key *key)
+{
+	struct pipeline_routing *p;
+
+	struct pipeline_routing_route_delete_msg_req *req;
+	struct pipeline_routing_route_delete_msg_rsp *rsp;
+
+	struct app_pipeline_routing_entry *entry;
+
+	p = app_pipeline_data_fe(app, pipeline_id);
+	if (p == NULL)
+		return -EINVAL;
+
+	/* Find rule */
+	entry = app_pipeline_routing_find_route(p, key);
+	if (entry == NULL)
+		return 0;
+
+	/* Allocate and write request */
+	req = app_msg_alloc(app);
+	if (req == NULL)
+		return -1;
+
+	req->type = PIPELINE_MSG_REQ_CUSTOM;
+	req->subtype = PIPELINE_ROUTING_MSG_REQ_ROUTE_DEL;
+	memcpy(&req->key, key, sizeof(*key));
+
+
+	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT);
+	if (rsp == NULL)
+		return -1;
+
+	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	if (rsp->status) {
+		app_msg_free(app, rsp);
+		return -1;
+	}
+
+	/* Remove route */
+	TAILQ_REMOVE(&p->routes, entry, node);
+	p->n_routes--;
+
+	rte_free(entry);
+
+	/* Free response */
+	app_msg_free(app, rsp);
+
+	return 0;
+}
+
+int
+app_pipeline_routing_add_default_route(struct app_params *app,
+	uint32_t pipeline_id,
+	uint32_t port_id)
+{
+	struct pipeline_routing *p;
+
+	struct pipeline_routing_route_add_default_msg_req *req;
+	struct pipeline_routing_route_add_default_msg_rsp *rsp;
+
+	p = app_pipeline_data_fe(app, pipeline_id);
+	if (p == NULL)
+		return -EINVAL;
+
+	/* Allocate and write request */
+	req = app_msg_alloc(app);
+	if (req == NULL)
+		return -1;
+
+	req->type = PIPELINE_MSG_REQ_CUSTOM;
+	req->subtype = PIPELINE_ROUTING_MSG_REQ_ROUTE_ADD_DEFAULT;
+	req->port_id = port_id;
+
+	/* Send request and wait for response */
+	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response and write route */
+	if (rsp->status || (rsp->entry_ptr == NULL)) {
+		app_msg_free(app, rsp);
+		return -1;
 	}
 
-	/* Interconnecting ports and tables */
-	for (i = 0; i < app.n_ports; i++) {
-		if (rte_pipeline_port_in_connect_to_table(p, port_in_id[i],
-			routing_table_id))
-			rte_panic("Unable to connect input port %u to "
-				"table %u\n", port_in_id[i],  routing_table_id);
+	p->default_route_port_id = port_id;
+	p->default_route_entry_ptr = rsp->entry_ptr;
+
+	/* Commit route */
+	p->default_route_present = 1;
+
+	/* Free response */
+	app_msg_free(app, rsp);
+
+	return 0;
+}
+
+int
+app_pipeline_routing_delete_default_route(struct app_params *app,
+	uint32_t pipeline_id)
+{
+	struct pipeline_routing *p;
+
+	struct pipeline_routing_arp_delete_default_msg_req *req;
+	struct pipeline_routing_arp_delete_default_msg_rsp *rsp;
+
+	p = app_pipeline_data_fe(app, pipeline_id);
+	if (p == NULL)
+		return -EINVAL;
+
+	/* Allocate and write request */
+	req = app_msg_alloc(app);
+	if (req == NULL)
+		return -1;
+
+	req->type = PIPELINE_MSG_REQ_CUSTOM;
+	req->subtype = PIPELINE_ROUTING_MSG_REQ_ROUTE_DEL_DEFAULT;
+
+	/* Send request and wait for response */
+	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response and write route */
+	if (rsp->status) {
+		app_msg_free(app, rsp);
+		return -1;
 	}
 
-	/* Enable input ports */
-	for (i = 0; i < app.n_ports; i++)
-		if (rte_pipeline_port_in_enable(p, port_in_id[i]))
-			rte_panic("Unable to enable input port %u\n",
-				port_in_id[i]);
-
-	/* Check pipeline consistency */
-	if (rte_pipeline_check(p) < 0)
-		rte_panic("Pipeline consistency check failed\n");
-
-	/* Message handling */
-	mh_params.ring_req =
-		app_get_ring_req(app_get_first_core_id(APP_CORE_RT));
-	mh_params.ring_resp =
-		app_get_ring_resp(app_get_first_core_id(APP_CORE_RT));
-	mh_params.p = p;
-	mh_params.port_out_id = port_out_id;
-	mh_params.routing_table_id = routing_table_id;
-	mh_params.arp_table_id = arp_table_id;
-
-	/* Run-time */
-	for (i = 0; ; i++) {
-		rte_pipeline_run(p);
-
-		if ((i & APP_FLUSH) == 0) {
-			rte_pipeline_flush(p);
-			app_message_handle(&mh_params);
+	/* Commit route */
+	p->default_route_present = 0;
+
+	/* Free response */
+	app_msg_free(app, rsp);
+
+	return 0;
+}
+
+/* CLI */
+
+/* *** Routing - Add *** */
+struct cmd_route_add_result {
+	cmdline_fixed_string_t p_string;
+	uint32_t p;
+	cmdline_fixed_string_t route_string;
+	cmdline_fixed_string_t add_string;
+	cmdline_ipaddr_t ip;
+	uint8_t depth;
+	uint8_t port;
+	cmdline_ipaddr_t nh_ip;
+};
+
+static void
+cmd_route_add_parsed(
+	void *parsed_result,
+	__rte_unused struct cmdline *cl,
+	void *data)
+{
+	struct cmd_route_add_result *params = parsed_result;
+	struct app_params *app = data;
+	struct pipeline_routing_route_key key;
+	struct app_pipeline_routing_route_params rt_params;
+	uint32_t netmask;
+
+	int status;
+
+	APP_CHECK(params->ip.family == AF_INET,
+			"BUG: only IPv4 is supported for now.\n");
+	if ((params->depth == 0) || (params->depth > 32)) {
+			printf("Illegal value for depth parameter (%u)\n",
+				params->depth);
+			return;
 		}
+
+	netmask = (~0) << (32 - params->depth);
+
+	/* Create route */
+	if (params->ip.family == AF_INET) {
+		key.type = PIPELINE_ROUTING_ROUTE_IPV4;
+		key.key.ipv4.ip = rte_bswap32((uint32_t) params->ip.addr.ipv4.s_addr)
+				& netmask;
+		key.key.ipv4.depth = params->depth;
+	} else
+		APP_CHECK(0, "IPv6 not implemented yet");
+
+	rt_params.flags = 0; /* FIXME: ? */
+	rt_params.port_id = params->port;
+	rt_params.ip = rte_bswap32((uint32_t) params->nh_ip.addr.ipv4.s_addr);
+	status = app_pipeline_routing_add_route(app, params->p, &key, &rt_params);
+
+	if (status != 0) {
+		printf("Command failed\n");
+		return;
 	}
 }
 
-void
-app_message_handle(struct app_core_routing_message_handle_params *params)
+static cmdline_parse_token_string_t cmd_route_add_p_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_route_add_result, p_string,
+	"p");
+
+static cmdline_parse_token_num_t cmd_route_add_p =
+	TOKEN_NUM_INITIALIZER(struct cmd_route_add_result, p, UINT32);
+
+static cmdline_parse_token_string_t cmd_route_add_route_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_route_add_result, route_string,
+	"route");
+
+static cmdline_parse_token_string_t cmd_route_add_add_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_route_add_result, add_string,
+	"add");
+
+static cmdline_parse_token_ipaddr_t cmd_route_add_ip =
+	TOKEN_IPADDR_INITIALIZER(struct cmd_route_add_result, ip);
+
+static cmdline_parse_token_num_t cmd_route_add_depth =
+	TOKEN_NUM_INITIALIZER(struct cmd_route_add_result, depth, UINT8);
+
+static cmdline_parse_token_num_t cmd_route_add_port =
+	TOKEN_NUM_INITIALIZER(struct cmd_route_add_result, port, UINT8);
+
+static cmdline_parse_token_ipaddr_t cmd_route_add_nh_ip =
+	TOKEN_IPADDR_INITIALIZER(struct cmd_route_add_result, nh_ip);
+
+static cmdline_parse_inst_t cmd_route_add = {
+	.f = cmd_route_add_parsed,
+	.data = NULL,
+	.help_str = "Route add",
+	.tokens = {
+		(void *)&cmd_route_add_p_string,
+		(void *)&cmd_route_add_p,
+		(void *)&cmd_route_add_route_string,
+		(void *)&cmd_route_add_add_string,
+		(void *)&cmd_route_add_ip,
+		(void *)&cmd_route_add_depth,
+		(void *)&cmd_route_add_port,
+		(void *)&cmd_route_add_nh_ip,
+		NULL,
+	},
+};
+
+/* *** Routing - Add Default *** */
+struct cmd_route_add_default_result {
+	cmdline_fixed_string_t p_string;
+	uint32_t p;
+	cmdline_fixed_string_t route_string;
+	cmdline_fixed_string_t add_string;
+	cmdline_fixed_string_t default_string;
+	uint8_t port;
+};
+
+static void
+cmd_route_add_default_parsed(
+	void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	void *data)
 {
-	struct rte_ring *ring_req = params->ring_req;
-	struct rte_ring *ring_resp;
-	void *msg;
-	struct app_msg_req *req;
-	struct app_msg_resp *resp;
-	struct rte_pipeline *p;
-	uint32_t *port_out_id;
-	uint32_t routing_table_id, arp_table_id;
-	int result;
-
-	/* Read request message */
-	result = rte_ring_sc_dequeue(ring_req, &msg);
-	if (result != 0)
+	struct cmd_route_add_default_result *params = parsed_result;
+	struct app_params *app = data;
+	int status;
+
+	status = app_pipeline_routing_add_default_route(app, params->p,
+			params->port);
+
+	if (status != 0) {
+		printf("Command failed\n");
 		return;
+	}
+}
 
-	ring_resp = params->ring_resp;
-	p = params->p;
-	port_out_id = params->port_out_id;
-	routing_table_id = params->routing_table_id;
-	arp_table_id = params->arp_table_id;
-
-	/* Handle request */
-	req = (struct app_msg_req *)rte_ctrlmbuf_data((struct rte_mbuf *)msg);
-	switch (req->type) {
-	case APP_MSG_REQ_PING:
-	{
-		result = 0;
-		break;
+static cmdline_parse_token_string_t cmd_route_add_default_p_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_route_add_default_result, p_string,
+	"p");
+
+static cmdline_parse_token_num_t cmd_route_add_default_p =
+	TOKEN_NUM_INITIALIZER(struct cmd_route_add_default_result, p, UINT32);
+
+cmdline_parse_token_string_t cmd_route_add_default_route_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_route_add_default_result, route_string,
+	"route");
+
+cmdline_parse_token_string_t cmd_route_add_default_add_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_route_add_default_result, add_string,
+	"add");
+
+cmdline_parse_token_string_t cmd_route_add_default_default_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_route_add_default_result,
+	default_string, "default");
+
+cmdline_parse_token_num_t cmd_route_add_default_port =
+	TOKEN_NUM_INITIALIZER(struct cmd_route_add_default_result, port, UINT8);
+
+cmdline_parse_inst_t cmd_route_add_default = {
+	.f = cmd_route_add_default_parsed,
+	.data = NULL,
+	.help_str = "Set the default route",
+	.tokens = {
+		(void *)&cmd_route_add_default_p_string,
+		(void *)&cmd_route_add_default_p,
+		(void *)&cmd_route_add_default_route_string,
+		(void *)&cmd_route_add_default_add_string,
+		(void *)&cmd_route_add_default_default_string,
+		(void *)&cmd_route_add_default_port,
+		NULL,
+	},
+};
+
+/* *** Routing - Del *** */
+struct cmd_route_del_result {
+	cmdline_fixed_string_t p_string;
+	uint32_t p;
+	cmdline_fixed_string_t route_string;
+	cmdline_fixed_string_t del_string;
+	cmdline_ipaddr_t ip;
+	uint8_t depth;
+};
+
+static void
+cmd_route_del_parsed(
+	void *parsed_result,
+	__rte_unused struct cmdline *cl,
+	void *data)
+{
+	struct cmd_route_del_result *params = parsed_result;
+	struct app_params *app = data;
+	struct pipeline_routing_route_key key;
+	uint32_t netmask;
+
+	int status;
+
+	APP_CHECK(params->ip.family == AF_INET,
+			"BUG: only IPv4 is supported for now.\n");
+	if ((params->depth == 0) || (params->depth > 32)) {
+		printf("Illegal value for depth parameter (%u)\n",
+			params->depth);
+		return;
 	}
 
-	case APP_MSG_REQ_RT_ADD:
-	{
-		struct app_routing_table_entry entry = {
-			.head = {
-				.action = RTE_PIPELINE_ACTION_TABLE,
-				{.table_id = arp_table_id},
-			},
-			.nh_ip = req->routing_add.nh_ip,
-			.nh_iface = port_out_id[req->routing_add.port],
-		};
-
-		struct rte_table_lpm_key key = {
-			.ip = req->routing_add.ip,
-			.depth = req->routing_add.depth,
-		};
-
-		struct rte_pipeline_table_entry *entry_ptr;
-
-		int key_found;
-
-		result = rte_pipeline_table_entry_add(p, routing_table_id, &key,
-			(struct rte_pipeline_table_entry *) &entry, &key_found,
-			&entry_ptr);
-		break;
+	netmask = (~0) << (32 - params->depth);
+
+	/* Create route */
+	if (params->ip.family == AF_INET) {
+		key.type = PIPELINE_ROUTING_ROUTE_IPV4;
+		key.key.ipv4.ip = rte_bswap32((uint32_t) params->ip.addr.ipv4.s_addr)
+				& netmask;
+		key.key.ipv4.depth = params->depth;
+	} else
+		APP_CHECK(0, "IPv6 not implemented yet");
+
+	status = app_pipeline_routing_delete_route(app, params->p, &key);
+
+	if (status != 0) {
+		printf("Command failed\n");
+		return;
 	}
+}
 
-	case APP_MSG_REQ_RT_DEL:
-	{
-		struct rte_table_lpm_key key = {
-			.ip = req->routing_del.ip,
-			.depth = req->routing_del.depth,
-		};
+static cmdline_parse_token_string_t cmd_route_del_p_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_route_del_result, p_string,
+	"p");
+
+static cmdline_parse_token_num_t cmd_route_del_p =
+	TOKEN_NUM_INITIALIZER(struct cmd_route_del_result, p, UINT32);
+
+static cmdline_parse_token_string_t cmd_route_del_route_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_route_del_result, route_string,
+	"route");
+
+static cmdline_parse_token_string_t cmd_route_del_del_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_route_del_result, del_string,
+	"del");
+
+static cmdline_parse_token_ipaddr_t cmd_route_del_ip =
+	TOKEN_IPADDR_INITIALIZER(struct cmd_route_del_result, ip);
+
+static cmdline_parse_token_num_t cmd_route_del_depth =
+	TOKEN_NUM_INITIALIZER(struct cmd_route_del_result, depth, UINT8);
+
+static cmdline_parse_inst_t cmd_route_del = {
+	.f = cmd_route_del_parsed,
+	.data = NULL,
+	.help_str = "Route delete",
+	.tokens = {
+		(void *)&cmd_route_del_p_string,
+		(void *)&cmd_route_del_p,
+		(void *)&cmd_route_del_route_string,
+		(void *)&cmd_route_del_del_string,
+		(void *)&cmd_route_del_ip,
+		(void *)&cmd_route_del_depth,
+		NULL,
+	},
+};
 
-		int key_found;
+/* *** Routing - Del default *** */
+struct cmd_route_del_default_result {
+	cmdline_fixed_string_t p_string;
+	uint32_t p;
+	cmdline_fixed_string_t route_string;
+	cmdline_fixed_string_t del_string;
+	cmdline_fixed_string_t default_string;
+	uint8_t out_iface;
+};
+
+static void
+cmd_route_del_default_parsed(
+	__rte_unused void *parsed_result,
+	__rte_unused struct cmdline *cl,
+	__rte_unused void *data)
+{
+	struct cmd_route_del_default_result *params = parsed_result;
+	struct app_params *app = data;
+	int status;
 
-		result = rte_pipeline_table_entry_delete(p, routing_table_id,
-			&key, &key_found, NULL);
-		break;
+	status = app_pipeline_routing_add_default_route(app, params->p,
+			params->out_iface);
+
+	if (status != 0) {
+		printf("Command failed\n");
+		return;
 	}
+}
 
-	case APP_MSG_REQ_ARP_ADD:
-	{
+static cmdline_parse_token_string_t cmd_route_del_default_p_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_route_del_default_result, p_string,
+	"p");
+
+static cmdline_parse_token_num_t cmd_route_del_default_p =
+	TOKEN_NUM_INITIALIZER(struct cmd_route_del_default_result, p, UINT32);
+
+static cmdline_parse_token_string_t cmd_route_del_default_route_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_route_del_default_result, route_string,
+	"route");
+
+static cmdline_parse_token_string_t cmd_route_del_default_del_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_route_del_default_result, del_string,
+	"del");
+
+static cmdline_parse_token_string_t cmd_route_del_default_default_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_route_del_default_result,
+	default_string, "default");
+
+
+static cmdline_parse_inst_t cmd_route_del_default = {
+	.f = cmd_route_del_default_parsed,
+	.data = NULL,
+	.help_str = "Route delete",
+	.tokens = {
+		(void *)&cmd_route_del_default_p_string,
+		(void *)&cmd_route_del_default_p,
+		(void *)&cmd_route_del_default_route_string,
+		(void *)&cmd_route_del_default_del_string,
+		(void *)&cmd_route_del_default_default_string,
+		NULL,
+	},
+};
 
-		struct app_arp_table_entry entry = {
-			.head = {
-				.action = RTE_PIPELINE_ACTION_PORT,
-				{.port_id =
-					port_out_id[req->arp_add.out_iface]},
-			},
-			.nh_arp = req->arp_add.nh_arp,
-		};
+/* *** Routing - List *** */
+struct cmd_route_ls_result {
+	cmdline_fixed_string_t p_string;
+	uint32_t p;
+	cmdline_fixed_string_t route_string;
+	cmdline_fixed_string_t ls_string;
+};
 
-		struct app_arp_key arp_key = {
-			.nh_ip = req->arp_add.nh_ip,
-			.nh_iface = port_out_id[req->arp_add.out_iface],
-		};
+static void
+cmd_route_ls_parsed(
+	void *parsed_result,
+	__rte_unused struct cmdline *cl,
+	void *data)
+{
+	struct cmd_route_ls_result *params = parsed_result;
+	struct app_params *app = data;
+	int status;
 
-		struct rte_pipeline_table_entry *entry_ptr;
+	status = app_pipeline_routing_ls(app, params->p);
 
-		int key_found;
+	if (status != 0) {
+		printf("Command failed\n");
+		return;
+	}
+}
+
+static cmdline_parse_token_string_t cmd_route_ls_p_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_route_ls_result, p_string, "p");
+
+static cmdline_parse_token_num_t cmd_route_ls_p =
+	TOKEN_NUM_INITIALIZER(struct cmd_route_ls_result, p, UINT32);
+
+static cmdline_parse_token_string_t cmd_route_ls_route_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_route_ls_result,
+	route_string, "route");
+
+static cmdline_parse_token_string_t cmd_route_ls_ls_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_route_ls_result, ls_string,
+	"ls");
+
+static cmdline_parse_inst_t cmd_route_ls = {
+	.f = cmd_route_ls_parsed,
+	.data = NULL,
+	.help_str = "Route list",
+	.tokens = {
+		(void *)&cmd_route_ls_p_string,
+		(void *)&cmd_route_ls_p,
+		(void *)&cmd_route_ls_route_string,
+		(void *)&cmd_route_ls_ls_string,
+		NULL,
+	},
+};
+
+/* *** ARP - Add *** */
+struct cmd_arp_add_result {
+	cmdline_fixed_string_t p_string;
+	uint32_t p;
+	cmdline_fixed_string_t arp_string;
+	cmdline_fixed_string_t add_string;
+	uint8_t out_iface;
+	cmdline_ipaddr_t nh_ip;
+	struct ether_addr nh_arp;
+
+};
+
+static void
+cmd_arp_add_parsed(
+	void *parsed_result,
+	__rte_unused struct cmdline *cl,
+	void *data)
+{
+	struct cmd_arp_add_result *params = parsed_result;
+	struct app_params *app = data;
+
+	struct pipeline_routing_arp_key key;
+	int status;
+
+	APP_CHECK(params->nh_ip.family == AF_INET,
+			"BUG: only IPv4 is supported for now.\n");
+
+	key.key.ipv4.port_id = params->out_iface;
+	key.key.ipv4.ip = rte_cpu_to_be_32(params->nh_ip.addr.ipv4.s_addr);
 
-		result = rte_pipeline_table_entry_add(p, arp_table_id, &arp_key,
-			(struct rte_pipeline_table_entry *) &entry, &key_found,
-			&entry_ptr);
-		break;
+	status = app_pipeline_routing_add_arp_entry(app, params->p, &key,
+			&params->nh_arp);
+
+	if (status != 0) {
+		printf("Command failed\n");
+		return;
 	}
+}
+
+static cmdline_parse_token_string_t cmd_arp_add_p_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_arp_add_result, p_string,
+	"p");
+
+static cmdline_parse_token_num_t cmd_arp_add_p =
+	TOKEN_NUM_INITIALIZER(struct cmd_arp_add_result, p, UINT32);
+
+static cmdline_parse_token_string_t cmd_arp_add_arp_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_arp_add_result, arp_string, "arp");
+
+static cmdline_parse_token_string_t cmd_arp_add_add_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_arp_add_result, add_string, "add");
+
+static cmdline_parse_token_num_t cmd_arp_add_out_iface =
+	TOKEN_NUM_INITIALIZER(struct cmd_arp_add_result, out_iface, UINT8);
+
+static cmdline_parse_token_ipaddr_t cmd_arp_add_nh_ip =
+	TOKEN_IPV4_INITIALIZER(struct cmd_arp_add_result, nh_ip);
+
+static cmdline_parse_token_etheraddr_t cmd_arp_add_nh_arp =
+	TOKEN_ETHERADDR_INITIALIZER(struct cmd_arp_add_result, nh_arp);
+
+static cmdline_parse_inst_t cmd_arp_add = {
+	.f = cmd_arp_add_parsed,
+	.data = NULL,
+	.help_str = "ARP add",
+	.tokens = {
+		(void *)&cmd_arp_add_p_string,
+		(void *)&cmd_arp_add_p,
+		(void *)&cmd_arp_add_arp_string,
+		(void *)&cmd_arp_add_add_string,
+		(void *)&cmd_arp_add_out_iface,
+		(void *)&cmd_arp_add_nh_ip,
+		(void *)&cmd_arp_add_nh_arp,
+		NULL,
+	},
+};
+
+/* *** ARP - Add default *** */
+struct cmd_arp_add_default_result {
+	cmdline_fixed_string_t p_string;
+	uint32_t p;
+	cmdline_fixed_string_t arp_string;
+	cmdline_fixed_string_t del_string;
+	cmdline_fixed_string_t default_string;
+	uint8_t out_iface;
+};
+
+static void
+cmd_arp_add_default_parsed(
+	__rte_unused void *parsed_result,
+	__rte_unused struct cmdline *cl,
+	__rte_unused void *data)
+{
+	struct cmd_arp_add_default_result *params = parsed_result;
+	struct app_params *app = data;
+
+	int status;
+
+	status = app_pipeline_routing_add_default_arp_entry(app, params->p,
+			params->out_iface);
+
+	if (status != 0) {
+		printf("Command failed\n");
+		return;
+	}
+}
+
+static cmdline_parse_token_string_t cmd_arp_add_default_p_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_arp_add_default_result, p_string,
+	"p");
+
+static cmdline_parse_token_num_t cmd_arp_add_default_p =
+	TOKEN_NUM_INITIALIZER(struct cmd_arp_add_default_result, p, UINT32);
+
+static cmdline_parse_token_string_t cmd_arp_add_default_arp_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_arp_add_default_result, arp_string,
+	"arp");
+
+static cmdline_parse_token_string_t cmd_arp_add_default_add_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_arp_add_default_result, del_string,
+	"del");
+
+static cmdline_parse_token_string_t cmd_arp_add_default_default_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_arp_add_default_result, default_string,
+	"default");
+
+static cmdline_parse_token_num_t cmd_arp_add_default_out_iface =
+	TOKEN_STRING_INITIALIZER(struct cmd_arp_add_default_result, out_iface,
+	UINT8);
+
+static cmdline_parse_inst_t cmd_arp_add_default = {
+	.f = cmd_arp_add_default_parsed,
+	.data = NULL,
+	.help_str = "ARP add default",
+	.tokens = {
+		(void *)&cmd_arp_add_default_p_string,
+		(void *)&cmd_arp_add_default_p,
+		(void *)&cmd_arp_add_default_arp_string,
+		(void *)&cmd_arp_add_default_add_string,
+		(void *)&cmd_arp_add_default_default_string,
+		(void *)&cmd_arp_add_default_out_iface,
+		NULL,
+	},
+};
+
+/* *** ARP - Del *** */
+struct cmd_arp_del_result {
+	cmdline_fixed_string_t p_string;
+	uint32_t p;
+	cmdline_fixed_string_t arp_string;
+	cmdline_fixed_string_t del_string;
+	uint8_t out_iface;
+	cmdline_ipaddr_t nh_ip;
+};
+
+static void
+cmd_arp_del_parsed(
+	void *parsed_result,
+	__rte_unused struct cmdline *cl,
+	void *data)
+{
+	struct cmd_arp_del_result *params = parsed_result;
+	struct app_params *app = data;
+
+	struct pipeline_routing_arp_key key;
+	int status;
 
-	case APP_MSG_REQ_ARP_DEL:
-	{
-		struct app_arp_key arp_key = {
-			.nh_ip = req->arp_del.nh_ip,
-			.nh_iface = port_out_id[req->arp_del.out_iface],
-		};
+	APP_CHECK(params->nh_ip.family != AF_INET,
+			"BUG: only IPv4 is supported for now.\n");
 
-		int key_found;
+	key.key.ipv4.ip = rte_cpu_to_be_32(params->nh_ip.addr.ipv4.s_addr);
+	key.key.ipv4.port_id = params->out_iface;
 
-		result = rte_pipeline_table_entry_delete(p, arp_table_id,
-			&arp_key, &key_found, NULL);
-		break;
+	status = app_pipeline_routing_delete_arp_entry(app, params->p, &key);
+
+	if (status != 0) {
+		printf("Command failed\n");
+		return;
 	}
+}
+
+static cmdline_parse_token_string_t cmd_arp_del_p_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_arp_del_result, p_string,
+	"p");
+
+static cmdline_parse_token_num_t cmd_arp_del_p =
+	TOKEN_NUM_INITIALIZER(struct cmd_arp_del_result, p, UINT32);
+
+static cmdline_parse_token_string_t cmd_arp_del_arp_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_arp_del_result, arp_string, "arp");
+
+static cmdline_parse_token_string_t cmd_arp_del_del_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_arp_del_result, del_string, "del");
+
+static cmdline_parse_token_num_t cmd_arp_del_out_iface =
+	TOKEN_NUM_INITIALIZER(struct cmd_arp_del_result, out_iface, UINT8);
+
+static cmdline_parse_token_ipaddr_t cmd_arp_del_nh_ip =
+	TOKEN_IPV4_INITIALIZER(struct cmd_arp_del_result, nh_ip);
+
+static cmdline_parse_inst_t cmd_arp_del = {
+	.f = cmd_arp_del_parsed,
+	.data = NULL,
+	.help_str = "ARP delete",
+	.tokens = {
+		(void *)&cmd_arp_del_p_string,
+		(void *)&cmd_arp_del_p,
+		(void *)&cmd_arp_del_arp_string,
+		(void *)&cmd_arp_del_del_string,
+		(void *)&cmd_arp_del_out_iface,
+		(void *)&cmd_arp_del_nh_ip,
+		NULL,
+	},
+};
+
+/* *** ARP - Del default *** */
+struct cmd_arp_del_default_result {
+	cmdline_fixed_string_t p_string;
+	uint32_t p;
+	cmdline_fixed_string_t arp_string;
+	cmdline_fixed_string_t del_string;
+	cmdline_fixed_string_t default_string;
+};
+
+static void
+cmd_arp_del_default_parsed(
+	void *parsed_result,
+	__rte_unused struct cmdline *cl,
+	void *data)
+{
+	struct cmd_arp_del_default_result *params = parsed_result;
+	struct app_params *app = data;
+
+	int status;
 
-	default:
-		rte_panic("RT Unrecognized message type (%u)\n", req->type);
+	status = app_pipeline_routing_delete_default_arp_entry(app, params->p);
+
+	if (status != 0) {
+		printf("Command failed\n");
+		return;
 	}
+}
 
-	/* Fill in response message */
-	resp = (struct app_msg_resp *)rte_ctrlmbuf_data((struct rte_mbuf *)msg);
-	resp->result = result;
+static cmdline_parse_token_string_t cmd_arp_del_default_p_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_arp_del_default_result, p_string,
+	"p");
+
+static cmdline_parse_token_num_t cmd_arp_del_default_p =
+	TOKEN_NUM_INITIALIZER(struct cmd_arp_del_default_result, p, UINT32);
+
+static cmdline_parse_token_string_t cmd_arp_del_default_arp_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_arp_del_default_result, arp_string,
+	"arp");
+
+static cmdline_parse_token_string_t cmd_arp_del_default_del_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_arp_del_default_result, del_string,
+	"del");
+
+static cmdline_parse_token_string_t cmd_arp_del_default_default_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_arp_del_default_result, default_string,
+	"default");
+
+static cmdline_parse_inst_t cmd_arp_del_default = {
+	.f = cmd_arp_del_default_parsed,
+	.data = NULL,
+	.help_str = "ARP delete default",
+	.tokens = {
+		(void *)&cmd_arp_del_default_p_string,
+		(void *)&cmd_arp_del_default_p,
+		(void *)&cmd_arp_del_default_arp_string,
+		(void *)&cmd_arp_del_default_del_string,
+		(void *)&cmd_arp_del_default_default_string,
+		NULL,
+	},
+};
 
-	/* Send response */
-	do {
-		result = rte_ring_sp_enqueue(ring_resp, msg);
-	} while (result == -ENOBUFS);
+/* *** ARP - Print *** */
+struct cmd_arp_ls_result {
+	cmdline_fixed_string_t p_string;
+	uint32_t p;
+	cmdline_fixed_string_t arp_string;
+	cmdline_fixed_string_t ls_string;
+};
+
+static void
+cmd_arp_ls_parsed(
+	void *parsed_result,
+	__rte_unused struct cmdline *cl,
+	void *data)
+{
+	struct cmd_arp_ls_result *params = parsed_result;
+	struct app_params *app = data;
+	struct pipeline_routing *p;
+
+	p = app_pipeline_data_fe(app, params->p);
+	if (p == NULL)
+		return;
+
+	app_pipeline_routing_arp_ls(app, params->p);
 }
+
+static cmdline_parse_token_string_t cmd_arp_ls_p_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_arp_ls_result, p_string,
+	"p");
+
+static cmdline_parse_token_num_t cmd_arp_ls_p =
+	TOKEN_NUM_INITIALIZER(struct cmd_arp_ls_result, p, UINT32);
+
+static cmdline_parse_token_string_t cmd_arp_ls_arp_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_arp_ls_result, arp_string,
+	"arp");
+
+static cmdline_parse_token_string_t cmd_arp_ls_ls_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_arp_ls_result, ls_string,
+	"ls");
+
+static cmdline_parse_inst_t cmd_arp_ls = {
+	.f = cmd_arp_ls_parsed,
+	.data = NULL,
+	.help_str = "ARP list",
+	.tokens = {
+		(void *)&cmd_arp_ls_p_string,
+		(void *)&cmd_arp_ls_p,
+		(void *)&cmd_arp_ls_arp_string,
+		(void *)&cmd_arp_ls_ls_string,
+		NULL,
+	},
+};
+
+
+static cmdline_parse_ctx_t pipeline_cmds[] = {
+	(cmdline_parse_inst_t *)&cmd_route_add,
+	(cmdline_parse_inst_t *)&cmd_route_del,
+	(cmdline_parse_inst_t *)&cmd_route_add_default,
+	(cmdline_parse_inst_t *)&cmd_route_del_default,
+	(cmdline_parse_inst_t *)&cmd_route_ls,
+	(cmdline_parse_inst_t *)&cmd_arp_add,
+	(cmdline_parse_inst_t *)&cmd_arp_del,
+	(cmdline_parse_inst_t *)&cmd_arp_add_default,
+	(cmdline_parse_inst_t *)&cmd_arp_del_default,
+	(cmdline_parse_inst_t *)&cmd_arp_ls,
+	NULL,
+};
+
+static struct pipeline_fe_ops pipeline_routing_fe_ops = {
+	.f_init = pipeline_routing_init,
+	.f_free = app_pipeline_routing_free,
+	.cmds = pipeline_cmds,
+};
+
+struct pipeline_type pipeline_routing = {
+	.name = "ROUTING",
+	.ops = &pipeline_routing_ops,
+	.fe_ops = &pipeline_routing_fe_ops,
+};
diff --git a/examples/ip_pipeline/pipeline/pipeline_routing.h b/examples/ip_pipeline/pipeline/pipeline_routing.h
new file mode 100644
index 0000000..c5892d8
--- /dev/null
+++ b/examples/ip_pipeline/pipeline/pipeline_routing.h
@@ -0,0 +1,99 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __INCLUDE_PIPELINE_ROUTING_H__
+#define __INCLUDE_PIPELINE_ROUTING_H__
+
+#include "pipeline.h"
+#include "pipeline_routing_ops.h"
+
+/*
+ * Route
+ */
+
+struct app_pipeline_routing_route_params {
+	enum pipeline_routing_route_flags flags;
+	uint32_t port_id; /* Output port ID */
+	uint32_t ip; /* IP address for the next hop (only for remote routes) */
+};
+
+int
+app_pipeline_routing_add_route(struct app_params *app,
+	uint32_t pipeline_id,
+	struct pipeline_routing_route_key *key,
+	struct app_pipeline_routing_route_params *route_params);
+
+int
+app_pipeline_routing_delete_route(struct app_params *app,
+	uint32_t pipeline_id,
+	struct pipeline_routing_route_key *key);
+
+int
+app_pipeline_routing_add_default_route(struct app_params *app,
+	uint32_t pipeline_id,
+	uint32_t port_id);
+
+int
+app_pipeline_routing_delete_default_route(struct app_params *app,
+	uint32_t pipeline_id);
+
+/*
+ * ARP
+ */
+
+int
+app_pipeline_routing_add_arp_entry(struct app_params *app,
+	uint32_t pipeline_id,
+	struct pipeline_routing_arp_key *key,
+	struct ether_addr *macaddr);
+
+int
+app_pipeline_routing_delete_arp_entry(struct app_params *app,
+	uint32_t pipeline_id,
+	struct pipeline_routing_arp_key *key);
+
+int
+app_pipeline_routing_add_default_arp_entry(struct app_params *app,
+	uint32_t pipeline_id,
+	uint32_t port_id);
+
+int
+app_pipeline_routing_delete_default_arp_entry(struct app_params *app,
+	uint32_t pipeline_id);
+
+/*
+ * Pipeline type
+ */
+extern struct pipeline_type pipeline_routing;
+
+#endif
diff --git a/examples/ip_pipeline/pipeline/pipeline_routing_ops.c b/examples/ip_pipeline/pipeline/pipeline_routing_ops.c
new file mode 100644
index 0000000..4a29502
--- /dev/null
+++ b/examples/ip_pipeline/pipeline/pipeline_routing_ops.c
@@ -0,0 +1,978 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <rte_common.h>
+#include <rte_log.h>
+#include <rte_malloc.h>
+#include <rte_ip.h>
+#include <rte_byteorder.h>
+#include <rte_table_lpm.h>
+#include <rte_table_hash.h>
+#include <rte_pipeline.h>
+
+#include "pipeline_common_ops.h"
+#include "pipeline_routing_ops.h"
+
+struct pipeline_routing {
+	struct pipeline p;
+	pipeline_msg_req_handler custom_handlers[PIPELINE_ROUTING_MSG_REQS];
+
+	uint32_t n_routes;
+	uint32_t n_arp_entries;
+	uint32_t n_arp_entries_ext;
+	uint32_t ip_da_offset;
+	uint32_t arp_key_offset;
+} __rte_cache_aligned;
+
+static void *
+pipeline_routing_msg_req_custom_handler(struct pipeline *p, void *msg);
+
+static pipeline_msg_req_handler handlers[] = {
+	[PIPELINE_MSG_REQ_PING] = pipeline_msg_req_ping_handler,
+	[PIPELINE_MSG_REQ_STATS_PORT_IN] = pipeline_msg_req_stats_port_in_handler,
+	[PIPELINE_MSG_REQ_STATS_PORT_OUT] = pipeline_msg_req_stats_port_out_handler,
+	[PIPELINE_MSG_REQ_STATS_TABLE] = pipeline_msg_req_stats_table_handler,
+	[PIPELINE_MSG_REQ_PORT_IN_ENABLE] = pipeline_msg_req_port_in_enable_handler,
+	[PIPELINE_MSG_REQ_PORT_IN_DISABLE] = pipeline_msg_req_port_in_disable_handler,
+	[PIPELINE_MSG_REQ_CUSTOM] = pipeline_routing_msg_req_custom_handler,
+};
+
+static void *
+pipeline_routing_msg_req_route_add_handler(struct pipeline *p, void *msg);
+
+static void *
+pipeline_routing_msg_req_route_del_handler(struct pipeline *p, void *msg);
+
+static void *
+pipeline_routing_msg_req_route_add_default_handler(struct pipeline *p, void *msg);
+
+static void *
+pipeline_routing_msg_req_route_del_default_handler(struct pipeline *p, void *msg);
+
+static void *
+pipeline_routing_msg_req_arp_add_handler(struct pipeline *p, void *msg);
+
+static void *
+pipeline_routing_msg_req_arp_del_handler(struct pipeline *p, void *msg);
+
+static void *
+pipeline_routing_msg_req_arp_add_default_handler(struct pipeline *p, void *msg);
+
+static void *
+pipeline_routing_msg_req_arp_del_default_handler(struct pipeline *p, void *msg);
+
+static pipeline_msg_req_handler custom_handlers[] = {
+	[PIPELINE_ROUTING_MSG_REQ_ROUTE_ADD] = pipeline_routing_msg_req_route_add_handler,
+	[PIPELINE_ROUTING_MSG_REQ_ROUTE_DEL] = pipeline_routing_msg_req_route_del_handler,
+	[PIPELINE_ROUTING_MSG_REQ_ROUTE_ADD_DEFAULT] = pipeline_routing_msg_req_route_add_default_handler,
+	[PIPELINE_ROUTING_MSG_REQ_ROUTE_DEL_DEFAULT] = pipeline_routing_msg_req_route_del_default_handler,
+	[PIPELINE_ROUTING_MSG_REQ_ARP_ADD] = pipeline_routing_msg_req_arp_add_handler,
+	[PIPELINE_ROUTING_MSG_REQ_ARP_DEL] = pipeline_routing_msg_req_arp_del_handler,
+	[PIPELINE_ROUTING_MSG_REQ_ARP_ADD_DEFAULT] = pipeline_routing_msg_req_arp_add_default_handler,
+	[PIPELINE_ROUTING_MSG_REQ_ARP_DEL_DEFAULT] = pipeline_routing_msg_req_arp_del_default_handler,
+};
+
+/*
+ * Routing table
+ */
+struct routing_table_entry {
+	struct rte_pipeline_table_entry head;
+	enum pipeline_routing_route_flags flags;
+	uint32_t port_id; /* Output port ID */
+	uint32_t ip; /* IP address for the next hop (only valid for remote routes) */
+};
+
+static inline void
+pkt_work_routing(
+	struct pipeline_routing *p_rt,
+	struct rte_mbuf *pkt,
+	struct routing_table_entry *entry)
+{
+	struct pipeline_routing_arp_key_ipv4 *arp_key = 
+		(struct pipeline_routing_arp_key_ipv4 *) RTE_MBUF_METADATA_UINT8_PTR(pkt, p_rt->arp_key_offset);
+	uint32_t ip = RTE_MBUF_METADATA_UINT32(pkt, p_rt->ip_da_offset);
+		
+	arp_key->port_id = entry->port_id;
+	arp_key->ip = entry->ip;
+	if (entry->flags & PIPELINE_ROUTING_ROUTE_LOCAL)
+		arp_key->ip = ip;
+}
+
+static inline void
+pkt4_work_routing(
+	struct pipeline_routing *p_rt,
+	struct rte_mbuf *pkt0,
+	struct rte_mbuf *pkt1,
+	struct rte_mbuf *pkt2,
+	struct rte_mbuf *pkt3,
+	struct routing_table_entry *entry0,
+	struct routing_table_entry *entry1,
+	struct routing_table_entry *entry2,
+	struct routing_table_entry *entry3)
+{
+	struct pipeline_routing_arp_key_ipv4 *arp_key0 = 
+		(struct pipeline_routing_arp_key_ipv4 *) RTE_MBUF_METADATA_UINT8_PTR(pkt0, p_rt->arp_key_offset);
+	struct pipeline_routing_arp_key_ipv4 *arp_key1 = 
+		(struct pipeline_routing_arp_key_ipv4 *) RTE_MBUF_METADATA_UINT8_PTR(pkt1, p_rt->arp_key_offset);
+	struct pipeline_routing_arp_key_ipv4 *arp_key2 = 
+		(struct pipeline_routing_arp_key_ipv4 *) RTE_MBUF_METADATA_UINT8_PTR(pkt2, p_rt->arp_key_offset);
+	struct pipeline_routing_arp_key_ipv4 *arp_key3 = 
+		(struct pipeline_routing_arp_key_ipv4 *) RTE_MBUF_METADATA_UINT8_PTR(pkt3, p_rt->arp_key_offset);
+
+	uint32_t ip0 = RTE_MBUF_METADATA_UINT32(pkt0, p_rt->ip_da_offset);
+	uint32_t ip1 = RTE_MBUF_METADATA_UINT32(pkt1, p_rt->ip_da_offset);
+	uint32_t ip2 = RTE_MBUF_METADATA_UINT32(pkt2, p_rt->ip_da_offset);
+	uint32_t ip3 = RTE_MBUF_METADATA_UINT32(pkt3, p_rt->ip_da_offset);
+		
+	arp_key0->port_id = entry0->port_id;
+	arp_key1->port_id = entry1->port_id;
+	arp_key2->port_id = entry2->port_id;
+	arp_key3->port_id = entry3->port_id;
+
+	arp_key0->ip = entry0->ip;
+	if (entry0->flags & PIPELINE_ROUTING_ROUTE_LOCAL)
+		arp_key0->ip = ip0;
+	arp_key1->ip = entry1->ip;
+	if (entry1->flags & PIPELINE_ROUTING_ROUTE_LOCAL)
+		arp_key1->ip = ip1;
+	arp_key2->ip = entry2->ip;
+	if (entry2->flags & PIPELINE_ROUTING_ROUTE_LOCAL)
+		arp_key2->ip = ip2;
+	arp_key3->ip = entry3->ip;
+	if (entry3->flags & PIPELINE_ROUTING_ROUTE_LOCAL)
+		arp_key3->ip = ip3;
+}
+
+static int
+routing_table_ah_hit(
+	struct rte_mbuf **pkts,
+	uint64_t *pkts_mask,
+	struct rte_pipeline_table_entry **entries,
+	void *arg)
+{
+	struct pipeline_routing *p_rt = arg;
+	uint64_t pkts_in_mask = *pkts_mask;
+
+	if ((pkts_in_mask & (pkts_in_mask + 1)) == 0) {
+		uint64_t n_pkts = __builtin_popcountll(pkts_in_mask);
+		uint32_t i;
+
+		for (i = 0; i < (n_pkts & 0x3); i += 4) {
+			struct rte_mbuf *pkt0 = pkts[i];
+			struct rte_mbuf *pkt1 = pkts[i + 1];
+			struct rte_mbuf *pkt2 = pkts[i + 2];
+			struct rte_mbuf *pkt3 = pkts[i + 3];
+
+			struct routing_table_entry *e0 =
+				(struct routing_table_entry *) entries[i];
+			struct routing_table_entry *e1 =
+				(struct routing_table_entry *) entries[i + 1];
+			struct routing_table_entry *e2 =
+				(struct routing_table_entry *) entries[i + 2];
+			struct routing_table_entry *e3 =
+				(struct routing_table_entry *) entries[i + 3];
+
+			pkt4_work_routing(p_rt, pkt0, pkt1, pkt2, pkt3, e0, e1, e2, e3);
+		}
+
+		for ( ; i < n_pkts; i++) {
+			struct rte_mbuf *pkt = pkts[i];
+			struct routing_table_entry *e =
+				(struct routing_table_entry *) entries[i];
+
+			pkt_work_routing(p_rt, pkt, e);
+		}
+	} else
+		for ( ; pkts_in_mask; ) {
+			struct rte_mbuf *pkt;
+			struct routing_table_entry *e;
+			uint64_t pkt_mask;
+			uint32_t packet_index;
+
+			packet_index = __builtin_ctzll(pkts_in_mask);
+			pkt_mask = 1LLU << packet_index;
+			pkts_in_mask &= ~pkt_mask;
+
+			pkt = pkts[packet_index];
+			e = (struct routing_table_entry *)
+				entries[packet_index];
+			pkt_work_routing(p_rt, pkt, e);
+		}
+
+	return 0;
+}
+
+/*
+ * ARP table
+ */
+struct arp_table_entry {
+	struct rte_pipeline_table_entry head;
+	uint64_t macaddr;
+};
+
+static uint64_t arp_table_hash(
+	void *key,
+	__rte_unused uint32_t key_size,
+	__rte_unused uint64_t seed)
+{
+	uint32_t *k = (uint32_t *) key;
+
+	return k[1];
+}
+
+static inline void
+pkt_work_arp(
+	__rte_unused struct pipeline_routing *p_rt,
+	struct rte_mbuf *pkt,
+	struct arp_table_entry *entry)
+{
+	/* Read: pkt buffer - mbuf */
+	uint8_t *raw = rte_pktmbuf_mtod(pkt, uint8_t *);
+
+	/* Read: table entry */
+	uint64_t mac_addr_dst = entry->macaddr;
+	uint64_t mac_addr_src = 0;
+
+	/* Compute: Ethernet header */
+	uint64_t slab0 = mac_addr_dst | (mac_addr_src << 48);
+	uint32_t slab1 = mac_addr_src >> 16;
+
+	/* Write: pkt buffer - pkt headers */
+	*((uint64_t *) raw) = slab0;
+	*((uint32_t *) (raw + 8)) = slab1;
+}
+
+static inline void
+pkt4_work_arp(
+	__rte_unused struct pipeline_routing *p_rt,
+	struct rte_mbuf *pkt0,
+	struct rte_mbuf *pkt1,
+	struct rte_mbuf *pkt2,
+	struct rte_mbuf *pkt3,
+	struct arp_table_entry *entry0,
+	struct arp_table_entry *entry1,
+	struct arp_table_entry *entry2,
+	struct arp_table_entry *entry3)
+{
+	/* Read: pkt buffer - mbuf */
+	uint8_t *raw0 = rte_pktmbuf_mtod(pkt0, uint8_t *);
+	uint8_t *raw1 = rte_pktmbuf_mtod(pkt1, uint8_t *);
+	uint8_t *raw2 = rte_pktmbuf_mtod(pkt2, uint8_t *);
+	uint8_t *raw3 = rte_pktmbuf_mtod(pkt3, uint8_t *);
+
+	/* Read: table entry */
+	uint64_t mac_addr_dst0 = entry0->macaddr;
+	uint64_t mac_addr_dst1 = entry1->macaddr;
+	uint64_t mac_addr_dst2 = entry2->macaddr;
+	uint64_t mac_addr_dst3 = entry3->macaddr;
+
+	uint64_t mac_addr_src0 = 0;
+	uint64_t mac_addr_src1 = 0;
+	uint64_t mac_addr_src2 = 0;
+	uint64_t mac_addr_src3 = 0;
+
+	/* Compute: Ethernet header */
+	uint64_t pkt0_slab0 = mac_addr_dst0 | (mac_addr_src0 << 48);
+	uint64_t pkt1_slab0 = mac_addr_dst1 | (mac_addr_src1 << 48);
+	uint64_t pkt2_slab0 = mac_addr_dst2 | (mac_addr_src2 << 48);
+	uint64_t pkt3_slab0 = mac_addr_dst3 | (mac_addr_src3 << 48);
+
+	uint32_t pkt0_slab1 = mac_addr_src0 >> 16;
+	uint32_t pkt1_slab1 = mac_addr_src1 >> 16;
+	uint32_t pkt2_slab1 = mac_addr_src2 >> 16;
+	uint32_t pkt3_slab1 = mac_addr_src3 >> 16;
+
+	/* Write: pkt buffer - pkt headers */
+	*((uint64_t *) raw0) = pkt0_slab0;
+	*((uint32_t *) (raw0 + 8)) = pkt0_slab1;
+	*((uint64_t *) raw1) = pkt1_slab0;
+	*((uint32_t *) (raw1 + 8)) = pkt1_slab1;
+	*((uint64_t *) raw2) = pkt2_slab0;
+	*((uint32_t *) (raw2 + 8)) = pkt2_slab1;
+	*((uint64_t *) raw3) = pkt3_slab0;
+	*((uint32_t *) (raw3 + 8)) = pkt3_slab1;
+}
+
+static int
+arp_table_ah_hit(
+	struct rte_mbuf **pkts,
+	uint64_t *pkts_mask,
+	struct rte_pipeline_table_entry **entries,
+	__rte_unused void *arg)
+{
+	struct pipeline_routing *p_rt = arg;
+	uint64_t pkts_in_mask = *pkts_mask;
+
+	if ((pkts_in_mask & (pkts_in_mask + 1)) == 0) {
+		uint64_t n_pkts = __builtin_popcountll(pkts_in_mask);
+		uint32_t i;
+
+		for (i = 0; i < (n_pkts & 0x3); i += 4) {
+			struct rte_mbuf *pkt0 = pkts[i];
+			struct rte_mbuf *pkt1 = pkts[i + 1];
+			struct rte_mbuf *pkt2 = pkts[i + 2];
+			struct rte_mbuf *pkt3 = pkts[i + 3];
+
+			struct arp_table_entry *e0 =
+				(struct arp_table_entry *) entries[i];
+			struct arp_table_entry *e1 =
+				(struct arp_table_entry *) entries[i + 1];
+			struct arp_table_entry *e2 =
+				(struct arp_table_entry *) entries[i + 2];
+			struct arp_table_entry *e3 =
+				(struct arp_table_entry *) entries[i + 3];
+
+			pkt4_work_arp(p_rt, pkt0, pkt1, pkt2, pkt3, e0, e1, e2, e3);
+		}
+
+		for ( ; i < n_pkts; i++) {
+			struct rte_mbuf *pkt = pkts[i];
+			struct arp_table_entry *e =
+				(struct arp_table_entry *) entries[i];
+
+			pkt_work_arp(p_rt, pkt, e);
+		}
+	} else
+		for ( ; pkts_in_mask; ) {
+			struct rte_mbuf *pkt;
+			struct arp_table_entry *e;
+			uint64_t pkt_mask;
+			uint32_t packet_index;
+
+			packet_index = __builtin_ctzll(pkts_in_mask);
+			pkt_mask = 1LLU << packet_index;
+			pkts_in_mask &= ~pkt_mask;
+
+			pkt = pkts[packet_index];
+			e = (struct arp_table_entry *)
+				entries[packet_index];
+			pkt_work_arp(p_rt, pkt, e);
+		}
+
+	return 0;
+}
+
+static int
+pipeline_routing_parse_args(struct pipeline_routing *p,
+	struct pipeline_params *params)
+{
+	uint32_t n_routes_present = 0;
+	uint32_t n_arp_entries_present = 0;
+	uint32_t n_arp_entries_ext_present = 0;
+	uint32_t ip_da_offset_present = 0;
+	uint32_t arp_key_offset_present = 0;
+	uint32_t i;
+
+	for (i = 0; i < params->n_args; i++) {
+		char *arg_name = params->args_name[i];
+		char *arg_value = params->args_value[i];
+
+		/* n_routes */
+		if (strcmp(arg_name, "n_routes") == 0) {
+			if (n_routes_present)
+				return -1;
+			n_routes_present = 1;
+
+			p->n_routes = atoi(arg_value);
+			if (p->n_routes == 0)
+				return -1;
+
+			continue;
+		}
+
+		/* n_arp_entries */
+		if (strcmp(arg_name, "n_arp_entries") == 0) {
+			if (n_arp_entries_present)
+				return -1;
+			n_arp_entries_present = 1;
+
+			p->n_arp_entries = atoi(arg_value);
+			if (p->n_arp_entries == 0)
+				return -1;
+
+			continue;
+		}
+
+		/* n_arp_entries_ext */
+		if (strcmp(arg_name, "n_arp_entries_ext") == 0) {
+			if (n_arp_entries_ext_present)
+				return -1;
+			n_arp_entries_ext_present = 1;
+
+			p->n_arp_entries_ext = atoi(arg_value);
+			if (p->n_arp_entries_ext == 0)
+				return -1;
+
+			continue;
+		}
+
+		/* ip_da_offset */
+		if (strcmp(arg_name, "ip_da_offset") == 0) {
+			if (ip_da_offset_present)
+				return -1;
+			ip_da_offset_present = 1;
+
+			p->ip_da_offset = atoi(arg_value);
+
+			continue;
+		}
+
+		/* arp_key_offset */
+		if (strcmp(arg_name, "arp_key_offset") == 0) {
+			if (arp_key_offset_present)
+				return -1;
+			arp_key_offset_present = 1;
+
+			p->arp_key_offset = atoi(arg_value);
+
+			continue;
+		}
+
+		/* any other */
+		return -1;
+	}
+
+	/* Check that mandatory arguments are present */
+	if ((n_routes_present == 0) ||
+		(n_arp_entries_present == 0) ||
+		(n_arp_entries_ext_present == 0) ||
+		(ip_da_offset_present == 0) ||
+		(n_arp_entries_present && (arp_key_offset_present == 0)))
+		return -1;
+
+	return 0;
+}
+
+static void *
+pipeline_routing_init(struct pipeline_params *params,
+	__rte_unused void *arg)
+{
+	struct pipeline *p;
+	struct pipeline_routing *p_rt;
+	uint32_t size, i;
+
+	/* Check input arguments */
+	if ((params == NULL) ||
+		(params->n_ports_in == 0) ||
+		(params->n_ports_out == 0))
+		return NULL;
+
+	/* Memory allocation */
+	size = RTE_CACHE_LINE_ROUNDUP(sizeof(struct pipeline_routing));
+	p = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
+	p_rt = (struct pipeline_routing *) p;
+	if (p == NULL)
+		return NULL;
+
+	strcpy(p->name, params->name);
+
+	/* Parse arguments */
+	if (pipeline_routing_parse_args(p_rt, params))
+		return NULL;
+
+	/* Pipeline */
+	{
+		struct rte_pipeline_params pipeline_params = {
+			.name = params->name,
+			.socket_id = params->socket_id,
+			.offset_port_id = 0,
+		};
+
+		p->p = rte_pipeline_create(&pipeline_params);
+		if (p->p == NULL) {
+			rte_free(p);
+			return NULL;
+		}
+	}
+
+	/* Input ports */
+	p->n_ports_in = params->n_ports_in;
+	for (i = 0; i < p->n_ports_in; i++) {
+		struct rte_pipeline_port_in_params port_params = {
+			.ops = pipeline_port_in_params_get_ops(&params->port_in[i]),
+			.arg_create = pipeline_port_in_params_convert(&params->port_in[i]),
+			.f_action = NULL,
+			.arg_ah = NULL,
+			.burst_size = params->port_in[i].burst_size,
+		};
+
+		int status = rte_pipeline_port_in_create(p->p,
+			&port_params,
+			&p->port_in_id[i]);
+
+		if (status) {
+			rte_pipeline_free(p->p);
+			rte_free(p);
+			return NULL;
+		}
+	}
+
+	/* Output ports */
+	p->n_ports_out = params->n_ports_out;
+	for (i = 0; i < p->n_ports_out; i++) {
+		struct rte_pipeline_port_out_params port_params = {
+			.ops = pipeline_port_out_params_get_ops(&params->port_out[i]),
+			.arg_create = pipeline_port_out_params_convert(&params->port_out[i]),
+			.f_action = NULL,
+			.f_action_bulk = NULL,
+			.arg_ah = NULL,
+		};
+
+		int status = rte_pipeline_port_out_create(p->p,
+			&port_params,
+			&p->port_out_id[i]);
+
+		if (status) {
+			rte_pipeline_free(p->p);
+			rte_free(p);
+			return NULL;
+		}
+	}
+
+	/* Routing table */
+	p->n_tables = 1;
+	{
+		struct rte_table_lpm_params table_lpm_params = {
+			.n_rules = p_rt->n_routes,
+			.entry_unique_size = sizeof(struct routing_table_entry),
+			.offset = p_rt->ip_da_offset,
+		};
+
+		struct rte_pipeline_table_params table_params = {
+				.ops = &rte_table_lpm_ops,
+				.arg_create = &table_lpm_params,
+				.f_action_hit = routing_table_ah_hit,
+				.f_action_miss = NULL,
+				.arg_ah = p_rt,
+				.action_data_size = 
+					sizeof(struct routing_table_entry) -
+					sizeof(struct rte_pipeline_table_entry),
+			};
+
+		int status;
+
+		status = rte_pipeline_table_create(p->p,
+			&table_params,
+			&p->table_id[0]);
+
+		if (status) {
+			rte_pipeline_free(p->p);
+			rte_free(p);
+			return NULL;
+		}
+	}
+
+	/* ARP table configuration */
+	if (p_rt->n_arp_entries) {
+		struct rte_table_hash_key8_ext_params table_arp_params = {
+			.n_entries = p_rt->n_arp_entries,
+			.n_entries_ext = p_rt->n_arp_entries_ext,
+			.f_hash = arp_table_hash,
+			.seed = 0,
+			.signature_offset = 0, /* Unused */
+			.key_offset = p_rt->arp_key_offset,
+		};
+
+		struct rte_pipeline_table_params table_params = {
+			.ops = &rte_table_hash_key8_ext_dosig_ops,
+			.arg_create = &table_arp_params,
+			.f_action_hit = arp_table_ah_hit,
+			.f_action_miss = NULL,
+			.arg_ah = p_rt,
+			.action_data_size = sizeof(struct arp_table_entry) -
+				sizeof(struct rte_pipeline_table_entry),
+		};
+
+		int status;
+
+		status = rte_pipeline_table_create(p->p,
+			&table_params,
+			&p->table_id[1]);
+
+		if (status) {
+			rte_pipeline_free(p->p);
+			rte_free(p);
+			return NULL;
+		}
+
+		p->n_tables ++;
+	}
+
+	/* Connecting input ports to tables */
+	for (i = 0; i < p->n_ports_in; i++) {
+		int status = rte_pipeline_port_in_connect_to_table(p->p,
+			p->port_in_id[i],
+			p->table_id[0]);
+
+		if (status) {
+			rte_pipeline_free(p->p);
+			rte_free(p);
+			return NULL;
+		}
+	}
+
+	/* Enable input ports */
+	for (i = 0; i < p->n_ports_in; i++) {
+		int status = rte_pipeline_port_in_enable(p->p,
+			p->port_in_id[i]);
+
+		if (status) {
+			rte_pipeline_free(p->p);
+			rte_free(p);
+			return NULL;
+		}
+	}
+
+	/* Check pipeline consistency */
+	if (rte_pipeline_check(p->p) < 0) {
+		rte_pipeline_free(p->p);
+		rte_free(p);
+		return NULL;
+	}
+
+	/* Message queues */
+	p->n_msgq = params->n_msgq;
+	for (i = 0; i < p->n_msgq; i++)
+		p->msgq_in[i] = params->msgq_in[i];
+	for (i = 0; i < p->n_msgq; i++)
+		p->msgq_out[i] = params->msgq_out[i];
+
+	/* Message handlers */
+	memcpy(p->handlers, handlers, sizeof(p->handlers));
+	memcpy(p_rt->custom_handlers,
+		custom_handlers,
+		sizeof(p_rt->custom_handlers));
+
+	return p;
+}
+
+static int
+pipeline_routing_free(void *pipeline)
+{
+	struct pipeline *p = (struct pipeline *) pipeline;
+
+	/* Check input arguments */
+	if (p == NULL)
+		return -1;
+
+	/* Free resources */
+	rte_pipeline_free(p->p);
+	rte_free(p);
+	return 0;
+}
+
+static int
+pipeline_routing_track(void *pipeline,
+	__rte_unused uint32_t port_in,
+	uint32_t *port_out)
+{
+	struct pipeline *p = (struct pipeline *) pipeline;
+
+	/* Check input arguments */
+	if ((p == NULL) ||
+		(port_in >= p->n_ports_in) ||
+		(port_out == NULL))
+		return -1;
+
+	if (p->n_ports_in == 1) {
+		*port_out = 0;
+		return 0;
+	}
+
+	return -1;
+}
+
+static int
+pipeline_routing_timer(void *pipeline)
+{
+	struct pipeline *p = (struct pipeline *) pipeline;
+
+	pipeline_msg_req_handle(p);
+	rte_pipeline_flush(p->p);
+
+	return 0;
+}
+
+void *
+pipeline_routing_msg_req_custom_handler(struct pipeline *p,
+	void *msg)
+{
+	struct pipeline_routing *p_rt = (struct pipeline_routing *) p;
+	struct pipeline_custom_msg_req *req = msg;
+	pipeline_msg_req_handler f_handle;
+
+	f_handle = (req->subtype < PIPELINE_ROUTING_MSG_REQS)?
+		p_rt->custom_handlers[req->subtype] :
+		pipeline_msg_req_invalid_handler;
+
+	if (f_handle == NULL)
+		f_handle = pipeline_msg_req_invalid_handler;
+
+	return f_handle(p, req);
+}
+
+void *
+pipeline_routing_msg_req_route_add_handler(struct pipeline *p, void *msg)
+{
+	struct pipeline_routing_route_add_msg_req *req = msg;
+	struct pipeline_routing_route_add_msg_rsp *rsp = msg;
+
+	struct rte_table_lpm_key key = {
+		.ip = req->key.key.ipv4.ip,
+		.depth = req->key.key.ipv4.depth,
+	};
+
+	struct routing_table_entry entry = {
+		.head = {
+			.action = RTE_PIPELINE_ACTION_TABLE,
+			{.table_id = p->table_id[1]},
+		},
+
+		.flags = req->flags,
+		.port_id = req->port_id,
+		.ip = req->ip,
+	};
+
+	if (req->key.type != PIPELINE_ROUTING_ROUTE_IPV4) {
+		rsp->status = -1;
+		return rsp;
+	}
+
+	rsp->status = rte_pipeline_table_entry_add(p->p,
+		p->table_id[0],
+		&key,
+		(struct rte_pipeline_table_entry *) &entry,
+		&rsp->key_found,
+		(struct rte_pipeline_table_entry **) &rsp->entry_ptr);
+
+	RTE_LOG(INFO, USER1, "%s Back-End: Key %s\n",
+		p->name,
+		(rsp->key_found)? "found" : "not found");
+
+	return rsp;
+}
+
+void *
+pipeline_routing_msg_req_route_del_handler(struct pipeline *p, void *msg)
+{
+	struct pipeline_routing_route_delete_msg_req *req = msg;
+	struct pipeline_routing_route_delete_msg_rsp *rsp = msg;
+
+	struct rte_table_lpm_key key = {
+		.ip = req->key.key.ipv4.ip,
+		.depth = req->key.key.ipv4.depth,
+	};
+
+	if (req->key.type != PIPELINE_ROUTING_ROUTE_IPV4) {
+		rsp->status = -1;
+		return rsp;
+	}
+
+	rsp->status = rte_pipeline_table_entry_delete(p->p,
+		p->table_id[0],
+		&key,
+		&rsp->key_found,
+		NULL);
+
+	RTE_LOG(INFO, USER1, "%s Back-End: Key %s\n",
+		p->name,
+		(rsp->key_found)? "found" : "not found");
+
+	return rsp;
+}
+
+void *
+pipeline_routing_msg_req_route_add_default_handler(struct pipeline *p, void *msg)
+{
+	struct pipeline_routing_route_add_default_msg_req *req = msg;
+	struct pipeline_routing_route_add_default_msg_rsp *rsp = msg;
+
+	struct routing_table_entry default_entry = {
+		.head = {
+			.action = RTE_PIPELINE_ACTION_PORT,
+			{.port_id = p->port_out_id[req->port_id]},
+		},
+
+		.flags = 0,
+		.port_id = 0,
+		.ip = 0,
+	};
+
+	rsp->status = rte_pipeline_table_default_entry_add(p->p,
+		p->table_id[0],
+		(struct rte_pipeline_table_entry *) &default_entry,
+		(struct rte_pipeline_table_entry **) &rsp->entry_ptr);
+
+	return rsp;
+}
+
+void *
+pipeline_routing_msg_req_route_del_default_handler(struct pipeline *p, void *msg)
+{
+	struct pipeline_routing_route_delete_default_msg_rsp *rsp = msg;
+
+	rsp->status = rte_pipeline_table_default_entry_delete(p->p,
+		p->table_id[0],
+		NULL);
+
+	return rsp;
+}
+
+void *
+pipeline_routing_msg_req_arp_add_handler(struct pipeline *p, void *msg)
+{
+	struct pipeline_routing_arp_add_msg_req *req = msg;
+	struct pipeline_routing_arp_add_msg_rsp *rsp = msg;
+
+	struct pipeline_routing_arp_key key = {
+		.type = PIPELINE_ROUTING_ARP_IPV4,
+		.key = {
+			.ipv4 = {
+				.port_id = req->key.key.ipv4.port_id,
+				.ip = req->key.key.ipv4.ip,
+			},
+		},
+	};
+
+	struct arp_table_entry entry = {
+		.head = {
+			.action = RTE_PIPELINE_ACTION_PORT,
+			{.port_id = p->port_out_id[req->key.key.ipv4.port_id]},
+		},
+
+		.macaddr = 0,
+	};
+
+	if (req->key.type != PIPELINE_ROUTING_ARP_IPV4) {
+		rsp->status = -1;
+		return rsp;
+	}
+
+	*((struct ether_addr *) &entry.macaddr) = req->macaddr;
+
+	rsp->status = rte_pipeline_table_entry_add(p->p,
+		p->table_id[1],
+		&key.key.ipv4,
+		(struct rte_pipeline_table_entry *) &entry,
+		&rsp->key_found,
+		(struct rte_pipeline_table_entry **) &rsp->entry_ptr);
+
+	RTE_LOG(INFO, USER1, "%s Back-End: Key %s\n",
+		p->name,
+		(rsp->key_found)? "found" : "not found");
+
+	return rsp;
+}
+
+void *
+pipeline_routing_msg_req_arp_del_handler(struct pipeline *p, void *msg)
+{
+	struct pipeline_routing_arp_delete_msg_req *req = msg;
+	struct pipeline_routing_arp_delete_msg_rsp *rsp = msg;
+
+	struct pipeline_routing_arp_key key = {
+		.type = PIPELINE_ROUTING_ARP_IPV4,
+		.key = {
+			.ipv4 = {
+				.port_id = req->key.key.ipv4.port_id,
+				.ip = req->key.key.ipv4.ip,
+			},
+		},
+	};
+
+	if (req->key.type != PIPELINE_ROUTING_ARP_IPV4) {
+		rsp->status = -1;
+		return rsp;
+	}
+
+	rsp->status = rte_pipeline_table_entry_delete(p->p,
+		p->table_id[1],
+		&key,
+		&rsp->key_found,
+		NULL);
+
+	RTE_LOG(INFO, USER1, "%s Back-End: Key %s\n",
+		p->name,
+		(rsp->key_found)? "found" : "not found");
+
+	return rsp;
+}
+
+void *
+pipeline_routing_msg_req_arp_add_default_handler(struct pipeline *p, void *msg)
+{
+	struct pipeline_routing_arp_add_default_msg_req *req = msg;
+	struct pipeline_routing_arp_add_default_msg_rsp *rsp = msg;
+
+	struct arp_table_entry default_entry = {
+		.head = {
+			.action = RTE_PIPELINE_ACTION_PORT,
+			{.port_id = p->port_out_id[req->port_id]},
+		},
+
+		.macaddr = 0,
+	};
+
+	rsp->status = rte_pipeline_table_default_entry_add(p->p,
+		p->table_id[1],
+		(struct rte_pipeline_table_entry *) &default_entry,
+		(struct rte_pipeline_table_entry **) &rsp->entry_ptr);
+
+	return rsp;
+}
+
+void *
+pipeline_routing_msg_req_arp_del_default_handler(struct pipeline *p, void *msg)
+{
+	struct pipeline_routing_arp_delete_default_msg_rsp *rsp = msg;
+
+	rsp->status = rte_pipeline_table_default_entry_delete(p->p,
+		p->table_id[1],
+		NULL);
+
+	return rsp;
+}
+
+struct pipeline_ops pipeline_routing_ops = {
+		.f_init = pipeline_routing_init,
+		.f_free = pipeline_routing_free,
+		.f_run = NULL,
+		.f_timer = pipeline_routing_timer,
+		.f_track = pipeline_routing_track,
+};
diff --git a/examples/ip_pipeline/pipeline/pipeline_routing_ops.h b/examples/ip_pipeline/pipeline/pipeline_routing_ops.h
new file mode 100644
index 0000000..303b562
--- /dev/null
+++ b/examples/ip_pipeline/pipeline/pipeline_routing_ops.h
@@ -0,0 +1,231 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __INCLUDE_PIPELINE_ROUTING_OPS_H__
+#define __INCLUDE_PIPELINE_ROUTING_OPS_H__
+
+#include <rte_ether.h>
+
+#include "pipeline_common_ops.h"
+#include "pipeline_ops.h"
+
+/*
+ * Route
+ */
+enum pipeline_routing_route_key_type {
+	PIPELINE_ROUTING_ROUTE_IPV4,
+};
+
+struct pipeline_routing_route_key_ipv4 {
+	uint32_t ip;
+	uint8_t depth;
+};
+
+struct pipeline_routing_route_key {
+	enum pipeline_routing_route_key_type type;
+	union {
+		struct pipeline_routing_route_key_ipv4 ipv4;
+	} key;
+};
+
+enum pipeline_routing_route_flags {
+	PIPELINE_ROUTING_ROUTE_LOCAL = 1 << 0, /* 0 = remote; 1 = local */
+};
+
+/*
+ * ARP
+ */
+enum pipeline_routing_arp_key_type {
+	PIPELINE_ROUTING_ARP_IPV4,
+};
+
+struct pipeline_routing_arp_key_ipv4 {
+	uint32_t port_id;
+	uint32_t ip;
+};
+
+struct pipeline_routing_arp_key {
+	enum pipeline_routing_arp_key_type type;
+	union {
+		struct pipeline_routing_arp_key_ipv4 ipv4;
+	} key;
+};
+
+/*
+ * Messages
+ */
+enum pipeline_routing_msg_req_type {
+	PIPELINE_ROUTING_MSG_REQ_ROUTE_ADD,
+	PIPELINE_ROUTING_MSG_REQ_ROUTE_DEL,
+	PIPELINE_ROUTING_MSG_REQ_ROUTE_ADD_DEFAULT,
+	PIPELINE_ROUTING_MSG_REQ_ROUTE_DEL_DEFAULT,
+	PIPELINE_ROUTING_MSG_REQ_ARP_ADD,
+	PIPELINE_ROUTING_MSG_REQ_ARP_DEL,
+	PIPELINE_ROUTING_MSG_REQ_ARP_ADD_DEFAULT,
+	PIPELINE_ROUTING_MSG_REQ_ARP_DEL_DEFAULT,
+	PIPELINE_ROUTING_MSG_REQS
+};
+
+/*
+ * MSG ROUTE ADD
+ */
+struct pipeline_routing_route_add_msg_req {
+	enum pipeline_msg_req_type type;
+	enum pipeline_routing_msg_req_type subtype;
+
+	/* key */
+	struct pipeline_routing_route_key key;
+
+	/* data */
+	enum pipeline_routing_route_flags flags;
+	uint32_t port_id; /* Output port ID */
+	uint32_t ip; /* IP address for the next hop (only valid for remote routes) */
+};
+
+struct pipeline_routing_route_add_msg_rsp {
+	int status;
+	int key_found;
+	void *entry_ptr;
+};
+
+/*
+ * MSG ROUTE DELETE
+ */
+struct pipeline_routing_route_delete_msg_req {
+	enum pipeline_msg_req_type type;
+	enum pipeline_routing_msg_req_type subtype;
+
+	/* key */
+	struct pipeline_routing_route_key key;
+};
+
+struct pipeline_routing_route_delete_msg_rsp {
+	int status;
+	int key_found;
+};
+
+/*
+ * MSG ROUTE ADD DEFAULT
+ */
+struct pipeline_routing_route_add_default_msg_req {
+	enum pipeline_msg_req_type type;
+	enum pipeline_routing_msg_req_type subtype;
+
+	/* data */
+	uint32_t port_id;
+};
+
+struct pipeline_routing_route_add_default_msg_rsp {
+	int status;
+	void *entry_ptr;
+};
+
+/*
+ * MSG ROUTE DELETE DEFAULT
+ */
+struct pipeline_routing_route_delete_default_msg_req {
+	enum pipeline_msg_req_type type;
+	enum pipeline_routing_msg_req_type subtype;
+};
+
+struct pipeline_routing_route_delete_default_msg_rsp {
+	int status;
+};
+
+/*
+ * MSG ARP ADD
+ */
+struct pipeline_routing_arp_add_msg_req {
+	enum pipeline_msg_req_type type;
+	enum pipeline_routing_msg_req_type subtype;
+
+	/* key */
+	struct pipeline_routing_arp_key key;
+
+	/* data */
+	struct ether_addr macaddr;
+};
+
+struct pipeline_routing_arp_add_msg_rsp {
+	int status;
+	int key_found;
+	void *entry_ptr;
+};
+
+/*
+ * MSG ARP DELETE
+ */
+struct pipeline_routing_arp_delete_msg_req {
+	enum pipeline_msg_req_type type;
+	enum pipeline_routing_msg_req_type subtype;
+
+	/* key */
+	struct pipeline_routing_arp_key key;
+};
+
+struct pipeline_routing_arp_delete_msg_rsp {
+	int status;
+	int key_found;
+};
+
+/*
+ * MSG ARP ADD DEFAULT
+ */
+struct pipeline_routing_arp_add_default_msg_req {
+	enum pipeline_msg_req_type type;
+	enum pipeline_routing_msg_req_type subtype;
+
+	/* data */
+	uint32_t port_id;
+};
+
+struct pipeline_routing_arp_add_default_msg_rsp {
+	int status;
+	void *entry_ptr;
+};
+
+/*
+ * MSG ARP DELETE DEFAULT
+ */
+struct pipeline_routing_arp_delete_default_msg_req {
+	enum pipeline_msg_req_type type;
+	enum pipeline_routing_msg_req_type subtype;
+};
+
+struct pipeline_routing_arp_delete_default_msg_rsp {
+	int status;
+};
+
+extern struct pipeline_ops pipeline_routing_ops;
+
+#endif
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 11/11] ip_pipeline: added new implementation of flow classification pipeline
  2015-05-29 15:43 [PATCH 00/11] ip_pipeline: ip_pipeline application enhancements Maciej Gajdzica
                   ` (9 preceding siblings ...)
  2015-05-29 15:43 ` [PATCH 10/11] ip_pipeline: added new implementation of routing pipeline Maciej Gajdzica
@ 2015-05-29 15:43 ` Maciej Gajdzica
  2015-06-23 13:48 ` [PATCH 00/11] ip_pipeline: ip_pipeline application enhancements Thomas Monjalon
  11 siblings, 0 replies; 16+ messages in thread
From: Maciej Gajdzica @ 2015-05-29 15:43 UTC (permalink / raw)
  To: dev

Flow classification pipeline implementation is split to two files.
pipeline_flow_classification.c file handles front-end functions (cli
commands parsing) pipeline_flow_classification_ops.c contains
implementation of functions done by pipeline (back-end).

Signed-off-by: Maciej Gajdzica <maciejx.t.gajdzica@intel.com>
---
 examples/ip_pipeline/Makefile                      |    3 +-
 examples/ip_pipeline/init.c                        |    2 +
 .../pipeline/pipeline_flow_classification.c        | 1761 +++++++++++++++++---
 .../pipeline/pipeline_flow_classification.h        |   41 +
 .../pipeline/pipeline_flow_classification_ops.c    |  559 +++++++
 .../pipeline/pipeline_flow_classification_ops.h    |  150 ++
 6 files changed, 2292 insertions(+), 224 deletions(-)
 create mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_classification.h
 create mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_classification_ops.c
 create mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_classification_ops.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index f8c7c5f..4a1d970 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -65,7 +65,8 @@ SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_firewall_ops.c
 SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_firewall.c
 SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_routing_ops.c
 SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_routing.c
-#SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_flow_classification.c
+SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_flow_classification.c
+SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_flow_classification_ops.c
 
 CFLAGS += -I$(SRCDIR) -I$(SRCDIR)/pipeline
 CFLAGS += -O3
diff --git a/examples/ip_pipeline/init.c b/examples/ip_pipeline/init.c
index 29caae8..a8d2f67 100644
--- a/examples/ip_pipeline/init.c
+++ b/examples/ip_pipeline/init.c
@@ -47,6 +47,7 @@
 #include "pipeline_passthrough.h"
 #include "pipeline_firewall.h"
 #include "pipeline_routing.h"
+#include "pipeline_flow_classification.h"
 
 #define APP_NAME_SIZE	32
 
@@ -1150,6 +1151,7 @@ int app_init(struct app_params *app)
 	app_pipeline_type_register(app, &pipeline_passthrough);
 	app_pipeline_type_register(app, &pipeline_firewall);
 	app_pipeline_type_register(app, &pipeline_routing);
+	app_pipeline_type_register(app, &pipeline_flow_classification);
 
 	app_init_pipelines(app);
 	app_init_threads(app);
diff --git a/examples/ip_pipeline/pipeline/pipeline_flow_classification.c b/examples/ip_pipeline/pipeline/pipeline_flow_classification.c
index cc0cbf1..928e2ab 100644
--- a/examples/ip_pipeline/pipeline/pipeline_flow_classification.c
+++ b/examples/ip_pipeline/pipeline/pipeline_flow_classification.c
@@ -1,7 +1,7 @@
 /*-
  *   BSD LICENSE
  *
- *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
  *   All rights reserved.
  *
  *   Redistribution and use in source and binary forms, with or without
@@ -32,275 +32,1590 @@
  */
 
 #include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
+#include <string.h>
+#include <sys/queue.h>
+#include <netinet/in.h>
 
+#include <rte_common.h>
 #include <rte_malloc.h>
-#include <rte_log.h>
-#include <rte_ethdev.h>
-#include <rte_ether.h>
-#include <rte_ip.h>
-#include <rte_byteorder.h>
+#include <cmdline_rdline.h>
+#include <cmdline_parse.h>
+#include <cmdline_parse_num.h>
+#include <cmdline_parse_string.h>
+#include <cmdline_parse_ipaddr.h>
+#include <cmdline_parse_etheraddr.h>
 
-#include <rte_port_ring.h>
-#include <rte_table_hash.h>
-#include <rte_pipeline.h>
+#include "app.h"
+#include "pipeline_flow_classification_ops.h"
+#include "pipeline_flow_classification.h"
+#include "pipeline_common.h"
 
-#include "main.h"
+#define MSG_TIMEOUT 1000
 
-struct app_core_fc_message_handle_params {
-	struct rte_ring *ring_req;
-	struct rte_ring *ring_resp;
+struct app_pipeline_fc_flow {
+	struct pipeline_fc_key key;
+	uint32_t port_id;
+	void *entry_ptr;
 
-	struct rte_pipeline *p;
-	uint32_t *port_out_id;
-	uint32_t table_id;
+	TAILQ_ENTRY(app_pipeline_fc_flow) node;
 };
 
+struct app_pipeline_fc {
+	TAILQ_HEAD(, app_pipeline_fc_flow) flows;
+
+	uint32_t n_flows;
+};
+
+static struct app_pipeline_fc_flow *
+app_pipeline_fc_flow_find(struct app_pipeline_fc *p,
+	struct pipeline_fc_key *key)
+{
+	struct app_pipeline_fc_flow *f;
+
+	TAILQ_FOREACH(f, &p->flows, node)
+		if (memcmp(key, &f->key, sizeof(struct pipeline_fc_key)) == 0)
+			return f;
+
+	return NULL;
+}
+
+static void
+print_fc_qinq_flow(struct app_pipeline_fc_flow *flow)
+{
+	printf("svlan = %u, "
+		   "cvlan = %u "
+		   "=> Port = %u "
+		   "(entry_ptr = %p)\n",
+
+		   flow->key.key.qinq.svlan,
+		   flow->key.key.qinq.cvlan,
+		   flow->port_id,
+		   flow->entry_ptr);
+}
+
 static void
-app_message_handle(struct app_core_fc_message_handle_params *params);
+print_fc_ipv4_5tuple_flow(struct app_pipeline_fc_flow *flow)
+{
+	printf("SA = %u.%u.%u.%u "
+		   "DA = %u.%u.%u.%u "
+		   "SP = %u "
+		   "DP = %u "
+		   "Proto = %u "
+		   "=> Port = %u "
+		   "(entry_ptr = %p)\n",
+
+		   (flow->key.key.ipv4_5tuple.ip_src >> 24) & 0xFF,
+		   (flow->key.key.ipv4_5tuple.ip_src >> 16) & 0xFF,
+		   (flow->key.key.ipv4_5tuple.ip_src >> 8) & 0xFF,
+		   flow->key.key.ipv4_5tuple.ip_src & 0xFF,
+
+		   (flow->key.key.ipv4_5tuple.ip_dst >> 24) & 0xFF,
+		   (flow->key.key.ipv4_5tuple.ip_dst >> 16) & 0xFF,
+		   (flow->key.key.ipv4_5tuple.ip_dst >> 8) & 0xFF,
+		   flow->key.key.ipv4_5tuple.ip_dst & 0xFF,
+
+		   flow->key.key.ipv4_5tuple.port_src,
+		   flow->key.key.ipv4_5tuple.port_dst,
+
+		   flow->key.key.ipv4_5tuple.proto,
+
+		   flow->port_id,
+		   flow->entry_ptr);
+}
+
+static void
+print_fc_ipv6_5tuple_flow(struct app_pipeline_fc_flow *flow)
+{
+	printf("SA = %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x "
+		   "DA = %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x "
+		   "SP = %u "
+		   "DP = %u "
+		   "Proto = %u "
+		   "=> Port = %u "
+		   "(entry_ptr = %p)\n",
+
+		   flow->key.key.ipv6_5tuple.ip_src[0],
+		   flow->key.key.ipv6_5tuple.ip_src[1],
+		   flow->key.key.ipv6_5tuple.ip_src[2],
+		   flow->key.key.ipv6_5tuple.ip_src[3],
+		   flow->key.key.ipv6_5tuple.ip_src[4],
+		   flow->key.key.ipv6_5tuple.ip_src[5],
+		   flow->key.key.ipv6_5tuple.ip_src[6],
+		   flow->key.key.ipv6_5tuple.ip_src[7],
+		   flow->key.key.ipv6_5tuple.ip_src[8],
+		   flow->key.key.ipv6_5tuple.ip_src[9],
+		   flow->key.key.ipv6_5tuple.ip_src[10],
+		   flow->key.key.ipv6_5tuple.ip_src[11],
+		   flow->key.key.ipv6_5tuple.ip_src[12],
+		   flow->key.key.ipv6_5tuple.ip_src[13],
+		   flow->key.key.ipv6_5tuple.ip_src[14],
+		   flow->key.key.ipv6_5tuple.ip_src[15],
+
+		   flow->key.key.ipv6_5tuple.ip_dst[0],
+		   flow->key.key.ipv6_5tuple.ip_dst[1],
+		   flow->key.key.ipv6_5tuple.ip_dst[2],
+		   flow->key.key.ipv6_5tuple.ip_dst[3],
+		   flow->key.key.ipv6_5tuple.ip_dst[4],
+		   flow->key.key.ipv6_5tuple.ip_dst[5],
+		   flow->key.key.ipv6_5tuple.ip_dst[6],
+		   flow->key.key.ipv6_5tuple.ip_dst[7],
+		   flow->key.key.ipv6_5tuple.ip_dst[8],
+		   flow->key.key.ipv6_5tuple.ip_dst[9],
+		   flow->key.key.ipv6_5tuple.ip_dst[10],
+		   flow->key.key.ipv6_5tuple.ip_dst[11],
+		   flow->key.key.ipv6_5tuple.ip_dst[12],
+		   flow->key.key.ipv6_5tuple.ip_dst[13],
+		   flow->key.key.ipv6_5tuple.ip_dst[14],
+		   flow->key.key.ipv6_5tuple.ip_dst[15],
 
-static int app_flow_classification_table_init(
-	struct rte_pipeline *p,
-	uint32_t *port_out_id,
-	uint32_t table_id)
+		   flow->key.key.ipv6_5tuple.port_src,
+		   flow->key.key.ipv6_5tuple.port_dst,
+
+		   flow->key.key.ipv6_5tuple.proto,
+
+		   flow->port_id,
+		   flow->entry_ptr);
+}
+
+static void
+print_fc_flow(struct app_pipeline_fc_flow *flow)
 {
-	struct app_flow_key flow_key;
-	uint32_t i;
-
-	/* Add entries to tables */
-	for (i = 0; i < (1 << 24); i++) {
-		struct rte_pipeline_table_entry entry = {
-			.action = RTE_PIPELINE_ACTION_PORT,
-			{.port_id = port_out_id[i & (app.n_ports - 1)]},
-		};
-		struct rte_pipeline_table_entry *entry_ptr;
-		int key_found, status;
-
-		flow_key.ttl = 0;
-		flow_key.proto = 6; /* TCP */
-		flow_key.header_checksum = 0;
-		flow_key.ip_src = 0;
-		flow_key.ip_dst = rte_bswap32(i);
-		flow_key.port_src = 0;
-		flow_key.port_dst = 0;
-
-		status = rte_pipeline_table_entry_add(p, table_id,
-			(void *) &flow_key, &entry, &key_found, &entry_ptr);
-		if (status < 0)
-			rte_panic("Unable to add entry to table %u (%d)\n",
-				table_id, status);
+	switch(flow->key.type) {
+	case FLOW_KEY_QINQ:
+		print_fc_qinq_flow(flow);
+		break;
+	case FLOW_KEY_IPV4_5TUPLE:
+		print_fc_ipv4_5tuple_flow(flow);
+		break;
+	case FLOW_KEY_IPV6_5TUPLE:
+		print_fc_ipv6_5tuple_flow(flow);
+		break;
 	}
+}
 
-	return 0;
+static void
+app_pipeline_fc_qinq_default_set(struct pipeline_fc_key *default_key)
+{
+	default_key->key.qinq.svlan = 0xFFFF;
+	default_key->key.qinq.cvlan = 0xFFFF;
 }
 
-void
-app_main_loop_pipeline_flow_classification(void) {
-	struct rte_pipeline_params pipeline_params = {
-		.name = "pipeline",
-		.socket_id = rte_socket_id(),
-	};
+static void
+app_pipeline_fc_ipv4_5tuple_default_set(struct pipeline_fc_key *default_key)
+{
+	default_key->key.ipv4_5tuple.ip_src = 0;
+	default_key->key.ipv4_5tuple.ip_dst = 0;
+	default_key->key.ipv4_5tuple.port_src = 0;
+	default_key->key.ipv4_5tuple.port_dst = 0;
+	default_key->key.ipv4_5tuple.proto = 0xFF;
+}
+
+static void
+app_pipeline_fc_ipv6_5tuple_default_set(struct pipeline_fc_key *default_key)
+{
+	memset(default_key->key.ipv6_5tuple.ip_src, 0, 16);
+	memset(default_key->key.ipv6_5tuple.ip_dst, 0, 16);
+	default_key->key.ipv6_5tuple.port_src = 0;
+	default_key->key.ipv6_5tuple.port_dst = 0;
+	default_key->key.ipv6_5tuple.proto = 0xFF;
+}
 
-	struct rte_pipeline *p;
-	uint32_t port_in_id[APP_MAX_PORTS];
-	uint32_t port_out_id[APP_MAX_PORTS];
-	uint32_t table_id;
-	uint32_t i;
+static void*
+app_pipeline_fc_init(struct pipeline_params *params,
+	__rte_unused void *arg)
+{
+	struct app_pipeline_fc *p;
+	uint32_t size;
+
+	/* Check input arguments */
+	if ((params == NULL))
+		return NULL;
+
+	/* Memory allocation */
+	size = RTE_CACHE_LINE_ROUNDUP(sizeof(struct app_pipeline_fc));
+	p = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
+	if (p == NULL)
+		return NULL;
 
-	uint32_t core_id = rte_lcore_id();
-	struct app_core_params *core_params = app_get_core_params(core_id);
-	struct app_core_fc_message_handle_params mh_params;
+	/* Initialization */
+	TAILQ_INIT(&p->flows);
+	p->n_flows = 0;
 
-	if ((core_params == NULL) || (core_params->core_type != APP_CORE_FC))
-		rte_panic("Core %u misconfiguration\n", core_id);
+	return (void *) p;
+}
 
-	RTE_LOG(INFO, USER1, "Core %u is doing flow classification "
-		"(pipeline with hash table, 16-byte key, LRU)\n", core_id);
+static int
+app_pipeline_fc_free(void *pipeline)
+{
+	struct app_pipeline_fc *p = pipeline;
+	struct app_pipeline_fc_flow *flow;
 
-	/* Pipeline configuration */
-	p = rte_pipeline_create(&pipeline_params);
+	/* Check input arguments */
 	if (p == NULL)
-		rte_panic("Unable to configure the pipeline\n");
-
-	/* Input port configuration */
-	for (i = 0; i < app.n_ports; i++) {
-		struct rte_port_ring_reader_params port_ring_params = {
-			.ring = app.rings[core_params->swq_in[i]],
-		};
-
-		struct rte_pipeline_port_in_params port_params = {
-			.ops = &rte_port_ring_reader_ops,
-			.arg_create = (void *) &port_ring_params,
-			.f_action = NULL,
-			.arg_ah = NULL,
-			.burst_size = app.bsz_swq_rd,
-		};
-
-		if (rte_pipeline_port_in_create(p, &port_params,
-			&port_in_id[i]))
-			rte_panic("Unable to configure input port for "
-				"ring %d\n", i);
+		return -1;
+
+	/* Free resources */
+	TAILQ_FOREACH(flow, &p->flows, node) {
+		TAILQ_REMOVE(&p->flows, flow, node);
+		rte_free(flow);
 	}
 
-	/* Output port configuration */
-	for (i = 0; i < app.n_ports; i++) {
-		struct rte_port_ring_writer_params port_ring_params = {
-			.ring = app.rings[core_params->swq_out[i]],
-			.tx_burst_sz = app.bsz_swq_wr,
-		};
-
-		struct rte_pipeline_port_out_params port_params = {
-			.ops = &rte_port_ring_writer_ops,
-			.arg_create = (void *) &port_ring_params,
-			.f_action = NULL,
-			.f_action_bulk = NULL,
-			.arg_ah = NULL,
-		};
-
-		if (rte_pipeline_port_out_create(p, &port_params,
-			&port_out_id[i]))
-			rte_panic("Unable to configure output port for "
-				"ring %d\n", i);
+	rte_free(p);
+	return 0;
+}
+
+static int
+app_pipeline_fc_add(struct app_params *app,
+		uint32_t pipeline_id,
+		struct pipeline_fc_key *key,
+		uint32_t port_id)
+{
+	struct app_pipeline_params *params;
+	struct app_pipeline_data *data;
+	struct app_pipeline_fc *p;
+	struct app_pipeline_fc_flow *flow;
+
+	struct pipeline_fc_add_msg_req *req;
+	struct pipeline_fc_add_msg_rsp *rsp;
+
+	int new_flow;
+
+	/* Check input arguments */
+	if ((app == NULL) ||
+		(key == NULL))
+		return -1;
+
+	APP_PARAM_FIND_BY_ID(app->pipeline_params, "PIPELINE", pipeline_id, params);
+	if ((params == NULL))
+		return -1;
+
+	data = &app->pipeline_data[params - app->pipeline_params];
+	p = data->fe;
+
+	/* Find existing flow or allocate new flow */
+	flow = app_pipeline_fc_flow_find(p, key);
+	new_flow = (flow == NULL);
+	if (flow == NULL) {
+		flow = rte_malloc(NULL, sizeof(*flow), RTE_CACHE_LINE_SIZE);
+
+		if (flow == NULL)
+			return -1;
 	}
 
-	/* Table configuration */
-	{
-		struct rte_table_hash_key16_lru_params table_hash_params = {
-			.n_entries = 1 << 24,
-			.signature_offset = __builtin_offsetof(
-				struct app_pkt_metadata, signature),
-			.key_offset = __builtin_offsetof(
-				struct app_pkt_metadata, flow_key),
-			.f_hash = test_hash,
-			.seed = 0,
-		};
-
-		struct rte_pipeline_table_params table_params = {
-			.ops = &rte_table_hash_key16_lru_ops,
-			.arg_create = &table_hash_params,
-			.f_action_hit = NULL,
-			.f_action_miss = NULL,
-			.arg_ah = NULL,
-			.action_data_size = 0,
-		};
-
-		if (rte_pipeline_table_create(p, &table_params, &table_id))
-			rte_panic("Unable to configure the hash table\n");
+	/* Allocate and write request */
+	req = app_msg_alloc(app);
+	if (req == NULL)
+		return -1;
+
+	req->type = PIPELINE_MSG_REQ_CUSTOM;
+	req->subtype = PIPELINE_FC_MSG_REQ_FLOW_ADD;
+	memcpy(&req->key, key, sizeof(*key));
+	req->port_id = port_id;
+
+	/* Send request and wait for response */
+	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT);
+	if (rsp == NULL) {
+		if (new_flow)
+			rte_free(flow);
+		return -1;
 	}
 
-	/* Interconnecting ports and tables */
-	for (i = 0; i < app.n_ports; i++)
-		if (rte_pipeline_port_in_connect_to_table(p, port_in_id[i],
-			table_id))
-			rte_panic("Unable to connect input port %u to "
-				"table %u\n", port_in_id[i],  table_id);
-
-	/* Enable input ports */
-	for (i = 0; i < app.n_ports; i++)
-		if (rte_pipeline_port_in_enable(p, port_in_id[i]))
-			rte_panic("Unable to enable input port %u\n",
-				port_in_id[i]);
-
-	/* Check pipeline consistency */
-	if (rte_pipeline_check(p) < 0)
-		rte_panic("Pipeline consistency check failed\n");
-
-	/* Message handling */
-	mh_params.ring_req = app_get_ring_req(
-		app_get_first_core_id(APP_CORE_FC));
-	mh_params.ring_resp = app_get_ring_resp(
-		app_get_first_core_id(APP_CORE_FC));
-	mh_params.p = p;
-	mh_params.port_out_id = port_out_id;
-	mh_params.table_id = table_id;
-
-	/* Run-time */
-	for (i = 0; ; i++) {
-		rte_pipeline_run(p);
-
-		if ((i & APP_FLUSH) == 0) {
-			rte_pipeline_flush(p);
-			app_message_handle(&mh_params);
-		}
+	/* Read response and write flow */
+	if (rsp->status || (rsp->entry_ptr == NULL)){
+		app_msg_free(app, rsp);
+		if (new_flow)
+			rte_free(flow);
+		return -1;
+	}
+
+	memcpy(&flow->key, key, sizeof(*key));
+	flow->port_id = port_id;
+	flow->entry_ptr = rsp->entry_ptr;
+
+	/* Commit rule */
+	if (new_flow) {
+		TAILQ_INSERT_TAIL(&p->flows, flow, node);
+		p->n_flows++;
 	}
+
+	print_fc_flow(flow);
+
+	/* Free response */
+	app_msg_free(app, rsp);
+
+	return 0;
 }
 
-void
-app_message_handle(struct app_core_fc_message_handle_params *params)
+static int
+app_pipeline_fc_del(struct app_params *app,
+		uint32_t pipeline_id,
+		struct pipeline_fc_key *key)
 {
-	struct rte_ring *ring_req = params->ring_req;
-	struct rte_ring *ring_resp;
-	void *msg;
-	struct app_msg_req *req;
-	struct app_msg_resp *resp;
-	struct rte_pipeline *p;
-	uint32_t *port_out_id;
-	uint32_t table_id;
-	int result;
-
-	/* Read request message */
-	result = rte_ring_sc_dequeue(ring_req, &msg);
-	if (result != 0)
-		return;
+	struct app_pipeline_params *params;
+	struct app_pipeline_data *data;
+	struct app_pipeline_fc *p;
+	struct app_pipeline_fc_flow *flow;
 
-	ring_resp = params->ring_resp;
-	p = params->p;
-	port_out_id = params->port_out_id;
-	table_id = params->table_id;
-
-	/* Handle request */
-	req = (struct app_msg_req *)rte_ctrlmbuf_data((struct rte_mbuf *)msg);
-	switch (req->type) {
-	case APP_MSG_REQ_PING:
-	{
-		result = 0;
-		break;
+	struct pipeline_fc_del_msg_req *req;
+	struct pipeline_fc_del_msg_rsp *rsp;
+
+	/* Check input arguments */
+	if ((app == NULL) ||
+		(key == NULL))
+		return -1;
+
+	APP_PARAM_FIND_BY_ID(app->pipeline_params, "PIPELINE", pipeline_id, params);
+	if (params == NULL)
+		return -1;
+
+	data = &app->pipeline_data[params - app->pipeline_params];
+	p = data->fe;
+
+	/* Find rule */
+	flow = app_pipeline_fc_flow_find(p, key);
+	if (flow == NULL)
+		return 0;
+
+	/* Allocate and write request */
+	req = app_msg_alloc(app);
+	if (req == NULL)
+		return -1;
+
+	req->type = PIPELINE_MSG_REQ_CUSTOM;
+	req->subtype = PIPELINE_FC_MSG_REQ_FLOW_DEL;
+	memcpy(&req->key, key, sizeof(*key));
+
+	/* Send request and wait for response */
+	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	if (rsp->status) {
+		app_msg_free(app, rsp);
+		return -1;
 	}
 
-	case APP_MSG_REQ_FC_ADD_ALL:
-	{
-		result = app_flow_classification_table_init(p, port_out_id,
-			table_id);
+	/* Remove rule */
+	TAILQ_REMOVE(&p->flows, flow, node);
+	p->n_flows--;
+
+	/* Free response */
+	app_msg_free(app, rsp);
+
+	return 0;
+}
+
+static int
+app_pipeline_fc_add_default(struct app_params *app,
+		uint32_t pipeline_id,
+		enum flow_key_type type,
+		uint32_t port_id)
+{
+	struct app_pipeline_params *params;
+	struct app_pipeline_data *data;
+	struct app_pipeline_fc *p;
+	struct app_pipeline_fc_flow *flow;
+	struct pipeline_fc_key *default_key;
+
+	struct pipeline_fc_add_default_msg_req *req;
+	struct pipeline_fc_add_default_msg_rsp *rsp;
+
+	int new_flow;
+
+	/* Check input arguments */
+	if (app == NULL)
+		return -1;
+
+	APP_PARAM_FIND_BY_ID(app->pipeline_params, "PIPELINE", pipeline_id, params);
+	if ((params == NULL))
+		return -1;
+
+	data = &app->pipeline_data[params - app->pipeline_params];
+	p = data->fe;
+
+	/* Set default flow settings */
+	default_key = rte_malloc(NULL, sizeof(*default_key), RTE_CACHE_LINE_SIZE);
+	if (default_key == NULL)
+		return -1;
+
+	switch (type) {
+	case FLOW_KEY_QINQ:
+		app_pipeline_fc_qinq_default_set(default_key);
+		break;
+	case FLOW_KEY_IPV4_5TUPLE:
+		app_pipeline_fc_ipv4_5tuple_default_set(default_key);
+		break;
+	case FLOW_KEY_IPV6_5TUPLE:
+		app_pipeline_fc_ipv6_5tuple_default_set(default_key);
 		break;
 	}
 
-	case APP_MSG_REQ_FC_ADD:
-	{
-		struct rte_pipeline_table_entry entry = {
-			.action = RTE_PIPELINE_ACTION_PORT,
-			{.port_id = port_out_id[req->flow_classif_add.port]},
-		};
+	/* Find existing flow or allocate new flow */
+	flow = app_pipeline_fc_flow_find(p, default_key);
+	new_flow = (flow == NULL);
+	if (flow == NULL) {
+		flow = rte_malloc(NULL, sizeof(*flow), RTE_CACHE_LINE_SIZE);
+
+		if (flow == NULL) {
+			rte_free(default_key);
+			return -1;
+		}
+	}
+
+	/* Allocate and write request */
+	req = app_msg_alloc(app);
+	if (req == NULL) {
+		rte_free(default_key);
+		return -1;
+	}
 
-		struct rte_pipeline_table_entry *entry_ptr;
+	req->type = PIPELINE_MSG_REQ_CUSTOM;
+	req->subtype = PIPELINE_FC_MSG_REQ_FLOW_ADD_DEFAULT;
+	req->port_id = port_id;
 
-		int key_found;
+	/* Send request and wait for response */
+	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT);
+	if (rsp == NULL) {
+		if (new_flow) {
+			rte_free(flow);
+			rte_free(default_key);
+		}
+		return -1;
+	}
 
-		result = rte_pipeline_table_entry_add(p, table_id,
-			req->flow_classif_add.key_raw, &entry, &key_found,
-			&entry_ptr);
-		break;
+	/* Read response and write flow */
+	if (rsp->status || (rsp->default_entry_ptr == NULL)){
+		app_msg_free(app, rsp);
+		if (new_flow) {
+			rte_free(flow);
+			rte_free(default_key);
+		}
+		return -1;
 	}
 
-	case APP_MSG_REQ_FC_DEL:
-	{
-		int key_found;
+	memcpy(&flow->key, default_key, sizeof(*default_key));
+	flow->port_id = port_id;
+	flow->entry_ptr = rsp->default_entry_ptr;
 
-		result = rte_pipeline_table_entry_delete(p, table_id,
-			req->flow_classif_add.key_raw, &key_found, NULL);
+	/* Commit rule */
+	if (new_flow) {
+		TAILQ_INSERT_TAIL(&p->flows, flow, node);
+		p->n_flows++;
+	}
+
+	/* Free response */
+	app_msg_free(app, rsp);
+	rte_free(default_key);
+
+	return 0;
+}
+
+static int
+app_pipeline_fc_del_default(struct app_params *app,
+		enum flow_key_type type,
+		uint32_t pipeline_id)
+{
+	struct app_pipeline_params *params;
+	struct app_pipeline_data *data;
+	struct app_pipeline_fc *p;
+	struct app_pipeline_fc_flow *flow;
+	struct pipeline_fc_key *default_key;
+
+	struct pipeline_fc_del_default_msg_req *req;
+	struct pipeline_fc_del_default_msg_rsp *rsp;
+
+	/* Check input arguments */
+	if (app == NULL)
+		return -1;
+
+	APP_PARAM_FIND_BY_ID(app->pipeline_params, "PIPELINE", pipeline_id, params);
+	if ((params == NULL))
+		return -1;
+
+	data = &app->pipeline_data[params - app->pipeline_params];
+	p = data->fe;
+
+	/* Set default flow settings */
+	default_key = rte_malloc(NULL, sizeof(*default_key), RTE_CACHE_LINE_SIZE);
+	if (default_key == NULL)
+		return -1;
+
+	switch (type) {
+	case FLOW_KEY_QINQ:
+		app_pipeline_fc_qinq_default_set(default_key);
 		break;
+	case FLOW_KEY_IPV4_5TUPLE:
+		app_pipeline_fc_ipv4_5tuple_default_set(default_key);
+		break;
+	case FLOW_KEY_IPV6_5TUPLE:
+		app_pipeline_fc_ipv6_5tuple_default_set(default_key);
+		break;
+	}
+
+	/* Find rule */
+	flow = app_pipeline_fc_flow_find(p, default_key);
+	if (flow == NULL) {
+		rte_free(default_key);
+		return 0;
+	}
+
+	/* Allocate and write request */
+	req = app_msg_alloc(app);
+	if (req == NULL) {
+		rte_free(default_key);
+		return -1;
 	}
 
-	default:
-		rte_panic("FC Unrecognized message type (%u)\n", req->type);
+	req->type = PIPELINE_MSG_REQ_CUSTOM;
+	req->subtype = PIPELINE_FC_MSG_REQ_FLOW_DEL_DEFAULT;
+
+	/* Send request and wait for response */
+	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT);
+	if (rsp == NULL) {
+		rte_free(default_key);
+		return -1;
+	}
+
+	/* Read response */
+	if (rsp->status) {
+		app_msg_free(app, rsp);
+		rte_free(default_key);
+		return -1;
 	}
 
-	/* Fill in response message */
-	resp = (struct app_msg_resp *)rte_ctrlmbuf_data((struct rte_mbuf *)msg);
-	resp->result = result;
+	/* Remove rule */
+	TAILQ_REMOVE(&p->flows, flow, node);
+	p->n_flows--;
+
+	/* Free response */
+	app_msg_free(app, rsp);
+	rte_free(default_key);
+
+	return 0;
+}
+
+static void
+app_pipeline_fc_ls(struct app_params *app,
+		uint32_t pipeline_id)
+{
+	struct app_pipeline_params *pipeline_params;
+	struct app_pipeline_data *pipeline_data;
+	struct app_pipeline_fc *p;
+	struct app_pipeline_fc_flow *flow;
+
+	/* Check input arguments */
+	if (app == NULL)
+		return;
+
+	APP_PARAM_FIND_BY_ID(app->pipeline_params, "PIPELINE", pipeline_id, pipeline_params);
+	if (pipeline_params == NULL)
+		return;
+
+	pipeline_data = &app->pipeline_data[pipeline_params - app->pipeline_params];
+	p = pipeline_data->fe;
+
+	TAILQ_FOREACH(flow, &p->flows, node) {
+		print_fc_flow(flow);
+	}
+}
+
+struct cmd_fc_add_qinq_result {
+	cmdline_fixed_string_t p_string;
+	uint32_t pipeline_id;
+	cmdline_fixed_string_t flow_string;
+	cmdline_fixed_string_t add_string;
+	cmdline_fixed_string_t qinq_string;
+	uint16_t svlan;
+	uint16_t cvlan;
+	uint8_t port;
+};
+
+static void
+cmd_fc_add_qinq_parsed(
+	void *parsed_result,
+	__rte_unused struct cmdline *cl,
+	void *data)
+{
+	struct cmd_fc_add_qinq_result *params = parsed_result;
+	struct app_params *app = data;
+	struct pipeline_fc_key key;
+	int status;
+
+	memset(&key, 0, sizeof(key));
+	key.type = FLOW_KEY_QINQ;
+	key.key.qinq.svlan = params->svlan;
+	key.key.qinq.cvlan = params->cvlan;
+	status = app_pipeline_fc_add(app, params->pipeline_id, &key, params->port);
+
+	if(status != 0)
+		printf("Command failed\n");
+}
+
+cmdline_parse_token_string_t cmd_fc_add_qinq_p_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_qinq_result, p_string, "p");
+
+cmdline_parse_token_num_t cmd_fc_add_qinq_pipeline_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_qinq_result, pipeline_id, UINT32);
+
+cmdline_parse_token_string_t cmd_fc_add_qinq_flow_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_qinq_result, flow_string, "flow");
+
+cmdline_parse_token_string_t cmd_fc_add_qinq_add_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_qinq_result, add_string, "add");
+
+cmdline_parse_token_string_t cmd_fc_add_qinq_qinq_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_qinq_result, add_string, "qinq");
+
+cmdline_parse_token_num_t cmd_fc_add_qinq_svlan =
+	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_qinq_result, svlan, UINT16);
+
+cmdline_parse_token_num_t cmd_fc_add_qinq_cvlan =
+	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_qinq_result, cvlan, UINT16);
+
+cmdline_parse_token_num_t cmd_fc_add_qinq_port =
+	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_qinq_result, port, UINT8);
+
+cmdline_parse_inst_t cmd_fc_add_qinq = {
+	.f = cmd_fc_add_qinq_parsed,
+	.data = NULL,
+	.help_str = "p <pipeline_id> flow add qinq <svlan> <cvlan> <port>",
+	.tokens = {
+		(void *) &cmd_fc_add_qinq_p_string,
+		(void *) &cmd_fc_add_qinq_pipeline_id,
+		(void *) &cmd_fc_add_qinq_flow_string,
+		(void *) &cmd_fc_add_qinq_add_string,
+		(void *) &cmd_fc_add_qinq_qinq_string,
+		(void *) &cmd_fc_add_qinq_svlan,
+		(void *) &cmd_fc_add_qinq_cvlan,
+		(void *) &cmd_fc_add_qinq_port,
+		NULL,
+	},
+};
+
+/*
+ * flow add ipv4_5tuple
+ */
+
+struct cmd_fc_add_ipv4_5tuple_result {
+	cmdline_fixed_string_t p_string;
+	uint32_t pipeline_id;
+	cmdline_fixed_string_t flow_string;
+	cmdline_fixed_string_t add_string;
+	cmdline_fixed_string_t ipv4_5tuple_string;
+	cmdline_ipaddr_t ip_src;
+	cmdline_ipaddr_t ip_dst;
+	uint16_t port_src;
+	uint16_t port_dst;
+	uint32_t proto;
+	uint8_t port;
+};
+
+static void
+cmd_fc_add_ipv4_5tuple_parsed(
+	void *parsed_result,
+	__rte_unused struct cmdline *cl,
+	void *data)
+{
+	struct cmd_fc_add_ipv4_5tuple_result *params = parsed_result;
+	struct app_params *app = data;
+	struct pipeline_fc_key key;
+	int status;
+
+	memset(&key, 0, sizeof(key));
+	key.type = FLOW_KEY_IPV4_5TUPLE;
+	key.key.ipv4_5tuple.ip_src = params->ip_src.addr.ipv4.s_addr;
+	key.key.ipv4_5tuple.ip_dst = params->ip_dst.addr.ipv4.s_addr;
+	key.key.ipv4_5tuple.port_src = params->port_src;
+	key.key.ipv4_5tuple.port_dst = params->port_dst;
+	key.key.ipv4_5tuple.proto = params->proto;
+	status = app_pipeline_fc_add(app, params->pipeline_id, &key, params->port);
+
+	if(status != 0)
+		printf("Command failed\n");
+}
+
+cmdline_parse_token_string_t cmd_fc_add_ipv4_5tuple_p_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_result, p_string, "p");
+
+cmdline_parse_token_num_t cmd_fc_add_ipv4_5tuple_pipeline_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_result, pipeline_id, UINT32);
+
+cmdline_parse_token_string_t cmd_fc_add_ipv4_5tuple_flow_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_result, flow_string, "flow");
+
+cmdline_parse_token_string_t cmd_fc_add_ipv4_5tuple_add_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_result, add_string, "add");
+
+cmdline_parse_token_string_t cmd_fc_add_ipv4_5tuple_ipv4_5tuple_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_result, ipv4_5tuple_string, "ipv4_5tuple");
+
+cmdline_parse_token_ipaddr_t cmd_fc_add_ipv4_5tuple_ip_src =
+	TOKEN_IPADDR_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_result, ip_src);
+
+cmdline_parse_token_ipaddr_t cmd_fc_add_ipv4_5tuple_ip_dst =
+	TOKEN_IPADDR_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_result, ip_dst);
+
+cmdline_parse_token_num_t cmd_fc_add_ipv4_5tuple_port_src =
+	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_result, port_src, UINT16);
+
+cmdline_parse_token_num_t cmd_fc_add_ipv4_5tuple_port_dst =
+	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_result, port_dst, UINT16);
+
+cmdline_parse_token_num_t cmd_fc_add_ipv4_5tuple_proto =
+	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_result, proto, UINT32);
+
+cmdline_parse_token_num_t cmd_fc_add_ipv4_5tuple_port =
+	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv4_5tuple_result, port, UINT8);
+
+cmdline_parse_inst_t cmd_fc_add_ipv4_5tuple = {
+	.f = cmd_fc_add_ipv4_5tuple_parsed,
+	.data = NULL,
+	.help_str = "p <pipeline_id> flow add ipv4_5tuple <ip_src> <ip_dst> <port_src> <port_dst> <proto> <port>",
+	.tokens = {
+		(void *) &cmd_fc_add_ipv4_5tuple_p_string,
+		(void *) &cmd_fc_add_ipv4_5tuple_pipeline_id,
+		(void *) &cmd_fc_add_ipv4_5tuple_flow_string,
+		(void *) &cmd_fc_add_ipv4_5tuple_add_string,
+		(void *) &cmd_fc_add_ipv4_5tuple_ipv4_5tuple_string,
+		(void *) &cmd_fc_add_ipv4_5tuple_ip_src,
+		(void *) &cmd_fc_add_ipv4_5tuple_ip_dst,
+		(void *) &cmd_fc_add_ipv4_5tuple_port_src,
+		(void *) &cmd_fc_add_ipv4_5tuple_port_dst,
+		(void *) &cmd_fc_add_ipv4_5tuple_proto,
+		(void *) &cmd_fc_add_ipv4_5tuple_port,
+		NULL,
+	},
+};
+
+/*
+ * flow add ipv6_5tuple
+ */
+
+struct cmd_fc_add_ipv6_5tuple_result {
+	cmdline_fixed_string_t p_string;
+	uint32_t pipeline_id;
+	cmdline_fixed_string_t flow_string;
+	cmdline_fixed_string_t add_string;
+	cmdline_fixed_string_t ipv6_5tuple_string;
+	cmdline_ipaddr_t ip_src;
+	cmdline_ipaddr_t ip_dst;
+	uint16_t port_src;
+	uint16_t port_dst;
+	uint32_t proto;
+	uint8_t port;
+};
+
+static void
+cmd_fc_add_ipv6_5tuple_parsed(
+	void *parsed_result,
+	__rte_unused struct cmdline *cl,
+	void *data)
+{
+	struct cmd_fc_add_ipv6_5tuple_result *params = parsed_result;
+	struct app_params *app = data;
+	struct pipeline_fc_key key;
+	int status;
+
+	memset(&key, 0, sizeof(key));
+	key.type = FLOW_KEY_IPV6_5TUPLE;
+	memcpy(key.key.ipv6_5tuple.ip_src, params->ip_src.addr.ipv6.s6_addr, 16);
+	memcpy(key.key.ipv6_5tuple.ip_dst, params->ip_dst.addr.ipv6.s6_addr, 16);
+	key.key.ipv6_5tuple.port_src = params->port_src;
+	key.key.ipv6_5tuple.port_dst = params->port_dst;
+	key.key.ipv6_5tuple.proto = params->proto;
+	status = app_pipeline_fc_add(app, params->pipeline_id, &key, params->port);
+
+	if(status != 0)
+		printf("Command failed\n");
+}
+
+cmdline_parse_token_string_t cmd_fc_add_ipv6_5tuple_p_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_result, p_string, "p");
+
+cmdline_parse_token_num_t cmd_fc_add_ipv6_5tuple_pipeline_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_result, pipeline_id, UINT32);
+
+cmdline_parse_token_string_t cmd_fc_add_ipv6_5tuple_flow_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_result, flow_string, "flow");
+
+cmdline_parse_token_string_t cmd_fc_add_ipv6_5tuple_add_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_result, add_string, "add");
+
+cmdline_parse_token_string_t cmd_fc_add_ipv6_5tuple_ipv6_5tuple_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_result, ipv6_5tuple_string, "ipv6_5tuple");
+
+cmdline_parse_token_ipaddr_t cmd_fc_add_ipv6_5tuple_ip_src =
+	TOKEN_IPADDR_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_result, ip_src);
 
-	/* Send response */
-	do {
-		result = rte_ring_sp_enqueue(ring_resp, msg);
-	} while (result == -ENOBUFS);
+cmdline_parse_token_ipaddr_t cmd_fc_add_ipv6_5tuple_ip_dst =
+	TOKEN_IPADDR_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_result, ip_dst);
+
+cmdline_parse_token_num_t cmd_fc_add_ipv6_5tuple_port_src =
+	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_result, port_src, UINT16);
+
+cmdline_parse_token_num_t cmd_fc_add_ipv6_5tuple_port_dst =
+	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_result, port_dst, UINT16);
+
+cmdline_parse_token_num_t cmd_fc_add_ipv6_5tuple_proto =
+	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_result, proto, UINT32);
+
+cmdline_parse_token_num_t cmd_fc_add_ipv6_5tuple_port =
+	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_ipv6_5tuple_result, port, UINT8);
+
+cmdline_parse_inst_t cmd_fc_add_ipv6_5tuple = {
+	.f = cmd_fc_add_ipv6_5tuple_parsed,
+	.data = NULL,
+	.help_str = "p <pipeline_id> flow add ipv6_5tuple <ip_src> <ip_dst> <port_src> <port_dst> <proto> <port>",
+	.tokens = {
+		(void *) &cmd_fc_add_ipv6_5tuple_p_string,
+		(void *) &cmd_fc_add_ipv6_5tuple_pipeline_id,
+		(void *) &cmd_fc_add_ipv6_5tuple_flow_string,
+		(void *) &cmd_fc_add_ipv6_5tuple_add_string,
+		(void *) &cmd_fc_add_ipv6_5tuple_ipv6_5tuple_string,
+		(void *) &cmd_fc_add_ipv6_5tuple_ip_src,
+		(void *) &cmd_fc_add_ipv6_5tuple_ip_dst,
+		(void *) &cmd_fc_add_ipv6_5tuple_port_src,
+		(void *) &cmd_fc_add_ipv6_5tuple_port_dst,
+		(void *) &cmd_fc_add_ipv6_5tuple_proto,
+		(void *) &cmd_fc_add_ipv6_5tuple_port,
+		NULL,
+	},
+};
+
+/*
+ * flow del qinq
+ */
+struct cmd_fc_del_qinq_result {
+	cmdline_fixed_string_t p_string;
+	uint32_t pipeline_id;
+	cmdline_fixed_string_t flow_string;
+	cmdline_fixed_string_t del_string;
+	cmdline_fixed_string_t qinq_string;
+	uint16_t svlan;
+	uint16_t cvlan;
+};
+
+static void
+cmd_fc_del_qinq_parsed(
+	void *parsed_result,
+	__rte_unused struct cmdline *cl,
+	void *data)
+{
+	struct cmd_fc_del_qinq_result *params = parsed_result;
+	struct app_params *app = data;
+	struct pipeline_fc_key key;
+	int status;
+
+	memset(&key, 0, sizeof(key));
+	key.type = FLOW_KEY_QINQ;
+	key.key.qinq.svlan = params->svlan;
+	key.key.qinq.cvlan = params->cvlan;
+	status = app_pipeline_fc_del(app, params->pipeline_id, &key);
+
+	if(status != 0)
+		printf("Command failed\n");
+}
+
+cmdline_parse_token_string_t cmd_fc_del_qinq_p_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_qinq_result, p_string, "p");
+
+cmdline_parse_token_num_t cmd_fc_del_qinq_pipeline_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_fc_del_qinq_result, pipeline_id, UINT32);
+
+cmdline_parse_token_string_t cmd_fc_del_qinq_flow_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_qinq_result, flow_string, "flow");
+
+cmdline_parse_token_string_t cmd_fc_del_qinq_del_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_qinq_result, del_string, "del");
+
+cmdline_parse_token_string_t cmd_fc_del_qinq_qinq_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_qinq_result, qinq_string, "qinq");
+
+cmdline_parse_token_num_t cmd_fc_del_qinq_svlan =
+	TOKEN_NUM_INITIALIZER(struct cmd_fc_del_qinq_result, svlan, UINT16);
+
+cmdline_parse_token_num_t cmd_fc_del_qinq_cvlan =
+	TOKEN_NUM_INITIALIZER(struct cmd_fc_del_qinq_result, cvlan, UINT16);
+
+cmdline_parse_inst_t cmd_fc_del_qinq = {
+	.f = cmd_fc_del_qinq_parsed,
+	.data = NULL,
+	.help_str = "p <pipeline_id> flow del qinq <svlan> <cvlan>",
+	.tokens = {
+		(void *) &cmd_fc_del_qinq_p_string,
+		(void *) &cmd_fc_del_qinq_pipeline_id,
+		(void *) &cmd_fc_del_qinq_flow_string,
+		(void *) &cmd_fc_del_qinq_del_string,
+		(void *) &cmd_fc_del_qinq_qinq_string,
+		(void *) &cmd_fc_del_qinq_svlan,
+		(void *) &cmd_fc_del_qinq_cvlan,
+		NULL,
+	},
+};
+
+/*
+ * flow del ipv4_5tuple
+ */
+
+struct cmd_fc_del_ipv4_5tuple_result {
+	cmdline_fixed_string_t p_string;
+	uint32_t pipeline_id;
+	cmdline_fixed_string_t flow_string;
+	cmdline_fixed_string_t del_string;
+	cmdline_fixed_string_t ipv4_5tuple_string;
+	cmdline_ipaddr_t ip_src;
+	cmdline_ipaddr_t ip_dst;
+	uint16_t port_src;
+	uint16_t port_dst;
+	uint32_t proto;
+	uint8_t port;
+};
+
+static void
+cmd_fc_del_ipv4_5tuple_parsed(
+	void *parsed_result,
+	__rte_unused struct cmdline *cl,
+	void *data)
+{
+	struct cmd_fc_del_ipv4_5tuple_result *params = parsed_result;
+	struct app_params *app = data;
+	struct pipeline_fc_key key;
+	int status;
+
+	memset(&key, 0, sizeof(key));
+	key.type = FLOW_KEY_IPV4_5TUPLE;
+	key.key.ipv4_5tuple.ip_src = params->ip_src.addr.ipv4.s_addr;
+	key.key.ipv4_5tuple.ip_dst = params->ip_dst.addr.ipv4.s_addr;
+	key.key.ipv4_5tuple.port_src = params->port_src;
+	key.key.ipv4_5tuple.port_dst = params->port_dst;
+	key.key.ipv4_5tuple.proto = params->proto;
+	status = app_pipeline_fc_del(app, params->pipeline_id, &key);
+
+	if(status != 0)
+		printf("Command failed\n");
+}
+
+cmdline_parse_token_string_t cmd_fc_del_ipv4_5tuple_p_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_ipv4_5tuple_result, p_string, "p");
+
+cmdline_parse_token_num_t cmd_fc_del_ipv4_5tuple_pipeline_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_fc_del_ipv4_5tuple_result, pipeline_id, UINT32);
+
+cmdline_parse_token_string_t cmd_fc_del_ipv4_5tuple_flow_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_ipv4_5tuple_result, flow_string, "flow");
+
+cmdline_parse_token_string_t cmd_fc_del_ipv4_5tuple_del_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_ipv4_5tuple_result, del_string, "del");
+
+cmdline_parse_token_string_t cmd_fc_del_ipv4_5tuple_ipv4_5tuple_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_ipv4_5tuple_result, ipv4_5tuple_string, "ipv4_5tuple");
+
+cmdline_parse_token_ipaddr_t cmd_fc_del_ipv4_5tuple_ip_src =
+	TOKEN_IPADDR_INITIALIZER(struct cmd_fc_del_ipv4_5tuple_result, ip_src);
+
+cmdline_parse_token_ipaddr_t cmd_fc_del_ipv4_5tuple_ip_dst =
+	TOKEN_IPADDR_INITIALIZER(struct cmd_fc_del_ipv4_5tuple_result, ip_dst);
+
+cmdline_parse_token_num_t cmd_fc_del_ipv4_5tuple_port_src =
+	TOKEN_NUM_INITIALIZER(struct cmd_fc_del_ipv4_5tuple_result, port_src, UINT16);
+
+cmdline_parse_token_num_t cmd_fc_del_ipv4_5tuple_port_dst =
+	TOKEN_NUM_INITIALIZER(struct cmd_fc_del_ipv4_5tuple_result, port_dst, UINT16);
+
+cmdline_parse_token_num_t cmd_fc_del_ipv4_5tuple_proto =
+	TOKEN_NUM_INITIALIZER(struct cmd_fc_del_ipv4_5tuple_result, proto, UINT32);
+
+cmdline_parse_inst_t cmd_fc_del_ipv4_5tuple = {
+	.f = cmd_fc_del_ipv4_5tuple_parsed,
+	.data = NULL,
+	.help_str = "p <pipeline_id> flow del ipv4_5tuple <ip_src> <ip_dst> <port_src> <port_dst> <proto>",
+	.tokens = {
+		(void *) &cmd_fc_add_ipv4_5tuple_p_string,
+		(void *) &cmd_fc_add_ipv4_5tuple_pipeline_id,
+		(void *) &cmd_fc_add_ipv4_5tuple_flow_string,
+		(void *) &cmd_fc_add_ipv4_5tuple_add_string,
+		(void *) &cmd_fc_add_ipv4_5tuple_ipv4_5tuple_string,
+		(void *) &cmd_fc_add_ipv4_5tuple_ip_src,
+		(void *) &cmd_fc_add_ipv4_5tuple_ip_dst,
+		(void *) &cmd_fc_add_ipv4_5tuple_port_src,
+		(void *) &cmd_fc_add_ipv4_5tuple_port_dst,
+		(void *) &cmd_fc_add_ipv4_5tuple_proto,
+		NULL,
+	},
+};
+
+/*
+ * flow del ipv6_5tuple
+ */
+
+struct cmd_fc_del_ipv6_5tuple_result {
+	cmdline_fixed_string_t p_string;
+	uint32_t pipeline_id;
+	cmdline_fixed_string_t flow_string;
+	cmdline_fixed_string_t del_string;
+	cmdline_fixed_string_t ipv6_5tuple_string;
+	cmdline_ipaddr_t ip_src;
+	cmdline_ipaddr_t ip_dst;
+	uint16_t port_src;
+	uint16_t port_dst;
+	uint32_t proto;
+	uint8_t port;
+};
+
+static void
+cmd_fc_del_ipv6_5tuple_parsed(
+	void *parsed_result,
+	__rte_unused struct cmdline *cl,
+	void *data)
+{
+	struct cmd_fc_del_ipv6_5tuple_result *params = parsed_result;
+	struct app_params *app = data;
+	struct pipeline_fc_key key;
+	int status;
+
+	memset(&key, 0, sizeof(key));
+	key.type = FLOW_KEY_IPV6_5TUPLE;
+	memcpy(key.key.ipv6_5tuple.ip_src, params->ip_src.addr.ipv6.s6_addr, 16);
+	memcpy(key.key.ipv6_5tuple.ip_dst, params->ip_dst.addr.ipv6.s6_addr, 16);
+	key.key.ipv6_5tuple.port_src = params->port_src;
+	key.key.ipv6_5tuple.port_dst = params->port_dst;
+	key.key.ipv6_5tuple.proto = params->proto;
+	status = app_pipeline_fc_del(app, params->pipeline_id, &key);
+
+	if(status != 0)
+		printf("Command failed\n");
+}
+
+cmdline_parse_token_string_t cmd_fc_del_ipv6_5tuple_p_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_ipv6_5tuple_result, p_string, "p");
+
+cmdline_parse_token_num_t cmd_fc_del_ipv6_5tuple_pipeline_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_fc_del_ipv6_5tuple_result, pipeline_id, UINT32);
+
+cmdline_parse_token_string_t cmd_fc_del_ipv6_5tuple_flow_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_ipv6_5tuple_result, flow_string, "flow");
+
+cmdline_parse_token_string_t cmd_fc_del_ipv6_5tuple_add_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_ipv6_5tuple_result, del_string, "del");
+
+cmdline_parse_token_string_t cmd_fc_del_ipv6_5tuple_ipv6_5tuple_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_ipv6_5tuple_result, ipv6_5tuple_string, "ipv6_5tuple");
+
+cmdline_parse_token_ipaddr_t cmd_fc_del_ipv6_5tuple_ip_src =
+	TOKEN_IPADDR_INITIALIZER(struct cmd_fc_del_ipv6_5tuple_result, ip_src);
+
+cmdline_parse_token_ipaddr_t cmd_fc_del_ipv6_5tuple_ip_dst =
+	TOKEN_IPADDR_INITIALIZER(struct cmd_fc_del_ipv6_5tuple_result, ip_dst);
+
+cmdline_parse_token_num_t cmd_fc_del_ipv6_5tuple_port_src =
+	TOKEN_NUM_INITIALIZER(struct cmd_fc_del_ipv6_5tuple_result, port_src, UINT16);
+
+cmdline_parse_token_num_t cmd_fc_del_ipv6_5tuple_port_dst =
+	TOKEN_NUM_INITIALIZER(struct cmd_fc_del_ipv6_5tuple_result, port_dst, UINT16);
+
+cmdline_parse_token_num_t cmd_fc_del_ipv6_5tuple_proto =
+	TOKEN_NUM_INITIALIZER(struct cmd_fc_del_ipv6_5tuple_result, proto, UINT32);
+
+cmdline_parse_token_num_t cmd_fc_del_ipv6_5tuple_port =
+	TOKEN_NUM_INITIALIZER(struct cmd_fc_del_ipv6_5tuple_result, port, UINT8);
+
+cmdline_parse_inst_t cmd_fc_del_ipv6_5tuple = {
+	.f = cmd_fc_del_ipv6_5tuple_parsed,
+	.data = NULL,
+	.help_str = "p <pipeline_id> flow del ipv6_5tuple <ip_src> <ip_dst> <port_src> <port_dst> <proto>",
+	.tokens = {
+		(void *) &cmd_fc_del_ipv6_5tuple_p_string,
+		(void *) &cmd_fc_del_ipv6_5tuple_pipeline_id,
+		(void *) &cmd_fc_del_ipv6_5tuple_flow_string,
+		(void *) &cmd_fc_del_ipv6_5tuple_add_string,
+		(void *) &cmd_fc_del_ipv6_5tuple_ipv6_5tuple_string,
+		(void *) &cmd_fc_del_ipv6_5tuple_ip_src,
+		(void *) &cmd_fc_del_ipv6_5tuple_ip_dst,
+		(void *) &cmd_fc_del_ipv6_5tuple_port_src,
+		(void *) &cmd_fc_del_ipv6_5tuple_port_dst,
+		(void *) &cmd_fc_del_ipv6_5tuple_proto,
+		NULL,
+	},
+};
+
+/*
+ * flow add default qinq
+ */
+
+struct cmd_fc_add_default_qinq_result {
+	cmdline_fixed_string_t p_string;
+	uint32_t pipeline_id;
+	cmdline_fixed_string_t flow_string;
+	cmdline_fixed_string_t add_string;
+	cmdline_fixed_string_t default_string;
+	cmdline_fixed_string_t qinq_string;
+	uint8_t port;
+};
+
+static void
+cmd_fc_add_default_qinq_parsed(
+	void *parsed_result,
+	__rte_unused struct cmdline *cl,
+	void *data)
+{
+	struct cmd_fc_add_default_qinq_result *params = parsed_result;
+	struct app_params *app = data;
+	enum flow_key_type type;
+	int status;
+
+	type = FLOW_KEY_QINQ;
+	status = app_pipeline_fc_add_default(app, params->pipeline_id, type,
+		params->port);
+
+	if(status != 0)
+		printf("Command failed\n");
+}
+
+cmdline_parse_token_string_t cmd_fc_add_default_qinq_p_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_default_qinq_result, p_string, "p");
+
+cmdline_parse_token_num_t cmd_fc_add_default_qinq_pipeline_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_default_qinq_result, pipeline_id, UINT32);
+
+cmdline_parse_token_string_t cmd_fc_add_default_qinq_flow_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_default_qinq_result, flow_string, "flow");
+
+cmdline_parse_token_string_t cmd_fc_add_default_qinq_add_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_default_qinq_result, add_string, "add");
+
+cmdline_parse_token_string_t cmd_fc_add_default_qinq_default_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_default_qinq_result, default_string, "default");
+
+cmdline_parse_token_string_t cmd_fc_add_default_qinq_qinq_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_default_qinq_result, qinq_string, "qinq");
+
+cmdline_parse_token_num_t cmd_fc_add_default_qinq_port =
+	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_default_qinq_result, port, UINT8);
+
+cmdline_parse_inst_t cmd_fc_add_default_qinq = {
+	.f = cmd_fc_add_default_qinq_parsed,
+	.data = NULL,
+	.help_str = "p <pipeline_id> flow add default qinq <port>",
+	.tokens = {
+		(void *) &cmd_fc_add_default_qinq_p_string,
+		(void *) &cmd_fc_add_default_qinq_pipeline_id,
+		(void *) &cmd_fc_add_default_qinq_flow_string,
+		(void *) &cmd_fc_add_default_qinq_add_string,
+		(void *) &cmd_fc_add_default_qinq_default_string,
+		(void *) &cmd_fc_add_default_qinq_qinq_string,
+		(void *) &cmd_fc_add_default_qinq_port,
+		NULL,
+	},
+};
+
+/*
+ * flow add default ipv4_5tuple
+ */
+
+struct cmd_fc_add_default_ipv4_5tuple_result {
+	cmdline_fixed_string_t p_string;
+	uint32_t pipeline_id;
+	cmdline_fixed_string_t flow_string;
+	cmdline_fixed_string_t add_string;
+	cmdline_fixed_string_t default_string;
+	cmdline_fixed_string_t ipv4_5tuple_string;
+	uint8_t port;
+};
+
+static void
+cmd_fc_add_default_ipv4_5tuple_parsed(
+	void *parsed_result,
+	__rte_unused struct cmdline *cl,
+	void *data)
+{
+	struct cmd_fc_add_default_ipv4_5tuple_result *params = parsed_result;
+	struct app_params *app = data;
+	enum flow_key_type type;
+	int status;
+
+	type = FLOW_KEY_IPV4_5TUPLE;
+	status = app_pipeline_fc_add_default(app, params->pipeline_id, type,
+		params->port);
+
+	if(status != 0)
+		printf("Command failed\n");
+}
+
+cmdline_parse_token_string_t cmd_fc_add_default_ipv4_5tuple_p_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_default_ipv4_5tuple_result, p_string, "p");
+
+cmdline_parse_token_num_t cmd_fc_add_default_ipv4_5tuple_pipeline_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_default_ipv4_5tuple_result, pipeline_id, UINT32);
+
+cmdline_parse_token_string_t cmd_fc_add_default_ipv4_5tuple_flow_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_default_ipv4_5tuple_result, flow_string, "flow");
+
+cmdline_parse_token_string_t cmd_fc_add_default_ipv4_5tuple_add_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_default_ipv4_5tuple_result, add_string, "add");
+
+cmdline_parse_token_string_t cmd_fc_add_default_ipv4_5tuple_default_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_default_ipv4_5tuple_result, default_string, "default");
+
+cmdline_parse_token_string_t cmd_fc_add_default_ipv4_5tuple_ipv4_5tuple_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_default_ipv4_5tuple_result, ipv4_5tuple_string, "ipv4_5tuple");
+
+cmdline_parse_token_num_t cmd_fc_add_default_ipv4_5tuple_port =
+	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_default_ipv4_5tuple_result, port, UINT8);
+
+cmdline_parse_inst_t cmd_fc_add_default_ipv4_5tuple = {
+	.f = cmd_fc_add_default_ipv4_5tuple_parsed,
+	.data = NULL,
+	.help_str = "p <pipeline_id> flow add default ipv4_5tuple <port>",
+	.tokens = {
+		(void *) &cmd_fc_add_default_ipv4_5tuple_p_string,
+		(void *) &cmd_fc_add_default_ipv4_5tuple_pipeline_id,
+		(void *) &cmd_fc_add_default_ipv4_5tuple_flow_string,
+		(void *) &cmd_fc_add_default_ipv4_5tuple_add_string,
+		(void *) &cmd_fc_add_default_ipv4_5tuple_default_string,
+		(void *) &cmd_fc_add_default_ipv4_5tuple_ipv4_5tuple_string,
+		(void *) &cmd_fc_add_default_ipv4_5tuple_port,
+		NULL,
+	},
+};
+
+/*
+ * flow add default ipv6_5tuple
+ */
+
+struct cmd_fc_add_default_ipv6_5tuple_result {
+	cmdline_fixed_string_t p_string;
+	uint32_t pipeline_id;
+	cmdline_fixed_string_t flow_string;
+	cmdline_fixed_string_t add_string;
+	cmdline_fixed_string_t default_string;
+	cmdline_fixed_string_t ipv6_5tuple_string;
+	uint8_t port;
+};
+
+static void
+cmd_fc_add_default_ipv6_5tuple_parsed(
+	void *parsed_result,
+	__rte_unused struct cmdline *cl,
+	void *data)
+{
+	struct cmd_fc_add_default_ipv6_5tuple_result *params = parsed_result;
+	struct app_params *app = data;
+	enum flow_key_type type;
+	int status;
+
+	type = FLOW_KEY_IPV6_5TUPLE;
+	status = app_pipeline_fc_add_default(app, params->pipeline_id, type,
+		params->port);
+
+	if(status != 0)
+		printf("Command failed\n");
+}
+
+cmdline_parse_token_string_t cmd_fc_add_default_ipv6_5tuple_p_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_default_ipv6_5tuple_result, p_string, "p");
+
+cmdline_parse_token_num_t cmd_fc_add_default_ipv6_5tuple_pipeline_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_default_ipv6_5tuple_result, pipeline_id, UINT32);
+
+cmdline_parse_token_string_t cmd_fc_add_default_ipv6_5tuple_flow_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_default_ipv6_5tuple_result, flow_string, "flow");
+
+cmdline_parse_token_string_t cmd_fc_add_default_ipv6_5tuple_add_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_default_ipv6_5tuple_result, add_string, "add");
+
+cmdline_parse_token_string_t cmd_fc_add_default_ipv6_5tuple_default_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_default_ipv6_5tuple_result, default_string, "default");
+
+cmdline_parse_token_string_t cmd_fc_add_default_ipv6_5tuple_ipv6_5tuple_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_fc_add_default_ipv6_5tuple_result, ipv6_5tuple_string, "ipv6_5tuple");
+
+cmdline_parse_token_num_t cmd_fc_add_default_ipv6_5tuple_port =
+	TOKEN_NUM_INITIALIZER(struct cmd_fc_add_default_ipv6_5tuple_result, port, UINT8);
+
+cmdline_parse_inst_t cmd_fc_add_default_ipv6_5tuple = {
+	.f = cmd_fc_add_default_ipv6_5tuple_parsed,
+	.data = NULL,
+	.help_str = "p <pipeline_id> flow add default ipv6_5tuple <port>",
+	.tokens = {
+		(void *) &cmd_fc_add_default_ipv6_5tuple_p_string,
+		(void *) &cmd_fc_add_default_ipv6_5tuple_pipeline_id,
+		(void *) &cmd_fc_add_default_ipv6_5tuple_flow_string,
+		(void *) &cmd_fc_add_default_ipv6_5tuple_add_string,
+		(void *) &cmd_fc_add_default_ipv6_5tuple_default_string,
+		(void *) &cmd_fc_add_default_ipv6_5tuple_ipv6_5tuple_string,
+		(void *) &cmd_fc_add_default_ipv6_5tuple_port,
+		NULL,
+	},
+};
+
+/*
+ * flow del default qinq
+ */
+
+struct cmd_fc_del_default_qinq_result {
+	cmdline_fixed_string_t p_string;
+	uint32_t pipeline_id;
+	cmdline_fixed_string_t flow_string;
+	cmdline_fixed_string_t del_string;
+	cmdline_fixed_string_t default_string;
+	cmdline_fixed_string_t qinq_string;
+};
+
+static void
+cmd_fc_del_default_qinq_parsed(
+	void *parsed_result,
+	__rte_unused struct cmdline *cl,
+	void *data)
+{
+	struct cmd_fc_del_default_qinq_result *params = parsed_result;
+	struct app_params *app = data;
+	enum flow_key_type type;
+	int status;
+
+	type = FLOW_KEY_QINQ;
+	status = app_pipeline_fc_del_default(app, params->pipeline_id, type);
+
+	if(status != 0)
+		printf("Command failed\n");
+}
+
+cmdline_parse_token_string_t cmd_fc_del_default_qinq_p_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_default_qinq_result, p_string, "p");
+
+cmdline_parse_token_num_t cmd_fc_del_default_qinq_pipeline_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_fc_del_default_qinq_result, pipeline_id, UINT32);
+
+cmdline_parse_token_string_t cmd_fc_del_default_qinq_flow_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_default_qinq_result, flow_string, "flow");
+
+cmdline_parse_token_string_t cmd_fc_del_default_qinq_del_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_default_qinq_result, del_string, "del");
+
+cmdline_parse_token_string_t cmd_fc_del_default_qinq_default_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_default_qinq_result, default_string, "default");
+
+cmdline_parse_token_string_t cmd_fc_del_default_qinq_qinq_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_default_qinq_result, qinq_string, "qinq");
+
+cmdline_parse_inst_t cmd_fc_del_default_qinq = {
+	.f = cmd_fc_del_default_qinq_parsed,
+	.data = NULL,
+	.help_str = "p <pipeline_id> flow del default qinq",
+	.tokens = {
+		(void *) &cmd_fc_del_default_qinq_p_string,
+		(void *) &cmd_fc_del_default_qinq_pipeline_id,
+		(void *) &cmd_fc_del_default_qinq_flow_string,
+		(void *) &cmd_fc_del_default_qinq_del_string,
+		(void *) &cmd_fc_del_default_qinq_default_string,
+		(void *) &cmd_fc_del_default_qinq_qinq_string,
+		NULL,
+	},
+};
+
+/*
+ * flow del default ipv4_5tuple
+ */
+
+struct cmd_fc_del_default_ipv4_5tuple_result {
+	cmdline_fixed_string_t p_string;
+	uint32_t pipeline_id;
+	cmdline_fixed_string_t flow_string;
+	cmdline_fixed_string_t del_string;
+	cmdline_fixed_string_t default_string;
+	cmdline_fixed_string_t ipv4_5tuple_string;
+};
+
+static void
+cmd_fc_del_default_ipv4_5tuple_parsed(
+	void *parsed_result,
+	__rte_unused struct cmdline *cl,
+	void *data)
+{
+	struct cmd_fc_del_default_ipv4_5tuple_result *params = parsed_result;
+	struct app_params *app = data;
+	enum flow_key_type type;
+	int status;
+
+	type = FLOW_KEY_IPV4_5TUPLE;
+	status = app_pipeline_fc_del_default(app, params->pipeline_id, type);
+
+	if(status != 0)
+		printf("Command failed\n");
+}
+
+cmdline_parse_token_string_t cmd_fc_del_default_ipv4_5tuple_p_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_default_ipv4_5tuple_result, p_string, "p");
+
+cmdline_parse_token_num_t cmd_fc_del_default_ipv4_5tuple_pipeline_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_fc_del_default_ipv4_5tuple_result, pipeline_id, UINT32);
+
+cmdline_parse_token_string_t cmd_fc_del_default_ipv4_5tuple_flow_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_default_ipv4_5tuple_result, flow_string, "flow");
+
+cmdline_parse_token_string_t cmd_fc_del_default_ipv4_5tuple_del_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_default_ipv4_5tuple_result, del_string, "del");
+
+cmdline_parse_token_string_t cmd_fc_del_default_ipv4_5tuple_default_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_default_ipv4_5tuple_result, default_string, "default");
+
+cmdline_parse_token_string_t cmd_fc_del_default_ipv4_5tuple_ipv4_5tuple_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_default_ipv4_5tuple_result, ipv4_5tuple_string, "ipv4_5tuple");
+
+cmdline_parse_inst_t cmd_fc_del_default_ipv4_5tuple = {
+	.f = cmd_fc_del_default_ipv4_5tuple_parsed,
+	.data = NULL,
+	.help_str = "p <pipeline_id> flow del default ipv4_5tuple",
+	.tokens = {
+		(void *) &cmd_fc_del_default_ipv4_5tuple_p_string,
+		(void *) &cmd_fc_del_default_ipv4_5tuple_pipeline_id,
+		(void *) &cmd_fc_del_default_ipv4_5tuple_flow_string,
+		(void *) &cmd_fc_del_default_ipv4_5tuple_del_string,
+		(void *) &cmd_fc_del_default_ipv4_5tuple_default_string,
+		(void *) &cmd_fc_del_default_ipv4_5tuple_ipv4_5tuple_string,
+		NULL,
+	},
+};
+
+/*
+ * flow del default ipv6_5tuple
+ */
+
+struct cmd_fc_del_default_ipv6_5tuple_result {
+	cmdline_fixed_string_t p_string;
+	uint32_t pipeline_id;
+	cmdline_fixed_string_t flow_string;
+	cmdline_fixed_string_t del_string;
+	cmdline_fixed_string_t default_string;
+	cmdline_fixed_string_t ipv6_5tuple_string;
+};
+
+static void
+cmd_fc_del_default_ipv6_5tuple_parsed(
+	void *parsed_result,
+	__rte_unused struct cmdline *cl,
+	void *data)
+{
+	struct cmd_fc_del_default_ipv6_5tuple_result *params = parsed_result;
+	struct app_params *app = data;
+	enum flow_key_type type;
+	int status;
+
+	type = FLOW_KEY_IPV6_5TUPLE;
+	status = app_pipeline_fc_del_default(app, params->pipeline_id, type);
+
+	if(status != 0)
+		printf("Command failed\n");
+}
+
+cmdline_parse_token_string_t cmd_fc_del_default_ipv6_5tuple_p_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_default_ipv6_5tuple_result, p_string, "p");
+
+cmdline_parse_token_num_t cmd_fc_del_default_ipv6_5tuple_pipeline_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_fc_del_default_ipv6_5tuple_result, pipeline_id, UINT32);
+
+cmdline_parse_token_string_t cmd_fc_del_default_ipv6_5tuple_flow_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_default_ipv6_5tuple_result, flow_string, "flow");
+
+cmdline_parse_token_string_t cmd_fc_del_default_ipv6_5tuple_del_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_default_ipv6_5tuple_result, del_string, "del");
+
+cmdline_parse_token_string_t cmd_fc_del_default_ipv6_5tuple_default_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_default_ipv6_5tuple_result, default_string, "default");
+
+cmdline_parse_token_string_t cmd_fc_del_default_ipv6_5tuple_ipv6_5tuple_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_fc_del_default_ipv6_5tuple_result, ipv6_5tuple_string, "ipv6_5tuple");
+
+cmdline_parse_inst_t cmd_fc_del_default_ipv6_5tuple = {
+	.f = cmd_fc_del_default_ipv6_5tuple_parsed,
+	.data = NULL,
+	.help_str = "p <pipeline_id> flow del default ipv6_5tuple",
+	.tokens = {
+		(void *) &cmd_fc_del_default_ipv6_5tuple_p_string,
+		(void *) &cmd_fc_del_default_ipv6_5tuple_pipeline_id,
+		(void *) &cmd_fc_del_default_ipv6_5tuple_flow_string,
+		(void *) &cmd_fc_del_default_ipv6_5tuple_del_string,
+		(void *) &cmd_fc_del_default_ipv6_5tuple_default_string,
+		(void *) &cmd_fc_del_default_ipv6_5tuple_ipv6_5tuple_string,
+		NULL,
+	},
+};
+
+/*
+ * flow ls
+ */
+
+struct cmd_fc_ls_result {
+	cmdline_fixed_string_t p_string;
+	uint32_t pipeline_id;
+	cmdline_fixed_string_t flow_string;
+	cmdline_fixed_string_t ls_string;
+};
+
+static void
+cmd_fc_ls_parsed(
+	void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	void *data)
+{
+	struct cmd_fc_ls_result *params = parsed_result;
+	struct app_params *app = data;
+
+	app_pipeline_fc_ls(app, params->pipeline_id);
 }
+
+cmdline_parse_token_string_t cmd_fc_ls_p_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_fc_ls_result, p_string, "p");
+
+cmdline_parse_token_num_t cmd_fc_ls_pipeline_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_fc_ls_result, pipeline_id, UINT32);
+
+cmdline_parse_token_string_t cmd_fc_ls_flow_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_fc_ls_result,
+	flow_string, "flow");
+
+cmdline_parse_token_string_t cmd_fc_ls_ls_string =
+	TOKEN_STRING_INITIALIZER(struct cmd_fc_ls_result, ls_string,
+	"ls");
+
+cmdline_parse_inst_t cmd_fc_ls = {
+	.f = cmd_fc_ls_parsed,
+	.data = NULL,
+	.help_str = "p <pipeline_id> flow ls",
+	.tokens = {
+		(void *) &cmd_fc_ls_p_string,
+		(void *) &cmd_fc_ls_pipeline_id,
+		(void *) &cmd_fc_ls_flow_string,
+		(void *) &cmd_fc_ls_ls_string,
+		NULL,
+	},
+};
+
+static cmdline_parse_ctx_t pipeline_cmds[] = {
+	(cmdline_parse_inst_t *) &cmd_fc_add_qinq,
+	(cmdline_parse_inst_t *) &cmd_fc_add_ipv4_5tuple,
+	(cmdline_parse_inst_t *) &cmd_fc_add_ipv6_5tuple,
+	(cmdline_parse_inst_t *) &cmd_fc_del_qinq,
+	(cmdline_parse_inst_t *) &cmd_fc_del_ipv4_5tuple,
+	(cmdline_parse_inst_t *) &cmd_fc_del_ipv6_5tuple,
+	(cmdline_parse_inst_t *) &cmd_fc_add_default_qinq,
+	(cmdline_parse_inst_t *) &cmd_fc_add_default_ipv4_5tuple,
+	(cmdline_parse_inst_t *) &cmd_fc_add_default_ipv6_5tuple,
+	(cmdline_parse_inst_t *) &cmd_fc_del_default_qinq,
+	(cmdline_parse_inst_t *) &cmd_fc_del_default_ipv4_5tuple,
+	(cmdline_parse_inst_t *) &cmd_fc_del_default_ipv6_5tuple,
+	(cmdline_parse_inst_t *) &cmd_fc_ls,
+	NULL,
+};
+
+static struct pipeline_fe_ops pipeline_flow_classification_fe_ops = {
+	.f_init = app_pipeline_fc_init,
+	.f_free = app_pipeline_fc_free,
+	.cmds = pipeline_cmds,
+};
+
+struct pipeline_type pipeline_flow_classification = {
+	.name = "FLOW_CLASSIF",
+	.ops = &pipeline_flow_classification_ops,
+	.fe_ops = &pipeline_flow_classification_fe_ops,
+};
diff --git a/examples/ip_pipeline/pipeline/pipeline_flow_classification.h b/examples/ip_pipeline/pipeline/pipeline_flow_classification.h
new file mode 100644
index 0000000..3f0b2aa
--- /dev/null
+++ b/examples/ip_pipeline/pipeline/pipeline_flow_classification.h
@@ -0,0 +1,41 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __INCLUDE_PIPELINE_FLOW_CLASSIFICATION_H__
+#define __INCLUDE_PIPELINE_FLOW_CLASSIFICATION_H__
+
+#include "pipeline.h"
+
+extern struct pipeline_type pipeline_flow_classification;
+
+#endif
diff --git a/examples/ip_pipeline/pipeline/pipeline_flow_classification_ops.c b/examples/ip_pipeline/pipeline/pipeline_flow_classification_ops.c
new file mode 100644
index 0000000..213894e
--- /dev/null
+++ b/examples/ip_pipeline/pipeline/pipeline_flow_classification_ops.c
@@ -0,0 +1,559 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string.h>
+
+#include <rte_common.h>
+#include <rte_malloc.h>
+#include <rte_table_hash.h>
+#include <rte_byteorder.h>
+
+#include "pipeline_common_ops.h"
+#include "pipeline_flow_classification_ops.h"
+
+enum flow_meter_type {
+	METER_TYPE_SRTCM,
+	METER_TYPE_TRTCM,
+};
+
+struct pipeline_flow_classification {
+	struct pipeline p;
+	pipeline_msg_req_handler custom_handlers[PIPELINE_FC_MSG_REQS];
+
+	uint32_t n_flows;
+	uint32_t key_offset;
+	uint32_t key_size;
+	uint32_t hash_offset;
+	uint32_t flow_id_offset;
+	uint32_t flow_stats;
+	uint32_t color_offset;
+	uint32_t input_color_offset;
+	enum flow_meter_type meter_type;
+} __rte_cache_aligned;
+
+static void *
+pipeline_fc_msg_req_custom_handler(struct pipeline *p, void *msg);
+
+static pipeline_msg_req_handler handlers[] = {
+	[PIPELINE_MSG_REQ_PING] = pipeline_msg_req_ping_handler,
+	[PIPELINE_MSG_REQ_STATS_PORT_IN] = pipeline_msg_req_stats_port_in_handler,
+	[PIPELINE_MSG_REQ_STATS_PORT_OUT] = pipeline_msg_req_stats_port_out_handler,
+	[PIPELINE_MSG_REQ_STATS_TABLE] = pipeline_msg_req_stats_table_handler,
+	[PIPELINE_MSG_REQ_PORT_IN_ENABLE] = pipeline_msg_req_port_in_enable_handler,
+	[PIPELINE_MSG_REQ_PORT_IN_DISABLE] = pipeline_msg_req_port_in_disable_handler,
+	[PIPELINE_MSG_REQ_CUSTOM] = pipeline_fc_msg_req_custom_handler,
+};
+
+static void *
+pipeline_fc_msg_req_add_handler(struct pipeline *p, void *msg);
+
+static void *
+pipeline_fc_msg_req_del_handler(struct pipeline *p, void *msg);
+
+static void *
+pipeline_fc_msg_req_add_default_handler(struct pipeline *p, void *msg);
+
+static void *
+pipeline_fc_msg_req_del_default_handler(struct pipeline *p, void *msg);
+
+static void *
+pipeline_fc_msg_req_add_all_handler(struct pipeline *p, void *msg);
+
+static void *
+pipeline_fc_msg_req_meter_handler(struct pipeline *p, void *msg);
+
+static void *
+pipeline_fc_msg_req_ls_handler(struct pipeline *p, void *msg);
+
+static pipeline_msg_req_handler custom_handlers[] = {
+		[PIPELINE_FC_MSG_REQ_FLOW_ADD] = pipeline_fc_msg_req_add_handler,
+		[PIPELINE_FC_MSG_REQ_FLOW_DEL] = pipeline_fc_msg_req_del_handler,
+		[PIPELINE_FC_MSG_REQ_FLOW_ADD_DEFAULT] = pipeline_fc_msg_req_add_default_handler,
+		[PIPELINE_FC_MSG_REQ_FLOW_DEL_DEFAULT] = pipeline_fc_msg_req_del_default_handler,
+		[PIPELINE_FC_MSG_REQ_FLOW_ADD_ALL] = pipeline_fc_msg_req_add_all_handler,
+		[PIPELINE_FC_MSG_REQ_FLOW_METER] = pipeline_fc_msg_req_meter_handler,
+		[PIPELINE_FC_MSG_REQ_FLOW_LS] = pipeline_fc_msg_req_ls_handler,
+};
+
+static uint64_t
+test_hash(
+	void *key,
+	__attribute__((unused)) uint32_t key_size,
+	__attribute__((unused)) uint64_t seed)
+{
+	uint32_t *k32 = (uint32_t *) key;
+	uint32_t ip_dst = rte_be_to_cpu_32(k32[0]);
+	uint64_t signature = (ip_dst >> 2) | ((ip_dst & 0x3) << 30);
+
+	return signature;
+}
+
+static int
+pipeline_fc_parse_args(struct pipeline_flow_classification *p,
+	struct pipeline_params *params)
+{
+	uint32_t n_flows_present = 0;
+	uint32_t key_offset_present = 0;
+	uint32_t key_size_present = 0;
+	uint32_t hash_offset_present = 0;
+	uint32_t flow_id_offset_present = 0;
+	uint32_t flow_stats_present = 0;
+	uint32_t color_offset_present = 0;
+	uint32_t input_color_offset_present = 0;
+	uint32_t meter_type_present = 0;
+
+	uint32_t i;
+
+	for (i = 0; i < params->n_args; i++) {
+		char *arg_name = params->args_name[i];
+		char *arg_value = params->args_value[i];
+
+		if (strcmp(arg_name, "n_flows") == 0) {
+			if (n_flows_present)
+				return -1;
+			n_flows_present = 1;
+
+			p->n_flows = atoi(arg_value);
+		} else if (strcmp(arg_name, "key_offset") == 0) {
+			if (key_offset_present)
+				return -1;
+			key_offset_present = 1;
+
+			p->key_offset = atoi(arg_value);
+		} else if (strcmp(arg_name, "key_size") == 0) {
+			if (key_size_present)
+				return -1;
+			key_size_present = 1;
+
+			p->key_size = atoi(arg_value);
+		} else if (strcmp(arg_name, "hash_offset") == 0) {
+			if (hash_offset_present)
+				return -1;
+			hash_offset_present = 1;
+
+			p->hash_offset = atoi(arg_value);
+		} else if (strcmp(arg_name, "flow_id_offset") == 0) {
+			if (flow_id_offset_present)
+				return -1;
+			flow_id_offset_present = 1;
+
+			p->flow_id_offset = atoi(arg_value);
+		} else if (strcmp(arg_name, "flow_stats") == 0) {
+			if (flow_stats_present)
+				return -1;
+			flow_stats_present = 1;
+
+			if (strcmp(arg_value, "off") == 0)
+				p->flow_stats = 0;
+			else if (strcmp(arg_value, "on") == 0)
+				p->flow_stats = 1;
+			else
+				return -1;
+		} else if (strcmp(arg_name, "color_offset") == 0) {
+			if (color_offset_present)
+				return -1;
+			color_offset_present = 1;
+
+			p->color_offset = atoi(arg_value);
+		} else if (strcmp(arg_name, "input_color_offset") == 0) {
+			if (input_color_offset_present)
+				return -1;
+			input_color_offset_present = 1;
+
+			p->input_color_offset = atoi(arg_value);
+		} else if (strcmp(arg_name, "meter_type") == 0) {
+			if (meter_type_present)
+				return -1;
+			meter_type_present = 1;
+
+			if (strcmp(arg_value, "srtcm") == 0)
+				p->meter_type = METER_TYPE_SRTCM;
+			else if (strcmp(arg_value, "trtcm") == 0)
+				p->meter_type = METER_TYPE_TRTCM;
+			else
+				return -1;
+		} else {
+			/* Unknown command */
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+static void * pipeline_init(struct pipeline_params *params,
+	__rte_unused void *arg)
+{
+	struct pipeline *p;
+	struct pipeline_flow_classification *p_fc;
+	uint32_t size, i;
+
+	/* Check input arguments */
+	if (params == NULL)
+		return NULL;
+
+	/* Memory allocation */
+	size = RTE_CACHE_LINE_ROUNDUP(sizeof(struct pipeline_flow_classification));
+	p_fc = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
+	if (p_fc == NULL)
+		return NULL;
+	p = &p_fc->p;
+
+	strcpy(p->name, params->name);
+
+	/* Parse arguments */
+	if (pipeline_fc_parse_args(p_fc, params))
+		return NULL;
+
+	/* Pipeline */
+	{
+		struct rte_pipeline_params pipeline_params = {
+			.name = "FLOW_CLASSIF",
+			.socket_id = params->socket_id,
+			.offset_port_id = 0,
+		};
+
+		p->p = rte_pipeline_create(&pipeline_params);
+		if (p->p == NULL) {
+			rte_free(p);
+			return NULL;
+		}
+	}
+
+	/* Input ports */
+	p->n_ports_in = params->n_ports_in;
+	for (i = 0; i < p->n_ports_in; i++) {
+		struct rte_pipeline_port_in_params port_params = {
+			.ops = pipeline_port_in_params_get_ops(&params->port_in[i]),
+			.arg_create = pipeline_port_in_params_convert(&params->port_in[i]),
+			.f_action = NULL,
+			.arg_ah = NULL,
+			.burst_size = params->port_in[i].burst_size,
+		};
+
+		int status = rte_pipeline_port_in_create(p->p,
+			&port_params,
+			&p->port_in_id[i]);
+
+		if (status) {
+			rte_pipeline_free(p->p);
+			rte_free(p);
+			return NULL;
+		}
+	}
+
+	/* Output ports */
+	p->n_ports_out = params->n_ports_out;
+	for (i = 0; i < p->n_ports_out; i++) {
+		struct rte_pipeline_port_out_params port_params = {
+			.ops = pipeline_port_out_params_get_ops(&params->port_out[i]),
+			.arg_create = pipeline_port_out_params_convert(&params->port_out[i]),
+			.f_action = NULL,
+			.f_action_bulk = NULL,
+			.arg_ah = NULL,
+		};
+
+		int status = rte_pipeline_port_out_create(p->p,
+			&port_params,
+			&p->port_out_id[i]);
+
+		if (status) {
+			rte_pipeline_free(p->p);
+			rte_free(p);
+			return NULL;
+		}
+	}
+
+	/* Tables */
+	{
+		p->n_tables = 1;
+		struct rte_table_hash_key8_ext_params table_hash_params = {
+				.n_entries = p_fc->n_flows,
+				.n_entries_ext = 1,
+				.signature_offset = 0,
+				.key_offset = p_fc->key_offset,
+				.f_hash = &test_hash,
+				.seed = 0,
+		};
+
+		struct rte_pipeline_table_params table_params = {
+			.ops = &rte_table_hash_key8_ext_ops,
+			.arg_create = &table_hash_params,
+			.f_action_hit = NULL,
+			.f_action_miss = NULL,
+			.arg_ah = NULL,
+			.action_data_size = 0,
+		};
+
+		int status = rte_pipeline_table_create(p->p,
+			&table_params,
+			&p->table_id[0]);
+
+
+		if (status) {
+			rte_pipeline_free(p->p);
+			rte_free(p);
+			return NULL;
+		}
+	}
+
+	/* Connecting input ports to tables */
+	for (i = 0; i < p->n_ports_in; i++) {
+		int status = rte_pipeline_port_in_connect_to_table(p->p,
+			p->port_in_id[i],
+			p->table_id[0]);
+
+		if (status) {
+			rte_pipeline_free(p->p);
+			rte_free(p);
+			return NULL;
+		}
+	}
+
+	/* Enable input ports */
+	for (i = 0; i < p->n_ports_in; i++) {
+		int status = rte_pipeline_port_in_enable(p->p,
+			p->port_in_id[i]);
+
+		if (status) {
+			rte_pipeline_free(p->p);
+			rte_free(p);
+			return NULL;
+		}
+	}
+
+	/* Check pipeline consistency */
+	if (rte_pipeline_check(p->p) < 0) {
+		rte_pipeline_free(p->p);
+		rte_free(p);
+		return NULL;
+	}
+
+	/* Message queues */
+	p->n_msgq = params->n_msgq;
+	for (i = 0; i < p->n_msgq; i++)
+		p->msgq_in[i] = params->msgq_in[i];
+	for (i = 0; i < p->n_msgq; i++)
+		p->msgq_out[i] = params->msgq_out[i];
+
+	/* Message handlers */
+	memcpy(p->handlers, handlers, sizeof(p->handlers));
+	memcpy(p_fc->custom_handlers,
+		custom_handlers,
+		sizeof(p_fc->custom_handlers));
+
+	return p;
+}
+
+static int
+pipeline_free(void *pipeline)
+{
+	struct pipeline *p = (struct pipeline *) pipeline;
+
+	/* Check input arguments */
+	if (p == NULL)
+		return -1;
+
+	/* Free resources */
+	rte_pipeline_free(p->p);
+	rte_free(p);
+	return 0;
+}
+
+static int
+pipeline_timer(void *pipeline)
+{
+	struct pipeline *p = (struct pipeline *) pipeline;
+
+	pipeline_msg_req_handle(p);
+	rte_pipeline_flush(p->p);
+
+	return 0;
+}
+
+static void *
+pipeline_fc_msg_req_custom_handler(struct pipeline *p, void *msg)
+{
+	struct pipeline_flow_classification *p_fc =
+			(struct pipeline_flow_classification *) p;
+	struct pipeline_custom_msg_req *req = msg;
+	pipeline_msg_req_handler f_handle;
+
+	f_handle = (req->subtype < PIPELINE_FC_MSG_REQS)?
+		p_fc->custom_handlers[req->subtype] :
+		pipeline_msg_req_invalid_handler;
+
+	if (f_handle == NULL)
+		f_handle = pipeline_msg_req_invalid_handler;
+
+	return f_handle(p, req);
+}
+
+static void *
+pipeline_fc_msg_req_add_handler(struct pipeline *p, void *msg)
+{
+	struct pipeline_fc_add_msg_req *req = msg;
+	struct pipeline_fc_add_msg_rsp *rsp = msg;
+
+	struct rte_pipeline_table_entry entry = {
+		.action = RTE_PIPELINE_ACTION_PORT,
+		{.port_id = p->port_out_id[req->port_id]},
+	};
+
+	switch (req->key.type) {
+		case FLOW_KEY_QINQ: {
+			uint64_t svlan = req->key.key.qinq.svlan;
+			uint64_t cvlan = req->key.key.qinq.cvlan;
+			uint64_t key = rte_bswap64((svlan << 48) | (cvlan << 16));
+
+		rsp->status = rte_pipeline_table_entry_add(p->p, p->table_id[0], &key,
+				&entry, &rsp->key_found,
+				(struct rte_pipeline_table_entry **) &rsp->entry_ptr);
+		break;
+		}
+		case FLOW_KEY_IPV4_5TUPLE: {
+		rsp->status = rte_pipeline_table_entry_add(p->p, p->table_id[0],
+				req->key.key.raw, &entry, &rsp->key_found,
+				(struct rte_pipeline_table_entry **) &rsp->entry_ptr);
+		break;
+		}
+		case FLOW_KEY_IPV6_5TUPLE: {
+		rsp->status = rte_pipeline_table_entry_add(p->p, p->table_id[0],
+				req->key.key.raw, &entry, &rsp->key_found,
+				(struct rte_pipeline_table_entry **) &rsp->entry_ptr);
+		break;
+		}
+	}
+
+	RTE_LOG(INFO, USER1, "%s Back-End: Key %s\n",
+		p->name,
+		(rsp->key_found)? "found" : "not found");
+
+	return rsp;
+}
+
+static void *
+pipeline_fc_msg_req_del_handler(struct pipeline *p, void *msg)
+{
+	struct pipeline_fc_del_msg_req *req = msg;
+	struct pipeline_fc_del_msg_rsp *rsp = msg;
+
+	switch (req->key.type) {
+		case FLOW_KEY_QINQ: {
+			uint64_t svlan = req->key.key.qinq.svlan;
+			uint64_t cvlan = req->key.key.qinq.cvlan;
+			uint64_t key = rte_bswap64((svlan << 48) | (cvlan << 16));
+
+			rsp->status = rte_pipeline_table_entry_delete(p->p, p->table_id[0],
+					&key, &rsp->key_found, NULL);
+			break;
+		}
+		case FLOW_KEY_IPV4_5TUPLE: {
+			rsp->status = rte_pipeline_table_entry_delete(p->p, p->table_id[0],
+				req->key.key.raw, &rsp->key_found, NULL);
+			break;
+		}
+		case FLOW_KEY_IPV6_5TUPLE: {
+			rsp->status = rte_pipeline_table_entry_delete(p->p, p->table_id[0],
+				req->key.key.raw, &rsp->key_found, NULL);
+			break;
+		}
+	}
+
+	RTE_LOG(INFO, USER1, "%s Back-End: Key %s\n",
+		p->name,
+		(rsp->key_found)? "found" : "not found");
+
+	return rsp;
+}
+
+static void *
+pipeline_fc_msg_req_add_default_handler(struct pipeline *p, void *msg)
+{
+	struct pipeline_fc_add_default_msg_req *req = msg;
+	struct pipeline_fc_add_default_msg_rsp *rsp = msg;
+
+	struct rte_pipeline_table_entry default_entry = {
+		.action = RTE_PIPELINE_ACTION_PORT,
+		{.port_id = p->port_out_id[req->port_id]},
+	};
+
+	rsp->status = rte_pipeline_table_default_entry_add(p->p, p->table_id[0],
+			&default_entry,
+			(struct rte_pipeline_table_entry **) &rsp->default_entry_ptr);
+
+	return rsp;
+}
+
+static void *
+pipeline_fc_msg_req_del_default_handler(struct pipeline *p, void *msg)
+{
+	struct pipeline_fc_del_default_msg_rsp *rsp = msg;
+
+	rsp->status = rte_pipeline_table_default_entry_delete(p->p,
+		p->table_id[0], NULL);
+
+	return rsp;
+}
+
+static void *
+pipeline_fc_msg_req_add_all_handler(struct pipeline *p, void *msg)
+{
+	(void) p;
+	(void) msg;
+	return NULL;
+}
+
+static void *
+pipeline_fc_msg_req_meter_handler(struct pipeline *p, void *msg)
+{
+	(void) p;
+	(void) msg;
+	return NULL;
+}
+
+static void *
+pipeline_fc_msg_req_ls_handler(struct pipeline *p, void *msg)
+{
+	(void) p;
+	(void) msg;
+	return NULL;
+}
+
+struct pipeline_ops pipeline_flow_classification_ops = {
+		.f_init = pipeline_init,
+		.f_free = pipeline_free,
+		.f_run = NULL,
+		.f_timer = pipeline_timer,
+		.f_track = NULL,
+};
diff --git a/examples/ip_pipeline/pipeline/pipeline_flow_classification_ops.h b/examples/ip_pipeline/pipeline/pipeline_flow_classification_ops.h
new file mode 100644
index 0000000..a3f9b00
--- /dev/null
+++ b/examples/ip_pipeline/pipeline/pipeline_flow_classification_ops.h
@@ -0,0 +1,150 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __INCLUDE_PIPELINE_FLOW_CLASSIFICATION_OPS_H__
+#define __INCLUDE_PIPELINE_FLOW_CLASSIFICATION_OPS_H__
+
+#include "pipeline.h"
+#include "pipeline_common.h"
+
+enum pipeline_fc_msg_req_type {
+	PIPELINE_FC_MSG_REQ_FLOW_ADD = 0,
+	PIPELINE_FC_MSG_REQ_FLOW_DEL,
+	PIPELINE_FC_MSG_REQ_FLOW_ADD_DEFAULT,
+	PIPELINE_FC_MSG_REQ_FLOW_DEL_DEFAULT,
+	PIPELINE_FC_MSG_REQ_FLOW_ADD_ALL,
+	PIPELINE_FC_MSG_REQ_FLOW_METER,
+	PIPELINE_FC_MSG_REQ_FLOW_LS,
+	PIPELINE_FC_MSG_REQS,
+};
+
+enum flow_key_type {
+	FLOW_KEY_QINQ,
+	FLOW_KEY_IPV4_5TUPLE,
+	FLOW_KEY_IPV6_5TUPLE,
+};
+
+struct flow_key_qinq {
+	uint16_t svlan;
+	uint16_t cvlan;
+};
+
+struct flow_key_ipv4_5tuple {
+	uint32_t ip_src;
+	uint32_t ip_dst;
+	uint16_t port_src;
+	uint16_t port_dst;
+	uint32_t proto;
+};
+
+struct flow_key_ipv6_5tuple {
+	uint8_t ip_src[16];
+	uint8_t ip_dst[16];
+	uint16_t port_src;
+	uint16_t port_dst;
+	uint32_t proto;
+};
+
+struct pipeline_fc_key {
+	enum flow_key_type type;
+	union {
+		struct flow_key_qinq qinq;
+		struct flow_key_ipv4_5tuple ipv4_5tuple;
+		struct flow_key_ipv6_5tuple ipv6_5tuple;
+		uint8_t raw[40];
+	} key;
+};
+
+/*
+ * MSG ADD
+ */
+struct pipeline_fc_add_msg_req {
+	enum pipeline_msg_req_type type;
+	enum pipeline_fc_msg_req_type subtype;
+
+	struct pipeline_fc_key key;
+
+	uint32_t port_id;
+};
+
+struct pipeline_fc_add_msg_rsp {
+	int status;
+	int key_found;
+	void *entry_ptr;
+};
+
+/*
+ * MSG DEL
+ */
+struct pipeline_fc_del_msg_req {
+	enum pipeline_msg_req_type type;
+	enum pipeline_fc_msg_req_type subtype;
+
+	struct pipeline_fc_key key;
+};
+
+struct pipeline_fc_del_msg_rsp {
+	int status;
+	int key_found;
+};
+
+/*
+ * MSG ADD DEFAULT
+ */
+struct pipeline_fc_add_default_msg_req {
+	enum pipeline_msg_req_type type;
+	enum pipeline_fc_msg_req_type subtype;
+
+	uint32_t port_id;
+};
+
+struct pipeline_fc_add_default_msg_rsp {
+	int status;
+	void *default_entry_ptr;
+};
+
+/*
+ * MSG DEL DEFAULT
+ */
+struct pipeline_fc_del_default_msg_req {
+	enum pipeline_msg_req_type type;
+	enum pipeline_fc_msg_req_type subtype;
+};
+
+struct pipeline_fc_del_default_msg_rsp {
+	int status;
+};
+
+extern struct pipeline_ops pipeline_flow_classification_ops;
+
+#endif
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: [PATCH 01/11] ip_pipeline: add parsing for config files with new syntax
  2015-05-29 15:43 ` [PATCH 01/11] ip_pipeline: add parsing for config files with new syntax Maciej Gajdzica
@ 2015-06-01 13:34   ` Stephen Hemminger
  2015-06-04 17:29     ` Dumitrescu, Cristian
  0 siblings, 1 reply; 16+ messages in thread
From: Stephen Hemminger @ 2015-06-01 13:34 UTC (permalink / raw)
  To: Maciej Gajdzica; +Cc: dev

On Fri, 29 May 2015 17:43:08 +0200
Maciej Gajdzica <maciejx.t.gajdzica@intel.com> wrote:

> +/**
> + * Find object of name *name* in *obj_array* which is constant size array of
> + * elements that have field *name*.
> + *
> + * @param obj_array
> + *  Constant size array
> + * @param name
> + *  name of object to find.
> + * @return
> + *  Pointer to object in *obj_array* or NULL if not found.
> + */
> +#define APP_PARAM_FIND(obj_array, key)                          \
> +({                                                              \
> +	ssize_t obj_idx;                                            \
> +	const ssize_t obj_count = RTE_DIM(obj_array);               \
> +                                                                \
> +	for (obj_idx = 0; obj_idx < obj_count; obj_idx++) {         \
> +		if (!APP_PARAM_VALID(&((obj_array)[obj_idx])))          \
> +			continue;                                           \
> +			                                                    \
> +		if (strcmp(key, (obj_array)[obj_idx].name) == 0)        \
> +			break;                                              \
> +	}                                                           \
> +	obj_idx < obj_count ? obj_idx : -ENOENT;                    \
> +})

Converting all the functions to macro's is a step backwards in several ways.
 * macro's are hard to support
 * macro's lead to lots of programming errors
 * macro's look ugly

Why not use real functions, or make the example into C++ if you have
to do generic programming.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 01/11] ip_pipeline: add parsing for config files with new syntax
  2015-06-01 13:34   ` Stephen Hemminger
@ 2015-06-04 17:29     ` Dumitrescu, Cristian
  0 siblings, 0 replies; 16+ messages in thread
From: Dumitrescu, Cristian @ 2015-06-04 17:29 UTC (permalink / raw)
  To: Stephen Hemminger, Gajdzica, MaciejX T; +Cc: dev



> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Stephen
> Hemminger
> Sent: Monday, June 1, 2015 2:34 PM
> To: Gajdzica, MaciejX T
> Cc: dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH 01/11] ip_pipeline: add parsing for config
> files with new syntax
> 
> On Fri, 29 May 2015 17:43:08 +0200
> Maciej Gajdzica <maciejx.t.gajdzica@intel.com> wrote:
> 
> > +/**
> > + * Find object of name *name* in *obj_array* which is constant size array
> of
> > + * elements that have field *name*.
> > + *
> > + * @param obj_array
> > + *  Constant size array
> > + * @param name
> > + *  name of object to find.
> > + * @return
> > + *  Pointer to object in *obj_array* or NULL if not found.
> > + */
> > +#define APP_PARAM_FIND(obj_array, key)                          \
> > +({                                                              \
> > +	ssize_t obj_idx;                                            \
> > +	const ssize_t obj_count = RTE_DIM(obj_array);               \
> > +                                                                \
> > +	for (obj_idx = 0; obj_idx < obj_count; obj_idx++) {         \
> > +		if (!APP_PARAM_VALID(&((obj_array)[obj_idx])))          \
> > +			continue;                                           \
> > +			                                                    \
> > +		if (strcmp(key, (obj_array)[obj_idx].name) == 0)        \
> > +			break;                                              \
> > +	}                                                           \
> > +	obj_idx < obj_count ? obj_idx : -ENOENT;                    \
> > +})
> 
> Converting all the functions to macro's is a step backwards in several ways.
>  * macro's are hard to support
>  * macro's lead to lots of programming errors
>  * macro's look ugly
> 
> Why not use real functions, or make the example into C++ if you have
> to do generic programming.

We are using macros here only because C language does not offer us a better choice (i.e. support for templates). The alternative would be to write a quasi-identical function per each object type, which would lead to unnecessary code duplication.

We did our best to keep the number of macros small and to implement each macro as straightforward as possible.

All the DPDK sample applications are written in C, so this is the main reason we want to keep this application as C code. As people expect C code from DPDK sample apps, it is easier for people to reuse parts of this application.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 00/11] ip_pipeline: ip_pipeline application enhancements
  2015-05-29 15:43 [PATCH 00/11] ip_pipeline: ip_pipeline application enhancements Maciej Gajdzica
                   ` (10 preceding siblings ...)
  2015-05-29 15:43 ` [PATCH 11/11] ip_pipeline: added new implementation of flow classification pipeline Maciej Gajdzica
@ 2015-06-23 13:48 ` Thomas Monjalon
  2015-06-23 13:54   ` Gajdzica, MaciejX T
  11 siblings, 1 reply; 16+ messages in thread
From: Thomas Monjalon @ 2015-06-23 13:48 UTC (permalink / raw)
  To: Maciej Gajdzica; +Cc: dev

Is this patchset still candidate for 2.1?

2015-05-29 17:43, Maciej Gajdzica:
> This patchset enhances functionality of ip_pipeline application. New config
> file syntax is introduced, so parser is changed. Changed structure of the
> application. Now every global variable is stored in app_struct in app.h.
> Syntax of pipeline cli commands was changed. Implementation of cli commands
> for every pipeline is moved to the separate file.
> 
> 
> Maciej Gajdzica (11):
>   ip_pipeline: add parsing for config files with new syntax
>   ip_pipeline: added config checks
>   ip_pipeline: modified init to match new params struct
>   ip_pipeline: moved pipelines to separate folder
>   ip_pipeline: added master pipeline
>   ip_pipeline: added application thread
>   ip_pipeline: moved config files to separate folder
>   ip_pipeline: added new implementation of passthrough pipeline
>   ip_pipeline: added new implementation of firewall pipeline
>   ip_pipeline: added new implementation of routing pipeline
>   ip_pipeline: added new implementation of flow classification pipeline

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 00/11] ip_pipeline: ip_pipeline application enhancements
  2015-06-23 13:48 ` [PATCH 00/11] ip_pipeline: ip_pipeline application enhancements Thomas Monjalon
@ 2015-06-23 13:54   ` Gajdzica, MaciejX T
  0 siblings, 0 replies; 16+ messages in thread
From: Gajdzica, MaciejX T @ 2015-06-23 13:54 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev

> -----Original Message-----
> From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> Sent: Tuesday, June 23, 2015 3:49 PM
> To: Gajdzica, MaciejX T
> Cc: dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH 00/11] ip_pipeline: ip_pipeline application
> enhancements
> 
> Is this patchset still candidate for 2.1?

Yes, it is, but some changes need to be made. V2 will be send in a few days.

Best Regards
Maciek

> 
> 2015-05-29 17:43, Maciej Gajdzica:
> > This patchset enhances functionality of ip_pipeline application. New
> > config file syntax is introduced, so parser is changed. Changed
> > structure of the application. Now every global variable is stored in app_struct
> in app.h.
> > Syntax of pipeline cli commands was changed. Implementation of cli
> > commands for every pipeline is moved to the separate file.
> >
> >
> > Maciej Gajdzica (11):
> >   ip_pipeline: add parsing for config files with new syntax
> >   ip_pipeline: added config checks
> >   ip_pipeline: modified init to match new params struct
> >   ip_pipeline: moved pipelines to separate folder
> >   ip_pipeline: added master pipeline
> >   ip_pipeline: added application thread
> >   ip_pipeline: moved config files to separate folder
> >   ip_pipeline: added new implementation of passthrough pipeline
> >   ip_pipeline: added new implementation of firewall pipeline
> >   ip_pipeline: added new implementation of routing pipeline
> >   ip_pipeline: added new implementation of flow classification
> > pipeline
> 

^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2015-06-23 13:54 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-05-29 15:43 [PATCH 00/11] ip_pipeline: ip_pipeline application enhancements Maciej Gajdzica
2015-05-29 15:43 ` [PATCH 01/11] ip_pipeline: add parsing for config files with new syntax Maciej Gajdzica
2015-06-01 13:34   ` Stephen Hemminger
2015-06-04 17:29     ` Dumitrescu, Cristian
2015-05-29 15:43 ` [PATCH 02/11] ip_pipeline: added config checks Maciej Gajdzica
2015-05-29 15:43 ` [PATCH 03/11] ip_pipeline: modified init to match new params struct Maciej Gajdzica
2015-05-29 15:43 ` [PATCH 04/11] ip_pipeline: moved pipelines to separate folder Maciej Gajdzica
2015-05-29 15:43 ` [PATCH 05/11] ip_pipeline: added master pipeline Maciej Gajdzica
2015-05-29 15:43 ` [PATCH 06/11] ip_pipeline: added application thread Maciej Gajdzica
2015-05-29 15:43 ` [PATCH 07/11] ip_pipeline: moved config files to separate folder Maciej Gajdzica
2015-05-29 15:43 ` [PATCH 08/11] ip_pipeline: added new implementation of passthrough pipeline Maciej Gajdzica
2015-05-29 15:43 ` [PATCH 09/11] ip_pipeline: added new implementation of firewall pipeline Maciej Gajdzica
2015-05-29 15:43 ` [PATCH 10/11] ip_pipeline: added new implementation of routing pipeline Maciej Gajdzica
2015-05-29 15:43 ` [PATCH 11/11] ip_pipeline: added new implementation of flow classification pipeline Maciej Gajdzica
2015-06-23 13:48 ` [PATCH 00/11] ip_pipeline: ip_pipeline application enhancements Thomas Monjalon
2015-06-23 13:54   ` Gajdzica, MaciejX T

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.