DPDK patches and discussions
 help / color / mirror / Atom feed
* [dpdk-dev] [PATCH 00/37] ip_pipeline: refactoring
@ 2018-03-09 18:23 Jasvinder Singh
  2018-03-09 18:23 ` [dpdk-dev] [PATCH 01/37] pipeline: add pipeline table action APIs Jasvinder Singh
                   ` (36 more replies)
  0 siblings, 37 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-09 18:23 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Refactored the IP pipeline application. As result, the code base
size (lines of code) reduces by ~60%.

1. Moved table actions into the librte_pipeline library. As result,
   the pre-fabricated pipelines from the application pipeline folder
   were removed. The flexibility is greatly improved, as now any
   action can be combined with any match (i.e. table type), which
   was not possible before.

2. Removed configuration file as the initialization method. Now
   all the pipelines are set up and assigned to threads through
   CLI commands for improved flexibility.

3. Replaced the local CLI with remote CLI. Any standard TCP
   client (e.g. telnet, netcat) can now connect to the app,
   send request as command string through the network and wait
   for the response string before pushing the next command.
   Results in better flexibility and automation.


Jasvinder Singh (37):
  pipeline: add pipeline table action APIs
  pipeline: get pipeline table action params
  pipeline: add traffic metering action
  pipeline: add traffic manager action
  pipeline: add packet encapsulation action
  pipeline: add nat action
  pipeline: add ttl update action
  pipeline: add statistics read action
  pipeline: add timestamp action
  ip_pipeline: rework and improvements
  ip_pipeline: add cli interface
  ip_pipeline: add mempool object for pipeline
  ip_pipeline: add link object
  ip_pipeline: add software queue object
  ip_pipeline: add traffic manager object
  ip_pipeline: add tap object
  ip_pipeline: add kni object
  ip_pipeline: add action profile object
  ip_pipeline: add pipeline object
  ip_pipeline: add threads
  ip_pipeline: add thread runtime
  ip_pipeline: add cli to enable and disable pipeline
  ip_pipeline: add cli to enable and disable pipeline port
  ip_pipeline: add cli to read pipeline port and table stats
  ip_pipeline: add cli for pipeline table entries
  ip_pipeline: add cli to delete pipeline table entry
  ip_pipeline: add cli to read pipeline table entry stats
  ip_pipeline: add cli to configure meter profile
  ip_pipeline: add cli to read meter stats
  ip_pipeline: add cli to update dscp table
  ip_pipeline: add cli to read ttl stats
  ip_pipeline: add l2fwd example
  ip_pipeline: add KNI port example
  ip_pipeline: add TAP port example
  ip_pipeline: add route example
  ip_pipeline: add firewall example
  ip_pipeline: add flow classification example

 doc/api/doxy-api-index.md                          |    1 +
 examples/ip_pipeline/Makefile                      |   48 +-
 examples/ip_pipeline/app.h                         | 1401 -------
 examples/ip_pipeline/cli.c                         | 4261 ++++++++++++++++++++
 examples/ip_pipeline/cli.h                         |   18 +
 examples/ip_pipeline/common.h                      |   12 +
 examples/ip_pipeline/config/action.cfg             |   68 -
 examples/ip_pipeline/config/action.sh              |  119 -
 examples/ip_pipeline/config/action.txt             |    8 -
 examples/ip_pipeline/config/diagram-generator.py   |  317 --
 .../ip_pipeline/config/edge_router_downstream.cfg  |   97 -
 .../ip_pipeline/config/edge_router_downstream.sh   |   13 -
 .../ip_pipeline/config/edge_router_upstream.cfg    |  124 -
 .../ip_pipeline/config/edge_router_upstream.sh     |   33 -
 examples/ip_pipeline/config/firewall.cfg           |   68 -
 examples/ip_pipeline/config/firewall.sh            |   13 -
 examples/ip_pipeline/config/firewall.txt           |    9 -
 examples/ip_pipeline/config/flow.cfg               |   72 -
 examples/ip_pipeline/config/flow.sh                |   25 -
 examples/ip_pipeline/config/flow.txt               |   17 -
 examples/ip_pipeline/config/ip_pipeline.cfg        |    9 -
 examples/ip_pipeline/config/ip_pipeline.sh         |    5 -
 examples/ip_pipeline/config/kni.cfg                |   67 -
 examples/ip_pipeline/config/l2fwd.cfg              |   58 -
 examples/ip_pipeline/config/l3fwd.cfg              |   68 -
 examples/ip_pipeline/config/l3fwd.sh               |   33 -
 examples/ip_pipeline/config/l3fwd_arp.cfg          |   70 -
 examples/ip_pipeline/config/l3fwd_arp.sh           |   43 -
 examples/ip_pipeline/config/network_layers.cfg     |  227 --
 examples/ip_pipeline/config/network_layers.sh      |   79 -
 .../ip_pipeline/config/pipeline-to-core-mapping.py |  906 -----
 examples/ip_pipeline/config/tap.cfg                |   64 -
 examples/ip_pipeline/config/tm_profile.cfg         |  105 -
 examples/ip_pipeline/config_check.c                |  488 ---
 examples/ip_pipeline/config_parse.c                | 3395 ----------------
 examples/ip_pipeline/config_parse_tm.c             |  419 --
 examples/ip_pipeline/conn.c                        |  326 ++
 examples/ip_pipeline/conn.h                        |   47 +
 examples/ip_pipeline/cpu_core_map.c                |  471 ---
 examples/ip_pipeline/cpu_core_map.h                |   40 -
 examples/ip_pipeline/examples/firewall.cli         |   59 +
 examples/ip_pipeline/examples/flow.cli             |   60 +
 examples/ip_pipeline/examples/kni.cli              |   69 +
 examples/ip_pipeline/examples/l2fwd.cli            |   53 +
 examples/ip_pipeline/examples/route.cli            |   60 +
 examples/ip_pipeline/examples/tap.cli              |   66 +
 examples/ip_pipeline/{pipeline => }/hash_func.h    |    3 +-
 .../ip_pipeline/{pipeline => }/hash_func_arm64.h   |    0
 examples/ip_pipeline/init.c                        | 1927 ---------
 examples/ip_pipeline/kni.c                         |  165 +
 examples/ip_pipeline/kni.h                         |   44 +
 examples/ip_pipeline/link.c                        |  268 ++
 examples/ip_pipeline/link.h                        |   63 +
 examples/ip_pipeline/main.c                        |  253 +-
 examples/ip_pipeline/mempool.c                     |   81 +
 examples/ip_pipeline/mempool.h                     |   40 +
 examples/ip_pipeline/meson.build                   |   35 +-
 examples/ip_pipeline/parser.c                      |   16 +-
 examples/ip_pipeline/parser.h                      |    8 +
 examples/ip_pipeline/pipeline.c                    |  930 +++++
 examples/ip_pipeline/pipeline.h                    |  373 +-
 .../ip_pipeline/pipeline/pipeline_actions_common.h |  202 -
 examples/ip_pipeline/pipeline/pipeline_common_be.c |  176 -
 examples/ip_pipeline/pipeline/pipeline_common_be.h |  134 -
 examples/ip_pipeline/pipeline/pipeline_common_fe.c | 1455 -------
 examples/ip_pipeline/pipeline/pipeline_common_fe.h |  231 --
 examples/ip_pipeline/pipeline/pipeline_firewall.c  | 1421 -------
 examples/ip_pipeline/pipeline/pipeline_firewall.h  |   60 -
 .../ip_pipeline/pipeline/pipeline_firewall_be.c    |  856 ----
 .../ip_pipeline/pipeline/pipeline_firewall_be.h    |  147 -
 .../ip_pipeline/pipeline/pipeline_flow_actions.c   | 1286 ------
 .../ip_pipeline/pipeline/pipeline_flow_actions.h   |   60 -
 .../pipeline/pipeline_flow_actions_be.c            |  983 -----
 .../pipeline/pipeline_flow_actions_be.h            |  139 -
 .../pipeline/pipeline_flow_classification.c        | 1878 ---------
 .../pipeline/pipeline_flow_classification.h        |  106 -
 .../pipeline/pipeline_flow_classification_be.c     |  723 ----
 .../pipeline/pipeline_flow_classification_be.h     |  113 -
 examples/ip_pipeline/pipeline/pipeline_master.c    |   20 -
 examples/ip_pipeline/pipeline/pipeline_master.h    |   12 -
 examples/ip_pipeline/pipeline/pipeline_master_be.c |  141 -
 examples/ip_pipeline/pipeline/pipeline_master_be.h |   12 -
 .../ip_pipeline/pipeline/pipeline_passthrough.c    |   45 -
 .../ip_pipeline/pipeline/pipeline_passthrough.h    |   12 -
 .../ip_pipeline/pipeline/pipeline_passthrough_be.c |  929 -----
 .../ip_pipeline/pipeline/pipeline_passthrough_be.h |   44 -
 examples/ip_pipeline/pipeline/pipeline_routing.c   | 1613 --------
 examples/ip_pipeline/pipeline/pipeline_routing.h   |   71 -
 .../ip_pipeline/pipeline/pipeline_routing_be.c     | 1966 ---------
 .../ip_pipeline/pipeline/pipeline_routing_be.h     |  283 --
 examples/ip_pipeline/pipeline_be.h                 |  322 --
 examples/ip_pipeline/swq.c                         |   74 +
 examples/ip_pipeline/swq.h                         |   37 +
 examples/ip_pipeline/tap.c                         |   97 +
 examples/ip_pipeline/tap.h                         |   29 +
 examples/ip_pipeline/thread.c                      | 2484 +++++++++++-
 examples/ip_pipeline/thread.h                      |   75 +-
 examples/ip_pipeline/thread_fe.c                   |  457 ---
 examples/ip_pipeline/thread_fe.h                   |   72 -
 examples/ip_pipeline/tmgr.c                        |  227 ++
 examples/ip_pipeline/tmgr.h                        |   70 +
 lib/librte_pipeline/Makefile                       |    6 +-
 lib/librte_pipeline/meson.build                    |    7 +-
 lib/librte_pipeline/rte_pipeline_version.map       |   21 +
 lib/librte_pipeline/rte_table_action.c             | 2084 ++++++++++
 lib/librte_pipeline/rte_table_action.h             |  853 ++++
 106 files changed, 13032 insertions(+), 27218 deletions(-)
 delete mode 100644 examples/ip_pipeline/app.h
 create mode 100644 examples/ip_pipeline/cli.c
 create mode 100644 examples/ip_pipeline/cli.h
 create mode 100644 examples/ip_pipeline/common.h
 delete mode 100644 examples/ip_pipeline/config/action.cfg
 delete mode 100644 examples/ip_pipeline/config/action.sh
 delete mode 100644 examples/ip_pipeline/config/action.txt
 delete mode 100755 examples/ip_pipeline/config/diagram-generator.py
 delete mode 100644 examples/ip_pipeline/config/edge_router_downstream.cfg
 delete mode 100644 examples/ip_pipeline/config/edge_router_downstream.sh
 delete mode 100644 examples/ip_pipeline/config/edge_router_upstream.cfg
 delete mode 100644 examples/ip_pipeline/config/edge_router_upstream.sh
 delete mode 100644 examples/ip_pipeline/config/firewall.cfg
 delete mode 100644 examples/ip_pipeline/config/firewall.sh
 delete mode 100644 examples/ip_pipeline/config/firewall.txt
 delete mode 100644 examples/ip_pipeline/config/flow.cfg
 delete mode 100644 examples/ip_pipeline/config/flow.sh
 delete mode 100644 examples/ip_pipeline/config/flow.txt
 delete mode 100644 examples/ip_pipeline/config/ip_pipeline.cfg
 delete mode 100644 examples/ip_pipeline/config/ip_pipeline.sh
 delete mode 100644 examples/ip_pipeline/config/kni.cfg
 delete mode 100644 examples/ip_pipeline/config/l2fwd.cfg
 delete mode 100644 examples/ip_pipeline/config/l3fwd.cfg
 delete mode 100644 examples/ip_pipeline/config/l3fwd.sh
 delete mode 100644 examples/ip_pipeline/config/l3fwd_arp.cfg
 delete mode 100644 examples/ip_pipeline/config/l3fwd_arp.sh
 delete mode 100644 examples/ip_pipeline/config/network_layers.cfg
 delete mode 100644 examples/ip_pipeline/config/network_layers.sh
 delete mode 100755 examples/ip_pipeline/config/pipeline-to-core-mapping.py
 delete mode 100644 examples/ip_pipeline/config/tap.cfg
 delete mode 100644 examples/ip_pipeline/config/tm_profile.cfg
 delete mode 100644 examples/ip_pipeline/config_check.c
 delete mode 100644 examples/ip_pipeline/config_parse.c
 delete mode 100644 examples/ip_pipeline/config_parse_tm.c
 create mode 100644 examples/ip_pipeline/conn.c
 create mode 100644 examples/ip_pipeline/conn.h
 delete mode 100644 examples/ip_pipeline/cpu_core_map.c
 delete mode 100644 examples/ip_pipeline/cpu_core_map.h
 create mode 100644 examples/ip_pipeline/examples/firewall.cli
 create mode 100644 examples/ip_pipeline/examples/flow.cli
 create mode 100644 examples/ip_pipeline/examples/kni.cli
 create mode 100644 examples/ip_pipeline/examples/l2fwd.cli
 create mode 100644 examples/ip_pipeline/examples/route.cli
 create mode 100644 examples/ip_pipeline/examples/tap.cli
 rename examples/ip_pipeline/{pipeline => }/hash_func.h (99%)
 rename examples/ip_pipeline/{pipeline => }/hash_func_arm64.h (100%)
 delete mode 100644 examples/ip_pipeline/init.c
 create mode 100644 examples/ip_pipeline/kni.c
 create mode 100644 examples/ip_pipeline/kni.h
 create mode 100644 examples/ip_pipeline/link.c
 create mode 100644 examples/ip_pipeline/link.h
 create mode 100644 examples/ip_pipeline/mempool.c
 create mode 100644 examples/ip_pipeline/mempool.h
 create mode 100644 examples/ip_pipeline/pipeline.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_actions_common.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_common_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_common_be.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_common_fe.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_common_fe.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_firewall.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_firewall.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_firewall_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_firewall_be.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_actions.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_actions.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_actions_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_actions_be.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_classification.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_classification.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_classification_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_classification_be.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_master.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_master.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_master_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_master_be.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_passthrough.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_passthrough.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_passthrough_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_passthrough_be.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_routing.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_routing.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_routing_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_routing_be.h
 delete mode 100644 examples/ip_pipeline/pipeline_be.h
 create mode 100644 examples/ip_pipeline/swq.c
 create mode 100644 examples/ip_pipeline/swq.h
 create mode 100644 examples/ip_pipeline/tap.c
 create mode 100644 examples/ip_pipeline/tap.h
 delete mode 100644 examples/ip_pipeline/thread_fe.c
 delete mode 100644 examples/ip_pipeline/thread_fe.h
 create mode 100644 examples/ip_pipeline/tmgr.c
 create mode 100644 examples/ip_pipeline/tmgr.h
 create mode 100644 lib/librte_pipeline/rte_table_action.c
 create mode 100644 lib/librte_pipeline/rte_table_action.h

-- 
2.9.3

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

* [dpdk-dev] [PATCH 01/37] pipeline: add pipeline table action APIs
  2018-03-09 18:23 [dpdk-dev] [PATCH 00/37] ip_pipeline: refactoring Jasvinder Singh
@ 2018-03-09 18:23 ` Jasvinder Singh
  2018-03-12 17:25   ` [dpdk-dev] [PATCH v2 00/44] ip_pipeline: refactoring Jasvinder Singh
  2018-03-09 18:23 ` [dpdk-dev] [PATCH 02/37] pipeline: get pipeline table action params Jasvinder Singh
                   ` (35 subsequent siblings)
  36 siblings, 1 reply; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-09 18:23 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

This API provides a common set of actions for pipeline tables to speed up
application development.

Each match-action rule added to a pipeline table has associated data
that stores the action context. This data is input to the table
action handler called for every input packet that hits the rule as
part of the table lookup during the pipeline execution.

The pipeline library allows the user to define his own table
actions by providing customized table action handlers (table
lookup) and complete freedom of setting the rules and their data
(table rule add/delete). While the user can still follow this
process, this API is intended to provide a quicker development
alternative for a set of predefined actions.

The typical steps to use this API are:
* Define a table action profile.
* Instantiate the table action profile to create table action objects.
* Use the table action object to generate the pipeline table action
  handlers (invoked by the pipeline table lookup operation).
* Use the table action object to generate the rule data (for the
  pipeline table rule add operation) based on given action parameters.
* Use the table action object to read action data (e.g. stats counters)
  for any given rule.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 doc/api/doxy-api-index.md                    |   1 +
 lib/librte_pipeline/Makefile                 |   3 +-
 lib/librte_pipeline/meson.build              |   5 +-
 lib/librte_pipeline/rte_pipeline_version.map |  13 ++
 lib/librte_pipeline/rte_table_action.c       | 278 +++++++++++++++++++++++++++
 lib/librte_pipeline/rte_table_action.h       | 224 +++++++++++++++++++++
 6 files changed, 521 insertions(+), 3 deletions(-)
 create mode 100644 lib/librte_pipeline/rte_table_action.c
 create mode 100644 lib/librte_pipeline/rte_table_action.h

diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md
index d77f205..e24b70e 100644
--- a/doc/api/doxy-api-index.md
+++ b/doc/api/doxy-api-index.md
@@ -159,6 +159,7 @@ The public API headers are grouped by topics:
     [array]            (@ref rte_table_array.h),
     [stub]             (@ref rte_table_stub.h)
   * [pipeline]         (@ref rte_pipeline.h)
+    [table_action].....(@ref rte_table_action.h)
 
 - **basic**:
   [approx fraction]    (@ref rte_approx.h),
diff --git a/lib/librte_pipeline/Makefile b/lib/librte_pipeline/Makefile
index e94fbc0..e8c43c7 100644
--- a/lib/librte_pipeline/Makefile
+++ b/lib/librte_pipeline/Makefile
@@ -21,8 +21,9 @@ LIBABIVER := 3
 # all source are stored in SRCS-y
 #
 SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) := rte_pipeline.c
+SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += rte_table_action.c
 
 # install includes
-SYMLINK-$(CONFIG_RTE_LIBRTE_PIPELINE)-include += rte_pipeline.h
+SYMLINK-$(CONFIG_RTE_LIBRTE_PIPELINE)-include += rte_pipeline.h rte_table_action.h
 
 include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_pipeline/meson.build b/lib/librte_pipeline/meson.build
index a35b622..4dda560 100644
--- a/lib/librte_pipeline/meson.build
+++ b/lib/librte_pipeline/meson.build
@@ -2,6 +2,7 @@
 # Copyright(c) 2017 Intel Corporation
 
 version = 3
-sources = files('rte_pipeline.c')
-headers = files('rte_pipeline.h')
+allow_experimental_apis = true
+sources = files('rte_pipeline.c', 'rte_table_action.c')
+headers = files('rte_pipeline.h', 'rte_table_action.h')
 deps += ['port', 'table']
diff --git a/lib/librte_pipeline/rte_pipeline_version.map b/lib/librte_pipeline/rte_pipeline_version.map
index e4ee154..4bc414c 100644
--- a/lib/librte_pipeline/rte_pipeline_version.map
+++ b/lib/librte_pipeline/rte_pipeline_version.map
@@ -45,3 +45,16 @@ DPDK_16.04 {
 	rte_pipeline_ah_packet_drop;
 
 } DPDK_2.2;
+
+EXPERIMENTAL {
+	global:
+
+	rte_table_action_apply;
+	rte_table_action_create;
+	rte_table_action_free;
+	rte_table_action_profile_action_register;
+	rte_table_action_profile_create;
+	rte_table_action_profile_free;
+	rte_table_action_profile_freeze;
+
+} DPDK_16.04;
diff --git a/lib/librte_pipeline/rte_table_action.c b/lib/librte_pipeline/rte_table_action.c
new file mode 100644
index 0000000..45e22a4
--- /dev/null
+++ b/lib/librte_pipeline/rte_table_action.c
@@ -0,0 +1,278 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <rte_malloc.h>
+
+#include <rte_common.h>
+#include <rte_malloc.h>
+
+#include "rte_table_action.h"
+
+/**
+ * RTE_TABLE_ACTION_FWD
+ */
+#define fwd_data rte_pipeline_table_entry
+
+static int
+fwd_apply(struct fwd_data *data,
+	struct rte_table_action_fwd_params *p)
+{
+	data->action = p->action;
+
+	if (p->action == RTE_PIPELINE_ACTION_PORT)
+		data->port_id = p->id;
+
+	if (p->action == RTE_PIPELINE_ACTION_TABLE)
+		data->table_id = p->id;
+
+	return 0;
+}
+
+/**
+ * Action profile
+ */
+static int
+action_valid(enum rte_table_action_type action)
+{
+	switch (action) {
+	case RTE_TABLE_ACTION_FWD:
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+
+#define RTE_TABLE_ACTION_MAX                                   64
+
+struct ap_config {
+	uint64_t action_mask;
+	struct rte_table_action_common_config common;
+};
+
+static size_t
+action_cfg_size(enum rte_table_action_type action)
+{
+	switch (action) {
+	default:
+		return 0;
+	}
+}
+
+static void*
+action_cfg_get(struct ap_config *ap_config __rte_unused,
+	enum rte_table_action_type type)
+{
+	switch (type) {
+	default:
+		return NULL;
+	}
+}
+
+static void
+action_cfg_set(struct ap_config *ap_config,
+	enum rte_table_action_type type,
+	void *action_cfg)
+{
+	void *dst = action_cfg_get(ap_config, type);
+
+	if (dst)
+		memcpy(dst, action_cfg, action_cfg_size(type));
+
+	ap_config->action_mask |= 1LLU << type;
+}
+
+struct ap_data {
+	size_t offset[RTE_TABLE_ACTION_MAX];
+	size_t total_size;
+};
+
+static size_t
+action_data_size(enum rte_table_action_type action,
+	struct ap_config *ap_config __rte_unused)
+{
+	switch (action) {
+	case RTE_TABLE_ACTION_FWD:
+		return sizeof(struct fwd_data);
+
+	default:
+		return 0;
+	}
+}
+
+
+static void
+action_data_offset_set(struct ap_data *ap_data,
+	struct ap_config *ap_config)
+{
+	uint64_t action_mask = ap_config->action_mask;
+	size_t offset;
+	enum rte_table_action_type action;
+
+	memset(ap_data->offset, 0, sizeof(ap_data->offset));
+
+	offset = 0;
+	for (action = 0; action < RTE_TABLE_ACTION_MAX; action++)
+		if (action_mask & (1LLU << action)) {
+			ap_data->offset[action] = offset;
+			offset += action_data_size(action, ap_config);
+		}
+
+	ap_data->total_size = offset;
+}
+
+struct rte_table_action_profile {
+	struct ap_config cfg;
+	struct ap_data data;
+	int frozen;
+};
+
+struct rte_table_action_profile *
+rte_table_action_profile_create(struct rte_table_action_common_config *common)
+{
+	struct rte_table_action_profile *ap;
+
+	/* Check input arguments */
+	if (common == NULL)
+		return NULL;
+
+	/* Memory allocation */
+	ap = calloc(1, sizeof(struct rte_table_action_profile));
+	if (ap == NULL)
+		return NULL;
+
+	/* Initialization */
+	memcpy(&ap->cfg.common, common, sizeof(*common));
+
+	return ap;
+}
+
+
+int
+rte_table_action_profile_action_register(struct rte_table_action_profile *profile,
+	enum rte_table_action_type type,
+	void *action_config)
+{
+	/* Check input arguments */
+	if ((profile == NULL) ||
+		profile->frozen ||
+		(action_valid(type) == 0) ||
+		(profile->cfg.action_mask & (1LLU << type)) ||
+		((action_cfg_size(type) == 0) && action_config) ||
+		(action_cfg_size(type) && (action_config == NULL)))
+		return -EINVAL;
+
+	/* Action enable */
+	action_cfg_set(&profile->cfg, type, action_config);
+
+	return 0;
+}
+
+int
+rte_table_action_profile_freeze(struct rte_table_action_profile *profile)
+{
+	if (profile->frozen)
+		return -EBUSY;
+
+	profile->cfg.action_mask |= 1LLU << RTE_TABLE_ACTION_FWD;
+	action_data_offset_set(&profile->data, &profile->cfg);
+	profile->frozen = 1;
+
+	return 0;
+}
+
+int
+rte_table_action_profile_free(struct rte_table_action_profile *profile)
+{
+	if (profile == NULL)
+		return 0;
+
+	free(profile);
+	return 0;
+}
+
+struct rte_table_action {
+	struct ap_config cfg;
+	struct ap_data data;
+};
+
+struct rte_table_action *
+rte_table_action_create(struct rte_table_action_profile *profile,
+	uint32_t socket_id)
+{
+	struct rte_table_action *action;
+
+	/* Check input arguments */
+	if ((profile == NULL) ||
+		(profile->frozen == 0))
+		return NULL;
+
+	/* Memory allocation */
+	action = rte_zmalloc_socket(NULL,
+		sizeof(struct rte_table_action),
+		RTE_CACHE_LINE_SIZE,
+		socket_id);
+	if (action == NULL)
+		return NULL;
+
+	/* Initialization */
+	memcpy(&action->cfg, &profile->cfg, sizeof(profile->cfg));
+	memcpy(&action->data, &profile->data, sizeof(profile->data));
+
+	return action;
+}
+
+static __rte_always_inline void *
+action_data_get(void *data,
+	struct rte_table_action *action,
+	enum rte_table_action_type type)
+{
+	size_t offset = action->data.offset[type];
+	uint8_t *data_bytes = data;
+
+	return &data_bytes[offset];
+}
+
+int
+rte_table_action_apply(struct rte_table_action *action,
+	void *data,
+	enum rte_table_action_type type,
+	void *action_params)
+{
+	void *action_data;
+
+	/* Check input arguments */
+	if ((action == NULL) ||
+		(data == NULL) ||
+		(action_valid(type) == 0) ||
+		((action->cfg.action_mask & (1LLU << type)) == 0) ||
+		(action_params == NULL))
+		return -EINVAL;
+
+	/* Data update */
+	action_data = action_data_get(data, action, type);
+
+	switch (type) {
+	case RTE_TABLE_ACTION_FWD:
+		return fwd_apply(action_data,
+			action_params);
+
+	default:
+		return -EINVAL;
+	}
+}
+
+int
+rte_table_action_free(struct rte_table_action *action)
+{
+	if (action == NULL)
+		return 0;
+
+	rte_free(action);
+
+	return 0;
+}
\ No newline at end of file
diff --git a/lib/librte_pipeline/rte_table_action.h b/lib/librte_pipeline/rte_table_action.h
new file mode 100644
index 0000000..da7f12c
--- /dev/null
+++ b/lib/librte_pipeline/rte_table_action.h
@@ -0,0 +1,224 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation
+ */
+
+#ifndef __INCLUDE_RTE_TABLE_ACTION_H__
+#define __INCLUDE_RTE_TABLE_ACTION_H__
+
+/**
+ * @file
+ * RTE Pipeline Table Actions
+ *
+ * This API provides a common set of actions for pipeline tables to speed up
+ * application development.
+ *
+ * Each match-action rule added to a pipeline table has associated data that
+ * stores the action context. This data is input to the table action handler
+ * called for every input packet that hits the rule as part of the table lookup
+ * during the pipeline execution. The pipeline library allows the user to define
+ * his own table actions by providing customized table action handlers (table
+ * lookup) and complete freedom of setting the rules and their data (table rule
+ * add/delete). While the user can still follow this process, this API is
+ * intended to provide a quicker development alternative for a set of predefined
+ * actions.
+ *
+ * The typical steps to use this API are:
+ *  - Define a table action profile. This is a configuration template that can
+ *    potentially be shared by multiple tables from the same or different
+ *    pipelines, with different tables from the same pipeline likely to use
+ *    different action profiles. For every table using a given action profile,
+ *    the profile defines the set of actions and the action configuration to be
+ *    implemented for all the table rules. API functions:
+ *    rte_table_action_profile_create(),
+ *    rte_table_action_profile_action_register(),
+ *    rte_table_action_profile_freeze().
+ *
+ *  - Instantiate the table action profile to create table action objects. Each
+ *    pipeline table has its own table action object. API functions:
+ *    rte_table_action_create().
+ *
+ *  - Use the table action object to generate the pipeline table action handlers
+ *    (invoked by the pipeline table lookup operation). API functions:
+ *    rte_table_action_table_params_get().
+ *
+ *  - Use the table action object to generate the rule data (for the pipeline
+ *    table rule add operation) based on given action parameters. API functions:
+ *    rte_table_action_apply().
+ *
+ *  - Use the table action object to read action data (e.g. stats counters) for
+ *    any given rule. API functions: rte_table_action_XYZ_read().
+ *
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+
+#include <rte_compat.h>
+
+#include "rte_pipeline.h"
+
+/** Table actions. */
+enum rte_table_action_type {
+	/** Forward to next pipeline table, output port or drop. */
+	RTE_TABLE_ACTION_FWD = 0,
+};
+
+/** Common action configuration (per table action profile). */
+struct rte_table_action_common_config {
+	/** Input packet Internet Protocol (IP) version. Non-zero for IPv4, zero
+	 * for IPv6.
+	 */
+	int ip_version;
+
+	/** IP header offset within the input packet buffer. Offset 0 points to
+	 * the first byte of the MBUF structure.
+	 */
+	uint32_t ip_offset;
+};
+
+/**
+ * RTE_TABLE_ACTION_FWD
+ */
+/** Forward action parameters (per table rule). */
+struct rte_table_action_fwd_params {
+	/** Forward action. */
+	enum rte_pipeline_action action;
+
+	/** Pipeline table ID or output port ID. */
+	uint32_t id;
+};
+
+/**
+ * Table action profile.
+ */
+struct rte_table_action_profile;
+
+/**
+ * Table action profile create.
+ *
+ * @param[in] common
+ *   Common action configuration.
+ * @return
+ *   Table action profile handle on success, NULL otherwise.
+ */
+struct rte_table_action_profile * __rte_experimental
+rte_table_action_profile_create(struct rte_table_action_common_config *common);
+
+/**
+ * Table action profile free.
+ *
+ * @param[in] profile
+ *   Table profile action handle (needs to be valid).
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_table_action_profile_free(struct rte_table_action_profile *profile);
+
+/**
+ * Table action profile action register.
+ *
+ * @param[in] profile
+ *   Table profile action handle (needs to be valid and not in frozen state).
+ * @param[in] type
+ *   Specific table action to be registered for *profile*.
+ * @param[in] action_config
+ *   Configuration for the *type* action.
+ *   If struct rte_table_action_*type*_config is defined by the Table Action
+ *   API, it needs to point to a valid instance of this structure, otherwise it
+ *   needs to be set to NULL.
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_table_action_profile_action_register(struct rte_table_action_profile *profile,
+	enum rte_table_action_type type,
+	void *action_config);
+
+/**
+ * Table action profile freeze.
+ *
+ * Once this function is called successfully, the given profile enters the
+ * frozen state with the following immediate effects: no more actions can be
+ * registered for this profile, so the profile can be instantiated to create
+ * table action objects.
+ *
+ * @param[in] profile
+ *   Table profile action handle (needs to be valid and not in frozen state).
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ *
+ * @see rte_table_action_create()
+ */
+int __rte_experimental
+rte_table_action_profile_freeze(struct rte_table_action_profile *profile);
+
+/**
+ * Table action.
+ */
+struct rte_table_action;
+
+/**
+ * Table action create.
+ *
+ * Instantiates the given table action profile to create a table action object.
+ *
+ * @param[in] profile
+ *   Table profile action handle (needs to be valid and in frozen state).
+ * @param[in] socket_id
+ *   CPU socket ID where the internal data structures required by the new table
+ *   action object should be allocated.
+ * @return
+ *   Handle to table action object on success, NULL on error.
+ *
+ * @see rte_table_action_create()
+ */
+struct rte_table_action * __rte_experimental
+rte_table_action_create(struct rte_table_action_profile *profile,
+	uint32_t socket_id);
+
+/**
+ * Table action free.
+ *
+ * @param[in] action
+ *   Handle to table action object (needs to be valid).
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_table_action_free(struct rte_table_action *action);
+
+/**
+ * Table action apply.
+ *
+ * @param[in] action
+ *   Handle to table action object (needs to be valid).
+ * @param[in] data
+ *   Data byte array (typically table rule data) to apply action *type* on.
+ * @param[in] type
+ *   Specific table action previously registered for the table action profile of
+ *   the *action* object.
+ * @param[in] action_params
+ *   Parameters for the *type* action.
+ *   If struct rte_table_action_*type*_params is defined by the Table Action
+ *   API, it needs to point to a valid instance of this structure, otherwise it
+ *   needs to be set to NULL.
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_table_action_apply(struct rte_table_action *action,
+	void *data,
+	enum rte_table_action_type type,
+	void *action_params);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __INCLUDE_RTE_TABLE_ACTION_H__ */
-- 
2.9.3

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

* [dpdk-dev] [PATCH 02/37] pipeline: get pipeline table action params
  2018-03-09 18:23 [dpdk-dev] [PATCH 00/37] ip_pipeline: refactoring Jasvinder Singh
  2018-03-09 18:23 ` [dpdk-dev] [PATCH 01/37] pipeline: add pipeline table action APIs Jasvinder Singh
@ 2018-03-09 18:23 ` Jasvinder Singh
  2018-03-09 18:23 ` [dpdk-dev] [PATCH 03/37] pipeline: add traffic metering action Jasvinder Singh
                   ` (34 subsequent siblings)
  36 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-09 18:23 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add API to specify action related parameters such as action
handler, table entry data size, etc. for the pipeline table.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 lib/librte_pipeline/rte_pipeline_version.map |   1 +
 lib/librte_pipeline/rte_table_action.c       | 132 ++++++++++++++++++++++++++-
 lib/librte_pipeline/rte_table_action.h       |  14 +++
 3 files changed, 146 insertions(+), 1 deletion(-)

diff --git a/lib/librte_pipeline/rte_pipeline_version.map b/lib/librte_pipeline/rte_pipeline_version.map
index 4bc414c..13337de 100644
--- a/lib/librte_pipeline/rte_pipeline_version.map
+++ b/lib/librte_pipeline/rte_pipeline_version.map
@@ -56,5 +56,6 @@ EXPERIMENTAL {
 	rte_table_action_profile_create;
 	rte_table_action_profile_free;
 	rte_table_action_profile_freeze;
+	rte_table_action_table_params_get;
 
 } DPDK_16.04;
diff --git a/lib/librte_pipeline/rte_table_action.c b/lib/librte_pipeline/rte_table_action.c
index 45e22a4..ce484e4 100644
--- a/lib/librte_pipeline/rte_table_action.c
+++ b/lib/librte_pipeline/rte_table_action.c
@@ -266,6 +266,136 @@ rte_table_action_apply(struct rte_table_action *action,
 	}
 }
 
+static __rte_always_inline uint64_t
+pkt_work(struct rte_mbuf *mbuf __rte_unused,
+	struct rte_pipeline_table_entry *table_entry __rte_unused,
+	uint64_t time __rte_unused,
+	struct rte_table_action *action __rte_unused,
+	struct ap_config *cfg __rte_unused)
+{
+	return 0;
+}
+
+static __rte_always_inline uint64_t
+pkt4_work(struct rte_mbuf **mbufs __rte_unused,
+	struct rte_pipeline_table_entry **table_entries __rte_unused,
+	uint64_t time __rte_unused,
+	struct rte_table_action *action __rte_unused,
+	struct ap_config *cfg __rte_unused)
+{
+	return 0;
+}
+
+static __rte_always_inline int
+ah(struct rte_pipeline *p,
+	struct rte_mbuf **pkts,
+	uint64_t pkts_mask,
+	struct rte_pipeline_table_entry **entries,
+	struct rte_table_action *action,
+	struct ap_config *cfg)
+{
+	uint64_t pkts_drop_mask = 0;
+	uint64_t time = 0;
+
+	if ((pkts_mask & (pkts_mask + 1)) == 0) {
+		uint64_t n_pkts = __builtin_popcountll(pkts_mask);
+		uint32_t i;
+
+		for (i = 0; i < (n_pkts & (~0x3LLU)); i += 4) {
+			uint64_t drop_mask;
+
+			drop_mask = pkt4_work(&pkts[i],
+				&entries[i],
+				time,
+				action,
+				cfg);
+
+			pkts_drop_mask |= drop_mask << i;
+		}
+
+		for ( ; i < n_pkts; i++) {
+			uint64_t drop_mask;
+
+			drop_mask = pkt_work(pkts[i],
+				entries[i],
+				time,
+				action,
+				cfg);
+
+			pkts_drop_mask |= drop_mask << i;
+		}
+	} else
+		for ( ; pkts_mask; ) {
+			uint32_t pos = __builtin_ctzll(pkts_mask);
+			uint64_t pkt_mask = 1LLU << pos;
+			uint64_t drop_mask;
+
+			drop_mask = pkt_work(pkts[pos],
+				entries[pos],
+				time,
+				action,
+				cfg);
+
+			pkts_mask &= ~pkt_mask;
+			pkts_drop_mask |= drop_mask << pos;
+		}
+
+	rte_pipeline_ah_packet_drop(p, pkts_drop_mask);
+
+	return 0;
+}
+
+static int
+ah_default(struct rte_pipeline *p,
+	struct rte_mbuf **pkts,
+	uint64_t pkts_mask,
+	struct rte_pipeline_table_entry **entries,
+	void *arg)
+{
+	struct rte_table_action *action = arg;
+
+	return ah(p,
+		pkts,
+		pkts_mask,
+		entries,
+		action,
+		&action->cfg);
+}
+
+static rte_pipeline_table_action_handler_hit
+ah_selector(struct rte_table_action *action)
+{
+	if (action->cfg.action_mask == (1LLU << RTE_TABLE_ACTION_FWD))
+		return NULL;
+
+	return ah_default;
+}
+
+int
+rte_table_action_table_params_get(struct rte_table_action *action,
+	struct rte_pipeline_table_params *params)
+{
+	rte_pipeline_table_action_handler_hit f_action_hit;
+	uint32_t total_size;
+
+	/* Check input arguments */
+	if ((action == NULL) ||
+		(params == NULL))
+		return -EINVAL;
+
+	f_action_hit = ah_selector(action);
+	total_size = rte_align32pow2(action->data.total_size);
+
+	/* Fill in params */
+	params->f_action_hit = f_action_hit;
+	params->f_action_miss = NULL;
+	params->arg_ah = (f_action_hit) ? action : NULL;
+	params->action_data_size = total_size -
+		sizeof(struct rte_pipeline_table_entry);
+
+	return 0;
+}
+
 int
 rte_table_action_free(struct rte_table_action *action)
 {
@@ -275,4 +405,4 @@ rte_table_action_free(struct rte_table_action *action)
 	rte_free(action);
 
 	return 0;
-}
\ No newline at end of file
+}
diff --git a/lib/librte_pipeline/rte_table_action.h b/lib/librte_pipeline/rte_table_action.h
index da7f12c..03b77ca 100644
--- a/lib/librte_pipeline/rte_table_action.h
+++ b/lib/librte_pipeline/rte_table_action.h
@@ -194,6 +194,20 @@ int __rte_experimental
 rte_table_action_free(struct rte_table_action *action);
 
 /**
+ * Table action table params get.
+ *
+ * @param[in] action
+ *   Handle to table action object (needs to be valid).
+ * @param[inout] params
+ *   Pipeline table parameters (needs to be pre-allocated).
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_table_action_table_params_get(struct rte_table_action *action,
+	struct rte_pipeline_table_params *params);
+
+/**
  * Table action apply.
  *
  * @param[in] action
-- 
2.9.3

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

* [dpdk-dev] [PATCH 03/37] pipeline: add traffic metering action
  2018-03-09 18:23 [dpdk-dev] [PATCH 00/37] ip_pipeline: refactoring Jasvinder Singh
  2018-03-09 18:23 ` [dpdk-dev] [PATCH 01/37] pipeline: add pipeline table action APIs Jasvinder Singh
  2018-03-09 18:23 ` [dpdk-dev] [PATCH 02/37] pipeline: get pipeline table action params Jasvinder Singh
@ 2018-03-09 18:23 ` Jasvinder Singh
  2018-03-09 18:23 ` [dpdk-dev] [PATCH 04/37] pipeline: add traffic manager action Jasvinder Singh
                   ` (33 subsequent siblings)
  36 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-09 18:23 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add traffic metering action implementation.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 lib/librte_pipeline/Makefile                 |   3 +-
 lib/librte_pipeline/meson.build              |   2 +-
 lib/librte_pipeline/rte_pipeline_version.map |   4 +
 lib/librte_pipeline/rte_table_action.c       | 638 ++++++++++++++++++++++++++-
 lib/librte_pipeline/rte_table_action.h       | 248 +++++++++++
 5 files changed, 877 insertions(+), 18 deletions(-)

diff --git a/lib/librte_pipeline/Makefile b/lib/librte_pipeline/Makefile
index e8c43c7..72e4c7c 100644
--- a/lib/librte_pipeline/Makefile
+++ b/lib/librte_pipeline/Makefile
@@ -8,10 +8,11 @@ include $(RTE_SDK)/mk/rte.vars.mk
 #
 LIB = librte_pipeline.a
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
 LDLIBS += -lrte_eal -lrte_mempool -lrte_mbuf -lrte_table
-LDLIBS += -lrte_port
+LDLIBS += -lrte_port -lrte_meter
 
 EXPORT_MAP := rte_pipeline_version.map
 
diff --git a/lib/librte_pipeline/meson.build b/lib/librte_pipeline/meson.build
index 4dda560..71da295 100644
--- a/lib/librte_pipeline/meson.build
+++ b/lib/librte_pipeline/meson.build
@@ -5,4 +5,4 @@ version = 3
 allow_experimental_apis = true
 sources = files('rte_pipeline.c', 'rte_table_action.c')
 headers = files('rte_pipeline.h', 'rte_table_action.h')
-deps += ['port', 'table']
+deps += ['port', 'table', 'meter']
diff --git a/lib/librte_pipeline/rte_pipeline_version.map b/lib/librte_pipeline/rte_pipeline_version.map
index 13337de..c7106dc 100644
--- a/lib/librte_pipeline/rte_pipeline_version.map
+++ b/lib/librte_pipeline/rte_pipeline_version.map
@@ -51,7 +51,11 @@ EXPERIMENTAL {
 
 	rte_table_action_apply;
 	rte_table_action_create;
+	rte_table_action_dscp_table_update;
 	rte_table_action_free;
+	rte_table_action_meter_profile_add;
+	rte_table_action_meter_profile_delete;
+	rte_table_action_meter_read;
 	rte_table_action_profile_action_register;
 	rte_table_action_profile_create;
 	rte_table_action_profile_free;
diff --git a/lib/librte_pipeline/rte_table_action.c b/lib/librte_pipeline/rte_table_action.c
index ce484e4..b22bf80 100644
--- a/lib/librte_pipeline/rte_table_action.c
+++ b/lib/librte_pipeline/rte_table_action.c
@@ -5,13 +5,21 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include <rte_malloc.h>
-
 #include <rte_common.h>
+#include <rte_byteorder.h>
+#include <rte_cycles.h>
 #include <rte_malloc.h>
+#include <rte_ip.h>
+
 
 #include "rte_table_action.h"
 
+#define rte_htons rte_cpu_to_be_16
+#define rte_htonl rte_cpu_to_be_32
+
+#define rte_ntohs rte_be_to_cpu_16
+#define rte_ntohl rte_be_to_cpu_32
+
 /**
  * RTE_TABLE_ACTION_FWD
  */
@@ -33,6 +41,262 @@ fwd_apply(struct fwd_data *data,
 }
 
 /**
+ * RTE_TABLE_ACTION_MTR
+ */
+static int
+mtr_cfg_check(struct rte_table_action_mtr_config *mtr)
+{
+	if ((mtr->alg == RTE_TABLE_ACTION_METER_SRTCM) ||
+		((mtr->n_tc != 1) && (mtr->n_tc != 4)) ||
+		(mtr->n_bytes_enabled != 0))
+		return -ENOTSUP;
+	return 0;
+}
+
+#define MBUF_SCHED_QUEUE_TC_COLOR(queue, tc, color)        \
+	((uint16_t)((((uint64_t)(queue)) & 0x3) |          \
+	((((uint64_t)(tc)) & 0x3) << 2) |                  \
+	((((uint64_t)(color)) & 0x3) << 4)))
+
+#define MBUF_SCHED_COLOR(sched, color)                     \
+	(((sched) & (~0x30LLU)) | ((color) << 4))
+
+struct mtr_trtcm_data {
+	struct rte_meter_trtcm trtcm;
+	uint64_t stats[e_RTE_METER_COLORS];
+} __attribute__((__packed__));
+
+#define MTR_TRTCM_DATA_METER_PROFILE_ID_GET(data)          \
+	(((data)->stats[e_RTE_METER_GREEN] & 0xF8LLU) >> 3)
+
+static void
+mtr_trtcm_data_meter_profile_id_set(struct mtr_trtcm_data *data,
+	uint32_t profile_id)
+{
+	data->stats[e_RTE_METER_GREEN] &= ~0xF8LLU;
+	data->stats[e_RTE_METER_GREEN] |= (profile_id % 32) << 3;
+}
+
+#define MTR_TRTCM_DATA_POLICER_ACTION_DROP_GET(data, color)\
+	(((data)->stats[(color)] & 4LLU) >> 2)
+
+#define MTR_TRTCM_DATA_POLICER_ACTION_COLOR_GET(data, color)\
+	((enum rte_meter_color)((data)->stats[(color)] & 3LLU))
+
+static void
+mtr_trtcm_data_policer_action_set(struct mtr_trtcm_data *data,
+	enum rte_meter_color color,
+	enum rte_table_action_policer action)
+{
+	if (action == RTE_TABLE_ACTION_POLICER_DROP) {
+		data->stats[color] |= 4LLU;
+	} else {
+		data->stats[color] &= ~7LLU;
+		data->stats[color] |= color & 3LLU;
+	}
+}
+
+static uint64_t
+mtr_trtcm_data_stats_get(struct mtr_trtcm_data *data,
+	enum rte_meter_color color) {
+	return data->stats[color] >> 8;
+}
+
+static void
+mtr_trtcm_data_stats_reset(struct mtr_trtcm_data *data,
+	enum rte_meter_color color) {
+	data->stats[color] &= 0xFFLU;
+}
+
+#define MTR_TRTCM_DATA_STATS_INC(data, color)              \
+	((data)->stats[(color)] += (1LLU << 8))
+
+static size_t
+mtr_data_size(struct rte_table_action_mtr_config *mtr)
+{
+	return mtr->n_tc * sizeof(struct mtr_trtcm_data);
+}
+
+struct dscp_table_entry_data {
+	enum rte_meter_color color;
+	uint16_t tc;
+	uint16_t queue_tc_color;
+};
+
+struct dscp_table_data {
+	struct dscp_table_entry_data entry[64];
+};
+
+struct meter_profile_data {
+	struct rte_meter_trtcm_profile profile;
+	uint32_t profile_id;
+	int valid;
+};
+
+static struct meter_profile_data *
+meter_profile_data_find(struct meter_profile_data *mp,
+	uint32_t mp_size,
+	uint32_t profile_id)
+{
+	uint32_t i;
+
+	for (i = 0; i < mp_size; i++) {
+		struct meter_profile_data *mp_data = &mp[i];
+
+		if (mp_data->valid && (mp_data->profile_id == profile_id))
+			return mp_data;
+	}
+
+	return NULL;
+}
+
+static struct meter_profile_data *
+meter_profile_data_find_unused(struct meter_profile_data *mp,
+	uint32_t mp_size)
+{
+	uint32_t i;
+
+	for (i = 0; i < mp_size; i++) {
+		struct meter_profile_data *mp_data = &mp[i];
+
+		if (!mp_data->valid)
+			return mp_data;
+	}
+
+	return NULL;
+}
+
+static int
+mtr_apply_check(struct rte_table_action_mtr_params *p,
+	struct rte_table_action_mtr_config *cfg,
+	struct meter_profile_data *mp,
+	uint32_t mp_size)
+{
+	uint32_t i;
+
+	if (p->tc_mask > RTE_LEN2MASK(cfg->n_tc, uint32_t))
+		return -EINVAL;
+
+	for (i = 0; i < RTE_TABLE_ACTION_TC_MAX; i++) {
+		struct rte_table_action_mtr_tc_params *p_tc = &p->mtr[i];
+		struct meter_profile_data *mp_data;
+
+		if ((p->tc_mask & (1LLU << i)) == 0)
+			continue;
+
+		mp_data = meter_profile_data_find(mp,
+			mp_size,
+			p_tc->meter_profile_id);
+		if (!mp_data)
+			return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int
+mtr_apply(struct mtr_trtcm_data *data,
+	struct rte_table_action_mtr_params *p,
+	struct rte_table_action_mtr_config *cfg,
+	struct meter_profile_data *mp,
+	uint32_t mp_size)
+{
+	uint32_t i;
+	int status;
+
+	/* Check input arguments */
+	status = mtr_apply_check(p, cfg, mp, mp_size);
+	if (status)
+		return status;
+
+	/* Apply */
+	for (i = 0; i < RTE_TABLE_ACTION_TC_MAX; i++) {
+		struct rte_table_action_mtr_tc_params *p_tc = &p->mtr[i];
+		struct mtr_trtcm_data *data_tc = &data[i];
+		struct meter_profile_data *mp_data;
+
+		if ((p->tc_mask & (1LLU << i)) == 0)
+			continue;
+
+		/* Find profile */
+		mp_data = meter_profile_data_find(mp,
+			mp_size,
+			p_tc->meter_profile_id);
+		if (!mp_data)
+			return -EINVAL;
+
+		memset(data_tc, 0, sizeof(*data_tc));
+
+		/* Meter object */
+		status = rte_meter_trtcm_config(&data_tc->trtcm,
+			&mp_data->profile);
+		if (status)
+			return status;
+
+		/* Meter profile */
+		mtr_trtcm_data_meter_profile_id_set(data_tc,
+			mp_data - mp);
+
+		/* Policer actions */
+		mtr_trtcm_data_policer_action_set(data_tc,
+			e_RTE_METER_GREEN,
+			p_tc->policer[e_RTE_METER_GREEN]);
+
+		mtr_trtcm_data_policer_action_set(data_tc,
+			e_RTE_METER_YELLOW,
+			p_tc->policer[e_RTE_METER_YELLOW]);
+
+		mtr_trtcm_data_policer_action_set(data_tc,
+			e_RTE_METER_RED,
+			p_tc->policer[e_RTE_METER_RED]);
+	}
+
+	return 0;
+}
+
+static __rte_always_inline uint64_t
+pkt_work_mtr(struct rte_mbuf *mbuf,
+	struct mtr_trtcm_data *data,
+	struct dscp_table_data *dscp_table,
+	struct meter_profile_data *mp,
+	uint64_t time,
+	uint32_t dscp,
+	uint16_t total_length)
+{
+	uint64_t drop_mask, sched;
+	uint64_t *sched_ptr = (uint64_t *) &mbuf->hash.sched;
+	struct dscp_table_entry_data *dscp_entry = &dscp_table->entry[dscp];
+	enum rte_meter_color color_in, color_meter, color_policer;
+	uint32_t tc, mp_id;
+
+	tc = dscp_entry->tc;
+	color_in = dscp_entry->color;
+	data += tc;
+	mp_id = MTR_TRTCM_DATA_METER_PROFILE_ID_GET(data);
+	sched = *sched_ptr;
+
+	/* Meter */
+	color_meter = rte_meter_trtcm_color_aware_check(
+		&data->trtcm,
+		&mp[mp_id].profile,
+		time,
+		total_length,
+		color_in);
+
+	/* Stats */
+	MTR_TRTCM_DATA_STATS_INC(data, color_meter);
+
+	/* Police */
+	drop_mask = MTR_TRTCM_DATA_POLICER_ACTION_DROP_GET(data, color_meter);
+	color_policer =
+		MTR_TRTCM_DATA_POLICER_ACTION_COLOR_GET(data, color_meter);
+	*sched_ptr = MBUF_SCHED_COLOR(sched, color_policer);
+
+	return drop_mask;
+}
+
+
+/**
  * Action profile
  */
 static int
@@ -40,6 +304,7 @@ action_valid(enum rte_table_action_type action)
 {
 	switch (action) {
 	case RTE_TABLE_ACTION_FWD:
+	case RTE_TABLE_ACTION_MTR:
 		return 1;
 	default:
 		return 0;
@@ -52,22 +317,28 @@ action_valid(enum rte_table_action_type action)
 struct ap_config {
 	uint64_t action_mask;
 	struct rte_table_action_common_config common;
+	struct rte_table_action_mtr_config mtr;
 };
 
 static size_t
 action_cfg_size(enum rte_table_action_type action)
 {
 	switch (action) {
+	case RTE_TABLE_ACTION_MTR:
+		return sizeof(struct rte_table_action_mtr_config);
 	default:
 		return 0;
 	}
 }
 
 static void*
-action_cfg_get(struct ap_config *ap_config __rte_unused,
+action_cfg_get(struct ap_config *ap_config,
 	enum rte_table_action_type type)
 {
 	switch (type) {
+	case RTE_TABLE_ACTION_MTR:
+		return &ap_config->mtr;
+
 	default:
 		return NULL;
 	}
@@ -93,12 +364,15 @@ struct ap_data {
 
 static size_t
 action_data_size(enum rte_table_action_type action,
-	struct ap_config *ap_config __rte_unused)
+	struct ap_config *ap_config)
 {
 	switch (action) {
 	case RTE_TABLE_ACTION_FWD:
 		return sizeof(struct fwd_data);
 
+	case RTE_TABLE_ACTION_MTR:
+		return mtr_data_size(&ap_config->mtr);
+
 	default:
 		return 0;
 	}
@@ -157,6 +431,8 @@ rte_table_action_profile_action_register(struct rte_table_action_profile *profil
 	enum rte_table_action_type type,
 	void *action_config)
 {
+	int status;
+
 	/* Check input arguments */
 	if ((profile == NULL) ||
 		profile->frozen ||
@@ -166,6 +442,19 @@ rte_table_action_profile_action_register(struct rte_table_action_profile *profil
 		(action_cfg_size(type) && (action_config == NULL)))
 		return -EINVAL;
 
+	switch (type) {
+	case RTE_TABLE_ACTION_MTR:
+		status = mtr_cfg_check(action_config);
+		break;
+
+	default:
+		status = 0;
+		break;
+	}
+
+	if (status)
+		return status;
+
 	/* Action enable */
 	action_cfg_set(&profile->cfg, type, action_config);
 
@@ -195,9 +484,16 @@ rte_table_action_profile_free(struct rte_table_action_profile *profile)
 	return 0;
 }
 
+/**
+ * Action
+ */
+#define METER_PROFILES_MAX                                 32
+
 struct rte_table_action {
 	struct ap_config cfg;
 	struct ap_data data;
+	struct dscp_table_data dscp_table;
+	struct meter_profile_data mp[METER_PROFILES_MAX];
 };
 
 struct rte_table_action *
@@ -261,31 +557,338 @@ rte_table_action_apply(struct rte_table_action *action,
 		return fwd_apply(action_data,
 			action_params);
 
+	case RTE_TABLE_ACTION_MTR:
+		return mtr_apply(action_data,
+			action_params,
+			&action->cfg.mtr,
+			action->mp,
+			RTE_DIM(action->mp));
+
 	default:
 		return -EINVAL;
 	}
 }
 
-static __rte_always_inline uint64_t
-pkt_work(struct rte_mbuf *mbuf __rte_unused,
-	struct rte_pipeline_table_entry *table_entry __rte_unused,
-	uint64_t time __rte_unused,
-	struct rte_table_action *action __rte_unused,
-	struct ap_config *cfg __rte_unused)
+int
+rte_table_action_dscp_table_update(struct rte_table_action *action,
+	uint64_t dscp_mask,
+	struct rte_table_action_dscp_table *table)
 {
+	uint32_t i;
+
+	/* Check input arguments */
+	if ((action == NULL) ||
+		(action->cfg.action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) ||
+		(dscp_mask == 0) ||
+		(table == NULL))
+		return -EINVAL;
+
+	for (i = 0; i < RTE_DIM(table->entry); i++) {
+		struct dscp_table_entry_data *data =
+			&action->dscp_table.entry[i];
+		struct rte_table_action_dscp_table_entry *entry =
+			&table->entry[i];
+		uint16_t queue_tc_color =
+			MBUF_SCHED_QUEUE_TC_COLOR(entry->tc_queue_id,
+				entry->tc_id,
+				entry->color);
+
+		if ((dscp_mask & (1LLU << i)) == 0)
+			continue;
+
+		data->color = entry->color;
+		data->tc = entry->tc_id;
+		data->queue_tc_color = queue_tc_color;
+	}
+
 	return 0;
 }
 
-static __rte_always_inline uint64_t
-pkt4_work(struct rte_mbuf **mbufs __rte_unused,
-	struct rte_pipeline_table_entry **table_entries __rte_unused,
-	uint64_t time __rte_unused,
-	struct rte_table_action *action __rte_unused,
-	struct ap_config *cfg __rte_unused)
+int
+rte_table_action_meter_profile_add(struct rte_table_action *action,
+	uint32_t meter_profile_id,
+	struct rte_table_action_meter_profile *profile)
+{
+	struct meter_profile_data *mp_data;
+	uint32_t status;
+
+	/* Check input arguments */
+	if ((action == NULL) ||
+		((action->cfg.action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) == 0) ||
+		(profile == NULL))
+		return -EINVAL;
+
+	if (profile->alg != RTE_TABLE_ACTION_METER_TRTCM)
+		return -ENOTSUP;
+
+	mp_data = meter_profile_data_find(action->mp,
+		RTE_DIM(action->mp),
+		meter_profile_id);
+	if (mp_data)
+		return -EEXIST;
+
+	mp_data = meter_profile_data_find_unused(action->mp,
+		RTE_DIM(action->mp));
+	if (!mp_data)
+		return -ENOSPC;
+
+	/* Install new profile */
+	status = rte_meter_trtcm_profile_config(&mp_data->profile,
+		&profile->trtcm);
+	if (status)
+		return status;
+
+	mp_data->profile_id = meter_profile_id;
+	mp_data->valid = 1;
+
+	return 0;
+}
+
+int
+rte_table_action_meter_profile_delete(struct rte_table_action *action,
+	uint32_t meter_profile_id)
 {
+	struct meter_profile_data *mp_data;
+
+	/* Check input arguments */
+	if ((action == NULL) ||
+		((action->cfg.action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) == 0))
+		return -EINVAL;
+
+	mp_data = meter_profile_data_find(action->mp,
+		RTE_DIM(action->mp),
+		meter_profile_id);
+	if (!mp_data)
+		return 0;
+
+	/* Uninstall profile */
+	mp_data->valid = 0;
+
+	return 0;
+}
+
+int
+rte_table_action_meter_read(struct rte_table_action *action,
+	void *data,
+	uint32_t tc_mask,
+	struct rte_table_action_mtr_counters *stats,
+	int clear)
+{
+	struct mtr_trtcm_data *mtr_data;
+	uint32_t i;
+
+	/* Check input arguments */
+	if ((action == NULL) ||
+		((action->cfg.action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) == 0) ||
+		(data == NULL) ||
+		(tc_mask > RTE_LEN2MASK(action->cfg.mtr.n_tc, uint32_t)))
+		return -EINVAL;
+
+	mtr_data = action_data_get(data, action, RTE_TABLE_ACTION_MTR);
+
+	/* Read */
+	if (stats) {
+		for (i = 0; i < RTE_TABLE_ACTION_TC_MAX; i++) {
+			struct rte_table_action_mtr_counters_tc *dst =
+				&stats->stats[i];
+			struct mtr_trtcm_data *src = &mtr_data[i];
+
+			if ((tc_mask & (1 << i)) == 0)
+				continue;
+
+			dst->n_packets[e_RTE_METER_GREEN] =
+				mtr_trtcm_data_stats_get(src, e_RTE_METER_GREEN);
+
+			dst->n_packets[e_RTE_METER_YELLOW] =
+				mtr_trtcm_data_stats_get(src, e_RTE_METER_YELLOW);
+
+			dst->n_packets[e_RTE_METER_RED] =
+				mtr_trtcm_data_stats_get(src, e_RTE_METER_RED);
+
+			dst->n_packets_valid = 1;
+			dst->n_bytes_valid = 0;
+		}
+
+		stats->tc_mask = tc_mask;
+	}
+
+	/* Clear */
+	if (clear)
+		for (i = 0; i < RTE_TABLE_ACTION_TC_MAX; i++) {
+			struct mtr_trtcm_data *src = &mtr_data[i];
+
+			if ((tc_mask & (1 << i)) == 0)
+				continue;
+
+			mtr_trtcm_data_stats_reset(src, e_RTE_METER_GREEN);
+			mtr_trtcm_data_stats_reset(src, e_RTE_METER_YELLOW);
+			mtr_trtcm_data_stats_reset(src, e_RTE_METER_RED);
+		}
+
+
 	return 0;
 }
 
+static __rte_always_inline uint64_t
+pkt_work(struct rte_mbuf *mbuf,
+	struct rte_pipeline_table_entry *table_entry,
+	uint64_t time,
+	struct rte_table_action *action,
+	struct ap_config *cfg)
+{
+	uint64_t drop_mask = 0;
+
+	uint32_t ip_offset = action->cfg.common.ip_offset;
+	void *ip = RTE_MBUF_METADATA_UINT32_PTR(mbuf, ip_offset);
+
+	uint32_t dscp;
+	uint16_t total_length;
+
+	if (cfg->common.ip_version) {
+		struct ipv4_hdr *hdr = ip;
+
+		dscp = hdr->type_of_service >> 2;
+		total_length = rte_ntohs(hdr->total_length);
+	} else {
+		struct ipv6_hdr *hdr = ip;
+
+		dscp = (rte_ntohl(hdr->vtc_flow) & 0x0F600000) >> 18;
+		total_length =
+			rte_ntohs(hdr->payload_len) + sizeof(struct ipv6_hdr);
+	}
+
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) {
+		void *data =
+			action_data_get(table_entry, action, RTE_TABLE_ACTION_MTR);
+
+		drop_mask |= pkt_work_mtr(mbuf,
+			data,
+			&action->dscp_table,
+			action->mp,
+			time,
+			dscp,
+			total_length);
+	}
+
+	return drop_mask;
+}
+
+static __rte_always_inline uint64_t
+pkt4_work(struct rte_mbuf **mbufs,
+	struct rte_pipeline_table_entry **table_entries,
+	uint64_t time,
+	struct rte_table_action *action,
+	struct ap_config *cfg)
+{
+	uint64_t drop_mask0 = 0;
+	uint64_t drop_mask1 = 0;
+	uint64_t drop_mask2 = 0;
+	uint64_t drop_mask3 = 0;
+
+	struct rte_mbuf *mbuf0 = mbufs[0];
+	struct rte_mbuf *mbuf1 = mbufs[1];
+	struct rte_mbuf *mbuf2 = mbufs[2];
+	struct rte_mbuf *mbuf3 = mbufs[3];
+
+	struct rte_pipeline_table_entry *table_entry0 = table_entries[0];
+	struct rte_pipeline_table_entry *table_entry1 = table_entries[1];
+	struct rte_pipeline_table_entry *table_entry2 = table_entries[2];
+	struct rte_pipeline_table_entry *table_entry3 = table_entries[3];
+
+	uint32_t ip_offset = action->cfg.common.ip_offset;
+	void *ip0 = RTE_MBUF_METADATA_UINT32_PTR(mbuf0, ip_offset);
+	void *ip1 = RTE_MBUF_METADATA_UINT32_PTR(mbuf1, ip_offset);
+	void *ip2 = RTE_MBUF_METADATA_UINT32_PTR(mbuf2, ip_offset);
+	void *ip3 = RTE_MBUF_METADATA_UINT32_PTR(mbuf3, ip_offset);
+
+	uint32_t dscp0, dscp1, dscp2, dscp3;
+	uint16_t total_length0, total_length1, total_length2, total_length3;
+
+	if (cfg->common.ip_version) {
+		struct ipv4_hdr *hdr0 = ip0;
+		struct ipv4_hdr *hdr1 = ip1;
+		struct ipv4_hdr *hdr2 = ip2;
+		struct ipv4_hdr *hdr3 = ip3;
+
+		dscp0 = hdr0->type_of_service >> 2;
+		dscp1 = hdr1->type_of_service >> 2;
+		dscp2 = hdr2->type_of_service >> 2;
+		dscp3 = hdr3->type_of_service >> 2;
+
+		total_length0 = rte_ntohs(hdr0->total_length);
+		total_length1 = rte_ntohs(hdr1->total_length);
+		total_length2 = rte_ntohs(hdr2->total_length);
+		total_length3 = rte_ntohs(hdr3->total_length);
+	} else {
+		struct ipv6_hdr *hdr0 = ip0;
+		struct ipv6_hdr *hdr1 = ip1;
+		struct ipv6_hdr *hdr2 = ip2;
+		struct ipv6_hdr *hdr3 = ip3;
+
+		dscp0 = (rte_ntohl(hdr0->vtc_flow) & 0x0F600000) >> 18;
+		dscp1 = (rte_ntohl(hdr1->vtc_flow) & 0x0F600000) >> 18;
+		dscp2 = (rte_ntohl(hdr2->vtc_flow) & 0x0F600000) >> 18;
+		dscp3 = (rte_ntohl(hdr3->vtc_flow) & 0x0F600000) >> 18;
+
+		total_length0 =
+			rte_ntohs(hdr0->payload_len) + sizeof(struct ipv6_hdr);
+		total_length1 =
+			rte_ntohs(hdr1->payload_len) + sizeof(struct ipv6_hdr);
+		total_length2 =
+			rte_ntohs(hdr2->payload_len) + sizeof(struct ipv6_hdr);
+		total_length3 =
+			rte_ntohs(hdr3->payload_len) + sizeof(struct ipv6_hdr);
+	}
+
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) {
+		void *data0 =
+			action_data_get(table_entry0, action, RTE_TABLE_ACTION_MTR);
+		void *data1 =
+			action_data_get(table_entry1, action, RTE_TABLE_ACTION_MTR);
+		void *data2 =
+			action_data_get(table_entry2, action, RTE_TABLE_ACTION_MTR);
+		void *data3 =
+			action_data_get(table_entry3, action, RTE_TABLE_ACTION_MTR);
+
+		drop_mask0 |= pkt_work_mtr(mbuf0,
+			data0,
+			&action->dscp_table,
+			action->mp,
+			time,
+			dscp0,
+			total_length0);
+
+		drop_mask1 |= pkt_work_mtr(mbuf1,
+			data1,
+			&action->dscp_table,
+			action->mp,
+			time,
+			dscp1,
+			total_length1);
+
+		drop_mask2 |= pkt_work_mtr(mbuf2,
+			data2,
+			&action->dscp_table,
+			action->mp,
+			time,
+			dscp2,
+			total_length2);
+
+		drop_mask3 |= pkt_work_mtr(mbuf3,
+			data3,
+			&action->dscp_table,
+			action->mp,
+			time,
+			dscp3,
+			total_length3);
+	}
+
+	return drop_mask0 |
+		(drop_mask1 << 1) |
+		(drop_mask2 << 2) |
+		(drop_mask3 << 3);
+}
+
 static __rte_always_inline int
 ah(struct rte_pipeline *p,
 	struct rte_mbuf **pkts,
@@ -297,6 +900,9 @@ ah(struct rte_pipeline *p,
 	uint64_t pkts_drop_mask = 0;
 	uint64_t time = 0;
 
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_MTR))
+		time = rte_rdtsc();
+
 	if ((pkts_mask & (pkts_mask + 1)) == 0) {
 		uint64_t n_pkts = __builtin_popcountll(pkts_mask);
 		uint32_t i;
diff --git a/lib/librte_pipeline/rte_table_action.h b/lib/librte_pipeline/rte_table_action.h
index 03b77ca..c2f4a55 100644
--- a/lib/librte_pipeline/rte_table_action.h
+++ b/lib/librte_pipeline/rte_table_action.h
@@ -59,6 +59,7 @@ extern "C" {
 #include <stdint.h>
 
 #include <rte_compat.h>
+#include <rte_meter.h>
 
 #include "rte_pipeline.h"
 
@@ -66,6 +67,9 @@ extern "C" {
 enum rte_table_action_type {
 	/** Forward to next pipeline table, output port or drop. */
 	RTE_TABLE_ACTION_FWD = 0,
+
+	/**  Traffic Metering and Policing. */
+	RTE_TABLE_ACTION_MTR,
 };
 
 /** Common action configuration (per table action profile). */
@@ -94,6 +98,164 @@ struct rte_table_action_fwd_params {
 };
 
 /**
+ * RTE_TABLE_ACTION_MTR
+ */
+/** Max number of traffic classes (TCs). */
+#define RTE_TABLE_ACTION_TC_MAX                                  4
+
+/** Max number of queues per traffic class. */
+#define RTE_TABLE_ACTION_TC_QUEUE_MAX                            4
+
+/** Differentiated Services Code Point (DSCP) translation table entry. */
+struct rte_table_action_dscp_table_entry {
+	/** Traffic class. Used by the meter or the traffic management actions.
+	 * Has to be strictly smaller than *RTE_TABLE_ACTION_TC_MAX*. Traffic
+	 * class 0 is the highest priority.
+	 */
+	uint32_t tc_id;
+
+	/** Traffic class queue. Used by the traffic management action. Has to
+	 * be strictly smaller than *RTE_TABLE_ACTION_TC_QUEUE_MAX*.
+	 */
+	uint32_t tc_queue_id;
+
+	/** Packet color. Used by the meter action as the packet input color
+	 * for the color aware mode of the traffic metering algorithm.
+	 */
+	enum rte_meter_color color;
+};
+
+/** DSCP translation table. */
+struct rte_table_action_dscp_table {
+	/** Array of DSCP table entries */
+	struct rte_table_action_dscp_table_entry entry[64];
+};
+
+/** Supported traffic metering algorithms. */
+enum rte_table_action_meter_algorithm {
+	/** Single Rate Three Color Marker (srTCM) - IETF RFC 2697. */
+	RTE_TABLE_ACTION_METER_SRTCM,
+
+	/** Two Rate Three Color Marker (trTCM) - IETF RFC 2698. */
+	RTE_TABLE_ACTION_METER_TRTCM,
+};
+
+/** Traffic metering profile (configuration template). */
+struct rte_table_action_meter_profile {
+	/** Traffic metering algorithm. */
+	enum rte_table_action_meter_algorithm alg;
+
+	RTE_STD_C11
+	union {
+		/** Only valid when *alg* is set to srTCM - IETF RFC 2697. */
+		struct rte_meter_srtcm_params srtcm;
+
+		/** Only valid when *alg* is set to trTCM - IETF RFC 2698. */
+		struct rte_meter_trtcm_params trtcm;
+	};
+};
+
+/** Policer actions. */
+enum rte_table_action_policer {
+	/** Recolor the packet as green. */
+	RTE_TABLE_ACTION_POLICER_COLOR_GREEN = 0,
+
+	/** Recolor the packet as yellow. */
+	RTE_TABLE_ACTION_POLICER_COLOR_YELLOW,
+
+	/** Recolor the packet as red. */
+	RTE_TABLE_ACTION_POLICER_COLOR_RED,
+
+	/** Drop the packet. */
+	RTE_TABLE_ACTION_POLICER_DROP,
+
+	/** Number of policer actions. */
+	RTE_TABLE_ACTION_POLICER_MAX
+};
+
+/** Meter action configuration per traffic class. */
+struct rte_table_action_mtr_tc_params {
+	/** Meter profile ID. */
+	uint32_t meter_profile_id;
+
+	/** Policer actions. */
+	enum rte_table_action_policer policer[e_RTE_METER_COLORS];
+};
+
+/** Meter action statistics counters per traffic class. */
+struct rte_table_action_mtr_counters_tc {
+	/** Number of packets per color at the output of the traffic metering
+	 * and before the policer actions are executed. Only valid when
+	 * *n_packets_valid* is non-zero.
+	 */
+	uint64_t n_packets[e_RTE_METER_COLORS];
+
+	/** Number of packet bytes per color at the output of the traffic
+	 * metering and before the policer actions are executed. Only valid when
+	 * *n_bytes_valid* is non-zero.
+	 */
+	uint64_t n_bytes[e_RTE_METER_COLORS];
+
+	/** When non-zero, the *n_packets* field is valid. */
+	int n_packets_valid;
+
+	/** When non-zero, the *n_bytes* field is valid. */
+	int n_bytes_valid;
+};
+
+/** Meter action configuration (per table action profile). */
+struct rte_table_action_mtr_config {
+	/** Meter algorithm. */
+	enum rte_table_action_meter_algorithm alg;
+
+	/** Number of traffic classes. Each traffic class has its own traffic
+	 * meter and policer instances. Needs to be equal to either 1 or to
+	 * *RTE_TABLE_ACTION_TC_MAX*.
+	 */
+	uint32_t n_tc;
+
+	/** When non-zero, the *n_packets* meter stats counter is enabled,
+	 * otherwise it is disabled.
+	 *
+	 * @see struct rte_table_action_mtr_counters_tc
+	 */
+	int n_packets_enabled;
+
+	/** When non-zero, the *n_bytes* meter stats counter is enabled,
+	 * otherwise it is disabled.
+	 *
+	 * @see struct rte_table_action_mtr_counters_tc
+	 */
+	int n_bytes_enabled;
+};
+
+/** Meter action parameters (per table rule). */
+struct rte_table_action_mtr_params {
+	/** Traffic meter and policer parameters for each of the *tc_mask*
+	 * traffic classes.
+	 */
+	struct rte_table_action_mtr_tc_params mtr[RTE_TABLE_ACTION_TC_MAX];
+
+	/** Bit mask defining which traffic class parameters are valid in *mtr*.
+	 * If bit N is set in *tc_mask*, then parameters for traffic class N are
+	 * valid in *mtr*.
+	 */
+	uint32_t tc_mask;
+};
+
+/** Meter action statistics counters (per table rule). */
+struct rte_table_action_mtr_counters {
+	/** Stats counters for each of the *tc_mask* traffic classes. */
+	struct rte_table_action_mtr_counters_tc stats[RTE_TABLE_ACTION_TC_MAX];
+
+	/** Bit mask defining which traffic class parameters are valid in *mtr*.
+	 * If bit N is set in *tc_mask*, then parameters for traffic class N are
+	 * valid in *mtr*.
+	 */
+	uint32_t tc_mask;
+};
+
+/**
  * Table action profile.
  */
 struct rte_table_action_profile;
@@ -231,6 +393,92 @@ rte_table_action_apply(struct rte_table_action *action,
 	enum rte_table_action_type type,
 	void *action_params);
 
+/**
+ * Table action DSCP table update.
+ *
+ * @param[in] action
+ *   Handle to table action object (needs to be valid).
+ * @param[in] dscp_mask
+ *   64-bit mask defining the DSCP table entries to be updated. If bit N is set
+ *   in this bit mask, then DSCP table entry N is to be updated, otherwise not.
+ * @param[in] table
+ *   DSCP table.
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_table_action_dscp_table_update(struct rte_table_action *action,
+	uint64_t dscp_mask,
+	struct rte_table_action_dscp_table *table);
+
+/**
+ * Table action meter profile add.
+ *
+ * @param[in] action
+ *   Handle to table action object (needs to be valid).
+ * @param[in] meter_profile_id
+ *   Meter profile ID to be used for the *profile* once it is successfully added
+ *   to the *action* object (needs to be unused by the set of meter profiles
+ *   currently registered for the *action* object).
+ * @param[in] profile
+ *   Meter profile to be added.
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_table_action_meter_profile_add(struct rte_table_action *action,
+	uint32_t meter_profile_id,
+	struct rte_table_action_meter_profile *profile);
+
+/**
+ * Table action meter profile delete.
+ *
+ * @param[in] action
+ *   Handle to table action object (needs to be valid).
+ * @param[in] meter_profile_id
+ *   Meter profile ID of the meter profile to be deleted from the *action*
+ *   object (needs to be valid for the *action* object).
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_table_action_meter_profile_delete(struct rte_table_action *action,
+	uint32_t meter_profile_id);
+
+/**
+ * Table action meter read.
+ *
+ * @param[in] action
+ *   Handle to table action object (needs to be valid).
+ * @param[in] data
+ *   Data byte array (typically table rule data) with meter action previously
+ *   applied on it.
+ * @param[in] tc_mask
+ *   Bit mask defining which traffic classes should have the meter stats
+ *   counters read from *data* and stored into *stats*. If bit N is set in this
+ *   bit mask, then traffic class N is part of this operation, otherwise it is
+ *   not. If bit N is set in this bit mask, then traffic class N must be one of
+ *   the traffic classes that are enabled for the meter action in the table
+ *   action profile used by the *action* object.
+ * @param[inout] stats
+ *   When non-NULL, it points to the area where the meter stats counters read
+ *   from *data* are saved. Only the meter stats counters for the *tc_mask*
+ *   traffic classes are read and stored to *stats*.
+ * @param[in] clear
+ *   When non-zero, the meter stats counters are cleared (i.e. set to zero),
+ *   otherwise the counters are not modified. When the read operation is enabled
+ *   (*stats* is non-NULL), the clear operation is performed after the read
+ *   operation is completed.
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_table_action_meter_read(struct rte_table_action *action,
+	void *data,
+	uint32_t tc_mask,
+	struct rte_table_action_mtr_counters *stats,
+	int clear);
+
 #ifdef __cplusplus
 }
 #endif
-- 
2.9.3

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

* [dpdk-dev] [PATCH 04/37] pipeline: add traffic manager action
  2018-03-09 18:23 [dpdk-dev] [PATCH 00/37] ip_pipeline: refactoring Jasvinder Singh
                   ` (2 preceding siblings ...)
  2018-03-09 18:23 ` [dpdk-dev] [PATCH 03/37] pipeline: add traffic metering action Jasvinder Singh
@ 2018-03-09 18:23 ` Jasvinder Singh
  2018-03-09 18:23 ` [dpdk-dev] [PATCH 05/37] pipeline: add packet encapsulation action Jasvinder Singh
                   ` (32 subsequent siblings)
  36 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-09 18:23 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add implementation of traffic manager action.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 lib/librte_pipeline/Makefile           |   2 +-
 lib/librte_pipeline/meson.build        |   2 +-
 lib/librte_pipeline/rte_table_action.c | 130 ++++++++++++++++++++++++++++++++-
 lib/librte_pipeline/rte_table_action.h |  24 ++++++
 4 files changed, 155 insertions(+), 3 deletions(-)

diff --git a/lib/librte_pipeline/Makefile b/lib/librte_pipeline/Makefile
index 72e4c7c..c0eaa09 100644
--- a/lib/librte_pipeline/Makefile
+++ b/lib/librte_pipeline/Makefile
@@ -12,7 +12,7 @@ CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
 LDLIBS += -lrte_eal -lrte_mempool -lrte_mbuf -lrte_table
-LDLIBS += -lrte_port -lrte_meter
+LDLIBS += -lrte_port -lrte_meter -lrte_sched
 
 EXPORT_MAP := rte_pipeline_version.map
 
diff --git a/lib/librte_pipeline/meson.build b/lib/librte_pipeline/meson.build
index 71da295..1ee276f 100644
--- a/lib/librte_pipeline/meson.build
+++ b/lib/librte_pipeline/meson.build
@@ -5,4 +5,4 @@ version = 3
 allow_experimental_apis = true
 sources = files('rte_pipeline.c', 'rte_table_action.c')
 headers = files('rte_pipeline.h', 'rte_table_action.h')
-deps += ['port', 'table', 'meter']
+deps += ['port', 'table', 'meter', 'sched']
diff --git a/lib/librte_pipeline/rte_table_action.c b/lib/librte_pipeline/rte_table_action.c
index b22bf80..09016d1 100644
--- a/lib/librte_pipeline/rte_table_action.c
+++ b/lib/librte_pipeline/rte_table_action.c
@@ -295,6 +295,73 @@ pkt_work_mtr(struct rte_mbuf *mbuf,
 	return drop_mask;
 }
 
+/**
+ * RTE_TABLE_ACTION_TM
+ */
+static int
+tm_cfg_check(struct rte_table_action_tm_config *tm)
+{
+	if ((tm->n_subports_per_port == 0) ||
+		(rte_is_power_of_2(tm->n_subports_per_port) == 0) ||
+		(tm->n_subports_per_port > UINT16_MAX) ||
+		(tm->n_pipes_per_subport == 0) ||
+		(rte_is_power_of_2(tm->n_pipes_per_subport) == 0))
+		return -ENOTSUP;
+
+	return 0;
+}
+
+struct tm_data {
+	uint16_t queue_tc_color;
+	uint16_t subport;
+	uint32_t pipe;
+} __attribute__((__packed__));
+
+static int
+tm_apply_check(struct rte_table_action_tm_params *p,
+	struct rte_table_action_tm_config *cfg)
+{
+	if ((p->subport_id >= cfg->n_subports_per_port) ||
+		(p->pipe_id >= cfg->n_pipes_per_subport))
+		return -EINVAL;
+
+	return 0;
+}
+
+static int
+tm_apply(struct tm_data *data,
+	struct rte_table_action_tm_params *p,
+	struct rte_table_action_tm_config *cfg)
+{
+	int status;
+
+	/* Check input arguments */
+	status = tm_apply_check(p, cfg);
+	if (status)
+		return status;
+
+	/* Apply */
+	data->queue_tc_color = 0;
+	data->subport = (uint16_t) p->subport_id;
+	data->pipe = p->pipe_id;
+
+	return 0;
+}
+
+static __rte_always_inline void
+pkt_work_tm(struct rte_mbuf *mbuf,
+	struct tm_data *data,
+	struct dscp_table_data *dscp_table,
+	uint32_t dscp)
+{
+	struct dscp_table_entry_data *dscp_entry = &dscp_table->entry[dscp];
+	struct tm_data *sched_ptr = (struct tm_data *) &mbuf->hash.sched;
+	struct tm_data sched;
+
+	sched = *data;
+	sched.queue_tc_color = dscp_entry->queue_tc_color;
+	*sched_ptr = sched;
+}
 
 /**
  * Action profile
@@ -305,6 +372,7 @@ action_valid(enum rte_table_action_type action)
 	switch (action) {
 	case RTE_TABLE_ACTION_FWD:
 	case RTE_TABLE_ACTION_MTR:
+	case RTE_TABLE_ACTION_TM:
 		return 1;
 	default:
 		return 0;
@@ -318,6 +386,7 @@ struct ap_config {
 	uint64_t action_mask;
 	struct rte_table_action_common_config common;
 	struct rte_table_action_mtr_config mtr;
+	struct rte_table_action_tm_config tm;
 };
 
 static size_t
@@ -326,6 +395,8 @@ action_cfg_size(enum rte_table_action_type action)
 	switch (action) {
 	case RTE_TABLE_ACTION_MTR:
 		return sizeof(struct rte_table_action_mtr_config);
+	case RTE_TABLE_ACTION_TM:
+		return sizeof(struct rte_table_action_tm_config);
 	default:
 		return 0;
 	}
@@ -339,6 +410,9 @@ action_cfg_get(struct ap_config *ap_config,
 	case RTE_TABLE_ACTION_MTR:
 		return &ap_config->mtr;
 
+	case RTE_TABLE_ACTION_TM:
+		return &ap_config->tm;
+
 	default:
 		return NULL;
 	}
@@ -373,6 +447,9 @@ action_data_size(enum rte_table_action_type action,
 	case RTE_TABLE_ACTION_MTR:
 		return mtr_data_size(&ap_config->mtr);
 
+	case RTE_TABLE_ACTION_TM:
+		return sizeof(struct tm_data);
+
 	default:
 		return 0;
 	}
@@ -447,6 +524,10 @@ rte_table_action_profile_action_register(struct rte_table_action_profile *profil
 		status = mtr_cfg_check(action_config);
 		break;
 
+	case RTE_TABLE_ACTION_TM:
+		status = tm_cfg_check(action_config);
+		break;
+
 	default:
 		status = 0;
 		break;
@@ -564,6 +645,11 @@ rte_table_action_apply(struct rte_table_action *action,
 			action->mp,
 			RTE_DIM(action->mp));
 
+	case RTE_TABLE_ACTION_TM:
+		return tm_apply(action_data,
+			action_params,
+			&action->cfg.tm);
+
 	default:
 		return -EINVAL;
 	}
@@ -578,7 +664,8 @@ rte_table_action_dscp_table_update(struct rte_table_action *action,
 
 	/* Check input arguments */
 	if ((action == NULL) ||
-		(action->cfg.action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) ||
+		((action->cfg.action_mask & ((1LLU << RTE_TABLE_ACTION_MTR) |
+		(1LLU << RTE_TABLE_ACTION_TM))) == 0) ||
 		(dscp_mask == 0) ||
 		(table == NULL))
 		return -EINVAL;
@@ -770,6 +857,16 @@ pkt_work(struct rte_mbuf *mbuf,
 			total_length);
 	}
 
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_TM)) {
+		void *data =
+			action_data_get(table_entry, action, RTE_TABLE_ACTION_TM);
+
+		pkt_work_tm(mbuf,
+			data,
+			&action->dscp_table,
+			dscp);
+	}
+
 	return drop_mask;
 }
 
@@ -883,6 +980,37 @@ pkt4_work(struct rte_mbuf **mbufs,
 			total_length3);
 	}
 
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_TM)) {
+		void *data0 =
+			action_data_get(table_entry0, action, RTE_TABLE_ACTION_TM);
+		void *data1 =
+			action_data_get(table_entry1, action, RTE_TABLE_ACTION_TM);
+		void *data2 =
+			action_data_get(table_entry2, action, RTE_TABLE_ACTION_TM);
+		void *data3 =
+			action_data_get(table_entry3, action, RTE_TABLE_ACTION_TM);
+
+		pkt_work_tm(mbuf0,
+			data0,
+			&action->dscp_table,
+			dscp0);
+
+		pkt_work_tm(mbuf1,
+			data1,
+			&action->dscp_table,
+			dscp1);
+
+		pkt_work_tm(mbuf2,
+			data2,
+			&action->dscp_table,
+			dscp2);
+
+		pkt_work_tm(mbuf3,
+			data3,
+			&action->dscp_table,
+			dscp3);
+	}
+
 	return drop_mask0 |
 		(drop_mask1 << 1) |
 		(drop_mask2 << 2) |
diff --git a/lib/librte_pipeline/rte_table_action.h b/lib/librte_pipeline/rte_table_action.h
index c2f4a55..98babc5 100644
--- a/lib/librte_pipeline/rte_table_action.h
+++ b/lib/librte_pipeline/rte_table_action.h
@@ -70,6 +70,9 @@ enum rte_table_action_type {
 
 	/**  Traffic Metering and Policing. */
 	RTE_TABLE_ACTION_MTR,
+
+	/**  Traffic Management. */
+	RTE_TABLE_ACTION_TM,
 };
 
 /** Common action configuration (per table action profile). */
@@ -256,6 +259,27 @@ struct rte_table_action_mtr_counters {
 };
 
 /**
+ * RTE_TABLE_ACTION_TM
+ */
+/** Traffic management action configuration (per table action profile). */
+struct rte_table_action_tm_config {
+	/** Number of subports per port. */
+	uint32_t n_subports_per_port;
+
+	/** Number of pipes per subport. */
+	uint32_t n_pipes_per_subport;
+};
+
+/** Traffic management action parameters (per table rule). */
+struct rte_table_action_tm_params {
+	/** Subport ID. */
+	uint32_t subport_id;
+
+	/** Pipe ID. */
+	uint32_t pipe_id;
+};
+
+/**
  * Table action profile.
  */
 struct rte_table_action_profile;
-- 
2.9.3

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

* [dpdk-dev] [PATCH 05/37] pipeline: add packet encapsulation action
  2018-03-09 18:23 [dpdk-dev] [PATCH 00/37] ip_pipeline: refactoring Jasvinder Singh
                   ` (3 preceding siblings ...)
  2018-03-09 18:23 ` [dpdk-dev] [PATCH 04/37] pipeline: add traffic manager action Jasvinder Singh
@ 2018-03-09 18:23 ` Jasvinder Singh
  2018-03-09 18:23 ` [dpdk-dev] [PATCH 06/37] pipeline: add nat action Jasvinder Singh
                   ` (31 subsequent siblings)
  36 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-09 18:23 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add implementation of different type of packet encap
such as vlan, qinq, mpls, pppoe, etc.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 lib/librte_pipeline/rte_table_action.c | 440 ++++++++++++++++++++++++++++++++-
 lib/librte_pipeline/rte_table_action.h | 129 ++++++++++
 2 files changed, 568 insertions(+), 1 deletion(-)

diff --git a/lib/librte_pipeline/rte_table_action.c b/lib/librte_pipeline/rte_table_action.c
index 09016d1..a3c1546 100644
--- a/lib/librte_pipeline/rte_table_action.c
+++ b/lib/librte_pipeline/rte_table_action.c
@@ -9,8 +9,12 @@
 #include <rte_byteorder.h>
 #include <rte_cycles.h>
 #include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_ether.h>
 #include <rte_ip.h>
-
+#include <rte_esp.h>
+#include <rte_tcp.h>
+#include <rte_udp.h>
 
 #include "rte_table_action.h"
 
@@ -364,6 +368,369 @@ pkt_work_tm(struct rte_mbuf *mbuf,
 }
 
 /**
+ * RTE_TABLE_ACTION_ENCAP
+ */
+static int
+encap_valid(enum rte_table_action_encap_type encap)
+{
+	switch (encap) {
+	case RTE_TABLE_ACTION_ENCAP_ETHER:
+	case RTE_TABLE_ACTION_ENCAP_VLAN:
+	case RTE_TABLE_ACTION_ENCAP_QINQ:
+	case RTE_TABLE_ACTION_ENCAP_MPLS:
+	case RTE_TABLE_ACTION_ENCAP_PPPOE:
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+static int
+encap_cfg_check(struct rte_table_action_encap_config *encap)
+{
+	if ((encap->encap_mask == 0) ||
+		(__builtin_popcountll(encap->encap_mask) != 1))
+		return -ENOTSUP;
+
+	return 0;
+}
+
+struct encap_ether_data {
+	struct ether_hdr ether;
+} __attribute__((__packed__));
+
+#define VLAN(pcp, dei, vid)                                \
+	((uint16_t)((((uint64_t)(pcp)) & 0x7LLU) << 13) |  \
+	((((uint64_t)(dei)) & 0x1LLU) << 12) |             \
+	(((uint64_t)(vid)) & 0xFFFLLU))                    \
+
+struct encap_vlan_data {
+	struct ether_hdr ether;
+	struct vlan_hdr vlan;
+} __attribute__((__packed__));
+
+struct encap_qinq_data {
+	struct ether_hdr ether;
+	struct vlan_hdr svlan;
+	struct vlan_hdr cvlan;
+} __attribute__((__packed__));
+
+#define ETHER_TYPE_MPLS_UNICAST                            0x8847
+
+#define ETHER_TYPE_MPLS_MULTICAST                          0x8848
+
+#define MPLS(label, tc, s, ttl)                            \
+	((uint32_t)(((((uint64_t)(label)) & 0xFFFFFLLU) << 12) |\
+	((((uint64_t)(tc)) & 0x7LLU) << 9) |               \
+	((((uint64_t)(s)) & 0x1LLU) << 8) |                \
+	(((uint64_t)(ttl)) & 0xFFLLU)))
+
+struct encap_mpls_data {
+	struct ether_hdr ether;
+	uint32_t mpls[RTE_TABLE_ACTION_MPLS_LABELS_MAX];
+	uint32_t mpls_count;
+} __attribute__((__packed__));
+
+#define ETHER_TYPE_PPPOE_SESSION                           0x8864
+
+#define PPP_PROTOCOL_IP                                    0x0021
+
+struct pppoe_ppp_hdr {
+	uint16_t ver_type_code;
+	uint16_t session_id;
+	uint16_t length;
+	uint16_t protocol;
+} __attribute__((__packed__));
+
+struct encap_pppoe_data {
+	struct ether_hdr ether;
+	struct pppoe_ppp_hdr pppoe_ppp;
+} __attribute__((__packed__));
+
+static size_t
+encap_data_size(struct rte_table_action_encap_config *encap)
+{
+	switch (encap->encap_mask) {
+	case 1LLU << RTE_TABLE_ACTION_ENCAP_ETHER:
+		return sizeof(struct encap_ether_data);
+
+	case 1LLU << RTE_TABLE_ACTION_ENCAP_VLAN:
+		return sizeof(struct encap_vlan_data);
+
+	case 1LLU << RTE_TABLE_ACTION_ENCAP_QINQ:
+		return sizeof(struct encap_qinq_data);
+
+	case 1LLU << RTE_TABLE_ACTION_ENCAP_MPLS:
+		return sizeof(struct encap_mpls_data);
+
+	case 1LLU << RTE_TABLE_ACTION_ENCAP_PPPOE:
+		return sizeof(struct encap_pppoe_data);
+
+	default:
+		return 0;
+	}
+}
+
+static int
+encap_apply_check(struct rte_table_action_encap_params *p,
+	struct rte_table_action_encap_config *cfg)
+{
+	if ((encap_valid(p->type) == 0) ||
+		((cfg->encap_mask & (1LLU << p->type)) == 0))
+		return -EINVAL;
+
+	switch (p->type) {
+	case RTE_TABLE_ACTION_ENCAP_ETHER:
+		return 0;
+
+	case RTE_TABLE_ACTION_ENCAP_VLAN:
+		return 0;
+
+	case RTE_TABLE_ACTION_ENCAP_QINQ:
+		return 0;
+
+	case RTE_TABLE_ACTION_ENCAP_MPLS:
+		if ((p->mpls.mpls_count == 0) ||
+			(p->mpls.mpls_count > RTE_TABLE_ACTION_MPLS_LABELS_MAX))
+			return -EINVAL;
+
+		return 0;
+
+	case RTE_TABLE_ACTION_ENCAP_PPPOE:
+		return 0;
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static int
+encap_ether_apply(void *data,
+	struct rte_table_action_encap_params *p,
+	struct rte_table_action_common_config *common_cfg)
+{
+	struct encap_ether_data *d = data;
+	uint16_t ethertype = (common_cfg->ip_version) ?
+		ETHER_TYPE_IPv4 :
+		ETHER_TYPE_IPv6;
+
+	/* Ethernet */
+	ether_addr_copy(&p->ether.ether.da, &d->ether.d_addr);
+	ether_addr_copy(&p->ether.ether.sa, &d->ether.s_addr);
+	d->ether.ether_type = rte_htons(ethertype);
+
+	return 0;
+}
+
+static int
+encap_vlan_apply(void *data,
+	struct rte_table_action_encap_params *p,
+	struct rte_table_action_common_config *common_cfg)
+{
+	struct encap_vlan_data *d = data;
+	uint16_t ethertype = (common_cfg->ip_version) ?
+		ETHER_TYPE_IPv4 :
+		ETHER_TYPE_IPv6;
+
+	/* Ethernet */
+	ether_addr_copy(&p->vlan.ether.da, &d->ether.d_addr);
+	ether_addr_copy(&p->vlan.ether.sa, &d->ether.s_addr);
+	d->ether.ether_type = rte_htons(ETHER_TYPE_VLAN);
+
+	/* VLAN */
+	d->vlan.vlan_tci = rte_htons(VLAN(p->vlan.vlan.pcp,
+		p->vlan.vlan.dei,
+		p->vlan.vlan.vid));
+	d->vlan.eth_proto = rte_htons(ethertype);
+
+	return 0;
+}
+
+static int
+encap_qinq_apply(void *data,
+	struct rte_table_action_encap_params *p,
+	struct rte_table_action_common_config *common_cfg)
+{
+	struct encap_qinq_data *d = data;
+	uint16_t ethertype = (common_cfg->ip_version) ?
+		ETHER_TYPE_IPv4 :
+		ETHER_TYPE_IPv6;
+
+	/* Ethernet */
+	ether_addr_copy(&p->qinq.ether.da, &d->ether.d_addr);
+	ether_addr_copy(&p->qinq.ether.sa, &d->ether.s_addr);
+	d->ether.ether_type = rte_htons(ETHER_TYPE_QINQ);
+
+	/* SVLAN */
+	d->svlan.vlan_tci = rte_htons(VLAN(p->qinq.svlan.pcp,
+		p->qinq.svlan.dei,
+		p->qinq.svlan.vid));
+	d->svlan.eth_proto = rte_htons(ETHER_TYPE_VLAN);
+
+	/* CVLAN */
+	d->cvlan.vlan_tci = rte_htons(VLAN(p->qinq.cvlan.pcp,
+		p->qinq.cvlan.dei,
+		p->qinq.cvlan.vid));
+	d->cvlan.eth_proto = rte_htons(ethertype);
+
+	return 0;
+}
+
+static int
+encap_mpls_apply(void *data,
+	struct rte_table_action_encap_params *p)
+{
+	struct encap_mpls_data *d = data;
+	uint16_t ethertype = (p->mpls.unicast) ?
+		ETHER_TYPE_MPLS_UNICAST :
+		ETHER_TYPE_MPLS_MULTICAST;
+	uint32_t i;
+
+	/* Ethernet */
+	ether_addr_copy(&p->mpls.ether.da, &d->ether.d_addr);
+	ether_addr_copy(&p->mpls.ether.sa, &d->ether.s_addr);
+	d->ether.ether_type = rte_htons(ethertype);
+
+	/* MPLS */
+	for (i = 0; i < p->mpls.mpls_count - 1; i++)
+		d->mpls[i] = rte_htonl(MPLS(p->mpls.mpls[i].label,
+			p->mpls.mpls[i].tc,
+			0,
+			p->mpls.mpls[i].ttl));
+
+	d->mpls[i] = rte_htonl(MPLS(p->mpls.mpls[i].label,
+		p->mpls.mpls[i].tc,
+		1,
+		p->mpls.mpls[i].ttl));
+
+	d->mpls_count = p->mpls.mpls_count;
+	return 0;
+}
+
+static int
+encap_pppoe_apply(void *data,
+	struct rte_table_action_encap_params *p)
+{
+	struct encap_pppoe_data *d = data;
+
+	/* Ethernet */
+	ether_addr_copy(&p->pppoe.ether.da, &d->ether.d_addr);
+	ether_addr_copy(&p->pppoe.ether.sa, &d->ether.s_addr);
+	d->ether.ether_type = rte_htons(ETHER_TYPE_PPPOE_SESSION);
+
+	/* PPPoE and PPP*/
+	d->pppoe_ppp.ver_type_code = rte_htons(0x1100);
+	d->pppoe_ppp.session_id = rte_htons(p->pppoe.pppoe.session_id);
+	d->pppoe_ppp.length = 0; /* not pre-computed */
+	d->pppoe_ppp.protocol = rte_htons(PPP_PROTOCOL_IP);
+
+	return 0;
+}
+
+static int
+encap_apply(void *data,
+	struct rte_table_action_encap_params *p,
+	struct rte_table_action_encap_config *cfg,
+	struct rte_table_action_common_config *common_cfg)
+{
+	int status;
+
+	/* Check input arguments */
+	status = encap_apply_check(p, cfg);
+	if (status)
+		return status;
+
+	switch (p->type) {
+	case RTE_TABLE_ACTION_ENCAP_ETHER:
+		return encap_ether_apply(data, p, common_cfg);
+
+	case RTE_TABLE_ACTION_ENCAP_VLAN:
+		return encap_vlan_apply(data, p, common_cfg);
+
+	case RTE_TABLE_ACTION_ENCAP_QINQ:
+		return encap_qinq_apply(data, p, common_cfg);
+
+	case RTE_TABLE_ACTION_ENCAP_MPLS:
+		return encap_mpls_apply(data, p);
+
+	case RTE_TABLE_ACTION_ENCAP_PPPOE:
+		return encap_pppoe_apply(data, p);
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static __rte_always_inline void *
+encap(void *dst, const void *src, size_t n)
+{
+	dst = ((uint8_t *) dst) - n;
+	return rte_memcpy(dst, src, n);
+}
+
+static __rte_always_inline void
+pkt_work_encap(struct rte_mbuf *mbuf,
+	void *data,
+	struct rte_table_action_encap_config *cfg,
+	void *ip,
+	uint16_t total_length,
+	uint32_t ip_offset)
+{
+	switch (cfg->encap_mask) {
+	case 1LLU << RTE_TABLE_ACTION_ENCAP_ETHER:
+		encap(ip, data, sizeof(struct encap_ether_data));
+		mbuf->data_off = ip_offset - (sizeof(struct rte_mbuf) +
+			sizeof(struct encap_ether_data));
+		mbuf->pkt_len = mbuf->data_len = total_length +
+			sizeof(struct encap_ether_data);
+		break;
+
+	case 1LLU << RTE_TABLE_ACTION_ENCAP_VLAN:
+		encap(ip, data, sizeof(struct encap_vlan_data));
+		mbuf->data_off = ip_offset - (sizeof(struct rte_mbuf) +
+			sizeof(struct encap_vlan_data));
+		mbuf->pkt_len = mbuf->data_len = total_length +
+			sizeof(struct encap_vlan_data);
+		break;
+
+	case 1LLU << RTE_TABLE_ACTION_ENCAP_QINQ:
+		encap(ip, data, sizeof(struct encap_qinq_data));
+		mbuf->data_off = ip_offset - (sizeof(struct rte_mbuf) +
+			sizeof(struct encap_qinq_data));
+		mbuf->pkt_len = mbuf->data_len = total_length +
+			sizeof(struct encap_qinq_data);
+		break;
+
+	case 1LLU << RTE_TABLE_ACTION_ENCAP_MPLS:
+	{
+		struct encap_mpls_data *mpls = data;
+		size_t size = sizeof(struct ether_hdr) +
+			mpls->mpls_count * 4;
+
+		encap(ip, data, size);
+		mbuf->data_off = ip_offset - (sizeof(struct rte_mbuf) + size);
+		mbuf->pkt_len = mbuf->data_len = total_length + size;
+		break;
+	}
+
+	case 1LLU << RTE_TABLE_ACTION_ENCAP_PPPOE:
+	{
+		struct encap_pppoe_data *pppoe =
+			encap(ip, data, sizeof(struct encap_pppoe_data));
+		pppoe->pppoe_ppp.length = rte_htons(total_length + 2);
+		mbuf->data_off = ip_offset - (sizeof(struct rte_mbuf) +
+			sizeof(struct encap_pppoe_data));
+		mbuf->pkt_len = mbuf->data_len = total_length +
+			sizeof(struct encap_pppoe_data);
+		break;
+	}
+
+	default:
+		break;
+	}
+}
+
+/**
  * Action profile
  */
 static int
@@ -373,6 +740,7 @@ action_valid(enum rte_table_action_type action)
 	case RTE_TABLE_ACTION_FWD:
 	case RTE_TABLE_ACTION_MTR:
 	case RTE_TABLE_ACTION_TM:
+	case RTE_TABLE_ACTION_ENCAP:
 		return 1;
 	default:
 		return 0;
@@ -387,6 +755,7 @@ struct ap_config {
 	struct rte_table_action_common_config common;
 	struct rte_table_action_mtr_config mtr;
 	struct rte_table_action_tm_config tm;
+	struct rte_table_action_encap_config encap;
 };
 
 static size_t
@@ -397,6 +766,8 @@ action_cfg_size(enum rte_table_action_type action)
 		return sizeof(struct rte_table_action_mtr_config);
 	case RTE_TABLE_ACTION_TM:
 		return sizeof(struct rte_table_action_tm_config);
+	case RTE_TABLE_ACTION_ENCAP:
+		return sizeof(struct rte_table_action_encap_config);
 	default:
 		return 0;
 	}
@@ -413,6 +784,9 @@ action_cfg_get(struct ap_config *ap_config,
 	case RTE_TABLE_ACTION_TM:
 		return &ap_config->tm;
 
+	case RTE_TABLE_ACTION_ENCAP:
+		return &ap_config->encap;
+
 	default:
 		return NULL;
 	}
@@ -450,6 +824,9 @@ action_data_size(enum rte_table_action_type action,
 	case RTE_TABLE_ACTION_TM:
 		return sizeof(struct tm_data);
 
+	case RTE_TABLE_ACTION_ENCAP:
+		return encap_data_size(&ap_config->encap);
+
 	default:
 		return 0;
 	}
@@ -528,6 +905,10 @@ rte_table_action_profile_action_register(struct rte_table_action_profile *profil
 		status = tm_cfg_check(action_config);
 		break;
 
+	case RTE_TABLE_ACTION_ENCAP:
+		status = encap_cfg_check(action_config);
+		break;
+
 	default:
 		status = 0;
 		break;
@@ -650,6 +1031,12 @@ rte_table_action_apply(struct rte_table_action *action,
 			action_params,
 			&action->cfg.tm);
 
+	case RTE_TABLE_ACTION_ENCAP:
+		return encap_apply(action_data,
+			action_params,
+			&action->cfg.encap,
+			&action->cfg.common);
+
 	default:
 		return -EINVAL;
 	}
@@ -867,6 +1254,18 @@ pkt_work(struct rte_mbuf *mbuf,
 			dscp);
 	}
 
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_ENCAP)) {
+		void *data =
+			action_data_get(table_entry, action, RTE_TABLE_ACTION_ENCAP);
+
+		pkt_work_encap(mbuf,
+			data,
+			&cfg->encap,
+			ip,
+			total_length,
+			ip_offset);
+	}
+
 	return drop_mask;
 }
 
@@ -1011,6 +1410,45 @@ pkt4_work(struct rte_mbuf **mbufs,
 			dscp3);
 	}
 
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_ENCAP)) {
+		void *data0 =
+			action_data_get(table_entry0, action, RTE_TABLE_ACTION_ENCAP);
+		void *data1 =
+			action_data_get(table_entry1, action, RTE_TABLE_ACTION_ENCAP);
+		void *data2 =
+			action_data_get(table_entry2, action, RTE_TABLE_ACTION_ENCAP);
+		void *data3 =
+			action_data_get(table_entry3, action, RTE_TABLE_ACTION_ENCAP);
+
+		pkt_work_encap(mbuf0,
+			data0,
+			&cfg->encap,
+			ip0,
+			total_length0,
+			ip_offset);
+
+		pkt_work_encap(mbuf1,
+			data1,
+			&cfg->encap,
+			ip1,
+			total_length1,
+			ip_offset);
+
+		pkt_work_encap(mbuf2,
+			data2,
+			&cfg->encap,
+			ip2,
+			total_length2,
+			ip_offset);
+
+		pkt_work_encap(mbuf3,
+			data3,
+			&cfg->encap,
+			ip3,
+			total_length3,
+			ip_offset);
+	}
+
 	return drop_mask0 |
 		(drop_mask1 << 1) |
 		(drop_mask2 << 2) |
diff --git a/lib/librte_pipeline/rte_table_action.h b/lib/librte_pipeline/rte_table_action.h
index 98babc5..c5c987d 100644
--- a/lib/librte_pipeline/rte_table_action.h
+++ b/lib/librte_pipeline/rte_table_action.h
@@ -59,6 +59,7 @@ extern "C" {
 #include <stdint.h>
 
 #include <rte_compat.h>
+#include <rte_ether.h>
 #include <rte_meter.h>
 
 #include "rte_pipeline.h"
@@ -73,6 +74,9 @@ enum rte_table_action_type {
 
 	/**  Traffic Management. */
 	RTE_TABLE_ACTION_TM,
+
+	/** Packet encapsulations. */
+	RTE_TABLE_ACTION_ENCAP,
 };
 
 /** Common action configuration (per table action profile). */
@@ -280,6 +284,131 @@ struct rte_table_action_tm_params {
 };
 
 /**
+ * RTE_TABLE_ACTION_ENCAP
+ */
+/** Supported packet encapsulation types. */
+enum rte_table_action_encap_type {
+	/** IP -> { Ether | IP } */
+	RTE_TABLE_ACTION_ENCAP_ETHER = 0,
+
+	/** IP -> { Ether | VLAN | IP } */
+	RTE_TABLE_ACTION_ENCAP_VLAN,
+
+	/** IP -> { Ether | S-VLAN | C-VLAN | IP } */
+	RTE_TABLE_ACTION_ENCAP_QINQ,
+
+	/** IP -> { Ether | MPLS | IP } */
+	RTE_TABLE_ACTION_ENCAP_MPLS,
+
+	/** IP -> { Ether | PPPoE | PPP | IP } */
+	RTE_TABLE_ACTION_ENCAP_PPPOE,
+};
+
+/** Pre-computed Ethernet header fields for encapsulation action. */
+struct rte_table_action_ether_hdr {
+	struct ether_addr da; /**< Destination address. */
+	struct ether_addr sa; /**< Source address. */
+};
+
+/** Pre-computed VLAN header fields for encapsulation action. */
+struct rte_table_action_vlan_hdr {
+	uint8_t pcp; /**< Priority Code Point (PCP). */
+	uint8_t dei; /**< Drop Eligibility Indicator (DEI). */
+	uint16_t vid; /**< VLAN Identifier (VID). */
+};
+
+/** Pre-computed MPLS header fields for encapsulation action. */
+struct rte_table_action_mpls_hdr {
+	uint32_t label; /**< Label. */
+	uint8_t tc; /**< Traffic Class (TC). */
+	uint8_t ttl; /**< Time to Live (TTL). */
+};
+
+/** Pre-computed PPPoE header fields for encapsulation action. */
+struct rte_table_action_pppoe_hdr {
+	uint16_t session_id; /**< Session ID. */
+};
+
+/** Ether encap parameters. */
+struct rte_table_action_encap_ether_params {
+	struct rte_table_action_ether_hdr ether; /**< Ethernet header. */
+};
+
+/** VLAN encap parameters. */
+struct rte_table_action_encap_vlan_params {
+	struct rte_table_action_ether_hdr ether; /**< Ethernet header. */
+	struct rte_table_action_vlan_hdr vlan; /**< VLAN header. */
+};
+
+/** QinQ encap parameters. */
+struct rte_table_action_encap_qinq_params {
+	struct rte_table_action_ether_hdr ether; /**< Ethernet header. */
+	struct rte_table_action_vlan_hdr svlan; /**< Service VLAN header. */
+	struct rte_table_action_vlan_hdr cvlan; /**< Customer VLAN header. */
+};
+
+/** Max number of MPLS labels per output packet for MPLS encapsulation. */
+#ifndef RTE_TABLE_ACTION_MPLS_LABELS_MAX
+#define RTE_TABLE_ACTION_MPLS_LABELS_MAX                   4
+#endif
+
+/** MPLS encap parameters. */
+struct rte_table_action_encap_mpls_params {
+	/** Ethernet header. */
+	struct rte_table_action_ether_hdr ether;
+
+	/** MPLS header. */
+	struct rte_table_action_mpls_hdr mpls[RTE_TABLE_ACTION_MPLS_LABELS_MAX];
+
+	/** Number of MPLS labels in MPLS header. */
+	uint32_t mpls_count;
+
+	/** Non-zero for MPLS unicast, zero for MPLS multicast. */
+	int unicast;
+};
+
+/** PPPoE encap parameters. */
+struct rte_table_action_encap_pppoe_params {
+	struct rte_table_action_ether_hdr ether; /**< Ethernet header. */
+	struct rte_table_action_pppoe_hdr pppoe; /**< PPPoE/PPP headers. */
+};
+
+/** Encap action configuration (per table action profile). */
+struct rte_table_action_encap_config {
+	/** Bit mask defining the set of packet encapsulations enabled for the
+	 * current table action profile. If bit (1 << N) is set in *encap_mask*,
+	 * then packet encapsulation N is enabled, otherwise it is disabled.
+	 *
+	 * @see enum rte_table_action_encap_type
+	 */
+	uint64_t encap_mask;
+};
+
+/** Encap action parameters (per table rule). */
+struct rte_table_action_encap_params {
+	/** Encapsulation type. */
+	enum rte_table_action_encap_type type;
+
+	RTE_STD_C11
+	union {
+		/** Only valid when *type* is set to Ether. */
+		struct rte_table_action_encap_ether_params ether;
+
+		/** Only valid when *type* is set to VLAN. */
+		struct rte_table_action_encap_vlan_params vlan;
+
+		/** Only valid when *type* is set to QinQ. */
+		struct rte_table_action_encap_qinq_params qinq;
+
+		/** Only valid when *type* is set to MPLS. */
+		struct rte_table_action_encap_mpls_params mpls;
+
+		/** Only valid when *type* is set to PPPoE. */
+		struct rte_table_action_encap_pppoe_params pppoe;
+	};
+};
+
+/**
  * Table action profile.
  */
 struct rte_table_action_profile;
-- 
2.9.3

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

* [dpdk-dev] [PATCH 06/37] pipeline: add nat action
  2018-03-09 18:23 [dpdk-dev] [PATCH 00/37] ip_pipeline: refactoring Jasvinder Singh
                   ` (4 preceding siblings ...)
  2018-03-09 18:23 ` [dpdk-dev] [PATCH 05/37] pipeline: add packet encapsulation action Jasvinder Singh
@ 2018-03-09 18:23 ` Jasvinder Singh
  2018-03-09 18:23 ` [dpdk-dev] [PATCH 07/37] pipeline: add ttl update action Jasvinder Singh
                   ` (30 subsequent siblings)
  36 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-09 18:23 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add implementation of Network Address Translation(NAT) action.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 lib/librte_pipeline/rte_table_action.c | 162 +++++++++++++++++++++++++++++++++
 lib/librte_pipeline/rte_table_action.h |  39 ++++++++
 2 files changed, 201 insertions(+)

diff --git a/lib/librte_pipeline/rte_table_action.c b/lib/librte_pipeline/rte_table_action.c
index a3c1546..fccf577 100644
--- a/lib/librte_pipeline/rte_table_action.c
+++ b/lib/librte_pipeline/rte_table_action.c
@@ -731,6 +731,115 @@ pkt_work_encap(struct rte_mbuf *mbuf,
 }
 
 /**
+ * RTE_TABLE_ACTION_NAT
+ */
+static int
+nat_cfg_check(struct rte_table_action_nat_config *nat)
+{
+	if ((nat->proto != 0x06) &&
+		(nat->proto != 0x11))
+		return -ENOTSUP;
+
+	return 0;
+}
+
+struct nat_ipv4_data {
+	uint32_t addr;
+	uint16_t port;
+	uint16_t checksum;
+} __attribute__((__packed__));
+
+struct nat_ipv6_data {
+	uint8_t addr[16];
+	uint16_t port;
+	uint16_t checksum;
+} __attribute__((__packed__));
+
+static size_t
+nat_data_size(struct rte_table_action_nat_config *nat __rte_unused,
+	struct rte_table_action_common_config *common)
+{
+	int ip_version = common->ip_version;
+
+	return (ip_version) ?
+		sizeof(struct nat_ipv4_data) :
+		sizeof(struct nat_ipv6_data);
+}
+
+static int
+nat_apply_check(struct rte_table_action_nat_params *p,
+	struct rte_table_action_common_config *cfg)
+{
+	if ((p->ip_version && (cfg->ip_version == 0)) ||
+		((p->ip_version == 0) && cfg->ip_version))
+		return -EINVAL;
+
+	return 0;
+}
+
+static int
+nat_apply(void *data,
+	struct rte_table_action_nat_params *p,
+	struct rte_table_action_common_config *cfg)
+{
+	int status;
+
+	/* Check input arguments */
+	status = nat_apply_check(p, cfg);
+	if (status)
+		return status;
+
+	/* Apply */
+	if (p->ip_version) {
+		struct nat_ipv4_data *d = data;
+
+		d->addr = rte_htonl(p->addr.ipv4);
+		d->port = rte_htons(p->port);
+		d->checksum = 0;
+	} else {
+		struct nat_ipv6_data *d = data;
+
+		memcpy(d->addr, p->addr.ipv6, sizeof(d->addr));
+		d->port = rte_htons(p->port);
+		d->checksum = 0;
+	}
+
+	return 0;
+}
+
+static __rte_always_inline void
+pkt_ipv4_work_nat(struct ipv4_hdr *ip,
+	struct nat_ipv4_data *data,
+	struct rte_table_action_nat_config *cfg)
+{
+	struct tcp_hdr *tcp = (struct tcp_hdr *) &ip[1];
+
+	if (cfg->source_nat) {
+		ip->src_addr = data->addr;
+		tcp->src_port = data->port;
+	} else {
+		ip->dst_addr = data->addr;
+		tcp->dst_port = data->port;
+	}
+}
+
+static __rte_always_inline void
+pkt_ipv6_work_nat(struct ipv6_hdr *ip,
+	struct nat_ipv6_data *data,
+	struct rte_table_action_nat_config *cfg)
+{
+	struct tcp_hdr *tcp = (struct tcp_hdr *) &ip[1];
+
+	if (cfg->source_nat) {
+		rte_memcpy(ip->src_addr, data->addr, 16);
+		tcp->src_port = data->port;
+	} else {
+		rte_memcpy(ip->dst_addr, data->addr, 16);
+		tcp->dst_port = data->port;
+	}
+}
+
+/**
  * Action profile
  */
 static int
@@ -741,6 +850,7 @@ action_valid(enum rte_table_action_type action)
 	case RTE_TABLE_ACTION_MTR:
 	case RTE_TABLE_ACTION_TM:
 	case RTE_TABLE_ACTION_ENCAP:
+	case RTE_TABLE_ACTION_NAT:
 		return 1;
 	default:
 		return 0;
@@ -756,6 +866,7 @@ struct ap_config {
 	struct rte_table_action_mtr_config mtr;
 	struct rte_table_action_tm_config tm;
 	struct rte_table_action_encap_config encap;
+	struct rte_table_action_nat_config nat;
 };
 
 static size_t
@@ -768,6 +879,8 @@ action_cfg_size(enum rte_table_action_type action)
 		return sizeof(struct rte_table_action_tm_config);
 	case RTE_TABLE_ACTION_ENCAP:
 		return sizeof(struct rte_table_action_encap_config);
+	case RTE_TABLE_ACTION_NAT:
+		return sizeof(struct rte_table_action_nat_config);
 	default:
 		return 0;
 	}
@@ -787,6 +900,9 @@ action_cfg_get(struct ap_config *ap_config,
 	case RTE_TABLE_ACTION_ENCAP:
 		return &ap_config->encap;
 
+	case RTE_TABLE_ACTION_NAT:
+		return &ap_config->nat;
+
 	default:
 		return NULL;
 	}
@@ -827,6 +943,10 @@ action_data_size(enum rte_table_action_type action,
 	case RTE_TABLE_ACTION_ENCAP:
 		return encap_data_size(&ap_config->encap);
 
+	case RTE_TABLE_ACTION_NAT:
+		return nat_data_size(&ap_config->nat,
+			&ap_config->common);
+
 	default:
 		return 0;
 	}
@@ -909,6 +1029,10 @@ rte_table_action_profile_action_register(struct rte_table_action_profile *profil
 		status = encap_cfg_check(action_config);
 		break;
 
+	case RTE_TABLE_ACTION_NAT:
+		status = nat_cfg_check(action_config);
+		break;
+
 	default:
 		status = 0;
 		break;
@@ -1037,6 +1161,11 @@ rte_table_action_apply(struct rte_table_action *action,
 			&action->cfg.encap,
 			&action->cfg.common);
 
+	case RTE_TABLE_ACTION_NAT:
+		return nat_apply(action_data,
+			action_params,
+			&action->cfg.common);
+
 	default:
 		return -EINVAL;
 	}
@@ -1266,6 +1395,16 @@ pkt_work(struct rte_mbuf *mbuf,
 			ip_offset);
 	}
 
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_NAT)) {
+		void *data =
+			action_data_get(table_entry, action, RTE_TABLE_ACTION_NAT);
+
+		if (cfg->common.ip_version)
+			pkt_ipv4_work_nat(ip, data, &cfg->nat);
+		else
+			pkt_ipv6_work_nat(ip, data, &cfg->nat);
+	}
+
 	return drop_mask;
 }
 
@@ -1449,6 +1588,29 @@ pkt4_work(struct rte_mbuf **mbufs,
 			ip_offset);
 	}
 
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_NAT)) {
+		void *data0 =
+			action_data_get(table_entry0, action, RTE_TABLE_ACTION_NAT);
+		void *data1 =
+			action_data_get(table_entry1, action, RTE_TABLE_ACTION_NAT);
+		void *data2 =
+			action_data_get(table_entry2, action, RTE_TABLE_ACTION_NAT);
+		void *data3 =
+			action_data_get(table_entry3, action, RTE_TABLE_ACTION_NAT);
+
+		if (cfg->common.ip_version) {
+			pkt_ipv4_work_nat(ip0, data0, &cfg->nat);
+			pkt_ipv4_work_nat(ip1, data1, &cfg->nat);
+			pkt_ipv4_work_nat(ip2, data2, &cfg->nat);
+			pkt_ipv4_work_nat(ip3, data3, &cfg->nat);
+		} else {
+			pkt_ipv6_work_nat(ip0, data0, &cfg->nat);
+			pkt_ipv6_work_nat(ip1, data1, &cfg->nat);
+			pkt_ipv6_work_nat(ip2, data2, &cfg->nat);
+			pkt_ipv6_work_nat(ip3, data3, &cfg->nat);
+		}
+	}
+
 	return drop_mask0 |
 		(drop_mask1 << 1) |
 		(drop_mask2 << 2) |
diff --git a/lib/librte_pipeline/rte_table_action.h b/lib/librte_pipeline/rte_table_action.h
index c5c987d..5204511 100644
--- a/lib/librte_pipeline/rte_table_action.h
+++ b/lib/librte_pipeline/rte_table_action.h
@@ -77,6 +77,9 @@ enum rte_table_action_type {
 
 	/** Packet encapsulations. */
 	RTE_TABLE_ACTION_ENCAP,
+
+	/** Network Address Translation (NAT). */
+	RTE_TABLE_ACTION_NAT,
 };
 
 /** Common action configuration (per table action profile). */
@@ -409,6 +412,42 @@ struct rte_table_action_encap_params {
 };
 
 /**
+ * RTE_TABLE_ACTION_NAT
+ */
+/** NAT action configuration (per table action profile). */
+struct rte_table_action_nat_config {
+	/** When non-zero, the IP source address and L4 protocol source port are
+	 * translated. When zero, the IP destination address and L4 protocol
+	 * destination port are translated.
+	 */
+	int source_nat;
+
+	/** Layer 4 protocol, for example TCP (0x06) or UDP (0x11). The checksum
+	 * field is computed differently and placed at different header offset
+	 * by each layer 4 protocol.
+	 */
+	uint8_t proto;
+};
+
+/** NAT action parameters (per table rule). */
+struct rte_table_action_nat_params {
+	/** IP version for *addr*: non-zero for IPv4, zero for IPv6. */
+	int ip_version;
+
+	/** IP address. */
+	union {
+		/** IPv4 address; only valid when *ip_version* is non-zero. */
+		uint32_t ipv4;
+
+		/** IPv6 address; only valid when *ip_version* is set to 0. */
+		uint8_t ipv6[16];
+	} addr;
+
+	/** Port. */
+	uint16_t port;
+};
+
+/**
  * Table action profile.
  */
 struct rte_table_action_profile;
-- 
2.9.3

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

* [dpdk-dev] [PATCH 07/37] pipeline: add ttl update action
  2018-03-09 18:23 [dpdk-dev] [PATCH 00/37] ip_pipeline: refactoring Jasvinder Singh
                   ` (5 preceding siblings ...)
  2018-03-09 18:23 ` [dpdk-dev] [PATCH 06/37] pipeline: add nat action Jasvinder Singh
@ 2018-03-09 18:23 ` Jasvinder Singh
  2018-03-09 18:23 ` [dpdk-dev] [PATCH 08/37] pipeline: add statistics read action Jasvinder Singh
                   ` (29 subsequent siblings)
  36 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-09 18:23 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add implementation of ttl update action.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 lib/librte_pipeline/rte_pipeline_version.map |   1 +
 lib/librte_pipeline/rte_table_action.c       | 155 +++++++++++++++++++++++++++
 lib/librte_pipeline/rte_table_action.h       |  66 ++++++++++++
 3 files changed, 222 insertions(+)

diff --git a/lib/librte_pipeline/rte_pipeline_version.map b/lib/librte_pipeline/rte_pipeline_version.map
index c7106dc..9388585 100644
--- a/lib/librte_pipeline/rte_pipeline_version.map
+++ b/lib/librte_pipeline/rte_pipeline_version.map
@@ -61,5 +61,6 @@ EXPERIMENTAL {
 	rte_table_action_profile_free;
 	rte_table_action_profile_freeze;
 	rte_table_action_table_params_get;
+	rte_table_action_ttl_read;
 
 } DPDK_16.04;
diff --git a/lib/librte_pipeline/rte_table_action.c b/lib/librte_pipeline/rte_table_action.c
index fccf577..157af49 100644
--- a/lib/librte_pipeline/rte_table_action.c
+++ b/lib/librte_pipeline/rte_table_action.c
@@ -840,6 +840,82 @@ pkt_ipv6_work_nat(struct ipv6_hdr *ip,
 }
 
 /**
+ * RTE_TABLE_ACTION_TTL
+ */
+static int
+ttl_cfg_check(struct rte_table_action_ttl_config *ttl)
+{
+	if (ttl->drop == 0)
+		return -ENOTSUP;
+
+	return 0;
+}
+
+struct ttl_data {
+	uint32_t n_packets;
+} __attribute__((__packed__));
+
+#define TTL_INIT(data, decrement)                         \
+	((data)->n_packets = (decrement) ? 1 : 0)
+
+#define TTL_DEC_GET(data)                                  \
+	((uint8_t)((data)->n_packets & 1))
+
+#define TTL_STATS_RESET(data)                             \
+	((data)->n_packets = ((data)->n_packets & 1))
+
+#define TTL_STATS_READ(data)                               \
+	((data)->n_packets >> 1)
+
+#define TTL_STATS_ADD(data, value)                        \
+	((data)->n_packets =                                  \
+		(((((data)->n_packets >> 1) + (value)) << 1) |    \
+		((data)->n_packets & 1)))
+
+static int
+ttl_apply(void *data,
+	struct rte_table_action_ttl_params *p)
+{
+	struct ttl_data *d = data;
+
+	TTL_INIT(d, p->decrement);
+
+	return 0;
+}
+
+static __rte_always_inline uint64_t
+pkt_ipv4_work_ttl(struct ipv4_hdr *ip,
+	struct ttl_data *data)
+{
+	uint32_t drop;
+	uint8_t ttl = ip->time_to_live;
+
+	ttl -= TTL_DEC_GET(data);
+	ip->time_to_live = ttl;
+
+	drop = (ttl == 0) ? 1 : 0;
+	TTL_STATS_ADD(data, drop);
+
+	return drop;
+}
+
+static __rte_always_inline uint64_t
+pkt_ipv6_work_ttl(struct ipv6_hdr *ip,
+	struct ttl_data *data)
+{
+	uint32_t drop;
+	uint8_t ttl = ip->hop_limits;
+
+	ttl -= TTL_DEC_GET(data);
+	ip->hop_limits = ttl;
+
+	drop = (ttl == 0) ? 1 : 0;
+	TTL_STATS_ADD(data, drop);
+
+	return drop;
+}
+
+/**
  * Action profile
  */
 static int
@@ -851,6 +927,7 @@ action_valid(enum rte_table_action_type action)
 	case RTE_TABLE_ACTION_TM:
 	case RTE_TABLE_ACTION_ENCAP:
 	case RTE_TABLE_ACTION_NAT:
+	case RTE_TABLE_ACTION_TTL:
 		return 1;
 	default:
 		return 0;
@@ -867,6 +944,7 @@ struct ap_config {
 	struct rte_table_action_tm_config tm;
 	struct rte_table_action_encap_config encap;
 	struct rte_table_action_nat_config nat;
+	struct rte_table_action_ttl_config ttl;
 };
 
 static size_t
@@ -881,6 +959,8 @@ action_cfg_size(enum rte_table_action_type action)
 		return sizeof(struct rte_table_action_encap_config);
 	case RTE_TABLE_ACTION_NAT:
 		return sizeof(struct rte_table_action_nat_config);
+	case RTE_TABLE_ACTION_TTL:
+		return sizeof(struct rte_table_action_ttl_config);
 	default:
 		return 0;
 	}
@@ -903,6 +983,9 @@ action_cfg_get(struct ap_config *ap_config,
 	case RTE_TABLE_ACTION_NAT:
 		return &ap_config->nat;
 
+	case RTE_TABLE_ACTION_TTL:
+		return &ap_config->ttl;
+
 	default:
 		return NULL;
 	}
@@ -947,6 +1030,9 @@ action_data_size(enum rte_table_action_type action,
 		return nat_data_size(&ap_config->nat,
 			&ap_config->common);
 
+	case RTE_TABLE_ACTION_TTL:
+		return sizeof(struct ttl_data);
+
 	default:
 		return 0;
 	}
@@ -1033,6 +1119,10 @@ rte_table_action_profile_action_register(struct rte_table_action_profile *profil
 		status = nat_cfg_check(action_config);
 		break;
 
+	case RTE_TABLE_ACTION_TTL:
+		status = ttl_cfg_check(action_config);
+		break;
+
 	default:
 		status = 0;
 		break;
@@ -1166,6 +1256,10 @@ rte_table_action_apply(struct rte_table_action *action,
 			action_params,
 			&action->cfg.common);
 
+	case RTE_TABLE_ACTION_TTL:
+		return ttl_apply(action_data,
+			action_params);
+
 	default:
 		return -EINVAL;
 	}
@@ -1332,6 +1426,34 @@ rte_table_action_meter_read(struct rte_table_action *action,
 	return 0;
 }
 
+int
+rte_table_action_ttl_read(struct rte_table_action *action,
+	void *data,
+	struct rte_table_action_ttl_counters *stats,
+	int clear)
+{
+	struct ttl_data *ttl_data;
+
+	/* Check input arguments */
+	if ((action == NULL) ||
+		((action->cfg.action_mask &
+		(1LLU << RTE_TABLE_ACTION_TTL)) == 0) ||
+		(data == NULL))
+		return -EINVAL;
+
+	ttl_data = action_data_get(data, action, RTE_TABLE_ACTION_TTL);
+
+	/* Read */
+	if (stats)
+		stats->n_packets = TTL_STATS_READ(ttl_data);
+
+	/* Clear */
+	if (clear)
+		TTL_STATS_RESET(ttl_data);
+
+	return 0;
+}
+
 static __rte_always_inline uint64_t
 pkt_work(struct rte_mbuf *mbuf,
 	struct rte_pipeline_table_entry *table_entry,
@@ -1405,6 +1527,16 @@ pkt_work(struct rte_mbuf *mbuf,
 			pkt_ipv6_work_nat(ip, data, &cfg->nat);
 	}
 
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_TTL)) {
+		void *data =
+			action_data_get(table_entry, action, RTE_TABLE_ACTION_TTL);
+
+		if (cfg->common.ip_version)
+			drop_mask |= pkt_ipv4_work_ttl(ip, data);
+		else
+			drop_mask |= pkt_ipv6_work_ttl(ip, data);
+	}
+
 	return drop_mask;
 }
 
@@ -1611,6 +1743,29 @@ pkt4_work(struct rte_mbuf **mbufs,
 		}
 	}
 
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_TTL)) {
+		void *data0 =
+				action_data_get(table_entry0, action, RTE_TABLE_ACTION_TTL);
+		void *data1 =
+				action_data_get(table_entry1, action, RTE_TABLE_ACTION_TTL);
+		void *data2 =
+				action_data_get(table_entry2, action, RTE_TABLE_ACTION_TTL);
+		void *data3 =
+				action_data_get(table_entry3, action, RTE_TABLE_ACTION_TTL);
+
+		if (cfg->common.ip_version) {
+			drop_mask0 |= pkt_ipv4_work_ttl(ip0, data0);
+			drop_mask1 |= pkt_ipv4_work_ttl(ip1, data1);
+			drop_mask2 |= pkt_ipv4_work_ttl(ip2, data2);
+			drop_mask3 |= pkt_ipv4_work_ttl(ip3, data3);
+		} else {
+			drop_mask0 |= pkt_ipv6_work_ttl(ip0, data0);
+			drop_mask1 |= pkt_ipv6_work_ttl(ip1, data1);
+			drop_mask2 |= pkt_ipv6_work_ttl(ip2, data2);
+			drop_mask3 |= pkt_ipv6_work_ttl(ip3, data3);
+		}
+	}
+
 	return drop_mask0 |
 		(drop_mask1 << 1) |
 		(drop_mask2 << 2) |
diff --git a/lib/librte_pipeline/rte_table_action.h b/lib/librte_pipeline/rte_table_action.h
index 5204511..57ac4f9 100644
--- a/lib/librte_pipeline/rte_table_action.h
+++ b/lib/librte_pipeline/rte_table_action.h
@@ -80,6 +80,9 @@ enum rte_table_action_type {
 
 	/** Network Address Translation (NAT). */
 	RTE_TABLE_ACTION_NAT,
+
+	/** Time to Live (TTL) update. */
+	RTE_TABLE_ACTION_TTL,
 };
 
 /** Common action configuration (per table action profile). */
@@ -448,6 +451,44 @@ struct rte_table_action_nat_params {
 };
 
 /**
+ * RTE_TABLE_ACTION_TTL
+ */
+/** TTL action configuration (per table action profile). */
+struct rte_table_action_ttl_config {
+	/** When non-zero, the input packets whose updated IPv4 Time to Live
+	 * (TTL) field or IPv6 Hop Limit (HL) field is zero are dropped.
+	 * When zero, the input packets whose updated IPv4 TTL field or IPv6 HL
+	 * field is zero are forwarded as usual (typically for debugging
+	 * purpose).
+	 */
+	int drop;
+
+	/** When non-zero, the *n_packets* stats counter for TTL action is
+	 * enabled, otherwise disabled.
+	 *
+	 * @see struct rte_table_action_ttl_counters
+	 */
+	int n_packets_enabled;
+};
+
+/** TTL action parameters (per table rule). */
+struct rte_table_action_ttl_params {
+	/** When non-zero, decrement the IPv4 TTL field and update the checksum
+	 * field, or decrement the IPv6 HL field. When zero, the IPv4 TTL field
+	 * or the IPv6 HL field is not changed.
+	 */
+	int decrement;
+};
+
+/** TTL action statistics packets (per table rule). */
+struct rte_table_action_ttl_counters {
+	/** Number of IPv4 packets whose updated TTL field is zero or IPv6
+	 * packets whose updated HL field is zero.
+	 */
+	uint64_t n_packets;
+};
+
+/**
  * Table action profile.
  */
 struct rte_table_action_profile;
@@ -671,6 +712,31 @@ rte_table_action_meter_read(struct rte_table_action *action,
 	struct rte_table_action_mtr_counters *stats,
 	int clear);
 
+/**
+ * Table action TTL read.
+ *
+ * @param[in] action
+ *   Handle to table action object (needs to be valid).
+ * @param[in] data
+ *   Data byte array (typically table rule data) with TTL action previously
+ *   applied on it.
+ * @param[inout] stats
+ *   When non-NULL, it points to the area where the TTL stats counters read from
+ *   *data* are saved.
+ * @param[in] clear
+ *   When non-zero, the TTL stats counters are cleared (i.e. set to zero),
+ *   otherwise the counters are not modified. When the read operation is enabled
+ *   (*stats* is non-NULL), the clear operation is performed after the read
+ *   operation is completed.
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_table_action_ttl_read(struct rte_table_action *action,
+	void *data,
+	struct rte_table_action_ttl_counters *stats,
+	int clear);
+
 #ifdef __cplusplus
 }
 #endif
-- 
2.9.3

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

* [dpdk-dev] [PATCH 08/37] pipeline: add statistics read action
  2018-03-09 18:23 [dpdk-dev] [PATCH 00/37] ip_pipeline: refactoring Jasvinder Singh
                   ` (6 preceding siblings ...)
  2018-03-09 18:23 ` [dpdk-dev] [PATCH 07/37] pipeline: add ttl update action Jasvinder Singh
@ 2018-03-09 18:23 ` Jasvinder Singh
  2018-03-09 18:23 ` [dpdk-dev] [PATCH 09/37] pipeline: add timestamp action Jasvinder Singh
                   ` (28 subsequent siblings)
  36 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-09 18:23 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add implementation of stats read action

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 lib/librte_pipeline/rte_pipeline_version.map |   1 +
 lib/librte_pipeline/rte_table_action.c       | 112 ++++++++++++++++++++++++++-
 lib/librte_pipeline/rte_table_action.h       |  78 +++++++++++++++++++
 3 files changed, 190 insertions(+), 1 deletion(-)

diff --git a/lib/librte_pipeline/rte_pipeline_version.map b/lib/librte_pipeline/rte_pipeline_version.map
index 9388585..8241efc 100644
--- a/lib/librte_pipeline/rte_pipeline_version.map
+++ b/lib/librte_pipeline/rte_pipeline_version.map
@@ -61,6 +61,7 @@ EXPERIMENTAL {
 	rte_table_action_profile_free;
 	rte_table_action_profile_freeze;
 	rte_table_action_table_params_get;
+	rte_table_action_stats_read;
 	rte_table_action_ttl_read;
 
 } DPDK_16.04;
diff --git a/lib/librte_pipeline/rte_table_action.c b/lib/librte_pipeline/rte_table_action.c
index 157af49..06d54df 100644
--- a/lib/librte_pipeline/rte_table_action.c
+++ b/lib/librte_pipeline/rte_table_action.c
@@ -916,6 +916,41 @@ pkt_ipv6_work_ttl(struct ipv6_hdr *ip,
 }
 
 /**
+ * RTE_TABLE_ACTION_STATS
+ */
+static int
+stats_cfg_check(struct rte_table_action_stats_config *stats)
+{
+	if ((stats->n_packets_enabled == 0) && (stats->n_bytes_enabled == 0))
+		return -EINVAL;
+
+	return 0;
+}
+
+struct stats_data {
+	uint64_t n_packets;
+	uint64_t n_bytes;
+} __attribute__((__packed__));
+
+static int
+stats_apply(struct stats_data *data,
+	struct rte_table_action_stats_params *p)
+{
+	data->n_packets = p->n_packets;
+	data->n_bytes = p->n_bytes;
+
+	return 0;
+}
+
+static __rte_always_inline void
+pkt_work_stats(struct stats_data *data,
+	uint16_t total_length)
+{
+	data->n_packets++;
+	data->n_bytes += total_length;
+}
+
+/**
  * Action profile
  */
 static int
@@ -928,13 +963,13 @@ action_valid(enum rte_table_action_type action)
 	case RTE_TABLE_ACTION_ENCAP:
 	case RTE_TABLE_ACTION_NAT:
 	case RTE_TABLE_ACTION_TTL:
+	case RTE_TABLE_ACTION_STATS:
 		return 1;
 	default:
 		return 0;
 	}
 }
 
-
 #define RTE_TABLE_ACTION_MAX                                   64
 
 struct ap_config {
@@ -945,6 +980,7 @@ struct ap_config {
 	struct rte_table_action_encap_config encap;
 	struct rte_table_action_nat_config nat;
 	struct rte_table_action_ttl_config ttl;
+	struct rte_table_action_stats_config stats;
 };
 
 static size_t
@@ -961,6 +997,8 @@ action_cfg_size(enum rte_table_action_type action)
 		return sizeof(struct rte_table_action_nat_config);
 	case RTE_TABLE_ACTION_TTL:
 		return sizeof(struct rte_table_action_ttl_config);
+	case RTE_TABLE_ACTION_STATS:
+		return sizeof(struct rte_table_action_stats_config);
 	default:
 		return 0;
 	}
@@ -986,6 +1024,9 @@ action_cfg_get(struct ap_config *ap_config,
 	case RTE_TABLE_ACTION_TTL:
 		return &ap_config->ttl;
 
+	case RTE_TABLE_ACTION_STATS:
+		return &ap_config->stats;
+
 	default:
 		return NULL;
 	}
@@ -1033,6 +1074,9 @@ action_data_size(enum rte_table_action_type action,
 	case RTE_TABLE_ACTION_TTL:
 		return sizeof(struct ttl_data);
 
+	case RTE_TABLE_ACTION_STATS:
+		return sizeof(struct stats_data);
+
 	default:
 		return 0;
 	}
@@ -1123,6 +1167,10 @@ rte_table_action_profile_action_register(struct rte_table_action_profile *profil
 		status = ttl_cfg_check(action_config);
 		break;
 
+	case RTE_TABLE_ACTION_STATS:
+		status = stats_cfg_check(action_config);
+		break;
+
 	default:
 		status = 0;
 		break;
@@ -1260,6 +1308,10 @@ rte_table_action_apply(struct rte_table_action *action,
 		return ttl_apply(action_data,
 			action_params);
 
+	case RTE_TABLE_ACTION_STATS:
+		return stats_apply(action_data,
+			action_params);
+
 	default:
 		return -EINVAL;
 	}
@@ -1454,6 +1506,41 @@ rte_table_action_ttl_read(struct rte_table_action *action,
 	return 0;
 }
 
+int
+rte_table_action_stats_read(struct rte_table_action *action,
+	void *data,
+	struct rte_table_action_stats_counters *stats,
+	int clear)
+{
+	struct stats_data *stats_data;
+
+	/* Check input arguments */
+	if ((action == NULL) ||
+		((action->cfg.action_mask &
+		(1LLU << RTE_TABLE_ACTION_STATS)) == 0) ||
+		(data == NULL))
+		return -EINVAL;
+
+	stats_data = action_data_get(data, action,
+		RTE_TABLE_ACTION_STATS);
+
+	/* Read */
+	if (stats) {
+		stats->n_packets = stats_data->n_packets;
+		stats->n_bytes = stats_data->n_bytes;
+		stats->n_packets_valid = 1;
+		stats->n_bytes_valid = 1;
+	}
+
+	/* Clear */
+	if (clear) {
+		stats_data->n_packets = 0;
+		stats_data->n_bytes = 0;
+	}
+
+	return 0;
+}
+
 static __rte_always_inline uint64_t
 pkt_work(struct rte_mbuf *mbuf,
 	struct rte_pipeline_table_entry *table_entry,
@@ -1537,6 +1624,13 @@ pkt_work(struct rte_mbuf *mbuf,
 			drop_mask |= pkt_ipv6_work_ttl(ip, data);
 	}
 
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_STATS)) {
+		void *data =
+			action_data_get(table_entry, action, RTE_TABLE_ACTION_STATS);
+
+		pkt_work_stats(data, total_length);
+	}
+
 	return drop_mask;
 }
 
@@ -1766,6 +1860,22 @@ pkt4_work(struct rte_mbuf **mbufs,
 		}
 	}
 
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_STATS)) {
+		void *data0 =
+			action_data_get(table_entry0, action, RTE_TABLE_ACTION_STATS);
+		void *data1 =
+			action_data_get(table_entry1, action, RTE_TABLE_ACTION_STATS);
+		void *data2 =
+			action_data_get(table_entry2, action, RTE_TABLE_ACTION_STATS);
+		void *data3 =
+			action_data_get(table_entry3, action, RTE_TABLE_ACTION_STATS);
+
+		pkt_work_stats(data0, total_length0);
+		pkt_work_stats(data1, total_length1);
+		pkt_work_stats(data2, total_length2);
+		pkt_work_stats(data3, total_length3);
+	}
+
 	return drop_mask0 |
 		(drop_mask1 << 1) |
 		(drop_mask2 << 2) |
diff --git a/lib/librte_pipeline/rte_table_action.h b/lib/librte_pipeline/rte_table_action.h
index 57ac4f9..53b9866 100644
--- a/lib/librte_pipeline/rte_table_action.h
+++ b/lib/librte_pipeline/rte_table_action.h
@@ -83,6 +83,9 @@ enum rte_table_action_type {
 
 	/** Time to Live (TTL) update. */
 	RTE_TABLE_ACTION_TTL,
+
+	/** Statistics. */
+	RTE_TABLE_ACTION_STATS,
 };
 
 /** Common action configuration (per table action profile). */
@@ -489,6 +492,56 @@ struct rte_table_action_ttl_counters {
 };
 
 /**
+ * RTE_TABLE_ACTION_STATS
+ */
+/** Stats action configuration (per table action profile). */
+struct rte_table_action_stats_config {
+	/** When non-zero, the *n_packets* stats counter is enabled, otherwise
+	 * disabled.
+	 *
+	 * @see struct rte_table_action_stats_counters
+	 */
+	int n_packets_enabled;
+
+	/** When non-zero, the *n_bytes* stats counter is enabled, otherwise
+	 * disabled.
+	 *
+	 * @see struct rte_table_action_stats_counters
+	 */
+	int n_bytes_enabled;
+};
+
+/** Stats action parameters (per table rule). */
+struct rte_table_action_stats_params {
+	/** Initial value for the *n_packets* stats counter. Typically set to 0.
+	 *
+	 * @see struct rte_table_action_stats_counters
+	 */
+	uint64_t n_packets;
+
+	/** Initial value for the *n_bytes* stats counter. Typically set to 0.
+	 *
+	 * @see struct rte_table_action_stats_counters
+	 */
+	uint64_t n_bytes;
+};
+
+/** Stats action counters (per table rule). */
+struct rte_table_action_stats_counters {
+	/** Number of packets. Valid only when *n_packets_valid* is non-zero. */
+	uint64_t n_packets;
+
+	/** Number of bytes. Valid only when *n_bytes_valid* is non-zero. */
+	uint64_t n_bytes;
+
+	/** When non-zero, the *n_packets* field is valid, otherwise invalid. */
+	int n_packets_valid;
+
+	/** When non-zero, the *n_bytes* field is valid, otherwise invalid. */
+	int n_bytes_valid;
+};
+
+/**
  * Table action profile.
  */
 struct rte_table_action_profile;
@@ -737,6 +790,31 @@ rte_table_action_ttl_read(struct rte_table_action *action,
 	struct rte_table_action_ttl_counters *stats,
 	int clear);
 
+/**
+ * Table action stats read.
+ *
+ * @param[in] action
+ *   Handle to table action object (needs to be valid).
+ * @param[in] data
+ *   Data byte array (typically table rule data) with stats action previously
+ *   applied on it.
+ * @param[inout] stats
+ *   When non-NULL, it points to the area where the stats counters read from
+ *   *data* are saved.
+ * @param[in] clear
+ *   When non-zero, the stats counters are cleared (i.e. set to zero), otherwise
+ *   the counters are not modified. When the read operation is enabled (*stats*
+ *   is non-NULL), the clear operation is performed after the read operation is
+ *   completed.
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_table_action_stats_read(struct rte_table_action *action,
+	void *data,
+	struct rte_table_action_stats_counters *stats,
+	int clear);
+
 #ifdef __cplusplus
 }
 #endif
-- 
2.9.3

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

* [dpdk-dev] [PATCH 09/37] pipeline: add timestamp action
  2018-03-09 18:23 [dpdk-dev] [PATCH 00/37] ip_pipeline: refactoring Jasvinder Singh
                   ` (7 preceding siblings ...)
  2018-03-09 18:23 ` [dpdk-dev] [PATCH 08/37] pipeline: add statistics read action Jasvinder Singh
@ 2018-03-09 18:23 ` Jasvinder Singh
  2018-03-09 18:23 ` [dpdk-dev] [PATCH 10/37] ip_pipeline: rework and improvements Jasvinder Singh
                   ` (27 subsequent siblings)
  36 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-09 18:23 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add implementation of timestamp action.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 lib/librte_pipeline/rte_pipeline_version.map |  1 +
 lib/librte_pipeline/rte_table_action.c       | 79 +++++++++++++++++++++++++++-
 lib/librte_pipeline/rte_table_action.h       | 31 +++++++++++
 3 files changed, 110 insertions(+), 1 deletion(-)

diff --git a/lib/librte_pipeline/rte_pipeline_version.map b/lib/librte_pipeline/rte_pipeline_version.map
index 8241efc..4e948b8 100644
--- a/lib/librte_pipeline/rte_pipeline_version.map
+++ b/lib/librte_pipeline/rte_pipeline_version.map
@@ -62,6 +62,7 @@ EXPERIMENTAL {
 	rte_table_action_profile_freeze;
 	rte_table_action_table_params_get;
 	rte_table_action_stats_read;
+	rte_table_action_time_read;
 	rte_table_action_ttl_read;
 
 } DPDK_16.04;
diff --git a/lib/librte_pipeline/rte_table_action.c b/lib/librte_pipeline/rte_table_action.c
index 06d54df..b4b2325 100644
--- a/lib/librte_pipeline/rte_table_action.c
+++ b/lib/librte_pipeline/rte_table_action.c
@@ -951,6 +951,28 @@ pkt_work_stats(struct stats_data *data,
 }
 
 /**
+ * RTE_TABLE_ACTION_TIME
+ */
+struct time_data {
+	uint64_t time;
+} __attribute__((__packed__));
+
+static int
+time_apply(struct time_data *data,
+	struct rte_table_action_time_params *p)
+{
+	data->time = p->time;
+	return 0;
+}
+
+static __rte_always_inline void
+pkt_work_time(struct time_data *data,
+	uint64_t time)
+{
+	data->time = time;
+}
+
+/**
  * Action profile
  */
 static int
@@ -964,6 +986,7 @@ action_valid(enum rte_table_action_type action)
 	case RTE_TABLE_ACTION_NAT:
 	case RTE_TABLE_ACTION_TTL:
 	case RTE_TABLE_ACTION_STATS:
+	case RTE_TABLE_ACTION_TIME:
 		return 1;
 	default:
 		return 0;
@@ -1077,6 +1100,9 @@ action_data_size(enum rte_table_action_type action,
 	case RTE_TABLE_ACTION_STATS:
 		return sizeof(struct stats_data);
 
+	case RTE_TABLE_ACTION_TIME:
+		return sizeof(struct time_data);
+
 	default:
 		return 0;
 	}
@@ -1312,6 +1338,10 @@ rte_table_action_apply(struct rte_table_action *action,
 		return stats_apply(action_data,
 			action_params);
 
+	case RTE_TABLE_ACTION_TIME:
+		return time_apply(action_data,
+			action_params);
+
 	default:
 		return -EINVAL;
 	}
@@ -1541,6 +1571,29 @@ rte_table_action_stats_read(struct rte_table_action *action,
 	return 0;
 }
 
+int
+rte_table_action_time_read(struct rte_table_action *action,
+	void *data,
+	uint64_t *timestamp)
+{
+	struct time_data *time_data;
+
+	/* Check input arguments */
+	if ((action == NULL) ||
+		((action->cfg.action_mask &
+		(1LLU << RTE_TABLE_ACTION_TIME)) == 0) ||
+		(data == NULL) ||
+		(timestamp == NULL))
+		return -EINVAL;
+
+	time_data = action_data_get(data, action, RTE_TABLE_ACTION_TIME);
+
+	/* Read */
+	*timestamp = time_data->time;
+
+	return 0;
+}
+
 static __rte_always_inline uint64_t
 pkt_work(struct rte_mbuf *mbuf,
 	struct rte_pipeline_table_entry *table_entry,
@@ -1631,6 +1684,13 @@ pkt_work(struct rte_mbuf *mbuf,
 		pkt_work_stats(data, total_length);
 	}
 
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_TIME)) {
+		void *data =
+			action_data_get(table_entry, action, RTE_TABLE_ACTION_TIME);
+
+		pkt_work_time(data, time);
+	}
+
 	return drop_mask;
 }
 
@@ -1876,6 +1936,22 @@ pkt4_work(struct rte_mbuf **mbufs,
 		pkt_work_stats(data3, total_length3);
 	}
 
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_TIME)) {
+		void *data0 =
+			action_data_get(table_entry0, action, RTE_TABLE_ACTION_TIME);
+		void *data1 =
+			action_data_get(table_entry1, action, RTE_TABLE_ACTION_TIME);
+		void *data2 =
+			action_data_get(table_entry2, action, RTE_TABLE_ACTION_TIME);
+		void *data3 =
+			action_data_get(table_entry3, action, RTE_TABLE_ACTION_TIME);
+
+		pkt_work_time(data0, time);
+		pkt_work_time(data1, time);
+		pkt_work_time(data2, time);
+		pkt_work_time(data3, time);
+	}
+
 	return drop_mask0 |
 		(drop_mask1 << 1) |
 		(drop_mask2 << 2) |
@@ -1893,7 +1969,8 @@ ah(struct rte_pipeline *p,
 	uint64_t pkts_drop_mask = 0;
 	uint64_t time = 0;
 
-	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_MTR))
+	if (cfg->action_mask & ((1LLU << RTE_TABLE_ACTION_MTR) |
+		(1LLU << RTE_TABLE_ACTION_TIME)))
 		time = rte_rdtsc();
 
 	if ((pkts_mask & (pkts_mask + 1)) == 0) {
diff --git a/lib/librte_pipeline/rte_table_action.h b/lib/librte_pipeline/rte_table_action.h
index 53b9866..e9b30ab 100644
--- a/lib/librte_pipeline/rte_table_action.h
+++ b/lib/librte_pipeline/rte_table_action.h
@@ -86,6 +86,9 @@ enum rte_table_action_type {
 
 	/** Statistics. */
 	RTE_TABLE_ACTION_STATS,
+
+	/** Timestamp. */
+	RTE_TABLE_ACTION_TIME,
 };
 
 /** Common action configuration (per table action profile). */
@@ -542,6 +545,15 @@ struct rte_table_action_stats_counters {
 };
 
 /**
+ * RTE_TABLE_ACTION_TIME
+ */
+/** Timestamp action parameters (per table rule). */
+struct rte_table_action_time_params {
+	/** Initial timestamp value. Typically set to current time. */
+	uint64_t time;
+};
+
+/**
  * Table action profile.
  */
 struct rte_table_action_profile;
@@ -815,6 +827,25 @@ rte_table_action_stats_read(struct rte_table_action *action,
 	struct rte_table_action_stats_counters *stats,
 	int clear);
 
+/**
+ * Table action timestamp read.
+ *
+ * @param[in] action
+ *   Handle to table action object (needs to be valid).
+ * @param[in] data
+ *   Data byte array (typically table rule data) with timestamp action
+ *   previously applied on it.
+ * @param[inout] timestamp
+ *   Pre-allocated memory where the timestamp read from *data* is saved (has to
+ *   be non-NULL).
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_table_action_time_read(struct rte_table_action *action,
+	void *data,
+	uint64_t *timestamp);
+
 #ifdef __cplusplus
 }
 #endif
-- 
2.9.3

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

* [dpdk-dev] [PATCH 10/37] ip_pipeline: rework and improvements
  2018-03-09 18:23 [dpdk-dev] [PATCH 00/37] ip_pipeline: refactoring Jasvinder Singh
                   ` (8 preceding siblings ...)
  2018-03-09 18:23 ` [dpdk-dev] [PATCH 09/37] pipeline: add timestamp action Jasvinder Singh
@ 2018-03-09 18:23 ` Jasvinder Singh
  2018-03-09 18:24 ` [dpdk-dev] [PATCH 11/37] ip_pipeline: add cli interface Jasvinder Singh
                   ` (26 subsequent siblings)
  36 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-09 18:23 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

All the actions associated with application pipelines
tables and ports are now implemented using the new action
APIs. Therefore, thousands of lines of code are eliminated
from the application. The reduced code size is easier to
maintain and extend.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/Makefile                      |   38 +-
 examples/ip_pipeline/app.h                         | 1401 --------
 examples/ip_pipeline/config/action.cfg             |   68 -
 examples/ip_pipeline/config/action.sh              |  119 -
 examples/ip_pipeline/config/action.txt             |    8 -
 examples/ip_pipeline/config/diagram-generator.py   |  317 --
 .../ip_pipeline/config/edge_router_downstream.cfg  |   97 -
 .../ip_pipeline/config/edge_router_downstream.sh   |   13 -
 .../ip_pipeline/config/edge_router_upstream.cfg    |  124 -
 .../ip_pipeline/config/edge_router_upstream.sh     |   33 -
 examples/ip_pipeline/config/firewall.cfg           |   68 -
 examples/ip_pipeline/config/firewall.sh            |   13 -
 examples/ip_pipeline/config/firewall.txt           |    9 -
 examples/ip_pipeline/config/flow.cfg               |   72 -
 examples/ip_pipeline/config/flow.sh                |   25 -
 examples/ip_pipeline/config/flow.txt               |   17 -
 examples/ip_pipeline/config/ip_pipeline.cfg        |    9 -
 examples/ip_pipeline/config/ip_pipeline.sh         |    5 -
 examples/ip_pipeline/config/kni.cfg                |   67 -
 examples/ip_pipeline/config/l2fwd.cfg              |   58 -
 examples/ip_pipeline/config/l3fwd.cfg              |   68 -
 examples/ip_pipeline/config/l3fwd.sh               |   33 -
 examples/ip_pipeline/config/l3fwd_arp.cfg          |   70 -
 examples/ip_pipeline/config/l3fwd_arp.sh           |   43 -
 examples/ip_pipeline/config/network_layers.cfg     |  227 --
 examples/ip_pipeline/config/network_layers.sh      |   79 -
 .../ip_pipeline/config/pipeline-to-core-mapping.py |  906 ------
 examples/ip_pipeline/config/tap.cfg                |   64 -
 examples/ip_pipeline/config/tm_profile.cfg         |  105 -
 examples/ip_pipeline/config_check.c                |  488 ---
 examples/ip_pipeline/config_parse.c                | 3395 --------------------
 examples/ip_pipeline/config_parse_tm.c             |  419 ---
 examples/ip_pipeline/cpu_core_map.c                |  471 ---
 examples/ip_pipeline/cpu_core_map.h                |   40 -
 examples/ip_pipeline/{pipeline => }/hash_func.h    |    3 +-
 .../ip_pipeline/{pipeline => }/hash_func_arm64.h   |    0
 examples/ip_pipeline/init.c                        | 1927 -----------
 examples/ip_pipeline/main.c                        |   36 +-
 examples/ip_pipeline/meson.build                   |   23 +-
 examples/ip_pipeline/parser.c                      |   16 +-
 examples/ip_pipeline/parser.h                      |    8 +
 examples/ip_pipeline/pipeline.h                    |   73 -
 .../ip_pipeline/pipeline/pipeline_actions_common.h |  202 --
 examples/ip_pipeline/pipeline/pipeline_common_be.c |  176 -
 examples/ip_pipeline/pipeline/pipeline_common_be.h |  134 -
 examples/ip_pipeline/pipeline/pipeline_common_fe.c | 1455 ---------
 examples/ip_pipeline/pipeline/pipeline_common_fe.h |  231 --
 examples/ip_pipeline/pipeline/pipeline_firewall.c  | 1421 --------
 examples/ip_pipeline/pipeline/pipeline_firewall.h  |   60 -
 .../ip_pipeline/pipeline/pipeline_firewall_be.c    |  856 -----
 .../ip_pipeline/pipeline/pipeline_firewall_be.h    |  147 -
 .../ip_pipeline/pipeline/pipeline_flow_actions.c   | 1286 --------
 .../ip_pipeline/pipeline/pipeline_flow_actions.h   |   60 -
 .../pipeline/pipeline_flow_actions_be.c            |  983 ------
 .../pipeline/pipeline_flow_actions_be.h            |  139 -
 .../pipeline/pipeline_flow_classification.c        | 1878 -----------
 .../pipeline/pipeline_flow_classification.h        |  106 -
 .../pipeline/pipeline_flow_classification_be.c     |  723 -----
 .../pipeline/pipeline_flow_classification_be.h     |  113 -
 examples/ip_pipeline/pipeline/pipeline_master.c    |   20 -
 examples/ip_pipeline/pipeline/pipeline_master.h    |   12 -
 examples/ip_pipeline/pipeline/pipeline_master_be.c |  141 -
 examples/ip_pipeline/pipeline/pipeline_master_be.h |   12 -
 .../ip_pipeline/pipeline/pipeline_passthrough.c    |   45 -
 .../ip_pipeline/pipeline/pipeline_passthrough.h    |   12 -
 .../ip_pipeline/pipeline/pipeline_passthrough_be.c |  929 ------
 .../ip_pipeline/pipeline/pipeline_passthrough_be.h |   44 -
 examples/ip_pipeline/pipeline/pipeline_routing.c   | 1613 ----------
 examples/ip_pipeline/pipeline/pipeline_routing.h   |   71 -
 .../ip_pipeline/pipeline/pipeline_routing_be.c     | 1966 ------------
 .../ip_pipeline/pipeline/pipeline_routing_be.h     |  283 --
 examples/ip_pipeline/pipeline_be.h                 |  322 --
 examples/ip_pipeline/thread.c                      |  293 --
 examples/ip_pipeline/thread.h                      |   69 -
 examples/ip_pipeline/thread_fe.c                   |  457 ---
 examples/ip_pipeline/thread_fe.h                   |   72 -
 76 files changed, 38 insertions(+), 27348 deletions(-)
 delete mode 100644 examples/ip_pipeline/app.h
 delete mode 100644 examples/ip_pipeline/config/action.cfg
 delete mode 100644 examples/ip_pipeline/config/action.sh
 delete mode 100644 examples/ip_pipeline/config/action.txt
 delete mode 100755 examples/ip_pipeline/config/diagram-generator.py
 delete mode 100644 examples/ip_pipeline/config/edge_router_downstream.cfg
 delete mode 100644 examples/ip_pipeline/config/edge_router_downstream.sh
 delete mode 100644 examples/ip_pipeline/config/edge_router_upstream.cfg
 delete mode 100644 examples/ip_pipeline/config/edge_router_upstream.sh
 delete mode 100644 examples/ip_pipeline/config/firewall.cfg
 delete mode 100644 examples/ip_pipeline/config/firewall.sh
 delete mode 100644 examples/ip_pipeline/config/firewall.txt
 delete mode 100644 examples/ip_pipeline/config/flow.cfg
 delete mode 100644 examples/ip_pipeline/config/flow.sh
 delete mode 100644 examples/ip_pipeline/config/flow.txt
 delete mode 100644 examples/ip_pipeline/config/ip_pipeline.cfg
 delete mode 100644 examples/ip_pipeline/config/ip_pipeline.sh
 delete mode 100644 examples/ip_pipeline/config/kni.cfg
 delete mode 100644 examples/ip_pipeline/config/l2fwd.cfg
 delete mode 100644 examples/ip_pipeline/config/l3fwd.cfg
 delete mode 100644 examples/ip_pipeline/config/l3fwd.sh
 delete mode 100644 examples/ip_pipeline/config/l3fwd_arp.cfg
 delete mode 100644 examples/ip_pipeline/config/l3fwd_arp.sh
 delete mode 100644 examples/ip_pipeline/config/network_layers.cfg
 delete mode 100644 examples/ip_pipeline/config/network_layers.sh
 delete mode 100755 examples/ip_pipeline/config/pipeline-to-core-mapping.py
 delete mode 100644 examples/ip_pipeline/config/tap.cfg
 delete mode 100644 examples/ip_pipeline/config/tm_profile.cfg
 delete mode 100644 examples/ip_pipeline/config_check.c
 delete mode 100644 examples/ip_pipeline/config_parse.c
 delete mode 100644 examples/ip_pipeline/config_parse_tm.c
 delete mode 100644 examples/ip_pipeline/cpu_core_map.c
 delete mode 100644 examples/ip_pipeline/cpu_core_map.h
 rename examples/ip_pipeline/{pipeline => }/hash_func.h (99%)
 rename examples/ip_pipeline/{pipeline => }/hash_func_arm64.h (100%)
 delete mode 100644 examples/ip_pipeline/init.c
 delete mode 100644 examples/ip_pipeline/pipeline.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_actions_common.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_common_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_common_be.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_common_fe.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_common_fe.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_firewall.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_firewall.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_firewall_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_firewall_be.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_actions.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_actions.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_actions_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_actions_be.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_classification.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_classification.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_classification_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_classification_be.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_master.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_master.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_master_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_master_be.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_passthrough.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_passthrough.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_passthrough_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_passthrough_be.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_routing.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_routing.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_routing_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_routing_be.h
 delete mode 100644 examples/ip_pipeline/pipeline_be.h
 delete mode 100644 examples/ip_pipeline/thread.c
 delete mode 100644 examples/ip_pipeline/thread.h
 delete mode 100644 examples/ip_pipeline/thread_fe.c
 delete mode 100644 examples/ip_pipeline/thread_fe.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index 85fbbaf..981c4f7 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -1,34 +1,13 @@
 # SPDX-License-Identifier: BSD-3-Clause
-# Copyright(c) 2010-2014 Intel Corporation
+# Copyright(c) 2010-2018 Intel Corporation
 
 # binary name
 APP = ip_pipeline
 
 # all source are stored in SRCS-y
 SRCS-y := main.c
-SRCS-y += config_parse.c
 SRCS-y += parser.c
-SRCS-y += config_parse_tm.c
-SRCS-y += config_check.c
-SRCS-y += init.c
-SRCS-y += thread.c
-SRCS-y += thread_fe.c
-SRCS-y += cpu_core_map.c
-
-SRCS-y += pipeline_common_be.c
-SRCS-y += pipeline_common_fe.c
-SRCS-y += pipeline_master_be.c
-SRCS-y += pipeline_master.c
-SRCS-y += pipeline_passthrough_be.c
-SRCS-y += pipeline_passthrough.c
-SRCS-y += pipeline_firewall_be.c
-SRCS-y += pipeline_firewall.c
-SRCS-y += pipeline_flow_classification_be.c
-SRCS-y += pipeline_flow_classification.c
-SRCS-y += pipeline_flow_actions_be.c
-SRCS-y += pipeline_flow_actions.c
-SRCS-y += pipeline_routing_be.c
-SRCS-y += pipeline_routing.c
+#SRCS-y += thread.c
 
 # Build using pkg-config variables if possible
 $(shell pkg-config --exists libdpdk)
@@ -46,9 +25,7 @@ CFLAGS += -O3 $(shell pkg-config --cflags libdpdk)
 LDFLAGS_SHARED = $(shell pkg-config --libs libdpdk)
 LDFLAGS_STATIC = -Wl,-Bstatic $(shell pkg-config --static --libs libdpdk)
 
-VPATH += pipeline
-CFLAGS += -I. -I./pipeline/
-CFLAGS += -DALLOW_EXPERIMENTAL_API
+CFLAGS += -I.
 
 OBJS := $(patsubst %.c,build/%.o,$(SRCS-y))
 
@@ -75,21 +52,18 @@ ifeq ($(RTE_SDK),)
 $(error "Please define RTE_SDK environment variable")
 endif
 
-VPATH += $(SRCDIR)/pipeline
-
 # Default target, can be overridden by command line or environment
 RTE_TARGET ?= x86_64-native-linuxapp-gcc
 
 include $(RTE_SDK)/mk/rte.vars.mk
 
-INC += $(sort $(wildcard *.h)) $(sort $(wildcard pipeline/*.h))
+INC += $(sort $(wildcard *.h))
 
 SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) := $(SRCS-y)
 
-CFLAGS += -I$(SRCDIR) -I$(SRCDIR)/pipeline
+CFLAGS += -I$(SRCDIR)
 CFLAGS += -O3
-CFLAGS += $(WERROR_FLAGS) -Wno-error=unused-function -Wno-error=unused-variable
-CFLAGS += -DALLOW_EXPERIMENTAL_API
+CFLAGS += $(WERROR_FLAGS)
 
 include $(RTE_SDK)/mk/rte.extapp.mk
 
diff --git a/examples/ip_pipeline/app.h b/examples/ip_pipeline/app.h
deleted file mode 100644
index 907d4e7..0000000
--- a/examples/ip_pipeline/app.h
+++ /dev/null
@@ -1,1401 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2016 Intel Corporation
- */
-
-#ifndef __INCLUDE_APP_H__
-#define __INCLUDE_APP_H__
-
-#include <stdint.h>
-#include <string.h>
-
-#include <rte_common.h>
-#include <rte_mempool.h>
-#include <rte_ring.h>
-#include <rte_sched.h>
-#include <cmdline_parse.h>
-
-#include <rte_ethdev.h>
-#ifdef RTE_LIBRTE_KNI
-#include <rte_kni.h>
-#endif
-
-#include "cpu_core_map.h"
-#include "pipeline.h"
-
-#define APP_PARAM_NAME_SIZE                      PIPELINE_NAME_SIZE
-#define APP_LINK_PCI_BDF_SIZE                    16
-
-#ifndef APP_LINK_MAX_HWQ_IN
-#define APP_LINK_MAX_HWQ_IN                      128
-#endif
-
-#ifndef APP_LINK_MAX_HWQ_OUT
-#define APP_LINK_MAX_HWQ_OUT                     128
-#endif
-
-struct app_mempool_params {
-	char *name;
-	uint32_t parsed;
-	uint32_t buffer_size;
-	uint32_t pool_size;
-	uint32_t cache_size;
-	uint32_t cpu_socket_id;
-};
-
-struct app_link_params {
-	char *name;
-	uint32_t parsed;
-	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_q; /* 0 = Disabled (pkts go to default queue) */
-	uint32_t ip_local_q; /* 0 = Disabled (pkts go to default queue 0) */
-	uint32_t tcp_local_q; /* 0 = Disabled (pkts go to default queue 0) */
-	uint32_t udp_local_q; /* 0 = Disabled (pkts go to default queue 0) */
-	uint32_t sctp_local_q; /* 0 = Disabled (pkts go to default queue 0) */
-	uint32_t rss_qs[APP_LINK_MAX_HWQ_IN];
-	uint32_t n_rss_qs;
-	uint64_t rss_proto_ipv4;
-	uint64_t rss_proto_ipv6;
-	uint64_t rss_proto_l2;
-	uint32_t promisc;
-	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 */
-	char pci_bdf[APP_LINK_PCI_BDF_SIZE];
-
-	struct rte_eth_conf conf;
-};
-
-struct app_pktq_hwq_in_params {
-	char *name;
-	uint32_t parsed;
-	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;
-	uint32_t parsed;
-	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;
-	uint32_t parsed;
-	uint32_t size;
-	uint32_t burst_read;
-	uint32_t burst_write;
-	uint32_t dropless;
-	uint64_t n_retries;
-	uint32_t cpu_socket_id;
-	uint32_t ipv4_frag;
-	uint32_t ipv6_frag;
-	uint32_t ipv4_ras;
-	uint32_t ipv6_ras;
-	uint32_t mtu;
-	uint32_t metadata_size;
-	uint32_t mempool_direct_id;
-	uint32_t mempool_indirect_id;
-};
-
-struct app_pktq_kni_params {
-	char *name;
-	uint32_t parsed;
-
-	uint32_t socket_id;
-	uint32_t core_id;
-	uint32_t hyper_th_id;
-	uint32_t force_bind;
-
-	uint32_t mempool_id; /* Position in the app->mempool_params */
-	uint32_t burst_read;
-	uint32_t burst_write;
-	uint32_t dropless;
-	uint64_t n_retries;
-};
-
-#ifndef APP_FILE_NAME_SIZE
-#define APP_FILE_NAME_SIZE                       256
-#endif
-
-#ifndef APP_MAX_SCHED_SUBPORTS
-#define APP_MAX_SCHED_SUBPORTS                   8
-#endif
-
-#ifndef APP_MAX_SCHED_PIPES
-#define APP_MAX_SCHED_PIPES                      4096
-#endif
-
-struct app_pktq_tm_params {
-	char *name;
-	uint32_t parsed;
-	const char *file_name;
-	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_tap_params {
-	char *name;
-	uint32_t parsed;
-	uint32_t burst_read;
-	uint32_t burst_write;
-	uint32_t dropless;
-	uint64_t n_retries;
-	uint32_t mempool_id; /* Position in the app->mempool_params */
-};
-
-struct app_pktq_source_params {
-	char *name;
-	uint32_t parsed;
-	uint32_t mempool_id; /* Position in the app->mempool_params array */
-	uint32_t burst;
-	const char *file_name; /* Full path of PCAP file to be copied to mbufs */
-	uint32_t n_bytes_per_pkt;
-};
-
-struct app_pktq_sink_params {
-	char *name;
-	uint8_t parsed;
-	const char *file_name; /* Full path of PCAP file to be copied to mbufs */
-	uint32_t n_pkts_to_dump;
-};
-
-struct app_msgq_params {
-	char *name;
-	uint32_t parsed;
-	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_TAP,
-	APP_PKTQ_IN_KNI,
-	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_TAP,
-	APP_PKTQ_OUT_KNI,
-	APP_PKTQ_OUT_SINK,
-};
-
-struct app_pktq_out_params {
-	enum app_pktq_out_type type;
-	uint32_t id; /* Position in the appropriate app array */
-};
-
-#define APP_PIPELINE_TYPE_SIZE                   PIPELINE_TYPE_SIZE
-
-#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
-
-#define APP_MAX_PIPELINE_ARGS                    PIPELINE_MAX_ARGS
-
-struct app_pipeline_params {
-	char *name;
-	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_params;
-
-typedef void (*app_link_op)(struct app_params *app,
-	uint32_t link_id,
-	uint32_t up,
-	void *arg);
-
-#ifndef APP_MAX_PIPELINES
-#define APP_MAX_PIPELINES                        64
-#endif
-
-struct app_link_data {
-	app_link_op f_link[APP_MAX_PIPELINES];
-	void *arg[APP_MAX_PIPELINES];
-};
-
-struct app_pipeline_data {
-	void *be;
-	void *fe;
-	struct pipeline_type *ptype;
-	uint64_t timer_period;
-	uint32_t enabled;
-};
-
-struct app_thread_pipeline_data {
-	uint32_t pipeline_id;
-	void *be;
-	pipeline_be_op_run f_run;
-	pipeline_be_op_timer f_timer;
-	uint64_t timer_period;
-	uint64_t deadline;
-};
-
-#ifndef APP_MAX_THREAD_PIPELINES
-#define APP_MAX_THREAD_PIPELINES                 64
-#endif
-
-#ifndef APP_THREAD_TIMER_PERIOD
-#define APP_THREAD_TIMER_PERIOD                  1
-#endif
-
-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 timer_period;
-	uint64_t thread_req_deadline;
-
-	uint64_t deadline;
-
-	struct rte_ring *msgq_in;
-	struct rte_ring *msgq_out;
-
-	uint64_t headroom_time;
-	uint64_t headroom_cycles;
-	double headroom_ratio;
-} __rte_cache_aligned;
-
-#ifndef APP_MAX_LINKS
-#define APP_MAX_LINKS                            16
-#endif
-
-struct app_eal_params {
-	/* Map lcore set to physical cpu set */
-	char *coremap;
-
-	/* Core ID that is used as master */
-	uint32_t master_lcore_present;
-	uint32_t master_lcore;
-
-	/* Number of memory channels */
-	uint32_t channels_present;
-	uint32_t channels;
-
-	/* Memory to allocate (see also --socket-mem) */
-	uint32_t memory_present;
-	uint32_t memory;
-
-	/* Force number of memory ranks (don't detect) */
-	uint32_t ranks_present;
-	uint32_t ranks;
-
-	/* Add a PCI device in black list. */
-	char *pci_blacklist[APP_MAX_LINKS];
-
-	/* Add a PCI device in white list. */
-	char *pci_whitelist[APP_MAX_LINKS];
-
-	/* Add a virtual device. */
-	char *vdev[APP_MAX_LINKS];
-
-	 /* Use VMware TSC map instead of native RDTSC */
-	uint32_t vmware_tsc_map_present;
-	int vmware_tsc_map;
-
-	 /* Type of this process (primary|secondary|auto) */
-	char *proc_type;
-
-	 /* Set syslog facility */
-	char *syslog;
-
-	/* Set default log level */
-	uint32_t log_level_present;
-	uint32_t log_level;
-
-	/* Display version information on startup */
-	uint32_t version_present;
-	int version;
-
-	/* This help */
-	uint32_t help_present;
-	int help;
-
-	 /* Use malloc instead of hugetlbfs */
-	uint32_t no_huge_present;
-	int no_huge;
-
-	/* Disable PCI */
-	uint32_t no_pci_present;
-	int no_pci;
-
-	/* Disable HPET */
-	uint32_t no_hpet_present;
-	int no_hpet;
-
-	/* No shared config (mmap'd files) */
-	uint32_t no_shconf_present;
-	int no_shconf;
-
-	/* Add driver */
-	char *add_driver;
-
-	/*  Memory to allocate on sockets (comma separated values)*/
-	char *socket_mem;
-
-	/* Directory where hugetlbfs is mounted */
-	char *huge_dir;
-
-	/* Prefix for hugepage filenames */
-	char *file_prefix;
-
-	/* Base virtual address */
-	char *base_virtaddr;
-
-	/* Create /dev/uioX (usually done by hotplug) */
-	uint32_t create_uio_dev_present;
-	int create_uio_dev;
-
-	/* Interrupt mode for VFIO (legacy|msi|msix) */
-	char *vfio_intr;
-
-	uint32_t parsed;
-};
-
-#ifndef APP_APPNAME_SIZE
-#define APP_APPNAME_SIZE                         256
-#endif
-
-#ifndef APP_MAX_MEMPOOLS
-#define APP_MAX_MEMPOOLS                         8
-#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_TAP
-#define APP_MAX_PKTQ_TAP                         APP_MAX_LINKS
-#endif
-
-#define APP_MAX_PKTQ_KNI                         APP_MAX_LINKS
-
-#ifndef APP_MAX_PKTQ_SOURCE
-#define APP_MAX_PKTQ_SOURCE                      64
-#endif
-
-#ifndef APP_MAX_PKTQ_SINK
-#define APP_MAX_PKTQ_SINK                        64
-#endif
-
-#ifndef APP_MAX_MSGQ
-#define APP_MAX_MSGQ                             256
-#endif
-
-#ifndef APP_EAL_ARGC
-#define APP_EAL_ARGC                             64
-#endif
-
-#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
-
-#ifndef APP_THREAD_HEADROOM_STATS_COLLECT
-#define APP_THREAD_HEADROOM_STATS_COLLECT        1
-#endif
-
-#define APP_CORE_MASK_SIZE					\
-	(RTE_MAX_LCORE / 64 + ((RTE_MAX_LCORE % 64) ? 1 : 0))
-
-struct app_params {
-	/* Config */
-	char app_name[APP_APPNAME_SIZE];
-	const char *config_file;
-	const char *script_file;
-	const char *parser_file;
-	const char *output_file;
-	const char *preproc;
-	const char *preproc_args;
-	uint64_t port_mask;
-	uint32_t log_level;
-
-	struct app_eal_params eal_params;
-	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_tap_params tap_params[APP_MAX_PKTQ_TAP];
-	struct app_pktq_kni_params kni_params[APP_MAX_PKTQ_KNI];
-	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_tap;
-	uint32_t n_pktq_kni;
-	uint32_t n_pktq_source;
-	uint32_t n_pktq_sink;
-	uint32_t n_msgq;
-	uint32_t n_pipelines;
-
-	/* Init */
-	char *eal_argv[1 + APP_EAL_ARGC];
-	struct cpu_core_map *core_map;
-	uint64_t core_mask[APP_CORE_MASK_SIZE];
-	struct rte_mempool *mempool[APP_MAX_MEMPOOLS];
-	struct app_link_data link_data[APP_MAX_LINKS];
-	struct rte_ring *swq[APP_MAX_PKTQ_SWQ];
-	struct rte_sched_port *tm[APP_MAX_PKTQ_TM];
-	int tap[APP_MAX_PKTQ_TAP];
-#ifdef RTE_LIBRTE_KNI
-	struct rte_kni *kni[APP_MAX_PKTQ_KNI];
-#endif /* RTE_LIBRTE_KNI */
-	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];
-
-	int eal_argc;
-	uint32_t n_pipeline_types;
-	uint32_t n_cmds;
-};
-
-#define APP_PARAM_VALID(obj) ((obj)->name != NULL)
-
-#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++;					\
-}
-
-#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 "%" PRIu32, 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 "%" SCNu32, &id);				\
-while (0)								\
-
-#define	APP_CHECK(exp, fmt, ...)					\
-do {									\
-	if (!(exp)) {							\
-		fprintf(stderr, fmt "\n", ## __VA_ARGS__);		\
-		abort();						\
-	}								\
-} while (0)
-
-enum app_log_level {
-	APP_LOG_LEVEL_HIGH = 1,
-	APP_LOG_LEVEL_LOW,
-	APP_LOG_LEVELS
-};
-
-#define APP_LOG(app, level, fmt, ...)					\
-do {									\
-	if (app->log_level >= APP_LOG_LEVEL_ ## level)			\
-		fprintf(stdout, "[APP] " fmt "\n", ## __VA_ARGS__);	\
-} while (0)
-
-static inline uint32_t
-app_link_get_n_rxq(struct app_params *app, struct app_link_params *link)
-{
-	uint32_t n_rxq = 0, link_id, i;
-	uint32_t n_pktq_hwq_in = RTE_MIN(app->n_pktq_hwq_in,
-		RTE_DIM(app->hwq_in_params));
-
-	APP_PARAM_GET_ID(link, "LINK", link_id);
-
-	for (i = 0; i < n_pktq_hwq_in; i++) {
-		struct app_pktq_hwq_in_params *p = &app->hwq_in_params[i];
-		uint32_t rxq_link_id, rxq_queue_id;
-
-		sscanf(p->name, "RXQ%" SCNu32 ".%" SCNu32,
-			&rxq_link_id, &rxq_queue_id);
-		if (rxq_link_id == link_id)
-			n_rxq++;
-	}
-
-	return n_rxq;
-}
-
-static inline uint32_t
-app_link_get_n_txq(struct app_params *app, struct app_link_params *link)
-{
-	uint32_t n_txq = 0, link_id, i;
-	uint32_t n_pktq_hwq_out = RTE_MIN(app->n_pktq_hwq_out,
-		RTE_DIM(app->hwq_out_params));
-
-	APP_PARAM_GET_ID(link, "LINK", link_id);
-
-	for (i = 0; i < n_pktq_hwq_out; i++) {
-		struct app_pktq_hwq_out_params *p = &app->hwq_out_params[i];
-		uint32_t txq_link_id, txq_queue_id;
-
-		sscanf(p->name, "TXQ%" SCNu32 ".%" SCNu32,
-			&txq_link_id, &txq_queue_id);
-		if (txq_link_id == link_id)
-			n_txq++;
-	}
-
-	return n_txq;
-}
-
-static inline uint32_t
-app_rxq_get_readers(struct app_params *app, struct app_pktq_hwq_in_params *rxq)
-{
-	uint32_t pos = rxq - app->hwq_in_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_readers = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_in = RTE_MIN(p->n_pktq_in, RTE_DIM(p->pktq_in));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_in; j++) {
-			struct app_pktq_in_params *pktq = &p->pktq_in[j];
-
-			if ((pktq->type == APP_PKTQ_IN_HWQ) &&
-				(pktq->id == pos))
-				n_readers++;
-		}
-	}
-
-	return n_readers;
-}
-
-static inline uint32_t
-app_swq_get_readers(struct app_params *app, struct app_pktq_swq_params *swq)
-{
-	uint32_t pos = swq - app->swq_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_readers = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_in = RTE_MIN(p->n_pktq_in, RTE_DIM(p->pktq_in));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_in; j++) {
-			struct app_pktq_in_params *pktq = &p->pktq_in[j];
-
-			if ((pktq->type == APP_PKTQ_IN_SWQ) &&
-				(pktq->id == pos))
-				n_readers++;
-		}
-	}
-
-	return n_readers;
-}
-
-static inline struct app_pipeline_params *
-app_swq_get_reader(struct app_params *app,
-	struct app_pktq_swq_params *swq,
-	uint32_t *pktq_in_id)
-{
-	struct app_pipeline_params *reader = NULL;
-	uint32_t pos = swq - app->swq_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_readers = 0, id = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_in = RTE_MIN(p->n_pktq_in, RTE_DIM(p->pktq_in));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_in; j++) {
-			struct app_pktq_in_params *pktq = &p->pktq_in[j];
-
-			if ((pktq->type == APP_PKTQ_IN_SWQ) &&
-				(pktq->id == pos)) {
-				n_readers++;
-				reader = p;
-				id = j;
-			}
-		}
-	}
-
-	if (n_readers != 1)
-		return NULL;
-
-	*pktq_in_id = id;
-	return reader;
-}
-
-static inline uint32_t
-app_tm_get_readers(struct app_params *app, struct app_pktq_tm_params *tm)
-{
-	uint32_t pos = tm - app->tm_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_readers = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_in = RTE_MIN(p->n_pktq_in, RTE_DIM(p->pktq_in));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_in; j++) {
-			struct app_pktq_in_params *pktq = &p->pktq_in[j];
-
-			if ((pktq->type == APP_PKTQ_IN_TM) &&
-				(pktq->id == pos))
-				n_readers++;
-		}
-	}
-
-	return n_readers;
-}
-
-static inline struct app_pipeline_params *
-app_tm_get_reader(struct app_params *app,
-	struct app_pktq_tm_params *tm,
-	uint32_t *pktq_in_id)
-{
-	struct app_pipeline_params *reader = NULL;
-	uint32_t pos = tm - app->tm_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_readers = 0, id = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_in = RTE_MIN(p->n_pktq_in, RTE_DIM(p->pktq_in));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_in; j++) {
-			struct app_pktq_in_params *pktq = &p->pktq_in[j];
-
-			if ((pktq->type == APP_PKTQ_IN_TM) &&
-				(pktq->id == pos)) {
-				n_readers++;
-				reader = p;
-				id = j;
-			}
-		}
-	}
-
-	if (n_readers != 1)
-		return NULL;
-
-	*pktq_in_id = id;
-	return reader;
-}
-
-static inline uint32_t
-app_tap_get_readers(struct app_params *app, struct app_pktq_tap_params *tap)
-{
-	uint32_t pos = tap - app->tap_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_readers = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_in = RTE_MIN(p->n_pktq_in, RTE_DIM(p->pktq_in));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_in; j++) {
-			struct app_pktq_in_params *pktq = &p->pktq_in[j];
-
-			if ((pktq->type == APP_PKTQ_IN_TAP) &&
-				(pktq->id == pos))
-				n_readers++;
-		}
-	}
-
-	return n_readers;
-}
-
-static inline struct app_pipeline_params *
-app_tap_get_reader(struct app_params *app,
-	struct app_pktq_tap_params *tap,
-	uint32_t *pktq_in_id)
-{
-	struct app_pipeline_params *reader = NULL;
-	uint32_t pos = tap - app->tap_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_readers = 0, id = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_in = RTE_MIN(p->n_pktq_in, RTE_DIM(p->pktq_in));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_in; j++) {
-			struct app_pktq_in_params *pktq = &p->pktq_in[j];
-
-			if ((pktq->type == APP_PKTQ_IN_TAP) &&
-				(pktq->id == pos)) {
-				n_readers++;
-				reader = p;
-				id = j;
-			}
-		}
-	}
-
-	if (n_readers != 1)
-		return NULL;
-
-	*pktq_in_id = id;
-	return reader;
-}
-
-static inline uint32_t
-app_kni_get_readers(struct app_params *app, struct app_pktq_kni_params *kni)
-{
-	uint32_t pos = kni - app->kni_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_readers = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_in = RTE_MIN(p->n_pktq_in, RTE_DIM(p->pktq_in));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_in; j++) {
-			struct app_pktq_in_params *pktq = &p->pktq_in[j];
-
-			if ((pktq->type == APP_PKTQ_IN_KNI) &&
-				(pktq->id == pos))
-				n_readers++;
-		}
-	}
-
-	return n_readers;
-}
-
-static inline struct app_pipeline_params *
-app_kni_get_reader(struct app_params *app,
-				  struct app_pktq_kni_params *kni,
-				  uint32_t *pktq_in_id)
-{
-	struct app_pipeline_params *reader = NULL;
-	uint32_t pos = kni - app->kni_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_readers = 0, id = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_in = RTE_MIN(p->n_pktq_in, RTE_DIM(p->pktq_in));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_in; j++) {
-			struct app_pktq_in_params *pktq = &p->pktq_in[j];
-
-			if ((pktq->type == APP_PKTQ_IN_KNI) &&
-				(pktq->id == pos)) {
-				n_readers++;
-				reader = p;
-				id = j;
-			}
-		}
-	}
-
-	if (n_readers != 1)
-		return NULL;
-
-	*pktq_in_id = id;
-	return reader;
-}
-
-static inline uint32_t
-app_source_get_readers(struct app_params *app,
-struct app_pktq_source_params *source)
-{
-	uint32_t pos = source - app->source_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_readers = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_in = RTE_MIN(p->n_pktq_in, RTE_DIM(p->pktq_in));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_in; j++) {
-			struct app_pktq_in_params *pktq = &p->pktq_in[j];
-
-			if ((pktq->type == APP_PKTQ_IN_SOURCE) &&
-				(pktq->id == pos))
-				n_readers++;
-		}
-	}
-
-	return n_readers;
-}
-
-static inline uint32_t
-app_msgq_get_readers(struct app_params *app, struct app_msgq_params *msgq)
-{
-	uint32_t pos = msgq - app->msgq_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_readers = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_msgq_in = RTE_MIN(p->n_msgq_in, RTE_DIM(p->msgq_in));
-		uint32_t j;
-
-		for (j = 0; j < n_msgq_in; j++)
-			if (p->msgq_in[j] == pos)
-				n_readers++;
-	}
-
-	return n_readers;
-}
-
-static inline uint32_t
-app_txq_get_writers(struct app_params *app, struct app_pktq_hwq_out_params *txq)
-{
-	uint32_t pos = txq - app->hwq_out_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_writers = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_out = RTE_MIN(p->n_pktq_out,
-			RTE_DIM(p->pktq_out));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_out; j++) {
-			struct app_pktq_out_params *pktq = &p->pktq_out[j];
-
-			if ((pktq->type == APP_PKTQ_OUT_HWQ) &&
-				(pktq->id == pos))
-				n_writers++;
-		}
-	}
-
-	return n_writers;
-}
-
-static inline uint32_t
-app_swq_get_writers(struct app_params *app, struct app_pktq_swq_params *swq)
-{
-	uint32_t pos = swq - app->swq_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_writers = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_out = RTE_MIN(p->n_pktq_out,
-			RTE_DIM(p->pktq_out));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_out; j++) {
-			struct app_pktq_out_params *pktq = &p->pktq_out[j];
-
-			if ((pktq->type == APP_PKTQ_OUT_SWQ) &&
-				(pktq->id == pos))
-				n_writers++;
-		}
-	}
-
-	return n_writers;
-}
-
-static inline struct app_pipeline_params *
-app_swq_get_writer(struct app_params *app,
-	struct app_pktq_swq_params *swq,
-	uint32_t *pktq_out_id)
-{
-	struct app_pipeline_params *writer = NULL;
-	uint32_t pos = swq - app->swq_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_writers = 0, id = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_out = RTE_MIN(p->n_pktq_out,
-			RTE_DIM(p->pktq_out));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_out; j++) {
-			struct app_pktq_out_params *pktq = &p->pktq_out[j];
-
-			if ((pktq->type == APP_PKTQ_OUT_SWQ) &&
-				(pktq->id == pos)) {
-				n_writers++;
-				writer = p;
-				id = j;
-			}
-		}
-	}
-
-	if (n_writers != 1)
-		return NULL;
-
-	*pktq_out_id = id;
-	return writer;
-}
-
-static inline uint32_t
-app_tm_get_writers(struct app_params *app, struct app_pktq_tm_params *tm)
-{
-	uint32_t pos = tm - app->tm_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_writers = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_out = RTE_MIN(p->n_pktq_out,
-			RTE_DIM(p->pktq_out));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_out; j++) {
-			struct app_pktq_out_params *pktq = &p->pktq_out[j];
-
-			if ((pktq->type == APP_PKTQ_OUT_TM) &&
-				(pktq->id == pos))
-				n_writers++;
-		}
-	}
-
-	return n_writers;
-}
-
-static inline struct app_pipeline_params *
-app_tm_get_writer(struct app_params *app,
-	struct app_pktq_tm_params *tm,
-	uint32_t *pktq_out_id)
-{
-	struct app_pipeline_params *writer = NULL;
-	uint32_t pos = tm - app->tm_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_writers = 0, id = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_out = RTE_MIN(p->n_pktq_out,
-			RTE_DIM(p->pktq_out));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_out; j++) {
-			struct app_pktq_out_params *pktq = &p->pktq_out[j];
-
-			if ((pktq->type == APP_PKTQ_OUT_TM) &&
-				(pktq->id == pos)) {
-				n_writers++;
-				writer = p;
-				id = j;
-			}
-		}
-	}
-
-	if (n_writers != 1)
-		return NULL;
-
-	*pktq_out_id = id;
-	return writer;
-}
-
-static inline uint32_t
-app_tap_get_writers(struct app_params *app, struct app_pktq_tap_params *tap)
-{
-	uint32_t pos = tap - app->tap_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_writers = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_out = RTE_MIN(p->n_pktq_out,
-			RTE_DIM(p->pktq_out));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_out; j++) {
-			struct app_pktq_out_params *pktq = &p->pktq_out[j];
-
-		if ((pktq->type == APP_PKTQ_OUT_TAP) &&
-			(pktq->id == pos))
-			n_writers++;
-		}
-	}
-
-	return n_writers;
-}
-
-static inline struct app_pipeline_params *
-app_tap_get_writer(struct app_params *app,
-	struct app_pktq_tap_params *tap,
-	uint32_t *pktq_out_id)
-{
-	struct app_pipeline_params *writer = NULL;
-	uint32_t pos = tap - app->tap_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_writers = 0, id = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_out = RTE_MIN(p->n_pktq_out,
-			RTE_DIM(p->pktq_out));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_out; j++) {
-			struct app_pktq_out_params *pktq = &p->pktq_out[j];
-
-			if ((pktq->type == APP_PKTQ_OUT_TAP) &&
-				(pktq->id == pos)) {
-				n_writers++;
-				writer = p;
-				id = j;
-			}
-		}
-	}
-
-	if (n_writers != 1)
-		return NULL;
-
-	*pktq_out_id = id;
-	return writer;
-}
-
-static inline uint32_t
-app_kni_get_writers(struct app_params *app, struct app_pktq_kni_params *kni)
-{
-	uint32_t pos = kni - app->kni_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_writers = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_out = RTE_MIN(p->n_pktq_out,
-			RTE_DIM(p->pktq_out));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_out; j++) {
-			struct app_pktq_out_params *pktq = &p->pktq_out[j];
-
-			if ((pktq->type == APP_PKTQ_OUT_KNI) &&
-				(pktq->id == pos))
-				n_writers++;
-		}
-	}
-
-	return n_writers;
-}
-
-static inline struct app_pipeline_params *
-app_kni_get_writer(struct app_params *app,
-				  struct app_pktq_kni_params *kni,
-				  uint32_t *pktq_out_id)
-{
-	struct app_pipeline_params *writer = NULL;
-	uint32_t pos = kni - app->kni_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_writers = 0, id = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_out = RTE_MIN(p->n_pktq_out,
-			RTE_DIM(p->pktq_out));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_out; j++) {
-			struct app_pktq_out_params *pktq = &p->pktq_out[j];
-
-			if ((pktq->type == APP_PKTQ_OUT_KNI) &&
-				(pktq->id == pos)) {
-				n_writers++;
-				writer = p;
-				id = j;
-			}
-		}
-	}
-
-	if (n_writers != 1)
-		return NULL;
-
-	*pktq_out_id = id;
-	return writer;
-}
-
-static inline uint32_t
-app_sink_get_writers(struct app_params *app, struct app_pktq_sink_params *sink)
-{
-	uint32_t pos = sink - app->sink_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_writers = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_out = RTE_MIN(p->n_pktq_out,
-			RTE_DIM(p->pktq_out));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_out; j++) {
-			struct app_pktq_out_params *pktq = &p->pktq_out[j];
-
-			if ((pktq->type == APP_PKTQ_OUT_SINK) &&
-				(pktq->id == pos))
-				n_writers++;
-		}
-	}
-
-	return n_writers;
-}
-
-static inline uint32_t
-app_msgq_get_writers(struct app_params *app, struct app_msgq_params *msgq)
-{
-	uint32_t pos = msgq - app->msgq_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_writers = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_msgq_out = RTE_MIN(p->n_msgq_out,
-			RTE_DIM(p->msgq_out));
-		uint32_t j;
-
-		for (j = 0; j < n_msgq_out; j++)
-			if (p->msgq_out[j] == pos)
-				n_writers++;
-	}
-
-	return n_writers;
-}
-
-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%" SCNu32 ".%" SCNu32,
-		&rxq_link_id, &rxq_queue_id);
-	sprintf(link_name, "LINK%" PRIu32, 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%" SCNu32 ".%" SCNu32,
-		&txq_link_id, &txq_queue_id);
-	sprintf(link_name, "LINK%" PRIu32, 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%" PRIu32, &link_id);
-	sprintf(link_name, "LINK%" PRIu32, 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];
-}
-
-static inline struct app_link_params *
-app_get_link_for_kni(struct app_params *app, struct app_pktq_kni_params *p_kni)
-{
-	char link_name[APP_PARAM_NAME_SIZE];
-	uint32_t link_id;
-	ssize_t link_param_idx;
-
-	sscanf(p_kni->name, "KNI%" PRIu32, &link_id);
-	sprintf(link_name, "LINK%" PRIu32, 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_kni->name);
-
-	return &app->link_params[link_param_idx];
-}
-
-static inline uint32_t
-app_core_is_enabled(struct app_params *app, uint32_t lcore_id)
-{
-	return(app->core_mask[lcore_id / 64] &
-		(1LLU << (lcore_id % 64)));
-}
-
-static inline void
-app_core_enable_in_core_mask(struct app_params *app, int lcore_id)
-{
-	app->core_mask[lcore_id / 64] |= 1LLU << (lcore_id % 64);
-
-}
-
-static inline void
-app_core_build_core_mask_string(struct app_params *app, char *mask_buffer)
-{
-	int i;
-
-	mask_buffer[0] = '\0';
-	for (i = (int)RTE_DIM(app->core_mask); i > 0; i--) {
-		/* For Hex representation of bits in uint64_t */
-		char buffer[(64 / 8) * 2 + 1];
-		memset(buffer, 0, sizeof(buffer));
-		snprintf(buffer, sizeof(buffer), "%016" PRIx64,
-			 app->core_mask[i-1]);
-		strcat(mask_buffer, buffer);
-	}
-}
-
-void app_pipeline_params_get(struct app_params *app,
-	struct app_pipeline_params *p_in,
-	struct pipeline_params *p_out);
-
-int app_config_init(struct app_params *app);
-
-int app_config_args(struct app_params *app,
-	int argc, char **argv);
-
-int app_config_preproc(struct app_params *app);
-
-int app_config_parse(struct app_params *app,
-	const char *file_name);
-
-int app_config_parse_tm(struct app_params *app);
-
-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_post_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/action.cfg b/examples/ip_pipeline/config/action.cfg
deleted file mode 100644
index 994ae94..0000000
--- a/examples/ip_pipeline/config/action.cfg
+++ /dev/null
@@ -1,68 +0,0 @@
-;   BSD LICENSE
-;
-;   Copyright(c) 2016 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.
-
-;             ________________
-; RXQ0.0 --->|                |---> TXQ0.0
-;            |                |
-; RXQ1.0 --->|                |---> TXQ1.0
-;            |      Flow      |
-; RXQ2.0 --->|     Actions    |---> TXQ2.0
-;            |                |
-; RXQ3.0 --->|                |---> TXQ3.0
-;            |________________|
-;
-;
-; Input packet: Ethernet/IPv4
-;
-; Packet buffer layout:
-; #	Field Name		Offset (Bytes)	Size (Bytes)
-; 0	Mbuf			0 		128
-; 1	Headroom		128 		128
-; 2	Ethernet header		256 		14
-; 3	IPv4 header		270 		20
-
-[EAL]
-log_level = 0
-
-[PIPELINE0]
-type = MASTER
-core = 0
-
-[PIPELINE1]
-type = FLOW_ACTIONS
-core = 1
-pktq_in = RXQ0.0 RXQ1.0 RXQ2.0 RXQ3.0
-pktq_out = TXQ0.0 TXQ1.0 TXQ2.0 TXQ3.0
-n_flows = 65536
-n_meters_per_flow = 4
-flow_id_offset = 286; ipdaddr
-ip_hdr_offset = 270
-color_offset = 128
diff --git a/examples/ip_pipeline/config/action.sh b/examples/ip_pipeline/config/action.sh
deleted file mode 100644
index 2986ae6..0000000
--- a/examples/ip_pipeline/config/action.sh
+++ /dev/null
@@ -1,119 +0,0 @@
-#
-# run ./config/action.sh
-#
-
-p 1 action flow 0 meter 0 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 0 policer 0 g G y Y r R
-p 1 action flow 0 meter 1 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 0 policer 1 g G y Y r R
-p 1 action flow 0 meter 2 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 0 policer 2 g G y Y r R
-p 1 action flow 0 meter 3 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 0 policer 3 g G y Y r R
-p 1 action flow 0 port 0
-
-p 1 action flow 1 meter 0 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 1 policer 0 g G y Y r R
-p 1 action flow 1 meter 1 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 1 policer 1 g G y Y r R
-p 1 action flow 1 meter 2 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 1 policer 2 g G y Y r R
-p 1 action flow 1 meter 3 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 1 policer 3 g G y Y r R
-p 1 action flow 1 port 1
-
-p 1 action flow 2 meter 0 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 2 policer 0 g G y Y r R
-p 1 action flow 2 meter 1 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 2 policer 1 g G y Y r R
-p 1 action flow 2 meter 2 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 2 policer 2 g G y Y r R
-p 1 action flow 2 meter 3 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 2 policer 3 g G y Y r R
-p 1 action flow 2 port 2
-
-p 1 action flow 3 meter 0 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 3 policer 0 g G y Y r R
-p 1 action flow 3 meter 1 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 3 policer 1 g G y Y r R
-p 1 action flow 3 meter 2 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 3 policer 2 g G y Y r R
-p 1 action flow 3 meter 3 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 3 policer 3 g G y Y r R
-p 1 action flow 3 port 3
-
-#p 1 action flow bulk ./config/action.txt
-
-#p 1 action flow ls
-
-p 1 action flow 0 stats
-p 1 action flow 1 stats
-p 1 action flow 2 stats
-p 1 action flow 3 stats
-
-p 1 action dscp 0 class 0 color G
-p 1 action dscp 1 class 1 color G
-p 1 action dscp 2 class 2 color G
-p 1 action dscp 3 class 3 color G
-p 1 action dscp 4 class 0 color G
-p 1 action dscp 5 class 1 color G
-p 1 action dscp 6 class 2 color G
-p 1 action dscp 7 class 3 color G
-p 1 action dscp 8 class 0 color G
-p 1 action dscp 9 class 1 color G
-p 1 action dscp 10 class 2 color G
-p 1 action dscp 11 class 3 color G
-p 1 action dscp 12 class 0 color G
-p 1 action dscp 13 class 1 color G
-p 1 action dscp 14 class 2 color G
-p 1 action dscp 15 class 3 color G
-p 1 action dscp 16 class 0 color G
-p 1 action dscp 17 class 1 color G
-p 1 action dscp 18 class 2 color G
-p 1 action dscp 19 class 3 color G
-p 1 action dscp 20 class 0 color G
-p 1 action dscp 21 class 1 color G
-p 1 action dscp 22 class 2 color G
-p 1 action dscp 23 class 3 color G
-p 1 action dscp 24 class 0 color G
-p 1 action dscp 25 class 1 color G
-p 1 action dscp 26 class 2 color G
-p 1 action dscp 27 class 3 color G
-p 1 action dscp 27 class 0 color G
-p 1 action dscp 29 class 1 color G
-p 1 action dscp 30 class 2 color G
-p 1 action dscp 31 class 3 color G
-p 1 action dscp 32 class 0 color G
-p 1 action dscp 33 class 1 color G
-p 1 action dscp 34 class 2 color G
-p 1 action dscp 35 class 3 color G
-p 1 action dscp 36 class 0 color G
-p 1 action dscp 37 class 1 color G
-p 1 action dscp 38 class 2 color G
-p 1 action dscp 39 class 3 color G
-p 1 action dscp 40 class 0 color G
-p 1 action dscp 41 class 1 color G
-p 1 action dscp 42 class 2 color G
-p 1 action dscp 43 class 3 color G
-p 1 action dscp 44 class 0 color G
-p 1 action dscp 45 class 1 color G
-p 1 action dscp 46 class 2 color G
-p 1 action dscp 47 class 3 color G
-p 1 action dscp 48 class 0 color G
-p 1 action dscp 49 class 1 color G
-p 1 action dscp 50 class 2 color G
-p 1 action dscp 51 class 3 color G
-p 1 action dscp 52 class 0 color G
-p 1 action dscp 53 class 1 color G
-p 1 action dscp 54 class 2 color G
-p 1 action dscp 55 class 3 color G
-p 1 action dscp 56 class 0 color G
-p 1 action dscp 57 class 1 color G
-p 1 action dscp 58 class 2 color G
-p 1 action dscp 59 class 3 color G
-p 1 action dscp 60 class 0 color G
-p 1 action dscp 61 class 1 color G
-p 1 action dscp 62 class 2 color G
-p 1 action dscp 63 class 3 color G
-
-p 1 action dscp ls
diff --git a/examples/ip_pipeline/config/action.txt b/examples/ip_pipeline/config/action.txt
deleted file mode 100644
index f14207b..0000000
--- a/examples/ip_pipeline/config/action.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-# p <pipelineid> action flow bulk ./config/action.txt
-#
-
-flow 0 meter 0 trtcm 1250000000 1250000000 1000000 1000000 policer 0 g G y Y r R meter 1 trtcm 1250000000 1250000000 1000000 1000000 policer 1 g G y Y r R meter 2 trtcm 1250000000 1250000000 1000000 1000000 policer 2 g G y Y r R meter 3 trtcm 1250000000 1250000000 1000000 1000000 policer 3 g G y Y r R port 0
-flow 1 meter 0 trtcm 1250000000 1250000000 1000000 1000000 policer 0 g G y Y r R meter 1 trtcm 1250000000 1250000000 1000000 1000000 policer 1 g G y Y r R meter 2 trtcm 1250000000 1250000000 1000000 1000000 policer 2 g G y Y r R meter 3 trtcm 1250000000 1250000000 1000000 1000000 policer 3 g G y Y r R port 1
-flow 2 meter 0 trtcm 1250000000 1250000000 1000000 1000000 policer 0 g G y Y r R meter 1 trtcm 1250000000 1250000000 1000000 1000000 policer 1 g G y Y r R meter 2 trtcm 1250000000 1250000000 1000000 1000000 policer 2 g G y Y r R meter 3 trtcm 1250000000 1250000000 1000000 1000000 policer 3 g G y Y r R port 2
-flow 3 meter 0 trtcm 1250000000 1250000000 1000000 1000000 policer 0 g G y Y r R meter 1 trtcm 1250000000 1250000000 1000000 1000000 policer 1 g G y Y r R meter 2 trtcm 1250000000 1250000000 1000000 1000000 policer 2 g G y Y r R meter 3 trtcm 1250000000 1250000000 1000000 1000000 policer 3 g G y Y r R port 3
diff --git a/examples/ip_pipeline/config/diagram-generator.py b/examples/ip_pipeline/config/diagram-generator.py
deleted file mode 100755
index d9efc75..0000000
--- a/examples/ip_pipeline/config/diagram-generator.py
+++ /dev/null
@@ -1,317 +0,0 @@
-#!/usr/bin/env python
-# SPDX-License-Identifier: BSD-3-Clause
-# Copyright(c) 2016 Intel Corporation
-
-#
-# This script creates a visual representation for a configuration file used by
-# the DPDK ip_pipeline application.
-#
-# The input configuration file is translated to an output file in DOT syntax,
-# which is then used to create the image file using graphviz
-# (www.graphviz.org).
-#
-
-from __future__ import print_function
-import argparse
-import re
-import os
-
-#
-# Command to generate the image file
-#
-DOT_COMMAND = 'dot -Gsize=20,30 -Tpng %s > %s'
-
-#
-# Layout of generated DOT file
-#
-DOT_INTRO = \
-    '#\n# Command to generate image file:\n# \t%s\n#\n\n'
-DOT_GRAPH_BEGIN = \
-    'digraph g {\n  graph [ splines = true rankdir = "LR" ]\n'
-DOT_NODE_LINK_RX = \
-    '  "%s RX" [ shape = box style = filled fillcolor = yellowgreen ]\n'
-DOT_NODE_LINK_TX = \
-    '  "%s TX" [ shape = box style = filled fillcolor = yellowgreen ]\n'
-DOT_NODE_KNI_RX = \
-    '  "%s RX" [ shape = box style = filled fillcolor = orange ]\n'
-DOT_NODE_KNI_TX = \
-    '  "%s TX" [ shape = box style = filled fillcolor = orange ]\n'
-DOT_NODE_TAP_RX = \
-    '  "%s RX" [ shape = box style = filled fillcolor = gold ]\n'
-DOT_NODE_TAP_TX = \
-    '  "%s TX" [ shape = box style = filled fillcolor = gold ]\n'
-DOT_NODE_SOURCE = \
-    '  "%s" [ shape = box style = filled fillcolor = darkgreen ]\n'
-DOT_NODE_SINK = \
-    '  "%s" [ shape = box style = filled fillcolor = peachpuff ]\n'
-DOT_NODE_PIPELINE = \
-    '  "%s" [ shape = box style = filled fillcolor = royalblue ]\n'
-DOT_EDGE_PKTQ = \
-    '  "%s" -> "%s" [ label = "%s" color = gray ]\n'
-DOT_GRAPH_END = \
-    '}\n'
-
-# Relationships between the graph nodes and the graph edges:
-#
-# Edge ID | Edge Label | Writer Node | Reader Node   | Dependencies
-# --------+------------+-------------+---------------+--------------
-# RXQx.y  | RXQx.y     | LINKx       | PIPELINEz     | LINKx
-# TXQx.y  | TXQx.y     | PIPELINEz   | LINKx         | LINKx
-# SWQx    | SWQx       | PIPELINEy   | PIPELINEz     | -
-# TMx     | TMx        | PIPELINEy   | PIPELINEz     | LINKx
-# KNIx RX | KNIx       | KNIx RX     | PIPELINEy     | KNIx, LINKx
-# KNIx TX | KNIx       | PIPELINEy   | KNIx TX       | KNIx, LINKx
-# TAPx RX | TAPx       | TAPx RX     | PIPELINEy     | TAPx
-# TAPx TX | TAPx       | PIPELINEy   | TAPx TX       | TAPx
-# SOURCEx | SOURCEx    | SOURCEx     | PIPELINEy     | SOURCEx
-# SINKx   | SINKx      | PIPELINEy   | SINKx         | SINKx
-
-
-#
-# Parse the input configuration file to detect the graph nodes and edges
-#
-def process_config_file(cfgfile):
-    edges = {}
-    links = set()
-    knis = set()
-    taps = set()
-    sources = set()
-    sinks = set()
-    pipelines = set()
-    pipeline = ''
-
-    dotfile = cfgfile + '.txt'
-    imgfile = cfgfile + '.png'
-
-    #
-    # Read configuration file
-    #
-    lines = open(cfgfile, 'r')
-    for line in lines:
-        # Remove any leading and trailing white space characters
-        line = line.strip()
-
-        # Remove any comment at end of line
-        line, sep, tail = line.partition(';')
-
-        # Look for next "PIPELINE" section
-        match = re.search(r'\[(PIPELINE\d+)\]', line)
-        if match:
-            pipeline = match.group(1)
-            continue
-
-        # Look for next "pktq_in" section entry
-        match = re.search(r'pktq_in\s*=\s*(.+)', line)
-        if match:
-            pipelines.add(pipeline)
-            for q in re.findall('\S+', match.group(1)):
-                match_rxq = re.search(r'^RXQ(\d+)\.\d+$', q)
-                match_swq = re.search(r'^SWQ\d+$', q)
-                match_tm = re.search(r'^TM(\d+)$', q)
-                match_kni = re.search(r'^KNI(\d+)$', q)
-                match_tap = re.search(r'^TAP\d+$', q)
-                match_source = re.search(r'^SOURCE\d+$', q)
-
-                # Set ID for the current packet queue (graph edge)
-                q_id = ''
-                if match_rxq or match_swq or match_tm or match_source:
-                    q_id = q
-                elif match_kni or match_tap:
-                    q_id = q + ' RX'
-                else:
-                    print('Error: Unrecognized pktq_in element "%s"' % q)
-                    return
-
-                # Add current packet queue to the set of graph edges
-                if q_id not in edges:
-                    edges[q_id] = {}
-                if 'label' not in edges[q_id]:
-                    edges[q_id]['label'] = q
-                if 'readers' not in edges[q_id]:
-                    edges[q_id]['readers'] = []
-                if 'writers' not in edges[q_id]:
-                    edges[q_id]['writers'] = []
-
-                # Add reader for the new edge
-                edges[q_id]['readers'].append(pipeline)
-
-                # Check for RXQ
-                if match_rxq:
-                    link = 'LINK' + str(match_rxq.group(1))
-                    edges[q_id]['writers'].append(link + ' RX')
-                    links.add(link)
-                    continue
-
-                # Check for SWQ
-                if match_swq:
-                    continue
-
-                # Check for TM
-                if match_tm:
-                    link = 'LINK' + str(match_tm.group(1))
-                    links.add(link)
-                    continue
-
-                # Check for KNI
-                if match_kni:
-                    link = 'LINK' + str(match_kni.group(1))
-                    edges[q_id]['writers'].append(q_id)
-                    knis.add(q)
-                    links.add(link)
-                    continue
-
-                # Check for TAP
-                if match_tap:
-                    edges[q_id]['writers'].append(q_id)
-                    taps.add(q)
-                    continue
-
-                # Check for SOURCE
-                if match_source:
-                    edges[q_id]['writers'].append(q)
-                    sources.add(q)
-                    continue
-
-                continue
-
-        # Look for next "pktq_out" section entry
-        match = re.search(r'pktq_out\s*=\s*(.+)', line)
-        if match:
-            for q in re.findall('\S+', match.group(1)):
-                match_txq = re.search(r'^TXQ(\d+)\.\d+$', q)
-                match_swq = re.search(r'^SWQ\d+$', q)
-                match_tm = re.search(r'^TM(\d+)$', q)
-                match_kni = re.search(r'^KNI(\d+)$', q)
-                match_tap = re.search(r'^TAP(\d+)$', q)
-                match_sink = re.search(r'^SINK(\d+)$', q)
-
-                # Set ID for the current packet queue (graph edge)
-                q_id = ''
-                if match_txq or match_swq or match_tm or match_sink:
-                    q_id = q
-                elif match_kni or match_tap:
-                    q_id = q + ' TX'
-                else:
-                    print('Error: Unrecognized pktq_out element "%s"' % q)
-                    return
-
-                # Add current packet queue to the set of graph edges
-                if q_id not in edges:
-                    edges[q_id] = {}
-                if 'label' not in edges[q_id]:
-                    edges[q_id]['label'] = q
-                if 'readers' not in edges[q_id]:
-                    edges[q_id]['readers'] = []
-                if 'writers' not in edges[q_id]:
-                    edges[q_id]['writers'] = []
-
-                # Add writer for the new edge
-                edges[q_id]['writers'].append(pipeline)
-
-                # Check for TXQ
-                if match_txq:
-                    link = 'LINK' + str(match_txq.group(1))
-                    edges[q_id]['readers'].append(link + ' TX')
-                    links.add(link)
-                    continue
-
-                # Check for SWQ
-                if match_swq:
-                    continue
-
-                # Check for TM
-                if match_tm:
-                    link = 'LINK' + str(match_tm.group(1))
-                    links.add(link)
-                    continue
-
-                # Check for KNI
-                if match_kni:
-                    link = 'LINK' + str(match_kni.group(1))
-                    edges[q_id]['readers'].append(q_id)
-                    knis.add(q)
-                    links.add(link)
-                    continue
-
-                # Check for TAP
-                if match_tap:
-                    edges[q_id]['readers'].append(q_id)
-                    taps.add(q)
-                    continue
-
-                # Check for SINK
-                if match_sink:
-                    edges[q_id]['readers'].append(q)
-                    sinks.add(q)
-                    continue
-
-                continue
-
-    #
-    # Write DOT file
-    #
-    print('Creating DOT file "%s" ...' % dotfile)
-    dot_cmd = DOT_COMMAND % (dotfile, imgfile)
-    file = open(dotfile, 'w')
-    file.write(DOT_INTRO % dot_cmd)
-    file.write(DOT_GRAPH_BEGIN)
-
-    # Write the graph nodes to the DOT file
-    for l in sorted(links):
-        file.write(DOT_NODE_LINK_RX % l)
-        file.write(DOT_NODE_LINK_TX % l)
-    for k in sorted(knis):
-        file.write(DOT_NODE_KNI_RX % k)
-        file.write(DOT_NODE_KNI_TX % k)
-    for t in sorted(taps):
-        file.write(DOT_NODE_TAP_RX % t)
-        file.write(DOT_NODE_TAP_TX % t)
-    for s in sorted(sources):
-        file.write(DOT_NODE_SOURCE % s)
-    for s in sorted(sinks):
-        file.write(DOT_NODE_SINK % s)
-    for p in sorted(pipelines):
-        file.write(DOT_NODE_PIPELINE % p)
-
-    # Write the graph edges to the DOT file
-    for q in sorted(edges.keys()):
-        rw = edges[q]
-        if 'writers' not in rw:
-            print('Error: "%s" has no writer' % q)
-            return
-        if 'readers' not in rw:
-            print('Error: "%s" has no reader' % q)
-            return
-        for w in rw['writers']:
-            for r in rw['readers']:
-                file.write(DOT_EDGE_PKTQ % (w, r, rw['label']))
-
-    file.write(DOT_GRAPH_END)
-    file.close()
-
-    #
-    # Execute the DOT command to create the image file
-    #
-    print('Creating image file "%s" ...' % imgfile)
-    if os.system('which dot > /dev/null'):
-        print('Error: Unable to locate "dot" executable.'
-              'Please install the "graphviz" package (www.graphviz.org).')
-        return
-
-    os.system(dot_cmd)
-
-
-if __name__ == '__main__':
-    parser = argparse.ArgumentParser(description='Create diagram for IP '
-                                                 'pipeline configuration '
-                                                 'file.')
-
-    parser.add_argument(
-        '-f',
-        '--file',
-        help='input configuration file (e.g. "ip_pipeline.cfg")',
-        required=True)
-
-    args = parser.parse_args()
-
-    process_config_file(args.file)
diff --git a/examples/ip_pipeline/config/edge_router_downstream.cfg b/examples/ip_pipeline/config/edge_router_downstream.cfg
deleted file mode 100644
index c6b4e1f..0000000
--- a/examples/ip_pipeline/config/edge_router_downstream.cfg
+++ /dev/null
@@ -1,97 +0,0 @@
-;   BSD LICENSE
-;
-;   Copyright(c) 2015-2016 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.
-
-
-;   An edge router typically sits between two networks such as the provider
-;   core network and the provider access network. A typical packet processing
-;   pipeline for the downstream traffic (i.e. traffic from core to access
-;   network) contains the following functional blocks: Packet RX & Routing,
-;   Traffic management and Packet TX. The input packets are assumed to be
-;   IPv4, while the output packets are Q-in-Q IPv4.
-;
-;  A simple implementation for this functional pipeline is presented below.
-;
-;                  Packet Rx &                Traffic Management               Packet Tx
-;                   Routing                    (Pass-Through)                (Pass-Through)
-;             _____________________  SWQ0  ______________________  SWQ4  _____________________
-; RXQ0.0 --->|                     |----->|                      |----->|                     |---> TXQ0.0
-;            |                     | SWQ1 |                      | SWQ5 |                     |
-; RXQ1.0 --->|                     |----->|                      |----->|                     |---> TXQ1.0
-;            |        (P1)         | SWQ2 |         (P2)         | SWQ6 |        (P3)         |
-; RXQ2.0 --->|                     |----->|                      |----->|                     |---> TXQ2.0
-;            |                     | SWQ3 |                      | SWQ7 |                     |
-; RXQ3.0 --->|                     |----->|                      |----->|                     |---> TXQ3.0
-;            |_____________________|      |______________________|      |_____________________|
-;                       |                  |  ^  |  ^  |  ^  |  ^
-;                       |                  |__|  |__|  |__|  |__|
-;                       +--> SINK0          TM0   TM1   TM2   TM3
-;                      (Default)
-;
-; Input packet: Ethernet/IPv4
-; Output packet: Ethernet/QinQ/IPv4
-;
-; Packet buffer layout:
-; #	Field Name		Offset (Bytes)	Size (Bytes)
-; 0	Mbuf			0 		128
-; 1	Headroom		128 		128
-; 2	Ethernet header		256 		14
-; 3	IPv4 header		270 		20
-
-[EAL]
-log_level = 0
-
-[PIPELINE0]
-type = MASTER
-core = 0
-
-[PIPELINE1]
-type = ROUTING
-core = 1
-pktq_in = RXQ0.0 RXQ1.0 RXQ2.0 RXQ3.0
-pktq_out = SWQ0 SWQ1 SWQ2 SWQ3 SINK0
-encap = ethernet_qinq
-qinq_sched = test
-ip_hdr_offset = 270
-
-[PIPELINE2]
-type = PASS-THROUGH
-core = 2
-pktq_in = SWQ0 SWQ1 SWQ2 SWQ3 TM0 TM1 TM2 TM3
-pktq_out = TM0 TM1 TM2 TM3 SWQ4 SWQ5 SWQ6 SWQ7
-
-[PIPELINE3]
-type = PASS-THROUGH
-core = 3
-pktq_in = SWQ4 SWQ5 SWQ6 SWQ7
-pktq_out = TXQ0.0 TXQ1.0 TXQ2.0 TXQ3.0
-
-[MEMPOOL0]
-pool_size = 2M
diff --git a/examples/ip_pipeline/config/edge_router_downstream.sh b/examples/ip_pipeline/config/edge_router_downstream.sh
deleted file mode 100644
index 67c3a0d..0000000
--- a/examples/ip_pipeline/config/edge_router_downstream.sh
+++ /dev/null
@@ -1,13 +0,0 @@
-#
-# run ./config/edge_router_downstream.sh
-#
-
-################################################################################
-# Routing: Ether QinQ, ARP off
-################################################################################
-p 1 route add default 4 #SINK0
-p 1 route add 0.0.0.0 10 port 0 ether a0:b0:c0:d0:e0:f0 qinq 256 257
-p 1 route add 0.64.0.0 10 port 1 ether a1:b1:c1:d1:e1:f1 qinq 258 259
-p 1 route add 0.128.0.0 10 port 2 ether a2:b2:c2:d2:e2:f2 qinq 260 261
-p 1 route add 0.192.0.0 10 port 3 ether a3:b3:c3:d3:e3:f3 qinq 262 263
-#p 1 route ls
diff --git a/examples/ip_pipeline/config/edge_router_upstream.cfg b/examples/ip_pipeline/config/edge_router_upstream.cfg
deleted file mode 100644
index dea42b9..0000000
--- a/examples/ip_pipeline/config/edge_router_upstream.cfg
+++ /dev/null
@@ -1,124 +0,0 @@
-;   BSD LICENSE
-;
-;   Copyright(c) 2015-2016 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.
-
-
-;   An edge router typically sits between two networks such as the provider
-;   core network and the provider access network. A typical packet processing
-;   pipeline for the upstream traffic (i.e. traffic from access to core
-;   network) contains the following functional blocks: Packet RX & Firewall,
-;   Flow classification, Metering, Routing and Packet TX. The input packets
-;   are assumed to be Q-in-Q IPv4, while the output packets are MPLS IPv4
-;  (with variable number of labels per route).
-;
-;   A simple implementation for this functional pipeline is presented below.
-;
-;             Packet RX &       Pass-Through    Flow Classification   Flow Actions         Routing
-:              Firewall
-;             __________  SWQ0   __________  SWQ4   __________  SWQ8   __________  SWQ12  __________
-; RXQ0.0 --->|          |------>|          |------>|          |------>|          |------>|          |------> TXQ0.0
-;            |          | SWQ1  |          | SWQ5  |          | SWQ9  |          | SWQ13 |          |
-; RXQ1.0 --->|          |------>|          |------>|          |------>|          |------>|          |------> TXQ1.0
-;            |   (P1)   | SWQ2  |  (P2)    | SWQ6  |   (P3)   | SWQ10 |   (P4)   | SWQ14 |   (P5)   |
-; RXQ2.0 --->|          |------>|          |------>|          |------>|          |------>|          |------> TXQ2.0
-;            |          | SWQ3  |          | SWQ7  |          | SWQ11 |          | SWQ15 |          |
-; RXQ3.0 --->|          |------>|          |------>|          |------>|          |------>|          |------> TXQ3.0
-;            |__________|       |__________|       |__________|       |__________|       |__________|
-;                 |                                     |                                     |
-;                 +--> SINK0 (Default)                  +--> SINK1 (Default)                  +--> SINK2 (Default)
-;
-; Input packet: Ethernet/QinQ/IPv4
-; Output packet: Ethernet/MPLS/IPv4
-;
-; Packet buffer layout:
-; #	Field Name		Offset (Bytes)	Size (Bytes)
-; 0	Mbuf			0 		128
-; 1	Headroom		128 		128
-; 2	Ethernet header		256 		14
-; 3     QinQ header             270             8
-; 4	IPv4 header		278 		20
-
-[EAL]
-log_level = 0
-
-[PIPELINE0]
-type = MASTER
-core = 0
-
-[PIPELINE1]
-type = FIREWALL
-core = 1
-pktq_in = RXQ0.0 RXQ1.0 RXQ2.0 RXQ3.0
-pktq_out = SWQ0 SWQ1 SWQ2 SWQ3 SINK0
-n_rules = 4096
-pkt_type = qinq_ipv4
-
-[PIPELINE2]
-type = PASS-THROUGH
-core = 2
-pktq_in = SWQ0 SWQ1 SWQ2 SWQ3
-pktq_out = SWQ4 SWQ5 SWQ6 SWQ7
-dma_size = 8
-dma_dst_offset = 128
-dma_src_offset = 268; 1st Ethertype offset
-dma_src_mask = 00000FFF00000FFF; qinq
-dma_hash_offset = 136; dma_dst_offset + dma_size
-
-[PIPELINE3]
-type = FLOW_CLASSIFICATION
-core = 2
-pktq_in = SWQ4 SWQ5 SWQ6 SWQ7
-pktq_out = SWQ8 SWQ9 SWQ10 SWQ11 SINK1
-n_flows = 65536
-key_size = 8; dma_size
-key_offset = 128; dma_dst_offset
-hash_offset = 136; dma_hash_offset
-flowid_offset = 192
-
-[PIPELINE4]
-type = FLOW_ACTIONS
-core = 3
-pktq_in = SWQ8 SWQ9 SWQ10 SWQ11
-pktq_out = SWQ12 SWQ13 SWQ14 SWQ15
-n_flows = 65536
-n_meters_per_flow = 1
-flow_id_offset = 192; flowid_offset
-ip_hdr_offset = 278
-color_offset = 196; flowid_offset + sizeof(flow_id)
-
-[PIPELINE5]
-type = ROUTING
-core = 4
-pktq_in = SWQ12 SWQ13 SWQ14 SWQ15
-pktq_out = TXQ0.0 TXQ1.0 TXQ2.0 TXQ3.0 SINK2
-encap = ethernet_mpls
-mpls_color_mark = yes
-ip_hdr_offset = 278
-color_offset = 196; flowid_offset + sizeof(flow_id)
diff --git a/examples/ip_pipeline/config/edge_router_upstream.sh b/examples/ip_pipeline/config/edge_router_upstream.sh
deleted file mode 100644
index 5d574c1..0000000
--- a/examples/ip_pipeline/config/edge_router_upstream.sh
+++ /dev/null
@@ -1,33 +0,0 @@
-#
-# run ./config/edge_router_upstream.sh
-#
-
-################################################################################
-# Firewall
-################################################################################
-p 1 firewall add default 4 #SINK0
-p 1 firewall add bulk ./config/edge_router_upstream_firewall.txt
-#p 1 firewall ls
-
-################################################################################
-# Flow Classification
-################################################################################
-p 3 flow add default 4 #SINK1
-p 3 flow add qinq bulk ./config/edge_router_upstream_flow.txt
-#p 3 flow ls
-
-################################################################################
-# Flow Actions - Metering and Policing
-################################################################################
-p 4 action flow bulk ./config/edge_router_upstream_action.txt
-#p 4 action flow ls
-
-################################################################################
-# Routing: Ether MPLS, ARP off
-################################################################################
-p 5 route add default 4 #SINK2
-p 5 route add 0.0.0.0 10 port 0 ether a0:b0:c0:d0:e0:f0 mpls 0:1
-p 5 route add 0.64.0.0 10 port 1 ether a1:b1:c1:d1:e1:f1 mpls 10:11
-p 5 route add 0.128.0.0 10 port 2 ether a2:b2:c2:d2:e2:f2 mpls 20:21
-p 5 route add 0.192.0.0 10 port 3 ether a3:b3:c3:d3:e3:f3 mpls 30:31
-#p 5 route ls
diff --git a/examples/ip_pipeline/config/firewall.cfg b/examples/ip_pipeline/config/firewall.cfg
deleted file mode 100644
index 2f5dd9f..0000000
--- a/examples/ip_pipeline/config/firewall.cfg
+++ /dev/null
@@ -1,68 +0,0 @@
-;   BSD LICENSE
-;
-;   Copyright(c) 2015-2016 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.
-
-;             _______________
-; RXQ0.0 --->|               |---> TXQ0.0
-;            |               |
-; RXQ1.0 --->|               |---> TXQ1.0
-;            |   Firewall    |
-; RXQ2.0 --->|               |---> TXQ2.0
-;            |               |
-; RXQ3.0 --->|               |---> TXQ3.0
-;            |_______________|
-;                    |
-;                    +-----------> SINK0 (default rule)
-;
-; Input packet: Ethernet/IPv4
-;
-; Packet buffer layout:
-; #	Field Name		Offset (Bytes)	Size (Bytes)
-; 0	Mbuf			0 		128
-; 1	Headroom		128 		128
-; 2	Ethernet header		256 		14
-; 3	IPv4 header		270 		20
-
-[EAL]
-log_level = 0
-
-[PIPELINE0]
-type = MASTER
-core = 0
-
-[PIPELINE1]
-type = FIREWALL
-core = 1
-pktq_in = RXQ0.0 RXQ1.0 RXQ2.0 RXQ3.0
-pktq_out = TXQ0.0 TXQ1.0 TXQ2.0 TXQ3.0 SINK0
-n_rules = 4096
-pkt_type = ipv4
-;pkt_type = vlan_ipv4
-;pkt_type = qinq_ipv4
diff --git a/examples/ip_pipeline/config/firewall.sh b/examples/ip_pipeline/config/firewall.sh
deleted file mode 100644
index c83857e..0000000
--- a/examples/ip_pipeline/config/firewall.sh
+++ /dev/null
@@ -1,13 +0,0 @@
-#
-# run ./config/firewall.sh
-#
-
-p 1 firewall add default 4 #SINK0
-p 1 firewall add priority 1 ipv4 0.0.0.0 0 100.0.0.0 10 0 65535 0 65535 6 0xF port 0
-p 1 firewall add priority 1 ipv4 0.0.0.0 0 100.64.0.0 10 0 65535 0 65535 6 0xF port 1
-p 1 firewall add priority 1 ipv4 0.0.0.0 0 100.128.0.0 10 0 65535 0 65535 6 0xF port 2
-p 1 firewall add priority 1 ipv4 0.0.0.0 0 100.192.0.0 10 0 65535 0 65535 6 0xF port 3
-
-#p 1 firewall add bulk ./config/firewall.txt
-
-p 1 firewall ls
diff --git a/examples/ip_pipeline/config/firewall.txt b/examples/ip_pipeline/config/firewall.txt
deleted file mode 100644
index 54cfffd..0000000
--- a/examples/ip_pipeline/config/firewall.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# p <pipelineid> firewall add bulk ./config/firewall.txt
-# p <pipelineid> firewall del bulk ./config/firewall.txt
-#
-
-priority 1 ipv4 0.0.0.0 0 100.0.0.0 10 0 65535 0 65535 6 0xF port 0
-priority 1 ipv4 0.0.0.0 0 100.64.0.0 10 0 65535 0 65535 6 0xF port 1
-priority 1 ipv4 0.0.0.0 0 100.128.0.0 10 0 65535 0 65535 6 0xF port 2
-priority 1 ipv4 0.0.0.0 0 100.192.0.0 10 0 65535 0 65535 6 0xF port 3
diff --git a/examples/ip_pipeline/config/flow.cfg b/examples/ip_pipeline/config/flow.cfg
deleted file mode 100644
index cec990a..0000000
--- a/examples/ip_pipeline/config/flow.cfg
+++ /dev/null
@@ -1,72 +0,0 @@
-;   BSD LICENSE
-;
-;   Copyright(c) 2015-2016 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.
-
-;             ________________
-; RXQ0.0 --->|                |---> TXQ0.0
-;            |                |
-; RXQ1.0 --->|                |---> TXQ1.0
-;            |      Flow      |
-; RXQ2.0 --->| Classification |---> TXQ2.0
-;            |                |
-; RXQ3.0 --->|                |---> TXQ3.0
-;            |________________|
-;                    |
-;                    +-----------> SINK0 (flow lookup miss)
-;
-; Input packet: Ethernet/IPv4
-;
-; Packet buffer layout:
-; #	Field Name		Offset (Bytes)	Size (Bytes)
-; 0	Mbuf			0		128
-; 1	Headroom		128 		128
-; 2	Ethernet header		256 		14
-; 3	QinQ/IPv4/IPv6 header	270 		8/20/40
-
-[EAL]
-log_level = 0
-
-[PIPELINE0]
-type = MASTER
-core = 0
-
-[PIPELINE1]
-type = FLOW_CLASSIFICATION
-core = 1
-pktq_in = RXQ0.0 RXQ1.0 RXQ2.0 RXQ3.0
-pktq_out = TXQ0.0 TXQ1.0 TXQ2.0 TXQ3.0 SINK0
-n_flows = 65536
-;key_size = 8                ; QinQ key size
-;key_offset = 268            ; QinQ key offset
-;key_mask = 00000FFF00000FFF ; QinQ key mask
-key_size = 16                               ; IPv4 5-tuple key size
-key_offset = 278                            ; IPv4 5-tuple key offset
-key_mask = 00FF0000FFFFFFFFFFFFFFFFFFFFFFFF ; IPv4 5-tuple key mask
-flowid_offset = 128
diff --git a/examples/ip_pipeline/config/flow.sh b/examples/ip_pipeline/config/flow.sh
deleted file mode 100644
index 489c707..0000000
--- a/examples/ip_pipeline/config/flow.sh
+++ /dev/null
@@ -1,25 +0,0 @@
-#
-# run ./config/flow.sh
-#
-
-################################################################################
-# Flow classification (QinQ)
-################################################################################
-#p 1 flow add default 4 #SINK0
-#p 1 flow add qinq 100 200 port 0 id 0
-#p 1 flow add qinq 101 201 port 1 id 1
-#p 1 flow add qinq 102 202 port 2 id 2
-#p 1 flow add qinq 103 203 port 3 id 3
-
-#p 1 flow add qinq bulk ./config/flow.txt
-
-################################################################################
-# Flow classification (IPv4 5-tuple)
-################################################################################
-p 1 flow add default 4 #SINK0
-p 1 flow add ipv4 100.0.0.10 200.0.0.10 100 200 6 port 0 id 0
-p 1 flow add ipv4 100.0.0.11 200.0.0.11 101 201 6 port 1 id 1
-p 1 flow add ipv4 100.0.0.12 200.0.0.12 102 202 6 port 2 id 2
-p 1 flow add ipv4 100.0.0.13 200.0.0.13 103 203 6 port 3 id 3
-
-#p 1 flow add ipv4 bulk ./config/flow.txt
diff --git a/examples/ip_pipeline/config/flow.txt b/examples/ip_pipeline/config/flow.txt
deleted file mode 100644
index c1a141d..0000000
--- a/examples/ip_pipeline/config/flow.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-#
-# p <pipelineid> flow add qinq bulk ./config/flow.txt
-#
-
-#qinq 100 200 port 0 id 0
-#qinq 101 201 port 1 id 1
-#qinq 102 202 port 2 id 2
-#qinq 103 203 port 3 id 3
-
-#
-# p <pipelineid> flow add ipv4 bulk ./config/flow.txt
-#
-
-ipv4 100.0.0.10 200.0.0.10 100 200 6 port 0 id 0
-ipv4 100.0.0.11 200.0.0.11 101 201 6 port 1 id 1
-ipv4 100.0.0.12 200.0.0.12 102 202 6 port 2 id 2
-ipv4 100.0.0.13 200.0.0.13 103 203 6 port 3 id 3
diff --git a/examples/ip_pipeline/config/ip_pipeline.cfg b/examples/ip_pipeline/config/ip_pipeline.cfg
deleted file mode 100644
index 095ed25..0000000
--- a/examples/ip_pipeline/config/ip_pipeline.cfg
+++ /dev/null
@@ -1,9 +0,0 @@
-[PIPELINE0]
-type = MASTER
-core = 0
-
-[PIPELINE1]
-type = PASS-THROUGH
-core = 1
-pktq_in = RXQ0.0 RXQ1.0 RXQ2.0 RXQ3.0
-pktq_out = TXQ0.0 TXQ1.0 TXQ2.0 TXQ3.0
diff --git a/examples/ip_pipeline/config/ip_pipeline.sh b/examples/ip_pipeline/config/ip_pipeline.sh
deleted file mode 100644
index 4fca259..0000000
--- a/examples/ip_pipeline/config/ip_pipeline.sh
+++ /dev/null
@@ -1,5 +0,0 @@
-#
-#run config/ip_pipeline.sh
-#
-
-p 1 ping
diff --git a/examples/ip_pipeline/config/kni.cfg b/examples/ip_pipeline/config/kni.cfg
deleted file mode 100644
index cea208b..0000000
--- a/examples/ip_pipeline/config/kni.cfg
+++ /dev/null
@@ -1,67 +0,0 @@
-;   BSD LICENSE
-;
-;   Copyright(c) 2016 Intel Corporation.
-;   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.
-;
-;             ______________          ______________________
-;            |              |  KNI0  |                      |
-; RXQ0.0 --->|              |------->|--+                   |
-;            |              |  KNI1  |  | br0               |
-; TXQ1.0 <---|              |<-------|<-+                   |
-;            | Pass-through |        |     Linux Kernel     |
-;            |     (P1)     |        |     Network Stack    |
-;            |              |  KNI1  |                      |
-; RXQ1.0 --->|              |------->|--+                   |
-;            |              |  KNI0  |  | br0               |
-; TXQ0.0 <---|              |<-------|<-+                   |
-;            |______________|        |______________________|
-;
-; Insert Linux kernel KNI module:
-;    [Linux]$ insmod rte_kni.ko
-;
-; Configure Linux kernel bridge between KNI0 and KNI1 interfaces:
-;    [Linux]$ ifconfig KNI0 up
-;    [Linux]$ ifconfig KNI1 up
-;    [Linux]$ brctl addbr "br0"
-;    [Linux]$ brctl addif br0 KNI0
-;    [Linux]$ brctl addif br0 KNI1
-;    [Linux]$ ifconfig br0 up
-
-[EAL]
-log_level = 0
-
-[PIPELINE0]
-type = MASTER
-core = 0
-
-[PIPELINE1]
-type = PASS-THROUGH
-core = 1
-pktq_in = RXQ0.0 KNI1 RXQ1.0 KNI0
-pktq_out = KNI0 TXQ1.0 KNI1 TXQ0.0
diff --git a/examples/ip_pipeline/config/l2fwd.cfg b/examples/ip_pipeline/config/l2fwd.cfg
deleted file mode 100644
index a1df9e6..0000000
--- a/examples/ip_pipeline/config/l2fwd.cfg
+++ /dev/null
@@ -1,58 +0,0 @@
-;   BSD LICENSE
-;
-;   Copyright(c) 2015-2016 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.
-
-;
-; The pass-through pipeline below connects the input ports to the output ports
-; as follows: RXQ0.0 -> TXQ1.0, RXQ1.0 -> TXQ0.0, RXQ2.0 -> TXQ3.0 and
-; RXQ3.0 -> TXQ2.0.
-;             ________________
-; RXQ0.0 --->|................|---> TXQ1.0
-;            |                |
-; RXQ1.0 --->|................|---> TXQ0.0
-;            |  Pass-through  |
-; RXQ2.0 --->|................|---> TXQ3.0
-;            |                |
-; RXQ3.0 --->|................|---> TXQ2.0
-;            |________________|
-;
-
-[EAL]
-log_level = 0
-
-[PIPELINE0]
-type = MASTER
-core = 0
-
-[PIPELINE1]
-type = PASS-THROUGH
-core = 1
-pktq_in = RXQ0.0 RXQ1.0 RXQ2.0 RXQ3.0
-pktq_out = TXQ1.0 TXQ0.0 TXQ3.0 TXQ2.0
diff --git a/examples/ip_pipeline/config/l3fwd.cfg b/examples/ip_pipeline/config/l3fwd.cfg
deleted file mode 100644
index 02c8f36..0000000
--- a/examples/ip_pipeline/config/l3fwd.cfg
+++ /dev/null
@@ -1,68 +0,0 @@
-;   BSD LICENSE
-;
-;   Copyright(c) 2015-2016 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.
-
-;             _______________
-; RXQ0.0 --->|               |---> TXQ0.0
-;            |               |
-; RXQ1.0 --->|               |---> TXQ1.0
-;            |    Routing    |
-; RXQ2.0 --->|               |---> TXQ2.0
-;            |               |
-; RXQ3.0 --->|               |---> TXQ3.0
-;            |_______________|
-;                    |
-;                    +-----------> SINK0 (route miss)
-;
-; Input packet: Ethernet/IPv4
-;
-; Packet buffer layout:
-; #	Field Name		Offset (Bytes)	Size (Bytes)
-; 0	Mbuf			0 		128
-; 1	Headroom		128 		128
-; 2	Ethernet header		256 		14
-; 3	IPv4 header		270 		20
-
-[EAL]
-log_level = 0
-
-[PIPELINE0]
-type = MASTER
-core = 0
-
-[PIPELINE1]
-type = ROUTING
-core = 1
-pktq_in = RXQ0.0 RXQ1.0 RXQ2.0 RXQ3.0
-pktq_out = TXQ0.0 TXQ1.0 TXQ2.0 TXQ3.0 SINK0
-encap = ethernet
-;encap = ethernet_qinq
-;encap = ethernet_mpls
-ip_hdr_offset = 270
diff --git a/examples/ip_pipeline/config/l3fwd.sh b/examples/ip_pipeline/config/l3fwd.sh
deleted file mode 100644
index 47406aa..0000000
--- a/examples/ip_pipeline/config/l3fwd.sh
+++ /dev/null
@@ -1,33 +0,0 @@
-#
-# run ./config/l3fwd.sh
-#
-
-################################################################################
-# Routing: encap = ethernet, arp = off
-################################################################################
-p 1 route add default 4 #SINK0
-p 1 route add 100.0.0.0 10 port 0 ether a0:b0:c0:d0:e0:f0
-p 1 route add 100.64.0.0 10 port 1 ether a1:b1:c1:d1:e1:f1
-p 1 route add 100.128.0.0 10 port 2 ether a2:b2:c2:d2:e2:f2
-p 1 route add 100.192.0.0 10 port 3 ether a3:b3:c3:d3:e3:f3
-p 1 route ls
-
-################################################################################
-# Routing: encap = ethernet_qinq, arp = off
-################################################################################
-#p 1 route add default 4 #SINK0
-#p 1 route add 100.0.0.0 10 port 0 ether a0:b0:c0:d0:e0:f0 qinq 1000 2000
-#p 1 route add 100.64.0.0 10 port 1 ether a1:b1:c1:d1:e1:f1 qinq 1001 2001
-#p 1 route add 100.128.0.0 10 port 2 ether a2:b2:c2:d2:e2:f2 qinq 1002 2002
-#p 1 route add 100.192.0.0 10 port 3 ether a3:b3:c3:d3:e3:f3 qinq 1003 2003
-#p 1 route ls
-
-################################################################################
-# Routing: encap = ethernet_mpls, arp = off
-################################################################################
-#p 1 route add default 4 #SINK0
-#p 1 route add 100.0.0.0 10 port 0 ether a0:b0:c0:d0:e0:f0 mpls 1000:2000
-#p 1 route add 100.64.0.0 10 port 1 ether a1:b1:c1:d1:e1:f1 mpls 1001:2001
-#p 1 route add 100.128.0.0 10 port 2 ether a2:b2:c2:d2:e2:f2 mpls 1002:2002
-#p 1 route add 100.192.0.0 10 port 3 ether a3:b3:c3:d3:e3:f3 mpls 1003:2003
-#p 1 route ls
diff --git a/examples/ip_pipeline/config/l3fwd_arp.cfg b/examples/ip_pipeline/config/l3fwd_arp.cfg
deleted file mode 100644
index 2c63c8f..0000000
--- a/examples/ip_pipeline/config/l3fwd_arp.cfg
+++ /dev/null
@@ -1,70 +0,0 @@
-;   BSD LICENSE
-;
-;   Copyright(c) 2015-2016 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.
-
-;             _______________
-; RXQ0.0 --->|               |---> TXQ0.0
-;            |               |
-; RXQ1.0 --->|               |---> TXQ1.0
-;            |    Routing    |
-; RXQ2.0 --->|               |---> TXQ2.0
-;            |               |
-; RXQ3.0 --->|               |---> TXQ3.0
-;            |_______________|
-;                    |
-;                    +-----------> SINK0 (route miss)
-;
-; Input packet: Ethernet/IPv4
-;
-; Packet buffer layout:
-; #	Field Name		Offset (Bytes)	Size (Bytes)
-; 0	Mbuf			0 		128
-; 1	Headroom		128 		128
-; 2	Ethernet header		256 		14
-; 3	IPv4 header		270 		20
-
-[EAL]
-log_level = 0
-
-[PIPELINE0]
-type = MASTER
-core = 0
-
-[PIPELINE1]
-type = ROUTING
-core = 1
-pktq_in = RXQ0.0 RXQ1.0 RXQ2.0 RXQ3.0
-pktq_out = TXQ0.0 TXQ1.0 TXQ2.0 TXQ3.0 SINK0
-encap = ethernet
-;encap = ethernet_qinq
-;encap = ethernet_mpls
-n_arp_entries = 1024
-ip_hdr_offset = 270
-arp_key_offset = 128
diff --git a/examples/ip_pipeline/config/l3fwd_arp.sh b/examples/ip_pipeline/config/l3fwd_arp.sh
deleted file mode 100644
index 20bea58..0000000
--- a/examples/ip_pipeline/config/l3fwd_arp.sh
+++ /dev/null
@@ -1,43 +0,0 @@
-#
-# run ./config/l3fwd_arp.sh
-#
-
-################################################################################
-# ARP
-################################################################################
-p 1 arp add default 4 #SINK0
-p 1 arp add 0 10.0.0.1 a0:b0:c0:d0:e0:f0
-p 1 arp add 1 11.0.0.1 a1:b1:c1:d1:e1:f1
-p 1 arp add 2 12.0.0.1 a2:b2:c2:d2:e2:f2
-p 1 arp add 3 13.0.0.1 a3:b3:c3:d3:e3:f3
-p 1 arp ls
-
-################################################################################
-# Routing: encap = ethernet, arp = on
-################################################################################
-p 1 route add default 4 #SINK0
-p 1 route add 100.0.0.0 10 port 0 ether 10.0.0.1
-p 1 route add 100.64.0.0 10 port 1 ether 11.0.0.1
-p 1 route add 100.128.0.0 10 port 2 ether 12.0.0.1
-p 1 route add 100.192.0.0 10 port 3 ether 13.0.0.1
-p 1 route ls
-
-################################################################################
-# Routing: encap = ethernet_qinq, arp = on
-################################################################################
-#p 1 route add default 4 #SINK0
-#p 1 route add 100.0.0.0 10 port 0 ether 10.0.0.1 qinq 1000 2000
-#p 1 route add 100.64.0.0 10 port 1 ether 11.0.0.1 qinq 1001 2001
-#p 1 route add 100.128.0.0 10 port 2 ether 12.0.0.1 qinq 1002 2002
-#p 1 route add 100.192.0.0 10 port 3 ether 13.0.0.1 qinq 1003 2003
-#p 1 route ls
-
-################################################################################
-# Routing: encap = ethernet_mpls, arp = on
-################################################################################
-#p 1 route add default 4 #SINK0
-#p 1 route add 100.0.0.0 10 port 0 ether 10.0.0.1 mpls 1000:2000
-#p 1 route add 100.64.0.0 10 port 1 ether 11.0.0.1 mpls 1001:2001
-#p 1 route add 100.128.0.0 10 port 2 ether 12.0.0.1 mpls 1002:2002
-#p 1 route add 100.192.0.0 10 port 3 ether 13.0.0.1 mpls 1003:2003
-#p 1 route ls
diff --git a/examples/ip_pipeline/config/network_layers.cfg b/examples/ip_pipeline/config/network_layers.cfg
deleted file mode 100644
index 397b5d7..0000000
--- a/examples/ip_pipeline/config/network_layers.cfg
+++ /dev/null
@@ -1,227 +0,0 @@
-;   BSD LICENSE
-;
-;   Copyright(c) 2016 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.
-
-; The diagram below shows how additional protocol components can be plugged into
-; the IP layer implemented by the ip_pipeline application. Pick your favorite
-; open source components for dynamic ARP, ICMP, UDP or TCP termination, etc and
-; connect them through SWQs to the IP infrastructure.
-;
-; The input packets with local destination are sent to the UDP/TCP applications
-; while the input packets with remote destination are routed back to the
-; network. Additional features can easily be added to this setup:
-;  * IP Reassembly: add SWQs with IP reassembly enabled (typically required for
-;    the input traffic with local destination);
-;  * IP Fragmentation: add SWQs with IP fragmentation enabled (typically
-;    required to enforce the MTU for the routed output traffic);
-;  * Traffic Metering: add Flow Action pipeline instances (e.g. for metering the
-;    TCP connections or ICMP input traffic);
-;  * Traffic Management: add TMs for the required output LINKs;
-;  * Protocol encapsulations (QinQ, MPLS) for the output packets: part of the
-;    routing pipeline configuration.
-;
-;                     _________                       _________
-;                    |         |                     |         |
-;                    |   UDP   |                     |   TCP   |
-;                    |   App   |                     |   App   |
-;                    |_________|                     |_________|
-;                       ^   |                           ^   |
-;                     __|___V__                       __|___V__
-;                    |         |  SWQ0 (UDP TX)      |         |  SWQ1 (TCP TX)
-;                    |   UDP   |-------+             |   TCP   |------------+
-;                    |         |       |             |         |            |
-;                    |_________|       |             |_________|            |
-;                         ^            |                  ^                 |
-;                         | SWQ2       |                  | SWQ3            |
-;                         | (UDP RX)   |                  | (TCP RX)        |
-;                     ____|____        |              ____|____             |
-;                    |         |       |             |         |            |
-; RXQ<0..3>.1 ------>|Firewall +--->|  |     +------>|  Flow   +--->|       |
-; (UDP local dest)   |  (P2)   | SINK0 |     |       |  (P3)   |  SINK1     |
-;                    |_________| (Deny)|     |       |_________|  (RST)     |
-; RXQ<0..3>.2 -------------------------|-----+                              |
-; (TCP local dest)                     |                                    |
-;                                      |     +------------------------------+
-;                                      |     |
-;                                     _V_____V_
-;                                    |         |
-;                                    | Routing |                   TXQ<0..3>.0
-; RXQ<0..3>.0 ---------------------->|  & ARP  +----------------------------->
-; (IP remote dest)                   |  (P1)   |
-;                                    |_________|
-;                                      |  ^  |
-;                   SWQ4 +-------------+  |  |  SWQ5 (ARP miss)
-;           (Route miss) |                |  +------------+
-;                        |  +-------------+               |
-;                     ___V__|__   SWQ6                ____V____
-;                    |         |  (ICMP TX)          |         |   TXQ<0..3>.1
-; RXQ<0..3>.3 ------>|  ICMP   |             +------>| Dyn ARP +------------->
-; (IP local dest)    |         |             |       |         |
-;                    |_________|             |       |_________|
-; RXQ<0..3>.4 -------------------------------+
-; (ARP)
-;
-; This configuration file implements the diagram presented below, where the
-; dynamic ARP, ICMP, UDP and TCP components have been stubbed out and replaced
-; with loop-back and packet drop devices.
-;
-;                     _________                       _________
-;                    |         |  SWQ0 (UDP TX)      |         |  SWQ1 (TCP TX)
-;                    |Loobpack |-------+             |Loopback |------------+
-;                    |  (P4)   |       |             |  (P5)   |            |
-;                    |_________|       |             |_________|            |
-;                         ^            |                  ^                 |
-;                         | SWQ2       |                  | SWQ3            |
-;                         | (UDP RX)   |                  | (TCP RX)        |
-;                     ____|____        |              ____|____             |
-;                    |         |       |             |         |            |
-; RXQ<0..3>.1 ------>|Firewall +--->|  |     +------>|  Flow   +--->|       |
-; (UDP local dest)   |  (P2)   | SINK0 |     |       |  (P3)   |  SINK1     |
-;                    |_________| (Deny)|     |       |_________|  (RST)     |
-; RXQ<0..3>.2 -------------------------|-----+                              |
-; (TCP local dest)                     |                                    |
-;                                      |     +------------------------------+
-;                                      |     |
-;                                     _V_____V_
-;                                    |         |
-;                                    | Routing |                   TXQ<0..3>.0
-; RXQ<0..3>.0 ---------------------->|  & ARP  +----------------------------->
-; (IP remote dest)                   |  (P1)   |
-;                                    |_________|
-;                                      |     |
-;                           SINK2 |<---+     +--->| SINK3
-;                           (Route miss)            (ARP miss)
-;
-;                     _________                            _________
-;                    |         |                          |         |
-; RXQ<0..3>.3 ------>|  Drop   +--->| SINK<4..7>  +------>|  Drop   +--->| SINK<8..11>
-; (IP local dest)    |  (P6)   | (IP local dest)  |       |  (P7)   |     (ARP)
-;                    |_________|                  |       |_________|
-; RXQ<0..3>.4 ------------------------------------+
-; (ARP)
-;
-;
-; Input packet: Ethernet/IPv4 or Ethernet/ARP
-; Output packet: Ethernet/IPv4 or Ethernet/ARP
-;
-; Packet buffer layout (for input IPv4 packets):
-; #	Field Name			Offset (Bytes)	Size (Bytes)
-; 0	Mbuf				0				128
-; 1	Headroom			128				128
-; 2	Ethernet header		256				14
-; 3	IPv4 header			270				20
-; 4	ICMP/UDP/TCP header	290				8/8/20
-
-[EAL]
-log_level = 0
-
-[LINK0]
-udp_local_q = 1
-tcp_local_q = 2
-ip_local_q = 3
-arp_q = 4
-
-[LINK1]
-udp_local_q = 1
-tcp_local_q = 2
-ip_local_q = 3
-arp_q = 4
-
-[LINK2]
-udp_local_q = 1
-tcp_local_q = 2
-ip_local_q = 3
-arp_q = 4
-
-[LINK3]
-udp_local_q = 1
-tcp_local_q = 2
-ip_local_q = 3
-arp_q = 4
-
-[PIPELINE0]
-type = MASTER
-core = 0
-
-[PIPELINE1]
-type = ROUTING
-core = 1
-pktq_in = RXQ0.0 RXQ1.0 RXQ2.0 RXQ3.0 SWQ0 SWQ1
-pktq_out = TXQ0.0 TXQ1.0 TXQ2.0 TXQ3.0 SINK2 SINK3
-port_local_dest = 4 ; SINK2 (Drop)
-n_arp_entries = 1000
-ip_hdr_offset = 270
-arp_key_offset = 128
-
-[PIPELINE2]
-type = FIREWALL
-core = 1
-pktq_in = RXQ0.1 RXQ1.1 RXQ2.1 RXQ3.1
-pktq_out = SWQ2 SINK0
-n_rules = 4096
-
-[PIPELINE3]
-type = FLOW_CLASSIFICATION
-core = 1
-pktq_in = RXQ0.2 RXQ1.2 RXQ2.2 RXQ3.2
-pktq_out = SWQ3 SINK1
-n_flows = 65536
-key_size = 16                               ; IPv4 5-tuple key size
-key_offset = 278                            ; IPv4 5-tuple key offset
-key_mask = 00FF0000FFFFFFFFFFFFFFFFFFFFFFFF ; IPv4 5-tuple key mask
-flowid_offset = 128 ; Flow ID effectively acts as TCP socket ID
-
-[PIPELINE4]
-type = PASS-THROUGH ; Loop-back (UDP place-holder)
-core = 1
-pktq_in = SWQ2
-pktq_out = SWQ0
-swap = 282 286 ; IPSRC <-> IPDST
-swap = 290 292 ; PORTSRC <-> PORTDST
-
-[PIPELINE5]
-type = PASS-THROUGH ; Loop-back (TCP place-holder)
-core = 1
-pktq_in = SWQ3
-pktq_out = SWQ1
-swap = 282 286 ; IPSRC <-> IPDST
-swap = 290 292 ; PORTSRC <-> PORTDST
-
-[PIPELINE6]
-type = PASS-THROUGH ; Drop (ICMP place-holder)
-core = 1
-pktq_in = RXQ0.3 RXQ1.3 RXQ2.3 RXQ3.3
-pktq_out = SINK4 SINK5 SINK6 SINK7
-
-[PIPELINE7]
-type = PASS-THROUGH ; Drop (Dynamic ARP place-holder)
-core = 1
-pktq_in = RXQ0.4 RXQ1.4 RXQ2.4 RXQ3.4
-pktq_out = SINK8 SINK9 SINK10 SINK11
diff --git a/examples/ip_pipeline/config/network_layers.sh b/examples/ip_pipeline/config/network_layers.sh
deleted file mode 100644
index 449b006..0000000
--- a/examples/ip_pipeline/config/network_layers.sh
+++ /dev/null
@@ -1,79 +0,0 @@
-#
-# run ./config/network_layers.sh
-#
-
-################################################################################
-# Link configuration
-################################################################################
-# Routes added implicitly when links are brought UP:
-# IP Prefix = 10.0.0.1/16 => (Port 0, Local)
-# IP Prefix = 10.0.0.1/32 => (Port 4, Local)
-# IP Prefix = 10.1.0.1/16 => (Port 1, Local)
-# IP Prefix = 10.1.0.1/32 => (Port 4, Local)
-# IP Prefix = 10.2.0.1/16 => (Port 2, Local)
-# IP Prefix = 10.2.0.1/32 => (Port 4, Local)
-# IP Prefix = 10.3.0.1/16 => (Port 3, Local)
-# IP Prefix = 10.3.0.1/32 => (Port 4, Local)
-link 0 down
-link 1 down
-link 2 down
-link 3 down
-link 0 config 10.0.0.1 16
-link 1 config 10.1.0.1 16
-link 2 config 10.2.0.1 16
-link 3 config 10.3.0.1 16
-link 0 up
-link 1 up
-link 2 up
-link 3 up
-#link ls
-
-################################################################################
-# Static ARP
-################################################################################
-p 1 arp add default 5 #SINK3
-p 1 arp add 0 10.0.0.2 a0:b0:c0:d0:e0:f0
-p 1 arp add 1 10.1.0.2 a1:b1:c1:d1:e1:f1
-p 1 arp add 2 10.2.0.2 a2:b2:c2:d2:e2:f2
-p 1 arp add 3 10.3.0.2 a3:b3:c3:d3:e3:f3
-#p 1 arp ls
-
-################################################################################
-# Routes
-################################################################################
-p 1 route add default 4 #SINK2
-p 1 route add 100.0.0.0 16 port 0 ether 10.0.0.2
-p 1 route add 100.1.0.0 16 port 1 ether 10.1.0.2
-p 1 route add 100.2.0.0 16 port 2 ether 10.2.0.2
-p 1 route add 100.3.0.0 16 port 3 ether 10.3.0.2
-#p 1 route ls
-
-################################################################################
-# Local destination UDP traffic
-################################################################################
-# Prio = Lowest: [SA = ANY, DA = ANY, SP = ANY, DP = ANY, PROTO = ANY] => Drop
-# Prio = 1 (High): [SA = ANY, DA = 10.0.0.1, SP = ANY, DP = 1000, PROTO = UDP] => Allow
-# Prio = 1 (High): [SA = ANY, DA = 10.1.0.1, SP = ANY, DP = 1001, PROTO = UDP] => Allow
-# Prio = 1 (High): [SA = ANY, DA = 10.2.0.1, SP = ANY, DP = 1002, PROTO = UDP] => Allow
-# Prio = 1 (High): [SA = ANY, DA = 10.3.0.1, SP = ANY, DP = 1003, PROTO = UDP] => Allow
-p 2 firewall add default 1 #SINK0
-p 2 firewall add priority 1 ipv4 0.0.0.0 0 10.0.0.1 32 0 65535 1000 1000 17 0xF port 0
-p 2 firewall add priority 1 ipv4 0.0.0.0 0 10.1.0.1 32 0 65535 1001 1001 17 0xF port 0
-p 2 firewall add priority 1 ipv4 0.0.0.0 0 10.2.0.1 32 0 65535 1002 1002 17 0xF port 0
-p 2 firewall add priority 1 ipv4 0.0.0.0 0 10.3.0.1 32 0 65535 1003 1003 17 0xF port 0
-#p 2 firewall ls
-
-################################################################################
-# Local destination TCP traffic
-################################################################################
-# Unknown connection => Drop
-# TCP [SA = 100.0.0.10, DA = 10.0.0.1, SP = 1000, DP = 80] => socket ID = 0
-# TCP [SA = 100.1.0.10, DA = 10.1.0.1, SP = 1001, DP = 80] => socket ID = 1
-# TCP [SA = 100.2.0.10, DA = 10.2.0.1, SP = 1002, DP = 80] => socket ID = 2
-# TCP [SA = 100.3.0.10, DA = 10.3.0.1, SP = 1003, DP = 80] => socket ID = 3
-p 3 flow add default 1 #SINK1
-p 3 flow add ipv4 100.0.0.10 10.0.0.1 1000 80 6 port 0 id 0
-p 3 flow add ipv4 100.1.0.10 10.1.0.1 1001 80 6 port 0 id 1
-p 3 flow add ipv4 100.2.0.10 10.2.0.1 1002 80 6 port 0 id 2
-p 3 flow add ipv4 100.3.0.10 10.3.0.1 1003 80 6 port 0 id 3
-#p 3 flow ls
diff --git a/examples/ip_pipeline/config/pipeline-to-core-mapping.py b/examples/ip_pipeline/config/pipeline-to-core-mapping.py
deleted file mode 100755
index fc52b2b..0000000
--- a/examples/ip_pipeline/config/pipeline-to-core-mapping.py
+++ /dev/null
@@ -1,906 +0,0 @@
-#!/usr/bin/env python
-# SPDX-License-Identifier: BSD-3-Clause
-# Copyright(c) 2016 Intel Corporation
-
-#
-# This script maps the set of pipelines identified (MASTER pipelines are
-# ignored) from the input configuration file to the set of cores
-# provided as input argument and creates configuration files for each of
-# the mapping combinations.
-#
-
-from __future__ import print_function
-from collections import namedtuple
-import argparse
-import array
-import errno
-import itertools
-import os
-import re
-import sys
-
-# default values
-enable_stage0_traceout = 1
-enable_stage1_traceout = 1
-enable_stage2_traceout = 1
-
-enable_stage1_fileout = 1
-enable_stage2_fileout = 1
-
-Constants = namedtuple('Constants', ['MAX_CORES', 'MAX_PIPELINES'])
-constants = Constants(16, 64)
-
-# pattern for physical core
-pattern_phycore = '^(s|S)\d(c|C)[1-9][0-9]*$'
-reg_phycore = re.compile(pattern_phycore)
-
-
-def popcount(mask):
-    return bin(mask).count("1")
-
-
-def len2mask(length):
-    if (length == 0):
-        return 0
-
-    if (length > 64):
-        sys.exit('error: len2mask - length %i > 64. exiting' % length)
-
-    return int('1' * length, 2)
-
-
-def bitstring_write(n, n_bits):
-    tmpstr = ""
-    if (n_bits > 64):
-        return
-
-    i = n_bits - 1
-    while (i >= 0):
-        cond = (n & (1 << i))
-        if (cond):
-            print('1', end='')
-            tmpstr += '1'
-        else:
-            print('0', end='')
-            tmpstr += '0'
-        i -= 1
-    return tmpstr
-
-
-class Cores0:
-
-    def __init__(self):
-        self.n_pipelines = 0
-
-
-class Cores1:
-
-    def __init__(self):
-        self.pipelines = 0
-        self.n_pipelines = 0
-
-
-class Cores2:
-
-    def __init__(self):
-        self.pipelines = 0
-        self.n_pipelines = 0
-        self.counter = 0
-        self.counter_max = 0
-        self.bitpos = array.array(
-            "L", itertools.repeat(0, constants.MAX_PIPELINES))
-
-
-class Context0:
-
-    def __init__(self):
-        self.cores = [Cores0() for i in range(0, constants.MAX_CORES)]
-        self.n_cores = 0
-        self.n_pipelines = 0
-        self.n_pipelines0 = 0
-        self.pos = 0
-        self.file_comment = ""
-        self.ctx1 = None
-        self.ctx2 = None
-
-    def stage0_print(self):
-        print('printing Context0 obj')
-        print('c0.cores(n_pipelines) = [ ', end='')
-        for cores_count in range(0, constants.MAX_CORES):
-            print(self.cores[cores_count].n_pipelines, end=' ')
-        print(']')
-        print('c0.n_cores = %d' % self.n_cores)
-        print('c0.n_pipelines = %d' % self.n_pipelines)
-        print('c0.n_pipelines0 = %d' % self.n_pipelines0)
-        print('c0.pos = %d' % self.pos)
-        print('c0.file_comment = %s' % self.file_comment)
-        if (self.ctx1 is not None):
-            print('c0.ctx1 = ', end='')
-            print(repr(self.ctx1))
-        else:
-            print('c0.ctx1 = None')
-
-        if (self.ctx2 is not None):
-            print('c0.ctx2 = ', end='')
-            print(repr(self.ctx2))
-        else:
-            print('c0.ctx2 = None')
-
-    def stage0_init(self, num_cores, num_pipelines, ctx1, ctx2):
-        self.n_cores = num_cores
-        self.n_pipelines = num_pipelines
-        self.ctx1 = ctx1
-        self.ctx2 = ctx2
-
-    def stage0_process(self):
-        # stage0 init
-        self.cores[0].n_pipelines = self.n_pipelines
-        self.n_pipelines0 = 0
-        self.pos = 1
-
-        while True:
-            # go forward
-            while True:
-                if ((self.pos < self.n_cores) and (self.n_pipelines0 > 0)):
-                    self.cores[self.pos].n_pipelines = min(
-                        self.cores[self.pos - 1].n_pipelines,
-                        self.n_pipelines0)
-                    self.n_pipelines0 -= self.cores[self.pos].n_pipelines
-                    self.pos += 1
-                else:
-                    break
-
-            # check solution
-            if (self.n_pipelines0 == 0):
-                self.stage0_log()
-                self.ctx1.stage1_init(self, self.ctx2)  # self is object c0
-                self.ctx1.stage1_process()
-
-            # go backward
-            while True:
-                if (self.pos == 0):
-                    return
-
-                self.pos -= 1
-                if ((self.cores[self.pos].n_pipelines > 1) and
-                        (self.pos != (self.n_cores - 1))):
-                    break
-
-                self.n_pipelines0 += self.cores[self.pos].n_pipelines
-                self.cores[self.pos].n_pipelines = 0
-
-            # rearm
-            self.cores[self.pos].n_pipelines -= 1
-            self.n_pipelines0 += 1
-            self.pos += 1
-
-    def stage0_log(self):
-        tmp_file_comment = ""
-        if(enable_stage0_traceout != 1):
-            return
-
-        print('STAGE0: ', end='')
-        tmp_file_comment += 'STAGE0: '
-        for cores_count in range(0, self.n_cores):
-            print('C%d = %d\t'
-                  % (cores_count,
-                      self.cores[cores_count].n_pipelines), end='')
-            tmp_file_comment += "C{} = {}\t".format(
-                cores_count, self.cores[cores_count].n_pipelines)
-        # end for
-        print('')
-        self.ctx1.stage0_file_comment = tmp_file_comment
-        self.ctx2.stage0_file_comment = tmp_file_comment
-
-
-class Context1:
-    _fileTrace = None
-
-    def __init__(self):
-        self.cores = [Cores1() for i in range(constants.MAX_CORES)]
-        self.n_cores = 0
-        self.n_pipelines = 0
-        self.pos = 0
-        self.stage0_file_comment = ""
-        self.stage1_file_comment = ""
-
-        self.ctx2 = None
-        self.arr_pipelines2cores = []
-
-    def stage1_reset(self):
-        for i in range(constants.MAX_CORES):
-            self.cores[i].pipelines = 0
-            self.cores[i].n_pipelines = 0
-
-        self.n_cores = 0
-        self.n_pipelines = 0
-        self.pos = 0
-        self.ctx2 = None
-        # clear list
-        del self.arr_pipelines2cores[:]
-
-    def stage1_print(self):
-        print('printing Context1 obj')
-        print('ctx1.cores(pipelines,n_pipelines) = [ ', end='')
-        for cores_count in range(0, constants.MAX_CORES):
-            print('(%d,%d)' % (self.cores[cores_count].pipelines,
-                               self.cores[cores_count].n_pipelines), end=' ')
-        print(']')
-        print('ctx1.n_cores = %d' % self.n_cores)
-        print('ctx1.n_pipelines = %d' % self.n_pipelines)
-        print('ctx1.pos = %d' % self.pos)
-        print('ctx1.stage0_file_comment = %s' % self.stage0_file_comment)
-        print('ctx1.stage1_file_comment = %s' % self.stage1_file_comment)
-        if (self.ctx2 is not None):
-            print('ctx1.ctx2 = ', end='')
-            print(self.ctx2)
-        else:
-            print('ctx1.ctx2 = None')
-
-    def stage1_init(self, c0, ctx2):
-        self.stage1_reset()
-        self.n_cores = 0
-        while (c0.cores[self.n_cores].n_pipelines > 0):
-            self.n_cores += 1
-
-        self.n_pipelines = c0.n_pipelines
-        self.ctx2 = ctx2
-
-        self.arr_pipelines2cores = [0] * self.n_pipelines
-
-        i = 0
-        while (i < self.n_cores):
-            self.cores[i].n_pipelines = c0.cores[i].n_pipelines
-            i += 1
-
-    def stage1_process(self):
-        pipelines_max = len2mask(self.n_pipelines)
-        while True:
-            pos = 0
-            overlap = 0
-
-            if (self.cores[self.pos].pipelines == pipelines_max):
-                if (self.pos == 0):
-                    return
-
-                self.cores[self.pos].pipelines = 0
-                self.pos -= 1
-                continue
-
-            self.cores[self.pos].pipelines += 1
-            if (popcount(self.cores[self.pos].pipelines) !=
-                    self.cores[self.pos].n_pipelines):
-                continue
-
-            overlap = 0
-            pos = 0
-            while (pos < self.pos):
-                if ((self.cores[self.pos].pipelines) &
-                        (self.cores[pos].pipelines)):
-                    overlap = 1
-                    break
-                pos += 1
-
-            if (overlap):
-                continue
-
-            if ((self.pos > 0) and
-                ((self.cores[self.pos].n_pipelines) ==
-                    (self.cores[self.pos - 1].n_pipelines)) and
-                    ((self.cores[self.pos].pipelines) <
-                        (self.cores[self.pos - 1].pipelines))):
-                continue
-
-            if (self.pos == self.n_cores - 1):
-                self.stage1_log()
-                self.ctx2.stage2_init(self)
-                self.ctx2.stage2_process()
-
-                if (self.pos == 0):
-                    return
-
-                self.cores[self.pos].pipelines = 0
-                self.pos -= 1
-                continue
-
-            self.pos += 1
-
-    def stage1_log(self):
-        tmp_file_comment = ""
-        if(enable_stage1_traceout == 1):
-            print('STAGE1: ', end='')
-            tmp_file_comment += 'STAGE1: '
-            i = 0
-            while (i < self.n_cores):
-                print('C%d = [' % i, end='')
-                tmp_file_comment += "C{} = [".format(i)
-
-                j = self.n_pipelines - 1
-                while (j >= 0):
-                    cond = ((self.cores[i].pipelines) & (1 << j))
-                    if (cond):
-                        print('1', end='')
-                        tmp_file_comment += '1'
-                    else:
-                        print('0', end='')
-                        tmp_file_comment += '0'
-                    j -= 1
-
-                print(']\t', end='')
-                tmp_file_comment += ']\t'
-                i += 1
-
-            print('\n', end='')
-            self.stage1_file_comment = tmp_file_comment
-            self.ctx2.stage1_file_comment = tmp_file_comment
-
-        # check if file traceing is enabled
-        if(enable_stage1_fileout != 1):
-            return
-
-        # spit out the combination to file
-        self.stage1_process_file()
-
-    def stage1_updateCoresInBuf(self, nPipeline, sCore):
-        rePipeline = self._fileTrace.arr_pipelines[nPipeline]
-        rePipeline = rePipeline.replace("[", "\[").replace("]", "\]")
-        reCore = 'core\s*=\s*((\d*)|(((s|S)\d)?(c|C)[1-9][0-9]*)).*\n'
-        sSubs = 'core = ' + sCore + '\n'
-
-        reg_pipeline = re.compile(rePipeline)
-        search_match = reg_pipeline.search(self._fileTrace.in_buf)
-
-        if(search_match):
-            pos = search_match.start()
-            substr1 = self._fileTrace.in_buf[:pos]
-            substr2 = self._fileTrace.in_buf[pos:]
-            substr2 = re.sub(reCore, sSubs, substr2, 1)
-            self._fileTrace.in_buf = substr1 + substr2
-
-    def stage1_process_file(self):
-        outFileName = os.path.join(self._fileTrace.out_path,
-                                   self._fileTrace.prefix_outfile)
-        outFileName += "_{}CoReS".format(self.n_cores)
-
-        i = 0  # represents core number
-        while (i < self.n_cores):
-            j = self.n_pipelines - 1
-            pipeline_idx = 0
-            while(j >= 0):
-                cond = ((self.cores[i].pipelines) & (1 << j))
-                if (cond):
-                    # update the pipelines array to match the core
-                    # only in case of cond match
-                    self.arr_pipelines2cores[
-                        pipeline_idx] = fileTrace.in_physical_cores[i]
-
-                j -= 1
-                pipeline_idx += 1
-
-            i += 1
-
-        # update the in_buf as per the arr_pipelines2cores
-        for pipeline_idx in range(len(self.arr_pipelines2cores)):
-            outFileName += "_{}".format(self.arr_pipelines2cores[pipeline_idx])
-            self.stage1_updateCoresInBuf(
-                pipeline_idx, self.arr_pipelines2cores[pipeline_idx])
-
-        # by now the in_buf is all set to be written to file
-        outFileName += self._fileTrace.suffix_outfile
-        outputFile = open(outFileName, "w")
-
-        # write out the comments
-        strTruncated = ("", "(Truncated)")[self._fileTrace.ncores_truncated]
-        outputFile.write(
-            "; =============== Pipeline-to-Core Mapping ================\n"
-            "; Generated from file {}\n"
-            "; Input pipelines = {}\n"
-            "; Input cores = {}\n"
-            "; N_PIPELINES = {} N_CORES = {} {} hyper_thread = {}\n"
-            .format(
-                self._fileTrace.in_file_namepath,
-                fileTrace.arr_pipelines,
-                fileTrace.in_physical_cores,
-                self._fileTrace.n_pipelines,
-                self._fileTrace.n_cores,
-                strTruncated,
-                self._fileTrace.hyper_thread))
-
-        outputFile.write(
-            "; {stg0cmt}\n"
-            "; {stg1cmt}\n"
-            "; ========================================================\n"
-            "; \n"
-            .format(
-                stg0cmt=self.stage0_file_comment,
-                stg1cmt=self.stage1_file_comment))
-
-        # write buffer contents
-        outputFile.write(self._fileTrace.in_buf)
-        outputFile.flush()
-        outputFile.close()
-
-
-class Context2:
-    _fileTrace = None
-
-    def __init__(self):
-        self.cores = [Cores2() for i in range(constants.MAX_CORES)]
-        self.n_cores = 0
-        self.n_pipelines = 0
-        self.pos = 0
-        self.stage0_file_comment = ""
-        self.stage1_file_comment = ""
-        self.stage2_file_comment = ""
-
-        # each array entry is a pipeline mapped to core stored as string
-        # pipeline ranging from 1 to n, however stored in zero based array
-        self.arr2_pipelines2cores = []
-
-    def stage2_print(self):
-        print('printing Context2 obj')
-        print('ctx2.cores(pipelines, n_pipelines, counter, counter_max) =')
-        for cores_count in range(0, constants.MAX_CORES):
-            print('core[%d] = (%d,%d,%d,%d)' % (
-                cores_count,
-                self.cores[cores_count].pipelines,
-                self.cores[cores_count].n_pipelines,
-                self.cores[cores_count].counter,
-                self.cores[cores_count].counter_max))
-
-            print('ctx2.n_cores = %d' % self.n_cores, end='')
-            print('ctx2.n_pipelines = %d' % self.n_pipelines, end='')
-            print('ctx2.pos = %d' % self.pos)
-            print('ctx2.stage0_file_comment = %s' %
-                  self.self.stage0_file_comment)
-            print('ctx2.stage1_file_comment = %s' %
-                  self.self.stage1_file_comment)
-            print('ctx2.stage2_file_comment = %s' %
-                  self.self.stage2_file_comment)
-
-    def stage2_reset(self):
-        for i in range(0, constants.MAX_CORES):
-            self.cores[i].pipelines = 0
-            self.cores[i].n_pipelines = 0
-            self.cores[i].counter = 0
-            self.cores[i].counter_max = 0
-
-            for idx in range(0, constants.MAX_PIPELINES):
-                self.cores[i].bitpos[idx] = 0
-
-        self.n_cores = 0
-        self.n_pipelines = 0
-        self.pos = 0
-        # clear list
-        del self.arr2_pipelines2cores[:]
-
-    def bitpos_load(self, coreidx):
-        i = j = 0
-        while (i < self.n_pipelines):
-            if ((self.cores[coreidx].pipelines) &
-                    (1 << i)):
-                self.cores[coreidx].bitpos[j] = i
-                j += 1
-            i += 1
-        self.cores[coreidx].n_pipelines = j
-
-    def bitpos_apply(self, in_buf, pos, n_pos):
-        out = 0
-        for i in range(0, n_pos):
-            out |= (in_buf & (1 << i)) << (pos[i] - i)
-
-        return out
-
-    def stage2_init(self, ctx1):
-        self.stage2_reset()
-        self.n_cores = ctx1.n_cores
-        self.n_pipelines = ctx1.n_pipelines
-
-        self.arr2_pipelines2cores = [''] * self.n_pipelines
-
-        core_idx = 0
-        while (core_idx < self.n_cores):
-            self.cores[core_idx].pipelines = ctx1.cores[core_idx].pipelines
-
-            self.bitpos_load(core_idx)
-            core_idx += 1
-
-    def stage2_log(self):
-        tmp_file_comment = ""
-        if(enable_stage2_traceout == 1):
-            print('STAGE2: ', end='')
-            tmp_file_comment += 'STAGE2: '
-
-            for i in range(0, self.n_cores):
-                mask = len2mask(self.cores[i].n_pipelines)
-                pipelines_ht0 = self.bitpos_apply(
-                    (~self.cores[i].counter) & mask,
-                    self.cores[i].bitpos,
-                    self.cores[i].n_pipelines)
-
-                pipelines_ht1 = self.bitpos_apply(
-                    self.cores[i].counter,
-                    self.cores[i].bitpos,
-                    self.cores[i].n_pipelines)
-
-                print('C%dHT0 = [' % i, end='')
-                tmp_file_comment += "C{}HT0 = [".format(i)
-                tmp_file_comment += bitstring_write(
-                    pipelines_ht0, self.n_pipelines)
-
-                print(']\tC%dHT1 = [' % i, end='')
-                tmp_file_comment += "]\tC{}HT1 = [".format(i)
-                tmp_file_comment += bitstring_write(
-                    pipelines_ht1, self.n_pipelines)
-                print(']\t', end='')
-                tmp_file_comment += ']\t'
-
-            print('')
-            self.stage2_file_comment = tmp_file_comment
-
-        # check if file traceing is enabled
-        if(enable_stage2_fileout != 1):
-            return
-        # spit out the combination to file
-        self.stage2_process_file()
-
-    def stage2_updateCoresInBuf(self, nPipeline, sCore):
-        rePipeline = self._fileTrace.arr_pipelines[nPipeline]
-        rePipeline = rePipeline.replace("[", "\[").replace("]", "\]")
-        reCore = 'core\s*=\s*((\d*)|(((s|S)\d)?(c|C)[1-9][0-9]*)).*\n'
-        sSubs = 'core = ' + sCore + '\n'
-
-        reg_pipeline = re.compile(rePipeline)
-        search_match = reg_pipeline.search(self._fileTrace.in_buf)
-
-        if(search_match):
-            pos = search_match.start()
-            substr1 = self._fileTrace.in_buf[:pos]
-            substr2 = self._fileTrace.in_buf[pos:]
-            substr2 = re.sub(reCore, sSubs, substr2, 1)
-            self._fileTrace.in_buf = substr1 + substr2
-
-    def pipelines2cores(self, n, n_bits, nCore, bHT):
-        if (n_bits > 64):
-            return
-
-        i = n_bits - 1
-        pipeline_idx = 0
-        while (i >= 0):
-            cond = (n & (1 << i))
-            if (cond):
-                # update the pipelines array to match the core
-                # only in case of cond match
-                # PIPELINE0 and core 0 are reserved
-                if(bHT):
-                    tmpCore = fileTrace.in_physical_cores[nCore] + 'h'
-                    self.arr2_pipelines2cores[pipeline_idx] = tmpCore
-                else:
-                    self.arr2_pipelines2cores[pipeline_idx] = \
-                        fileTrace.in_physical_cores[nCore]
-
-            i -= 1
-            pipeline_idx += 1
-
-    def stage2_process_file(self):
-        outFileName = os.path.join(self._fileTrace.out_path,
-                                   self._fileTrace.prefix_outfile)
-        outFileName += "_{}CoReS".format(self.n_cores)
-
-        for i in range(0, self.n_cores):
-            mask = len2mask(self.cores[i].n_pipelines)
-            pipelines_ht0 = self.bitpos_apply((~self.cores[i].counter) & mask,
-                                              self.cores[i].bitpos,
-                                              self.cores[i].n_pipelines)
-
-            pipelines_ht1 = self.bitpos_apply(self.cores[i].counter,
-                                              self.cores[i].bitpos,
-                                              self.cores[i].n_pipelines)
-
-            # update pipelines to core mapping
-            self.pipelines2cores(pipelines_ht0, self.n_pipelines, i, False)
-            self.pipelines2cores(pipelines_ht1, self.n_pipelines, i, True)
-
-        # update the in_buf as per the arr_pipelines2cores
-        for pipeline_idx in range(len(self.arr2_pipelines2cores)):
-            outFileName += "_{}".format(
-                self.arr2_pipelines2cores[pipeline_idx])
-            self.stage2_updateCoresInBuf(
-                pipeline_idx, self.arr2_pipelines2cores[pipeline_idx])
-
-        # by now the in_buf is all set to be written to file
-        outFileName += self._fileTrace.suffix_outfile
-        outputFile = open(outFileName, "w")
-
-        # write the file comments
-        strTruncated = ("", "(Truncated)")[self._fileTrace.ncores_truncated]
-        outputFile.write(
-            "; =============== Pipeline-to-Core Mapping ================\n"
-            "; Generated from file {}\n"
-            "; Input pipelines = {}\n"
-            "; Input cores = {}\n"
-            "; N_PIPELINES = {}  N_CORES = {} {} hyper_thread = {} \n"
-            .format(
-                self._fileTrace.in_file_namepath,
-                fileTrace.arr_pipelines,
-                fileTrace.in_physical_cores,
-                self._fileTrace.n_pipelines,
-                self._fileTrace.n_cores,
-                strTruncated,
-                self._fileTrace.hyper_thread))
-
-        outputFile.write(
-            "; {stg0cmt}\n"
-            "; {stg1cmt}\n"
-            "; {stg2cmt}\n"
-            "; ========================================================\n"
-            "; \n"
-            .format(
-                stg0cmt=self.stage0_file_comment,
-                stg1cmt=self.stage1_file_comment,
-                stg2cmt=self.stage2_file_comment))
-
-        # write the buffer contents
-        outputFile.write(self._fileTrace.in_buf)
-        outputFile.flush()
-        outputFile.close()
-
-    def stage2_process(self):
-        i = 0
-        while(i < self.n_cores):
-            self.cores[i].counter_max = len2mask(
-                self.cores[i].n_pipelines - 1)
-            i += 1
-
-        self.pos = self.n_cores - 1
-        while True:
-            if (self.pos == self.n_cores - 1):
-                self.stage2_log()
-
-            if (self.cores[self.pos].counter ==
-                    self.cores[self.pos].counter_max):
-                if (self.pos == 0):
-                    return
-
-                self.cores[self.pos].counter = 0
-                self.pos -= 1
-                continue
-
-            self.cores[self.pos].counter += 1
-            if(self.pos < self.n_cores - 1):
-                self.pos += 1
-
-
-class FileTrace:
-
-    def __init__(self, filenamepath):
-        self.in_file_namepath = os.path.abspath(filenamepath)
-        self.in_filename = os.path.basename(self.in_file_namepath)
-        self.in_path = os.path.dirname(self.in_file_namepath)
-
-        filenamesplit = self.in_filename.split('.')
-        self.prefix_outfile = filenamesplit[0]
-        self.suffix_outfile = ".cfg"
-
-        # output folder:  in the same folder as input file
-        # create new folder in the name of input file
-        self.out_path = os.path.join(
-            os.path.abspath(os.path.dirname(__file__)),
-            self.prefix_outfile)
-
-        try:
-            os.makedirs(self.out_path)
-        except OSError as excep:
-            if excep.errno == errno.EEXIST and os.path.isdir(self.out_path):
-                pass
-            else:
-                raise
-
-        self.in_buf = None
-        self.arr_pipelines = []  # holds the positions of search
-
-        self.max_cores = 15
-        self.max_pipelines = 15
-
-        self.in_physical_cores = None
-        self.hyper_thread = None
-
-        # save the num of pipelines determined from input file
-        self.n_pipelines = 0
-        # save the num of cores input (or the truncated value)
-        self.n_cores = 0
-        self.ncores_truncated = False
-
-    def print_TraceFile(self):
-        print("self.in_file_namepath = ", self.in_file_namepath)
-        print("self.in_filename = ", self.in_filename)
-        print("self.in_path = ", self.in_path)
-        print("self.out_path = ", self.out_path)
-        print("self.prefix_outfile = ", self.prefix_outfile)
-        print("self.suffix_outfile = ", self.suffix_outfile)
-        print("self.in_buf = ", self.in_buf)
-        print("self.arr_pipelines =", self.arr_pipelines)
-        print("self.in_physical_cores", self.in_physical_cores)
-        print("self.hyper_thread", self.hyper_thread)
-
-
-def process(n_cores, n_pipelines, fileTrace):
-    '''process and map pipelines, cores.'''
-    if (n_cores == 0):
-        sys.exit('N_CORES is 0, exiting')
-
-    if (n_pipelines == 0):
-        sys.exit('N_PIPELINES is 0, exiting')
-
-    if (n_cores > n_pipelines):
-        print('\nToo many cores, truncating N_CORES to N_PIPELINES')
-        n_cores = n_pipelines
-        fileTrace.ncores_truncated = True
-
-    fileTrace.n_pipelines = n_pipelines
-    fileTrace.n_cores = n_cores
-
-    strTruncated = ("", "(Truncated)")[fileTrace.ncores_truncated]
-    print("N_PIPELINES = {}, N_CORES = {} {}"
-          .format(n_pipelines, n_cores, strTruncated))
-    print("---------------------------------------------------------------")
-
-    ctx0_inst = Context0()
-    ctx1_inst = Context1()
-    ctx2_inst = Context2()
-
-    # initialize the class variables
-    ctx1_inst._fileTrace = fileTrace
-    ctx2_inst._fileTrace = fileTrace
-
-    ctx0_inst.stage0_init(n_cores, n_pipelines, ctx1_inst, ctx2_inst)
-    ctx0_inst.stage0_process()
-
-
-def validate_core(core):
-    match = reg_phycore.match(core)
-    if(match):
-        return True
-    else:
-        return False
-
-
-def validate_phycores(phy_cores):
-    '''validate physical cores, check if unique.'''
-    # eat up whitespaces
-    phy_cores = phy_cores.strip().split(',')
-
-    # check if the core list is unique
-    if(len(phy_cores) != len(set(phy_cores))):
-        print('list of physical cores has duplicates')
-        return None
-
-    for core in phy_cores:
-        if not validate_core(core):
-            print('invalid physical core specified.')
-            return None
-    return phy_cores
-
-
-def scanconfigfile(fileTrace):
-    '''scan input file for pipelines, validate then process.'''
-    # open file
-    filetoscan = open(fileTrace.in_file_namepath, 'r')
-    fileTrace.in_buf = filetoscan.read()
-
-    # reset iterator on open file
-    filetoscan.seek(0)
-
-    # scan input file for pipelines
-    # master pipelines to be ignored
-    pattern_pipeline = r'\[PIPELINE\d*\]'
-    pattern_mastertype = r'type\s*=\s*MASTER'
-
-    pending_pipeline = False
-    for line in filetoscan:
-        match_pipeline = re.search(pattern_pipeline, line)
-        match_type = re.search('type\s*=', line)
-        match_mastertype = re.search(pattern_mastertype, line)
-
-        if(match_pipeline):
-            sPipeline = line[match_pipeline.start():match_pipeline.end()]
-            pending_pipeline = True
-        elif(match_type):
-            # found a type definition...
-            if(match_mastertype is None):
-                # and this is not a master pipeline...
-                if(pending_pipeline):
-                    # add it to the list of pipelines to be mapped
-                    fileTrace.arr_pipelines.append(sPipeline)
-                    pending_pipeline = False
-            else:
-                # and this is a master pipeline...
-                # ignore the current and move on to next
-                sPipeline = ""
-                pending_pipeline = False
-    filetoscan.close()
-
-    # validate if pipelines are unique
-    if(len(fileTrace.arr_pipelines) != len(set(fileTrace.arr_pipelines))):
-        sys.exit('Error: duplicate pipelines in input file')
-
-    num_pipelines = len(fileTrace.arr_pipelines)
-    num_cores = len(fileTrace.in_physical_cores)
-
-    print("-------------------Pipeline-to-core mapping--------------------")
-    print("Input pipelines = {}\nInput cores = {}"
-          .format(fileTrace.arr_pipelines, fileTrace.in_physical_cores))
-
-    # input configuration file validations goes here
-    if (num_cores > fileTrace.max_cores):
-        sys.exit('Error: number of cores specified > max_cores (%d)' %
-                 fileTrace.max_cores)
-
-    if (num_pipelines > fileTrace.max_pipelines):
-        sys.exit('Error: number of pipelines in input \
-                cfg file > max_pipelines (%d)' % fileTrace.max_pipelines)
-
-    # call process to generate pipeline-to-core mapping, trace and log
-    process(num_cores, num_pipelines, fileTrace)
-
-
-if __name__ == "__main__":
-    parser = argparse.ArgumentParser(description='mappipelines')
-
-    reqNamedGrp = parser.add_argument_group('required named args')
-    reqNamedGrp.add_argument(
-        '-i',
-        '--input-file',
-        type=argparse.FileType('r'),
-        help='Input config file',
-        required=True)
-
-    reqNamedGrp.add_argument(
-        '-pc',
-        '--physical-cores',
-        type=validate_phycores,
-        help='''Enter available CPU cores in
-                format:\"<core>,<core>,...\"
-                where each core format: \"s<SOCKETID>c<COREID>\"
-                where SOCKETID={0..9}, COREID={1-99}''',
-        required=True)
-
-    # add optional arguments
-    parser.add_argument(
-        '-ht',
-        '--hyper-thread',
-        help='enable/disable hyper threading. default is ON',
-        default='ON',
-        choices=['ON', 'OFF'])
-
-    parser.add_argument(
-        '-nO',
-        '--no-output-file',
-        help='''disable output config file generation.
-                Output file generation is enabled by default''',
-        action="store_true")
-
-    args = parser.parse_args()
-
-    if(args.physical_cores is None):
-        parser.error("invalid physical_cores specified")
-
-    # create object of FileTrace and initialise
-    fileTrace = FileTrace(args.input_file.name)
-    fileTrace.in_physical_cores = args.physical_cores
-    fileTrace.hyper_thread = args.hyper_thread
-
-    if(fileTrace.hyper_thread == 'OFF'):
-        print("!!!!disabling stage2 HT!!!!")
-        enable_stage2_traceout = 0
-        enable_stage2_fileout = 0
-    elif(fileTrace.hyper_thread == 'ON'):
-        print("!!!!HT enabled. disabling stage1 file generation.!!!!")
-        enable_stage1_fileout = 0
-
-    if(args.no_output_file is True):
-        print("!!!!disabling stage1 and stage2 fileout!!!!")
-        enable_stage1_fileout = 0
-        enable_stage2_fileout = 0
-
-    scanconfigfile(fileTrace)
diff --git a/examples/ip_pipeline/config/tap.cfg b/examples/ip_pipeline/config/tap.cfg
deleted file mode 100644
index 10d35eb..0000000
--- a/examples/ip_pipeline/config/tap.cfg
+++ /dev/null
@@ -1,64 +0,0 @@
-;   BSD LICENSE
-;
-;   Copyright(c) 2016 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.
-
-;             ______________          ______________________
-;            |              |  TAP0  |                      |
-; RXQ0.0 --->|              |------->|--+                   |
-;            |              |  TAP1  |  | br0               |
-; TXQ1.0 <---|              |<-------|<-+                   |
-;            | Pass-through |        |     Linux Kernel     |
-;            |     (P1)     |        |     Network Stack    |
-;            |              |  TAP1  |                      |
-; RXQ1.0 --->|              |------->|--+                   |
-;            |              |  TAP0  |  | br0               |
-; TXQ0.0 <---|              |<-------|<-+                   |
-;            |______________|        |______________________|
-;
-; Configure Linux kernel bridge between TAP0 and TAP1 interfaces:
-;    [Linux]$ ifconfig TAP0 up
-;    [Linux]$ ifconfig TAP1 up
-;    [Linux]$ brctl addbr "br0"
-;    [Linux]$ brctl addif br0 TAP0
-;    [Linux]$ brctl addif br0 TAP1
-;    [Linux]$ ifconfig br0 up
-
-[EAL]
-log_level = 0
-
-[PIPELINE0]
-type = MASTER
-core = 0
-
-[PIPELINE1]
-type = PASS-THROUGH
-core = 1
-pktq_in = RXQ0.0 TAP1 RXQ1.0 TAP0
-pktq_out = TAP0 TXQ1.0 TAP1 TXQ0.0
diff --git a/examples/ip_pipeline/config/tm_profile.cfg b/examples/ip_pipeline/config/tm_profile.cfg
deleted file mode 100644
index 2dfb215..0000000
--- a/examples/ip_pipeline/config/tm_profile.cfg
+++ /dev/null
@@ -1,105 +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.
-
-; This file enables the following hierarchical scheduler configuration for each
-; 10GbE output port:
-;	* Single subport (subport 0):
-;		- Subport rate set to 100% of port rate
-;		- Each of the 4 traffic classes has rate set to 100% of port rate
-;	* 4K pipes per subport 0 (pipes 0 .. 4095) with identical configuration:
-;		- Pipe rate set to 1/4K of port rate
-;		- Each of the 4 traffic classes has rate set to 100% of pipe rate
-;		- Within each traffic class, the byte-level WRR weights for the 4 queues
-;         are set to 1:1:1:1
-;
-; For more details, please refer to chapter "Quality of Service (QoS) Framework"
-; of Data Plane Development Kit (DPDK) Programmer's Guide.
-
-; Port configuration
-[port]
-frame overhead = 24 ; frame overhead = Preamble (7) + SFD (1) + FCS (4) + IFG (12)
-mtu = 1522; mtu = Q-in-Q MTU (FCS not included)
-number of subports per port = 1
-number of pipes per subport = 4096
-queue sizes = 64 64 64 64
-
-; Subport configuration
-[subport 0]
-tb rate = 1250000000           ; Bytes per second
-tb size = 1000000              ; Bytes
-
-tc 0 rate = 1250000000         ; Bytes per second
-tc 1 rate = 1250000000         ; Bytes per second
-tc 2 rate = 1250000000         ; Bytes per second
-tc 3 rate = 1250000000         ; Bytes per second
-tc period = 10                 ; Milliseconds
-
-pipe 0-4095 = 0                ; These pipes are configured with pipe profile 0
-
-; Pipe configuration
-[pipe profile 0]
-tb rate = 305175               ; Bytes per second
-tb size = 1000000              ; Bytes
-
-tc 0 rate = 305175             ; Bytes per second
-tc 1 rate = 305175             ; Bytes per second
-tc 2 rate = 305175             ; Bytes per second
-tc 3 rate = 305175             ; Bytes per second
-tc period = 40                 ; Milliseconds
-
-tc 3 oversubscription weight = 1
-
-tc 0 wrr weights = 1 1 1 1
-tc 1 wrr weights = 1 1 1 1
-tc 2 wrr weights = 1 1 1 1
-tc 3 wrr weights = 1 1 1 1
-
-; RED params per traffic class and color (Green / Yellow / Red)
-[red]
-tc 0 wred min = 48 40 32
-tc 0 wred max = 64 64 64
-tc 0 wred inv prob = 10 10 10
-tc 0 wred weight = 9 9 9
-
-tc 1 wred min = 48 40 32
-tc 1 wred max = 64 64 64
-tc 1 wred inv prob = 10 10 10
-tc 1 wred weight = 9 9 9
-
-tc 2 wred min = 48 40 32
-tc 2 wred max = 64 64 64
-tc 2 wred inv prob = 10 10 10
-tc 2 wred weight = 9 9 9
-
-tc 3 wred min = 48 40 32
-tc 3 wred max = 64 64 64
-tc 3 wred inv prob = 10 10 10
-tc 3 wred weight = 9 9 9
diff --git a/examples/ip_pipeline/config_check.c b/examples/ip_pipeline/config_check.c
deleted file mode 100644
index 86d1191..0000000
--- a/examples/ip_pipeline/config_check.c
+++ /dev/null
@@ -1,488 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2016 Intel Corporation
- */
-
-#include <stdio.h>
-
-#include <rte_ip.h>
-
-#include "app.h"
-
-static void
-check_mempools(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_mempools; i++) {
-		struct app_mempool_params *p = &app->mempool_params[i];
-
-		APP_CHECK((p->pool_size > 0),
-			"Mempool %s size is 0\n", p->name);
-
-		APP_CHECK((p->cache_size > 0),
-			"Mempool %s cache size is 0\n", p->name);
-
-		APP_CHECK(rte_is_power_of_2(p->cache_size),
-			"Mempool %s cache size not a power of 2\n", p->name);
-	}
-}
-
-static inline uint32_t
-link_rxq_used(struct app_link_params *link, uint32_t q_id)
-{
-	uint32_t i;
-
-	if ((link->arp_q == q_id) ||
-		(link->tcp_syn_q == q_id) ||
-		(link->ip_local_q == q_id) ||
-		(link->tcp_local_q == q_id) ||
-		(link->udp_local_q == q_id) ||
-		(link->sctp_local_q == q_id))
-		return 1;
-
-	for (i = 0; i < link->n_rss_qs; i++)
-		if (link->rss_qs[i] == q_id)
-			return 1;
-
-	return 0;
-}
-
-static void
-check_links(struct app_params *app)
-{
-	uint32_t i;
-
-	/* Check that number of links matches the port mask */
-	if (app->port_mask) {
-		uint32_t n_links_port_mask =
-			__builtin_popcountll(app->port_mask);
-
-		APP_CHECK((app->n_links == n_links_port_mask),
-			"Not enough links provided in the PORT_MASK\n");
-	}
-
-	for (i = 0; i < app->n_links; i++) {
-		struct app_link_params *link = &app->link_params[i];
-		uint32_t rxq_max, n_rxq, n_txq, link_id, i;
-
-		APP_PARAM_GET_ID(link, "LINK", link_id);
-
-		/* Check that link RXQs are contiguous */
-		rxq_max = 0;
-		if (link->arp_q > rxq_max)
-			rxq_max = link->arp_q;
-		if (link->tcp_syn_q > rxq_max)
-			rxq_max = link->tcp_syn_q;
-		if (link->ip_local_q > rxq_max)
-			rxq_max = link->ip_local_q;
-		if (link->tcp_local_q > rxq_max)
-			rxq_max = link->tcp_local_q;
-		if (link->udp_local_q > rxq_max)
-			rxq_max = link->udp_local_q;
-		if (link->sctp_local_q > rxq_max)
-			rxq_max = link->sctp_local_q;
-		for (i = 0; i < link->n_rss_qs; i++)
-			if (link->rss_qs[i] > rxq_max)
-				rxq_max = link->rss_qs[i];
-
-		for (i = 1; i <= rxq_max; i++)
-			APP_CHECK((link_rxq_used(link, i)),
-				"%s RXQs are not contiguous (A)\n", link->name);
-
-		n_rxq = app_link_get_n_rxq(app, link);
-
-		APP_CHECK((n_rxq), "%s does not have any RXQ\n", link->name);
-
-		APP_CHECK((n_rxq == rxq_max + 1),
-			"%s RXQs are not contiguous (B)\n", link->name);
-
-		for (i = 0; i < n_rxq; i++) {
-			char name[APP_PARAM_NAME_SIZE];
-			int pos;
-
-			sprintf(name, "RXQ%" PRIu32 ".%" PRIu32,
-				link_id, i);
-			pos = APP_PARAM_FIND(app->hwq_in_params, name);
-			APP_CHECK((pos >= 0),
-				"%s RXQs are not contiguous (C)\n", link->name);
-		}
-
-		/* Check that link TXQs are contiguous */
-		n_txq = app_link_get_n_txq(app, link);
-
-		APP_CHECK((n_txq),  "%s does not have any TXQ\n", link->name);
-
-		for (i = 0; i < n_txq; i++) {
-			char name[APP_PARAM_NAME_SIZE];
-			int pos;
-
-			sprintf(name, "TXQ%" PRIu32 ".%" PRIu32,
-				link_id, i);
-			pos = APP_PARAM_FIND(app->hwq_out_params, name);
-			APP_CHECK((pos >= 0),
-				"%s TXQs are not contiguous\n", link->name);
-		}
-	}
-}
-
-static void
-check_rxqs(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_pktq_hwq_in; i++) {
-		struct app_pktq_hwq_in_params *p = &app->hwq_in_params[i];
-		uint32_t n_readers = app_rxq_get_readers(app, p);
-
-		APP_CHECK((p->size > 0),
-			"%s size is 0\n", p->name);
-
-		APP_CHECK((rte_is_power_of_2(p->size)),
-			"%s size is not a power of 2\n", p->name);
-
-		APP_CHECK((p->burst > 0),
-			"%s burst size is 0\n", p->name);
-
-		APP_CHECK((p->burst <= p->size),
-			"%s burst size is bigger than its size\n", p->name);
-
-		APP_CHECK((n_readers != 0),
-			"%s has no reader\n", p->name);
-
-		APP_CHECK((n_readers == 1),
-			"%s has more than one reader\n", p->name);
-	}
-}
-
-static void
-check_txqs(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_pktq_hwq_out; i++) {
-		struct app_pktq_hwq_out_params *p = &app->hwq_out_params[i];
-		uint32_t n_writers = app_txq_get_writers(app, p);
-
-		APP_CHECK((p->size > 0),
-			"%s size is 0\n", p->name);
-
-		APP_CHECK((rte_is_power_of_2(p->size)),
-			"%s size is not a power of 2\n", p->name);
-
-		APP_CHECK((p->burst > 0),
-			"%s burst size is 0\n", p->name);
-
-		APP_CHECK((p->burst <= p->size),
-			"%s burst size is bigger than its size\n", p->name);
-
-		APP_CHECK((n_writers != 0),
-			"%s has no writer\n", p->name);
-
-		APP_CHECK((n_writers == 1),
-			"%s has more than one writer\n", p->name);
-	}
-}
-
-static void
-check_swqs(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_pktq_swq; i++) {
-		struct app_pktq_swq_params *p = &app->swq_params[i];
-		uint32_t n_readers = app_swq_get_readers(app, p);
-		uint32_t n_writers = app_swq_get_writers(app, p);
-		uint32_t n_flags;
-
-		APP_CHECK((p->size > 0),
-			"%s size is 0\n", p->name);
-
-		APP_CHECK((rte_is_power_of_2(p->size)),
-			"%s size is not a power of 2\n", p->name);
-
-		APP_CHECK((p->burst_read > 0),
-			"%s read burst size is 0\n", p->name);
-
-		APP_CHECK((p->burst_read <= p->size),
-			"%s read burst size is bigger than its size\n",
-			p->name);
-
-		APP_CHECK((p->burst_write > 0),
-			"%s write burst size is 0\n", p->name);
-
-		APP_CHECK((p->burst_write <= p->size),
-			"%s write burst size is bigger than its size\n",
-			p->name);
-
-		APP_CHECK((n_readers != 0),
-			"%s has no reader\n", p->name);
-
-		if (n_readers > 1)
-			APP_LOG(app, LOW, "%s has more than one reader", p->name);
-
-		APP_CHECK((n_writers != 0),
-			"%s has no writer\n", p->name);
-
-		if (n_writers > 1)
-			APP_LOG(app, LOW, "%s has more than one writer", p->name);
-
-		n_flags = p->ipv4_frag + p->ipv6_frag + p->ipv4_ras + p->ipv6_ras;
-
-		APP_CHECK((n_flags < 2),
-			"%s has more than one fragmentation or reassembly mode enabled\n",
-			p->name);
-
-		APP_CHECK((!((n_readers > 1) && (n_flags == 1))),
-			"%s has more than one reader when fragmentation or reassembly"
-			" mode enabled\n",
-			p->name);
-
-		APP_CHECK((!((n_writers > 1) && (n_flags == 1))),
-			"%s has more than one writer when fragmentation or reassembly"
-			" mode enabled\n",
-			p->name);
-
-		n_flags = p->ipv4_ras + p->ipv6_ras;
-
-		APP_CHECK((!((p->dropless == 1) && (n_flags == 1))),
-			"%s has dropless when reassembly mode enabled\n", p->name);
-
-		n_flags = p->ipv4_frag + p->ipv6_frag;
-
-		if (n_flags == 1) {
-			uint16_t ip_hdr_size = (p->ipv4_frag) ? sizeof(struct ipv4_hdr) :
-				sizeof(struct ipv6_hdr);
-
-			APP_CHECK((p->mtu > ip_hdr_size),
-				"%s mtu size is smaller than ip header\n", p->name);
-
-			APP_CHECK((!((p->mtu - ip_hdr_size) % 8)),
-				"%s mtu size is incorrect\n", p->name);
-		}
-	}
-}
-
-static void
-check_tms(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_pktq_tm; i++) {
-		struct app_pktq_tm_params *p = &app->tm_params[i];
-		uint32_t n_readers = app_tm_get_readers(app, p);
-		uint32_t n_writers = app_tm_get_writers(app, p);
-
-		APP_CHECK((n_readers != 0),
-			"%s has no reader\n", p->name);
-
-		APP_CHECK((n_readers == 1),
-			"%s has more than one reader\n", p->name);
-
-		APP_CHECK((n_writers != 0),
-			"%s has no writer\n", p->name);
-
-		APP_CHECK((n_writers == 1),
-			"%s has more than one writer\n", p->name);
-	}
-}
-
-static void
-check_taps(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_pktq_tap; i++) {
-		struct app_pktq_tap_params *p = &app->tap_params[i];
-		uint32_t n_readers = app_tap_get_readers(app, p);
-		uint32_t n_writers = app_tap_get_writers(app, p);
-
-		APP_CHECK((n_readers != 0),
-			"%s has no reader\n", p->name);
-
-		APP_CHECK((n_readers == 1),
-			"%s has more than one reader\n", p->name);
-
-		APP_CHECK((n_writers != 0),
-			"%s has no writer\n", p->name);
-
-		APP_CHECK((n_writers == 1),
-			"%s has more than one writer\n", p->name);
-
-		APP_CHECK((p->burst_read > 0),
-			"%s read burst size is 0\n", p->name);
-
-		APP_CHECK((p->burst_write > 0),
-			"%s write burst size is 0\n", p->name);
-	}
-}
-
-static void
-check_knis(struct app_params *app) {
-	uint32_t i;
-
-	for (i = 0; i < app->n_pktq_kni; i++) {
-		struct app_pktq_kni_params *p = &app->kni_params[i];
-		uint32_t n_readers = app_kni_get_readers(app, p);
-		uint32_t n_writers = app_kni_get_writers(app, p);
-
-		APP_CHECK((n_readers != 0),
-			"%s has no reader\n", p->name);
-
-		APP_CHECK((n_readers == 1),
-			"%s has more than one reader\n", p->name);
-
-		APP_CHECK((n_writers != 0),
-			"%s has no writer\n", p->name);
-
-		APP_CHECK((n_writers == 1),
-			"%s has more than one writer\n", p->name);
-	}
-}
-
-static void
-check_sources(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_pktq_source; i++) {
-		struct app_pktq_source_params *p = &app->source_params[i];
-		uint32_t n_readers = app_source_get_readers(app, p);
-
-		APP_CHECK((n_readers != 0),
-			"%s has no reader\n", p->name);
-
-		APP_CHECK((n_readers == 1),
-			"%s has more than one reader\n", p->name);
-	}
-}
-
-static void
-check_sinks(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_pktq_sink; i++) {
-		struct app_pktq_sink_params *p = &app->sink_params[i];
-		uint32_t n_writers = app_sink_get_writers(app, p);
-
-		APP_CHECK((n_writers != 0),
-			"%s has no writer\n", p->name);
-
-		APP_CHECK((n_writers == 1),
-			"%s has more than one writer\n", p->name);
-	}
-}
-
-static void
-check_msgqs(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_msgq; i++) {
-		struct app_msgq_params *p = &app->msgq_params[i];
-		uint32_t n_readers = app_msgq_get_readers(app, p);
-		uint32_t n_writers = app_msgq_get_writers(app, p);
-		uint32_t msgq_req_pipeline, msgq_rsp_pipeline;
-		uint32_t msgq_req_core, msgq_rsp_core;
-
-		APP_CHECK((p->size > 0),
-			"%s size is 0\n", p->name);
-
-		APP_CHECK((rte_is_power_of_2(p->size)),
-			"%s size is not a power of 2\n", p->name);
-
-		msgq_req_pipeline = (strncmp(p->name, "MSGQ-REQ-PIPELINE",
-			strlen("MSGQ-REQ-PIPELINE")) == 0);
-
-		msgq_rsp_pipeline = (strncmp(p->name, "MSGQ-RSP-PIPELINE",
-			strlen("MSGQ-RSP-PIPELINE")) == 0);
-
-		msgq_req_core = (strncmp(p->name, "MSGQ-REQ-CORE",
-			strlen("MSGQ-REQ-CORE")) == 0);
-
-		msgq_rsp_core = (strncmp(p->name, "MSGQ-RSP-CORE",
-			strlen("MSGQ-RSP-CORE")) == 0);
-
-		if ((msgq_req_pipeline == 0) &&
-			(msgq_rsp_pipeline == 0) &&
-			(msgq_req_core == 0) &&
-			(msgq_rsp_core == 0)) {
-			APP_CHECK((n_readers != 0),
-				"%s has no reader\n", p->name);
-
-			APP_CHECK((n_readers == 1),
-				"%s has more than one reader\n", p->name);
-
-			APP_CHECK((n_writers != 0),
-				"%s has no writer\n", p->name);
-
-			APP_CHECK((n_writers == 1),
-				"%s has more than one writer\n", p->name);
-		}
-
-		if (msgq_req_pipeline) {
-			struct app_pipeline_params *pipeline;
-			uint32_t pipeline_id;
-
-			APP_PARAM_GET_ID(p, "MSGQ-REQ-PIPELINE", pipeline_id);
-
-			APP_PARAM_FIND_BY_ID(app->pipeline_params,
-				"PIPELINE",
-				pipeline_id,
-				pipeline);
-
-			APP_CHECK((pipeline != NULL),
-				"%s is not associated with a valid pipeline\n",
-				p->name);
-		}
-
-		if (msgq_rsp_pipeline) {
-			struct app_pipeline_params *pipeline;
-			uint32_t pipeline_id;
-
-			APP_PARAM_GET_ID(p, "MSGQ-RSP-PIPELINE", pipeline_id);
-
-			APP_PARAM_FIND_BY_ID(app->pipeline_params,
-				"PIPELINE",
-				pipeline_id,
-				pipeline);
-
-			APP_CHECK((pipeline != NULL),
-				"%s is not associated with a valid pipeline\n",
-				p->name);
-		}
-	}
-}
-
-static void
-check_pipelines(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-
-		APP_CHECK((p->n_msgq_in == p->n_msgq_out),
-			"%s number of input MSGQs does not match "
-			"the number of output MSGQs\n", p->name);
-	}
-}
-
-int
-app_config_check(struct app_params *app)
-{
-	check_mempools(app);
-	check_links(app);
-	check_rxqs(app);
-	check_txqs(app);
-	check_swqs(app);
-	check_tms(app);
-	check_taps(app);
-	check_knis(app);
-	check_sources(app);
-	check_sinks(app);
-	check_msgqs(app);
-	check_pipelines(app);
-
-	return 0;
-}
diff --git a/examples/ip_pipeline/config_parse.c b/examples/ip_pipeline/config_parse.c
deleted file mode 100644
index e90499e..0000000
--- a/examples/ip_pipeline/config_parse.c
+++ /dev/null
@@ -1,3395 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2016 Intel Corporation
- */
-
-#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 <libgen.h>
-#include <unistd.h>
-#include <sys/wait.h>
-
-#include <rte_errno.h>
-#include <rte_cfgfile.h>
-#include <rte_string_fns.h>
-
-#include "app.h"
-#include "parser.h"
-
-/**
- * Default config values
- **/
-
-static struct app_params app_params_default = {
-	.config_file = "./config/ip_pipeline.cfg",
-	.log_level = APP_LOG_LEVEL_HIGH,
-	.port_mask = 0,
-
-	.eal_params = {
-		.channels = 4,
-	},
-};
-
-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_q = 0,
-	.ip_local_q = 0,
-	.tcp_local_q = 0,
-	.udp_local_q = 0,
-	.sctp_local_q = 0,
-	.rss_qs = {0},
-	.n_rss_qs = 0,
-	.rss_proto_ipv4 = ETH_RSS_IPV4,
-	.rss_proto_ipv6 = ETH_RSS_IPV6,
-	.rss_proto_l2 = 0,
-	.state = 0,
-	.ip = 0,
-	.depth = 0,
-	.mac_addr = 0,
-	.pci_bdf = {0},
-
-	.conf = {
-		.link_speeds = 0,
-		.rxmode = {
-			.mq_mode = ETH_MQ_RX_NONE,
-
-			.ignore_offload_bitfield = 1,
-			.offloads = DEV_RX_OFFLOAD_CRC_STRIP,
-
-			.max_rx_pkt_len = 9000, /* Jumbo frame max packet len */
-			.split_hdr_size = 0, /* Header split buffer size */
-		},
-		.rx_adv_conf = {
-			.rss_conf = {
-				.rss_key = NULL,
-				.rss_key_len = 40,
-				.rss_hf = 0,
-			},
-		},
-		.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_IGNORE,
-		.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,
-	.ipv4_frag = 0,
-	.ipv6_frag = 0,
-	.ipv4_ras = 0,
-	.ipv6_ras = 0,
-	.mtu = 0,
-	.metadata_size = 0,
-	.mempool_direct_id = 0,
-	.mempool_indirect_id = 0,
-};
-
-struct app_pktq_tm_params default_tm_params = {
-	.parsed = 0,
-	.file_name = "./config/tm_profile.cfg",
-	.burst_read = 24,
-	.burst_write = 32,
-};
-
-struct app_pktq_tap_params default_tap_params = {
-	.parsed = 0,
-	.burst_read = 32,
-	.burst_write = 32,
-	.dropless = 0,
-	.n_retries = 0,
-	.mempool_id = 0,
-};
-
-struct app_pktq_kni_params default_kni_params = {
-	.parsed = 0,
-	.socket_id = 0,
-	.core_id = 0,
-	.hyper_th_id = 0,
-	.force_bind = 0,
-
-	.mempool_id = 0,
-	.burst_read = 32,
-	.burst_write = 32,
-	.dropless = 0,
-	.n_retries = 0,
-};
-
-struct app_pktq_source_params default_source_params = {
-	.parsed = 0,
-	.mempool_id = 0,
-	.burst = 32,
-	.file_name = "./config/packets.pcap",
-	.n_bytes_per_pkt = 0,
-};
-
-struct app_pktq_sink_params default_sink_params = {
-	.parsed = 0,
-	.file_name = NULL,
-	.n_pkts_to_dump = 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] "
-	"[-l LOG_LEVEL] [--preproc PREPROCESSOR] [--preproc-args ARGS]\n"
-	"\n"
-	"Arguments:\n"
-	"\t-f CONFIG_FILE: Default config file is %s\n"
-	"\t-p PORT_MASK: Mask of NIC port IDs in hex format (generated from "
-		"config file when not provided)\n"
-	"\t-s SCRIPT_FILE: No CLI script file is run when not specified\n"
-	"\t-l LOG_LEVEL: 0 = NONE, 1 = HIGH PRIO (default), 2 = LOW PRIO\n"
-	"\t--preproc PREPROCESSOR: Configuration file pre-processor\n"
-	"\t--preproc-args ARGS: Arguments to be passed to pre-processor\n"
-	"\n";
-
-static void
-app_print_usage(char *prgname)
-{
-	rte_exit(0, app_usage, prgname, app_params_default.config_file);
-}
-
-#define APP_PARAM_ADD(set, key)						\
-({									\
-	ssize_t pos = APP_PARAM_FIND(set, key);				\
-	ssize_t size = RTE_DIM(set);					\
-									\
-	if (pos < 0) {							\
-		for (pos = 0; pos < size; pos++) {			\
-			if (!APP_PARAM_VALID(&((set)[pos])))		\
-				break;					\
-		}							\
-									\
-		APP_CHECK((pos < size),					\
-			"Parse error: size of %s is limited to %u elements",\
-			#set, (uint32_t) size);				\
-									\
-		(set)[pos].name = strdup(key);				\
-		APP_CHECK(((set)[pos].name),				\
-			"Parse error: no free memory");			\
-	}								\
-	pos;								\
-})
-
-#define APP_PARAM_ADD_LINK_FOR_RXQ(app, rxq_name)			\
-({									\
-	char link_name[APP_PARAM_NAME_SIZE];				\
-	ssize_t link_param_pos;						\
-	uint32_t link_id, queue_id;				\
-									\
-	sscanf((rxq_name), "RXQ%" SCNu32 ".%" SCNu32, &link_id, &queue_id);\
-	sprintf(link_name, "LINK%" PRIu32, link_id);			\
-	link_param_pos = APP_PARAM_ADD((app)->link_params, link_name);	\
-	link_param_pos;							\
-})
-
-#define APP_PARAM_ADD_LINK_FOR_TXQ(app, txq_name)			\
-({									\
-	char link_name[APP_PARAM_NAME_SIZE];				\
-	ssize_t link_param_pos;						\
-	uint32_t link_id, queue_id;					\
-									\
-	sscanf((txq_name), "TXQ%" SCNu32 ".%" SCNu32, &link_id, &queue_id);\
-	sprintf(link_name, "LINK%" PRIu32, link_id);			\
-	link_param_pos = APP_PARAM_ADD((app)->link_params, link_name);	\
-	link_param_pos;							\
-})
-
-#define APP_PARAM_ADD_LINK_FOR_TM(app, tm_name)				\
-({									\
-	char link_name[APP_PARAM_NAME_SIZE];				\
-	ssize_t link_param_pos;						\
-	uint32_t link_id;						\
-									\
-	sscanf((tm_name), "TM%" SCNu32, &link_id);			\
-	sprintf(link_name, "LINK%" PRIu32, link_id);			\
-	link_param_pos = APP_PARAM_ADD((app)->link_params, link_name);	\
-	link_param_pos;							\
-})
-
-#define APP_PARAM_ADD_LINK_FOR_KNI(app, kni_name)			\
-({									\
-	char link_name[APP_PARAM_NAME_SIZE];				\
-	ssize_t link_param_pos;						\
-	uint32_t link_id;						\
-									\
-	sscanf((kni_name), "KNI%" SCNu32, &link_id);		\
-	sprintf(link_name, "LINK%" PRIu32, link_id);			\
-	link_param_pos = APP_PARAM_ADD((app)->link_params, link_name);	\
-	link_param_pos;							\
-})
-
-#define PARSE_CHECK_DUPLICATE_SECTION(obj)				\
-do {									\
-	APP_CHECK(((obj)->parsed == 0),					\
-		"Parse error: duplicate \"%s\" section", (obj)->name);	\
-	(obj)->parsed++;					\
-} while (0)
-
-#define PARSE_CHECK_DUPLICATE_SECTION_EAL(obj)				\
-do {									\
-	APP_CHECK(((obj)->parsed == 0),					\
-		"Parse error: duplicate \"%s\" section", "EAL");	\
-	(obj)->parsed++;					\
-} while (0)
-
-#define PARSE_ERROR(exp, section, entry)				\
-APP_CHECK(exp, "Parse error in section \"%s\": entry \"%s\"", section, entry)
-
-#define PARSE_ERROR_MESSAGE(exp, section, entry, message)		\
-APP_CHECK(exp, "Parse error in section \"%s\", entry \"%s\": %s",	\
-	section, entry, message)
-
-#define PARSE_ERROR_NO_ELEMENTS(exp, section, entry)			\
-APP_CHECK(exp, "Parse error in section \"%s\", entry \"%s\": "		\
-	"no elements detected",						\
-	section, entry)
-
-#define PARSE_ERROR_TOO_MANY_ELEMENTS(exp, section, entry, max)		\
-APP_CHECK(exp, "Parse error in section \"%s\", entry \"%s\": "		\
-	"maximum number of elements allowed is %u",			\
-	section, entry, max)
-
-#define PARSE_ERROR_INVALID_ELEMENT(exp, section, entry, value)		\
-APP_CHECK(exp, "Parse error in section \"%s\", entry \"%s\": "		\
-	"Invalid element value \"%s\"",					\
-	section, entry, value)
-
-#define PARSE_ERROR_MALLOC(exp)						\
-APP_CHECK(exp, "Parse error: no free memory")
-
-#define PARSE_ERROR_SECTION(exp, section)				\
-APP_CHECK(exp, "Parse error in section \"%s\"", section)
-
-#define PARSE_ERROR_SECTION_NO_ENTRIES(exp, section)			\
-APP_CHECK(exp, "Parse error in section \"%s\": no entries", section)
-
-#define PARSE_WARNING_IGNORED(exp, section, entry)			\
-do									\
-if (!(exp))								\
-	fprintf(stderr, "Parse warning in section \"%s\": "		\
-		"entry \"%s\" is ignored", section, entry);		\
-while (0)
-
-#define PARSE_ERROR_INVALID(exp, section, entry)			\
-APP_CHECK(exp, "Parse error in section \"%s\": unrecognized entry \"%s\"",\
-	section, entry)
-
-#define PARSE_ERROR_DUPLICATE(exp, section, entry)			\
-APP_CHECK(exp, "Parse error in section \"%s\": duplicate entry \"%s\"",	\
-	section, entry)
-
-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 void
-parse_eal(struct app_params *app,
-	const char *section_name,
-	struct rte_cfgfile *cfg)
-{
-	struct app_eal_params *p = &app->eal_params;
-	struct rte_cfgfile_entry *entries;
-	int n_entries, i;
-
-	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
-	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
-
-	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
-	PARSE_ERROR_MALLOC(entries != NULL);
-
-	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
-
-	PARSE_CHECK_DUPLICATE_SECTION_EAL(p);
-
-	for (i = 0; i < n_entries; i++) {
-		struct rte_cfgfile_entry *entry = &entries[i];
-
-		/* coremask */
-		if (strcmp(entry->name, "c") == 0) {
-			PARSE_WARNING_IGNORED(0, section_name, entry->name);
-			continue;
-		}
-
-		/* corelist */
-		if (strcmp(entry->name, "l") == 0) {
-			PARSE_WARNING_IGNORED(0, section_name, entry->name);
-			continue;
-		}
-
-		/* coremap */
-		if (strcmp(entry->name, "lcores") == 0) {
-			PARSE_ERROR_DUPLICATE((p->coremap == NULL),
-				section_name,
-				entry->name);
-			p->coremap = strdup(entry->value);
-			continue;
-		}
-
-		/* master_lcore */
-		if (strcmp(entry->name, "master_lcore") == 0) {
-			int status;
-
-			PARSE_ERROR_DUPLICATE((p->master_lcore_present == 0),
-				section_name,
-				entry->name);
-			p->master_lcore_present = 1;
-
-			status = parser_read_uint32(&p->master_lcore,
-				entry->value);
-			PARSE_ERROR((status == 0), section_name, entry->name);
-			continue;
-		}
-
-		/* channels */
-		if (strcmp(entry->name, "n") == 0) {
-			int status;
-
-			PARSE_ERROR_DUPLICATE((p->channels_present == 0),
-				section_name,
-				entry->name);
-			p->channels_present = 1;
-
-			status = parser_read_uint32(&p->channels, entry->value);
-			PARSE_ERROR((status == 0), section_name, entry->name);
-			continue;
-		}
-
-		/* memory */
-		if (strcmp(entry->name, "m") == 0) {
-			int status;
-
-			PARSE_ERROR_DUPLICATE((p->memory_present == 0),
-				section_name,
-				entry->name);
-			p->memory_present = 1;
-
-			status = parser_read_uint32(&p->memory, entry->value);
-			PARSE_ERROR((status == 0), section_name, entry->name);
-			continue;
-		}
-
-		/* ranks */
-		if (strcmp(entry->name, "r") == 0) {
-			int status;
-
-			PARSE_ERROR_DUPLICATE((p->ranks_present == 0),
-				section_name,
-				entry->name);
-			p->ranks_present = 1;
-
-			status = parser_read_uint32(&p->ranks, entry->value);
-			PARSE_ERROR((status == 0), section_name, entry->name);
-			continue;
-		}
-
-		/* pci_blacklist */
-		if ((strcmp(entry->name, "pci_blacklist") == 0) ||
-			(strcmp(entry->name, "b") == 0)) {
-			uint32_t i;
-
-			for (i = 0; i < APP_MAX_LINKS; i++) {
-				if (p->pci_blacklist[i])
-					continue;
-
-				p->pci_blacklist[i] =
-					strdup(entry->value);
-				PARSE_ERROR_MALLOC(p->pci_blacklist[i]);
-
-				break;
-			}
-
-			PARSE_ERROR_MESSAGE((i < APP_MAX_LINKS),
-				section_name, entry->name,
-				"too many elements");
-			continue;
-		}
-
-		/* pci_whitelist */
-		if ((strcmp(entry->name, "pci_whitelist") == 0) ||
-			(strcmp(entry->name, "w") == 0)) {
-			uint32_t i;
-
-			PARSE_ERROR_MESSAGE((app->port_mask != 0),
-				section_name, entry->name, "entry to be "
-				"generated by the application (port_mask "
-				"not provided)");
-
-			for (i = 0; i < APP_MAX_LINKS; i++) {
-				if (p->pci_whitelist[i])
-					continue;
-
-				p->pci_whitelist[i] = strdup(entry->value);
-				PARSE_ERROR_MALLOC(p->pci_whitelist[i]);
-
-				break;
-			}
-
-			PARSE_ERROR_MESSAGE((i < APP_MAX_LINKS),
-				section_name, entry->name,
-				"too many elements");
-			continue;
-		}
-
-		/* vdev */
-		if (strcmp(entry->name, "vdev") == 0) {
-			uint32_t i;
-
-			for (i = 0; i < APP_MAX_LINKS; i++) {
-				if (p->vdev[i])
-					continue;
-
-				p->vdev[i] = strdup(entry->value);
-				PARSE_ERROR_MALLOC(p->vdev[i]);
-
-				break;
-			}
-
-			PARSE_ERROR_MESSAGE((i < APP_MAX_LINKS),
-				section_name, entry->name,
-				"too many elements");
-			continue;
-		}
-
-		/* vmware_tsc_map */
-		if (strcmp(entry->name, "vmware_tsc_map") == 0) {
-			int val;
-
-			PARSE_ERROR_DUPLICATE((p->vmware_tsc_map_present == 0),
-				section_name,
-				entry->name);
-			p->vmware_tsc_map_present = 1;
-
-			val = parser_read_arg_bool(entry->value);
-			PARSE_ERROR((val >= 0), section_name, entry->name);
-			p->vmware_tsc_map = val;
-			continue;
-		}
-
-		/* proc_type */
-		if (strcmp(entry->name, "proc_type") == 0) {
-			PARSE_ERROR_DUPLICATE((p->proc_type == NULL),
-				section_name,
-				entry->name);
-			p->proc_type = strdup(entry->value);
-			continue;
-		}
-
-		/* syslog */
-		if (strcmp(entry->name, "syslog") == 0) {
-			PARSE_ERROR_DUPLICATE((p->syslog == NULL),
-				section_name,
-				entry->name);
-			p->syslog = strdup(entry->value);
-			continue;
-		}
-
-		/* log_level */
-		if (strcmp(entry->name, "log_level") == 0) {
-			int status;
-
-			PARSE_ERROR_DUPLICATE((p->log_level_present == 0),
-				section_name,
-				entry->name);
-			p->log_level_present = 1;
-
-			status = parser_read_uint32(&p->log_level,
-				entry->value);
-			PARSE_ERROR((status == 0), section_name, entry->name);
-			continue;
-		}
-
-		/* version */
-		if (strcmp(entry->name, "v") == 0) {
-			int val;
-
-			PARSE_ERROR_DUPLICATE((p->version_present == 0),
-				section_name,
-				entry->name);
-			p->version_present = 1;
-
-			val = parser_read_arg_bool(entry->value);
-			PARSE_ERROR((val >= 0), section_name, entry->name);
-			p->version = val;
-			continue;
-		}
-
-		/* help */
-		if ((strcmp(entry->name, "help") == 0) ||
-			(strcmp(entry->name, "h") == 0)) {
-			int val;
-
-			PARSE_ERROR_DUPLICATE((p->help_present == 0),
-				section_name,
-				entry->name);
-			p->help_present = 1;
-
-			val = parser_read_arg_bool(entry->value);
-			PARSE_ERROR((val >= 0), section_name, entry->name);
-			p->help = val;
-			continue;
-		}
-
-		/* no_huge */
-		if (strcmp(entry->name, "no_huge") == 0) {
-			int val;
-
-			PARSE_ERROR_DUPLICATE((p->no_huge_present == 0),
-				section_name,
-				entry->name);
-			p->no_huge_present = 1;
-
-			val = parser_read_arg_bool(entry->value);
-			PARSE_ERROR((val >= 0), section_name, entry->name);
-			p->no_huge = val;
-			continue;
-		}
-
-		/* no_pci */
-		if (strcmp(entry->name, "no_pci") == 0) {
-			int val;
-
-			PARSE_ERROR_DUPLICATE((p->no_pci_present == 0),
-				section_name,
-				entry->name);
-			p->no_pci_present = 1;
-
-			val = parser_read_arg_bool(entry->value);
-			PARSE_ERROR((val >= 0), section_name, entry->name);
-			p->no_pci = val;
-			continue;
-		}
-
-		/* no_hpet */
-		if (strcmp(entry->name, "no_hpet") == 0) {
-			int val;
-
-			PARSE_ERROR_DUPLICATE((p->no_hpet_present == 0),
-				section_name,
-				entry->name);
-			p->no_hpet_present = 1;
-
-			val = parser_read_arg_bool(entry->value);
-			PARSE_ERROR((val >= 0), section_name, entry->name);
-			p->no_hpet = val;
-			continue;
-		}
-
-		/* no_shconf */
-		if (strcmp(entry->name, "no_shconf") == 0) {
-			int val;
-
-			PARSE_ERROR_DUPLICATE((p->no_shconf_present == 0),
-				section_name,
-				entry->name);
-			p->no_shconf_present = 1;
-
-			val = parser_read_arg_bool(entry->value);
-			PARSE_ERROR((val >= 0), section_name, entry->name);
-			p->no_shconf = val;
-			continue;
-		}
-
-		/* add_driver */
-		if (strcmp(entry->name, "d") == 0) {
-			PARSE_ERROR_DUPLICATE((p->add_driver == NULL),
-				section_name,
-				entry->name);
-			p->add_driver = strdup(entry->value);
-			continue;
-		}
-
-		/* socket_mem */
-		if (strcmp(entry->name, "socket_mem") == 0) {
-			PARSE_ERROR_DUPLICATE((p->socket_mem == NULL),
-				section_name,
-				entry->name);
-			p->socket_mem = strdup(entry->value);
-			continue;
-		}
-
-		/* huge_dir */
-		if (strcmp(entry->name, "huge_dir") == 0) {
-			PARSE_ERROR_DUPLICATE((p->huge_dir == NULL),
-				section_name,
-				entry->name);
-			p->huge_dir = strdup(entry->value);
-			continue;
-		}
-
-		/* file_prefix */
-		if (strcmp(entry->name, "file_prefix") == 0) {
-			PARSE_ERROR_DUPLICATE((p->file_prefix == NULL),
-				section_name,
-				entry->name);
-			p->file_prefix = strdup(entry->value);
-			continue;
-		}
-
-		/* base_virtaddr */
-		if (strcmp(entry->name, "base_virtaddr") == 0) {
-			PARSE_ERROR_DUPLICATE((p->base_virtaddr == NULL),
-				section_name,
-				entry->name);
-			p->base_virtaddr = strdup(entry->value);
-			continue;
-		}
-
-		/* create_uio_dev */
-		if (strcmp(entry->name, "create_uio_dev") == 0) {
-			int val;
-
-			PARSE_ERROR_DUPLICATE((p->create_uio_dev_present == 0),
-				section_name,
-				entry->name);
-			p->create_uio_dev_present = 1;
-
-			val = parser_read_arg_bool(entry->value);
-			PARSE_ERROR((val >= 0), section_name, entry->name);
-			p->create_uio_dev = val;
-			continue;
-		}
-
-		/* vfio_intr */
-		if (strcmp(entry->name, "vfio_intr") == 0) {
-			PARSE_ERROR_DUPLICATE((p->vfio_intr == NULL),
-				section_name,
-				entry->name);
-			p->vfio_intr = strdup(entry->value);
-			continue;
-		}
-
-		/* unrecognized */
-		PARSE_ERROR_INVALID(0, section_name, entry->name);
-	}
-
-	free(entries);
-}
-
-static void
-parse_pipeline_pktq_in(struct app_params *app,
-	struct app_pipeline_params *p,
-	char *value)
-{
-	p->n_pktq_in = 0;
-
-	while (1) {
-		enum app_pktq_in_type type;
-		int id;
-		char *name = strtok_r(value, PARSE_DELIMITER, &value);
-
-		if (name == NULL)
-			break;
-
-		PARSE_ERROR_TOO_MANY_ELEMENTS(
-			(p->n_pktq_in < RTE_DIM(p->pktq_in)),
-			p->name, "pktq_in", (uint32_t)RTE_DIM(p->pktq_in));
-
-		if (validate_name(name, "RXQ", 2) == 0) {
-			type = APP_PKTQ_IN_HWQ;
-			id = APP_PARAM_ADD(app->hwq_in_params, name);
-			APP_PARAM_ADD_LINK_FOR_RXQ(app, 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);
-			APP_PARAM_ADD_LINK_FOR_TM(app, name);
-		} else if (validate_name(name, "TAP", 1) == 0) {
-			type = APP_PKTQ_IN_TAP;
-			id = APP_PARAM_ADD(app->tap_params, name);
-		} else if (validate_name(name, "KNI", 1) == 0) {
-			type = APP_PKTQ_IN_KNI;
-			id = APP_PARAM_ADD(app->kni_params, name);
-			APP_PARAM_ADD_LINK_FOR_KNI(app, name);
-		} else if (validate_name(name, "SOURCE", 1) == 0) {
-			type = APP_PKTQ_IN_SOURCE;
-			id = APP_PARAM_ADD(app->source_params, name);
-		} else
-			PARSE_ERROR_INVALID_ELEMENT(0,
-				p->name, "pktq_in", name);
-
-		p->pktq_in[p->n_pktq_in].type = type;
-		p->pktq_in[p->n_pktq_in].id = (uint32_t) id;
-		p->n_pktq_in++;
-	}
-
-	PARSE_ERROR_NO_ELEMENTS((p->n_pktq_in > 0), p->name, "pktq_in");
-}
-
-static void
-parse_pipeline_pktq_out(struct app_params *app,
-	struct app_pipeline_params *p,
-	char *value)
-{
-	p->n_pktq_out = 0;
-
-	while (1) {
-		enum app_pktq_out_type type;
-		int id;
-		char *name = strtok_r(value, PARSE_DELIMITER, &value);
-
-		if (name == NULL)
-			break;
-
-		PARSE_ERROR_TOO_MANY_ELEMENTS(
-			(p->n_pktq_out < RTE_DIM(p->pktq_out)),
-			p->name, "pktq_out", (uint32_t)RTE_DIM(p->pktq_out));
-
-		if (validate_name(name, "TXQ", 2) == 0) {
-			type = APP_PKTQ_OUT_HWQ;
-			id = APP_PARAM_ADD(app->hwq_out_params, name);
-			APP_PARAM_ADD_LINK_FOR_TXQ(app, 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);
-			APP_PARAM_ADD_LINK_FOR_TM(app, name);
-		} else if (validate_name(name, "TAP", 1) == 0) {
-			type = APP_PKTQ_OUT_TAP;
-			id = APP_PARAM_ADD(app->tap_params, name);
-		} else if (validate_name(name, "KNI", 1) == 0) {
-			type = APP_PKTQ_OUT_KNI;
-			id = APP_PARAM_ADD(app->kni_params, name);
-			APP_PARAM_ADD_LINK_FOR_KNI(app, name);
-		} else if (validate_name(name, "SINK", 1) == 0) {
-			type = APP_PKTQ_OUT_SINK;
-			id = APP_PARAM_ADD(app->sink_params, name);
-		} else
-			PARSE_ERROR_INVALID_ELEMENT(0,
-				p->name, "pktq_out", name);
-
-		p->pktq_out[p->n_pktq_out].type = type;
-		p->pktq_out[p->n_pktq_out].id = id;
-		p->n_pktq_out++;
-	}
-
-	PARSE_ERROR_NO_ELEMENTS((p->n_pktq_out > 0), p->name, "pktq_out");
-}
-
-static void
-parse_pipeline_msgq_in(struct app_params *app,
-	struct app_pipeline_params *p,
-	char *value)
-{
-	p->n_msgq_in = 0;
-
-	while (1) {
-		int idx;
-		char *name = strtok_r(value, PARSE_DELIMITER, &value);
-
-		if (name == NULL)
-			break;
-
-		PARSE_ERROR_TOO_MANY_ELEMENTS(
-			(p->n_msgq_in < RTE_DIM(p->msgq_in)),
-			p->name, "msgq_in", (uint32_t)(RTE_DIM(p->msgq_in)));
-
-		PARSE_ERROR_INVALID_ELEMENT(
-			(validate_name(name, "MSGQ", 1) == 0),
-			p->name, "msgq_in", name);
-
-		idx = APP_PARAM_ADD(app->msgq_params, name);
-		p->msgq_in[p->n_msgq_in] = idx;
-		p->n_msgq_in++;
-	}
-
-	PARSE_ERROR_NO_ELEMENTS((p->n_msgq_in > 0), p->name, "msgq_in");
-}
-
-static void
-parse_pipeline_msgq_out(struct app_params *app,
-	struct app_pipeline_params *p,
-	char *value)
-{
-	p->n_msgq_out = 0;
-
-	while (1) {
-		int idx;
-		char *name = strtok_r(value, PARSE_DELIMITER, &value);
-
-		if (name == NULL)
-			break;
-
-		PARSE_ERROR_TOO_MANY_ELEMENTS(
-			(p->n_msgq_out < RTE_DIM(p->msgq_out)),
-			p->name, "msgq_out", (uint32_t)RTE_DIM(p->msgq_out));
-
-		PARSE_ERROR_INVALID_ELEMENT(
-			(validate_name(name, "MSGQ", 1) == 0),
-			p->name, "msgq_out", name);
-
-		idx = APP_PARAM_ADD(app->msgq_params, name);
-		p->msgq_out[p->n_msgq_out] = idx;
-		p->n_msgq_out++;
-	}
-
-	PARSE_ERROR_NO_ELEMENTS((p->n_msgq_out > 0), p->name, "msgq_out");
-}
-
-static void
-parse_pipeline(struct app_params *app,
-	const char *section_name,
-	struct rte_cfgfile *cfg)
-{
-	char name[CFG_NAME_LEN];
-	struct app_pipeline_params *param;
-	struct rte_cfgfile_entry *entries;
-	ssize_t param_idx;
-	int n_entries, i;
-
-	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
-	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
-
-	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
-	PARSE_ERROR_MALLOC(entries != NULL);
-
-	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
-
-	param_idx = APP_PARAM_ADD(app->pipeline_params, section_name);
-	param = &app->pipeline_params[param_idx];
-	PARSE_CHECK_DUPLICATE_SECTION(param);
-
-	for (i = 0; i < n_entries; i++) {
-		struct rte_cfgfile_entry *ent = &entries[i];
-
-		if (strcmp(ent->name, "type") == 0) {
-			int w_size = snprintf(param->type, RTE_DIM(param->type),
-					"%s", ent->value);
-
-			PARSE_ERROR(((w_size > 0) &&
-				(w_size < (int)RTE_DIM(param->type))),
-				section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "core") == 0) {
-			int status = parse_pipeline_core(
-				&param->socket_id, &param->core_id,
-				&param->hyper_th_id, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "pktq_in") == 0) {
-			parse_pipeline_pktq_in(app, param, ent->value);
-
-			continue;
-		}
-
-		if (strcmp(ent->name, "pktq_out") == 0) {
-			parse_pipeline_pktq_out(app, param, ent->value);
-
-			continue;
-		}
-
-		if (strcmp(ent->name, "msgq_in") == 0) {
-			parse_pipeline_msgq_in(app, param, ent->value);
-
-			continue;
-		}
-
-		if (strcmp(ent->name, "msgq_out") == 0) {
-			parse_pipeline_msgq_out(app, param, ent->value);
-
-			continue;
-		}
-
-		if (strcmp(ent->name, "timer_period") == 0) {
-			int status = parser_read_uint32(
-				&param->timer_period,
-				ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		/* pipeline type specific items */
-		APP_CHECK((param->n_args < APP_MAX_PIPELINE_ARGS),
-			"Parse error in section \"%s\": too many "
-			"pipeline specified parameters", section_name);
-
-		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),
-			"Parse error: no free memory");
-
-		param->n_args++;
-	}
-
-	snprintf(name, sizeof(name), "MSGQ-REQ-%s", section_name);
-	param_idx = APP_PARAM_ADD(app->msgq_params, 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", section_name);
-	param_idx = APP_PARAM_ADD(app->msgq_params, 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);
-	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);
-	app->msgq_params[param_idx].cpu_socket_id = param->socket_id;
-
-	free(entries);
-}
-
-static void
-parse_mempool(struct app_params *app,
-	const char *section_name,
-	struct rte_cfgfile *cfg)
-{
-	struct app_mempool_params *param;
-	struct rte_cfgfile_entry *entries;
-	ssize_t param_idx;
-	int n_entries, i;
-
-	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
-	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
-
-	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
-	PARSE_ERROR_MALLOC(entries != NULL);
-
-	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
-
-	param_idx = APP_PARAM_ADD(app->mempool_params, section_name);
-	param = &app->mempool_params[param_idx];
-	PARSE_CHECK_DUPLICATE_SECTION(param);
-
-	for (i = 0; i < n_entries; i++) {
-		struct rte_cfgfile_entry *ent = &entries[i];
-
-		if (strcmp(ent->name, "buffer_size") == 0) {
-			int status = parser_read_uint32(
-				&param->buffer_size, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "pool_size") == 0) {
-			int status = parser_read_uint32(
-				&param->pool_size, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "cache_size") == 0) {
-			int status = parser_read_uint32(
-				&param->cache_size, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "cpu") == 0) {
-			int status = parser_read_uint32(
-				&param->cpu_socket_id, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		/* unrecognized */
-		PARSE_ERROR_INVALID(0, section_name, ent->name);
-	}
-
-	free(entries);
-}
-
-static int
-parse_link_rss_qs(struct app_link_params *p,
-	char *value)
-{
-	p->n_rss_qs = 0;
-
-	while (1) {
-		char *token = strtok_r(value, PARSE_DELIMITER, &value);
-
-		if (token == NULL)
-			break;
-
-		if (p->n_rss_qs == RTE_DIM(p->rss_qs))
-			return -ENOMEM;
-
-		if (parser_read_uint32(&p->rss_qs[p->n_rss_qs++], token))
-			return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int
-parse_link_rss_proto_ipv4(struct app_link_params *p,
-	char *value)
-{
-	uint64_t mask = 0;
-
-	while (1) {
-		char *token = strtok_r(value, PARSE_DELIMITER, &value);
-
-		if (token == NULL)
-			break;
-
-		if (strcmp(token, "IP") == 0) {
-			mask |= ETH_RSS_IPV4;
-			continue;
-		}
-		if (strcmp(token, "FRAG") == 0) {
-			mask |= ETH_RSS_FRAG_IPV4;
-			continue;
-		}
-		if (strcmp(token, "TCP") == 0) {
-			mask |= ETH_RSS_NONFRAG_IPV4_TCP;
-			continue;
-		}
-		if (strcmp(token, "UDP") == 0) {
-			mask |= ETH_RSS_NONFRAG_IPV4_UDP;
-			continue;
-		}
-		if (strcmp(token, "SCTP") == 0) {
-			mask |= ETH_RSS_NONFRAG_IPV4_SCTP;
-			continue;
-		}
-		if (strcmp(token, "OTHER") == 0) {
-			mask |= ETH_RSS_NONFRAG_IPV4_OTHER;
-			continue;
-		}
-		return -EINVAL;
-	}
-
-	p->rss_proto_ipv4 = mask;
-	return 0;
-}
-
-static int
-parse_link_rss_proto_ipv6(struct app_link_params *p,
-	char *value)
-{
-	uint64_t mask = 0;
-
-	while (1) {
-		char *token = strtok_r(value, PARSE_DELIMITER, &value);
-
-		if (token == NULL)
-			break;
-
-		if (strcmp(token, "IP") == 0) {
-			mask |= ETH_RSS_IPV6;
-			continue;
-		}
-		if (strcmp(token, "FRAG") == 0) {
-			mask |= ETH_RSS_FRAG_IPV6;
-			continue;
-		}
-		if (strcmp(token, "TCP") == 0) {
-			mask |= ETH_RSS_NONFRAG_IPV6_TCP;
-			continue;
-		}
-		if (strcmp(token, "UDP") == 0) {
-			mask |= ETH_RSS_NONFRAG_IPV6_UDP;
-			continue;
-		}
-		if (strcmp(token, "SCTP") == 0) {
-			mask |= ETH_RSS_NONFRAG_IPV6_SCTP;
-			continue;
-		}
-		if (strcmp(token, "OTHER") == 0) {
-			mask |= ETH_RSS_NONFRAG_IPV6_OTHER;
-			continue;
-		}
-		if (strcmp(token, "IP_EX") == 0) {
-			mask |= ETH_RSS_IPV6_EX;
-			continue;
-		}
-		if (strcmp(token, "TCP_EX") == 0) {
-			mask |= ETH_RSS_IPV6_TCP_EX;
-			continue;
-		}
-		if (strcmp(token, "UDP_EX") == 0) {
-			mask |= ETH_RSS_IPV6_UDP_EX;
-			continue;
-		}
-		return -EINVAL;
-	}
-
-	p->rss_proto_ipv6 = mask;
-	return 0;
-}
-
-static int
-parse_link_rss_proto_l2(struct app_link_params *p,
-	char *value)
-{
-	uint64_t mask = 0;
-
-	while (1) {
-		char *token = strtok_r(value, PARSE_DELIMITER, &value);
-
-		if (token == NULL)
-			break;
-
-		if (strcmp(token, "L2") == 0) {
-			mask |= ETH_RSS_L2_PAYLOAD;
-			continue;
-		}
-		return -EINVAL;
-	}
-
-	p->rss_proto_l2 = mask;
-	return 0;
-}
-
-static void
-parse_link(struct app_params *app,
-	const char *section_name,
-	struct rte_cfgfile *cfg)
-{
-	struct app_link_params *param;
-	struct rte_cfgfile_entry *entries;
-	int n_entries, i;
-	int rss_qs_present = 0;
-	int rss_proto_ipv4_present = 0;
-	int rss_proto_ipv6_present = 0;
-	int rss_proto_l2_present = 0;
-	int pci_bdf_present = 0;
-	ssize_t param_idx;
-
-	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
-	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
-
-	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
-	PARSE_ERROR_MALLOC(entries != NULL);
-
-	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
-
-	param_idx = APP_PARAM_ADD(app->link_params, section_name);
-	param = &app->link_params[param_idx];
-	PARSE_CHECK_DUPLICATE_SECTION(param);
-
-	for (i = 0; i < n_entries; i++) {
-		struct rte_cfgfile_entry *ent = &entries[i];
-
-		if (strcmp(ent->name, "promisc") == 0) {
-			int status = parser_read_arg_bool(ent->value);
-
-			PARSE_ERROR((status != -EINVAL), section_name,
-				ent->name);
-			param->promisc = status;
-			continue;
-		}
-
-		if (strcmp(ent->name, "arp_q") == 0) {
-			int status = parser_read_uint32(&param->arp_q,
-				ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "tcp_syn_q") == 0) {
-			int status = parser_read_uint32(
-				&param->tcp_syn_q, ent->value);
-
-			PARSE_ERROR((status == 0), section_name, ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "ip_local_q") == 0) {
-			int status = parser_read_uint32(
-				&param->ip_local_q, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "tcp_local_q") == 0) {
-			int status = parser_read_uint32(
-				&param->tcp_local_q, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "udp_local_q") == 0) {
-			int status = parser_read_uint32(
-				&param->udp_local_q, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "sctp_local_q") == 0) {
-			int status = parser_read_uint32(
-				&param->sctp_local_q, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "rss_qs") == 0) {
-			int status = parse_link_rss_qs(param, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			rss_qs_present = 1;
-			continue;
-		}
-
-		if (strcmp(ent->name, "rss_proto_ipv4") == 0) {
-			int status =
-				parse_link_rss_proto_ipv4(param, ent->value);
-
-			PARSE_ERROR((status != -EINVAL), section_name,
-				ent->name);
-			rss_proto_ipv4_present = 1;
-			continue;
-		}
-
-		if (strcmp(ent->name, "rss_proto_ipv6") == 0) {
-			int status =
-				parse_link_rss_proto_ipv6(param, ent->value);
-
-			PARSE_ERROR((status != -EINVAL), section_name,
-				ent->name);
-			rss_proto_ipv6_present = 1;
-			continue;
-		}
-
-		if (strcmp(ent->name, "rss_proto_l2") == 0) {
-			int status = parse_link_rss_proto_l2(param, ent->value);
-
-			PARSE_ERROR((status != -EINVAL), section_name,
-				ent->name);
-			rss_proto_l2_present = 1;
-			continue;
-		}
-
-		if (strcmp(ent->name, "pci_bdf") == 0) {
-			PARSE_ERROR_DUPLICATE((pci_bdf_present == 0),
-				section_name, ent->name);
-
-			snprintf(param->pci_bdf, APP_LINK_PCI_BDF_SIZE,
-				"%s", ent->value);
-			pci_bdf_present = 1;
-			continue;
-		}
-
-		/* unrecognized */
-		PARSE_ERROR_INVALID(0, section_name, ent->name);
-	}
-
-	/* Check for mandatory fields */
-	if (app->port_mask)
-		PARSE_ERROR_MESSAGE((pci_bdf_present == 0),
-			section_name, "pci_bdf",
-			"entry not allowed (port_mask is provided)");
-	else
-		PARSE_ERROR_MESSAGE((pci_bdf_present),
-			section_name, "pci_bdf",
-			"this entry is mandatory (port_mask is not "
-			"provided)");
-
-	if (rss_proto_ipv4_present)
-		PARSE_ERROR_MESSAGE((rss_qs_present),
-			section_name, "rss_proto_ipv4",
-			"entry not allowed (rss_qs entry is not provided)");
-	if (rss_proto_ipv6_present)
-		PARSE_ERROR_MESSAGE((rss_qs_present),
-			section_name, "rss_proto_ipv6",
-			"entry not allowed (rss_qs entry is not provided)");
-	if (rss_proto_l2_present)
-		PARSE_ERROR_MESSAGE((rss_qs_present),
-			section_name, "rss_proto_l2",
-			"entry not allowed (rss_qs entry is not provided)");
-	if (rss_proto_ipv4_present |
-		rss_proto_ipv6_present |
-		rss_proto_l2_present){
-		if (rss_proto_ipv4_present == 0)
-			param->rss_proto_ipv4 = 0;
-		if (rss_proto_ipv6_present == 0)
-			param->rss_proto_ipv6 = 0;
-		if (rss_proto_l2_present == 0)
-			param->rss_proto_l2 = 0;
-	}
-
-	free(entries);
-}
-
-static void
-parse_rxq(struct app_params *app,
-	const char *section_name,
-	struct rte_cfgfile *cfg)
-{
-	struct app_pktq_hwq_in_params *param;
-	struct rte_cfgfile_entry *entries;
-	int n_entries, i;
-	ssize_t param_idx;
-
-	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
-	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
-
-	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
-	PARSE_ERROR_MALLOC(entries != NULL);
-
-	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
-
-	param_idx = APP_PARAM_ADD(app->hwq_in_params, section_name);
-	param = &app->hwq_in_params[param_idx];
-	PARSE_CHECK_DUPLICATE_SECTION(param);
-
-	APP_PARAM_ADD_LINK_FOR_RXQ(app, section_name);
-
-	for (i = 0; i < n_entries; i++) {
-		struct rte_cfgfile_entry *ent = &entries[i];
-
-		if (strcmp(ent->name, "mempool") == 0) {
-			int status = validate_name(ent->value,
-				"MEMPOOL", 1);
-			ssize_t idx;
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-
-			idx = APP_PARAM_ADD(app->mempool_params, ent->value);
-			param->mempool_id = idx;
-			continue;
-		}
-
-		if (strcmp(ent->name, "size") == 0) {
-			int status = parser_read_uint32(&param->size,
-				ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "burst") == 0) {
-			int status = parser_read_uint32(&param->burst,
-				ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		/* unrecognized */
-		PARSE_ERROR_INVALID(0, section_name, ent->name);
-	}
-
-	free(entries);
-}
-
-static void
-parse_txq(struct app_params *app,
-	const char *section_name,
-	struct rte_cfgfile *cfg)
-{
-	struct app_pktq_hwq_out_params *param;
-	struct rte_cfgfile_entry *entries;
-	int n_entries, i;
-	ssize_t param_idx;
-
-	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
-	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
-
-	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
-	PARSE_ERROR_MALLOC(entries != NULL);
-
-	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
-
-	param_idx = APP_PARAM_ADD(app->hwq_out_params, section_name);
-	param = &app->hwq_out_params[param_idx];
-	PARSE_CHECK_DUPLICATE_SECTION(param);
-
-	APP_PARAM_ADD_LINK_FOR_TXQ(app, section_name);
-
-	for (i = 0; i < n_entries; i++) {
-		struct rte_cfgfile_entry *ent = &entries[i];
-
-		if (strcmp(ent->name, "size") == 0) {
-			int status = parser_read_uint32(&param->size,
-				ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "burst") == 0) {
-			int status = parser_read_uint32(&param->burst,
-				ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "dropless") == 0) {
-			int status = parser_read_arg_bool(ent->value);
-
-
-			PARSE_ERROR((status != -EINVAL), section_name,
-				ent->name);
-			param->dropless = status;
-			continue;
-		}
-
-		if (strcmp(ent->name, "n_retries") == 0) {
-			int status = parser_read_uint64(&param->n_retries,
-				ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		/* unrecognized */
-		PARSE_ERROR_INVALID(0, section_name, ent->name);
-	}
-
-	free(entries);
-}
-
-static void
-parse_swq(struct app_params *app,
-	const char *section_name,
-	struct rte_cfgfile *cfg)
-{
-	struct app_pktq_swq_params *param;
-	struct rte_cfgfile_entry *entries;
-	int n_entries, i;
-	uint32_t mtu_present = 0;
-	uint32_t metadata_size_present = 0;
-	uint32_t mempool_direct_present = 0;
-	uint32_t mempool_indirect_present = 0;
-
-	ssize_t param_idx;
-
-	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
-	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
-
-	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
-	PARSE_ERROR_MALLOC(entries != NULL);
-
-	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
-
-	param_idx = APP_PARAM_ADD(app->swq_params, section_name);
-	param = &app->swq_params[param_idx];
-	PARSE_CHECK_DUPLICATE_SECTION(param);
-
-	for (i = 0; i < n_entries; i++) {
-		struct rte_cfgfile_entry *ent = &entries[i];
-
-		if (strcmp(ent->name, "size") == 0) {
-			int status = parser_read_uint32(&param->size,
-				ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "burst_read") == 0) {
-			int status = parser_read_uint32(&
-				param->burst_read, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "burst_write") == 0) {
-			int status = parser_read_uint32(
-				&param->burst_write, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "dropless") == 0) {
-			int status = parser_read_arg_bool(ent->value);
-
-			PARSE_ERROR((status != -EINVAL), section_name,
-				ent->name);
-			param->dropless = status;
-			continue;
-		}
-
-		if (strcmp(ent->name, "n_retries") == 0) {
-			int status = parser_read_uint64(&param->n_retries,
-				ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "cpu") == 0) {
-			int status = parser_read_uint32(
-				&param->cpu_socket_id, ent->value);
-
-			PARSE_ERROR((status == 0), section_name, ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "ipv4_frag") == 0) {
-			int status = parser_read_arg_bool(ent->value);
-
-			PARSE_ERROR((status != -EINVAL), section_name,
-				ent->name);
-
-			param->ipv4_frag = status;
-			if (param->mtu == 0)
-				param->mtu = 1500;
-
-			continue;
-		}
-
-		if (strcmp(ent->name, "ipv6_frag") == 0) {
-			int status = parser_read_arg_bool(ent->value);
-
-			PARSE_ERROR((status != -EINVAL), section_name,
-				ent->name);
-			param->ipv6_frag = status;
-			if (param->mtu == 0)
-				param->mtu = 1320;
-			continue;
-		}
-
-		if (strcmp(ent->name, "ipv4_ras") == 0) {
-			int status = parser_read_arg_bool(ent->value);
-
-			PARSE_ERROR((status != -EINVAL), section_name,
-				ent->name);
-			param->ipv4_ras = status;
-			continue;
-		}
-
-		if (strcmp(ent->name, "ipv6_ras") == 0) {
-			int status = parser_read_arg_bool(ent->value);
-
-			PARSE_ERROR((status != -EINVAL), section_name,
-				ent->name);
-			param->ipv6_ras = status;
-			continue;
-		}
-
-		if (strcmp(ent->name, "mtu") == 0) {
-			int status = parser_read_uint32(&param->mtu,
-					ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			mtu_present = 1;
-			continue;
-		}
-
-		if (strcmp(ent->name, "metadata_size") == 0) {
-			int status = parser_read_uint32(
-				&param->metadata_size, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			metadata_size_present = 1;
-			continue;
-		}
-
-		if (strcmp(ent->name, "mempool_direct") == 0) {
-			int status = validate_name(ent->value,
-				"MEMPOOL", 1);
-			ssize_t idx;
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-
-			idx = APP_PARAM_ADD(app->mempool_params, ent->value);
-			param->mempool_direct_id = idx;
-
-			mempool_direct_present = 1;
-			continue;
-		}
-
-		if (strcmp(ent->name, "mempool_indirect") == 0) {
-			int status = validate_name(ent->value,
-				"MEMPOOL", 1);
-			ssize_t idx;
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-
-			idx = APP_PARAM_ADD(app->mempool_params, ent->value);
-			param->mempool_indirect_id = idx;
-
-			mempool_indirect_present = 1;
-			continue;
-		}
-
-		/* unrecognized */
-		PARSE_ERROR_INVALID(0, section_name, ent->name);
-	}
-
-	APP_CHECK(((mtu_present == 0) ||
-		((param->ipv4_frag == 1) || (param->ipv6_frag == 1))),
-		"Parse error in section \"%s\": IPv4/IPv6 fragmentation "
-		"is off, therefore entry \"mtu\" is not allowed",
-		section_name);
-
-	APP_CHECK(((metadata_size_present == 0) ||
-		((param->ipv4_frag == 1) || (param->ipv6_frag == 1))),
-		"Parse error in section \"%s\": IPv4/IPv6 fragmentation "
-		"is off, therefore entry \"metadata_size\" is "
-		"not allowed", section_name);
-
-	APP_CHECK(((mempool_direct_present == 0) ||
-		((param->ipv4_frag == 1) || (param->ipv6_frag == 1))),
-		"Parse error in section \"%s\": IPv4/IPv6 fragmentation "
-		"is off, therefore entry \"mempool_direct\" is "
-		"not allowed", section_name);
-
-	APP_CHECK(((mempool_indirect_present == 0) ||
-		((param->ipv4_frag == 1) || (param->ipv6_frag == 1))),
-		"Parse error in section \"%s\": IPv4/IPv6 fragmentation "
-		"is off, therefore entry \"mempool_indirect\" is "
-		"not allowed", section_name);
-
-	free(entries);
-}
-
-static void
-parse_tm(struct app_params *app,
-	const char *section_name,
-	struct rte_cfgfile *cfg)
-{
-	struct app_pktq_tm_params *param;
-	struct rte_cfgfile_entry *entries;
-	int n_entries, i;
-	ssize_t param_idx;
-
-	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
-	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
-
-	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
-	PARSE_ERROR_MALLOC(entries != NULL);
-
-	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
-
-	param_idx = APP_PARAM_ADD(app->tm_params, section_name);
-	param = &app->tm_params[param_idx];
-	PARSE_CHECK_DUPLICATE_SECTION(param);
-
-	APP_PARAM_ADD_LINK_FOR_TM(app, section_name);
-
-	for (i = 0; i < n_entries; i++) {
-		struct rte_cfgfile_entry *ent = &entries[i];
-
-		if (strcmp(ent->name, "cfg") == 0) {
-			param->file_name = strdup(ent->value);
-			PARSE_ERROR_MALLOC(param->file_name != NULL);
-			continue;
-		}
-
-		if (strcmp(ent->name, "burst_read") == 0) {
-			int status = parser_read_uint32(
-				&param->burst_read, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "burst_write") == 0) {
-			int status = parser_read_uint32(
-				&param->burst_write, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		/* unrecognized */
-		PARSE_ERROR_INVALID(0, section_name, ent->name);
-	}
-
-	free(entries);
-}
-
-static void
-parse_tap(struct app_params *app,
-	const char *section_name,
-	struct rte_cfgfile *cfg)
-{
-	struct app_pktq_tap_params *param;
-	struct rte_cfgfile_entry *entries;
-	int n_entries, i;
-	ssize_t param_idx;
-
-	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
-	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
-
-	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
-	PARSE_ERROR_MALLOC(entries != NULL);
-
-	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
-
-	param_idx = APP_PARAM_ADD(app->tap_params, section_name);
-	param = &app->tap_params[param_idx];
-	PARSE_CHECK_DUPLICATE_SECTION(param);
-
-	for (i = 0; i < n_entries; i++) {
-		struct rte_cfgfile_entry *ent = &entries[i];
-
-		if (strcmp(ent->name, "burst_read") == 0) {
-			int status = parser_read_uint32(
-				&param->burst_read, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "burst_write") == 0) {
-			int status = parser_read_uint32(
-				&param->burst_write, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "dropless") == 0) {
-			int status = parser_read_arg_bool(ent->value);
-
-			PARSE_ERROR((status != -EINVAL), section_name,
-				ent->name);
-			param->dropless = status;
-			continue;
-		}
-
-		if (strcmp(ent->name, "n_retries") == 0) {
-			int status = parser_read_uint64(&param->n_retries,
-				ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "mempool") == 0) {
-			int status = validate_name(ent->value,
-				"MEMPOOL", 1);
-			ssize_t idx;
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-
-			idx = APP_PARAM_ADD(app->mempool_params, ent->value);
-			param->mempool_id = idx;
-
-			continue;
-		}
-
-		/* unrecognized */
-		PARSE_ERROR_INVALID(0, section_name, ent->name);
-	}
-
-	free(entries);
-}
-
-static void
-parse_kni(struct app_params *app,
-		  const char *section_name,
-		  struct rte_cfgfile *cfg)
-{
-	struct app_pktq_kni_params *param;
-	struct rte_cfgfile_entry *entries;
-	int n_entries, i;
-	ssize_t param_idx;
-
-	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
-	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
-
-	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
-	PARSE_ERROR_MALLOC(entries != NULL);
-
-	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
-
-	param_idx = APP_PARAM_ADD(app->kni_params, section_name);
-	param = &app->kni_params[param_idx];
-	PARSE_CHECK_DUPLICATE_SECTION(param);
-
-	APP_PARAM_ADD_LINK_FOR_KNI(app, section_name);
-
-	for (i = 0; i < n_entries; i++) {
-		struct rte_cfgfile_entry *ent = &entries[i];
-
-		if (strcmp(ent->name, "core") == 0) {
-			int status = parse_pipeline_core(
-					&param->socket_id,
-					&param->core_id,
-					&param->hyper_th_id,
-					ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-						ent->name);
-			param->force_bind = 1;
-			continue;
-		}
-
-		if (strcmp(ent->name, "mempool") == 0) {
-			int status = validate_name(ent->value,
-				"MEMPOOL", 1);
-			ssize_t idx;
-
-			PARSE_ERROR((status == 0), section_name,
-						ent->name);
-
-			idx = APP_PARAM_ADD(app->mempool_params, ent->value);
-			param->mempool_id = idx;
-			continue;
-		}
-
-		if (strcmp(ent->name, "burst_read") == 0) {
-			int status = parser_read_uint32(&param->burst_read,
-						ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-						ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "burst_write") == 0) {
-			int status = parser_read_uint32(&param->burst_write,
-						ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-						ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "dropless") == 0) {
-			int status = parser_read_arg_bool(ent->value);
-
-			PARSE_ERROR((status != -EINVAL), section_name,
-						ent->name);
-			param->dropless = status;
-			continue;
-		}
-
-		if (strcmp(ent->name, "n_retries") == 0) {
-			int status = parser_read_uint64(&param->n_retries,
-						ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-						ent->name);
-			continue;
-		}
-
-		/* unrecognized */
-		PARSE_ERROR_INVALID(0, section_name, ent->name);
-	}
-
-	free(entries);
-}
-
-static void
-parse_source(struct app_params *app,
-	const char *section_name,
-	struct rte_cfgfile *cfg)
-{
-	struct app_pktq_source_params *param;
-	struct rte_cfgfile_entry *entries;
-	int n_entries, i;
-	ssize_t param_idx;
-	uint32_t pcap_file_present = 0;
-	uint32_t pcap_size_present = 0;
-
-	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
-	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
-
-	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
-	PARSE_ERROR_MALLOC(entries != NULL);
-
-	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
-
-	param_idx = APP_PARAM_ADD(app->source_params, section_name);
-	param = &app->source_params[param_idx];
-	PARSE_CHECK_DUPLICATE_SECTION(param);
-
-	for (i = 0; i < n_entries; i++) {
-		struct rte_cfgfile_entry *ent = &entries[i];
-
-		if (strcmp(ent->name, "mempool") == 0) {
-			int status = validate_name(ent->value,
-				"MEMPOOL", 1);
-			ssize_t idx;
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-
-			idx = APP_PARAM_ADD(app->mempool_params, ent->value);
-			param->mempool_id = idx;
-			continue;
-		}
-
-		if (strcmp(ent->name, "burst") == 0) {
-			int status = parser_read_uint32(&param->burst,
-				ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "pcap_file_rd") == 0) {
-			PARSE_ERROR_DUPLICATE((pcap_file_present == 0),
-				section_name, ent->name);
-
-			param->file_name = strdup(ent->value);
-
-			PARSE_ERROR_MALLOC(param->file_name != NULL);
-			pcap_file_present = 1;
-
-			continue;
-		}
-
-		if (strcmp(ent->name, "pcap_bytes_rd_per_pkt") == 0) {
-			int status;
-
-			PARSE_ERROR_DUPLICATE((pcap_size_present == 0),
-				section_name, ent->name);
-
-			status = parser_read_uint32(
-				&param->n_bytes_per_pkt, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			pcap_size_present = 1;
-
-			continue;
-		}
-
-		/* unrecognized */
-		PARSE_ERROR_INVALID(0, section_name, ent->name);
-	}
-
-	free(entries);
-}
-
-static void
-parse_sink(struct app_params *app,
-	const char *section_name,
-	struct rte_cfgfile *cfg)
-{
-	struct app_pktq_sink_params *param;
-	struct rte_cfgfile_entry *entries;
-	int n_entries, i;
-	ssize_t param_idx;
-	uint32_t pcap_file_present = 0;
-	uint32_t pcap_n_pkt_present = 0;
-
-	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
-	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
-
-	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
-	PARSE_ERROR_MALLOC(entries != NULL);
-
-	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
-
-	param_idx = APP_PARAM_ADD(app->sink_params, section_name);
-	param = &app->sink_params[param_idx];
-	PARSE_CHECK_DUPLICATE_SECTION(param);
-
-	for (i = 0; i < n_entries; i++) {
-		struct rte_cfgfile_entry *ent = &entries[i];
-
-		if (strcmp(ent->name, "pcap_file_wr") == 0) {
-			PARSE_ERROR_DUPLICATE((pcap_file_present == 0),
-				section_name, ent->name);
-
-			param->file_name = strdup(ent->value);
-
-			PARSE_ERROR_MALLOC((param->file_name != NULL));
-
-			continue;
-		}
-
-		if (strcmp(ent->name, "pcap_n_pkt_wr") == 0) {
-			int status;
-
-			PARSE_ERROR_DUPLICATE((pcap_n_pkt_present == 0),
-				section_name, ent->name);
-
-			status = parser_read_uint32(
-				&param->n_pkts_to_dump, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-
-			continue;
-		}
-
-		/* unrecognized */
-		PARSE_ERROR_INVALID(0, section_name, ent->name);
-	}
-
-	free(entries);
-}
-
-static void
-parse_msgq_req_pipeline(struct app_params *app,
-	const char *section_name,
-	struct rte_cfgfile *cfg)
-{
-	struct app_msgq_params *param;
-	struct rte_cfgfile_entry *entries;
-	int n_entries, i;
-	ssize_t param_idx;
-
-	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
-	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
-
-	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
-	PARSE_ERROR_MALLOC(entries != NULL);
-
-	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
-
-	param_idx = APP_PARAM_ADD(app->msgq_params, section_name);
-	param = &app->msgq_params[param_idx];
-	PARSE_CHECK_DUPLICATE_SECTION(param);
-
-	for (i = 0; i < n_entries; i++) {
-		struct rte_cfgfile_entry *ent = &entries[i];
-
-		if (strcmp(ent->name, "size") == 0) {
-			int status = parser_read_uint32(&param->size,
-				ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		/* unrecognized */
-		PARSE_ERROR_INVALID(0, section_name, ent->name);
-	}
-
-	free(entries);
-}
-
-static void
-parse_msgq_rsp_pipeline(struct app_params *app,
-	const char *section_name,
-	struct rte_cfgfile *cfg)
-{
-	struct app_msgq_params *param;
-	struct rte_cfgfile_entry *entries;
-	int n_entries, i;
-	ssize_t param_idx;
-
-	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
-	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
-
-	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
-	PARSE_ERROR_MALLOC(entries != NULL);
-
-	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
-
-	param_idx = APP_PARAM_ADD(app->msgq_params, section_name);
-	param = &app->msgq_params[param_idx];
-	PARSE_CHECK_DUPLICATE_SECTION(param);
-
-	for (i = 0; i < n_entries; i++) {
-		struct rte_cfgfile_entry *ent = &entries[i];
-
-		if (strcmp(ent->name, "size") == 0) {
-			int status = parser_read_uint32(&param->size,
-				ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		/* unrecognized */
-		PARSE_ERROR_INVALID(0, section_name, ent->name);
-	}
-
-	free(entries);
-}
-
-static void
-parse_msgq(struct app_params *app,
-	const char *section_name,
-	struct rte_cfgfile *cfg)
-{
-	struct app_msgq_params *param;
-	struct rte_cfgfile_entry *entries;
-	int n_entries, i;
-	ssize_t param_idx;
-
-	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
-	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
-
-	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
-	PARSE_ERROR_MALLOC(entries != NULL);
-
-	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
-
-	param_idx = APP_PARAM_ADD(app->msgq_params, section_name);
-	param = &app->msgq_params[param_idx];
-	PARSE_CHECK_DUPLICATE_SECTION(param);
-
-	for (i = 0; i < n_entries; i++) {
-		struct rte_cfgfile_entry *ent = &entries[i];
-
-		if (strcmp(ent->name, "size") == 0) {
-			int status = parser_read_uint32(&param->size,
-				ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "cpu") == 0) {
-			int status = parser_read_uint32(
-				&param->cpu_socket_id, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		/* unrecognized */
-		PARSE_ERROR_INVALID(0, section_name, ent->name);
-	}
-
-	free(entries);
-}
-
-typedef void (*config_section_load)(struct app_params *p,
-	const char *section_name,
-	struct rte_cfgfile *cfg);
-
-struct config_section {
-	const char prefix[CFG_NAME_LEN];
-	int numbers;
-	config_section_load load;
-};
-
-static const struct config_section cfg_file_scheme[] = {
-	{"EAL", 0, parse_eal},
-	{"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},
-	{"TAP", 1, parse_tap},
-	{"KNI", 1, parse_kni},
-	{"SOURCE", 1, parse_source},
-	{"SINK", 1, parse_sink},
-	{"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)
-{
-	APP_PARAM_ADD(app->mempool_params, "MEMPOOL0");
-}
-
-static void
-create_implicit_links_from_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%" PRIu32, link_id);
-		idx = APP_PARAM_ADD(app->link_params, name);
-
-		app->link_params[idx].pmd_id = pmd_id;
-		link_id++;
-	}
-}
-
-static void
-assign_link_pmd_id_from_pci_bdf(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_links; i++) {
-		struct app_link_params *link = &app->link_params[i];
-
-		APP_CHECK((strlen(link->pci_bdf)),
-			"Parse error: %s pci_bdf is not configured "
-			"(port_mask is not provided)",
-			link->name);
-
-		link->pmd_id = i;
-	}
-}
-
-int
-app_config_parse(struct app_params *app, const char *file_name)
-{
-	struct rte_cfgfile *cfg;
-	char **section_names;
-	int i, j, sect_count;
-
-	/* Implicit mempools */
-	create_implicit_mempools(app);
-
-	/* Port mask */
-	if (app->port_mask)
-		create_implicit_links_from_port_mask(app, app->port_mask);
-
-	/* Load application configuration file */
-	cfg = rte_cfgfile_load(file_name, 0);
-	APP_CHECK((cfg != NULL), "Parse error: Unable to load config "
-		"file %s", file_name);
-
-	sect_count = rte_cfgfile_num_sections(cfg, NULL, 0);
-	APP_CHECK((sect_count > 0), "Parse error: number of sections "
-		"in file \"%s\" return %d", file_name,
-		sect_count);
-
-	section_names = malloc(sect_count * sizeof(char *));
-	PARSE_ERROR_MALLOC(section_names != NULL);
-
-	for (i = 0; i < sect_count; i++)
-		section_names[i] = malloc(CFG_NAME_LEN);
-
-	rte_cfgfile_sections(cfg, section_names, sect_count);
-
-	for (i = 0; i < sect_count; i++) {
-		const struct config_section *sch_s;
-		int len, cfg_name_len;
-
-		cfg_name_len = strlen(section_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,
-			 * for example: "ABC" should match section name
-			 * "ABC0.0", but it should not match section_name
-			 * "ABCDEF".
-			 */
-			if ((section_names[i][len] != '\0') &&
-				!isdigit(section_names[i][len]))
-				continue;
-
-			if (strncmp(sch_s->prefix, section_names[i], len) == 0)
-				break;
-		}
-
-		APP_CHECK(j < (int)RTE_DIM(cfg_file_scheme),
-			"Parse error: unknown section %s",
-			section_names[i]);
-
-		APP_CHECK(validate_name(section_names[i],
-			sch_s->prefix,
-			sch_s->numbers) == 0,
-			"Parse error: invalid section name \"%s\"",
-			section_names[i]);
-
-		sch_s->load(app, section_names[i], cfg);
-	}
-
-	for (i = 0; i < sect_count; i++)
-		free(section_names[i]);
-
-	free(section_names);
-
-	rte_cfgfile_close(cfg);
-
-	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->tap_params, app->n_pktq_tap);
-	APP_PARAM_COUNT(app->kni_params, app->n_pktq_kni);
-	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);
-
-	if (app->port_mask == 0)
-		assign_link_pmd_id_from_pci_bdf(app);
-
-	/* Save configuration to output file */
-	app_config_save(app, app->output_file);
-
-	/* Load TM configuration files */
-	app_config_parse_tm(app);
-
-	return 0;
-}
-
-static void
-save_eal_params(struct app_params *app, FILE *f)
-{
-	struct app_eal_params *p = &app->eal_params;
-	uint32_t i;
-
-	fprintf(f, "[EAL]\n");
-
-	if (p->coremap)
-		fprintf(f, "%s = %s\n", "lcores", p->coremap);
-
-	if (p->master_lcore_present)
-		fprintf(f, "%s = %" PRIu32 "\n",
-			"master_lcore", p->master_lcore);
-
-	fprintf(f, "%s = %" PRIu32 "\n", "n", p->channels);
-
-	if (p->memory_present)
-		fprintf(f, "%s = %" PRIu32 "\n", "m", p->memory);
-
-	if (p->ranks_present)
-		fprintf(f, "%s = %" PRIu32 "\n", "r", p->ranks);
-
-	for (i = 0; i < APP_MAX_LINKS; i++) {
-		if (p->pci_blacklist[i] == NULL)
-			break;
-
-		fprintf(f, "%s = %s\n", "pci_blacklist",
-			p->pci_blacklist[i]);
-	}
-
-	for (i = 0; i < APP_MAX_LINKS; i++) {
-		if (p->pci_whitelist[i] == NULL)
-			break;
-
-		fprintf(f, "%s = %s\n", "pci_whitelist",
-			p->pci_whitelist[i]);
-	}
-
-	for (i = 0; i < APP_MAX_LINKS; i++) {
-		if (p->vdev[i] == NULL)
-			break;
-
-		fprintf(f, "%s = %s\n", "vdev",
-			p->vdev[i]);
-	}
-
-	if (p->vmware_tsc_map_present)
-		fprintf(f, "%s = %s\n", "vmware_tsc_map",
-			(p->vmware_tsc_map) ? "yes" : "no");
-
-	if (p->proc_type)
-		fprintf(f, "%s = %s\n", "proc_type", p->proc_type);
-
-	if (p->syslog)
-		fprintf(f, "%s = %s\n", "syslog", p->syslog);
-
-	if (p->log_level_present)
-		fprintf(f, "%s = %" PRIu32 "\n", "log_level", p->log_level);
-
-	if (p->version_present)
-		fprintf(f, "%s = %s\n",	"v", (p->version) ? "yes" : "no");
-
-	if (p->help_present)
-		fprintf(f, "%s = %s\n",	"help", (p->help) ? "yes" : "no");
-
-	if (p->no_huge_present)
-		fprintf(f, "%s = %s\n",	"no_huge", (p->no_huge) ? "yes" : "no");
-
-	if (p->no_pci_present)
-		fprintf(f, "%s = %s\n",	"no_pci", (p->no_pci) ? "yes" : "no");
-
-	if (p->no_hpet_present)
-		fprintf(f, "%s = %s\n",	"no_hpet", (p->no_hpet) ? "yes" : "no");
-
-	if (p->no_shconf_present)
-		fprintf(f, "%s = %s\n", "no_shconf",
-			(p->no_shconf) ? "yes" : "no");
-
-	if (p->add_driver)
-		fprintf(f, "%s = %s\n",	"d", p->add_driver);
-
-	if (p->socket_mem)
-		fprintf(f, "%s = %s\n",	"socket_mem", p->socket_mem);
-
-	if (p->huge_dir)
-		fprintf(f, "%s = %s\n", "huge_dir", p->huge_dir);
-
-	if (p->file_prefix)
-		fprintf(f, "%s = %s\n", "file_prefix", p->file_prefix);
-
-	if (p->base_virtaddr)
-		fprintf(f, "%s = %s\n",	"base_virtaddr", p->base_virtaddr);
-
-	if (p->create_uio_dev_present)
-		fprintf(f, "%s = %s\n", "create_uio_dev",
-			(p->create_uio_dev) ? "yes" : "no");
-
-	if (p->vfio_intr)
-		fprintf(f, "%s = %s\n", "vfio_intr", p->vfio_intr);
-
-	fputc('\n', f);
-}
-
-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 = %s\n", "promisc", p->promisc ? "yes" : "no");
-		fprintf(f, "%s = %" PRIu32 "\n", "arp_q", p->arp_q);
-		fprintf(f, "%s = %" PRIu32 "\n", "tcp_syn_q",
-			p->tcp_syn_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);
-
-		if (p->n_rss_qs) {
-			uint32_t j;
-
-			/* rss_qs */
-			fprintf(f, "rss_qs = ");
-			for (j = 0; j < p->n_rss_qs; j++)
-				fprintf(f, "%" PRIu32 " ",	p->rss_qs[j]);
-			fputc('\n', f);
-
-			/* rss_proto_ipv4 */
-			if (p->rss_proto_ipv4) {
-				fprintf(f, "rss_proto_ipv4 = ");
-				if (p->rss_proto_ipv4 & ETH_RSS_IPV4)
-					fprintf(f, "IP ");
-				if (p->rss_proto_ipv4 & ETH_RSS_FRAG_IPV4)
-					fprintf(f, "FRAG ");
-				if (p->rss_proto_ipv4 &
-					ETH_RSS_NONFRAG_IPV4_TCP)
-					fprintf(f, "TCP ");
-				if (p->rss_proto_ipv4 &
-					ETH_RSS_NONFRAG_IPV4_UDP)
-					fprintf(f, "UDP ");
-				if (p->rss_proto_ipv4 &
-					ETH_RSS_NONFRAG_IPV4_SCTP)
-					fprintf(f, "SCTP ");
-				if (p->rss_proto_ipv4 &
-					ETH_RSS_NONFRAG_IPV4_OTHER)
-					fprintf(f, "OTHER ");
-				fprintf(f, "\n");
-			} else
-				fprintf(f, "; rss_proto_ipv4 = <NONE>\n");
-
-			/* rss_proto_ipv6 */
-			if (p->rss_proto_ipv6) {
-				fprintf(f, "rss_proto_ipv6 = ");
-				if (p->rss_proto_ipv6 & ETH_RSS_IPV6)
-					fprintf(f, "IP ");
-				if (p->rss_proto_ipv6 & ETH_RSS_FRAG_IPV6)
-					fprintf(f, "FRAG ");
-				if (p->rss_proto_ipv6 &
-					ETH_RSS_NONFRAG_IPV6_TCP)
-					fprintf(f, "TCP ");
-				if (p->rss_proto_ipv6 &
-					ETH_RSS_NONFRAG_IPV6_UDP)
-					fprintf(f, "UDP ");
-				if (p->rss_proto_ipv6 &
-					ETH_RSS_NONFRAG_IPV6_SCTP)
-					fprintf(f, "SCTP ");
-				if (p->rss_proto_ipv6 &
-					ETH_RSS_NONFRAG_IPV6_OTHER)
-					fprintf(f, "OTHER ");
-				if (p->rss_proto_ipv6 & ETH_RSS_IPV6_EX)
-					fprintf(f, "IP_EX ");
-				if (p->rss_proto_ipv6 &
-					ETH_RSS_IPV6_TCP_EX)
-					fprintf(f, "TCP_EX ");
-				if (p->rss_proto_ipv6 &
-					ETH_RSS_IPV6_UDP_EX)
-					fprintf(f, "UDP_EX ");
-				fprintf(f, "\n");
-			} else
-				fprintf(f, "; rss_proto_ipv6 = <NONE>\n");
-
-			/* rss_proto_l2 */
-			if (p->rss_proto_l2) {
-				fprintf(f, "rss_proto_l2 = ");
-				if (p->rss_proto_l2 & ETH_RSS_L2_PAYLOAD)
-					fprintf(f, "L2 ");
-				fprintf(f, "\n");
-			} else
-				fprintf(f, "; rss_proto_l2 = <NONE>\n");
-		} else {
-			fprintf(f, "; rss_qs = <NONE>\n");
-			fprintf(f, "; rss_proto_ipv4 = <NONE>\n");
-			fprintf(f, "; rss_proto_ipv6 = <NONE>\n");
-			fprintf(f, "; rss_proto_l2 = <NONE>\n");
-		}
-
-		if (strlen(p->pci_bdf))
-			fprintf(f, "%s = %s\n", "pci_bdf", p->pci_bdf);
-
-		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");
-		fprintf(f, "%s = %" PRIu64 "\n", "n_retries", p->n_retries);
-
-		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);
-		fprintf(f, "%s = %s\n", "ipv4_frag", p->ipv4_frag ? "yes" : "no");
-		fprintf(f, "%s = %s\n", "ipv6_frag", p->ipv6_frag ? "yes" : "no");
-		fprintf(f, "%s = %s\n", "ipv4_ras", p->ipv4_ras ? "yes" : "no");
-		fprintf(f, "%s = %s\n", "ipv6_ras", p->ipv6_ras ? "yes" : "no");
-		if ((p->ipv4_frag == 1) || (p->ipv6_frag == 1)) {
-			fprintf(f, "%s = %" PRIu32 "\n", "mtu", p->mtu);
-			fprintf(f, "%s = %" PRIu32 "\n", "metadata_size", p->metadata_size);
-			fprintf(f, "%s = %s\n",
-				"mempool_direct",
-				app->mempool_params[p->mempool_direct_id].name);
-			fprintf(f, "%s = %s\n",
-				"mempool_indirect",
-				app->mempool_params[p->mempool_indirect_id].name);
-		}
-
-		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 = %" PRIu32 "\n", "burst_read", p->burst_read);
-		fprintf(f, "%s = %" PRIu32 "\n", "burst_write", p->burst_write);
-
-		fputc('\n', f);
-	}
-}
-
-static void
-save_tap_params(struct app_params *app, FILE *f)
-{
-	struct app_pktq_tap_params *p;
-	size_t i, count;
-
-	count = RTE_DIM(app->tap_params);
-	for (i = 0; i < count; i++) {
-		p = &app->tap_params[i];
-		if (!APP_PARAM_VALID(p))
-			continue;
-
-		fprintf(f, "[%s]\n", p->name);
-		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 = %s\n", "mempool",
-			app->mempool_params[p->mempool_id].name);
-
-		fputc('\n', f);
-	}
-}
-
-static void
-save_kni_params(struct app_params *app, FILE *f)
-{
-	struct app_pktq_kni_params *p;
-	size_t i, count;
-
-	count = RTE_DIM(app->kni_params);
-	for (i = 0; i < count; i++) {
-		p = &app->kni_params[i];
-		if (!APP_PARAM_VALID(p))
-			continue;
-
-		/* section name */
-		fprintf(f, "[%s]\n", p->name);
-
-		/* core */
-		if (p->force_bind) {
-			fprintf(f, "; force_bind = 1\n");
-			fprintf(f, "core = s%" PRIu32 "c%" PRIu32 "%s\n",
-					p->socket_id,
-					p->core_id,
-					(p->hyper_th_id) ? "h" : "");
-		} else
-			fprintf(f, "; force_bind = 0\n");
-
-		/* mempool */
-		fprintf(f, "%s = %s\n", "mempool",
-				app->mempool_params[p->mempool_id].name);
-
-		/* burst_read */
-		fprintf(f, "%s = %" PRIu32 "\n", "burst_read", p->burst_read);
-
-		/* burst_write */
-		fprintf(f, "%s = %" PRIu32 "\n", "burst_write", p->burst_write);
-
-		/* dropless */
-		fprintf(f, "%s = %s\n",
-				"dropless",
-				p->dropless ? "yes" : "no");
-
-		/* n_retries */
-		fprintf(f, "%s = %" PRIu64 "\n", "n_retries", p->n_retries);
-
-		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 = %" PRIu32 "\n", "burst", p->burst);
-		fprintf(f, "%s = %s\n", "pcap_file_rd", p->file_name);
-		fprintf(f, "%s = %" PRIu32 "\n", "pcap_bytes_rd_per_pkt",
-			p->n_bytes_per_pkt);
-		fputc('\n', f);
-	}
-}
-
-static void
-save_sink_params(struct app_params *app, FILE *f)
-{
-	struct app_pktq_sink_params *p;
-	size_t i, count;
-
-	count = RTE_DIM(app->sink_params);
-	for (i = 0; i < count; i++) {
-		p = &app->sink_params[i];
-		if (!APP_PARAM_VALID(p))
-			continue;
-
-		fprintf(f, "[%s]\n", p->name);
-		fprintf(f, "%s = %s\n", "pcap_file_wr", p->file_name);
-		fprintf(f, "%s = %" PRIu32 "\n",
-				"pcap_n_pkt_wr", p->n_pkts_to_dump);
-		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%" PRIu32 "c%" PRIu32 "%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_TAP:
-					name = app->tap_params[pp->id].name;
-					break;
-				case APP_PKTQ_IN_KNI:
-					name = app->kni_params[pp->id].name;
-					break;
-				case APP_PKTQ_IN_SOURCE:
-					name = app->source_params[pp->id].name;
-					break;
-				default:
-					APP_CHECK(0, "System error "
-						"occurred while saving "
-						"parameter to file");
-				}
-
-				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_TAP:
-					name = app->tap_params[pp->id].name;
-					break;
-				case APP_PKTQ_OUT_KNI:
-					name = app->kni_params[pp->id].name;
-					break;
-				case APP_PKTQ_OUT_SINK:
-					name = app->sink_params[pp->id].name;
-					break;
-				default:
-					APP_CHECK(0, "System error "
-						"occurred while saving "
-						"parameter to file");
-				}
-
-				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_out) {
-			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 = %" PRIu32 "\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;
-	char *name, *dir_name;
-	int status;
-
-	name = strdup(file_name);
-	dir_name = dirname(name);
-	status = access(dir_name, W_OK);
-	APP_CHECK((status == 0),
-		"Error: need write access privilege to directory "
-		"\"%s\" to save configuration\n", dir_name);
-
-	file = fopen(file_name, "w");
-	APP_CHECK((file != NULL),
-		"Error: failed to save configuration to file \"%s\"",
-		file_name);
-
-	save_eal_params(app, file);
-	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_tap_params(app, file);
-	save_kni_params(app, file);
-	save_source_params(app, file);
-	save_sink_params(app, file);
-	save_msgq_params(app, file);
-
-	fclose(file);
-	free(name);
-}
-
-int
-app_config_init(struct app_params *app)
-{
-	size_t i;
-
-	memcpy(app, &app_params_default, sizeof(struct app_params));
-
-	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->tap_params); i++)
-		memcpy(&app->tap_params[i],
-			&default_tap_params,
-			sizeof(default_tap_params));
-
-	for (i = 0; i < RTE_DIM(app->kni_params); i++)
-		memcpy(&app->kni_params[i],
-			   &default_kni_params,
-			   sizeof(default_kni_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;
-}
-
-static char *
-filenamedup(const char *filename, const char *suffix)
-{
-	char *s = malloc(strlen(filename) + strlen(suffix) + 1);
-
-	if (!s)
-		return NULL;
-
-	sprintf(s, "%s%s", filename, suffix);
-	return s;
-}
-
-int
-app_config_args(struct app_params *app, int argc, char **argv)
-{
-	const char *optname;
-	int opt, option_index;
-	int f_present, s_present, p_present, l_present;
-	int preproc_present, preproc_params_present;
-	int scaned = 0;
-
-	static struct option lgopts[] = {
-		{ "preproc", 1, 0, 0 },
-		{ "preproc-args", 1, 0, 0 },
-		{ NULL,  0, 0, 0 }
-	};
-
-	/* Copy application name */
-	strncpy(app->app_name, argv[0], APP_APPNAME_SIZE - 1);
-
-	f_present = 0;
-	s_present = 0;
-	p_present = 0;
-	l_present = 0;
-	preproc_present = 0;
-	preproc_params_present = 0;
-
-	while ((opt = getopt_long(argc, argv, "f:s:p:l:", lgopts,
-			&option_index)) != EOF)
-		switch (opt) {
-		case 'f':
-			if (f_present)
-				rte_panic("Error: Config file is provided "
-					"more than once\n");
-			f_present = 1;
-
-			if (!strlen(optarg))
-				rte_panic("Error: Config file name is null\n");
-
-			app->config_file = strdup(optarg);
-			if (app->config_file == NULL)
-				rte_panic("Error: Memory allocation failure\n");
-
-			break;
-
-		case 's':
-			if (s_present)
-				rte_panic("Error: Script file is provided "
-					"more than once\n");
-			s_present = 1;
-
-			if (!strlen(optarg))
-				rte_panic("Error: Script file name is null\n");
-
-			app->script_file = strdup(optarg);
-			if (app->script_file == NULL)
-				rte_panic("Error: Memory allocation failure\n");
-
-			break;
-
-		case 'p':
-			if (p_present)
-				rte_panic("Error: PORT_MASK is provided "
-					"more than once\n");
-			p_present = 1;
-
-			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");
-
-			break;
-
-		case 'l':
-			if (l_present)
-				rte_panic("Error: LOG_LEVEL is provided "
-					"more than once\n");
-			l_present = 1;
-
-			if ((sscanf(optarg, "%" SCNu32 "%n", &app->log_level,
-				&scaned) != 1) ||
-				((size_t) scaned != strlen(optarg)) ||
-				(app->log_level >= APP_LOG_LEVELS))
-				rte_panic("Error: LOG_LEVEL invalid value\n");
-
-			break;
-
-		case 0:
-			optname = lgopts[option_index].name;
-
-			if (strcmp(optname, "preproc") == 0) {
-				if (preproc_present)
-					rte_panic("Error: Preprocessor argument "
-						"is provided more than once\n");
-				preproc_present = 1;
-
-				app->preproc = strdup(optarg);
-				break;
-			}
-
-			if (strcmp(optname, "preproc-args") == 0) {
-				if (preproc_params_present)
-					rte_panic("Error: Preprocessor args "
-						"are provided more than once\n");
-				preproc_params_present = 1;
-
-				app->preproc_args = strdup(optarg);
-				break;
-			}
-
-			app_print_usage(argv[0]);
-			break;
-
-		default:
-			app_print_usage(argv[0]);
-		}
-
-	optind = 1; /* reset getopt lib */
-
-	/* Check dependencies between args */
-	if (preproc_params_present && (preproc_present == 0))
-		rte_panic("Error: Preprocessor args specified while "
-			"preprocessor is not defined\n");
-
-	app->parser_file = preproc_present ?
-		filenamedup(app->config_file, ".preproc") :
-		strdup(app->config_file);
-	app->output_file = filenamedup(app->config_file, ".out");
-
-	return 0;
-}
-
-int
-app_config_preproc(struct app_params *app)
-{
-	char buffer[256];
-	int status;
-
-	if (app->preproc == NULL)
-		return 0;
-
-	status = access(app->config_file, F_OK | R_OK);
-	APP_CHECK((status == 0), "Error: Unable to open file %s",
-		app->config_file);
-
-	snprintf(buffer, sizeof(buffer), "%s %s %s > %s",
-		app->preproc,
-		app->preproc_args ? app->preproc_args : "",
-		app->config_file,
-		app->parser_file);
-
-	status = system(buffer);
-	APP_CHECK((WIFEXITED(status) && (WEXITSTATUS(status) == 0)),
-		"Error occurred while pre-processing file \"%s\"\n",
-		app->config_file);
-
-	return status;
-}
diff --git a/examples/ip_pipeline/config_parse_tm.c b/examples/ip_pipeline/config_parse_tm.c
deleted file mode 100644
index 6edd2ca..0000000
--- a/examples/ip_pipeline/config_parse_tm.c
+++ /dev/null
@@ -1,419 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-#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 <libgen.h>
-#include <unistd.h>
-
-#include <rte_errno.h>
-#include <rte_cfgfile.h>
-#include <rte_string_fns.h>
-
-#include "app.h"
-
-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", "mtu");
-	if (entry)
-		port_params->mtu = (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 %" PRId32 " 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 %" PRId32 " 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 %" PRId32 " 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 %" PRId32 " 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 %" PRId32, 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 %" PRId32, 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);
-			struct rte_cfgfile_entry entries[n_entries];
-
-			rte_cfgfile_section_entries(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 + 1];
-
-					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 %" PRId32,
-							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 i;
-
-	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_port_params));
-	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];
-
-	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;
-}
-
-int
-app_config_parse_tm(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < RTE_DIM(app->tm_params); i++) {
-		struct app_pktq_tm_params *p = &app->tm_params[i];
-		int status;
-
-		if (!APP_PARAM_VALID(p))
-			break;
-
-		status = tm_cfgfile_load(p);
-		APP_CHECK(status == 0,
-			"Parse error for %s configuration file \"%s\"\n",
-			p->name,
-			p->file_name);
-	}
-
-	return 0;
-}
diff --git a/examples/ip_pipeline/cpu_core_map.c b/examples/ip_pipeline/cpu_core_map.c
deleted file mode 100644
index 231f38e..0000000
--- a/examples/ip_pipeline/cpu_core_map.c
+++ /dev/null
@@ -1,471 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#include <inttypes.h>
-#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%" PRIu32 "/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%" PRIu32 "/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 !defined(RTE_ARCH_PPC_64)
-			if (lcore_socket_id < 0)
-				return -1;
-#endif
-
-			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 !defined(RTE_ARCH_PPC_64)
-				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;
-#endif
-
-#if !defined(RTE_ARCH_PPC_64)
-				if (((uint32_t) lcore_socket_id == socket_id) &&
-					((uint32_t) lcore_core_id == core_id)) {
-#else
-				if (((uint32_t) lcore_socket_id == socket_id)) {
-#endif
-					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)
-{
-	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 %" PRIu32 ":\n", socket_id);
-
-		for (core_id = 0;
-			core_id < map->n_cores_per_socket;
-			core_id++) {
-			printf("[%" PRIu32 "] = [", 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 =
-					cpu_core_map_get_core_id_linux(
-						lcore_id);
-
-				printf(" %" PRId32 " (%" PRIu32 ") ",
-					lcore_id,
-					core_id_noncontig);
-			}
-
-			printf("]\n");
-		}
-	}
-}
-
-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)
-{
-	free(map);
-}
diff --git a/examples/ip_pipeline/cpu_core_map.h b/examples/ip_pipeline/cpu_core_map.h
deleted file mode 100644
index 5e50f6e..0000000
--- a/examples/ip_pipeline/cpu_core_map.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#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/pipeline/hash_func.h b/examples/ip_pipeline/hash_func.h
similarity index 99%
rename from examples/ip_pipeline/pipeline/hash_func.h
rename to examples/ip_pipeline/hash_func.h
index 806ac22..f1b9d94 100644
--- a/examples/ip_pipeline/pipeline/hash_func.h
+++ b/examples/ip_pipeline/hash_func.h
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
+ * Copyright(c) 2010-2018 Intel Corporation
  */
+
 #ifndef __INCLUDE_HASH_FUNC_H__
 #define __INCLUDE_HASH_FUNC_H__
 
diff --git a/examples/ip_pipeline/pipeline/hash_func_arm64.h b/examples/ip_pipeline/hash_func_arm64.h
similarity index 100%
rename from examples/ip_pipeline/pipeline/hash_func_arm64.h
rename to examples/ip_pipeline/hash_func_arm64.h
diff --git a/examples/ip_pipeline/init.c b/examples/ip_pipeline/init.c
deleted file mode 100644
index bb07efa..0000000
--- a/examples/ip_pipeline/init.c
+++ /dev/null
@@ -1,1927 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2016 Intel Corporation
- */
-
-#include <inttypes.h>
-#include <stdio.h>
-#include <string.h>
-#include <netinet/in.h>
-#ifdef RTE_EXEC_ENV_LINUXAPP
-#include <linux/if.h>
-#include <linux/if_tun.h>
-#endif
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <unistd.h>
-
-#include <rte_cycles.h>
-#include <rte_ethdev.h>
-#include <rte_ether.h>
-#include <rte_ip.h>
-#include <rte_eal.h>
-#include <rte_malloc.h>
-#include <rte_bus_pci.h>
-
-#include "app.h"
-#include "pipeline.h"
-#include "pipeline_common_fe.h"
-#include "pipeline_master.h"
-#include "pipeline_passthrough.h"
-#include "pipeline_firewall.h"
-#include "pipeline_flow_classification.h"
-#include "pipeline_flow_actions.h"
-#include "pipeline_routing.h"
-#include "thread_fe.h"
-
-#define APP_NAME_SIZE	32
-
-#define APP_RETA_SIZE_MAX     (ETH_RSS_RETA_SIZE_512 / RTE_RETA_GROUP_SIZE)
-
-static void
-app_init_core_map(struct app_params *app)
-{
-	APP_LOG(app, HIGH, "Initializing CPU core map ...");
-	app->core_map = cpu_core_map_init(RTE_MAX_NUMA_NODES, RTE_MAX_LCORE,
-				4, 0);
-
-	if (app->core_map == NULL)
-		rte_panic("Cannot create CPU core map\n");
-
-	if (app->log_level >= APP_LOG_LEVEL_LOW)
-		cpu_core_map_print(app->core_map);
-}
-
-/* Core Mask String in Hex Representation */
-#define APP_CORE_MASK_STRING_SIZE ((64 * APP_CORE_MASK_SIZE) / 8 * 2 + 1)
-
-static void
-app_init_core_mask(struct app_params *app)
-{
-	uint32_t i;
-	char core_mask_str[APP_CORE_MASK_STRING_SIZE];
-
-	for (i = 0; i < app->n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		int lcore_id;
-
-		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");
-
-		app_core_enable_in_core_mask(app, lcore_id);
-	}
-
-	app_core_build_core_mask_string(app, core_mask_str);
-	APP_LOG(app, HIGH, "CPU core mask = 0x%s", core_mask_str);
-}
-
-static void
-app_init_eal(struct app_params *app)
-{
-	char buffer[256];
-	char core_mask_str[APP_CORE_MASK_STRING_SIZE];
-	struct app_eal_params *p = &app->eal_params;
-	uint32_t n_args = 0;
-	uint32_t i;
-	int status;
-
-	app->eal_argv[n_args++] = strdup(app->app_name);
-
-	app_core_build_core_mask_string(app, core_mask_str);
-	snprintf(buffer, sizeof(buffer), "-c%s", core_mask_str);
-	app->eal_argv[n_args++] = strdup(buffer);
-
-	if (p->coremap) {
-		snprintf(buffer, sizeof(buffer), "--lcores=%s", p->coremap);
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if (p->master_lcore_present) {
-		snprintf(buffer,
-			sizeof(buffer),
-			"--master-lcore=%" PRIu32,
-			p->master_lcore);
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	snprintf(buffer, sizeof(buffer), "-n%" PRIu32, p->channels);
-	app->eal_argv[n_args++] = strdup(buffer);
-
-	if (p->memory_present) {
-		snprintf(buffer, sizeof(buffer), "-m%" PRIu32, p->memory);
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if (p->ranks_present) {
-		snprintf(buffer, sizeof(buffer), "-r%" PRIu32, p->ranks);
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	for (i = 0; i < APP_MAX_LINKS; i++) {
-		if (p->pci_blacklist[i] == NULL)
-			break;
-
-		snprintf(buffer,
-			sizeof(buffer),
-			"--pci-blacklist=%s",
-			p->pci_blacklist[i]);
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if (app->port_mask != 0)
-		for (i = 0; i < APP_MAX_LINKS; i++) {
-			if (p->pci_whitelist[i] == NULL)
-				break;
-
-			snprintf(buffer,
-				sizeof(buffer),
-				"--pci-whitelist=%s",
-				p->pci_whitelist[i]);
-			app->eal_argv[n_args++] = strdup(buffer);
-		}
-	else
-		for (i = 0; i < app->n_links; i++) {
-			char *pci_bdf = app->link_params[i].pci_bdf;
-
-			snprintf(buffer,
-				sizeof(buffer),
-				"--pci-whitelist=%s",
-				pci_bdf);
-			app->eal_argv[n_args++] = strdup(buffer);
-		}
-
-	for (i = 0; i < APP_MAX_LINKS; i++) {
-		if (p->vdev[i] == NULL)
-			break;
-
-		snprintf(buffer,
-			sizeof(buffer),
-			"--vdev=%s",
-			p->vdev[i]);
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if ((p->vmware_tsc_map_present) && p->vmware_tsc_map) {
-		snprintf(buffer, sizeof(buffer), "--vmware-tsc-map");
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if (p->proc_type) {
-		snprintf(buffer,
-			sizeof(buffer),
-			"--proc-type=%s",
-			p->proc_type);
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if (p->syslog) {
-		snprintf(buffer, sizeof(buffer), "--syslog=%s", p->syslog);
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if (p->log_level_present) {
-		snprintf(buffer,
-			sizeof(buffer),
-			"--log-level=%" PRIu32,
-			p->log_level);
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if ((p->version_present) && p->version) {
-		snprintf(buffer, sizeof(buffer), "-v");
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if ((p->help_present) && p->help) {
-		snprintf(buffer, sizeof(buffer), "--help");
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if ((p->no_huge_present) && p->no_huge) {
-		snprintf(buffer, sizeof(buffer), "--no-huge");
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if ((p->no_pci_present) && p->no_pci) {
-		snprintf(buffer, sizeof(buffer), "--no-pci");
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if ((p->no_hpet_present) && p->no_hpet) {
-		snprintf(buffer, sizeof(buffer), "--no-hpet");
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if ((p->no_shconf_present) && p->no_shconf) {
-		snprintf(buffer, sizeof(buffer), "--no-shconf");
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if (p->add_driver) {
-		snprintf(buffer, sizeof(buffer), "-d%s", p->add_driver);
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if (p->socket_mem) {
-		snprintf(buffer,
-			sizeof(buffer),
-			"--socket-mem=%s",
-			p->socket_mem);
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if (p->huge_dir) {
-		snprintf(buffer, sizeof(buffer), "--huge-dir=%s", p->huge_dir);
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if (p->file_prefix) {
-		snprintf(buffer,
-			sizeof(buffer),
-			"--file-prefix=%s",
-			p->file_prefix);
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if (p->base_virtaddr) {
-		snprintf(buffer,
-			sizeof(buffer),
-			"--base-virtaddr=%s",
-			p->base_virtaddr);
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if ((p->create_uio_dev_present) && p->create_uio_dev) {
-		snprintf(buffer, sizeof(buffer), "--create-uio-dev");
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if (p->vfio_intr) {
-		snprintf(buffer,
-			sizeof(buffer),
-			"--vfio-intr=%s",
-			p->vfio_intr);
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	snprintf(buffer, sizeof(buffer), "--");
-	app->eal_argv[n_args++] = strdup(buffer);
-
-	app->eal_argc = n_args;
-
-	APP_LOG(app, HIGH, "Initializing EAL ...");
-	if (app->log_level >= APP_LOG_LEVEL_LOW) {
-		int i;
-
-		fprintf(stdout, "[APP] EAL arguments: \"");
-		for (i = 1; i < app->eal_argc; i++)
-			fprintf(stdout, "%s ", app->eal_argv[i]);
-		fprintf(stdout, "\"\n");
-	}
-
-	status = rte_eal_init(app->eal_argc, app->eal_argv);
-	if (status < 0)
-		rte_panic("EAL init error\n");
-}
-
-static void
-app_init_mempool(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_mempools; i++) {
-		struct app_mempool_params *p = &app->mempool_params[i];
-
-		APP_LOG(app, HIGH, "Initializing %s ...", p->name);
-		app->mempool[i] = rte_pktmbuf_pool_create(
-			p->name,
-			p->pool_size,
-			p->cache_size,
-			0, /* priv_size */
-			p->buffer_size -
-				sizeof(struct rte_mbuf), /* mbuf data size */
-			p->cpu_socket_id);
-
-		if (app->mempool[i] == NULL)
-			rte_panic("%s init error\n", p->name);
-	}
-}
-
-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 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_q,
-	};
-
-	return rte_eth_dev_filter_ctrl(link->pmd_id,
-		RTE_ETH_FILTER_SYN,
-		RTE_ETH_FILTER_ADD,
-		&filter);
-}
-
-static inline int
-app_link_filter_ip_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 = UINT32_MAX, /* Enable */
-		.src_ip = 0,
-		.src_ip_mask = 0, /* Disable */
-		.dst_port = 0,
-		.dst_port_mask = 0, /* Disable */
-		.src_port = 0,
-		.src_port_mask = 0, /* Disable */
-		.proto = 0,
-		.proto_mask = 0, /* 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);
-}
-
-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 = UINT32_MAX, /* Enable */
-		.src_ip = 0,
-		.src_ip_mask = 0, /* Disable */
-		.dst_port = 0,
-		.dst_port_mask = 0, /* Disable */
-		.src_port = 0,
-		.src_port_mask = 0, /* Disable */
-		.proto = 0,
-		.proto_mask = 0, /* 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);
-}
-
-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 = UINT32_MAX, /* Enable */
-		.src_ip = 0,
-		.src_ip_mask = 0, /* Disable */
-		.dst_port = 0,
-		.dst_port_mask = 0, /* Disable */
-		.src_port = 0,
-		.src_port_mask = 0, /* Disable */
-		.proto = IPPROTO_TCP,
-		.proto_mask = UINT8_MAX, /* 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);
-}
-
-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 = UINT32_MAX, /* Enable */
-		.src_ip = 0,
-		.src_ip_mask = 0, /* Disable */
-		.dst_port = 0,
-		.dst_port_mask = 0, /* Disable */
-		.src_port = 0,
-		.src_port_mask = 0, /* Disable */
-		.proto = IPPROTO_TCP,
-		.proto_mask = UINT8_MAX, /* 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);
-}
-
-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 = UINT32_MAX, /* Enable */
-		.src_ip = 0,
-		.src_ip_mask = 0, /* Disable */
-		.dst_port = 0,
-		.dst_port_mask = 0, /* Disable */
-		.src_port = 0,
-		.src_port_mask = 0, /* Disable */
-		.proto = IPPROTO_UDP,
-		.proto_mask = UINT8_MAX, /* 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 = UINT32_MAX, /* Enable */
-		.src_ip = 0,
-		.src_ip_mask = 0, /* Disable */
-		.dst_port = 0,
-		.dst_port_mask = 0, /* Disable */
-		.src_port = 0,
-		.src_port_mask = 0, /* Disable */
-		.proto = IPPROTO_UDP,
-		.proto_mask = UINT8_MAX, /* 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 = UINT32_MAX, /* Enable */
-		.src_ip = 0,
-		.src_ip_mask = 0, /* Disable */
-		.dst_port = 0,
-		.dst_port_mask = 0, /* Disable */
-		.src_port = 0,
-		.src_port_mask = 0, /* Disable */
-		.proto = IPPROTO_SCTP,
-		.proto_mask = UINT8_MAX, /* 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 = UINT32_MAX, /* Enable */
-		.src_ip = 0,
-		.src_ip_mask = 0, /* Disable */
-		.dst_port = 0,
-		.dst_port_mask = 0, /* Disable */
-		.src_port = 0,
-		.src_port_mask = 0, /* Disable */
-		.proto = IPPROTO_SCTP,
-		.proto_mask = UINT8_MAX, /* 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);
-}
-
-static void
-app_link_set_arp_filter(struct app_params *app, struct app_link_params *cp)
-{
-	if (cp->arp_q != 0) {
-		int status = app_link_filter_arp_add(cp);
-
-		APP_LOG(app, LOW, "%s (%" PRIu32 "): "
-			"Adding ARP filter (queue = %" PRIu32 ")",
-			cp->name, cp->pmd_id, cp->arp_q);
-
-		if (status)
-			rte_panic("%s (%" PRIu32 "): "
-				"Error adding ARP filter "
-				"(queue = %" PRIu32 ") (%" PRId32 ")\n",
-				cp->name, cp->pmd_id, cp->arp_q, status);
-	}
-}
-
-static void
-app_link_set_tcp_syn_filter(struct app_params *app, struct app_link_params *cp)
-{
-	if (cp->tcp_syn_q != 0) {
-		int status = app_link_filter_tcp_syn_add(cp);
-
-		APP_LOG(app, LOW, "%s (%" PRIu32 "): "
-			"Adding TCP SYN filter (queue = %" PRIu32 ")",
-			cp->name, cp->pmd_id, cp->tcp_syn_q);
-
-		if (status)
-			rte_panic("%s (%" PRIu32 "): "
-				"Error adding TCP SYN filter "
-				"(queue = %" PRIu32 ") (%" PRId32 ")\n",
-				cp->name, cp->pmd_id, cp->tcp_syn_q,
-				status);
-	}
-}
-
-void
-app_link_up_internal(struct app_params *app, struct app_link_params *cp)
-{
-	uint32_t i;
-	int status;
-
-	/* For each link, add filters for IP of current link */
-	if (cp->ip != 0) {
-		for (i = 0; i < app->n_links; i++) {
-			struct app_link_params *p = &app->link_params[i];
-
-			/* IP */
-			if (p->ip_local_q != 0) {
-				int status = app_link_filter_ip_add(p, cp);
-
-				APP_LOG(app, LOW, "%s (%" PRIu32 "): "
-					"Adding IP filter (queue= %" PRIu32
-					", IP = 0x%08" PRIx32 ")",
-					p->name, p->pmd_id, p->ip_local_q,
-					cp->ip);
-
-				if (status)
-					rte_panic("%s (%" PRIu32 "): "
-						"Error adding IP "
-						"filter (queue= %" PRIu32 ", "
-						"IP = 0x%08" PRIx32
-						") (%" PRId32 ")\n",
-						p->name, p->pmd_id,
-						p->ip_local_q, cp->ip, status);
-			}
-
-			/* TCP */
-			if (p->tcp_local_q != 0) {
-				int status = app_link_filter_tcp_add(p, cp);
-
-				APP_LOG(app, LOW, "%s (%" PRIu32 "): "
-					"Adding TCP filter "
-					"(queue = %" PRIu32
-					", IP = 0x%08" PRIx32 ")",
-					p->name, p->pmd_id, p->tcp_local_q,
-					cp->ip);
-
-				if (status)
-					rte_panic("%s (%" PRIu32 "): "
-						"Error adding TCP "
-						"filter (queue = %" PRIu32 ", "
-						"IP = 0x%08" PRIx32
-						") (%" PRId32 ")\n",
-						p->name, p->pmd_id,
-						p->tcp_local_q, cp->ip, status);
-			}
-
-			/* UDP */
-			if (p->udp_local_q != 0) {
-				int status = app_link_filter_udp_add(p, cp);
-
-				APP_LOG(app, LOW, "%s (%" PRIu32 "): "
-					"Adding UDP filter "
-					"(queue = %" PRIu32
-					", IP = 0x%08" PRIx32 ")",
-					p->name, p->pmd_id, p->udp_local_q,
-					cp->ip);
-
-				if (status)
-					rte_panic("%s (%" PRIu32 "): "
-						"Error adding UDP "
-						"filter (queue = %" PRIu32 ", "
-						"IP = 0x%08" PRIx32
-						") (%" PRId32 ")\n",
-						p->name, p->pmd_id,
-						p->udp_local_q, cp->ip, status);
-			}
-
-			/* SCTP */
-			if (p->sctp_local_q != 0) {
-				int status = app_link_filter_sctp_add(p, cp);
-
-				APP_LOG(app, LOW, "%s (%" PRIu32
-					"): Adding SCTP filter "
-					"(queue = %" PRIu32
-					", IP = 0x%08" PRIx32 ")",
-					p->name, p->pmd_id, p->sctp_local_q,
-					cp->ip);
-
-				if (status)
-					rte_panic("%s (%" PRIu32 "): "
-						"Error adding SCTP "
-						"filter (queue = %" PRIu32 ", "
-						"IP = 0x%08" PRIx32
-						") (%" PRId32 ")\n",
-						p->name, p->pmd_id,
-						p->sctp_local_q, cp->ip,
-						status);
-			}
-		}
-	}
-
-	/* PMD link up */
-	status = rte_eth_dev_set_link_up(cp->pmd_id);
-	/* Do not panic if PMD does not provide link up functionality */
-	if (status < 0 && status != -ENOTSUP)
-		rte_panic("%s (%" PRIu32 "): PMD set link up error %"
-			PRId32 "\n", cp->name, cp->pmd_id, status);
-
-	/* Mark link as UP */
-	cp->state = 1;
-}
-
-void
-app_link_down_internal(struct app_params *app, struct app_link_params *cp)
-{
-	uint32_t i;
-	int status;
-
-	/* PMD link down */
-	status = rte_eth_dev_set_link_down(cp->pmd_id);
-	/* Do not panic if PMD does not provide link down functionality */
-	if (status < 0 && status != -ENOTSUP)
-		rte_panic("%s (%" PRIu32 "): PMD set link down error %"
-			PRId32 "\n", cp->name, cp->pmd_id, status);
-
-	/* Mark link as DOWN */
-	cp->state = 0;
-
-	/* Return if current link IP is not valid */
-	if (cp->ip == 0)
-		return;
-
-	/* For each link, remove filters for IP of current link */
-	for (i = 0; i < app->n_links; i++) {
-		struct app_link_params *p = &app->link_params[i];
-
-		/* IP */
-		if (p->ip_local_q != 0) {
-			int status = app_link_filter_ip_del(p, cp);
-
-			APP_LOG(app, LOW, "%s (%" PRIu32
-				"): Deleting IP filter "
-				"(queue = %" PRIu32 ", IP = 0x%" PRIx32 ")",
-				p->name, p->pmd_id, p->ip_local_q, cp->ip);
-
-			if (status)
-				rte_panic("%s (%" PRIu32
-					"): Error deleting IP filter "
-					"(queue = %" PRIu32
-					", IP = 0x%" PRIx32
-					") (%" PRId32 ")\n",
-					p->name, p->pmd_id, p->ip_local_q,
-					cp->ip, status);
-		}
-
-		/* TCP */
-		if (p->tcp_local_q != 0) {
-			int status = app_link_filter_tcp_del(p, cp);
-
-			APP_LOG(app, LOW, "%s (%" PRIu32
-				"): Deleting TCP filter "
-				"(queue = %" PRIu32
-				", IP = 0x%" PRIx32 ")",
-				p->name, p->pmd_id, p->tcp_local_q, cp->ip);
-
-			if (status)
-				rte_panic("%s (%" PRIu32
-					"): Error deleting TCP filter "
-					"(queue = %" PRIu32
-					", IP = 0x%" PRIx32
-					") (%" PRId32 ")\n",
-					p->name, p->pmd_id, p->tcp_local_q,
-					cp->ip, status);
-		}
-
-		/* UDP */
-		if (p->udp_local_q != 0) {
-			int status = app_link_filter_udp_del(p, cp);
-
-			APP_LOG(app, LOW, "%s (%" PRIu32
-				"): Deleting UDP filter "
-				"(queue = %" PRIu32 ", IP = 0x%" PRIx32 ")",
-				p->name, p->pmd_id, p->udp_local_q, cp->ip);
-
-			if (status)
-				rte_panic("%s (%" PRIu32
-					"): Error deleting UDP filter "
-					"(queue = %" PRIu32
-					", IP = 0x%" PRIx32
-					") (%" PRId32 ")\n",
-					p->name, p->pmd_id, p->udp_local_q,
-					cp->ip, status);
-		}
-
-		/* SCTP */
-		if (p->sctp_local_q != 0) {
-			int status = app_link_filter_sctp_del(p, cp);
-
-			APP_LOG(app, LOW, "%s (%" PRIu32
-				"): Deleting SCTP filter "
-				"(queue = %" PRIu32
-				", IP = 0x%" PRIx32 ")",
-				p->name, p->pmd_id, p->sctp_local_q, cp->ip);
-
-			if (status)
-				rte_panic("%s (%" PRIu32
-					"): Error deleting SCTP filter "
-					"(queue = %" PRIu32
-					", IP = 0x%" PRIx32
-					") (%" PRId32 ")\n",
-					p->name, p->pmd_id, p->sctp_local_q,
-					cp->ip, status);
-		}
-	}
-}
-
-static void
-app_check_link(struct app_params *app)
-{
-	uint32_t all_links_up, i;
-
-	all_links_up = 1;
-
-	for (i = 0; i < app->n_links; i++) {
-		struct app_link_params *p = &app->link_params[i];
-		struct rte_eth_link link_params;
-
-		memset(&link_params, 0, sizeof(link_params));
-		rte_eth_link_get(p->pmd_id, &link_params);
-
-		APP_LOG(app, HIGH, "%s (%" PRIu32 ") (%" PRIu32 " Gbps) %s",
-			p->name,
-			p->pmd_id,
-			link_params.link_speed / 1000,
-			link_params.link_status ? "UP" : "DOWN");
-
-		if (link_params.link_status == ETH_LINK_DOWN)
-			all_links_up = 0;
-	}
-
-	if (all_links_up == 0)
-		rte_panic("Some links are DOWN\n");
-}
-
-static uint32_t
-is_any_swq_frag_or_ras(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_pktq_swq; i++) {
-		struct app_pktq_swq_params *p = &app->swq_params[i];
-
-		if ((p->ipv4_frag == 1) || (p->ipv6_frag == 1) ||
-			(p->ipv4_ras == 1) || (p->ipv6_ras == 1))
-			return 1;
-	}
-
-	return 0;
-}
-
-static void
-app_init_link_frag_ras(struct app_params *app)
-{
-	uint32_t i;
-
-	if (is_any_swq_frag_or_ras(app)) {
-		for (i = 0; i < app->n_links; i++) {
-			struct app_link_params *p_link = &app->link_params[i];
-				p_link->conf.txmode.offloads |=
-						DEV_TX_OFFLOAD_MULTI_SEGS;
-		}
-	}
-}
-
-static inline int
-app_get_cpu_socket_id(uint32_t pmd_id)
-{
-	int status = rte_eth_dev_socket_id(pmd_id);
-
-	return (status != SOCKET_ID_ANY) ? status : 0;
-}
-
-static inline int
-app_link_rss_enabled(struct app_link_params *cp)
-{
-	return (cp->n_rss_qs) ? 1 : 0;
-}
-
-static void
-app_link_rss_setup(struct app_link_params *cp)
-{
-	struct rte_eth_dev_info dev_info;
-	struct rte_eth_rss_reta_entry64 reta_conf[APP_RETA_SIZE_MAX];
-	uint32_t i;
-	int status;
-
-    /* Get RETA size */
-	memset(&dev_info, 0, sizeof(dev_info));
-	rte_eth_dev_info_get(cp->pmd_id, &dev_info);
-
-	if (dev_info.reta_size == 0)
-		rte_panic("%s (%u): RSS setup error (null RETA size)\n",
-			cp->name, cp->pmd_id);
-
-	if (dev_info.reta_size > ETH_RSS_RETA_SIZE_512)
-		rte_panic("%s (%u): RSS setup error (RETA size too big)\n",
-			cp->name, cp->pmd_id);
-
-	/* Setup RETA contents */
-	memset(reta_conf, 0, sizeof(reta_conf));
-
-	for (i = 0; i < dev_info.reta_size; i++)
-		reta_conf[i / RTE_RETA_GROUP_SIZE].mask = UINT64_MAX;
-
-	for (i = 0; i < dev_info.reta_size; i++) {
-		uint32_t reta_id = i / RTE_RETA_GROUP_SIZE;
-		uint32_t reta_pos = i % RTE_RETA_GROUP_SIZE;
-		uint32_t rss_qs_pos = i % cp->n_rss_qs;
-
-		reta_conf[reta_id].reta[reta_pos] =
-			(uint16_t) cp->rss_qs[rss_qs_pos];
-	}
-
-	/* RETA update */
-	status = rte_eth_dev_rss_reta_update(cp->pmd_id,
-		reta_conf,
-		dev_info.reta_size);
-	if (status != 0)
-		rte_panic("%s (%u): RSS setup error (RETA update failed)\n",
-			cp->name, cp->pmd_id);
-}
-
-static void
-app_init_link_set_config(struct app_link_params *p)
-{
-	if (p->n_rss_qs) {
-		p->conf.rxmode.mq_mode = ETH_MQ_RX_RSS;
-		p->conf.rx_adv_conf.rss_conf.rss_hf = p->rss_proto_ipv4 |
-			p->rss_proto_ipv6 |
-			p->rss_proto_l2;
-	}
-}
-
-static void
-app_init_link(struct app_params *app)
-{
-	uint32_t i;
-
-	app_init_link_frag_ras(app);
-
-	for (i = 0; i < app->n_links; i++) {
-		struct app_link_params *p_link = &app->link_params[i];
-		struct rte_eth_dev_info dev_info;
-		uint32_t link_id, n_hwq_in, n_hwq_out, j;
-		int status;
-
-		sscanf(p_link->name, "LINK%" PRIu32, &link_id);
-		n_hwq_in = app_link_get_n_rxq(app, p_link);
-		n_hwq_out = app_link_get_n_txq(app, p_link);
-		app_init_link_set_config(p_link);
-
-		APP_LOG(app, HIGH, "Initializing %s (%" PRIu32") "
-			"(%" PRIu32 " RXQ, %" PRIu32 " TXQ) ...",
-			p_link->name,
-			p_link->pmd_id,
-			n_hwq_in,
-			n_hwq_out);
-
-		/* LINK */
-		rte_eth_dev_info_get(p_link->pmd_id, &dev_info);
-		if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE)
-			p_link->conf.txmode.offloads |=
-				DEV_TX_OFFLOAD_MBUF_FAST_FREE;
-		status = rte_eth_dev_configure(
-			p_link->pmd_id,
-			n_hwq_in,
-			n_hwq_out,
-			&p_link->conf);
-		if (status < 0)
-			rte_panic("%s (%" PRId32 "): "
-				"init error (%" PRId32 ")\n",
-				p_link->name, p_link->pmd_id, status);
-
-		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->n_pktq_hwq_in; j++) {
-			struct app_pktq_hwq_in_params *p_rxq =
-				&app->hwq_in_params[j];
-			uint32_t rxq_link_id, rxq_queue_id;
-			uint16_t nb_rxd = p_rxq->size;
-
-			sscanf(p_rxq->name, "RXQ%" PRIu32 ".%" PRIu32,
-				&rxq_link_id, &rxq_queue_id);
-			if (rxq_link_id != link_id)
-				continue;
-
-			status = rte_eth_dev_adjust_nb_rx_tx_desc(
-				p_link->pmd_id,
-				&nb_rxd,
-				NULL);
-			if (status < 0)
-				rte_panic("%s (%" PRIu32 "): "
-					"%s adjust number of Rx descriptors "
-					"error (%" PRId32 ")\n",
-					p_link->name,
-					p_link->pmd_id,
-					p_rxq->name,
-					status);
-
-			p_rxq->conf.offloads = p_link->conf.rxmode.offloads;
-			status = rte_eth_rx_queue_setup(
-				p_link->pmd_id,
-				rxq_queue_id,
-				nb_rxd,
-				app_get_cpu_socket_id(p_link->pmd_id),
-				&p_rxq->conf,
-				app->mempool[p_rxq->mempool_id]);
-			if (status < 0)
-				rte_panic("%s (%" PRIu32 "): "
-					"%s init error (%" PRId32 ")\n",
-					p_link->name,
-					p_link->pmd_id,
-					p_rxq->name,
-					status);
-		}
-
-		/* TXQ */
-		for (j = 0; j < app->n_pktq_hwq_out; j++) {
-			struct app_pktq_hwq_out_params *p_txq =
-				&app->hwq_out_params[j];
-			uint32_t txq_link_id, txq_queue_id;
-			uint16_t nb_txd = p_txq->size;
-
-			sscanf(p_txq->name, "TXQ%" PRIu32 ".%" PRIu32,
-				&txq_link_id, &txq_queue_id);
-			if (txq_link_id != link_id)
-				continue;
-
-			status = rte_eth_dev_adjust_nb_rx_tx_desc(
-				p_link->pmd_id,
-				NULL,
-				&nb_txd);
-			if (status < 0)
-				rte_panic("%s (%" PRIu32 "): "
-					"%s adjust number of Tx descriptors "
-					"error (%" PRId32 ")\n",
-					p_link->name,
-					p_link->pmd_id,
-					p_txq->name,
-					status);
-
-			p_txq->conf.offloads = p_link->conf.txmode.offloads;
-			status = rte_eth_tx_queue_setup(
-				p_link->pmd_id,
-				txq_queue_id,
-				nb_txd,
-				app_get_cpu_socket_id(p_link->pmd_id),
-				&p_txq->conf);
-			if (status < 0)
-				rte_panic("%s (%" PRIu32 "): "
-					"%s init error (%" PRId32 ")\n",
-					p_link->name,
-					p_link->pmd_id,
-					p_txq->name,
-					status);
-		}
-
-		/* LINK START */
-		status = rte_eth_dev_start(p_link->pmd_id);
-		if (status < 0)
-			rte_panic("Cannot start %s (error %" PRId32 ")\n",
-				p_link->name, status);
-
-		/* LINK FILTERS */
-		app_link_set_arp_filter(app, p_link);
-		app_link_set_tcp_syn_filter(app, p_link);
-		if (app_link_rss_enabled(p_link))
-			app_link_rss_setup(p_link);
-
-		/* LINK UP */
-		app_link_up_internal(app, p_link);
-	}
-
-	app_check_link(app);
-}
-
-static void
-app_init_swq(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_pktq_swq; i++) {
-		struct app_pktq_swq_params *p = &app->swq_params[i];
-		unsigned flags = 0;
-
-		if (app_swq_get_readers(app, p) == 1)
-			flags |= RING_F_SC_DEQ;
-		if (app_swq_get_writers(app, p) == 1)
-			flags |= RING_F_SP_ENQ;
-
-		APP_LOG(app, HIGH, "Initializing %s...", p->name);
-		app->swq[i] = rte_ring_create(
-				p->name,
-				p->size,
-				p->cpu_socket_id,
-				flags);
-
-		if (app->swq[i] == NULL)
-			rte_panic("%s init error\n", p->name);
-	}
-}
-
-static void
-app_init_tm(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_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;
-
-		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 =
-			app_get_cpu_socket_id(p_link->pmd_id);
-		p_tm->sched_port_params.rate =
-			(uint64_t) link_eth_params.link_speed * 1000 * 1000 / 8;
-
-		APP_LOG(app, HIGH, "Initializing %s ...", p_tm->name);
-		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 %" PRIu32
-					" init error (%" PRId32 ")\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 %" PRIu32
-						" pipe %" PRIu32
-						" (profile %" PRId32 ") "
-						"init error (% " PRId32 ")\n",
-						p_tm->name, subport_id, pipe_id,
-						profile_id, status);
-			}
-		}
-	}
-}
-
-#ifndef RTE_EXEC_ENV_LINUXAPP
-static void
-app_init_tap(struct app_params *app) {
-	if (app->n_pktq_tap == 0)
-		return;
-
-	rte_panic("TAP device not supported.\n");
-}
-#else
-static void
-app_init_tap(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_pktq_tap; i++) {
-		struct app_pktq_tap_params *p_tap = &app->tap_params[i];
-		struct ifreq ifr;
-		int fd, status;
-
-		APP_LOG(app, HIGH, "Initializing %s ...", p_tap->name);
-
-		fd = open("/dev/net/tun", O_RDWR | O_NONBLOCK);
-		if (fd < 0)
-			rte_panic("Cannot open file /dev/net/tun\n");
-
-		memset(&ifr, 0, sizeof(ifr));
-		ifr.ifr_flags = IFF_TAP | IFF_NO_PI; /* No packet information */
-		snprintf(ifr.ifr_name, IFNAMSIZ, "%s", p_tap->name);
-
-		status = ioctl(fd, TUNSETIFF, (void *) &ifr);
-		if (status < 0)
-			rte_panic("TAP setup error\n");
-
-		app->tap[i] = fd;
-	}
-}
-#endif
-
-#ifdef RTE_LIBRTE_KNI
-static int
-kni_config_network_interface(uint16_t port_id, uint8_t if_up) {
-	int ret = 0;
-
-	if (port_id >= rte_eth_dev_count())
-		return -EINVAL;
-
-	ret = (if_up) ?
-		rte_eth_dev_set_link_up(port_id) :
-		rte_eth_dev_set_link_down(port_id);
-
-	return ret;
-}
-
-static int
-kni_change_mtu(uint16_t port_id, unsigned int new_mtu) {
-	int ret;
-
-	if (port_id >= rte_eth_dev_count())
-		return -EINVAL;
-
-	if (new_mtu > ETHER_MAX_LEN)
-		return -EINVAL;
-
-	/* Set new MTU */
-	ret = rte_eth_dev_set_mtu(port_id, new_mtu);
-	if (ret < 0)
-		return ret;
-
-	return 0;
-}
-#endif /* RTE_LIBRTE_KNI */
-
-#ifndef RTE_LIBRTE_KNI
-static void
-app_init_kni(struct app_params *app) {
-	if (app->n_pktq_kni == 0)
-		return;
-
-	rte_panic("Can not init KNI without librte_kni support.\n");
-}
-#else
-static void
-app_init_kni(struct app_params *app) {
-	uint32_t i;
-
-	if (app->n_pktq_kni == 0)
-		return;
-
-	rte_kni_init(app->n_pktq_kni);
-
-	for (i = 0; i < app->n_pktq_kni; i++) {
-		struct app_pktq_kni_params *p_kni = &app->kni_params[i];
-		struct app_link_params *p_link;
-		struct rte_eth_dev_info dev_info;
-		struct app_mempool_params *mempool_params;
-		struct rte_mempool *mempool;
-		struct rte_kni_conf conf;
-		struct rte_kni_ops ops;
-
-		/* LINK */
-		p_link = app_get_link_for_kni(app, p_kni);
-		memset(&dev_info, 0, sizeof(dev_info));
-		rte_eth_dev_info_get(p_link->pmd_id, &dev_info);
-
-		/* MEMPOOL */
-		mempool_params = &app->mempool_params[p_kni->mempool_id];
-		mempool = app->mempool[p_kni->mempool_id];
-
-		/* KNI */
-		memset(&conf, 0, sizeof(conf));
-		snprintf(conf.name, RTE_KNI_NAMESIZE, "%s", p_kni->name);
-		conf.force_bind = p_kni->force_bind;
-		if (conf.force_bind) {
-			int lcore_id;
-
-			lcore_id = cpu_core_map_get_lcore_id(app->core_map,
-				p_kni->socket_id,
-				p_kni->core_id,
-				p_kni->hyper_th_id);
-
-			if (lcore_id < 0)
-				rte_panic("%s invalid CPU core\n", p_kni->name);
-
-			conf.core_id = (uint32_t) lcore_id;
-		}
-		conf.group_id = p_link->pmd_id;
-		conf.mbuf_size = mempool_params->buffer_size;
-		conf.addr = dev_info.pci_dev->addr;
-		conf.id = dev_info.pci_dev->id;
-
-		memset(&ops, 0, sizeof(ops));
-		ops.port_id = (uint8_t) p_link->pmd_id;
-		ops.change_mtu = kni_change_mtu;
-		ops.config_network_if = kni_config_network_interface;
-
-		APP_LOG(app, HIGH, "Initializing %s ...", p_kni->name);
-		app->kni[i] = rte_kni_alloc(mempool, &conf, &ops);
-		if (!app->kni[i])
-			rte_panic("%s init error\n", p_kni->name);
-	}
-}
-#endif /* RTE_LIBRTE_KNI */
-
-static void
-app_init_msgq(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_msgq; i++) {
-		struct app_msgq_params *p = &app->msgq_params[i];
-
-		APP_LOG(app, HIGH, "Initializing %s ...", 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);
-	}
-}
-
-void app_pipeline_params_get(struct app_params *app,
-	struct app_pipeline_params *p_in,
-	struct pipeline_params *p_out)
-{
-	uint32_t i;
-
-	snprintf(p_out->name, PIPELINE_NAME_SIZE, "%s", p_in->name);
-
-	snprintf(p_out->type, PIPELINE_TYPE_SIZE, "%s", p_in->type);
-
-	p_out->socket_id = (int) p_in->socket_id;
-
-	p_out->log_level = app->log_level;
-
-	/* 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];
-
-		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%" SCNu32 ".%" SCNu32,
-				&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:
-		{
-			struct app_pktq_swq_params *swq_params = &app->swq_params[in->id];
-
-			if ((swq_params->ipv4_frag == 0) && (swq_params->ipv6_frag == 0)) {
-				if (app_swq_get_readers(app, swq_params) == 1) {
-					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;
-				} else {
-					out->type = PIPELINE_PORT_IN_RING_MULTI_READER;
-					out->params.ring_multi.ring = app->swq[in->id];
-					out->burst_size = swq_params->burst_read;
-				}
-			} else {
-				if (swq_params->ipv4_frag == 1) {
-					struct rte_port_ring_reader_ipv4_frag_params *params =
-						&out->params.ring_ipv4_frag;
-
-					out->type = PIPELINE_PORT_IN_RING_READER_IPV4_FRAG;
-					params->ring = app->swq[in->id];
-					params->mtu = swq_params->mtu;
-					params->metadata_size = swq_params->metadata_size;
-					params->pool_direct =
-						app->mempool[swq_params->mempool_direct_id];
-					params->pool_indirect =
-						app->mempool[swq_params->mempool_indirect_id];
-					out->burst_size = swq_params->burst_read;
-				} else {
-					struct rte_port_ring_reader_ipv6_frag_params *params =
-						&out->params.ring_ipv6_frag;
-
-					out->type = PIPELINE_PORT_IN_RING_READER_IPV6_FRAG;
-					params->ring = app->swq[in->id];
-					params->mtu = swq_params->mtu;
-					params->metadata_size = swq_params->metadata_size;
-					params->pool_direct =
-						app->mempool[swq_params->mempool_direct_id];
-					params->pool_indirect =
-						app->mempool[swq_params->mempool_indirect_id];
-					out->burst_size = swq_params->burst_read;
-				}
-			}
-			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;
-		}
-#ifdef RTE_EXEC_ENV_LINUXAPP
-		case APP_PKTQ_IN_TAP:
-		{
-			struct app_pktq_tap_params *tap_params =
-				&app->tap_params[in->id];
-			struct app_mempool_params *mempool_params =
-				&app->mempool_params[tap_params->mempool_id];
-			struct rte_mempool *mempool =
-				app->mempool[tap_params->mempool_id];
-
-			out->type = PIPELINE_PORT_IN_FD_READER;
-			out->params.fd.fd = app->tap[in->id];
-			out->params.fd.mtu = mempool_params->buffer_size;
-			out->params.fd.mempool = mempool;
-			out->burst_size = app->tap_params[in->id].burst_read;
-			break;
-		}
-#endif
-#ifdef RTE_LIBRTE_KNI
-		case APP_PKTQ_IN_KNI:
-		{
-			out->type = PIPELINE_PORT_IN_KNI_READER;
-			out->params.kni.kni = app->kni[in->id];
-			out->burst_size = app->kni_params[in->id].burst_read;
-			break;
-		}
-#endif /* RTE_LIBRTE_KNI */
-		case APP_PKTQ_IN_SOURCE:
-		{
-			uint32_t mempool_id =
-				app->source_params[in->id].mempool_id;
-
-			out->type = PIPELINE_PORT_IN_SOURCE;
-			out->params.source.mempool = app->mempool[mempool_id];
-			out->burst_size = app->source_params[in->id].burst;
-			out->params.source.file_name =
-				app->source_params[in->id].file_name;
-			out->params.source.n_bytes_per_pkt =
-				app->source_params[in->id].n_bytes_per_pkt;
-			break;
-		}
-		default:
-			break;
-		}
-	}
-
-	/* 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%" SCNu32 ".%" SCNu32,
-				&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:
-		{
-			struct app_pktq_swq_params *swq_params = &app->swq_params[in->id];
-
-			if ((swq_params->ipv4_ras == 0) && (swq_params->ipv6_ras == 0)) {
-				if (app_swq_get_writers(app, swq_params) == 1) {
-					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;
-					}
-				} else {
-					if (swq_params->dropless == 0) {
-						struct rte_port_ring_multi_writer_params *params =
-							&out->params.ring_multi;
-
-						out->type = PIPELINE_PORT_OUT_RING_MULTI_WRITER;
-						params->ring = app->swq[in->id];
-						params->tx_burst_sz = swq_params->burst_write;
-					} else {
-						struct rte_port_ring_multi_writer_nodrop_params
-							*params = &out->params.ring_multi_nodrop;
-
-						out->type = PIPELINE_PORT_OUT_RING_MULTI_WRITER_NODROP;
-						params->ring = app->swq[in->id];
-						params->tx_burst_sz = swq_params->burst_write;
-						params->n_retries = swq_params->n_retries;
-					}
-				}
-			} else {
-				if (swq_params->ipv4_ras == 1) {
-					struct rte_port_ring_writer_ipv4_ras_params *params =
-						&out->params.ring_ipv4_ras;
-
-					out->type = PIPELINE_PORT_OUT_RING_WRITER_IPV4_RAS;
-					params->ring = app->swq[in->id];
-					params->tx_burst_sz = swq_params->burst_write;
-				} else {
-					struct rte_port_ring_writer_ipv6_ras_params *params =
-						&out->params.ring_ipv6_ras;
-
-					out->type = PIPELINE_PORT_OUT_RING_WRITER_IPV6_RAS;
-					params->ring = app->swq[in->id];
-					params->tx_burst_sz = swq_params->burst_write;
-				}
-			}
-			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;
-		}
-#ifdef RTE_EXEC_ENV_LINUXAPP
-		case APP_PKTQ_OUT_TAP:
-		{
-			struct rte_port_fd_writer_params *params =
-				&out->params.fd;
-
-			out->type = PIPELINE_PORT_OUT_FD_WRITER;
-			params->fd = app->tap[in->id];
-			params->tx_burst_sz =
-				app->tap_params[in->id].burst_write;
-			break;
-		}
-#endif
-#ifdef RTE_LIBRTE_KNI
-		case APP_PKTQ_OUT_KNI:
-		{
-			struct app_pktq_kni_params *p_kni =
-				&app->kni_params[in->id];
-
-			if (p_kni->dropless == 0) {
-				struct rte_port_kni_writer_params *params =
-					&out->params.kni;
-
-				out->type = PIPELINE_PORT_OUT_KNI_WRITER;
-				params->kni = app->kni[in->id];
-				params->tx_burst_sz =
-					app->kni_params[in->id].burst_write;
-			} else {
-				struct rte_port_kni_writer_nodrop_params
-					*params = &out->params.kni_nodrop;
-
-				out->type = PIPELINE_PORT_OUT_KNI_WRITER_NODROP;
-				params->kni = app->kni[in->id];
-				params->tx_burst_sz =
-					app->kni_params[in->id].burst_write;
-				params->n_retries =
-					app->kni_params[in->id].n_retries;
-			}
-			break;
-		}
-#endif /* RTE_LIBRTE_KNI */
-		case APP_PKTQ_OUT_SINK:
-		{
-			out->type = PIPELINE_PORT_OUT_SINK;
-			out->params.sink.file_name =
-				app->sink_params[in->id].file_name;
-			out->params.sink.max_n_pkts =
-				app->sink_params[in->id].
-				n_pkts_to_dump;
-
-			break;
-		}
-		default:
-			break;
-		}
-	}
-
-	/* msgq */
-	p_out->n_msgq = p_in->n_msgq_in;
-
-	for (i = 0; i < p_in->n_msgq_in; i++)
-		p_out->msgq_in[i] = app->msgq[p_in->msgq_in[i]];
-
-	for (i = 0; i < p_in->n_msgq_out; i++)
-		p_out->msgq_out[i] = app->msgq[p_in->msgq_out[i]];
-
-	/* 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];
-	}
-}
-
-static void
-app_init_pipelines(struct app_params *app)
-{
-	uint32_t p_id;
-
-	for (p_id = 0; p_id < app->n_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;
-
-		APP_LOG(app, HIGH, "Initializing %s ...", 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->be_ops->f_init) {
-			data->be = ptype->be_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->ptype = ptype;
-
-		data->timer_period = (rte_get_tsc_hz() *
-			params->timer_period) / 1000;
-	}
-}
-
-static void
-app_post_init_pipelines(struct app_params *app)
-{
-	uint32_t p_id;
-
-	for (p_id = 0; p_id < app->n_pipelines; p_id++) {
-		struct app_pipeline_params *params =
-			&app->pipeline_params[p_id];
-		struct app_pipeline_data *data = &app->pipeline_data[p_id];
-		int status;
-
-		if (data->ptype->fe_ops->f_post_init == NULL)
-			continue;
-
-		status = data->ptype->fe_ops->f_post_init(data->fe);
-		if (status)
-			rte_panic("Pipeline instance \"%s\" front-end "
-				"post-init error\n", params->name);
-	}
-}
-
-static void
-app_init_threads(struct app_params *app)
-{
-	uint64_t time = rte_get_tsc_cycles();
-	uint32_t p_id;
-
-	for (p_id = 0; p_id < app->n_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;
-
-		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%" PRIu32 "c%" PRIu32 "%s\n",
-				params->socket_id,
-				params->core_id,
-				(params->hyper_th_id) ? "h" : "");
-
-		t = &app->thread_data[lcore_id];
-
-		t->timer_period = (rte_get_tsc_hz() * APP_THREAD_TIMER_PERIOD) / 1000;
-		t->thread_req_deadline = time + t->timer_period;
-
-		t->headroom_cycles = 0;
-		t->headroom_time = rte_get_tsc_cycles();
-		t->headroom_ratio = 0.0;
-
-		t->msgq_in = app_thread_msgq_in_get(app,
-				params->socket_id,
-				params->core_id,
-				params->hyper_th_id);
-		if (t->msgq_in == NULL)
-			rte_panic("Init error: Cannot find MSGQ_IN for thread %" PRId32,
-				lcore_id);
-
-		t->msgq_out = app_thread_msgq_out_get(app,
-				params->socket_id,
-				params->core_id,
-				params->hyper_th_id);
-		if (t->msgq_out == NULL)
-			rte_panic("Init error: Cannot find MSGQ_OUT for thread %" PRId32,
-				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->be_ops->f_run == NULL) ?
-			&t->regular[t->n_regular] :
-			&t->custom[t->n_custom];
-
-		p->pipeline_id = p_id;
-		p->be = data->be;
-		p->f_run = ptype->be_ops->f_run;
-		p->f_timer = ptype->be_ops->f_timer;
-		p->timer_period = data->timer_period;
-		p->deadline = time + data->timer_period;
-
-		data->enabled = 1;
-
-		if (ptype->be_ops->f_run == NULL)
-			t->n_regular++;
-		else
-			t->n_custom++;
-	}
-}
-
-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_tap(app);
-	app_init_kni(app);
-	app_init_msgq(app);
-
-	app_pipeline_common_cmd_push(app);
-	app_pipeline_thread_cmd_push(app);
-	app_pipeline_type_register(app, &pipeline_master);
-	app_pipeline_type_register(app, &pipeline_passthrough);
-	app_pipeline_type_register(app, &pipeline_flow_classification);
-	app_pipeline_type_register(app, &pipeline_flow_actions);
-	app_pipeline_type_register(app, &pipeline_firewall);
-	app_pipeline_type_register(app, &pipeline_routing);
-
-	app_init_pipelines(app);
-	app_init_threads(app);
-
-	return 0;
-}
-
-int app_post_init(struct app_params *app)
-{
-	app_post_init_pipelines(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)
-{
-	uint32_t n_cmds, i;
-
-	/* Check input arguments */
-	if ((app == NULL) ||
-		(ptype == NULL) ||
-		(ptype->name == NULL) ||
-		(strlen(ptype->name) == 0) ||
-		(ptype->be_ops->f_init == NULL) ||
-		(ptype->be_ops->f_timer == 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;
-}
-
-struct
-pipeline_type *app_pipeline_type_find(struct app_params *app, char *name)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_pipeline_types; i++)
-		if (strcmp(app->pipeline_type[i].name, name) == 0)
-			return &app->pipeline_type[i];
-
-	return NULL;
-}
diff --git a/examples/ip_pipeline/main.c b/examples/ip_pipeline/main.c
index a44cf9a..1696e36 100644
--- a/examples/ip_pipeline/main.c
+++ b/examples/ip_pipeline/main.c
@@ -2,34 +2,24 @@
  * Copyright(c) 2010-2015 Intel Corporation
  */
 
-#include "app.h"
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <getopt.h>
 
-static struct app_params app;
+#include <rte_eal.h>
 
 int
 main(int argc, char **argv)
 {
-	rte_openlog_stream(stderr);
+	int status;
 
-	/* Config */
-	app_config_init(&app);
+	/* EAL */
+	status = rte_eal_init(argc, argv);
+	if (status < 0) {
+		printf("Error: EAL initialization failed (%d)\n", status);
+		return status;
+	};
 
-	app_config_args(&app, argc, argv);
-
-	app_config_preproc(&app);
-
-	app_config_parse(&app, app.parser_file);
-
-	app_config_check(&app);
-
-	/* 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/meson.build b/examples/ip_pipeline/meson.build
index 748c9ae..ea89460 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -6,30 +6,9 @@
 # To build this example as a standalone application with an already-installed
 # DPDK instance, use 'make'
 
-deps += ['cfgfile', 'pipeline', 'bus_pci']
+deps += ['pipeline', 'bus_pci']
 includes += include_directories('pipeline')
 sources = files(
-	'config_check.c',
-	'config_parse.c',
-	'config_parse_tm.c',
-	'cpu_core_map.c',
-	'init.c',
 	'main.c',
 	'parser.c',
-	'thread.c',
-	'thread_fe.c',
-	'pipeline/pipeline_common_be.c',
-	'pipeline/pipeline_common_fe.c',
-	'pipeline/pipeline_firewall_be.c',
-	'pipeline/pipeline_firewall.c',
-	'pipeline/pipeline_flow_actions_be.c',
-	'pipeline/pipeline_flow_actions.c',
-	'pipeline/pipeline_flow_classification_be.c',
-	'pipeline/pipeline_flow_classification.c',
-	'pipeline/pipeline_master_be.c',
-	'pipeline/pipeline_master.c',
-	'pipeline/pipeline_passthrough_be.c',
-	'pipeline/pipeline_passthrough.c',
-	'pipeline/pipeline_routing_be.c',
-	'pipeline/pipeline_routing.c',
 )
diff --git a/examples/ip_pipeline/parser.c b/examples/ip_pipeline/parser.c
index 0901e9c..0ae3d1d 100644
--- a/examples/ip_pipeline/parser.c
+++ b/examples/ip_pipeline/parser.c
@@ -39,7 +39,6 @@
 #include <rte_cfgfile.h>
 #include <rte_string_fns.h>
 
-#include "app.h"
 #include "parser.h"
 
 static uint32_t
@@ -596,10 +595,8 @@ parse_mac_addr(const char *token, struct ether_addr *addr)
 }
 
 int
-parse_pipeline_core(uint32_t *socket,
-	uint32_t *core,
-	uint32_t *ht,
-	const char *entry)
+parse_cpu_core(const char *entry,
+	struct cpu_core_params *p)
 {
 	size_t num_len;
 	char num[8];
@@ -609,6 +606,9 @@ parse_pipeline_core(uint32_t *socket,
 	const char *next = skip_white_spaces(entry);
 	char type;
 
+	if (p == NULL)
+		return -EINVAL;
+
 	/* Expect <CORE> or [sX][cY][h]. At least one parameter is required. */
 	while (*next != '\0') {
 		/* If everything parsed nothing should left */
@@ -682,8 +682,8 @@ parse_pipeline_core(uint32_t *socket,
 		}
 	}
 
-	*socket = s;
-	*core = c;
-	*ht = h;
+	p->socket_id = s;
+	p->core_id = c;
+	p->thread_id = h;
 	return 0;
 }
diff --git a/examples/ip_pipeline/parser.h b/examples/ip_pipeline/parser.h
index 5c421d2..261a8c8 100644
--- a/examples/ip_pipeline/parser.h
+++ b/examples/ip_pipeline/parser.h
@@ -50,6 +50,14 @@ int parse_ipv6_addr(const char *token, struct in6_addr *ipv6);
 int parse_mac_addr(const char *token, struct ether_addr *addr);
 int parse_mpls_labels(char *string, uint32_t *labels, uint32_t *n_labels);
 
+struct cpu_core_params {
+	uint32_t socket_id;
+	uint32_t core_id;
+	uint32_t thread_id;
+};
+
+int parse_cpu_core(const char *entry, struct cpu_core_params *p);
+
 int parse_tokenize_string(char *string, char *tokens[], uint32_t *n_tokens);
 
 #endif
diff --git a/examples/ip_pipeline/pipeline.h b/examples/ip_pipeline/pipeline.h
deleted file mode 100644
index 7ca9cad..0000000
--- a/examples/ip_pipeline/pipeline.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#ifndef __INCLUDE_PIPELINE_H__
-#define __INCLUDE_PIPELINE_H__
-
-#include <cmdline_parse.h>
-
-#include "pipeline_be.h"
-
-/*
- * Pipeline type front-end operations
- */
-
-typedef void* (*pipeline_fe_op_init)(struct pipeline_params *params,
-	void *arg);
-
-typedef int (*pipeline_fe_op_post_init)(void *pipeline);
-
-typedef int (*pipeline_fe_op_free)(void *pipeline);
-
-typedef int (*pipeline_fe_op_track)(struct pipeline_params *params,
-	uint32_t port_in,
-	uint32_t *port_out);
-
-struct pipeline_fe_ops {
-	pipeline_fe_op_init f_init;
-	pipeline_fe_op_post_init f_post_init;
-	pipeline_fe_op_free f_free;
-	pipeline_fe_op_track f_track;
-	cmdline_parse_ctx_t *cmds;
-};
-
-/*
- * Pipeline type
- */
-
-struct pipeline_type {
-	const char *name;
-
-	/* pipeline back-end */
-	struct pipeline_be_ops *be_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;
-}
-
-int
-parse_pipeline_core(uint32_t *socket,
-	uint32_t *core,
-	uint32_t *ht,
-	const char *entry);
-
-#endif
diff --git a/examples/ip_pipeline/pipeline/pipeline_actions_common.h b/examples/ip_pipeline/pipeline/pipeline_actions_common.h
deleted file mode 100644
index 23f8836..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_actions_common.h
+++ /dev/null
@@ -1,202 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2016 Intel Corporation
- */
-#ifndef __INCLUDE_PIPELINE_ACTIONS_COMMON_H__
-#define __INCLUDE_PIPELINE_ACTIONS_COMMON_H__
-
-#include <stdint.h>
-
-#include <rte_common.h>
-#include <rte_cycles.h>
-#include <rte_mbuf.h>
-#include <rte_pipeline.h>
-
-#define PIPELINE_PORT_IN_AH(f_ah, f_pkt_work, f_pkt4_work)		\
-static int								\
-f_ah(									\
-	__rte_unused struct rte_pipeline *p,				\
-	struct rte_mbuf **pkts,						\
-	uint32_t n_pkts,						\
-	void *arg)							\
-{									\
-	uint32_t i;							\
-									\
-	for (i = 0; i < (n_pkts & (~0x3LLU)); i += 4)			\
-		f_pkt4_work(&pkts[i], arg);				\
-									\
-	for ( ; i < n_pkts; i++)					\
-		f_pkt_work(pkts[i], arg);				\
-									\
-	return 0;							\
-}
-
-#define PIPELINE_PORT_IN_AH_HIJACK_ALL(f_ah, f_pkt_work, f_pkt4_work) \
-static int								\
-f_ah(									\
-	struct rte_pipeline *p,				\
-	struct rte_mbuf **pkts,					\
-	uint32_t n_pkts,						\
-	void *arg)						\
-{									\
-	uint64_t pkt_mask = RTE_LEN2MASK(n_pkts, uint64_t);	\
-	uint32_t i;							\
-									\
-	rte_pipeline_ah_packet_hijack(p, pkt_mask);	\
-									\
-	for (i = 0; i < (n_pkts & (~0x3LLU)); i += 4)	\
-		f_pkt4_work(&pkts[i], arg);				\
-									\
-	for ( ; i < n_pkts; i++)				\
-		f_pkt_work(pkts[i], arg);			\
-									\
-	return 0;							\
-}
-
-#define PIPELINE_TABLE_AH_HIT(f_ah, f_pkt_work, f_pkt4_work)		\
-static int								\
-f_ah(									\
-	__rte_unused struct rte_pipeline *p,				\
-	struct rte_mbuf **pkts,						\
-	uint64_t pkts_in_mask,						\
-	struct rte_pipeline_table_entry **entries,			\
-	void *arg)							\
-{									\
-	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 & (~0x3LLU)); i += 4)		\
-			f_pkt4_work(&pkts[i], &entries[i], arg);	\
-									\
-		for ( ; i < n_pkts; i++)				\
-			f_pkt_work(pkts[i], entries[i], arg);		\
-	} else								\
-		for ( ; pkts_in_mask; ) {				\
-			uint32_t pos = __builtin_ctzll(pkts_in_mask);	\
-			uint64_t pkt_mask = 1LLU << pos;		\
-									\
-			pkts_in_mask &= ~pkt_mask;			\
-			f_pkt_work(pkts[pos], entries[pos], arg);	\
-		}							\
-									\
-	return 0;							\
-}
-
-#define PIPELINE_TABLE_AH_MISS(f_ah, f_pkt_work, f_pkt4_work)		\
-static int								\
-f_ah(									\
-	__rte_unused struct rte_pipeline *p,				\
-	struct rte_mbuf **pkts,						\
-	uint64_t pkts_in_mask,						\
-	struct rte_pipeline_table_entry *entry,				\
-	void *arg)							\
-{									\
-	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 & (~0x3LLU)); i += 4)		\
-			f_pkt4_work(&pkts[i], entry, arg);		\
-									\
-		for ( ; i < n_pkts; i++)				\
-			f_pkt_work(pkts[i], entry, arg);		\
-	} else								\
-		for ( ; pkts_in_mask; ) {				\
-			uint32_t pos = __builtin_ctzll(pkts_in_mask);	\
-			uint64_t pkt_mask = 1LLU << pos;		\
-									\
-			pkts_in_mask &= ~pkt_mask;			\
-			f_pkt_work(pkts[pos], entry, arg);		\
-		}							\
-									\
-	return 0;							\
-}
-
-#define PIPELINE_TABLE_AH_HIT_DROP_TIME(f_ah, f_pkt_work, f_pkt4_work)	\
-static int								\
-f_ah(									\
-	struct rte_pipeline *p,						\
-	struct rte_mbuf **pkts,						\
-	uint64_t pkts_mask,						\
-	struct rte_pipeline_table_entry **entries,			\
-	void *arg)							\
-{									\
-	uint64_t pkts_in_mask = pkts_mask;				\
-	uint64_t pkts_out_mask = pkts_mask;				\
-	uint64_t time = rte_rdtsc();					\
-									\
-	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 & (~0x3LLU)); i += 4) {		\
-			uint64_t mask = f_pkt4_work(&pkts[i],		\
-				&entries[i], arg, time);		\
-			pkts_out_mask ^= mask << i;			\
-		}							\
-									\
-		for ( ; i < n_pkts; i++) {				\
-			uint64_t mask = f_pkt_work(pkts[i],		\
-				entries[i], arg, time);			\
-			pkts_out_mask ^= mask << i;			\
-		}							\
-	} else								\
-		for ( ; pkts_in_mask; ) {				\
-			uint32_t pos = __builtin_ctzll(pkts_in_mask);	\
-			uint64_t pkt_mask = 1LLU << pos;		\
-			uint64_t mask = f_pkt_work(pkts[pos],		\
-				entries[pos], arg, time);		\
-									\
-			pkts_in_mask &= ~pkt_mask;			\
-			pkts_out_mask ^= mask << pos;			\
-		}							\
-									\
-	rte_pipeline_ah_packet_drop(p, pkts_out_mask ^ pkts_mask);	\
-									\
-	return 0;							\
-}
-
-#define PIPELINE_TABLE_AH_MISS_DROP_TIME(f_ah, f_pkt_work, f_pkt4_work)	\
-static int								\
-f_ah(									\
-	struct rte_pipeline *p,						\
-	struct rte_mbuf **pkts,						\
-	uint64_t pkts_mask,						\
-	struct rte_pipeline_table_entry *entry,				\
-	void *arg)							\
-{									\
-	uint64_t pkts_in_mask = pkts_mask;				\
-	uint64_t pkts_out_mask = pkts_mask;				\
-	uint64_t time = rte_rdtsc();					\
-									\
-	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 & (~0x3LLU)); i += 4) {		\
-			uint64_t mask = f_pkt4_work(&pkts[i],		\
-				entry, arg, time);			\
-			pkts_out_mask ^= mask << i;			\
-		}							\
-									\
-		for ( ; i < n_pkts; i++) {				\
-			uint64_t mask = f_pkt_work(pkts[i], entry, arg, time);\
-			pkts_out_mask ^= mask << i;			\
-		}							\
-	} else								\
-		for ( ; pkts_in_mask; ) {				\
-			uint32_t pos = __builtin_ctzll(pkts_in_mask);	\
-			uint64_t pkt_mask = 1LLU << pos;		\
-			uint64_t mask = f_pkt_work(pkts[pos],		\
-				entry, arg, time);		\
-									\
-			pkts_in_mask &= ~pkt_mask;			\
-			pkts_out_mask ^= mask << pos;			\
-		}							\
-									\
-	rte_pipeline_ah_packet_drop(p, pkts_out_mask ^ pkts_mask);	\
-									\
-	return 0;							\
-}
-
-#endif
diff --git a/examples/ip_pipeline/pipeline/pipeline_common_be.c b/examples/ip_pipeline/pipeline/pipeline_common_be.c
deleted file mode 100644
index 5d84989..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_common_be.c
+++ /dev/null
@@ -1,176 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#include <rte_common.h>
-#include <rte_malloc.h>
-
-#include "pipeline_common_be.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(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(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(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(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(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_be.h b/examples/ip_pipeline/pipeline/pipeline_common_be.h
deleted file mode 100644
index 83bd04e..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_common_be.h
+++ /dev/null
@@ -1,134 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#ifndef __INCLUDE_PIPELINE_COMMON_BE_H__
-#define __INCLUDE_PIPELINE_COMMON_BE_H__
-
-#include <rte_common.h>
-#include <rte_ring.h>
-#include <rte_pipeline.h>
-
-#include "pipeline_be.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];
-	uint32_t log_level;
-};
-
-enum pipeline_log_level {
-	PIPELINE_LOG_LEVEL_HIGH = 1,
-	PIPELINE_LOG_LEVEL_LOW,
-	PIPELINE_LOG_LEVELS
-};
-
-#define PLOG(p, level, fmt, ...)					\
-do {									\
-	if (p->log_level >= PIPELINE_LOG_LEVEL_ ## level)		\
-		fprintf(stdout, "[%s] " fmt "\n", p->name, ## __VA_ARGS__);\
-} while (0)
-
-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_common_fe.c b/examples/ip_pipeline/pipeline/pipeline_common_fe.c
deleted file mode 100644
index cc5214c..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_common_fe.c
+++ /dev/null
@@ -1,1455 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2016 Intel Corporation
- */
-
-#include <stdio.h>
-#include <fcntl.h>
-#include <unistd.h>
-
-#include <rte_common.h>
-#include <rte_malloc.h>
-#include <cmdline_rdline.h>
-#include <cmdline_parse.h>
-#include <cmdline_parse_num.h>
-#include <cmdline_parse_string.h>
-#include <cmdline.h>
-
-#include "pipeline_common_fe.h"
-#include "parser.h"
-
-struct app_link_params *
-app_pipeline_track_pktq_out_to_link(struct app_params *app,
-	uint32_t pipeline_id,
-	uint32_t pktq_out_id)
-{
-	struct app_pipeline_params *p;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return NULL;
-
-	APP_PARAM_FIND_BY_ID(app->pipeline_params, "PIPELINE", pipeline_id, p);
-	if (p == NULL)
-		return NULL;
-
-	for ( ; ; ) {
-		struct app_pktq_out_params *pktq_out =
-			&p->pktq_out[pktq_out_id];
-
-		switch (pktq_out->type) {
-		case APP_PKTQ_OUT_HWQ:
-		{
-			struct app_pktq_hwq_out_params *hwq_out;
-
-			hwq_out = &app->hwq_out_params[pktq_out->id];
-
-			return app_get_link_for_txq(app, hwq_out);
-		}
-
-		case APP_PKTQ_OUT_SWQ:
-		{
-			struct pipeline_params pp;
-			struct pipeline_type *ptype;
-			struct app_pktq_swq_params *swq;
-			uint32_t pktq_in_id;
-			int status;
-
-			swq = &app->swq_params[pktq_out->id];
-			p = app_swq_get_reader(app, swq, &pktq_in_id);
-			if (p == NULL)
-				return NULL;
-
-			ptype = app_pipeline_type_find(app, p->type);
-			if ((ptype == NULL) || (ptype->fe_ops->f_track == NULL))
-				return NULL;
-
-			app_pipeline_params_get(app, p, &pp);
-			status = ptype->fe_ops->f_track(&pp,
-				pktq_in_id,
-				&pktq_out_id);
-			if (status)
-				return NULL;
-
-			break;
-		}
-
-		case APP_PKTQ_OUT_TM:
-		{
-			struct pipeline_params pp;
-			struct pipeline_type *ptype;
-			struct app_pktq_tm_params *tm;
-			uint32_t pktq_in_id;
-			int status;
-
-			tm = &app->tm_params[pktq_out->id];
-			p = app_tm_get_reader(app, tm, &pktq_in_id);
-			if (p == NULL)
-				return NULL;
-
-			ptype = app_pipeline_type_find(app, p->type);
-			if ((ptype == NULL) || (ptype->fe_ops->f_track == NULL))
-				return NULL;
-
-			app_pipeline_params_get(app, p, &pp);
-			status = ptype->fe_ops->f_track(&pp,
-				pktq_in_id,
-				&pktq_out_id);
-			if (status)
-				return NULL;
-
-			break;
-		}
-
-		case APP_PKTQ_OUT_KNI:
-		{
-			struct pipeline_params pp;
-			struct pipeline_type *ptype;
-			struct app_pktq_kni_params *kni;
-			uint32_t pktq_in_id;
-			int status;
-
-			kni = &app->kni_params[pktq_out->id];
-			p = app_kni_get_reader(app, kni, &pktq_in_id);
-			if (p == NULL)
-				return NULL;
-
-			ptype = app_pipeline_type_find(app, p->type);
-			if ((ptype == NULL) || (ptype->fe_ops->f_track == NULL))
-				return NULL;
-
-			app_pipeline_params_get(app, p, &pp);
-			status = ptype->fe_ops->f_track(&pp,
-				pktq_in_id,
-				&pktq_out_id);
-			if (status)
-				return NULL;
-
-			break;
-		}
-
-		case APP_PKTQ_OUT_TAP:
-		case APP_PKTQ_OUT_SINK:
-		default:
-			return NULL;
-		}
-	}
-}
-
-int
-app_pipeline_track_default(struct pipeline_params *p,
-	uint32_t port_in,
-	uint32_t *port_out)
-{
-	/* Check input arguments */
-	if ((p == NULL) ||
-		(port_in >= p->n_ports_in) ||
-		(port_out == NULL))
-		return -1;
-
-	if (p->n_ports_out == 1) {
-		*port_out = 0;
-		return 0;
-	}
-
-	return -1;
-}
-
-int
-app_pipeline_ping(struct app_params *app,
-	uint32_t pipeline_id)
-{
-	struct app_pipeline_params *p;
-	struct pipeline_msg_req *req;
-	struct pipeline_msg_rsp *rsp;
-	int status = 0;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	APP_PARAM_FIND_BY_ID(app->pipeline_params, "PIPELINE", pipeline_id, p);
-	if (p == NULL)
-		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, MSG_TIMEOUT_DEFAULT);
-	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 app_pipeline_params *p;
-	struct pipeline_stats_msg_req *req;
-	struct pipeline_stats_port_in_msg_rsp *rsp;
-	int status = 0;
-
-	/* Check input arguments */
-	if ((app == NULL) ||
-		(stats == NULL))
-		return -1;
-
-	APP_PARAM_FIND_BY_ID(app->pipeline_params, "PIPELINE", pipeline_id, p);
-	if ((p == NULL) ||
-		(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, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	/* Check response */
-	status = rsp->status;
-	if (status == 0)
-		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 app_pipeline_params *p;
-	struct pipeline_stats_msg_req *req;
-	struct pipeline_stats_port_out_msg_rsp *rsp;
-	int status = 0;
-
-	/* Check input arguments */
-	if ((app == NULL) ||
-		(pipeline_id >= app->n_pipelines) ||
-		(stats == NULL))
-		return -1;
-
-	APP_PARAM_FIND_BY_ID(app->pipeline_params, "PIPELINE", pipeline_id, p);
-	if ((p == NULL) ||
-		(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, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	/* Check response */
-	status = rsp->status;
-	if (status == 0)
-		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 app_pipeline_params *p;
-	struct pipeline_stats_msg_req *req;
-	struct pipeline_stats_table_msg_rsp *rsp;
-	int status = 0;
-
-	/* Check input arguments */
-	if ((app == NULL) ||
-		(stats == NULL))
-		return -1;
-
-	APP_PARAM_FIND_BY_ID(app->pipeline_params, "PIPELINE", pipeline_id, p);
-	if (p == 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, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	/* Check response */
-	status = rsp->status;
-	if (status == 0)
-		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 app_pipeline_params *p;
-	struct pipeline_port_in_msg_req *req;
-	struct pipeline_msg_rsp *rsp;
-	int status = 0;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	APP_PARAM_FIND_BY_ID(app->pipeline_params, "PIPELINE", pipeline_id, p);
-	if ((p == NULL) ||
-		(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, MSG_TIMEOUT_DEFAULT);
-	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 app_pipeline_params *p;
-	struct pipeline_port_in_msg_req *req;
-	struct pipeline_msg_rsp *rsp;
-	int status = 0;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	APP_PARAM_FIND_BY_ID(app->pipeline_params, "PIPELINE", pipeline_id, p);
-	if ((p == NULL) ||
-		(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, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	/* Check response */
-	status = rsp->status;
-
-	/* Message buffer free */
-	app_msg_free(app, rsp);
-
-	return status;
-}
-
-int
-app_link_set_op(struct app_params *app,
-	uint32_t link_id,
-	uint32_t pipeline_id,
-	app_link_op op,
-	void *arg)
-{
-	struct app_pipeline_params *pp;
-	struct app_link_params *lp;
-	struct app_link_data *ld;
-	uint32_t ppos, lpos;
-
-	/* Check input arguments */
-	if ((app == NULL) ||
-		(op == NULL))
-		return -1;
-
-	APP_PARAM_FIND_BY_ID(app->link_params, "LINK", link_id, lp);
-	if (lp == NULL)
-		return -1;
-	lpos = lp - app->link_params;
-	ld = &app->link_data[lpos];
-
-	APP_PARAM_FIND_BY_ID(app->pipeline_params, "PIPELINE", pipeline_id, pp);
-	if (pp == NULL)
-		return -1;
-	ppos = pp - app->pipeline_params;
-
-	ld->f_link[ppos] = op;
-	ld->arg[ppos] = arg;
-
-	return 0;
-}
-
-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;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	APP_PARAM_FIND_BY_ID(app->link_params, "LINK", link_id, p);
-	if (p == NULL) {
-		APP_LOG(app, HIGH, "LINK%" PRIu32 " is not a valid link",
-			link_id);
-		return -1;
-	}
-
-	if (p->state) {
-		APP_LOG(app, HIGH, "%s is UP, please bring it DOWN first",
-			p->name);
-		return -1;
-	}
-
-	netmask = (~0U) << (32 - depth);
-	host = ip & netmask;
-	bcast = host | (~netmask);
-
-	if ((ip == 0) ||
-		(ip == UINT32_MAX) ||
-		(ip == host) ||
-		(ip == bcast)) {
-		APP_LOG(app, HIGH, "Illegal IP address");
-		return -1;
-	}
-
-	for (i = 0; i < app->n_links; i++) {
-		struct app_link_params *link = &app->link_params[i];
-
-		if (strcmp(p->name, link->name) == 0)
-			continue;
-
-		if (link->ip == ip) {
-			APP_LOG(app, HIGH,
-				"%s is already assigned this IP address",
-				link->name);
-			return -1;
-		}
-	}
-
-	if ((depth == 0) || (depth > 32)) {
-		APP_LOG(app, HIGH, "Illegal value for depth parameter "
-			"(%" PRIu32 ")",
-			depth);
-		return -1;
-	}
-
-	/* Save link parameters */
-	p->ip = ip;
-	p->depth = depth;
-
-	return 0;
-}
-
-int
-app_link_up(struct app_params *app,
-	uint32_t link_id)
-{
-	struct app_link_params *p;
-	struct app_link_data *d;
-	int i;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	APP_PARAM_FIND_BY_ID(app->link_params, "LINK", link_id, p);
-	if (p == NULL) {
-		APP_LOG(app, HIGH, "LINK%" PRIu32 " is not a valid link",
-			link_id);
-		return -1;
-	}
-
-	d = &app->link_data[p - app->link_params];
-
-	/* Check link state */
-	if (p->state) {
-		APP_LOG(app, HIGH, "%s is already UP", p->name);
-		return 0;
-	}
-
-	/* Check that IP address is valid */
-	if (p->ip == 0) {
-		APP_LOG(app, HIGH, "%s IP address is not set", p->name);
-		return 0;
-	}
-
-	app_link_up_internal(app, p);
-
-	/* Callbacks */
-	for (i = 0; i < APP_MAX_PIPELINES; i++)
-		if (d->f_link[i])
-			d->f_link[i](app, link_id, 1, d->arg[i]);
-
-	return 0;
-}
-
-int
-app_link_down(struct app_params *app,
-	uint32_t link_id)
-{
-	struct app_link_params *p;
-	struct app_link_data *d;
-	uint32_t i;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	APP_PARAM_FIND_BY_ID(app->link_params, "LINK", link_id, p);
-	if (p == NULL) {
-		APP_LOG(app, HIGH, "LINK%" PRIu32 " is not a valid link",
-			link_id);
-		return -1;
-	}
-
-	d = &app->link_data[p - app->link_params];
-
-	/* Check link state */
-	if (p->state == 0) {
-		APP_LOG(app, HIGH, "%s is already DOWN", p->name);
-		return 0;
-	}
-
-	app_link_down_internal(app, p);
-
-	/* Callbacks */
-	for (i = 0; i < APP_MAX_PIPELINES; i++)
-		if (d->f_link[i])
-			d->f_link[i](app, link_id, 0, d->arg[i]);
-
-	return 0;
-}
-
-/*
- * 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("Command failed\n");
-}
-
-static cmdline_parse_token_string_t cmd_ping_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_ping_result, p_string, "p");
-
-static cmdline_parse_token_num_t cmd_ping_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_ping_result, pipeline_id, UINT32);
-
-static cmdline_parse_token_string_t cmd_ping_ping_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_ping_result, ping_string, "ping");
-
-static cmdline_parse_inst_t cmd_ping = {
-	.f = cmd_ping_parsed,
-	.data = NULL,
-	.help_str = "Pipeline ping",
-	.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("Command failed\n");
-		return;
-	}
-
-	/* Display stats */
-	printf("Pipeline %" PRIu32 " - stats for input port %" PRIu32 ":\n"
-		"\tPkts in: %" PRIu64 "\n"
-		"\tPkts dropped by AH: %" PRIu64 "\n"
-		"\tPkts dropped by other: %" PRIu64 "\n",
-		params->pipeline_id,
-		params->port_in_id,
-		stats.stats.n_pkts_in,
-		stats.n_pkts_dropped_by_ah,
-		stats.stats.n_pkts_drop);
-}
-
-static cmdline_parse_token_string_t cmd_stats_port_in_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_stats_port_in_result, p_string,
-		"p");
-
-static cmdline_parse_token_num_t cmd_stats_port_in_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_stats_port_in_result, pipeline_id,
-		UINT32);
-
-static cmdline_parse_token_string_t cmd_stats_port_in_stats_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_stats_port_in_result, stats_string,
-		"stats");
-
-static cmdline_parse_token_string_t cmd_stats_port_in_port_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_stats_port_in_result, port_string,
-		"port");
-
-static 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);
-
-static cmdline_parse_inst_t cmd_stats_port_in = {
-	.f = cmd_stats_port_in_parsed,
-	.data = NULL,
-	.help_str = "Pipeline input port stats",
-	.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("Command failed\n");
-		return;
-	}
-
-	/* Display stats */
-	printf("Pipeline %" PRIu32 " - stats for output port %" PRIu32 ":\n"
-		"\tPkts in: %" PRIu64 "\n"
-		"\tPkts dropped by AH: %" PRIu64 "\n"
-		"\tPkts dropped by other: %" PRIu64 "\n",
-		params->pipeline_id,
-		params->port_out_id,
-		stats.stats.n_pkts_in,
-		stats.n_pkts_dropped_by_ah,
-		stats.stats.n_pkts_drop);
-}
-
-static cmdline_parse_token_string_t cmd_stats_port_out_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_stats_port_out_result, p_string,
-	"p");
-
-static cmdline_parse_token_num_t cmd_stats_port_out_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_stats_port_out_result, pipeline_id,
-		UINT32);
-
-static cmdline_parse_token_string_t cmd_stats_port_out_stats_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_stats_port_out_result, stats_string,
-		"stats");
-
-static cmdline_parse_token_string_t cmd_stats_port_out_port_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_stats_port_out_result, port_string,
-		"port");
-
-static cmdline_parse_token_string_t cmd_stats_port_out_out_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_stats_port_out_result, out_string,
-		"out");
-
-static 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);
-
-static cmdline_parse_inst_t cmd_stats_port_out = {
-	.f = cmd_stats_port_out_parsed,
-	.data = NULL,
-	.help_str = "Pipeline output port stats",
-	.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("Command failed\n");
-		return;
-	}
-
-	/* Display stats */
-	printf("Pipeline %" PRIu32 " - stats for table %" PRIu32 ":\n"
-		"\tPkts in: %" PRIu64 "\n"
-		"\tPkts in with lookup miss: %" PRIu64 "\n"
-		"\tPkts in with lookup hit dropped by AH: %" PRIu64 "\n"
-		"\tPkts in with lookup hit dropped by others: %" PRIu64 "\n"
-		"\tPkts in with lookup miss dropped by AH: %" PRIu64 "\n"
-		"\tPkts in with lookup miss dropped by others: %" PRIu64 "\n",
-		params->pipeline_id,
-		params->table_id,
-		stats.stats.n_pkts_in,
-		stats.stats.n_pkts_lookup_miss,
-		stats.n_pkts_dropped_by_lkp_hit_ah,
-		stats.n_pkts_dropped_lkp_hit,
-		stats.n_pkts_dropped_by_lkp_miss_ah,
-		stats.n_pkts_dropped_lkp_miss);
-}
-
-static cmdline_parse_token_string_t cmd_stats_table_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_stats_table_result, p_string,
-		"p");
-
-static cmdline_parse_token_num_t cmd_stats_table_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_stats_table_result, pipeline_id,
-		UINT32);
-
-static cmdline_parse_token_string_t cmd_stats_table_stats_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_stats_table_result, stats_string,
-		"stats");
-
-static cmdline_parse_token_string_t cmd_stats_table_table_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_stats_table_result, table_string,
-		"table");
-
-static cmdline_parse_token_num_t cmd_stats_table_table_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_stats_table_result, table_id, UINT32);
-
-static cmdline_parse_inst_t cmd_stats_table = {
-	.f = cmd_stats_table_parsed,
-	.data = NULL,
-	.help_str = "Pipeline table stats",
-	.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("Command failed\n");
-}
-
-static cmdline_parse_token_string_t cmd_port_in_enable_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_port_in_enable_result, p_string,
-		"p");
-
-static cmdline_parse_token_num_t cmd_port_in_enable_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_port_in_enable_result, pipeline_id,
-		UINT32);
-
-static cmdline_parse_token_string_t cmd_port_in_enable_port_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_port_in_enable_result, port_string,
-	"port");
-
-static cmdline_parse_token_string_t cmd_port_in_enable_in_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_port_in_enable_result, in_string,
-		"in");
-
-static 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);
-
-static cmdline_parse_token_string_t cmd_port_in_enable_enable_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_port_in_enable_result,
-		enable_string, "enable");
-
-static 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("Command failed\n");
-}
-
-static cmdline_parse_token_string_t cmd_port_in_disable_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_port_in_disable_result, p_string,
-		"p");
-
-static cmdline_parse_token_num_t cmd_port_in_disable_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_port_in_disable_result, pipeline_id,
-		UINT32);
-
-static cmdline_parse_token_string_t cmd_port_in_disable_port_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_port_in_disable_result, port_string,
-		"port");
-
-static cmdline_parse_token_string_t cmd_port_in_disable_in_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_port_in_disable_result, in_string,
-		"in");
-
-static 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);
-
-static cmdline_parse_token_string_t cmd_port_in_disable_disable_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_port_in_disable_result,
-		disable_string, "disable");
-
-static 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,
-	},
-};
-
-/*
- * 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 = (~0U) << (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;
-
-	if (strlen(p->pci_bdf))
-		printf("%s(%s): flags=<%s>\n",
-			p->name,
-			p->pci_bdf,
-			(p->state) ? "UP" : "DOWN");
-	else
-		printf("%s: flags=<%s>\n",
-			p->name,
-			(p->state) ? "UP" : "DOWN");
-
-	if (p->ip)
-		printf("\tinet %" PRIu32 ".%" PRIu32
-			".%" PRIu32 ".%" PRIu32
-			" netmask %" PRIu32 ".%" PRIu32
-			".%" PRIu32 ".%" PRIu32 " "
-			"broadcast %" PRIu32 ".%" PRIu32
-			".%" PRIu32 ".%" PRIu32 "\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 %02" PRIx32 ":%02" PRIx32 ":%02" PRIx32
-		":%02" PRIx32 ":%02" PRIx32 ":%02" PRIx32 "\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 errors %" PRIu64
-		"  missed %" PRIu64
-		"  no-mbuf %" PRIu64
-		"\n",
-		stats.ierrors,
-		stats.imissed,
-		stats.rx_nombuf);
-
-	printf("\tTX packets %" PRIu64
-		"  bytes %" PRIu64 "\n",
-		stats.opackets,
-		stats.obytes);
-
-	printf("\tTX errors %" PRIu64
-		"\n",
-		stats.oerrors);
-
-	printf("\n");
-}
-
-/*
- * link
- *
- * link config:
- *    link <linkid> config <ipaddr> <depth>
- *
- * link up:
- *    link <linkid> up
- *
- * link down:
- *    link <linkid> down
- *
- * link ls:
- *    link ls
- */
-
-struct cmd_link_result {
-	cmdline_fixed_string_t link_string;
-	cmdline_multi_string_t multi_string;
-};
-
-static void
-cmd_link_parsed(
-	void *parsed_result,
-	__attribute__((unused)) struct cmdline *cl,
-	 void *data)
-{
-	struct cmd_link_result *params = parsed_result;
-	struct app_params *app = data;
-
-	char *tokens[16];
-	uint32_t n_tokens = RTE_DIM(tokens);
-	int status;
-
-	uint32_t link_id;
-
-	status = parse_tokenize_string(params->multi_string, tokens, &n_tokens);
-	if (status != 0) {
-		printf(CMD_MSG_TOO_MANY_ARGS, "link");
-		return;
-	}
-
-	/* link ls */
-	if ((n_tokens == 1) && (strcmp(tokens[0], "ls") == 0)) {
-		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);
-		}
-		return;
-	} /* link ls */
-
-	if (n_tokens < 2) {
-		printf(CMD_MSG_MISMATCH_ARGS, "link");
-		return;
-	}
-
-	if (parser_read_uint32(&link_id, tokens[0])) {
-		printf(CMD_MSG_INVALID_ARG, "linkid");
-		return;
-	}
-
-	/* link config */
-	if (strcmp(tokens[1], "config") == 0) {
-		struct in_addr ipaddr_ipv4;
-		uint32_t depth;
-
-		if (n_tokens != 4) {
-			printf(CMD_MSG_MISMATCH_ARGS, "link config");
-			return;
-		}
-
-		if (parse_ipv4_addr(tokens[2], &ipaddr_ipv4)) {
-			printf(CMD_MSG_INVALID_ARG, "ipaddr");
-			return;
-		}
-
-		if (parser_read_uint32(&depth, tokens[3])) {
-			printf(CMD_MSG_INVALID_ARG, "depth");
-			return;
-		}
-
-		status = app_link_config(app,
-			link_id,
-			rte_be_to_cpu_32(ipaddr_ipv4.s_addr),
-			depth);
-		if (status)
-			printf(CMD_MSG_FAIL, "link config");
-
-		return;
-	} /* link config */
-
-	/* link up */
-	if (strcmp(tokens[1], "up") == 0) {
-		if (n_tokens != 2) {
-			printf(CMD_MSG_MISMATCH_ARGS, "link up");
-			return;
-		}
-
-		status = app_link_up(app, link_id);
-		if (status)
-			printf(CMD_MSG_FAIL, "link up");
-
-		return;
-	} /* link up */
-
-	/* link down */
-	if (strcmp(tokens[1], "down") == 0) {
-		if (n_tokens != 2) {
-			printf(CMD_MSG_MISMATCH_ARGS, "link down");
-			return;
-		}
-
-		status = app_link_down(app, link_id);
-		if (status)
-			printf(CMD_MSG_FAIL, "link down");
-
-		return;
-	} /* link down */
-
-	printf(CMD_MSG_MISMATCH_ARGS, "link");
-}
-
-static cmdline_parse_token_string_t cmd_link_link_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_link_result, link_string, "link");
-
-static cmdline_parse_token_string_t cmd_link_multi_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_link_result, multi_string,
-	TOKEN_STRING_MULTI);
-
-static cmdline_parse_inst_t cmd_link = {
-	.f = cmd_link_parsed,
-	.data = NULL,
-	.help_str = "link config / up / down / ls",
-	.tokens = {
-		(void *) &cmd_link_link_string,
-		(void *) &cmd_link_multi_string,
-		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,
-	},
-};
-
-/*
- * run
- *
- *    run <file>
- *    run <file> [<count> [<interval>]]
-	 <count> default is 1
- *       <interval> is measured in milliseconds, default is 1 second
- */
-
-static void
-app_run_file(
-	cmdline_parse_ctx_t *ctx,
-	const char *file_name)
-{
-	struct cmdline *file_cl;
-	int fd;
-
-	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_result {
-	cmdline_fixed_string_t run_string;
-	cmdline_multi_string_t multi_string;
-};
-
-static void
-cmd_run_parsed(
-	void *parsed_result,
-	struct cmdline *cl,
-	__attribute__((unused)) void *data)
-{
-	struct cmd_run_result *params = parsed_result;
-
-	char *tokens[16];
-	uint32_t n_tokens = RTE_DIM(tokens);
-	int status;
-
-	char *file_name;
-	uint32_t count, interval, i;
-
-	status = parse_tokenize_string(params->multi_string, tokens, &n_tokens);
-	if (status) {
-		printf(CMD_MSG_TOO_MANY_ARGS, "run");
-		return;
-	}
-
-	switch (n_tokens) {
-	case 0:
-		printf(CMD_MSG_NOT_ENOUGH_ARGS, "run");
-		return;
-
-	case 1:
-		file_name = tokens[0];
-		count = 1;
-		interval = 1000;
-		break;
-
-	case 2:
-		file_name = tokens[0];
-
-		if (parser_read_uint32(&count, tokens[1]) ||
-			(count == 0)) {
-			printf(CMD_MSG_INVALID_ARG, "count");
-			return;
-		}
-
-		interval = 1000;
-		break;
-
-	case 3:
-		file_name = tokens[0];
-
-		if (parser_read_uint32(&count, tokens[1]) ||
-			(count == 0)) {
-			printf(CMD_MSG_INVALID_ARG, "count");
-			return;
-		}
-
-		if (parser_read_uint32(&interval, tokens[2]) ||
-			(interval == 0)) {
-			printf(CMD_MSG_INVALID_ARG, "interval");
-			return;
-		}
-		break;
-
-	default:
-		printf(CMD_MSG_MISMATCH_ARGS, "run");
-		return;
-	}
-
-	for (i = 0; i < count; i++) {
-		app_run_file(cl->ctx, file_name);
-		if (interval)
-			usleep(interval * 1000);
-	}
-}
-
-static cmdline_parse_token_string_t cmd_run_run_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_run_result, run_string, "run");
-
-static cmdline_parse_token_string_t cmd_run_multi_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_run_result, multi_string,
-	TOKEN_STRING_MULTI);
-
-
-static 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_multi_string,
-		NULL,
-	},
-};
-
-static cmdline_parse_ctx_t pipeline_common_cmds[] = {
-	(cmdline_parse_inst_t *) &cmd_quit,
-	(cmdline_parse_inst_t *) &cmd_run,
-	(cmdline_parse_inst_t *) &cmd_link,
-	(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,
-	NULL,
-};
-
-int
-app_pipeline_common_cmd_push(struct app_params *app)
-{
-	uint32_t n_cmds, i;
-
-	/* Check for available slots in the application commands array */
-	n_cmds = RTE_DIM(pipeline_common_cmds) - 1;
-	if (n_cmds > APP_MAX_CMDS - app->n_cmds)
-		return -ENOMEM;
-
-	/* Push pipeline commands into the application */
-	memcpy(&app->cmds[app->n_cmds],
-		pipeline_common_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;
-}
diff --git a/examples/ip_pipeline/pipeline/pipeline_common_fe.h b/examples/ip_pipeline/pipeline/pipeline_common_fe.h
deleted file mode 100644
index 7227544..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_common_fe.h
+++ /dev/null
@@ -1,231 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#ifndef __INCLUDE_PIPELINE_COMMON_FE_H__
-#define __INCLUDE_PIPELINE_COMMON_FE_H__
-
-#include <rte_common.h>
-#include <rte_cycles.h>
-#include <rte_malloc.h>
-#include <cmdline_parse.h>
-
-#include "pipeline_common_be.h"
-#include "pipeline.h"
-#include "app.h"
-
-#ifndef MSG_TIMEOUT_DEFAULT
-#define MSG_TIMEOUT_DEFAULT                      1000
-#endif
-
-static inline struct app_pipeline_data *
-app_pipeline_data(struct app_params *app, uint32_t id)
-{
-	struct app_pipeline_params *params;
-
-	APP_PARAM_FIND_BY_ID(app->pipeline_params, "PIPELINE", id, params);
-	if (params == NULL)
-		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 pipeline_type *ptype)
-{
-	struct app_pipeline_data *pipeline_data;
-
-	pipeline_data = app_pipeline_data(app, id);
-	if (pipeline_data == NULL)
-		return NULL;
-
-	if (strcmp(pipeline_data->ptype->name, ptype->name) != 0)
-		return NULL;
-
-	if (pipeline_data->enabled == 0)
-		return NULL;
-
-	return pipeline_data->fe;
-}
-
-static inline struct rte_ring *
-app_pipeline_msgq_in_get(struct app_params *app,
-	uint32_t pipeline_id)
-{
-	struct app_msgq_params *p;
-
-	APP_PARAM_FIND_BY_ID(app->msgq_params,
-		"MSGQ-REQ-PIPELINE",
-		pipeline_id,
-		p);
-	if (p == NULL)
-		return NULL;
-
-	return app->msgq[p - app->msgq_params];
-}
-
-static inline struct rte_ring *
-app_pipeline_msgq_out_get(struct app_params *app,
-	uint32_t pipeline_id)
-{
-	struct app_msgq_params *p;
-
-	APP_PARAM_FIND_BY_ID(app->msgq_params,
-		"MSGQ-RSP-PIPELINE",
-		pipeline_id,
-		p);
-	if (p == NULL)
-		return NULL;
-
-	return app->msgq[p - app->msgq_params];
-}
-
-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;
-}
-
-struct app_link_params *
-app_pipeline_track_pktq_out_to_link(struct app_params *app,
-	uint32_t pipeline_id,
-	uint32_t pktq_out_id);
-
-int
-app_pipeline_track_default(struct pipeline_params *params,
-	uint32_t port_in,
-	uint32_t *port_out);
-
-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_set_op(struct app_params *app,
-	uint32_t link_id,
-	uint32_t pipeline_id,
-	app_link_op op,
-	void *arg);
-
-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);
-
-int
-app_pipeline_common_cmd_push(struct app_params *app);
-
-#define CMD_MSG_OUT_OF_MEMORY	"Not enough memory\n"
-#define CMD_MSG_NOT_ENOUGH_ARGS	"Not enough arguments for command \"%s\"\n"
-#define CMD_MSG_TOO_MANY_ARGS	"Too many arguments for command \"%s\"\n"
-#define CMD_MSG_MISMATCH_ARGS	"Incorrect set of arguments for command \"%s\"\n"
-#define CMD_MSG_INVALID_ARG	"Invalid value for argument \"%s\"\n"
-#define CMD_MSG_ARG_NOT_FOUND	"Syntax error: \"%s\" not found\n"
-#define CMD_MSG_FILE_ERR	"Error in file \"%s\" at line %u\n"
-#define CMD_MSG_FAIL		"Command \"%s\" failed\n"
-
-#endif
diff --git a/examples/ip_pipeline/pipeline/pipeline_firewall.c b/examples/ip_pipeline/pipeline/pipeline_firewall.c
deleted file mode 100644
index 0cae9d7..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_firewall.c
+++ /dev/null
@@ -1,1421 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-#include <errno.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/queue.h>
-#include <netinet/in.h>
-
-#include <rte_common.h>
-#include <rte_hexdump.h>
-#include <rte_malloc.h>
-#include <cmdline_rdline.h>
-#include <cmdline_parse.h>
-#include <cmdline_parse_num.h>
-#include <cmdline_parse_string.h>
-
-#include "app.h"
-#include "pipeline_common_fe.h"
-#include "pipeline_firewall.h"
-#include "parser.h"
-
-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;
-};
-
-static void
-print_firewall_ipv4_rule(struct app_pipeline_firewall_rule *rule)
-{
-	printf("Prio = %" PRId32 " (SA = %" PRIu32 ".%" PRIu32
-		".%" PRIu32 ".%" PRIu32 "/%" PRIu32 ", "
-		"DA = %" PRIu32 ".%" PRIu32
-		".%"PRIu32 ".%" PRIu32 "/%" PRIu32 ", "
-		"SP = %" PRIu32 "-%" PRIu32 ", "
-		"DP = %" PRIu32 "-%" PRIu32 ", "
-		"Proto = %" PRIu32 " / 0x%" PRIx32 ") => "
-		"Port = %" PRIu32 " (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);
-}
-
-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;
-
-	TAILQ_FOREACH(r, &p->rules, node)
-		if (memcmp(key,
-			&r->key,
-			sizeof(struct pipeline_firewall_key)) == 0)
-			return r;
-
-	return NULL;
-}
-
-static int
-app_pipeline_firewall_ls(
-	struct app_params *app,
-	uint32_t pipeline_id)
-{
-	struct app_pipeline_firewall *p;
-	struct app_pipeline_firewall_rule *rule;
-	uint32_t n_rules;
-	int priority;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_firewall);
-	if (p == NULL)
-		return -1;
-
-	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 %" PRIu32 " (entry ptr = %p)\n",
-			p->default_rule_port_id,
-			p->default_rule_entry_ptr);
-	else
-		printf("Default rule: DROP\n");
-
-	printf("\n");
-
-	return 0;
-}
-
-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;
-
-	/* Initialization */
-	p->n_ports_in = params->n_ports_in;
-	p->n_ports_out = params->n_ports_out;
-
-	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;
-
-	return (void *) p;
-}
-
-static int
-app_pipeline_firewall_free(void *pipeline)
-{
-	struct app_pipeline_firewall *p = pipeline;
-
-	/* Check input arguments */
-	if (p == NULL)
-		return -1;
-
-	/* Free resources */
-	while (!TAILQ_EMPTY(&p->rules)) {
-		struct app_pipeline_firewall_rule *rule;
-
-		rule = TAILQ_FIRST(&p->rules);
-		TAILQ_REMOVE(&p->rules, rule, node);
-		rte_free(rule);
-	}
-
-	rte_free(p);
-	return 0;
-}
-
-static int
-app_pipeline_firewall_key_check_and_normalize(struct pipeline_firewall_key *key)
-{
-	switch (key->type) {
-	case PIPELINE_FIREWALL_IPV4_5TUPLE:
-	{
-		uint32_t src_ip_depth = key->key.ipv4_5tuple.src_ip_mask;
-		uint32_t dst_ip_depth = key->key.ipv4_5tuple.dst_ip_mask;
-		uint16_t src_port_from = key->key.ipv4_5tuple.src_port_from;
-		uint16_t src_port_to = key->key.ipv4_5tuple.src_port_to;
-		uint16_t dst_port_from = key->key.ipv4_5tuple.dst_port_from;
-		uint16_t dst_port_to = key->key.ipv4_5tuple.dst_port_to;
-
-		uint32_t src_ip_netmask = 0;
-		uint32_t dst_ip_netmask = 0;
-
-		if ((src_ip_depth > 32) ||
-			(dst_ip_depth > 32) ||
-			(src_port_from > src_port_to) ||
-			(dst_port_from > dst_port_to))
-			return -1;
-
-		if (src_ip_depth)
-			src_ip_netmask = (~0U) << (32 - src_ip_depth);
-
-		if (dst_ip_depth)
-			dst_ip_netmask = ((~0U) << (32 - dst_ip_depth));
-
-		key->key.ipv4_5tuple.src_ip &= src_ip_netmask;
-		key->key.ipv4_5tuple.dst_ip &= dst_ip_netmask;
-
-		return 0;
-	}
-
-	default:
-		return -1;
-	}
-}
-
-int
-app_pipeline_firewall_load_file(char *filename,
-	struct pipeline_firewall_key *keys,
-	uint32_t *priorities,
-	uint32_t *port_ids,
-	uint32_t *n_keys,
-	uint32_t *line)
-{
-	FILE *f = NULL;
-	char file_buf[1024];
-	uint32_t i, l;
-
-	/* Check input arguments */
-	if ((filename == NULL) ||
-		(keys == NULL) ||
-		(priorities == NULL) ||
-		(port_ids == NULL) ||
-		(n_keys == NULL) ||
-		(*n_keys == 0) ||
-		(line == NULL)) {
-		if (line)
-			*line = 0;
-		return -1;
-		}
-
-	/* Open input file */
-	f = fopen(filename, "r");
-	if (f == NULL) {
-		*line = 0;
-		return -1;
-	}
-
-	/* Read file */
-	for (i = 0, l = 1; i < *n_keys; l++) {
-		char *tokens[32];
-		uint32_t n_tokens = RTE_DIM(tokens);
-
-		uint32_t priority = 0;
-		struct in_addr sipaddr;
-		uint32_t sipdepth = 0;
-		struct in_addr dipaddr;
-		uint32_t dipdepth = 0;
-		uint16_t sport0 = 0;
-		uint16_t sport1 = 0;
-		uint16_t dport0 = 0;
-		uint16_t dport1 = 0;
-		uint8_t proto = 0;
-		uint8_t protomask = 0;
-		uint32_t port_id = 0;
-
-		int status;
-
-		if (fgets(file_buf, sizeof(file_buf), f) == NULL)
-			break;
-
-		status = parse_tokenize_string(file_buf, tokens, &n_tokens);
-		if (status)
-			goto error1;
-
-		if ((n_tokens == 0) || (tokens[0][0] == '#'))
-			continue;
-
-		if ((n_tokens != 15) ||
-			strcmp(tokens[0], "priority") ||
-			parser_read_uint32(&priority, tokens[1]) ||
-			strcmp(tokens[2], "ipv4") ||
-			parse_ipv4_addr(tokens[3], &sipaddr) ||
-			parser_read_uint32(&sipdepth, tokens[4]) ||
-			parse_ipv4_addr(tokens[5], &dipaddr) ||
-			parser_read_uint32(&dipdepth, tokens[6]) ||
-			parser_read_uint16(&sport0, tokens[7]) ||
-			parser_read_uint16(&sport1, tokens[8]) ||
-			parser_read_uint16(&dport0, tokens[9]) ||
-			parser_read_uint16(&dport1, tokens[10]) ||
-			parser_read_uint8(&proto, tokens[11]) ||
-			parser_read_uint8_hex(&protomask, tokens[12]) ||
-			strcmp(tokens[13], "port") ||
-			parser_read_uint32(&port_id, tokens[14]))
-			goto error1;
-
-		keys[i].type = PIPELINE_FIREWALL_IPV4_5TUPLE;
-		keys[i].key.ipv4_5tuple.src_ip =
-			rte_be_to_cpu_32(sipaddr.s_addr);
-		keys[i].key.ipv4_5tuple.src_ip_mask = sipdepth;
-		keys[i].key.ipv4_5tuple.dst_ip =
-			rte_be_to_cpu_32(dipaddr.s_addr);
-		keys[i].key.ipv4_5tuple.dst_ip_mask = dipdepth;
-		keys[i].key.ipv4_5tuple.src_port_from = sport0;
-		keys[i].key.ipv4_5tuple.src_port_to = sport1;
-		keys[i].key.ipv4_5tuple.dst_port_from = dport0;
-		keys[i].key.ipv4_5tuple.dst_port_to = dport1;
-		keys[i].key.ipv4_5tuple.proto = proto;
-		keys[i].key.ipv4_5tuple.proto_mask = protomask;
-
-		port_ids[i] = port_id;
-		priorities[i] = priority;
-
-		if (app_pipeline_firewall_key_check_and_normalize(&keys[i]))
-			goto error1;
-
-		i++;
-	}
-
-	/* Close file */
-	*n_keys = i;
-	fclose(f);
-	return 0;
-
-error1:
-	*line = l;
-	fclose(f);
-	return -1;
-}
-
-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_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;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_firewall);
-	if (p == NULL)
-		return -1;
-
-	if (port_id >= p->n_ports_out)
-		return -1;
-
-	if (app_pipeline_firewall_key_check_and_normalize(key) != 0)
-		return -1;
-
-	/* 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;
-	}
-
-	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_DEFAULT);
-	if (rsp == NULL) {
-		if (new_rule)
-			rte_free(rule);
-		return -1;
-	}
-
-	/* Read response and write rule */
-	if (rsp->status ||
-		(rsp->entry_ptr == NULL) ||
-		((new_rule == 0) && (rsp->key_found == 0)) ||
-		((new_rule == 1) && (rsp->key_found == 1))) {
-		app_msg_free(app, rsp);
-		if (new_rule)
-			rte_free(rule);
-		return -1;
-	}
-
-	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;
-}
-
-int
-app_pipeline_firewall_delete_rule(struct app_params *app,
-	uint32_t pipeline_id,
-	struct pipeline_firewall_key *key)
-{
-	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;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_firewall);
-	if (p == NULL)
-		return -1;
-
-	if (app_pipeline_firewall_key_check_and_normalize(key) != 0)
-		return -1;
-
-	/* 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_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	/* Read response */
-	if (rsp->status || !rsp->key_found) {
-		app_msg_free(app, rsp);
-		return -1;
-	}
-
-	/* Remove rule */
-	TAILQ_REMOVE(&p->rules, rule, node);
-	p->n_rules--;
-	rte_free(rule);
-
-	/* Free response */
-	app_msg_free(app, rsp);
-
-	return 0;
-}
-
-int
-app_pipeline_firewall_add_bulk(struct app_params *app,
-		uint32_t pipeline_id,
-		struct pipeline_firewall_key *keys,
-		uint32_t n_keys,
-		uint32_t *priorities,
-		uint32_t *port_ids)
-{
-	struct app_pipeline_firewall *p;
-	struct pipeline_firewall_add_bulk_msg_req *req;
-	struct pipeline_firewall_add_bulk_msg_rsp *rsp;
-
-	struct app_pipeline_firewall_rule **rules;
-	int *new_rules;
-
-	int *keys_found;
-	void **entries_ptr;
-
-	uint32_t i;
-	int status = 0;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_firewall);
-	if (p == NULL)
-		return -1;
-
-	rules = rte_malloc(NULL,
-		n_keys * sizeof(struct app_pipeline_firewall_rule *),
-		RTE_CACHE_LINE_SIZE);
-	if (rules == NULL)
-		return -1;
-
-	new_rules = rte_malloc(NULL,
-		n_keys * sizeof(int),
-		RTE_CACHE_LINE_SIZE);
-	if (new_rules == NULL) {
-		rte_free(rules);
-		return -1;
-	}
-
-	/* check data integrity and add to rule list */
-	for (i = 0; i < n_keys; i++) {
-		if (port_ids[i]  >= p->n_ports_out) {
-			rte_free(rules);
-			rte_free(new_rules);
-			return -1;
-		}
-
-		if (app_pipeline_firewall_key_check_and_normalize(&keys[i]) != 0) {
-			rte_free(rules);
-			rte_free(new_rules);
-			return -1;
-		}
-
-		rules[i] = app_pipeline_firewall_rule_find(p, &keys[i]);
-		new_rules[i] = (rules[i] == NULL);
-		if (rules[i] == NULL) {
-			rules[i] = rte_malloc(NULL,
-				sizeof(*rules[i]),
-				RTE_CACHE_LINE_SIZE);
-
-			if (rules[i] == NULL) {
-				uint32_t j;
-
-				for (j = 0; j <= i; j++)
-					if (new_rules[j])
-						rte_free(rules[j]);
-
-				rte_free(rules);
-				rte_free(new_rules);
-				return -1;
-			}
-		}
-	}
-
-	keys_found = rte_malloc(NULL,
-		n_keys * sizeof(int),
-		RTE_CACHE_LINE_SIZE);
-	if (keys_found == NULL) {
-		uint32_t j;
-
-		for (j = 0; j < n_keys; j++)
-			if (new_rules[j])
-				rte_free(rules[j]);
-
-		rte_free(rules);
-		rte_free(new_rules);
-		return -1;
-	}
-
-	entries_ptr = rte_malloc(NULL,
-		n_keys * sizeof(struct rte_pipeline_table_entry *),
-		RTE_CACHE_LINE_SIZE);
-	if (entries_ptr == NULL) {
-		uint32_t j;
-
-		for (j = 0; j < n_keys; j++)
-			if (new_rules[j])
-				rte_free(rules[j]);
-
-		rte_free(rules);
-		rte_free(new_rules);
-		rte_free(keys_found);
-		return -1;
-	}
-	for (i = 0; i < n_keys; i++) {
-		entries_ptr[i] = rte_malloc(NULL,
-			sizeof(struct rte_pipeline_table_entry),
-			RTE_CACHE_LINE_SIZE);
-
-		if (entries_ptr[i] == NULL) {
-			uint32_t j;
-
-			for (j = 0; j < n_keys; j++)
-				if (new_rules[j])
-					rte_free(rules[j]);
-
-			for (j = 0; j <= i; j++)
-				rte_free(entries_ptr[j]);
-
-			rte_free(rules);
-			rte_free(new_rules);
-			rte_free(keys_found);
-			rte_free(entries_ptr);
-			return -1;
-		}
-	}
-
-	/* Allocate and write request */
-	req = app_msg_alloc(app);
-	if (req == NULL) {
-		uint32_t j;
-
-		for (j = 0; j < n_keys; j++)
-			if (new_rules[j])
-				rte_free(rules[j]);
-
-		for (j = 0; j < n_keys; j++)
-			rte_free(entries_ptr[j]);
-
-		rte_free(rules);
-		rte_free(new_rules);
-		rte_free(keys_found);
-		rte_free(entries_ptr);
-		return -1;
-	}
-
-	req->type = PIPELINE_MSG_REQ_CUSTOM;
-	req->subtype = PIPELINE_FIREWALL_MSG_REQ_ADD_BULK;
-
-	req->keys = keys;
-	req->n_keys = n_keys;
-	req->port_ids = port_ids;
-	req->priorities = priorities;
-	req->keys_found = keys_found;
-	req->entries_ptr = entries_ptr;
-
-	/* Send request and wait for response */
-	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL) {
-		uint32_t j;
-
-		for (j = 0; j < n_keys; j++)
-			if (new_rules[j])
-				rte_free(rules[j]);
-
-		for (j = 0; j < n_keys; j++)
-			rte_free(entries_ptr[j]);
-
-		rte_free(rules);
-		rte_free(new_rules);
-		rte_free(keys_found);
-		rte_free(entries_ptr);
-		return -1;
-	}
-
-	if (rsp->status) {
-		for (i = 0; i < n_keys; i++)
-			if (new_rules[i])
-				rte_free(rules[i]);
-
-		for (i = 0; i < n_keys; i++)
-			rte_free(entries_ptr[i]);
-
-		status = -1;
-		goto cleanup;
-	}
-
-	for (i = 0; i < n_keys; i++) {
-		if (entries_ptr[i] == NULL ||
-			((new_rules[i] == 0) && (keys_found[i] == 0)) ||
-			((new_rules[i] == 1) && (keys_found[i] == 1))) {
-			for (i = 0; i < n_keys; i++)
-				if (new_rules[i])
-					rte_free(rules[i]);
-
-			for (i = 0; i < n_keys; i++)
-				rte_free(entries_ptr[i]);
-
-			status = -1;
-			goto cleanup;
-		}
-	}
-
-	for (i = 0; i < n_keys; i++) {
-		memcpy(&rules[i]->key, &keys[i], sizeof(keys[i]));
-		rules[i]->priority = priorities[i];
-		rules[i]->port_id = port_ids[i];
-		rules[i]->entry_ptr = entries_ptr[i];
-
-		/* Commit rule */
-		if (new_rules[i]) {
-			TAILQ_INSERT_TAIL(&p->rules, rules[i], node);
-			p->n_rules++;
-		}
-
-		print_firewall_ipv4_rule(rules[i]);
-	}
-
-cleanup:
-	app_msg_free(app, rsp);
-	rte_free(rules);
-	rte_free(new_rules);
-	rte_free(keys_found);
-	rte_free(entries_ptr);
-
-	return status;
-}
-
-int
-app_pipeline_firewall_delete_bulk(struct app_params *app,
-	uint32_t pipeline_id,
-	struct pipeline_firewall_key *keys,
-	uint32_t n_keys)
-{
-	struct app_pipeline_firewall *p;
-	struct pipeline_firewall_del_bulk_msg_req *req;
-	struct pipeline_firewall_del_bulk_msg_rsp *rsp;
-
-	struct app_pipeline_firewall_rule **rules;
-	int *keys_found;
-
-	uint32_t i;
-	int status = 0;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_firewall);
-	if (p == NULL)
-		return -1;
-
-	rules = rte_malloc(NULL,
-		n_keys * sizeof(struct app_pipeline_firewall_rule *),
-		RTE_CACHE_LINE_SIZE);
-	if (rules == NULL)
-		return -1;
-
-	for (i = 0; i < n_keys; i++) {
-		if (app_pipeline_firewall_key_check_and_normalize(&keys[i]) != 0) {
-			return -1;
-		}
-
-		rules[i] = app_pipeline_firewall_rule_find(p, &keys[i]);
-	}
-
-	keys_found = rte_malloc(NULL,
-		n_keys * sizeof(int),
-		RTE_CACHE_LINE_SIZE);
-	if (keys_found == NULL) {
-		rte_free(rules);
-		return -1;
-	}
-
-	/* Allocate and write request */
-	req = app_msg_alloc(app);
-	if (req == NULL) {
-		rte_free(rules);
-		rte_free(keys_found);
-		return -1;
-	}
-
-	req->type = PIPELINE_MSG_REQ_CUSTOM;
-	req->subtype = PIPELINE_FIREWALL_MSG_REQ_DEL_BULK;
-
-	req->keys = keys;
-	req->n_keys = n_keys;
-	req->keys_found = keys_found;
-
-	/* Send request and wait for response */
-	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL) {
-		rte_free(rules);
-		rte_free(keys_found);
-		return -1;
-	}
-
-	if (rsp->status) {
-		status = -1;
-		goto cleanup;
-	}
-
-	for (i = 0; i < n_keys; i++) {
-		if (keys_found[i] == 0) {
-			status = -1;
-			goto cleanup;
-		}
-	}
-
-	for (i = 0; i < n_keys; i++) {
-		TAILQ_REMOVE(&p->rules, rules[i], node);
-		p->n_rules--;
-		rte_free(rules[i]);
-	}
-
-cleanup:
-	app_msg_free(app, rsp);
-	rte_free(rules);
-	rte_free(keys_found);
-
-	return status;
-}
-
-int
-app_pipeline_firewall_add_default_rule(struct app_params *app,
-	uint32_t pipeline_id,
-	uint32_t port_id)
-{
-	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;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_firewall);
-	if (p == NULL)
-		return -1;
-
-	if (port_id >= p->n_ports_out)
-		return -1;
-
-	/* 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_DEFAULT);
-	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_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;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_firewall);
-	if (p == NULL)
-		return -1;
-
-	/* 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_DEFAULT);
-	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);
-
-	return 0;
-}
-
-/*
- * firewall
- *
- * firewall add:
- *    p <pipelineid> firewall add priority <priority>
- *       ipv4 <sipaddr> <sipdepth> <dipaddr> <dipdepth>
- *       <sport0> <sport1> <dport0> <dport1> <proto> <protomask>
- *       port <portid>
- *       Note: <protomask> is a hex value
- *
- *    p <pipelineid> firewall add bulk <file>
- *
- * firewall add default:
- *    p <pipelineid> firewall add default <port ID>
- *
- * firewall del:
- *    p <pipelineid> firewall del
- *       ipv4 <sipaddr> <sipdepth> <dipaddr> <dipdepth>
- *       <sport0> <sport1> <dport0> <dport1> <proto> <protomask>
- *
- *    p <pipelineid> firewall del bulk <file>
- *
- * firewall del default:
- *    p <pipelineid> firewall del default
- *
- * firewall ls:
- *    p <pipelineid> firewall ls
- */
-
-struct cmd_firewall_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t firewall_string;
-	cmdline_multi_string_t multi_string;
-};
-
-static void cmd_firewall_parsed(void *parsed_result,
-	__attribute__((unused))  struct cmdline *cl,
-	void *data)
-{
-	struct cmd_firewall_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
-
-	char *tokens[17];
-	uint32_t n_tokens = RTE_DIM(tokens);
-
-	status = parse_tokenize_string(params->multi_string, tokens, &n_tokens);
-	if (status) {
-		printf(CMD_MSG_TOO_MANY_ARGS, "firewall");
-		return;
-	}
-
-	/* firewall add */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "add") == 0) &&
-		(strcmp(tokens[1], "priority") == 0)) {
-		struct pipeline_firewall_key key;
-		uint32_t priority;
-		struct in_addr sipaddr;
-		uint32_t sipdepth;
-		struct in_addr dipaddr;
-		uint32_t dipdepth;
-		uint16_t sport0;
-		uint16_t sport1;
-		uint16_t dport0;
-		uint16_t dport1;
-		uint8_t proto;
-		uint8_t protomask;
-		uint32_t port_id;
-
-		memset(&key, 0, sizeof(key));
-
-		if (n_tokens != 16) {
-			printf(CMD_MSG_MISMATCH_ARGS, "firewall add");
-			return;
-		}
-
-		if (parser_read_uint32(&priority, tokens[2])) {
-			printf(CMD_MSG_INVALID_ARG, "priority");
-			return;
-		}
-
-		if (strcmp(tokens[3], "ipv4")) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "ipv4");
-			return;
-		}
-
-		if (parse_ipv4_addr(tokens[4], &sipaddr)) {
-			printf(CMD_MSG_INVALID_ARG, "sipaddr");
-			return;
-		}
-
-		if (parser_read_uint32(&sipdepth, tokens[5])) {
-			printf(CMD_MSG_INVALID_ARG, "sipdepth");
-			return;
-		}
-
-		if (parse_ipv4_addr(tokens[6], &dipaddr)) {
-			printf(CMD_MSG_INVALID_ARG, "dipaddr");
-			return;
-		}
-
-		if (parser_read_uint32(&dipdepth, tokens[7])) {
-			printf(CMD_MSG_INVALID_ARG, "dipdepth");
-			return;
-		}
-
-		if (parser_read_uint16(&sport0, tokens[8])) {
-			printf(CMD_MSG_INVALID_ARG, "sport0");
-			return;
-		}
-
-		if (parser_read_uint16(&sport1, tokens[9])) {
-			printf(CMD_MSG_INVALID_ARG, "sport1");
-			return;
-		}
-
-		if (parser_read_uint16(&dport0, tokens[10])) {
-			printf(CMD_MSG_INVALID_ARG, "dport0");
-			return;
-		}
-
-		if (parser_read_uint16(&dport1, tokens[11])) {
-			printf(CMD_MSG_INVALID_ARG, "dport1");
-			return;
-		}
-
-		if (parser_read_uint8(&proto, tokens[12])) {
-			printf(CMD_MSG_INVALID_ARG, "proto");
-			return;
-		}
-
-		if (parser_read_uint8_hex(&protomask, tokens[13])) {
-			printf(CMD_MSG_INVALID_ARG, "protomask");
-			return;
-		}
-
-		if (strcmp(tokens[14], "port")) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "port");
-			return;
-		}
-
-		if (parser_read_uint32(&port_id, tokens[15])) {
-			printf(CMD_MSG_INVALID_ARG, "portid");
-			return;
-		}
-
-		key.type = PIPELINE_FIREWALL_IPV4_5TUPLE;
-		key.key.ipv4_5tuple.src_ip = rte_be_to_cpu_32(sipaddr.s_addr);
-		key.key.ipv4_5tuple.src_ip_mask = sipdepth;
-		key.key.ipv4_5tuple.dst_ip = rte_be_to_cpu_32(dipaddr.s_addr);
-		key.key.ipv4_5tuple.dst_ip_mask = dipdepth;
-		key.key.ipv4_5tuple.src_port_from = sport0;
-		key.key.ipv4_5tuple.src_port_to = sport1;
-		key.key.ipv4_5tuple.dst_port_from = dport0;
-		key.key.ipv4_5tuple.dst_port_to = dport1;
-		key.key.ipv4_5tuple.proto = proto;
-		key.key.ipv4_5tuple.proto_mask = protomask;
-
-		status = app_pipeline_firewall_add_rule(app,
-			params->pipeline_id,
-			&key,
-			priority,
-			port_id);
-		if (status)
-			printf(CMD_MSG_FAIL, "firewall add");
-
-		return;
-	} /* firewall add */
-
-	/* firewall add bulk */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "add") == 0) &&
-		(strcmp(tokens[1], "bulk") == 0)) {
-		struct pipeline_firewall_key *keys;
-		uint32_t *priorities, *port_ids, n_keys, line;
-		char *filename;
-
-		if (n_tokens != 3) {
-			printf(CMD_MSG_MISMATCH_ARGS, "firewall add bulk");
-			return;
-		}
-
-		filename = tokens[2];
-
-		n_keys = APP_PIPELINE_FIREWALL_MAX_RULES_IN_FILE;
-		keys = malloc(n_keys * sizeof(struct pipeline_firewall_key));
-		if (keys == NULL) {
-			printf(CMD_MSG_OUT_OF_MEMORY);
-			return;
-		}
-		memset(keys, 0, n_keys * sizeof(struct pipeline_firewall_key));
-
-		priorities = malloc(n_keys * sizeof(uint32_t));
-		if (priorities == NULL) {
-			printf(CMD_MSG_OUT_OF_MEMORY);
-			free(keys);
-			return;
-		}
-
-		port_ids = malloc(n_keys * sizeof(uint32_t));
-		if (port_ids == NULL) {
-			printf(CMD_MSG_OUT_OF_MEMORY);
-			free(priorities);
-			free(keys);
-			return;
-		}
-
-		status = app_pipeline_firewall_load_file(filename,
-			keys,
-			priorities,
-			port_ids,
-			&n_keys,
-			&line);
-		if (status != 0) {
-			printf(CMD_MSG_FILE_ERR, filename, line);
-			free(port_ids);
-			free(priorities);
-			free(keys);
-			return;
-		}
-
-		status = app_pipeline_firewall_add_bulk(app,
-			params->pipeline_id,
-			keys,
-			n_keys,
-			priorities,
-			port_ids);
-		if (status)
-			printf(CMD_MSG_FAIL, "firewall add bulk");
-
-		free(keys);
-		free(priorities);
-		free(port_ids);
-		return;
-	} /* firewall add bulk */
-
-	/* firewall add default */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "add") == 0) &&
-		(strcmp(tokens[1], "default") == 0)) {
-		uint32_t port_id;
-
-		if (n_tokens != 3) {
-			printf(CMD_MSG_MISMATCH_ARGS, "firewall add default");
-			return;
-		}
-
-		if (parser_read_uint32(&port_id, tokens[2])) {
-			printf(CMD_MSG_INVALID_ARG, "portid");
-			return;
-		}
-
-		status = app_pipeline_firewall_add_default_rule(app,
-			params->pipeline_id,
-			port_id);
-		if (status)
-			printf(CMD_MSG_FAIL, "firewall add default");
-
-		return;
-	} /* firewall add default */
-
-	/* firewall del */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "del") == 0) &&
-		(strcmp(tokens[1], "ipv4") == 0)) {
-		struct pipeline_firewall_key key;
-		struct in_addr sipaddr;
-		uint32_t sipdepth;
-		struct in_addr dipaddr;
-		uint32_t dipdepth;
-		uint16_t sport0;
-		uint16_t sport1;
-		uint16_t dport0;
-		uint16_t dport1;
-		uint8_t proto;
-		uint8_t protomask;
-
-		memset(&key, 0, sizeof(key));
-
-		if (n_tokens != 12) {
-			printf(CMD_MSG_MISMATCH_ARGS, "firewall del");
-			return;
-		}
-
-		if (parse_ipv4_addr(tokens[2], &sipaddr)) {
-			printf(CMD_MSG_INVALID_ARG, "sipaddr");
-			return;
-		}
-
-		if (parser_read_uint32(&sipdepth, tokens[3])) {
-			printf(CMD_MSG_INVALID_ARG, "sipdepth");
-			return;
-		}
-
-		if (parse_ipv4_addr(tokens[4], &dipaddr)) {
-			printf(CMD_MSG_INVALID_ARG, "dipaddr");
-			return;
-		}
-
-		if (parser_read_uint32(&dipdepth, tokens[5])) {
-			printf(CMD_MSG_INVALID_ARG, "dipdepth");
-			return;
-		}
-
-		if (parser_read_uint16(&sport0, tokens[6])) {
-			printf(CMD_MSG_INVALID_ARG, "sport0");
-			return;
-		}
-
-		if (parser_read_uint16(&sport1, tokens[7])) {
-			printf(CMD_MSG_INVALID_ARG, "sport1");
-			return;
-		}
-
-		if (parser_read_uint16(&dport0, tokens[8])) {
-			printf(CMD_MSG_INVALID_ARG, "dport0");
-			return;
-		}
-
-		if (parser_read_uint16(&dport1, tokens[9])) {
-			printf(CMD_MSG_INVALID_ARG, "dport1");
-			return;
-		}
-
-		if (parser_read_uint8(&proto, tokens[10])) {
-			printf(CMD_MSG_INVALID_ARG, "proto");
-			return;
-		}
-
-		if (parser_read_uint8_hex(&protomask, tokens[11])) {
-			printf(CMD_MSG_INVALID_ARG, "protomask");
-			return;
-		}
-
-		key.type = PIPELINE_FIREWALL_IPV4_5TUPLE;
-		key.key.ipv4_5tuple.src_ip = rte_be_to_cpu_32(sipaddr.s_addr);
-		key.key.ipv4_5tuple.src_ip_mask = sipdepth;
-		key.key.ipv4_5tuple.dst_ip = rte_be_to_cpu_32(dipaddr.s_addr);
-		key.key.ipv4_5tuple.dst_ip_mask = dipdepth;
-		key.key.ipv4_5tuple.src_port_from = sport0;
-		key.key.ipv4_5tuple.src_port_to = sport1;
-		key.key.ipv4_5tuple.dst_port_from = dport0;
-		key.key.ipv4_5tuple.dst_port_to = dport1;
-		key.key.ipv4_5tuple.proto = proto;
-		key.key.ipv4_5tuple.proto_mask = protomask;
-
-		status = app_pipeline_firewall_delete_rule(app,
-			params->pipeline_id,
-			&key);
-		if (status)
-			printf(CMD_MSG_FAIL, "firewall del");
-
-		return;
-	} /* firewall del */
-
-	/* firewall del bulk */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "del") == 0) &&
-		(strcmp(tokens[1], "bulk") == 0)) {
-		struct pipeline_firewall_key *keys;
-		uint32_t *priorities, *port_ids, n_keys, line;
-		char *filename;
-
-		if (n_tokens != 3) {
-			printf(CMD_MSG_MISMATCH_ARGS, "firewall del bulk");
-			return;
-		}
-
-		filename = tokens[2];
-
-		n_keys = APP_PIPELINE_FIREWALL_MAX_RULES_IN_FILE;
-		keys = malloc(n_keys * sizeof(struct pipeline_firewall_key));
-		if (keys == NULL) {
-			printf(CMD_MSG_OUT_OF_MEMORY);
-			return;
-		}
-		memset(keys, 0, n_keys * sizeof(struct pipeline_firewall_key));
-
-		priorities = malloc(n_keys * sizeof(uint32_t));
-		if (priorities == NULL) {
-			printf(CMD_MSG_OUT_OF_MEMORY);
-			free(keys);
-			return;
-		}
-
-		port_ids = malloc(n_keys * sizeof(uint32_t));
-		if (port_ids == NULL) {
-			printf(CMD_MSG_OUT_OF_MEMORY);
-			free(priorities);
-			free(keys);
-			return;
-		}
-
-		status = app_pipeline_firewall_load_file(filename,
-			keys,
-			priorities,
-			port_ids,
-			&n_keys,
-			&line);
-		if (status != 0) {
-			printf(CMD_MSG_FILE_ERR, filename, line);
-			free(port_ids);
-			free(priorities);
-			free(keys);
-			return;
-		}
-
-		status = app_pipeline_firewall_delete_bulk(app,
-			params->pipeline_id,
-			keys,
-			n_keys);
-		if (status)
-			printf(CMD_MSG_FAIL, "firewall del bulk");
-
-		free(port_ids);
-		free(priorities);
-		free(keys);
-		return;
-	} /* firewall del bulk */
-
-	/* firewall del default */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "del") == 0) &&
-		(strcmp(tokens[1], "default") == 0)) {
-		if (n_tokens != 2) {
-			printf(CMD_MSG_MISMATCH_ARGS, "firewall del default");
-			return;
-		}
-
-		status = app_pipeline_firewall_delete_default_rule(app,
-			params->pipeline_id);
-		if (status)
-			printf(CMD_MSG_FAIL, "firewall del default");
-
-		return;
-
-	} /* firewall del default */
-
-	/* firewall ls */
-	if ((n_tokens >= 1) && (strcmp(tokens[0], "ls") == 0)) {
-		if (n_tokens != 1) {
-			printf(CMD_MSG_MISMATCH_ARGS, "firewall ls");
-			return;
-		}
-
-		status = app_pipeline_firewall_ls(app, params->pipeline_id);
-		if (status)
-			printf(CMD_MSG_FAIL, "firewall ls");
-
-		return;
-	} /* firewall ls */
-
-	printf(CMD_MSG_MISMATCH_ARGS, "firewall");
-}
-
-static cmdline_parse_token_string_t cmd_firewall_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_result, p_string, "p");
-
-static cmdline_parse_token_num_t cmd_firewall_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_result, pipeline_id, UINT32);
-
-static cmdline_parse_token_string_t cmd_firewall_firewall_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_result, firewall_string,
-	"firewall");
-
-static cmdline_parse_token_string_t cmd_firewall_multi_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_result, multi_string,
-	TOKEN_STRING_MULTI);
-
-static cmdline_parse_inst_t cmd_firewall = {
-	.f = cmd_firewall_parsed,
-	.data = NULL,
-	.help_str =	"firewall add / add bulk / add default / del / del bulk"
-		" / del default / ls",
-	.tokens = {
-		(void *) &cmd_firewall_p_string,
-		(void *) &cmd_firewall_pipeline_id,
-		(void *) &cmd_firewall_firewall_string,
-		(void *) &cmd_firewall_multi_string,
-		NULL,
-	},
-};
-
-static cmdline_parse_ctx_t pipeline_cmds[] = {
-	(cmdline_parse_inst_t *) &cmd_firewall,
-	NULL,
-};
-
-static struct pipeline_fe_ops pipeline_firewall_fe_ops = {
-	.f_init = app_pipeline_firewall_init,
-	.f_post_init = NULL,
-	.f_free = app_pipeline_firewall_free,
-	.f_track = app_pipeline_track_default,
-	.cmds = pipeline_cmds,
-};
-
-struct pipeline_type pipeline_firewall = {
-	.name = "FIREWALL",
-	.be_ops = &pipeline_firewall_be_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
deleted file mode 100644
index 27304b0..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_firewall.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#ifndef __INCLUDE_PIPELINE_FIREWALL_H__
-#define __INCLUDE_PIPELINE_FIREWALL_H__
-
-#include "pipeline.h"
-#include "pipeline_firewall_be.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_bulk(struct app_params *app,
-		uint32_t pipeline_id,
-		struct pipeline_firewall_key *keys,
-		uint32_t n_keys,
-		uint32_t *priorities,
-		uint32_t *port_ids);
-
-int
-app_pipeline_firewall_delete_bulk(struct app_params *app,
-	uint32_t pipeline_id,
-	struct pipeline_firewall_key *keys,
-	uint32_t n_keys);
-
-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);
-
-#ifndef APP_PIPELINE_FIREWALL_MAX_RULES_IN_FILE
-#define APP_PIPELINE_FIREWALL_MAX_RULES_IN_FILE		65536
-#endif
-
-int
-app_pipeline_firewall_load_file(char *filename,
-	struct pipeline_firewall_key *keys,
-	uint32_t *priorities,
-	uint32_t *port_ids,
-	uint32_t *n_keys,
-	uint32_t *line);
-
-extern struct pipeline_type pipeline_firewall;
-
-#endif
diff --git a/examples/ip_pipeline/pipeline/pipeline_firewall_be.c b/examples/ip_pipeline/pipeline/pipeline_firewall_be.c
deleted file mode 100644
index bd5e1b2..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_firewall_be.c
+++ /dev/null
@@ -1,856 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2016 Intel Corporation
- */
-
-#include <string.h>
-
-#include <rte_common.h>
-#include <rte_malloc.h>
-#include <rte_ether.h>
-#include <rte_ip.h>
-#include <rte_tcp.h>
-#include <rte_byteorder.h>
-#include <rte_table_acl.h>
-
-#include "pipeline_firewall_be.h"
-#include "parser.h"
-
-struct pipeline_firewall {
-	struct pipeline p;
-	pipeline_msg_req_handler custom_handlers[PIPELINE_FIREWALL_MSG_REQS];
-
-	uint32_t n_rules;
-	uint32_t n_rule_fields;
-	struct rte_acl_field_def *field_format;
-	uint32_t field_format_size;
-} __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_bulk_handler(struct pipeline *p, void *msg);
-
-static void *
-pipeline_firewall_msg_req_del_bulk_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_BULK] =
-		pipeline_firewall_msg_req_add_bulk_handler,
-	[PIPELINE_FIREWALL_MSG_REQ_DEL_BULK] =
-		pipeline_firewall_msg_req_del_bulk_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,
-};
-
-/*
- * Firewall table
- */
-struct firewall_table_entry {
-	struct rte_pipeline_table_entry head;
-};
-
-static struct rte_acl_field_def field_format_ipv4[] = {
-	/* Protocol */
-	[0] = {
-		.type = RTE_ACL_FIELD_TYPE_BITMASK,
-		.size = sizeof(uint8_t),
-		.field_index = 0,
-		.input_index = 0,
-		.offset = sizeof(struct ether_hdr) +
-			offsetof(struct ipv4_hdr, next_proto_id),
-	},
-
-	/* Source IP address (IPv4) */
-	[1] = {
-		.type = RTE_ACL_FIELD_TYPE_MASK,
-		.size = sizeof(uint32_t),
-		.field_index = 1,
-		.input_index = 1,
-		.offset = sizeof(struct ether_hdr) +
-			offsetof(struct ipv4_hdr, src_addr),
-	},
-
-	/* Destination IP address (IPv4) */
-	[2] = {
-		.type = RTE_ACL_FIELD_TYPE_MASK,
-		.size = sizeof(uint32_t),
-		.field_index = 2,
-		.input_index = 2,
-		.offset = sizeof(struct ether_hdr) +
-			offsetof(struct ipv4_hdr, dst_addr),
-	},
-
-	/* Source Port */
-	[3] = {
-		.type = RTE_ACL_FIELD_TYPE_RANGE,
-		.size = sizeof(uint16_t),
-		.field_index = 3,
-		.input_index = 3,
-		.offset = sizeof(struct ether_hdr) +
-			sizeof(struct ipv4_hdr) +
-			offsetof(struct tcp_hdr, src_port),
-	},
-
-	/* Destination Port */
-	[4] = {
-		.type = RTE_ACL_FIELD_TYPE_RANGE,
-		.size = sizeof(uint16_t),
-		.field_index = 4,
-		.input_index = 3,
-		.offset = sizeof(struct ether_hdr) +
-			sizeof(struct ipv4_hdr) +
-			offsetof(struct tcp_hdr, dst_port),
-	},
-};
-
-#define SIZEOF_VLAN_HDR                          4
-
-static struct rte_acl_field_def field_format_vlan_ipv4[] = {
-	/* Protocol */
-	[0] = {
-		.type = RTE_ACL_FIELD_TYPE_BITMASK,
-		.size = sizeof(uint8_t),
-		.field_index = 0,
-		.input_index = 0,
-		.offset = sizeof(struct ether_hdr) +
-			SIZEOF_VLAN_HDR +
-			offsetof(struct ipv4_hdr, next_proto_id),
-	},
-
-	/* Source IP address (IPv4) */
-	[1] = {
-		.type = RTE_ACL_FIELD_TYPE_MASK,
-		.size = sizeof(uint32_t),
-		.field_index = 1,
-		.input_index = 1,
-		.offset = sizeof(struct ether_hdr) +
-			SIZEOF_VLAN_HDR +
-			offsetof(struct ipv4_hdr, src_addr),
-	},
-
-	/* Destination IP address (IPv4) */
-	[2] = {
-		.type = RTE_ACL_FIELD_TYPE_MASK,
-		.size = sizeof(uint32_t),
-		.field_index = 2,
-		.input_index = 2,
-		.offset = sizeof(struct ether_hdr) +
-			SIZEOF_VLAN_HDR +
-			offsetof(struct ipv4_hdr, dst_addr),
-	},
-
-	/* Source Port */
-	[3] = {
-		.type = RTE_ACL_FIELD_TYPE_RANGE,
-		.size = sizeof(uint16_t),
-		.field_index = 3,
-		.input_index = 3,
-		.offset = sizeof(struct ether_hdr) +
-			SIZEOF_VLAN_HDR +
-			sizeof(struct ipv4_hdr) +
-			offsetof(struct tcp_hdr, src_port),
-	},
-
-	/* Destination Port */
-	[4] = {
-		.type = RTE_ACL_FIELD_TYPE_RANGE,
-		.size = sizeof(uint16_t),
-		.field_index = 4,
-		.input_index = 3,
-		.offset = sizeof(struct ether_hdr) +
-			SIZEOF_VLAN_HDR +
-			sizeof(struct ipv4_hdr) +
-			offsetof(struct tcp_hdr, dst_port),
-	},
-};
-
-#define SIZEOF_QINQ_HEADER                       8
-
-static struct rte_acl_field_def field_format_qinq_ipv4[] = {
-	/* Protocol */
-	[0] = {
-		.type = RTE_ACL_FIELD_TYPE_BITMASK,
-		.size = sizeof(uint8_t),
-		.field_index = 0,
-		.input_index = 0,
-		.offset = sizeof(struct ether_hdr) +
-			SIZEOF_QINQ_HEADER +
-			offsetof(struct ipv4_hdr, next_proto_id),
-	},
-
-	/* Source IP address (IPv4) */
-	[1] = {
-		.type = RTE_ACL_FIELD_TYPE_MASK,
-		.size = sizeof(uint32_t),
-		.field_index = 1,
-		.input_index = 1,
-		.offset = sizeof(struct ether_hdr) +
-			SIZEOF_QINQ_HEADER +
-			offsetof(struct ipv4_hdr, src_addr),
-	},
-
-	/* Destination IP address (IPv4) */
-	[2] = {
-		.type = RTE_ACL_FIELD_TYPE_MASK,
-		.size = sizeof(uint32_t),
-		.field_index = 2,
-		.input_index = 2,
-		.offset = sizeof(struct ether_hdr) +
-			SIZEOF_QINQ_HEADER +
-			offsetof(struct ipv4_hdr, dst_addr),
-	},
-
-	/* Source Port */
-	[3] = {
-		.type = RTE_ACL_FIELD_TYPE_RANGE,
-		.size = sizeof(uint16_t),
-		.field_index = 3,
-		.input_index = 3,
-		.offset = sizeof(struct ether_hdr) +
-			SIZEOF_QINQ_HEADER +
-			sizeof(struct ipv4_hdr) +
-			offsetof(struct tcp_hdr, src_port),
-	},
-
-	/* Destination Port */
-	[4] = {
-		.type = RTE_ACL_FIELD_TYPE_RANGE,
-		.size = sizeof(uint16_t),
-		.field_index = 4,
-		.input_index = 3,
-		.offset = sizeof(struct ether_hdr) +
-			SIZEOF_QINQ_HEADER +
-			sizeof(struct ipv4_hdr) +
-			offsetof(struct tcp_hdr, dst_port),
-	},
-};
-
-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;
-
-	/* defaults */
-	p->n_rules = 4 * 1024;
-	p->n_rule_fields = RTE_DIM(field_format_ipv4);
-	p->field_format = field_format_ipv4;
-	p->field_format_size = sizeof(field_format_ipv4);
-
-	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) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				n_rules_present == 0, params->name,
-				arg_name);
-			n_rules_present = 1;
-
-			status = parser_read_uint32(&p->n_rules,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-			continue;
-		}
-
-		if (strcmp(arg_name, "pkt_type") == 0) {
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				pkt_type_present == 0, params->name,
-				arg_name);
-			pkt_type_present = 1;
-
-			/* ipv4 */
-			if (strcmp(arg_value, "ipv4") == 0) {
-				p->n_rule_fields = RTE_DIM(field_format_ipv4);
-				p->field_format = field_format_ipv4;
-				p->field_format_size =
-					sizeof(field_format_ipv4);
-				continue;
-			}
-
-			/* vlan_ipv4 */
-			if (strcmp(arg_value, "vlan_ipv4") == 0) {
-				p->n_rule_fields =
-					RTE_DIM(field_format_vlan_ipv4);
-				p->field_format = field_format_vlan_ipv4;
-				p->field_format_size =
-					sizeof(field_format_vlan_ipv4);
-				continue;
-			}
-
-			/* qinq_ipv4 */
-			if (strcmp(arg_value, "qinq_ipv4") == 0) {
-				p->n_rule_fields =
-					RTE_DIM(field_format_qinq_ipv4);
-				p->field_format = field_format_qinq_ipv4;
-				p->field_format_size =
-					sizeof(field_format_qinq_ipv4);
-				continue;
-			}
-
-			/* other */
-			PIPELINE_PARSE_ERR_INV_VAL(0, params->name,
-				arg_name, arg_value);
-		}
-
-		/* other */
-		PIPELINE_PARSE_ERR_INV_ENT(0, params->name, arg_name);
-	}
-
-	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);
-	p->log_level = params->log_level;
-
-	PLOG(p, HIGH, "Firewall");
-
-	/* 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,
-			.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 = params->name,
-			.n_rules = p_fw->n_rules,
-			.n_rule_fields = p_fw->n_rule_fields,
-		};
-
-		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 =
-					sizeof(struct firewall_table_entry) -
-					sizeof(struct rte_pipeline_table_entry),
-			};
-
-		int status;
-
-		memcpy(table_acl_params.field_format,
-			p_fw->field_format,
-			p_fw->field_format_size);
-
-		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_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 firewall_table_entry entry = {
-		.head = {
-			.action = RTE_PIPELINE_ACTION_PORT,
-			{.port_id = p->port_out_id[req->port_id]},
-		},
-	};
-
-	memset(&params, 0, sizeof(params));
-
-	switch (req->key.type) {
-	case PIPELINE_FIREWALL_IPV4_5TUPLE:
-		params.priority = req->priority;
-		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,
-		(struct rte_pipeline_table_entry *) &entry,
-		&rsp->key_found,
-		(struct rte_pipeline_table_entry **) &rsp->entry_ptr);
-
-	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;
-
-	memset(&params, 0, sizeof(params));
-
-	switch (req->key.type) {
-	case PIPELINE_FIREWALL_IPV4_5TUPLE:
-		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);
-
-	return rsp;
-}
-
-static void *
-pipeline_firewall_msg_req_add_bulk_handler(struct pipeline *p, void *msg)
-{
-	struct pipeline_firewall_add_bulk_msg_req *req = msg;
-	struct pipeline_firewall_add_bulk_msg_rsp *rsp = msg;
-
-	struct rte_table_acl_rule_add_params *params[req->n_keys];
-	struct firewall_table_entry *entries[req->n_keys];
-
-	uint32_t i, n_keys;
-
-	n_keys = req->n_keys;
-
-	for (i = 0; i < n_keys; i++) {
-		entries[i] = rte_zmalloc(NULL,
-				sizeof(struct firewall_table_entry),
-				RTE_CACHE_LINE_SIZE);
-		if (entries[i] == NULL) {
-			rsp->status = -1;
-			return rsp;
-		}
-
-		params[i] = rte_zmalloc(NULL,
-				sizeof(struct rte_table_acl_rule_add_params),
-				RTE_CACHE_LINE_SIZE);
-		if (params[i] == NULL) {
-			rsp->status = -1;
-			return rsp;
-		}
-
-		entries[i]->head.action = RTE_PIPELINE_ACTION_PORT;
-		entries[i]->head.port_id = p->port_out_id[req->port_ids[i]];
-
-		switch (req->keys[i].type) {
-		case PIPELINE_FIREWALL_IPV4_5TUPLE:
-			params[i]->priority = req->priorities[i];
-			params[i]->field_value[0].value.u8 =
-				req->keys[i].key.ipv4_5tuple.proto;
-			params[i]->field_value[0].mask_range.u8 =
-				req->keys[i].key.ipv4_5tuple.proto_mask;
-			params[i]->field_value[1].value.u32 =
-				req->keys[i].key.ipv4_5tuple.src_ip;
-			params[i]->field_value[1].mask_range.u32 =
-				req->keys[i].key.ipv4_5tuple.src_ip_mask;
-			params[i]->field_value[2].value.u32 =
-				req->keys[i].key.ipv4_5tuple.dst_ip;
-			params[i]->field_value[2].mask_range.u32 =
-				req->keys[i].key.ipv4_5tuple.dst_ip_mask;
-			params[i]->field_value[3].value.u16 =
-				req->keys[i].key.ipv4_5tuple.src_port_from;
-			params[i]->field_value[3].mask_range.u16 =
-				req->keys[i].key.ipv4_5tuple.src_port_to;
-			params[i]->field_value[4].value.u16 =
-				req->keys[i].key.ipv4_5tuple.dst_port_from;
-			params[i]->field_value[4].mask_range.u16 =
-				req->keys[i].key.ipv4_5tuple.dst_port_to;
-			break;
-
-		default:
-			rsp->status = -1; /* Error */
-
-			for (i = 0; i < n_keys; i++) {
-				rte_free(entries[i]);
-				rte_free(params[i]);
-			}
-
-			return rsp;
-		}
-	}
-
-	rsp->status = rte_pipeline_table_entry_add_bulk(p->p, p->table_id[0],
-			(void *)params, (struct rte_pipeline_table_entry **)entries,
-			n_keys, req->keys_found,
-			(struct rte_pipeline_table_entry **)req->entries_ptr);
-
-	for (i = 0; i < n_keys; i++) {
-		rte_free(entries[i]);
-		rte_free(params[i]);
-	}
-
-	return rsp;
-}
-
-static void *
-pipeline_firewall_msg_req_del_bulk_handler(struct pipeline *p, void *msg)
-{
-	struct pipeline_firewall_del_bulk_msg_req *req = msg;
-	struct pipeline_firewall_del_bulk_msg_rsp *rsp = msg;
-
-	struct rte_table_acl_rule_delete_params *params[req->n_keys];
-
-	uint32_t i, n_keys;
-
-	n_keys = req->n_keys;
-
-	for (i = 0; i < n_keys; i++) {
-		params[i] = rte_zmalloc(NULL,
-				sizeof(struct rte_table_acl_rule_delete_params),
-				RTE_CACHE_LINE_SIZE);
-		if (params[i] == NULL) {
-			rsp->status = -1;
-			return rsp;
-		}
-
-		switch (req->keys[i].type) {
-		case PIPELINE_FIREWALL_IPV4_5TUPLE:
-			params[i]->field_value[0].value.u8 =
-				req->keys[i].key.ipv4_5tuple.proto;
-			params[i]->field_value[0].mask_range.u8 =
-				req->keys[i].key.ipv4_5tuple.proto_mask;
-			params[i]->field_value[1].value.u32 =
-				req->keys[i].key.ipv4_5tuple.src_ip;
-			params[i]->field_value[1].mask_range.u32 =
-				req->keys[i].key.ipv4_5tuple.src_ip_mask;
-			params[i]->field_value[2].value.u32 =
-				req->keys[i].key.ipv4_5tuple.dst_ip;
-			params[i]->field_value[2].mask_range.u32 =
-				req->keys[i].key.ipv4_5tuple.dst_ip_mask;
-			params[i]->field_value[3].value.u16 =
-				req->keys[i].key.ipv4_5tuple.src_port_from;
-			params[i]->field_value[3].mask_range.u16 =
-				req->keys[i].key.ipv4_5tuple.src_port_to;
-			params[i]->field_value[4].value.u16 =
-				req->keys[i].key.ipv4_5tuple.dst_port_from;
-			params[i]->field_value[4].mask_range.u16 =
-				req->keys[i].key.ipv4_5tuple.dst_port_to;
-			break;
-
-		default:
-			rsp->status = -1; /* Error */
-
-			for (i = 0; i < n_keys; i++)
-				rte_free(params[i]);
-
-			return rsp;
-		}
-	}
-
-	rsp->status = rte_pipeline_table_entry_delete_bulk(p->p, p->table_id[0],
-			(void **)&params, n_keys, req->keys_found, NULL);
-
-	for (i = 0; i < n_keys; i++)
-		rte_free(params[i]);
-
-	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 firewall_table_entry default_entry = {
-		.head = {
-			.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],
-		(struct rte_pipeline_table_entry *) &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_be_ops pipeline_firewall_be_ops = {
-	.f_init = pipeline_firewall_init,
-	.f_free = pipeline_firewall_free,
-	.f_run = NULL,
-	.f_timer = pipeline_firewall_timer,
-};
diff --git a/examples/ip_pipeline/pipeline/pipeline_firewall_be.h b/examples/ip_pipeline/pipeline/pipeline_firewall_be.h
deleted file mode 100644
index 246f0a6..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_firewall_be.h
+++ /dev/null
@@ -1,147 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#ifndef __INCLUDE_PIPELINE_FIREWALL_BE_H__
-#define __INCLUDE_PIPELINE_FIREWALL_BE_H__
-
-#include "pipeline_common_be.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_BULK,
-	PIPELINE_FIREWALL_MSG_REQ_DEL_BULK,
-	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 BULK
- */
-struct pipeline_firewall_add_bulk_msg_req {
-	enum pipeline_msg_req_type type;
-	enum pipeline_firewall_msg_req_type subtype;
-
-	struct pipeline_firewall_key *keys;
-	uint32_t n_keys;
-
-	uint32_t *priorities;
-	uint32_t *port_ids;
-	int *keys_found;
-	void **entries_ptr;
-};
-struct pipeline_firewall_add_bulk_msg_rsp {
-	int status;
-};
-
-/*
- * MSG DEL BULK
- */
-struct pipeline_firewall_del_bulk_msg_req {
-	enum pipeline_msg_req_type type;
-	enum pipeline_firewall_msg_req_type subtype;
-
-	/* key */
-	struct pipeline_firewall_key *keys;
-	uint32_t n_keys;
-	int *keys_found;
-};
-
-struct pipeline_firewall_del_bulk_msg_rsp {
-	int status;
-};
-
-/*
- * 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_be_ops pipeline_firewall_be_ops;
-
-#endif
diff --git a/examples/ip_pipeline/pipeline/pipeline_flow_actions.c b/examples/ip_pipeline/pipeline/pipeline_flow_actions.c
deleted file mode 100644
index 021aee1..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_flow_actions.c
+++ /dev/null
@@ -1,1286 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <sys/queue.h>
-#include <netinet/in.h>
-#include <unistd.h>
-
-#include <rte_common.h>
-#include <rte_hexdump.h>
-#include <rte_malloc.h>
-#include <cmdline_rdline.h>
-#include <cmdline_parse.h>
-#include <cmdline_parse_num.h>
-#include <cmdline_parse_string.h>
-
-#include "app.h"
-#include "pipeline_common_fe.h"
-#include "pipeline_flow_actions.h"
-#include "hash_func.h"
-#include "parser.h"
-
-/*
- * Flow actions pipeline
- */
-#ifndef N_FLOWS_BULK
-#define N_FLOWS_BULK					4096
-#endif
-
-struct app_pipeline_fa_flow {
-	struct pipeline_fa_flow_params params;
-	void *entry_ptr;
-};
-
-struct app_pipeline_fa_dscp {
-	uint32_t traffic_class;
-	enum rte_meter_color color;
-};
-
-struct app_pipeline_fa {
-	/* Parameters */
-	uint32_t n_ports_in;
-	uint32_t n_ports_out;
-	struct pipeline_fa_params params;
-
-	/* Flows */
-	struct app_pipeline_fa_dscp dscp[PIPELINE_FA_N_DSCP];
-	struct app_pipeline_fa_flow *flows;
-} __rte_cache_aligned;
-
-static void*
-app_pipeline_fa_init(struct pipeline_params *params,
-	__rte_unused void *arg)
-{
-	struct app_pipeline_fa *p;
-	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 app_pipeline_fa));
-	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;
-	if (pipeline_fa_parse_args(&p->params, params)) {
-		rte_free(p);
-		return NULL;
-	}
-
-	/* Memory allocation */
-	size = RTE_CACHE_LINE_ROUNDUP(
-		p->params.n_flows * sizeof(struct app_pipeline_fa_flow));
-	p->flows = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
-	if (p->flows == NULL) {
-		rte_free(p);
-		return NULL;
-	}
-
-	/* Initialization of flow table */
-	for (i = 0; i < p->params.n_flows; i++)
-		pipeline_fa_flow_params_set_default(&p->flows[i].params);
-
-	/* Initialization of DSCP table */
-	for (i = 0; i < RTE_DIM(p->dscp); i++) {
-		p->dscp[i].traffic_class = 0;
-		p->dscp[i].color = e_RTE_METER_GREEN;
-	}
-
-	return (void *) p;
-}
-
-static int
-app_pipeline_fa_free(void *pipeline)
-{
-	struct app_pipeline_fa *p = pipeline;
-
-	/* Check input arguments */
-	if (p == NULL)
-		return -1;
-
-	/* Free resources */
-	rte_free(p->flows);
-	rte_free(p);
-
-	return 0;
-}
-
-static int
-flow_params_check(struct app_pipeline_fa *p,
-	__rte_unused uint32_t meter_update_mask,
-	uint32_t policer_update_mask,
-	uint32_t port_update,
-	struct pipeline_fa_flow_params *params)
-{
-	uint32_t mask, i;
-
-	/* Meter */
-
-	/* Policer */
-	for (i = 0, mask = 1; i < PIPELINE_FA_N_TC_MAX; i++, mask <<= 1) {
-		struct pipeline_fa_policer_params *p = &params->p[i];
-		uint32_t j;
-
-		if ((mask & policer_update_mask) == 0)
-			continue;
-
-		for (j = 0; j < e_RTE_METER_COLORS; j++) {
-			struct pipeline_fa_policer_action *action =
-				&p->action[j];
-
-			if ((action->drop == 0) &&
-				(action->color >= e_RTE_METER_COLORS))
-				return -1;
-		}
-	}
-
-	/* Port */
-	if (port_update && (params->port_id >= p->n_ports_out))
-		return -1;
-
-	return 0;
-}
-
-int
-app_pipeline_fa_flow_config(struct app_params *app,
-	uint32_t pipeline_id,
-	uint32_t flow_id,
-	uint32_t meter_update_mask,
-	uint32_t policer_update_mask,
-	uint32_t port_update,
-	struct pipeline_fa_flow_params *params)
-{
-	struct app_pipeline_fa *p;
-	struct app_pipeline_fa_flow *flow;
-
-	struct pipeline_fa_flow_config_msg_req *req;
-	struct pipeline_fa_flow_config_msg_rsp *rsp;
-
-	uint32_t i, mask;
-
-	/* Check input arguments */
-	if ((app == NULL) ||
-		((meter_update_mask == 0) &&
-		(policer_update_mask == 0) &&
-		(port_update == 0)) ||
-		(meter_update_mask >= (1 << PIPELINE_FA_N_TC_MAX)) ||
-		(policer_update_mask >= (1 << PIPELINE_FA_N_TC_MAX)) ||
-		(params == NULL))
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id,
-		&pipeline_flow_actions);
-	if (p == NULL)
-		return -1;
-
-	if (flow_params_check(p,
-		meter_update_mask,
-		policer_update_mask,
-		port_update,
-		params) != 0)
-		return -1;
-
-	flow_id %= p->params.n_flows;
-	flow = &p->flows[flow_id];
-
-	/* Allocate and write request */
-	req = app_msg_alloc(app);
-	if (req == NULL)
-		return -1;
-
-	req->type = PIPELINE_MSG_REQ_CUSTOM;
-	req->subtype = PIPELINE_FA_MSG_REQ_FLOW_CONFIG;
-	req->entry_ptr = flow->entry_ptr;
-	req->flow_id = flow_id;
-	req->meter_update_mask = meter_update_mask;
-	req->policer_update_mask = policer_update_mask;
-	req->port_update = port_update;
-	memcpy(&req->params, params, sizeof(*params));
-
-	/* Send request and wait for response */
-	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	/* Read response */
-	if (rsp->status ||
-		(rsp->entry_ptr == NULL)) {
-		app_msg_free(app, rsp);
-		return -1;
-	}
-
-	/* Commit flow */
-	for (i = 0, mask = 1; i < PIPELINE_FA_N_TC_MAX; i++, mask <<= 1) {
-		if ((mask & meter_update_mask) == 0)
-			continue;
-
-		memcpy(&flow->params.m[i], &params->m[i], sizeof(params->m[i]));
-	}
-
-	for (i = 0, mask = 1; i < PIPELINE_FA_N_TC_MAX; i++, mask <<= 1) {
-		if ((mask & policer_update_mask) == 0)
-			continue;
-
-		memcpy(&flow->params.p[i], &params->p[i], sizeof(params->p[i]));
-	}
-
-	if (port_update)
-		flow->params.port_id = params->port_id;
-
-	flow->entry_ptr = rsp->entry_ptr;
-
-	/* Free response */
-	app_msg_free(app, rsp);
-
-	return 0;
-}
-
-int
-app_pipeline_fa_flow_config_bulk(struct app_params *app,
-	uint32_t pipeline_id,
-	uint32_t *flow_id,
-	uint32_t n_flows,
-	uint32_t meter_update_mask,
-	uint32_t policer_update_mask,
-	uint32_t port_update,
-	struct pipeline_fa_flow_params *params)
-{
-	struct app_pipeline_fa *p;
-	struct pipeline_fa_flow_config_bulk_msg_req *req;
-	struct pipeline_fa_flow_config_bulk_msg_rsp *rsp;
-	void **req_entry_ptr;
-	uint32_t *req_flow_id;
-	uint32_t i;
-	int status;
-
-	/* Check input arguments */
-	if ((app == NULL) ||
-		(flow_id == NULL) ||
-		(n_flows == 0) ||
-		((meter_update_mask == 0) &&
-		(policer_update_mask == 0) &&
-		(port_update == 0)) ||
-		(meter_update_mask >= (1 << PIPELINE_FA_N_TC_MAX)) ||
-		(policer_update_mask >= (1 << PIPELINE_FA_N_TC_MAX)) ||
-		(params == NULL))
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id,
-		&pipeline_flow_actions);
-	if (p == NULL)
-		return -1;
-
-	for (i = 0; i < n_flows; i++) {
-		struct pipeline_fa_flow_params *flow_params = &params[i];
-
-		if (flow_params_check(p,
-			meter_update_mask,
-			policer_update_mask,
-			port_update,
-			flow_params) != 0)
-			return -1;
-	}
-
-	/* Allocate and write request */
-	req_entry_ptr = (void **) rte_malloc(NULL,
-		n_flows * sizeof(void *),
-		RTE_CACHE_LINE_SIZE);
-	if (req_entry_ptr == NULL)
-		return -1;
-
-	req_flow_id = (uint32_t *) rte_malloc(NULL,
-		n_flows * sizeof(uint32_t),
-		RTE_CACHE_LINE_SIZE);
-	if (req_flow_id == NULL) {
-		rte_free(req_entry_ptr);
-		return -1;
-	}
-
-	for (i = 0; i < n_flows; i++) {
-		uint32_t fid = flow_id[i] % p->params.n_flows;
-		struct app_pipeline_fa_flow *flow = &p->flows[fid];
-
-		req_flow_id[i] = fid;
-		req_entry_ptr[i] = flow->entry_ptr;
-	}
-
-	req = app_msg_alloc(app);
-	if (req == NULL) {
-		rte_free(req_flow_id);
-		rte_free(req_entry_ptr);
-		return -1;
-	}
-
-	req->type = PIPELINE_MSG_REQ_CUSTOM;
-	req->subtype = PIPELINE_FA_MSG_REQ_FLOW_CONFIG_BULK;
-	req->entry_ptr = req_entry_ptr;
-	req->flow_id = req_flow_id;
-	req->n_flows = n_flows;
-	req->meter_update_mask = meter_update_mask;
-	req->policer_update_mask = policer_update_mask;
-	req->port_update = port_update;
-	req->params = params;
-
-	/* Send request and wait for response */
-	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL) {
-		rte_free(req_flow_id);
-		rte_free(req_entry_ptr);
-		return -1;
-	}
-
-	/* Read response */
-	status = (rsp->n_flows == n_flows) ? 0 : -1;
-
-	/* Commit flows */
-	for (i = 0; i < rsp->n_flows; i++) {
-		uint32_t fid = flow_id[i] % p->params.n_flows;
-		struct app_pipeline_fa_flow *flow = &p->flows[fid];
-		struct pipeline_fa_flow_params *flow_params = &params[i];
-		void *entry_ptr = req_entry_ptr[i];
-		uint32_t j, mask;
-
-		for (j = 0, mask = 1; j < PIPELINE_FA_N_TC_MAX;
-			j++, mask <<= 1) {
-			if ((mask & meter_update_mask) == 0)
-				continue;
-
-			memcpy(&flow->params.m[j],
-				&flow_params->m[j],
-				sizeof(flow_params->m[j]));
-		}
-
-		for (j = 0, mask = 1; j < PIPELINE_FA_N_TC_MAX;
-			j++, mask <<= 1) {
-			if ((mask & policer_update_mask) == 0)
-				continue;
-
-			memcpy(&flow->params.p[j],
-				&flow_params->p[j],
-				sizeof(flow_params->p[j]));
-		}
-
-		if (port_update)
-			flow->params.port_id = flow_params->port_id;
-
-		flow->entry_ptr = entry_ptr;
-	}
-
-	/* Free response */
-	app_msg_free(app, rsp);
-	rte_free(req_flow_id);
-	rte_free(req_entry_ptr);
-
-	return status;
-}
-
-int
-app_pipeline_fa_dscp_config(struct app_params *app,
-	uint32_t pipeline_id,
-	uint32_t dscp,
-	uint32_t traffic_class,
-	enum rte_meter_color color)
-{
-	struct app_pipeline_fa *p;
-
-	struct pipeline_fa_dscp_config_msg_req *req;
-	struct pipeline_fa_dscp_config_msg_rsp *rsp;
-
-	/* Check input arguments */
-	if ((app == NULL) ||
-		(dscp >= PIPELINE_FA_N_DSCP) ||
-		(traffic_class >= PIPELINE_FA_N_TC_MAX) ||
-		(color >= e_RTE_METER_COLORS))
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id,
-		&pipeline_flow_actions);
-	if (p == NULL)
-		return -1;
-
-	if (p->params.dscp_enabled == 0)
-		return -1;
-
-	/* Allocate and write request */
-	req = app_msg_alloc(app);
-	if (req == NULL)
-		return -1;
-
-	req->type = PIPELINE_MSG_REQ_CUSTOM;
-	req->subtype = PIPELINE_FA_MSG_REQ_DSCP_CONFIG;
-	req->dscp = dscp;
-	req->traffic_class = traffic_class;
-	req->color = color;
-
-	/* Send request and wait for response */
-	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	/* Read response */
-	if (rsp->status) {
-		app_msg_free(app, rsp);
-		return -1;
-	}
-
-	/* Commit DSCP */
-	p->dscp[dscp].traffic_class = traffic_class;
-	p->dscp[dscp].color = color;
-
-	/* Free response */
-	app_msg_free(app, rsp);
-
-	return 0;
-}
-
-int
-app_pipeline_fa_flow_policer_stats_read(struct app_params *app,
-	uint32_t pipeline_id,
-	uint32_t flow_id,
-	uint32_t policer_id,
-	int clear,
-	struct pipeline_fa_policer_stats *stats)
-{
-	struct app_pipeline_fa *p;
-	struct app_pipeline_fa_flow *flow;
-
-	struct pipeline_fa_policer_stats_msg_req *req;
-	struct pipeline_fa_policer_stats_msg_rsp *rsp;
-
-	/* Check input arguments */
-	if ((app == NULL) || (stats == NULL))
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id,
-		&pipeline_flow_actions);
-	if (p == NULL)
-		return -1;
-
-	flow_id %= p->params.n_flows;
-	flow = &p->flows[flow_id];
-
-	if ((policer_id >= p->params.n_meters_per_flow) ||
-		(flow->entry_ptr == NULL))
-		return -1;
-
-	/* Allocate and write request */
-	req = app_msg_alloc(app);
-	if (req == NULL)
-		return -1;
-
-	req->type = PIPELINE_MSG_REQ_CUSTOM;
-	req->subtype = PIPELINE_FA_MSG_REQ_POLICER_STATS_READ;
-	req->entry_ptr = flow->entry_ptr;
-	req->policer_id = policer_id;
-	req->clear = clear;
-
-	/* Send request and wait for response */
-	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	/* Read response */
-	if (rsp->status) {
-		app_msg_free(app, rsp);
-		return -1;
-	}
-
-	memcpy(stats, &rsp->stats, sizeof(*stats));
-
-	/* Free response */
-	app_msg_free(app, rsp);
-
-	return 0;
-}
-
-static const char *
-color_to_string(enum rte_meter_color color)
-{
-	switch (color) {
-	case e_RTE_METER_GREEN: return "G";
-	case e_RTE_METER_YELLOW: return "Y";
-	case e_RTE_METER_RED: return "R";
-	default: return "?";
-	}
-}
-
-static int
-string_to_color(char *s, enum rte_meter_color *c)
-{
-	if (strcmp(s, "G") == 0) {
-		*c = e_RTE_METER_GREEN;
-		return 0;
-	}
-
-	if (strcmp(s, "Y") == 0) {
-		*c = e_RTE_METER_YELLOW;
-		return 0;
-	}
-
-	if (strcmp(s, "R") == 0) {
-		*c = e_RTE_METER_RED;
-		return 0;
-	}
-
-	return -1;
-}
-
-static const char *
-policer_action_to_string(struct pipeline_fa_policer_action *a)
-{
-	if (a->drop)
-		return "D";
-
-	return color_to_string(a->color);
-}
-
-static int
-string_to_policer_action(char *s, struct pipeline_fa_policer_action *a)
-{
-	if (strcmp(s, "G") == 0) {
-		a->drop = 0;
-		a->color = e_RTE_METER_GREEN;
-		return 0;
-	}
-
-	if (strcmp(s, "Y") == 0) {
-		a->drop = 0;
-		a->color = e_RTE_METER_YELLOW;
-		return 0;
-	}
-
-	if (strcmp(s, "R") == 0) {
-		a->drop = 0;
-		a->color = e_RTE_METER_RED;
-		return 0;
-	}
-
-	if (strcmp(s, "D") == 0) {
-		a->drop = 1;
-		a->color = e_RTE_METER_GREEN;
-		return 0;
-	}
-
-	return -1;
-}
-
-static void
-print_flow(struct app_pipeline_fa *p,
-	uint32_t flow_id,
-	struct app_pipeline_fa_flow *flow)
-{
-	uint32_t i;
-
-	printf("Flow ID = %" PRIu32 "\n", flow_id);
-
-	for (i = 0; i < p->params.n_meters_per_flow; i++) {
-		struct rte_meter_trtcm_params *meter = &flow->params.m[i];
-		struct pipeline_fa_policer_params *policer = &flow->params.p[i];
-
-	printf("\ttrTCM [CIR = %" PRIu64
-		", CBS = %" PRIu64 ", PIR = %" PRIu64
-		", PBS = %" PRIu64	"] Policer [G : %s, Y : %s, R : %s]\n",
-		meter->cir,
-		meter->cbs,
-		meter->pir,
-		meter->pbs,
-		policer_action_to_string(&policer->action[e_RTE_METER_GREEN]),
-		policer_action_to_string(&policer->action[e_RTE_METER_YELLOW]),
-		policer_action_to_string(&policer->action[e_RTE_METER_RED]));
-	}
-
-	printf("\tPort %u (entry_ptr = %p)\n",
-		flow->params.port_id,
-		flow->entry_ptr);
-}
-
-
-static int
-app_pipeline_fa_flow_ls(struct app_params *app,
-		uint32_t pipeline_id)
-{
-	struct app_pipeline_fa *p;
-	uint32_t i;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id,
-		&pipeline_flow_actions);
-	if (p == NULL)
-		return -1;
-
-	for (i = 0; i < p->params.n_flows; i++) {
-		struct app_pipeline_fa_flow *flow = &p->flows[i];
-
-		print_flow(p, i, flow);
-	}
-
-	return 0;
-}
-
-static int
-app_pipeline_fa_dscp_ls(struct app_params *app,
-		uint32_t pipeline_id)
-{
-	struct app_pipeline_fa *p;
-	uint32_t i;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id,
-		&pipeline_flow_actions);
-	if (p == NULL)
-		return -1;
-
-	if (p->params.dscp_enabled == 0)
-		return -1;
-
-	for (i = 0; i < RTE_DIM(p->dscp); i++) {
-		struct app_pipeline_fa_dscp *dscp =	&p->dscp[i];
-
-		printf("DSCP = %2" PRIu32 ": Traffic class = %" PRIu32
-			", Color = %s\n",
-			i,
-			dscp->traffic_class,
-			color_to_string(dscp->color));
-	}
-
-	return 0;
-}
-
-int
-app_pipeline_fa_load_file(char *filename,
-	uint32_t *flow_ids,
-	struct pipeline_fa_flow_params *p,
-	uint32_t *n_flows,
-	uint32_t *line)
-{
-	FILE *f = NULL;
-	char file_buf[1024];
-	uint32_t i, l;
-
-	/* Check input arguments */
-	if ((filename == NULL) ||
-		(flow_ids == NULL) ||
-		(p == NULL) ||
-		(n_flows == NULL) ||
-		(*n_flows == 0) ||
-		(line == NULL)) {
-		if (line)
-			*line = 0;
-		return -1;
-		}
-
-	/* Open input file */
-	f = fopen(filename, "r");
-	if (f == NULL) {
-		*line = 0;
-		return -1;
-	}
-
-	/* Read file */
-	for (i = 0, l = 1; i < *n_flows; l++) {
-		char *tokens[64];
-		uint32_t n_tokens = RTE_DIM(tokens);
-
-		int status;
-
-		if (fgets(file_buf, sizeof(file_buf), f) == NULL)
-			break;
-
-		status = parse_tokenize_string(file_buf, tokens, &n_tokens);
-		if (status)
-			goto error1;
-
-		if ((n_tokens == 0) || (tokens[0][0] == '#'))
-			continue;
-
-
-		if ((n_tokens != 64) ||
-			/* flow */
-			strcmp(tokens[0], "flow") ||
-			parser_read_uint32(&flow_ids[i], tokens[1]) ||
-
-			/* meter & policer 0 */
-			strcmp(tokens[2], "meter") ||
-			strcmp(tokens[3], "0") ||
-			strcmp(tokens[4], "trtcm") ||
-			parser_read_uint64(&p[i].m[0].cir, tokens[5]) ||
-			parser_read_uint64(&p[i].m[0].pir, tokens[6]) ||
-			parser_read_uint64(&p[i].m[0].cbs, tokens[7]) ||
-			parser_read_uint64(&p[i].m[0].pbs, tokens[8]) ||
-			strcmp(tokens[9], "policer") ||
-			strcmp(tokens[10], "0") ||
-			strcmp(tokens[11], "g") ||
-			string_to_policer_action(tokens[12],
-				&p[i].p[0].action[e_RTE_METER_GREEN]) ||
-			strcmp(tokens[13], "y") ||
-			string_to_policer_action(tokens[14],
-				&p[i].p[0].action[e_RTE_METER_YELLOW]) ||
-			strcmp(tokens[15], "r") ||
-			string_to_policer_action(tokens[16],
-				&p[i].p[0].action[e_RTE_METER_RED]) ||
-
-			/* meter & policer 1 */
-			strcmp(tokens[17], "meter") ||
-			strcmp(tokens[18], "1") ||
-			strcmp(tokens[19], "trtcm") ||
-			parser_read_uint64(&p[i].m[1].cir, tokens[20]) ||
-			parser_read_uint64(&p[i].m[1].pir, tokens[21]) ||
-			parser_read_uint64(&p[i].m[1].cbs, tokens[22]) ||
-			parser_read_uint64(&p[i].m[1].pbs, tokens[23]) ||
-			strcmp(tokens[24], "policer") ||
-			strcmp(tokens[25], "1") ||
-			strcmp(tokens[26], "g") ||
-			string_to_policer_action(tokens[27],
-				&p[i].p[1].action[e_RTE_METER_GREEN]) ||
-			strcmp(tokens[28], "y") ||
-			string_to_policer_action(tokens[29],
-				&p[i].p[1].action[e_RTE_METER_YELLOW]) ||
-			strcmp(tokens[30], "r") ||
-			string_to_policer_action(tokens[31],
-				&p[i].p[1].action[e_RTE_METER_RED]) ||
-
-			/* meter & policer 2 */
-			strcmp(tokens[32], "meter") ||
-			strcmp(tokens[33], "2") ||
-			strcmp(tokens[34], "trtcm") ||
-			parser_read_uint64(&p[i].m[2].cir, tokens[35]) ||
-			parser_read_uint64(&p[i].m[2].pir, tokens[36]) ||
-			parser_read_uint64(&p[i].m[2].cbs, tokens[37]) ||
-			parser_read_uint64(&p[i].m[2].pbs, tokens[38]) ||
-			strcmp(tokens[39], "policer") ||
-			strcmp(tokens[40], "2") ||
-			strcmp(tokens[41], "g") ||
-			string_to_policer_action(tokens[42],
-				&p[i].p[2].action[e_RTE_METER_GREEN]) ||
-			strcmp(tokens[43], "y") ||
-			string_to_policer_action(tokens[44],
-				&p[i].p[2].action[e_RTE_METER_YELLOW]) ||
-			strcmp(tokens[45], "r") ||
-			string_to_policer_action(tokens[46],
-				&p[i].p[2].action[e_RTE_METER_RED]) ||
-
-			/* meter & policer 3 */
-			strcmp(tokens[47], "meter") ||
-			strcmp(tokens[48], "3") ||
-			strcmp(tokens[49], "trtcm") ||
-			parser_read_uint64(&p[i].m[3].cir, tokens[50]) ||
-			parser_read_uint64(&p[i].m[3].pir, tokens[51]) ||
-			parser_read_uint64(&p[i].m[3].cbs, tokens[52]) ||
-			parser_read_uint64(&p[i].m[3].pbs, tokens[53]) ||
-			strcmp(tokens[54], "policer") ||
-			strcmp(tokens[55], "3") ||
-			strcmp(tokens[56], "g") ||
-			string_to_policer_action(tokens[57],
-				&p[i].p[3].action[e_RTE_METER_GREEN]) ||
-			strcmp(tokens[58], "y") ||
-			string_to_policer_action(tokens[59],
-				&p[i].p[3].action[e_RTE_METER_YELLOW]) ||
-			strcmp(tokens[60], "r") ||
-			string_to_policer_action(tokens[61],
-				&p[i].p[3].action[e_RTE_METER_RED]) ||
-
-			/* port */
-			strcmp(tokens[62], "port") ||
-			parser_read_uint32(&p[i].port_id, tokens[63]))
-			goto error1;
-
-		i++;
-	}
-
-	/* Close file */
-	*n_flows = i;
-	fclose(f);
-	return 0;
-
-error1:
-	*line = l;
-	fclose(f);
-	return -1;
-}
-
-/*
- * action
- *
- * flow meter, policer and output port configuration:
- *    p <pipelineid> action flow <flowid> meter <meterid> trtcm <cir> <pir> <cbs> <pbs>
- *
- *    p <pipelineid> action flow <flowid> policer <policerid> g <gaction> y <yaction> r <raction>
- *  <action> is one of the following:
- *      G = recolor to green
- *      Y = recolor as yellow
- *      R = recolor as red
- *      D = drop
- *
- *    p <pipelineid> action flow <flowid> port <port ID>
- *
- *    p <pipelineid> action flow bulk <file>
- *
- * flow policer stats read:
- *    p <pipelineid> action flow <flowid> stats
- *
- * flow ls:
- *    p <pipelineid> action flow ls
- *
- * dscp table configuration:
- *    p <pipelineid> action dscp <dscpid> class <class ID> color <color>
- *
- * dscp table ls:
- *    p <pipelineid> action dscp ls
-**/
-
-struct cmd_action_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t action_string;
-	cmdline_multi_string_t multi_string;
-};
-
-static void
-cmd_action_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_action_result *params = parsed_result;
-	struct app_params *app = data;
-
-	char *tokens[16];
-	uint32_t n_tokens = RTE_DIM(tokens);
-	int status;
-
-	status = parse_tokenize_string(params->multi_string, tokens, &n_tokens);
-	if (status != 0) {
-		printf(CMD_MSG_TOO_MANY_ARGS, "action");
-		return;
-	}
-
-	/* action flow meter */
-	if ((n_tokens >= 3) &&
-		(strcmp(tokens[0], "flow") == 0) &&
-		strcmp(tokens[1], "bulk") &&
-		strcmp(tokens[1], "ls") &&
-		(strcmp(tokens[2], "meter") == 0)) {
-		struct pipeline_fa_flow_params flow_params;
-		uint32_t flow_id, meter_id;
-
-		if (n_tokens != 9) {
-			printf(CMD_MSG_MISMATCH_ARGS, "action flow meter");
-			return;
-		}
-
-		memset(&flow_params, 0, sizeof(flow_params));
-
-		if (parser_read_uint32(&flow_id, tokens[1])) {
-			printf(CMD_MSG_INVALID_ARG, "flowid");
-			return;
-		}
-
-		if (parser_read_uint32(&meter_id, tokens[3]) ||
-			(meter_id >= PIPELINE_FA_N_TC_MAX)) {
-			printf(CMD_MSG_INVALID_ARG, "meterid");
-			return;
-		}
-
-		if (strcmp(tokens[4], "trtcm")) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "trtcm");
-			return;
-		}
-
-		if (parser_read_uint64(&flow_params.m[meter_id].cir, tokens[5])) {
-			printf(CMD_MSG_INVALID_ARG, "cir");
-			return;
-		}
-
-		if (parser_read_uint64(&flow_params.m[meter_id].pir, tokens[6])) {
-			printf(CMD_MSG_INVALID_ARG, "pir");
-			return;
-		}
-
-		if (parser_read_uint64(&flow_params.m[meter_id].cbs, tokens[7])) {
-			printf(CMD_MSG_INVALID_ARG, "cbs");
-			return;
-		}
-
-		if (parser_read_uint64(&flow_params.m[meter_id].pbs, tokens[8])) {
-			printf(CMD_MSG_INVALID_ARG, "pbs");
-			return;
-		}
-
-		status = app_pipeline_fa_flow_config(app,
-			params->pipeline_id,
-			flow_id,
-			1 << meter_id,
-			0,
-			0,
-			&flow_params);
-		if (status)
-			printf(CMD_MSG_FAIL, "action flow meter");
-
-		return;
-	} /* action flow meter */
-
-	/* action flow policer */
-	if ((n_tokens >= 3) &&
-		(strcmp(tokens[0], "flow") == 0) &&
-		strcmp(tokens[1], "bulk") &&
-		strcmp(tokens[1], "ls") &&
-		(strcmp(tokens[2], "policer") == 0)) {
-		struct pipeline_fa_flow_params flow_params;
-		uint32_t flow_id, policer_id;
-
-		if (n_tokens != 10) {
-			printf(CMD_MSG_MISMATCH_ARGS, "action flow policer");
-			return;
-		}
-
-		memset(&flow_params, 0, sizeof(flow_params));
-
-		if (parser_read_uint32(&flow_id, tokens[1])) {
-			printf(CMD_MSG_INVALID_ARG, "flowid");
-			return;
-		}
-
-		if (parser_read_uint32(&policer_id, tokens[3]) ||
-			(policer_id >= PIPELINE_FA_N_TC_MAX)) {
-			printf(CMD_MSG_INVALID_ARG, "policerid");
-			return;
-		}
-
-		if (strcmp(tokens[4], "g")) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "g");
-			return;
-		}
-
-		if (string_to_policer_action(tokens[5],
-			&flow_params.p[policer_id].action[e_RTE_METER_GREEN])) {
-			printf(CMD_MSG_INVALID_ARG, "gaction");
-			return;
-		}
-
-		if (strcmp(tokens[6], "y")) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "y");
-			return;
-		}
-
-		if (string_to_policer_action(tokens[7],
-			&flow_params.p[policer_id].action[e_RTE_METER_YELLOW])) {
-			printf(CMD_MSG_INVALID_ARG, "yaction");
-			return;
-		}
-
-		if (strcmp(tokens[8], "r")) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "r");
-			return;
-		}
-
-		if (string_to_policer_action(tokens[9],
-			&flow_params.p[policer_id].action[e_RTE_METER_RED])) {
-			printf(CMD_MSG_INVALID_ARG, "raction");
-			return;
-		}
-
-		status = app_pipeline_fa_flow_config(app,
-			params->pipeline_id,
-			flow_id,
-			0,
-			1 << policer_id,
-			0,
-			&flow_params);
-		if (status != 0)
-			printf(CMD_MSG_FAIL, "action flow policer");
-
-		return;
-	} /* action flow policer */
-
-	/* action flow port */
-	if ((n_tokens >= 3) &&
-		(strcmp(tokens[0], "flow") == 0) &&
-		strcmp(tokens[1], "bulk") &&
-		strcmp(tokens[1], "ls") &&
-		(strcmp(tokens[2], "port") == 0)) {
-		struct pipeline_fa_flow_params flow_params;
-		uint32_t flow_id, port_id;
-
-		if (n_tokens != 4) {
-			printf(CMD_MSG_MISMATCH_ARGS, "action flow port");
-			return;
-		}
-
-		memset(&flow_params, 0, sizeof(flow_params));
-
-		if (parser_read_uint32(&flow_id, tokens[1])) {
-			printf(CMD_MSG_INVALID_ARG, "flowid");
-			return;
-		}
-
-		if (parser_read_uint32(&port_id, tokens[3])) {
-			printf(CMD_MSG_INVALID_ARG, "portid");
-			return;
-		}
-
-		flow_params.port_id = port_id;
-
-		status = app_pipeline_fa_flow_config(app,
-			params->pipeline_id,
-			flow_id,
-			0,
-			0,
-			1,
-			&flow_params);
-		if (status)
-			printf(CMD_MSG_FAIL, "action flow port");
-
-		return;
-	} /* action flow port */
-
-	/* action flow stats */
-	if ((n_tokens >= 3) &&
-		(strcmp(tokens[0], "flow") == 0) &&
-		strcmp(tokens[1], "bulk") &&
-		strcmp(tokens[1], "ls") &&
-		(strcmp(tokens[2], "stats") == 0)) {
-		struct pipeline_fa_policer_stats stats;
-		uint32_t flow_id, policer_id;
-
-		if (n_tokens != 3) {
-			printf(CMD_MSG_MISMATCH_ARGS, "action flow stats");
-			return;
-		}
-
-		if (parser_read_uint32(&flow_id, tokens[1])) {
-			printf(CMD_MSG_INVALID_ARG, "flowid");
-			return;
-		}
-
-		for (policer_id = 0;
-			policer_id < PIPELINE_FA_N_TC_MAX;
-			policer_id++) {
-			status = app_pipeline_fa_flow_policer_stats_read(app,
-				params->pipeline_id,
-				flow_id,
-				policer_id,
-				1,
-				&stats);
-			if (status != 0) {
-				printf(CMD_MSG_FAIL, "action flow stats");
-				return;
-			}
-
-			/* Display stats */
-			printf("\tPolicer: %" PRIu32
-				"\tPkts G: %" PRIu64
-				"\tPkts Y: %" PRIu64
-				"\tPkts R: %" PRIu64
-				"\tPkts D: %" PRIu64 "\n",
-				policer_id,
-				stats.n_pkts[e_RTE_METER_GREEN],
-				stats.n_pkts[e_RTE_METER_YELLOW],
-				stats.n_pkts[e_RTE_METER_RED],
-				stats.n_pkts_drop);
-		}
-
-		return;
-	} /* action flow stats */
-
-	/* action flow bulk */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "flow") == 0) &&
-		(strcmp(tokens[1], "bulk") == 0)) {
-		struct pipeline_fa_flow_params *flow_params;
-		uint32_t *flow_ids, n_flows, line;
-		char *filename;
-
-		if (n_tokens != 3) {
-			printf(CMD_MSG_MISMATCH_ARGS, "action flow bulk");
-			return;
-		}
-
-		filename = tokens[2];
-
-		n_flows = APP_PIPELINE_FA_MAX_RECORDS_IN_FILE;
-		flow_ids = malloc(n_flows * sizeof(uint32_t));
-		if (flow_ids == NULL) {
-			printf(CMD_MSG_OUT_OF_MEMORY);
-			return;
-		}
-
-		flow_params = malloc(n_flows * sizeof(struct pipeline_fa_flow_params));
-		if (flow_params == NULL) {
-			printf(CMD_MSG_OUT_OF_MEMORY);
-			free(flow_ids);
-			return;
-		}
-
-		status = app_pipeline_fa_load_file(filename,
-			flow_ids,
-			flow_params,
-			&n_flows,
-			&line);
-		if (status) {
-			printf(CMD_MSG_FILE_ERR, filename, line);
-			free(flow_params);
-			free(flow_ids);
-			return;
-		}
-
-		status = app_pipeline_fa_flow_config_bulk(app,
-			params->pipeline_id,
-			flow_ids,
-			n_flows,
-			0xF,
-			0xF,
-			1,
-			flow_params);
-		if (status)
-			printf(CMD_MSG_FAIL, "action flow bulk");
-
-		free(flow_params);
-		free(flow_ids);
-		return;
-	} /* action flow bulk */
-
-	/* action flow ls */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "flow") == 0) &&
-		(strcmp(tokens[1], "ls") == 0)) {
-		if (n_tokens != 2) {
-			printf(CMD_MSG_MISMATCH_ARGS, "action flow ls");
-			return;
-		}
-
-		status = app_pipeline_fa_flow_ls(app,
-			params->pipeline_id);
-		if (status)
-			printf(CMD_MSG_FAIL, "action flow ls");
-
-		return;
-	} /* action flow ls */
-
-	/* action dscp */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "dscp") == 0) &&
-		strcmp(tokens[1], "ls")) {
-		uint32_t dscp_id, tc_id;
-		enum rte_meter_color color;
-
-		if (n_tokens != 6) {
-			printf(CMD_MSG_MISMATCH_ARGS, "action dscp");
-			return;
-		}
-
-		if (parser_read_uint32(&dscp_id, tokens[1])) {
-			printf(CMD_MSG_INVALID_ARG, "dscpid");
-			return;
-		}
-
-		if (strcmp(tokens[2], "class")) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "class");
-			return;
-		}
-
-		if (parser_read_uint32(&tc_id, tokens[3])) {
-			printf(CMD_MSG_INVALID_ARG, "classid");
-			return;
-		}
-
-		if (strcmp(tokens[4], "color")) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "color");
-			return;
-		}
-
-		if (string_to_color(tokens[5], &color)) {
-			printf(CMD_MSG_INVALID_ARG, "colorid");
-			return;
-		}
-
-		status = app_pipeline_fa_dscp_config(app,
-			params->pipeline_id,
-			dscp_id,
-			tc_id,
-			color);
-		if (status != 0)
-			printf(CMD_MSG_FAIL, "action dscp");
-
-		return;
-	} /* action dscp */
-
-	/* action dscp ls */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "dscp") == 0) &&
-		(strcmp(tokens[1], "ls") == 0)) {
-		if (n_tokens != 2) {
-			printf(CMD_MSG_MISMATCH_ARGS, "action dscp ls");
-			return;
-		}
-
-		status = app_pipeline_fa_dscp_ls(app,
-			params->pipeline_id);
-		if (status)
-			printf(CMD_MSG_FAIL, "action dscp ls");
-
-		return;
-	} /* action dscp ls */
-
-	printf(CMD_MSG_FAIL, "action");
-}
-
-static cmdline_parse_token_string_t cmd_action_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_action_result, p_string, "p");
-
-static cmdline_parse_token_num_t cmd_action_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_action_result, pipeline_id, UINT32);
-
-static cmdline_parse_token_string_t cmd_action_action_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_action_result, action_string, "action");
-
-static cmdline_parse_token_string_t cmd_action_multi_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_action_result, multi_string,
-	TOKEN_STRING_MULTI);
-
-cmdline_parse_inst_t cmd_action = {
-	.f = cmd_action_parsed,
-	.data = NULL,
-	.help_str = "flow actions (meter, policer, policer stats, dscp table)",
-	.tokens = {
-		(void *) &cmd_action_p_string,
-		(void *) &cmd_action_pipeline_id,
-		(void *) &cmd_action_action_string,
-		(void *) &cmd_action_multi_string,
-		NULL,
-	},
-};
-
-static cmdline_parse_ctx_t pipeline_cmds[] = {
-	(cmdline_parse_inst_t *) &cmd_action,
-	NULL,
-};
-
-static struct pipeline_fe_ops pipeline_flow_actions_fe_ops = {
-	.f_init = app_pipeline_fa_init,
-	.f_post_init = NULL,
-	.f_free = app_pipeline_fa_free,
-	.f_track = app_pipeline_track_default,
-	.cmds = pipeline_cmds,
-};
-
-struct pipeline_type pipeline_flow_actions = {
-	.name = "FLOW_ACTIONS",
-	.be_ops = &pipeline_flow_actions_be_ops,
-	.fe_ops = &pipeline_flow_actions_fe_ops,
-};
diff --git a/examples/ip_pipeline/pipeline/pipeline_flow_actions.h b/examples/ip_pipeline/pipeline/pipeline_flow_actions.h
deleted file mode 100644
index 885923e..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_flow_actions.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#ifndef __INCLUDE_PIPELINE_FLOW_ACTIONS_H__
-#define __INCLUDE_PIPELINE_FLOW_ACTIONS_H__
-
-#include <rte_meter.h>
-
-#include "pipeline.h"
-#include "pipeline_flow_actions_be.h"
-
-int
-app_pipeline_fa_flow_config(struct app_params *app,
-	uint32_t pipeline_id,
-	uint32_t flow_id,
-	uint32_t meter_update_mask,
-	uint32_t policer_update_mask,
-	uint32_t port_update,
-	struct pipeline_fa_flow_params *params);
-
-int
-app_pipeline_fa_flow_config_bulk(struct app_params *app,
-	uint32_t pipeline_id,
-	uint32_t *flow_id,
-	uint32_t n_flows,
-	uint32_t meter_update_mask,
-	uint32_t policer_update_mask,
-	uint32_t port_update,
-	struct pipeline_fa_flow_params *params);
-
-int
-app_pipeline_fa_dscp_config(struct app_params *app,
-	uint32_t pipeline_id,
-	uint32_t dscp,
-	uint32_t traffic_class,
-	enum rte_meter_color color);
-
-int
-app_pipeline_fa_flow_policer_stats_read(struct app_params *app,
-	uint32_t pipeline_id,
-	uint32_t flow_id,
-	uint32_t policer_id,
-	int clear,
-	struct pipeline_fa_policer_stats *stats);
-
-#ifndef APP_PIPELINE_FA_MAX_RECORDS_IN_FILE
-#define APP_PIPELINE_FA_MAX_RECORDS_IN_FILE		65536
-#endif
-
-int
-app_pipeline_fa_load_file(char *filename,
-	uint32_t *flow_ids,
-	struct pipeline_fa_flow_params *p,
-	uint32_t *n_flows,
-	uint32_t *line);
-
-extern struct pipeline_type pipeline_flow_actions;
-
-#endif
diff --git a/examples/ip_pipeline/pipeline/pipeline_flow_actions_be.c b/examples/ip_pipeline/pipeline/pipeline_flow_actions_be.c
deleted file mode 100644
index 33f1c41..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_flow_actions_be.c
+++ /dev/null
@@ -1,983 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2016 Intel Corporation
- */
-
-#include <string.h>
-
-#include <rte_common.h>
-#include <rte_malloc.h>
-#include <rte_cycles.h>
-#include <rte_table_array.h>
-#include <rte_byteorder.h>
-#include <rte_ip.h>
-
-#include "pipeline_actions_common.h"
-#include "pipeline_flow_actions_be.h"
-#include "parser.h"
-#include "hash_func.h"
-
-int
-pipeline_fa_flow_params_set_default(struct pipeline_fa_flow_params *params)
-{
-	uint32_t i;
-
-	if (params == NULL)
-		return -1;
-
-	for (i = 0; i < PIPELINE_FA_N_TC_MAX; i++) {
-		struct rte_meter_trtcm_params *m = &params->m[i];
-
-		m->cir = 1;
-		m->cbs = 1;
-		m->pir = 1;
-		m->pbs = 2;
-	}
-
-	for (i = 0; i < PIPELINE_FA_N_TC_MAX; i++) {
-		struct pipeline_fa_policer_params *p = &params->p[i];
-		uint32_t j;
-
-		for (j = 0; j < e_RTE_METER_COLORS; j++) {
-			struct pipeline_fa_policer_action *a = &p->action[j];
-
-			a->drop = 0;
-			a->color = (enum rte_meter_color) j;
-		}
-	}
-
-	params->port_id = 0;
-
-	return 0;
-}
-
-struct dscp_entry {
-	uint32_t traffic_class;
-	enum rte_meter_color color;
-};
-
-struct pipeline_flow_actions {
-	struct pipeline p;
-	struct pipeline_fa_params params;
-	pipeline_msg_req_handler custom_handlers[PIPELINE_FA_MSG_REQS];
-
-	struct dscp_entry dscp[PIPELINE_FA_N_DSCP];
-} __rte_cache_aligned;
-
-static void *
-pipeline_fa_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_fa_msg_req_custom_handler,
-};
-
-static void *
-pipeline_fa_msg_req_flow_config_handler(struct pipeline *p, void *msg);
-
-static void *
-pipeline_fa_msg_req_flow_config_bulk_handler(struct pipeline *p, void *msg);
-
-static void *
-pipeline_fa_msg_req_dscp_config_handler(struct pipeline *p, void *msg);
-
-static void *
-pipeline_fa_msg_req_policer_stats_read_handler(struct pipeline *p, void *msg);
-
-static pipeline_msg_req_handler custom_handlers[] = {
-	[PIPELINE_FA_MSG_REQ_FLOW_CONFIG] =
-		pipeline_fa_msg_req_flow_config_handler,
-	[PIPELINE_FA_MSG_REQ_FLOW_CONFIG_BULK] =
-		pipeline_fa_msg_req_flow_config_bulk_handler,
-	[PIPELINE_FA_MSG_REQ_DSCP_CONFIG] =
-		pipeline_fa_msg_req_dscp_config_handler,
-	[PIPELINE_FA_MSG_REQ_POLICER_STATS_READ] =
-		pipeline_fa_msg_req_policer_stats_read_handler,
-};
-
-/*
- * Flow table
- */
-struct meter_policer {
-	struct rte_meter_trtcm meter;
-	struct rte_meter_trtcm_profile meter_profile;
-	struct pipeline_fa_policer_params policer;
-	struct pipeline_fa_policer_stats stats;
-};
-
-struct flow_table_entry {
-	struct rte_pipeline_table_entry head;
-	struct meter_policer mp[PIPELINE_FA_N_TC_MAX];
-};
-
-static int
-flow_table_entry_set_meter(struct flow_table_entry *entry,
-	uint32_t meter_id,
-	struct pipeline_fa_flow_params *params)
-{
-	struct rte_meter_trtcm *meter = &entry->mp[meter_id].meter;
-	struct rte_meter_trtcm_params *meter_params = &params->m[meter_id];
-	struct rte_meter_trtcm_profile *meter_profile =
-					&entry->mp[meter_id].meter_profile;
-	int status;
-
-	status = rte_meter_trtcm_profile_config(meter_profile, meter_params);
-	if (status)
-		return status;
-
-	return rte_meter_trtcm_config(meter, meter_profile);
-}
-
-static void
-flow_table_entry_set_policer(struct flow_table_entry *entry,
-	uint32_t policer_id,
-	struct pipeline_fa_flow_params *params)
-{
-	struct pipeline_fa_policer_params *p0 = &entry->mp[policer_id].policer;
-	struct pipeline_fa_policer_params *p1 = &params->p[policer_id];
-
-	memcpy(p0, p1, sizeof(*p0));
-}
-
-static void
-flow_table_entry_set_port_id(struct pipeline_flow_actions *p,
-	struct flow_table_entry *entry,
-	struct pipeline_fa_flow_params *params)
-{
-	entry->head.action = RTE_PIPELINE_ACTION_PORT;
-	entry->head.port_id = p->p.port_out_id[params->port_id];
-}
-
-static int
-flow_table_entry_set_default(struct pipeline_flow_actions *p,
-	struct flow_table_entry *entry)
-{
-	struct pipeline_fa_flow_params params;
-	uint32_t i;
-
-	pipeline_fa_flow_params_set_default(&params);
-
-	memset(entry, 0, sizeof(*entry));
-
-	flow_table_entry_set_port_id(p, entry, &params);
-
-	for (i = 0; i < PIPELINE_FA_N_TC_MAX; i++) {
-		int status;
-
-		status = flow_table_entry_set_meter(entry, i, &params);
-		if (status)
-			return status;
-	}
-
-	for (i = 0; i < PIPELINE_FA_N_TC_MAX; i++)
-		flow_table_entry_set_policer(entry, i, &params);
-
-	return 0;
-}
-
-static inline uint64_t
-pkt_work(
-	struct rte_mbuf *pkt,
-	struct rte_pipeline_table_entry *table_entry,
-	void *arg,
-	uint64_t time)
-{
-	struct pipeline_flow_actions *p = arg;
-	struct flow_table_entry *entry =
-		(struct flow_table_entry *) table_entry;
-
-	struct ipv4_hdr *pkt_ip = (struct ipv4_hdr *)
-		RTE_MBUF_METADATA_UINT32_PTR(pkt, p->params.ip_hdr_offset);
-	enum rte_meter_color *pkt_color = (enum rte_meter_color *)
-		RTE_MBUF_METADATA_UINT32_PTR(pkt, p->params.color_offset);
-
-	/* Read (IP header) */
-	uint32_t total_length = rte_bswap16(pkt_ip->total_length);
-	uint32_t dscp = pkt_ip->type_of_service >> 2;
-
-	uint32_t tc = p->dscp[dscp].traffic_class;
-	enum rte_meter_color color = p->dscp[dscp].color;
-
-	struct rte_meter_trtcm *meter = &entry->mp[tc].meter;
-	struct rte_meter_trtcm_profile *meter_profile =
-					&entry->mp[tc].meter_profile;
-	struct pipeline_fa_policer_params *policer = &entry->mp[tc].policer;
-	struct pipeline_fa_policer_stats *stats = &entry->mp[tc].stats;
-
-	/* Read (entry), compute */
-	enum rte_meter_color color2 = rte_meter_trtcm_color_aware_check(meter,
-		meter_profile,
-		time,
-		total_length,
-		color);
-
-	enum rte_meter_color color3 = policer->action[color2].color;
-	uint64_t drop = policer->action[color2].drop;
-
-	/* Read (entry), write (entry, color) */
-	stats->n_pkts[color3] += drop ^ 1LLU;
-	stats->n_pkts_drop += drop;
-	*pkt_color = color3;
-
-	return drop;
-}
-
-static inline uint64_t
-pkt4_work(
-	struct rte_mbuf **pkts,
-	struct rte_pipeline_table_entry **table_entries,
-	void *arg,
-	uint64_t time)
-{
-	struct pipeline_flow_actions *p = arg;
-
-	struct flow_table_entry *entry0 =
-		(struct flow_table_entry *) table_entries[0];
-	struct flow_table_entry *entry1 =
-		(struct flow_table_entry *) table_entries[1];
-	struct flow_table_entry *entry2 =
-		(struct flow_table_entry *) table_entries[2];
-	struct flow_table_entry *entry3 =
-		(struct flow_table_entry *) table_entries[3];
-
-	struct ipv4_hdr *pkt0_ip = (struct ipv4_hdr *)
-		RTE_MBUF_METADATA_UINT32_PTR(pkts[0], p->params.ip_hdr_offset);
-	struct ipv4_hdr *pkt1_ip = (struct ipv4_hdr *)
-		RTE_MBUF_METADATA_UINT32_PTR(pkts[1], p->params.ip_hdr_offset);
-	struct ipv4_hdr *pkt2_ip = (struct ipv4_hdr *)
-		RTE_MBUF_METADATA_UINT32_PTR(pkts[2], p->params.ip_hdr_offset);
-	struct ipv4_hdr *pkt3_ip = (struct ipv4_hdr *)
-		RTE_MBUF_METADATA_UINT32_PTR(pkts[3], p->params.ip_hdr_offset);
-
-	enum rte_meter_color *pkt0_color = (enum rte_meter_color *)
-		RTE_MBUF_METADATA_UINT32_PTR(pkts[0], p->params.color_offset);
-	enum rte_meter_color *pkt1_color = (enum rte_meter_color *)
-		RTE_MBUF_METADATA_UINT32_PTR(pkts[1], p->params.color_offset);
-	enum rte_meter_color *pkt2_color = (enum rte_meter_color *)
-		RTE_MBUF_METADATA_UINT32_PTR(pkts[2], p->params.color_offset);
-	enum rte_meter_color *pkt3_color = (enum rte_meter_color *)
-		RTE_MBUF_METADATA_UINT32_PTR(pkts[3], p->params.color_offset);
-
-	/* Read (IP header) */
-	uint32_t total_length0 = rte_bswap16(pkt0_ip->total_length);
-	uint32_t dscp0 = pkt0_ip->type_of_service >> 2;
-
-	uint32_t total_length1 = rte_bswap16(pkt1_ip->total_length);
-	uint32_t dscp1 = pkt1_ip->type_of_service >> 2;
-
-	uint32_t total_length2 = rte_bswap16(pkt2_ip->total_length);
-	uint32_t dscp2 = pkt2_ip->type_of_service >> 2;
-
-	uint32_t total_length3 = rte_bswap16(pkt3_ip->total_length);
-	uint32_t dscp3 = pkt3_ip->type_of_service >> 2;
-
-	uint32_t tc0 = p->dscp[dscp0].traffic_class;
-	enum rte_meter_color color0 = p->dscp[dscp0].color;
-
-	uint32_t tc1 = p->dscp[dscp1].traffic_class;
-	enum rte_meter_color color1 = p->dscp[dscp1].color;
-
-	uint32_t tc2 = p->dscp[dscp2].traffic_class;
-	enum rte_meter_color color2 = p->dscp[dscp2].color;
-
-	uint32_t tc3 = p->dscp[dscp3].traffic_class;
-	enum rte_meter_color color3 = p->dscp[dscp3].color;
-
-	struct rte_meter_trtcm *meter0 = &entry0->mp[tc0].meter;
-	struct rte_meter_trtcm_profile *meter0_profile =
-				&entry0->mp[tc0].meter_profile;
-	struct pipeline_fa_policer_params *policer0 = &entry0->mp[tc0].policer;
-	struct pipeline_fa_policer_stats *stats0 = &entry0->mp[tc0].stats;
-
-	struct rte_meter_trtcm *meter1 = &entry1->mp[tc1].meter;
-	struct rte_meter_trtcm_profile *meter1_profile =
-				&entry1->mp[tc1].meter_profile;
-	struct pipeline_fa_policer_params *policer1 = &entry1->mp[tc1].policer;
-	struct pipeline_fa_policer_stats *stats1 = &entry1->mp[tc1].stats;
-
-	struct rte_meter_trtcm *meter2 = &entry2->mp[tc2].meter;
-	struct rte_meter_trtcm_profile *meter2_profile =
-				&entry2->mp[tc2].meter_profile;
-	struct pipeline_fa_policer_params *policer2 = &entry2->mp[tc2].policer;
-	struct pipeline_fa_policer_stats *stats2 = &entry2->mp[tc2].stats;
-
-	struct rte_meter_trtcm *meter3 = &entry3->mp[tc3].meter;
-	struct rte_meter_trtcm_profile *meter3_profile =
-				&entry3->mp[tc3].meter_profile;
-	struct pipeline_fa_policer_params *policer3 = &entry3->mp[tc3].policer;
-	struct pipeline_fa_policer_stats *stats3 = &entry3->mp[tc3].stats;
-
-	/* Read (entry), compute, write (entry) */
-	enum rte_meter_color color2_0 = rte_meter_trtcm_color_aware_check(
-		meter0,
-		meter0_profile,
-		time,
-		total_length0,
-		color0);
-
-	enum rte_meter_color color2_1 = rte_meter_trtcm_color_aware_check(
-		meter1,
-		meter1_profile,
-		time,
-		total_length1,
-		color1);
-
-	enum rte_meter_color color2_2 = rte_meter_trtcm_color_aware_check(
-		meter2,
-		meter2_profile,
-		time,
-		total_length2,
-		color2);
-
-	enum rte_meter_color color2_3 = rte_meter_trtcm_color_aware_check(
-		meter3,
-		meter3_profile,
-		time,
-		total_length3,
-		color3);
-
-	enum rte_meter_color color3_0 = policer0->action[color2_0].color;
-	enum rte_meter_color color3_1 = policer1->action[color2_1].color;
-	enum rte_meter_color color3_2 = policer2->action[color2_2].color;
-	enum rte_meter_color color3_3 = policer3->action[color2_3].color;
-
-	uint64_t drop0 = policer0->action[color2_0].drop;
-	uint64_t drop1 = policer1->action[color2_1].drop;
-	uint64_t drop2 = policer2->action[color2_2].drop;
-	uint64_t drop3 = policer3->action[color2_3].drop;
-
-	/* Read (entry), write (entry, color) */
-	stats0->n_pkts[color3_0] += drop0 ^ 1LLU;
-	stats0->n_pkts_drop += drop0;
-
-	stats1->n_pkts[color3_1] += drop1 ^ 1LLU;
-	stats1->n_pkts_drop += drop1;
-
-	stats2->n_pkts[color3_2] += drop2 ^ 1LLU;
-	stats2->n_pkts_drop += drop2;
-
-	stats3->n_pkts[color3_3] += drop3 ^ 1LLU;
-	stats3->n_pkts_drop += drop3;
-
-	*pkt0_color = color3_0;
-	*pkt1_color = color3_1;
-	*pkt2_color = color3_2;
-	*pkt3_color = color3_3;
-
-	return drop0 | (drop1 << 1) | (drop2 << 2) | (drop3 << 3);
-}
-
-PIPELINE_TABLE_AH_HIT_DROP_TIME(fa_table_ah_hit, pkt_work, pkt4_work);
-
-static rte_pipeline_table_action_handler_hit
-get_fa_table_ah_hit(__rte_unused struct pipeline_flow_actions *p)
-{
-	return fa_table_ah_hit;
-}
-
-/*
- * Argument parsing
- */
-int
-pipeline_fa_parse_args(struct pipeline_fa_params *p,
-	struct pipeline_params *params)
-{
-	uint32_t n_flows_present = 0;
-	uint32_t n_meters_per_flow_present = 0;
-	uint32_t flow_id_offset_present = 0;
-	uint32_t ip_hdr_offset_present = 0;
-	uint32_t color_offset_present = 0;
-	uint32_t i;
-
-	/* Default values */
-	p->n_meters_per_flow = 1;
-	p->dscp_enabled = 0;
-
-	for (i = 0; i < params->n_args; i++) {
-		char *arg_name = params->args_name[i];
-		char *arg_value = params->args_value[i];
-
-		/* n_flows */
-		if (strcmp(arg_name, "n_flows") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				n_flows_present == 0, params->name,
-				arg_name);
-			n_flows_present = 1;
-
-			status = parser_read_uint32(&p->n_flows,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL(((status != -EINVAL) &&
-				(p->n_flows != 0)), params->name,
-				arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			continue;
-		}
-
-		/* n_meters_per_flow */
-		if (strcmp(arg_name, "n_meters_per_flow") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				n_meters_per_flow_present == 0,
-				params->name, arg_name);
-			n_meters_per_flow_present = 1;
-
-			status = parser_read_uint32(&p->n_meters_per_flow,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL(((status != -EINVAL) &&
-				(p->n_meters_per_flow != 0)),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG(((status != -ERANGE) &&
-				(p->n_meters_per_flow <=
-				PIPELINE_FA_N_TC_MAX)), params->name,
-				arg_name, arg_value);
-
-			continue;
-		}
-
-		/* flow_id_offset */
-		if (strcmp(arg_name, "flow_id_offset") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				flow_id_offset_present == 0,
-				params->name, arg_name);
-			flow_id_offset_present = 1;
-
-			status = parser_read_uint32(&p->flow_id_offset,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			continue;
-		}
-
-		/* ip_hdr_offset */
-		if (strcmp(arg_name, "ip_hdr_offset") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				ip_hdr_offset_present == 0,
-				params->name, arg_name);
-			ip_hdr_offset_present = 1;
-
-			status = parser_read_uint32(&p->ip_hdr_offset,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			continue;
-		}
-
-		/* color_offset */
-		if (strcmp(arg_name, "color_offset") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				color_offset_present == 0, params->name,
-				arg_name);
-			color_offset_present = 1;
-
-			status = parser_read_uint32(&p->color_offset,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			p->dscp_enabled = 1;
-
-			continue;
-		}
-
-		/* Unknown argument */
-		PIPELINE_PARSE_ERR_INV_ENT(0, params->name, arg_name);
-	}
-
-	/* Check that mandatory arguments are present */
-	PIPELINE_PARSE_ERR_MANDATORY((n_flows_present), params->name,
-		"n_flows");
-	PIPELINE_PARSE_ERR_MANDATORY((flow_id_offset_present),
-		params->name, "flow_id_offset");
-	PIPELINE_PARSE_ERR_MANDATORY((ip_hdr_offset_present),
-		params->name, "ip_hdr_offset");
-	PIPELINE_PARSE_ERR_MANDATORY((color_offset_present), params->name,
-		"color_offset");
-
-	return 0;
-}
-
-static void
-dscp_init(struct pipeline_flow_actions *p)
-{
-	uint32_t i;
-
-	for (i = 0; i < PIPELINE_FA_N_DSCP; i++) {
-		p->dscp[i].traffic_class = 0;
-		p->dscp[i].color = e_RTE_METER_GREEN;
-	}
-}
-
-static void *pipeline_fa_init(struct pipeline_params *params,
-	__rte_unused void *arg)
-{
-	struct pipeline *p;
-	struct pipeline_flow_actions *p_fa;
-	uint32_t size, i;
-
-	/* Check input arguments */
-	if (params == NULL)
-		return NULL;
-
-	if (params->n_ports_in != params->n_ports_out)
-		return NULL;
-
-	/* Memory allocation */
-	size = RTE_CACHE_LINE_ROUNDUP(
-		sizeof(struct pipeline_flow_actions));
-	p = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
-	if (p == NULL)
-		return NULL;
-	p_fa = (struct pipeline_flow_actions *) p;
-
-	strcpy(p->name, params->name);
-	p->log_level = params->log_level;
-
-	PLOG(p, HIGH, "Flow actions");
-
-	/* Parse arguments */
-	if (pipeline_fa_parse_args(&p_fa->params, params))
-		return NULL;
-
-	dscp_init(p_fa);
-
-	/* 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,
-			.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_array_params table_array_params = {
-			.n_entries = p_fa->params.n_flows,
-			.offset = p_fa->params.flow_id_offset,
-		};
-
-		struct rte_pipeline_table_params table_params = {
-			.ops = &rte_table_array_ops,
-			.arg_create = &table_array_params,
-			.f_action_hit = get_fa_table_ah_hit(p_fa),
-			.f_action_miss = NULL,
-			.arg_ah = p_fa,
-			.action_data_size =
-				sizeof(struct flow_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;
-		}
-	}
-
-	/* 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;
-		}
-	}
-
-	/* Initialize table entries */
-	for (i = 0; i < p_fa->params.n_flows; i++) {
-		struct rte_table_array_key key = {
-			.pos = i,
-		};
-
-		struct flow_table_entry entry;
-		struct rte_pipeline_table_entry *entry_ptr;
-		int key_found, status;
-
-		flow_table_entry_set_default(p_fa, &entry);
-
-		status = rte_pipeline_table_entry_add(p->p,
-			p->table_id[0],
-			&key,
-			(struct rte_pipeline_table_entry *) &entry,
-			&key_found,
-			&entry_ptr);
-
-		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_fa->custom_handlers,
-		custom_handlers,
-		sizeof(p_fa->custom_handlers));
-
-	return p;
-}
-
-static int
-pipeline_fa_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_fa_timer(void *pipeline)
-{
-	struct pipeline *p = (struct pipeline *) pipeline;
-
-	pipeline_msg_req_handle(p);
-	rte_pipeline_flush(p->p);
-
-	return 0;
-}
-
-void *
-pipeline_fa_msg_req_custom_handler(struct pipeline *p, void *msg)
-{
-	struct pipeline_flow_actions *p_fa =
-			(struct pipeline_flow_actions *) p;
-	struct pipeline_custom_msg_req *req = msg;
-	pipeline_msg_req_handler f_handle;
-
-	f_handle = (req->subtype < PIPELINE_FA_MSG_REQS) ?
-		p_fa->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_fa_msg_req_flow_config_handler(struct pipeline *p, void *msg)
-{
-	struct pipeline_flow_actions *p_fa = (struct pipeline_flow_actions *) p;
-	struct pipeline_fa_flow_config_msg_req *req = msg;
-	struct pipeline_fa_flow_config_msg_rsp *rsp = msg;
-	struct flow_table_entry *entry;
-	uint32_t mask, i;
-
-	/* Set flow table entry to default if not configured before */
-	if (req->entry_ptr == NULL) {
-		struct rte_table_array_key key = {
-			.pos = req->flow_id % p_fa->params.n_flows,
-		};
-
-		struct flow_table_entry default_entry;
-
-		int key_found, status;
-
-		flow_table_entry_set_default(p_fa, &default_entry);
-
-		status = rte_pipeline_table_entry_add(p->p,
-			p->table_id[0],
-			&key,
-			(struct rte_pipeline_table_entry *) &default_entry,
-			&key_found,
-			(struct rte_pipeline_table_entry **) &entry);
-		if (status) {
-			rsp->status = -1;
-			return rsp;
-		}
-	} else
-		entry = (struct flow_table_entry *) req->entry_ptr;
-
-	/* Meter */
-	for (i = 0, mask = 1; i < PIPELINE_FA_N_TC_MAX; i++, mask <<= 1) {
-		int status;
-
-		if ((mask & req->meter_update_mask) == 0)
-			continue;
-
-		status = flow_table_entry_set_meter(entry, i, &req->params);
-		if (status) {
-			rsp->status = -1;
-			return rsp;
-		}
-	}
-
-	/* Policer */
-	for (i = 0, mask = 1; i < PIPELINE_FA_N_TC_MAX; i++, mask <<= 1) {
-		if ((mask & req->policer_update_mask) == 0)
-			continue;
-
-		flow_table_entry_set_policer(entry, i, &req->params);
-	}
-
-	/* Port */
-	if (req->port_update)
-		flow_table_entry_set_port_id(p_fa, entry, &req->params);
-
-	/* Response */
-	rsp->status = 0;
-	rsp->entry_ptr = (void *) entry;
-	return rsp;
-}
-
-void *
-pipeline_fa_msg_req_flow_config_bulk_handler(struct pipeline *p, void *msg)
-{
-	struct pipeline_flow_actions *p_fa = (struct pipeline_flow_actions *) p;
-	struct pipeline_fa_flow_config_bulk_msg_req *req = msg;
-	struct pipeline_fa_flow_config_bulk_msg_rsp *rsp = msg;
-	uint32_t i;
-
-	for (i = 0; i < req->n_flows; i++) {
-		struct flow_table_entry *entry;
-		uint32_t j, mask;
-
-		/* Set flow table entry to default if not configured before */
-		if (req->entry_ptr[i] == NULL) {
-			struct rte_table_array_key key = {
-				.pos = req->flow_id[i] % p_fa->params.n_flows,
-			};
-
-			struct flow_table_entry entry_to_add;
-
-			int key_found, status;
-
-			flow_table_entry_set_default(p_fa, &entry_to_add);
-
-			status = rte_pipeline_table_entry_add(p->p,
-			 p->table_id[0],
-			 &key,
-			 (struct rte_pipeline_table_entry *) &entry_to_add,
-			 &key_found,
-			 (struct rte_pipeline_table_entry **) &entry);
-			if (status) {
-				rsp->n_flows = i;
-				return rsp;
-			}
-
-			req->entry_ptr[i] = (void *) entry;
-		} else
-			entry = (struct flow_table_entry *) req->entry_ptr[i];
-
-		/* Meter */
-		for (j = 0, mask = 1;
-			j < PIPELINE_FA_N_TC_MAX;
-			j++, mask <<= 1) {
-			int status;
-
-			if ((mask & req->meter_update_mask) == 0)
-				continue;
-
-			status = flow_table_entry_set_meter(entry,
-				j, &req->params[i]);
-			if (status) {
-				rsp->n_flows = i;
-				return rsp;
-			}
-		}
-
-		/* Policer */
-		for (j = 0, mask = 1;
-			j < PIPELINE_FA_N_TC_MAX;
-			j++, mask <<= 1) {
-			if ((mask & req->policer_update_mask) == 0)
-				continue;
-
-			flow_table_entry_set_policer(entry,
-			 j, &req->params[i]);
-		}
-
-		/* Port */
-		if (req->port_update)
-			flow_table_entry_set_port_id(p_fa,
-			 entry, &req->params[i]);
-	}
-
-	/* Response */
-	rsp->n_flows = i;
-	return rsp;
-}
-
-void *
-pipeline_fa_msg_req_dscp_config_handler(struct pipeline *p, void *msg)
-{
-	struct pipeline_flow_actions *p_fa = (struct pipeline_flow_actions *) p;
-	struct pipeline_fa_dscp_config_msg_req *req = msg;
-	struct pipeline_fa_dscp_config_msg_rsp *rsp = msg;
-
-	/* Check request */
-	if ((req->dscp >= PIPELINE_FA_N_DSCP) ||
-		(req->traffic_class >= PIPELINE_FA_N_TC_MAX) ||
-		(req->color >= e_RTE_METER_COLORS)) {
-		rsp->status = -1;
-		return rsp;
-	}
-
-	p_fa->dscp[req->dscp].traffic_class = req->traffic_class;
-	p_fa->dscp[req->dscp].color = req->color;
-	rsp->status = 0;
-	return rsp;
-}
-
-void *
-pipeline_fa_msg_req_policer_stats_read_handler(__rte_unused struct pipeline *p,
-	void *msg)
-{
-	struct pipeline_fa_policer_stats_msg_req *req = msg;
-	struct pipeline_fa_policer_stats_msg_rsp *rsp = msg;
-
-	struct flow_table_entry *entry = req->entry_ptr;
-	uint32_t policer_id = req->policer_id;
-	int clear = req->clear;
-
-	/* Check request */
-	if ((req->entry_ptr == NULL) ||
-		(req->policer_id >= PIPELINE_FA_N_TC_MAX)) {
-		rsp->status = -1;
-		return rsp;
-	}
-
-	memcpy(&rsp->stats,
-		&entry->mp[policer_id].stats,
-		sizeof(rsp->stats));
-	if (clear)
-		memset(&entry->mp[policer_id].stats,
-			0, sizeof(entry->mp[policer_id].stats));
-	rsp->status = 0;
-	return rsp;
-}
-
-struct pipeline_be_ops pipeline_flow_actions_be_ops = {
-	.f_init = pipeline_fa_init,
-	.f_free = pipeline_fa_free,
-	.f_run = NULL,
-	.f_timer = pipeline_fa_timer,
-};
diff --git a/examples/ip_pipeline/pipeline/pipeline_flow_actions_be.h b/examples/ip_pipeline/pipeline/pipeline_flow_actions_be.h
deleted file mode 100644
index ef6cb26..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_flow_actions_be.h
+++ /dev/null
@@ -1,139 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#ifndef __INCLUDE_PIPELINE_FLOW_ACTIONS_BE_H__
-#define __INCLUDE_PIPELINE_FLOW_ACTIONS_BE_H__
-
-#include <rte_meter.h>
-
-#include "pipeline_common_be.h"
-
-#ifndef PIPELINE_FA_N_TC_MAX
-#define PIPELINE_FA_N_TC_MAX                               4
-#endif
-
-#define PIPELINE_FA_N_DSCP                                 64
-
-struct pipeline_fa_params {
-	uint32_t n_flows;
-	uint32_t n_meters_per_flow;
-	uint32_t flow_id_offset;
-	uint32_t ip_hdr_offset;
-	uint32_t color_offset;
-	uint32_t dscp_enabled;
-};
-
-int
-pipeline_fa_parse_args(struct pipeline_fa_params *p,
-	struct pipeline_params *params);
-
-struct pipeline_fa_policer_action {
-	uint32_t drop;
-	enum rte_meter_color color;
-};
-
-struct pipeline_fa_policer_params {
-	struct pipeline_fa_policer_action action[e_RTE_METER_COLORS];
-};
-
-struct pipeline_fa_flow_params {
-	struct rte_meter_trtcm_params m[PIPELINE_FA_N_TC_MAX];
-	struct pipeline_fa_policer_params p[PIPELINE_FA_N_TC_MAX];
-	uint32_t port_id;
-};
-
-int
-pipeline_fa_flow_params_set_default(struct pipeline_fa_flow_params *params);
-
-struct pipeline_fa_policer_stats {
-	uint64_t n_pkts[e_RTE_METER_COLORS];
-	uint64_t n_pkts_drop;
-};
-
-enum pipeline_fa_msg_req_type {
-	PIPELINE_FA_MSG_REQ_FLOW_CONFIG = 0,
-	PIPELINE_FA_MSG_REQ_FLOW_CONFIG_BULK,
-	PIPELINE_FA_MSG_REQ_DSCP_CONFIG,
-	PIPELINE_FA_MSG_REQ_POLICER_STATS_READ,
-	PIPELINE_FA_MSG_REQS,
-};
-
-/*
- * MSG FLOW CONFIG
- */
-struct pipeline_fa_flow_config_msg_req {
-	enum pipeline_msg_req_type type;
-	enum pipeline_fa_msg_req_type subtype;
-
-	void *entry_ptr;
-	uint32_t flow_id;
-
-	uint32_t meter_update_mask;
-	uint32_t policer_update_mask;
-	uint32_t port_update;
-	struct pipeline_fa_flow_params params;
-};
-
-struct pipeline_fa_flow_config_msg_rsp {
-	int status;
-	void *entry_ptr;
-};
-
-/*
- * MSG FLOW CONFIG BULK
- */
-struct pipeline_fa_flow_config_bulk_msg_req {
-	enum pipeline_msg_req_type type;
-	enum pipeline_fa_msg_req_type subtype;
-
-	void **entry_ptr;
-	uint32_t *flow_id;
-	uint32_t n_flows;
-
-	uint32_t meter_update_mask;
-	uint32_t policer_update_mask;
-	uint32_t port_update;
-	struct pipeline_fa_flow_params *params;
-};
-
-struct pipeline_fa_flow_config_bulk_msg_rsp {
-	uint32_t n_flows;
-};
-
-/*
- * MSG DSCP CONFIG
- */
-struct pipeline_fa_dscp_config_msg_req {
-	enum pipeline_msg_req_type type;
-	enum pipeline_fa_msg_req_type subtype;
-
-	uint32_t dscp;
-	uint32_t traffic_class;
-	enum rte_meter_color color;
-};
-
-struct pipeline_fa_dscp_config_msg_rsp {
-	int status;
-};
-
-/*
- * MSG POLICER STATS READ
- */
-struct pipeline_fa_policer_stats_msg_req {
-	enum pipeline_msg_req_type type;
-	enum pipeline_fa_msg_req_type subtype;
-
-	void *entry_ptr;
-	uint32_t policer_id;
-	int clear;
-};
-
-struct pipeline_fa_policer_stats_msg_rsp {
-	int status;
-	struct pipeline_fa_policer_stats stats;
-};
-
-extern struct pipeline_be_ops pipeline_flow_actions_be_ops;
-
-#endif
diff --git a/examples/ip_pipeline/pipeline/pipeline_flow_classification.c b/examples/ip_pipeline/pipeline/pipeline_flow_classification.c
deleted file mode 100644
index d39e0fb..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_flow_classification.c
+++ /dev/null
@@ -1,1878 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2016 Intel Corporation
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <sys/queue.h>
-#include <netinet/in.h>
-#include <unistd.h>
-
-#include <rte_common.h>
-#include <rte_hexdump.h>
-#include <rte_malloc.h>
-#include <cmdline_rdline.h>
-#include <cmdline_parse.h>
-#include <cmdline_parse_num.h>
-#include <cmdline_parse_string.h>
-
-#include "app.h"
-#include "pipeline_common_fe.h"
-#include "pipeline_flow_classification.h"
-#include "hash_func.h"
-#include "parser.h"
-
-/*
- * Key conversion
- */
-
-struct pkt_key_qinq {
-	uint16_t ethertype_svlan;
-	uint16_t svlan;
-	uint16_t ethertype_cvlan;
-	uint16_t cvlan;
-} __attribute__((__packed__));
-
-struct pkt_key_ipv4_5tuple {
-	uint8_t ttl;
-	uint8_t proto;
-	uint16_t checksum;
-	uint32_t ip_src;
-	uint32_t ip_dst;
-	uint16_t port_src;
-	uint16_t port_dst;
-} __attribute__((__packed__));
-
-struct pkt_key_ipv6_5tuple {
-	uint16_t payload_length;
-	uint8_t proto;
-	uint8_t hop_limit;
-	uint8_t ip_src[16];
-	uint8_t ip_dst[16];
-	uint16_t port_src;
-	uint16_t port_dst;
-} __attribute__((__packed__));
-
-static int
-app_pipeline_fc_key_convert(struct pipeline_fc_key *key_in,
-	uint8_t *key_out,
-	uint32_t *signature)
-{
-	uint8_t buffer[PIPELINE_FC_FLOW_KEY_MAX_SIZE];
-	uint8_t m[PIPELINE_FC_FLOW_KEY_MAX_SIZE]; /* key mask */
-	void *key_buffer = (key_out) ? key_out : buffer;
-
-	memset(m, 0xFF, sizeof(m));
-	switch (key_in->type) {
-	case FLOW_KEY_QINQ:
-	{
-		struct pkt_key_qinq *qinq = key_buffer;
-
-		qinq->ethertype_svlan = 0;
-		qinq->svlan = rte_cpu_to_be_16(key_in->key.qinq.svlan);
-		qinq->ethertype_cvlan = 0;
-		qinq->cvlan = rte_cpu_to_be_16(key_in->key.qinq.cvlan);
-
-		if (signature)
-			*signature = (uint32_t) hash_default_key8(qinq, m, 8, 0);
-		return 0;
-	}
-
-	case FLOW_KEY_IPV4_5TUPLE:
-	{
-		struct pkt_key_ipv4_5tuple *ipv4 = key_buffer;
-
-		ipv4->ttl = 0;
-		ipv4->proto = key_in->key.ipv4_5tuple.proto;
-		ipv4->checksum = 0;
-		ipv4->ip_src = rte_cpu_to_be_32(key_in->key.ipv4_5tuple.ip_src);
-		ipv4->ip_dst = rte_cpu_to_be_32(key_in->key.ipv4_5tuple.ip_dst);
-		ipv4->port_src = rte_cpu_to_be_16(key_in->key.ipv4_5tuple.port_src);
-		ipv4->port_dst = rte_cpu_to_be_16(key_in->key.ipv4_5tuple.port_dst);
-
-		if (signature)
-			*signature = (uint32_t) hash_default_key16(ipv4, m, 16, 0);
-		return 0;
-	}
-
-	case FLOW_KEY_IPV6_5TUPLE:
-	{
-		struct pkt_key_ipv6_5tuple *ipv6 = key_buffer;
-
-		memset(ipv6, 0, 64);
-		ipv6->payload_length = 0;
-		ipv6->proto = key_in->key.ipv6_5tuple.proto;
-		ipv6->hop_limit = 0;
-		memcpy(&ipv6->ip_src, &key_in->key.ipv6_5tuple.ip_src, 16);
-		memcpy(&ipv6->ip_dst, &key_in->key.ipv6_5tuple.ip_dst, 16);
-		ipv6->port_src = rte_cpu_to_be_16(key_in->key.ipv6_5tuple.port_src);
-		ipv6->port_dst = rte_cpu_to_be_16(key_in->key.ipv6_5tuple.port_dst);
-
-		if (signature)
-			*signature = (uint32_t) hash_default_key64(ipv6, m, 64, 0);
-		return 0;
-	}
-
-	default:
-		return -1;
-	}
-}
-
-/*
- * Flow classification pipeline
- */
-
-struct app_pipeline_fc_flow {
-	struct pipeline_fc_key key;
-	uint32_t port_id;
-	uint32_t flow_id;
-	uint32_t signature;
-	void *entry_ptr;
-
-	TAILQ_ENTRY(app_pipeline_fc_flow) node;
-};
-
-#define N_BUCKETS                                65536
-
-struct app_pipeline_fc {
-	/* Parameters */
-	uint32_t n_ports_in;
-	uint32_t n_ports_out;
-
-	/* Flows */
-	TAILQ_HEAD(, app_pipeline_fc_flow) flows[N_BUCKETS];
-	uint32_t n_flows;
-
-	/* Default flow */
-	uint32_t default_flow_present;
-	uint32_t default_flow_port_id;
-	void *default_flow_entry_ptr;
-};
-
-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;
-	uint32_t signature, bucket_id;
-
-	app_pipeline_fc_key_convert(key, NULL, &signature);
-	bucket_id = signature & (N_BUCKETS - 1);
-
-	TAILQ_FOREACH(f, &p->flows[bucket_id], node)
-		if ((signature == f->signature) &&
-			(memcmp(key,
-				&f->key,
-				sizeof(struct pipeline_fc_key)) == 0))
-			return f;
-
-	return NULL;
-}
-
-static void*
-app_pipeline_fc_init(struct pipeline_params *params,
-	__rte_unused void *arg)
-{
-	struct app_pipeline_fc *p;
-	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 app_pipeline_fc));
-	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;
-
-	for (i = 0; i < N_BUCKETS; i++)
-		TAILQ_INIT(&p->flows[i]);
-	p->n_flows = 0;
-
-	return (void *) p;
-}
-
-static int
-app_pipeline_fc_free(void *pipeline)
-{
-	struct app_pipeline_fc *p = pipeline;
-	uint32_t i;
-
-	/* Check input arguments */
-	if (p == NULL)
-		return -1;
-
-	/* Free resources */
-	for (i = 0; i < N_BUCKETS; i++)
-		while (!TAILQ_EMPTY(&p->flows[i])) {
-			struct app_pipeline_fc_flow *flow;
-
-			flow = TAILQ_FIRST(&p->flows[i]);
-			TAILQ_REMOVE(&p->flows[i], flow, node);
-			rte_free(flow);
-		}
-
-	rte_free(p);
-	return 0;
-}
-
-static int
-app_pipeline_fc_key_check(struct pipeline_fc_key *key)
-{
-	switch (key->type) {
-	case FLOW_KEY_QINQ:
-	{
-		uint16_t svlan = key->key.qinq.svlan;
-		uint16_t cvlan = key->key.qinq.cvlan;
-
-		if ((svlan & 0xF000) ||
-			(cvlan & 0xF000))
-			return -1;
-
-		return 0;
-	}
-
-	case FLOW_KEY_IPV4_5TUPLE:
-		return 0;
-
-	case FLOW_KEY_IPV6_5TUPLE:
-		return 0;
-
-	default:
-		return -1;
-	}
-}
-
-int
-app_pipeline_fc_load_file_qinq(char *filename,
-	struct pipeline_fc_key *keys,
-	uint32_t *port_ids,
-	uint32_t *flow_ids,
-	uint32_t *n_keys,
-	uint32_t *line)
-{
-	FILE *f = NULL;
-	char file_buf[1024];
-	uint32_t i, l;
-
-	/* Check input arguments */
-	if ((filename == NULL) ||
-		(keys == NULL) ||
-		(port_ids == NULL) ||
-		(flow_ids == NULL) ||
-		(n_keys == NULL) ||
-		(*n_keys == 0) ||
-		(line == NULL)) {
-		if (line)
-			*line = 0;
-		return -1;
-		}
-
-	/* Open input file */
-	f = fopen(filename, "r");
-	if (f == NULL) {
-		*line = 0;
-		return -1;
-	}
-
-	/* Read file */
-	for (i = 0, l = 1; i < *n_keys; l++) {
-		char *tokens[32];
-		uint32_t n_tokens = RTE_DIM(tokens);
-
-		uint16_t svlan, cvlan;
-		uint32_t portid, flowid;
-		int status;
-
-		if (fgets(file_buf, sizeof(file_buf), f) == NULL)
-			break;
-
-		status = parse_tokenize_string(file_buf, tokens, &n_tokens);
-		if (status)
-			goto error1;
-
-		if ((n_tokens == 0) || (tokens[0][0] == '#'))
-			continue;
-
-		if ((n_tokens != 7) ||
-			strcmp(tokens[0], "qinq") ||
-			parser_read_uint16(&svlan, tokens[1]) ||
-			parser_read_uint16(&cvlan, tokens[2]) ||
-			strcmp(tokens[3], "port") ||
-			parser_read_uint32(&portid, tokens[4]) ||
-			strcmp(tokens[5], "id") ||
-			parser_read_uint32(&flowid, tokens[6]))
-			goto error1;
-
-		keys[i].type = FLOW_KEY_QINQ;
-		keys[i].key.qinq.svlan = svlan;
-		keys[i].key.qinq.cvlan = cvlan;
-
-		port_ids[i] = portid;
-		flow_ids[i] = flowid;
-
-		if (app_pipeline_fc_key_check(&keys[i]))
-			goto error1;
-
-		i++;
-	}
-
-	/* Close file */
-	*n_keys = i;
-	fclose(f);
-	return 0;
-
-error1:
-	*line = l;
-	fclose(f);
-	return -1;
-}
-
-int
-app_pipeline_fc_load_file_ipv4(char *filename,
-	struct pipeline_fc_key *keys,
-	uint32_t *port_ids,
-	uint32_t *flow_ids,
-	uint32_t *n_keys,
-	uint32_t *line)
-{
-	FILE *f = NULL;
-	char file_buf[1024];
-	uint32_t i, l;
-
-	/* Check input arguments */
-	if ((filename == NULL) ||
-		(keys == NULL) ||
-		(port_ids == NULL) ||
-		(flow_ids == NULL) ||
-		(n_keys == NULL) ||
-		(*n_keys == 0) ||
-		(line == NULL)) {
-		if (line)
-			*line = 0;
-		return -1;
-		}
-
-	/* Open input file */
-	f = fopen(filename, "r");
-	if (f == NULL) {
-		*line = 0;
-		return -1;
-	}
-
-	/* Read file */
-	for (i = 0, l = 1; i < *n_keys; l++) {
-		char *tokens[32];
-		uint32_t n_tokens = RTE_DIM(tokens);
-
-		struct in_addr sipaddr, dipaddr;
-		uint16_t sport, dport;
-		uint8_t proto;
-		uint32_t portid, flowid;
-		int status;
-
-		if (fgets(file_buf, sizeof(file_buf), f) == NULL)
-			break;
-
-		status = parse_tokenize_string(file_buf, tokens, &n_tokens);
-		if (status)
-			goto error2;
-
-		if ((n_tokens == 0) || (tokens[0][0] == '#'))
-			continue;
-
-		if ((n_tokens != 10) ||
-			strcmp(tokens[0], "ipv4") ||
-			parse_ipv4_addr(tokens[1], &sipaddr) ||
-			parse_ipv4_addr(tokens[2], &dipaddr) ||
-			parser_read_uint16(&sport, tokens[3]) ||
-			parser_read_uint16(&dport, tokens[4]) ||
-			parser_read_uint8(&proto, tokens[5]) ||
-			strcmp(tokens[6], "port") ||
-			parser_read_uint32(&portid, tokens[7]) ||
-			strcmp(tokens[8], "id") ||
-			parser_read_uint32(&flowid, tokens[9]))
-			goto error2;
-
-		keys[i].type = FLOW_KEY_IPV4_5TUPLE;
-		keys[i].key.ipv4_5tuple.ip_src = rte_be_to_cpu_32(sipaddr.s_addr);
-		keys[i].key.ipv4_5tuple.ip_dst = rte_be_to_cpu_32(dipaddr.s_addr);
-		keys[i].key.ipv4_5tuple.port_src = sport;
-		keys[i].key.ipv4_5tuple.port_dst = dport;
-		keys[i].key.ipv4_5tuple.proto = proto;
-
-		port_ids[i] = portid;
-		flow_ids[i] = flowid;
-
-		if (app_pipeline_fc_key_check(&keys[i]))
-			goto error2;
-
-		i++;
-	}
-
-	/* Close file */
-	*n_keys = i;
-	fclose(f);
-	return 0;
-
-error2:
-	*line = l;
-	fclose(f);
-	return -1;
-}
-
-int
-app_pipeline_fc_load_file_ipv6(char *filename,
-	struct pipeline_fc_key *keys,
-	uint32_t *port_ids,
-	uint32_t *flow_ids,
-	uint32_t *n_keys,
-	uint32_t *line)
-{
-	FILE *f = NULL;
-	char file_buf[1024];
-	uint32_t i, l;
-
-	/* Check input arguments */
-	if ((filename == NULL) ||
-		(keys == NULL) ||
-		(port_ids == NULL) ||
-		(flow_ids == NULL) ||
-		(n_keys == NULL) ||
-		(*n_keys == 0) ||
-		(line == NULL)) {
-		if (line)
-			*line = 0;
-		return -1;
-		}
-
-	/* Open input file */
-	f = fopen(filename, "r");
-	if (f == NULL) {
-		*line = 0;
-		return -1;
-	}
-
-	/* Read file */
-	for (i = 0, l = 1; i < *n_keys; l++) {
-		char *tokens[32];
-		uint32_t n_tokens = RTE_DIM(tokens);
-
-		struct in6_addr sipaddr, dipaddr;
-		uint16_t sport, dport;
-		uint8_t proto;
-		uint32_t portid, flowid;
-		int status;
-
-		if (fgets(file_buf, sizeof(file_buf), f) == NULL)
-			break;
-
-		status = parse_tokenize_string(file_buf, tokens, &n_tokens);
-		if (status)
-			goto error3;
-
-		if ((n_tokens == 0) || (tokens[0][0] == '#'))
-			continue;
-
-		if ((n_tokens != 10) ||
-			strcmp(tokens[0], "ipv6") ||
-			parse_ipv6_addr(tokens[1], &sipaddr) ||
-			parse_ipv6_addr(tokens[2], &dipaddr) ||
-			parser_read_uint16(&sport, tokens[3]) ||
-			parser_read_uint16(&dport, tokens[4]) ||
-			parser_read_uint8(&proto, tokens[5]) ||
-			strcmp(tokens[6], "port") ||
-			parser_read_uint32(&portid, tokens[7]) ||
-			strcmp(tokens[8], "id") ||
-			parser_read_uint32(&flowid, tokens[9]))
-			goto error3;
-
-		keys[i].type = FLOW_KEY_IPV6_5TUPLE;
-		memcpy(keys[i].key.ipv6_5tuple.ip_src,
-			sipaddr.s6_addr,
-			sizeof(sipaddr.s6_addr));
-		memcpy(keys[i].key.ipv6_5tuple.ip_dst,
-			dipaddr.s6_addr,
-			sizeof(dipaddr.s6_addr));
-		keys[i].key.ipv6_5tuple.port_src = sport;
-		keys[i].key.ipv6_5tuple.port_dst = dport;
-		keys[i].key.ipv6_5tuple.proto = proto;
-
-		port_ids[i] = portid;
-		flow_ids[i] = flowid;
-
-		if (app_pipeline_fc_key_check(&keys[i]))
-			goto error3;
-
-		i++;
-	}
-
-	/* Close file */
-	*n_keys = i;
-	fclose(f);
-	return 0;
-
-error3:
-	*line = l;
-	fclose(f);
-	return -1;
-}
-
-
-
-int
-app_pipeline_fc_add(struct app_params *app,
-	uint32_t pipeline_id,
-	struct pipeline_fc_key *key,
-	uint32_t port_id,
-	uint32_t flow_id)
-{
-	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;
-
-	uint32_t signature;
-	int new_flow;
-
-	/* Check input arguments */
-	if ((app == NULL) ||
-		(key == NULL))
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_flow_classification);
-	if (p == NULL)
-		return -1;
-
-	if (port_id >= p->n_ports_out)
-		return -1;
-
-	if (app_pipeline_fc_key_check(key) != 0)
-		return -1;
-
-	/* 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;
-	}
-
-	/* 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;
-	app_pipeline_fc_key_convert(key, req->key, &signature);
-	req->port_id = port_id;
-	req->flow_id = flow_id;
-
-	/* Send request and wait for response */
-	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL) {
-		if (new_flow)
-			rte_free(flow);
-		return -1;
-	}
-
-	/* Read response and write flow */
-	if (rsp->status ||
-		(rsp->entry_ptr == NULL) ||
-		((new_flow == 0) && (rsp->key_found == 0)) ||
-		((new_flow == 1) && (rsp->key_found == 1))) {
-		app_msg_free(app, rsp);
-		if (new_flow)
-			rte_free(flow);
-		return -1;
-	}
-
-	memset(&flow->key, 0, sizeof(flow->key));
-	memcpy(&flow->key, key, sizeof(flow->key));
-	flow->port_id = port_id;
-	flow->flow_id = flow_id;
-	flow->signature = signature;
-	flow->entry_ptr = rsp->entry_ptr;
-
-	/* Commit rule */
-	if (new_flow) {
-		uint32_t bucket_id = signature & (N_BUCKETS - 1);
-
-		TAILQ_INSERT_TAIL(&p->flows[bucket_id], flow, node);
-		p->n_flows++;
-	}
-
-	/* Free response */
-	app_msg_free(app, rsp);
-
-	return 0;
-}
-
-int
-app_pipeline_fc_add_bulk(struct app_params *app,
-	uint32_t pipeline_id,
-	struct pipeline_fc_key *key,
-	uint32_t *port_id,
-	uint32_t *flow_id,
-	uint32_t n_keys)
-{
-	struct app_pipeline_fc *p;
-	struct pipeline_fc_add_bulk_msg_req *req;
-	struct pipeline_fc_add_bulk_msg_rsp *rsp;
-
-	struct app_pipeline_fc_flow **flow;
-	uint32_t *signature;
-	int *new_flow;
-	struct pipeline_fc_add_bulk_flow_req *flow_req;
-	struct pipeline_fc_add_bulk_flow_rsp *flow_rsp;
-
-	uint32_t i;
-	int status;
-
-	/* Check input arguments */
-	if ((app == NULL) ||
-		(key == NULL) ||
-		(port_id == NULL) ||
-		(flow_id == NULL) ||
-		(n_keys == 0))
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_flow_classification);
-	if (p == NULL)
-		return -1;
-
-	for (i = 0; i < n_keys; i++)
-		if (port_id[i] >= p->n_ports_out)
-			return -1;
-
-	for (i = 0; i < n_keys; i++)
-		if (app_pipeline_fc_key_check(&key[i]) != 0)
-			return -1;
-
-	/* Memory allocation */
-	flow = rte_malloc(NULL,
-		n_keys * sizeof(struct app_pipeline_fc_flow *),
-		RTE_CACHE_LINE_SIZE);
-	if (flow == NULL)
-		return -1;
-
-	signature = rte_malloc(NULL,
-		n_keys * sizeof(uint32_t),
-		RTE_CACHE_LINE_SIZE);
-	if (signature == NULL) {
-		rte_free(flow);
-		return -1;
-	}
-
-	new_flow = rte_malloc(
-		NULL,
-		n_keys * sizeof(int),
-		RTE_CACHE_LINE_SIZE);
-	if (new_flow == NULL) {
-		rte_free(signature);
-		rte_free(flow);
-		return -1;
-	}
-
-	flow_req = rte_malloc(NULL,
-		n_keys * sizeof(struct pipeline_fc_add_bulk_flow_req),
-		RTE_CACHE_LINE_SIZE);
-	if (flow_req == NULL) {
-		rte_free(new_flow);
-		rte_free(signature);
-		rte_free(flow);
-		return -1;
-	}
-
-	flow_rsp = rte_malloc(NULL,
-		n_keys * sizeof(struct pipeline_fc_add_bulk_flow_rsp),
-		RTE_CACHE_LINE_SIZE);
-	if (flow_rsp == NULL) {
-		rte_free(flow_req);
-		rte_free(new_flow);
-		rte_free(signature);
-		rte_free(flow);
-		return -1;
-	}
-
-	/* Find existing flow or allocate new flow */
-	for (i = 0; i < n_keys; i++) {
-		flow[i] = app_pipeline_fc_flow_find(p, &key[i]);
-		new_flow[i] = (flow[i] == NULL);
-		if (flow[i] == NULL) {
-			flow[i] = rte_zmalloc(NULL,
-				sizeof(struct app_pipeline_fc_flow),
-				RTE_CACHE_LINE_SIZE);
-
-			if (flow[i] == NULL) {
-				uint32_t j;
-
-				for (j = 0; j < i; j++)
-					if (new_flow[j])
-						rte_free(flow[j]);
-
-				rte_free(flow_rsp);
-				rte_free(flow_req);
-				rte_free(new_flow);
-				rte_free(signature);
-				rte_free(flow);
-				return -1;
-			}
-		}
-	}
-
-	/* Allocate and write request */
-	req = app_msg_alloc(app);
-	if (req == NULL) {
-		for (i = 0; i < n_keys; i++)
-			if (new_flow[i])
-				rte_free(flow[i]);
-
-		rte_free(flow_rsp);
-		rte_free(flow_req);
-		rte_free(new_flow);
-		rte_free(signature);
-		rte_free(flow);
-		return -1;
-	}
-
-	for (i = 0; i < n_keys; i++) {
-		app_pipeline_fc_key_convert(&key[i],
-			flow_req[i].key,
-			&signature[i]);
-		flow_req[i].port_id = port_id[i];
-		flow_req[i].flow_id = flow_id[i];
-	}
-
-	req->type = PIPELINE_MSG_REQ_CUSTOM;
-	req->subtype = PIPELINE_FC_MSG_REQ_FLOW_ADD_BULK;
-	req->req = flow_req;
-	req->rsp = flow_rsp;
-	req->n_keys = n_keys;
-
-	/* Send request and wait for response */
-	rsp = app_msg_send_recv(app, pipeline_id, req, 10000);
-	if (rsp == NULL) {
-		for (i = 0; i < n_keys; i++)
-			if (new_flow[i])
-				rte_free(flow[i]);
-
-		rte_free(flow_rsp);
-		rte_free(flow_req);
-		rte_free(new_flow);
-		rte_free(signature);
-		rte_free(flow);
-		return -1;
-	}
-
-	/* Read response */
-	status = 0;
-
-	for (i = 0; i < rsp->n_keys; i++)
-		if ((flow_rsp[i].entry_ptr == NULL) ||
-			((new_flow[i] == 0) && (flow_rsp[i].key_found == 0)) ||
-			((new_flow[i] == 1) && (flow_rsp[i].key_found == 1)))
-			status = -1;
-
-	if (rsp->n_keys < n_keys)
-		status = -1;
-
-	/* Commit flows */
-	for (i = 0; i < rsp->n_keys; i++) {
-		memcpy(&flow[i]->key, &key[i], sizeof(flow[i]->key));
-		flow[i]->port_id = port_id[i];
-		flow[i]->flow_id = flow_id[i];
-		flow[i]->signature = signature[i];
-		flow[i]->entry_ptr = flow_rsp[i].entry_ptr;
-
-		if (new_flow[i]) {
-			uint32_t bucket_id = signature[i] & (N_BUCKETS - 1);
-
-			TAILQ_INSERT_TAIL(&p->flows[bucket_id], flow[i], node);
-			p->n_flows++;
-		}
-	}
-
-	/* Free resources */
-
-	for (i = rsp->n_keys; i < n_keys; i++)
-		if (new_flow[i])
-			rte_free(flow[i]);
-
-	app_msg_free(app, rsp);
-	rte_free(flow_rsp);
-	rte_free(flow_req);
-	rte_free(new_flow);
-	rte_free(signature);
-	rte_free(flow);
-
-	return status;
-}
-
-int
-app_pipeline_fc_del(struct app_params *app,
-	uint32_t pipeline_id,
-	struct pipeline_fc_key *key)
-{
-	struct app_pipeline_fc *p;
-	struct app_pipeline_fc_flow *flow;
-
-	struct pipeline_fc_del_msg_req *req;
-	struct pipeline_fc_del_msg_rsp *rsp;
-
-	uint32_t signature, bucket_id;
-
-	/* Check input arguments */
-	if ((app == NULL) ||
-		(key == NULL))
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_flow_classification);
-	if (p == NULL)
-		return -1;
-
-	if (app_pipeline_fc_key_check(key) != 0)
-		return -1;
-
-	/* 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;
-	app_pipeline_fc_key_convert(key, req->key, &signature);
-
-	/* Send request and wait for response */
-	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	/* Read response */
-	if (rsp->status || !rsp->key_found) {
-		app_msg_free(app, rsp);
-		return -1;
-	}
-
-	/* Remove rule */
-	bucket_id = signature & (N_BUCKETS - 1);
-	TAILQ_REMOVE(&p->flows[bucket_id], flow, node);
-	p->n_flows--;
-	rte_free(flow);
-
-	/* Free response */
-	app_msg_free(app, rsp);
-
-	return 0;
-}
-
-int
-app_pipeline_fc_add_default(struct app_params *app,
-	uint32_t pipeline_id,
-	uint32_t port_id)
-{
-	struct app_pipeline_fc *p;
-
-	struct pipeline_fc_add_default_msg_req *req;
-	struct pipeline_fc_add_default_msg_rsp *rsp;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_flow_classification);
-	if (p == NULL)
-		return -1;
-
-	if (port_id >= p->n_ports_out)
-		return -1;
-
-	/* 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_DEFAULT;
-	req->port_id = port_id;
-
-	/* Send request and wait for response */
-	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	/* Read response and write flow */
-	if (rsp->status || (rsp->entry_ptr == NULL)) {
-		app_msg_free(app, rsp);
-		return -1;
-	}
-
-	p->default_flow_port_id = port_id;
-	p->default_flow_entry_ptr = rsp->entry_ptr;
-
-	/* Commit route */
-	p->default_flow_present = 1;
-
-	/* Free response */
-	app_msg_free(app, rsp);
-
-	return 0;
-}
-
-int
-app_pipeline_fc_del_default(struct app_params *app,
-	uint32_t pipeline_id)
-{
-	struct app_pipeline_fc *p;
-
-	struct pipeline_fc_del_default_msg_req *req;
-	struct pipeline_fc_del_default_msg_rsp *rsp;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_flow_classification);
-	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_FC_MSG_REQ_FLOW_DEL_DEFAULT;
-
-	/* Send request and wait for response */
-	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	/* Read response */
-	if (rsp->status) {
-		app_msg_free(app, rsp);
-		return -1;
-	}
-
-	/* Commit route */
-	p->default_flow_present = 0;
-
-	/* Free response */
-	app_msg_free(app, rsp);
-
-	return 0;
-}
-
-/*
- * Flow ls
- */
-
-static void
-print_fc_qinq_flow(struct app_pipeline_fc_flow *flow)
-{
-	printf("(SVLAN = %" PRIu32 ", "
-		"CVLAN = %" PRIu32 ") => "
-		"Port = %" PRIu32 ", "
-		"Flow ID = %" PRIu32 ", "
-		"(signature = 0x%08" PRIx32 ", "
-		"entry_ptr = %p)\n",
-
-		flow->key.key.qinq.svlan,
-		flow->key.key.qinq.cvlan,
-		flow->port_id,
-		flow->flow_id,
-		flow->signature,
-		flow->entry_ptr);
-}
-
-static void
-print_fc_ipv4_5tuple_flow(struct app_pipeline_fc_flow *flow)
-{
-	printf("(SA = %" PRIu32 ".%" PRIu32 ".%" PRIu32 ".%" PRIu32 ", "
-		   "DA = %" PRIu32 ".%" PRIu32 ".%" PRIu32 ".%" PRIu32 ", "
-		   "SP = %" PRIu32 ", "
-		   "DP = %" PRIu32 ", "
-		   "Proto = %" PRIu32 ") => "
-		   "Port = %" PRIu32 ", "
-		   "Flow ID = %" PRIu32 " "
-		   "(signature = 0x%08" PRIx32 ", "
-		   "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->flow_id,
-		   flow->signature,
-		   flow->entry_ptr);
-}
-
-static void
-print_fc_ipv6_5tuple_flow(struct app_pipeline_fc_flow *flow) {
-	printf("(SA = %02" PRIx32 "%02" PRIx32 ":%02" PRIx32 "%02" PRIx32
-		":%02" PRIx32 "%02" PRIx32 ":%02" PRIx32 "%02" PRIx32
-		":%02" PRIx32 "%02" PRIx32 ":%02" PRIx32 "%02" PRIx32
-		":%02" PRIx32 "%02" PRIx32 ":%02" PRIx32 "%02" PRIx32 ", "
-		"DA = %02" PRIx32 "%02" PRIx32 ":%02" PRIx32 "%02" PRIx32
-		":%02" PRIx32 "%02" PRIx32 ":%02" PRIx32 "%02" PRIx32
-		":%02" PRIx32 "%02" PRIx32 ":%02" PRIx32 "%02" PRIx32
-		":%02" PRIx32 "%02" PRIx32 ":%02" PRIx32 "%02" PRIx32 ", "
-		"SP = %" PRIu32 ", "
-		"DP = %" PRIu32 " "
-		"Proto = %" PRIu32 " "
-		"=> Port = %" PRIu32 ", "
-		"Flow ID = %" PRIu32 " "
-		"(signature = 0x%08" PRIx32 ", "
-		"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],
-
-		flow->key.key.ipv6_5tuple.port_src,
-		flow->key.key.ipv6_5tuple.port_dst,
-
-		flow->key.key.ipv6_5tuple.proto,
-
-		flow->port_id,
-		flow->flow_id,
-		flow->signature,
-		flow->entry_ptr);
-}
-
-static void
-print_fc_flow(struct app_pipeline_fc_flow *flow)
-{
-	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;
-	}
-}
-
-static int
-app_pipeline_fc_ls(struct app_params *app,
-		uint32_t pipeline_id)
-{
-	struct app_pipeline_fc *p;
-	struct app_pipeline_fc_flow *flow;
-	uint32_t i;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_flow_classification);
-	if (p == NULL)
-		return -1;
-
-	for (i = 0; i < N_BUCKETS; i++)
-		TAILQ_FOREACH(flow, &p->flows[i], node)
-			print_fc_flow(flow);
-
-	if (p->default_flow_present)
-		printf("Default flow: port %" PRIu32 " (entry ptr = %p)\n",
-			p->default_flow_port_id,
-			p->default_flow_entry_ptr);
-	else
-		printf("Default: DROP\n");
-
-	return 0;
-}
-/*
- * flow
- *
- * flow add:
- *    p <pipelineid> flow add qinq <svlan> <cvlan> port <portid> id <flowid>
- *    p <pipelineid> flow add qinq bulk <file>
- *    p <pipelineid> flow add ipv4 <sipaddr> <dipaddr> <sport> <dport> <proto> port <port ID> id <flowid>
- *    p <pipelineid> flow add ipv4 bulk <file>
- *    p <pipelineid> flow add ipv6 <sipaddr> <dipaddr> <sport> <dport> <proto> port <port ID> id <flowid>
- *    p <pipelineid> flow add ipv6 bulk <file>
- *
- * flow add default:
- *    p <pipelineid> flow add default <portid>
- *
- * flow del:
- *    p <pipelineid> flow del qinq <svlan> <cvlan>
- *    p <pipelineid> flow del ipv4 <sipaddr> <dipaddr> <sport> <dport> <proto>
- *    p <pipelineid> flow del ipv6 <sipaddr> <dipaddr> <sport> <dport> <proto>
- *
- * flow del default:
- *    p <pipelineid> flow del default
- *
- * flow ls:
- *    p <pipelineid> flow ls
- */
-
-struct cmd_flow_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t flow_string;
-	cmdline_multi_string_t multi_string;
-};
-
-static void
-cmd_flow_parsed(void *parsed_result,
-	__attribute__((unused)) struct cmdline *cl,
-	void *data)
-{
-	struct cmd_flow_result *results = parsed_result;
-	struct app_params *app = data;
-
-	char *tokens[16];
-	uint32_t n_tokens = RTE_DIM(tokens);
-	int status;
-
-	status = parse_tokenize_string(results->multi_string, tokens, &n_tokens);
-	if (status) {
-		printf(CMD_MSG_TOO_MANY_ARGS, "flow");
-		return;
-	}
-
-	/* flow add qinq */
-	if ((n_tokens >= 3) &&
-		(strcmp(tokens[0], "add") == 0) &&
-		(strcmp(tokens[1], "qinq") == 0) &&
-		strcmp(tokens[2], "bulk")) {
-		struct pipeline_fc_key key;
-		uint32_t svlan;
-		uint32_t cvlan;
-		uint32_t port_id;
-		uint32_t flow_id;
-
-		memset(&key, 0, sizeof(key));
-
-		if (n_tokens != 8) {
-			printf(CMD_MSG_MISMATCH_ARGS, "flow add qinq");
-			return;
-		}
-
-		if (parser_read_uint32(&svlan, tokens[2]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "svlan");
-			return;
-		}
-
-		if (parser_read_uint32(&cvlan, tokens[3]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "cvlan");
-			return;
-		}
-
-		if (strcmp(tokens[4], "port") != 0) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "port");
-			return;
-		}
-
-		if (parser_read_uint32(&port_id, tokens[5]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "portid");
-			return;
-		}
-
-		if (strcmp(tokens[6], "id") != 0) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "id");
-			return;
-		}
-
-		if (parser_read_uint32(&flow_id, tokens[7]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "flowid");
-			return;
-		}
-
-		key.type = FLOW_KEY_QINQ;
-		key.key.qinq.svlan = svlan;
-		key.key.qinq.cvlan = cvlan;
-
-		status = app_pipeline_fc_add(app,
-			results->pipeline_id,
-			&key,
-			port_id,
-			flow_id);
-		if (status)
-			printf(CMD_MSG_FAIL, "flow add qinq");
-
-		return;
-	} /* flow add qinq */
-
-	/* flow add ipv4 */
-	if ((n_tokens >= 3) &&
-		(strcmp(tokens[0], "add") == 0) &&
-		(strcmp(tokens[1], "ipv4") == 0) &&
-		strcmp(tokens[2], "bulk")) {
-		struct pipeline_fc_key key;
-		struct in_addr sipaddr;
-		struct in_addr dipaddr;
-		uint32_t sport;
-		uint32_t dport;
-		uint32_t proto;
-		uint32_t port_id;
-		uint32_t flow_id;
-
-		memset(&key, 0, sizeof(key));
-
-		if (n_tokens != 11) {
-			printf(CMD_MSG_MISMATCH_ARGS, "flow add ipv4");
-			return;
-		}
-
-		if (parse_ipv4_addr(tokens[2], &sipaddr) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "sipv4addr");
-			return;
-		}
-		if (parse_ipv4_addr(tokens[3], &dipaddr) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "dipv4addr");
-			return;
-		}
-
-		if (parser_read_uint32(&sport, tokens[4]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "sport");
-			return;
-		}
-
-		if (parser_read_uint32(&dport, tokens[5]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "dport");
-			return;
-		}
-
-		if (parser_read_uint32(&proto, tokens[6]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "proto");
-			return;
-		}
-
-		if (strcmp(tokens[7], "port") != 0) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "port");
-			return;
-		}
-
-		if (parser_read_uint32(&port_id, tokens[8]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "portid");
-			return;
-		}
-
-		if (strcmp(tokens[9], "id") != 0) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "id");
-			return;
-		}
-
-		if (parser_read_uint32(&flow_id, tokens[10]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "flowid");
-			return;
-		}
-
-		key.type = FLOW_KEY_IPV4_5TUPLE;
-		key.key.ipv4_5tuple.ip_src = rte_be_to_cpu_32(sipaddr.s_addr);
-		key.key.ipv4_5tuple.ip_dst = rte_be_to_cpu_32(dipaddr.s_addr);
-		key.key.ipv4_5tuple.port_src = sport;
-		key.key.ipv4_5tuple.port_dst = dport;
-		key.key.ipv4_5tuple.proto = proto;
-
-		status = app_pipeline_fc_add(app,
-			results->pipeline_id,
-			&key,
-			port_id,
-			flow_id);
-		if (status)
-			printf(CMD_MSG_FAIL, "flow add ipv4");
-
-		return;
-	} /* flow add ipv4 */
-
-	/* flow add ipv6 */
-	if ((n_tokens >= 3) &&
-		(strcmp(tokens[0], "add") == 0) &&
-		(strcmp(tokens[1], "ipv6") == 0) &&
-		strcmp(tokens[2], "bulk")) {
-		struct pipeline_fc_key key;
-		struct in6_addr sipaddr;
-		struct in6_addr dipaddr;
-		uint32_t sport;
-		uint32_t dport;
-		uint32_t proto;
-		uint32_t port_id;
-		uint32_t flow_id;
-
-		memset(&key, 0, sizeof(key));
-
-		if (n_tokens != 11) {
-			printf(CMD_MSG_MISMATCH_ARGS, "flow add ipv6");
-			return;
-		}
-
-		if (parse_ipv6_addr(tokens[2], &sipaddr) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "sipv6addr");
-			return;
-		}
-		if (parse_ipv6_addr(tokens[3], &dipaddr) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "dipv6addr");
-			return;
-		}
-
-		if (parser_read_uint32(&sport, tokens[4]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "sport");
-			return;
-		}
-
-		if (parser_read_uint32(&dport, tokens[5]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "dport");
-			return;
-		}
-
-		if (parser_read_uint32(&proto, tokens[6]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "proto");
-			return;
-		}
-
-		if (strcmp(tokens[7], "port") != 0) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "port");
-			return;
-		}
-
-		if (parser_read_uint32(&port_id, tokens[8]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "portid");
-			return;
-		}
-
-		if (strcmp(tokens[9], "id") != 0) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "id");
-			return;
-		}
-
-		if (parser_read_uint32(&flow_id, tokens[10]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "flowid");
-			return;
-		}
-
-		key.type = FLOW_KEY_IPV6_5TUPLE;
-		memcpy(key.key.ipv6_5tuple.ip_src, (void *)&sipaddr, 16);
-		memcpy(key.key.ipv6_5tuple.ip_dst, (void *)&dipaddr, 16);
-		key.key.ipv6_5tuple.port_src = sport;
-		key.key.ipv6_5tuple.port_dst = dport;
-		key.key.ipv6_5tuple.proto = proto;
-
-		status = app_pipeline_fc_add(app,
-			results->pipeline_id,
-			&key,
-			port_id,
-			flow_id);
-		if (status)
-			printf(CMD_MSG_FAIL, "flow add ipv6");
-
-		return;
-	} /* flow add ipv6 */
-
-	/* flow add qinq bulk */
-	if ((n_tokens >= 3) &&
-		(strcmp(tokens[0], "add") == 0) &&
-		(strcmp(tokens[1], "qinq") == 0) &&
-		(strcmp(tokens[2], "bulk") == 0)) {
-		struct pipeline_fc_key *keys;
-		uint32_t *port_ids, *flow_ids, n_keys, line;
-		char *filename;
-
-		if (n_tokens != 4) {
-			printf(CMD_MSG_MISMATCH_ARGS, "flow add qinq bulk");
-			return;
-		}
-
-		filename = tokens[3];
-
-		n_keys = APP_PIPELINE_FC_MAX_FLOWS_IN_FILE;
-		keys = malloc(n_keys * sizeof(struct pipeline_fc_key));
-		if (keys == NULL)
-			return;
-		memset(keys, 0, n_keys * sizeof(struct pipeline_fc_key));
-
-		port_ids = malloc(n_keys * sizeof(uint32_t));
-		if (port_ids == NULL) {
-			free(keys);
-			return;
-		}
-
-		flow_ids = malloc(n_keys * sizeof(uint32_t));
-		if (flow_ids == NULL) {
-			free(port_ids);
-			free(keys);
-			return;
-		}
-
-		status = app_pipeline_fc_load_file_qinq(filename,
-			keys,
-			port_ids,
-			flow_ids,
-			&n_keys,
-			&line);
-		if (status != 0) {
-			printf(CMD_MSG_FILE_ERR, filename, line);
-			free(flow_ids);
-			free(port_ids);
-			free(keys);
-			return;
-		}
-
-		status = app_pipeline_fc_add_bulk(app,
-			results->pipeline_id,
-			keys,
-			port_ids,
-			flow_ids,
-			n_keys);
-		if (status)
-			printf(CMD_MSG_FAIL, "flow add qinq bulk");
-
-		free(flow_ids);
-		free(port_ids);
-		free(keys);
-		return;
-	} /* flow add qinq bulk */
-
-	/* flow add ipv4 bulk */
-	if ((n_tokens >= 3) &&
-		(strcmp(tokens[0], "add") == 0) &&
-		(strcmp(tokens[1], "ipv4") == 0) &&
-		(strcmp(tokens[2], "bulk") == 0)) {
-		struct pipeline_fc_key *keys;
-		uint32_t *port_ids, *flow_ids, n_keys, line;
-		char *filename;
-
-		if (n_tokens != 4) {
-			printf(CMD_MSG_MISMATCH_ARGS, "flow add ipv4 bulk");
-			return;
-		}
-
-		filename = tokens[3];
-
-		n_keys = APP_PIPELINE_FC_MAX_FLOWS_IN_FILE;
-		keys = malloc(n_keys * sizeof(struct pipeline_fc_key));
-		if (keys == NULL)
-			return;
-		memset(keys, 0, n_keys * sizeof(struct pipeline_fc_key));
-
-		port_ids = malloc(n_keys * sizeof(uint32_t));
-		if (port_ids == NULL) {
-			free(keys);
-			return;
-		}
-
-		flow_ids = malloc(n_keys * sizeof(uint32_t));
-		if (flow_ids == NULL) {
-			free(port_ids);
-			free(keys);
-			return;
-		}
-
-		status = app_pipeline_fc_load_file_ipv4(filename,
-			keys,
-			port_ids,
-			flow_ids,
-			&n_keys,
-			&line);
-		if (status != 0) {
-			printf(CMD_MSG_FILE_ERR, filename, line);
-			free(flow_ids);
-			free(port_ids);
-			free(keys);
-			return;
-		}
-
-		status = app_pipeline_fc_add_bulk(app,
-			results->pipeline_id,
-			keys,
-			port_ids,
-			flow_ids,
-			n_keys);
-		if (status)
-			printf(CMD_MSG_FAIL, "flow add ipv4 bulk");
-
-		free(flow_ids);
-		free(port_ids);
-		free(keys);
-		return;
-	} /* flow add ipv4 bulk */
-
-	/* flow add ipv6 bulk */
-	if ((n_tokens >= 3) &&
-		(strcmp(tokens[0], "add") == 0) &&
-		(strcmp(tokens[1], "ipv6") == 0) &&
-		(strcmp(tokens[2], "bulk") == 0)) {
-		struct pipeline_fc_key *keys;
-		uint32_t *port_ids, *flow_ids, n_keys, line;
-		char *filename;
-
-		if (n_tokens != 4) {
-			printf(CMD_MSG_MISMATCH_ARGS, "flow add ipv6 bulk");
-			return;
-		}
-
-		filename = tokens[3];
-
-		n_keys = APP_PIPELINE_FC_MAX_FLOWS_IN_FILE;
-		keys = malloc(n_keys * sizeof(struct pipeline_fc_key));
-		if (keys == NULL)
-			return;
-		memset(keys, 0, n_keys * sizeof(struct pipeline_fc_key));
-
-		port_ids = malloc(n_keys * sizeof(uint32_t));
-		if (port_ids == NULL) {
-			free(keys);
-			return;
-		}
-
-		flow_ids = malloc(n_keys * sizeof(uint32_t));
-		if (flow_ids == NULL) {
-			free(port_ids);
-			free(keys);
-			return;
-		}
-
-		status = app_pipeline_fc_load_file_ipv6(filename,
-			keys,
-			port_ids,
-			flow_ids,
-			&n_keys,
-			&line);
-		if (status != 0) {
-			printf(CMD_MSG_FILE_ERR, filename, line);
-			free(flow_ids);
-			free(port_ids);
-			free(keys);
-			return;
-		}
-
-		status = app_pipeline_fc_add_bulk(app,
-			results->pipeline_id,
-			keys,
-			port_ids,
-			flow_ids,
-			n_keys);
-		if (status)
-			printf(CMD_MSG_FAIL, "flow add ipv6 bulk");
-
-		free(flow_ids);
-		free(port_ids);
-		free(keys);
-		return;
-	} /* flow add ipv6 bulk */
-
-	/* flow add default*/
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "add") == 0) &&
-		(strcmp(tokens[1], "default") == 0)) {
-		uint32_t port_id;
-
-		if (n_tokens != 3) {
-			printf(CMD_MSG_MISMATCH_ARGS, "flow add default");
-			return;
-		}
-
-		if (parser_read_uint32(&port_id, tokens[2]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "portid");
-			return;
-		}
-
-		status = app_pipeline_fc_add_default(app,
-			results->pipeline_id,
-			port_id);
-		if (status)
-			printf(CMD_MSG_FAIL, "flow add default");
-
-		return;
-	} /* flow add default */
-
-	/* flow del qinq */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "del") == 0) &&
-		(strcmp(tokens[1], "qinq") == 0)) {
-		struct pipeline_fc_key key;
-		uint32_t svlan;
-		uint32_t cvlan;
-
-		memset(&key, 0, sizeof(key));
-
-		if (n_tokens != 4) {
-			printf(CMD_MSG_MISMATCH_ARGS, "flow del qinq");
-			return;
-		}
-
-		if (parser_read_uint32(&svlan, tokens[2]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "svlan");
-			return;
-		}
-
-		if (parser_read_uint32(&cvlan, tokens[3]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "cvlan");
-			return;
-		}
-
-		key.type = FLOW_KEY_QINQ;
-		key.key.qinq.svlan = svlan;
-		key.key.qinq.cvlan = cvlan;
-
-		status = app_pipeline_fc_del(app,
-			results->pipeline_id,
-			&key);
-		if (status)
-			printf(CMD_MSG_FAIL, "flow del qinq");
-
-		return;
-	} /* flow del qinq */
-
-	/* flow del ipv4 */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "del") == 0) &&
-		(strcmp(tokens[1], "ipv4") == 0)) {
-		struct pipeline_fc_key key;
-		struct in_addr sipaddr;
-		struct in_addr dipaddr;
-		uint32_t sport;
-		uint32_t dport;
-		uint32_t proto;
-
-		memset(&key, 0, sizeof(key));
-
-		if (n_tokens != 7) {
-			printf(CMD_MSG_MISMATCH_ARGS, "flow del ipv4");
-			return;
-		}
-
-		if (parse_ipv4_addr(tokens[2], &sipaddr) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "sipv4addr");
-			return;
-		}
-		if (parse_ipv4_addr(tokens[3], &dipaddr) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "dipv4addr");
-			return;
-		}
-
-		if (parser_read_uint32(&sport, tokens[4]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "sport");
-			return;
-		}
-
-		if (parser_read_uint32(&dport, tokens[5]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "dport");
-			return;
-		}
-
-		if (parser_read_uint32(&proto, tokens[6]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "proto");
-			return;
-		}
-
-		key.type = FLOW_KEY_IPV4_5TUPLE;
-		key.key.ipv4_5tuple.ip_src = rte_be_to_cpu_32(sipaddr.s_addr);
-		key.key.ipv4_5tuple.ip_dst = rte_be_to_cpu_32(dipaddr.s_addr);
-		key.key.ipv4_5tuple.port_src = sport;
-		key.key.ipv4_5tuple.port_dst = dport;
-		key.key.ipv4_5tuple.proto = proto;
-
-		status = app_pipeline_fc_del(app,
-			results->pipeline_id,
-			&key);
-		if (status)
-			printf(CMD_MSG_FAIL, "flow del ipv4");
-
-		return;
-	} /* flow del ipv4 */
-
-	/* flow del ipv6 */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "del") == 0) &&
-		(strcmp(tokens[1], "ipv6") == 0)) {
-		struct pipeline_fc_key key;
-		struct in6_addr sipaddr;
-		struct in6_addr dipaddr;
-		uint32_t sport;
-		uint32_t dport;
-		uint32_t proto;
-
-		memset(&key, 0, sizeof(key));
-
-		if (n_tokens != 7) {
-			printf(CMD_MSG_MISMATCH_ARGS, "flow del ipv6");
-			return;
-		}
-
-		if (parse_ipv6_addr(tokens[2], &sipaddr) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "sipv6addr");
-			return;
-		}
-
-		if (parse_ipv6_addr(tokens[3], &dipaddr) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "dipv6addr");
-			return;
-		}
-
-		if (parser_read_uint32(&sport, tokens[4]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "sport");
-			return;
-		}
-
-		if (parser_read_uint32(&dport, tokens[5]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "dport");
-			return;
-		}
-
-		if (parser_read_uint32(&proto, tokens[6]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "proto");
-			return;
-		}
-
-		key.type = FLOW_KEY_IPV6_5TUPLE;
-		memcpy(key.key.ipv6_5tuple.ip_src, &sipaddr, 16);
-		memcpy(key.key.ipv6_5tuple.ip_dst, &dipaddr, 16);
-		key.key.ipv6_5tuple.port_src = sport;
-		key.key.ipv6_5tuple.port_dst = dport;
-		key.key.ipv6_5tuple.proto = proto;
-
-		status = app_pipeline_fc_del(app,
-			results->pipeline_id,
-			&key);
-		if (status)
-			printf(CMD_MSG_FAIL, "flow del ipv6");
-
-		return;
-	} /* flow del ipv6 */
-
-	/* flow del default*/
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "del") == 0) &&
-		(strcmp(tokens[1], "default") == 0)) {
-		if (n_tokens != 2) {
-			printf(CMD_MSG_MISMATCH_ARGS, "flow del default");
-			return;
-		}
-
-		status = app_pipeline_fc_del_default(app,
-			results->pipeline_id);
-		if (status)
-			printf(CMD_MSG_FAIL, "flow del default");
-
-		return;
-	} /* flow del default */
-
-	/* flow ls */
-	if ((n_tokens >= 1) && (strcmp(tokens[0], "ls") == 0)) {
-		if (n_tokens != 1) {
-			printf(CMD_MSG_MISMATCH_ARGS, "flow ls");
-			return;
-		}
-
-		status = app_pipeline_fc_ls(app, results->pipeline_id);
-		if (status)
-			printf(CMD_MSG_FAIL, "flow ls");
-
-		return;
-	} /* flow ls */
-
-	printf(CMD_MSG_MISMATCH_ARGS, "flow");
-}
-
-static cmdline_parse_token_string_t cmd_flow_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_flow_result, p_string, "p");
-
-static cmdline_parse_token_num_t cmd_flow_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_flow_result, pipeline_id, UINT32);
-
-static cmdline_parse_token_string_t cmd_flow_flow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_flow_result, flow_string, "flow");
-
-static cmdline_parse_token_string_t cmd_flow_multi_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_flow_result, multi_string,
-		TOKEN_STRING_MULTI);
-
-static cmdline_parse_inst_t cmd_flow = {
-	.f = cmd_flow_parsed,
-	.data = NULL,
-	.help_str = "flow add / add bulk / add default / del / del default / ls",
-	.tokens = {
-		(void *) &cmd_flow_p_string,
-		(void *) &cmd_flow_pipeline_id,
-		(void *) &cmd_flow_flow_string,
-		(void *) &cmd_flow_multi_string,
-		NULL,
-	},
-};
-
-static cmdline_parse_ctx_t pipeline_cmds[] = {
-	(cmdline_parse_inst_t *) &cmd_flow,
-	NULL,
-};
-
-static struct pipeline_fe_ops pipeline_flow_classification_fe_ops = {
-	.f_init = app_pipeline_fc_init,
-	.f_post_init = NULL,
-	.f_free = app_pipeline_fc_free,
-	.f_track = app_pipeline_track_default,
-	.cmds = pipeline_cmds,
-};
-
-struct pipeline_type pipeline_flow_classification = {
-	.name = "FLOW_CLASSIFICATION",
-	.be_ops = &pipeline_flow_classification_be_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
deleted file mode 100644
index 8c35498..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_flow_classification.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#ifndef __INCLUDE_PIPELINE_FLOW_CLASSIFICATION_H__
-#define __INCLUDE_PIPELINE_FLOW_CLASSIFICATION_H__
-
-#include "pipeline.h"
-#include "pipeline_flow_classification_be.h"
-
-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;
-	} key;
-};
-
-int
-app_pipeline_fc_add(struct app_params *app,
-	uint32_t pipeline_id,
-	struct pipeline_fc_key *key,
-	uint32_t port_id,
-	uint32_t flow_id);
-
-int
-app_pipeline_fc_add_bulk(struct app_params *app,
-	uint32_t pipeline_id,
-	struct pipeline_fc_key *key,
-	uint32_t *port_id,
-	uint32_t *flow_id,
-	uint32_t n_keys);
-
-int
-app_pipeline_fc_del(struct app_params *app,
-	uint32_t pipeline_id,
-	struct pipeline_fc_key *key);
-
-int
-app_pipeline_fc_add_default(struct app_params *app,
-	uint32_t pipeline_id,
-	uint32_t port_id);
-
-int
-app_pipeline_fc_del_default(struct app_params *app,
-	uint32_t pipeline_id);
-
-#ifndef APP_PIPELINE_FC_MAX_FLOWS_IN_FILE
-#define APP_PIPELINE_FC_MAX_FLOWS_IN_FILE	(16 * 1024 * 1024)
-#endif
-
-int
-app_pipeline_fc_load_file_qinq(char *filename,
-	struct pipeline_fc_key *keys,
-	uint32_t *port_ids,
-	uint32_t *flow_ids,
-	uint32_t *n_keys,
-	uint32_t *line);
-
-int
-app_pipeline_fc_load_file_ipv4(char *filename,
-	struct pipeline_fc_key *keys,
-	uint32_t *port_ids,
-	uint32_t *flow_ids,
-	uint32_t *n_keys,
-	uint32_t *line);
-
-int
-app_pipeline_fc_load_file_ipv6(char *filename,
-	struct pipeline_fc_key *keys,
-	uint32_t *port_ids,
-	uint32_t *flow_ids,
-	uint32_t *n_keys,
-	uint32_t *line);
-
-extern struct pipeline_type pipeline_flow_classification;
-
-#endif
diff --git a/examples/ip_pipeline/pipeline/pipeline_flow_classification_be.c b/examples/ip_pipeline/pipeline/pipeline_flow_classification_be.c
deleted file mode 100644
index 097ec34..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_flow_classification_be.c
+++ /dev/null
@@ -1,723 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2016 Intel Corporation
- */
-
-#include <string.h>
-
-#include <rte_common.h>
-#include <rte_malloc.h>
-#include <rte_table_hash.h>
-#include <rte_byteorder.h>
-#include <pipeline.h>
-
-#include "pipeline_flow_classification_be.h"
-#include "pipeline_actions_common.h"
-#include "parser.h"
-#include "hash_func.h"
-
-struct pipeline_flow_classification {
-	struct pipeline p;
-	pipeline_msg_req_handler custom_handlers[PIPELINE_FC_MSG_REQS];
-
-	uint32_t n_flows;
-	uint32_t key_size;
-	uint32_t flow_id;
-
-	uint32_t key_offset;
-	uint32_t hash_offset;
-	uint8_t key_mask[PIPELINE_FC_FLOW_KEY_MAX_SIZE];
-	uint32_t key_mask_present;
-	uint32_t flow_id_offset;
-
-} __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_add_bulk_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 pipeline_msg_req_handler custom_handlers[] = {
-	[PIPELINE_FC_MSG_REQ_FLOW_ADD] =
-		pipeline_fc_msg_req_add_handler,
-	[PIPELINE_FC_MSG_REQ_FLOW_ADD_BULK] =
-		pipeline_fc_msg_req_add_bulk_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,
-};
-
-/*
- * Flow table
- */
-struct flow_table_entry {
-	struct rte_pipeline_table_entry head;
-
-	uint32_t flow_id;
-	uint32_t pad;
-};
-
-rte_table_hash_op_hash hash_func[] = {
-	hash_default_key8,
-	hash_default_key16,
-	hash_default_key24,
-	hash_default_key32,
-	hash_default_key40,
-	hash_default_key48,
-	hash_default_key56,
-	hash_default_key64
-};
-
-/*
- * Flow table AH - Write flow_id to packet meta-data
- */
-static inline void
-pkt_work_flow_id(
-	struct rte_mbuf *pkt,
-	struct rte_pipeline_table_entry *table_entry,
-	void *arg)
-{
-	struct pipeline_flow_classification *p_fc = arg;
-	uint32_t *flow_id_ptr =
-		RTE_MBUF_METADATA_UINT32_PTR(pkt, p_fc->flow_id_offset);
-	struct flow_table_entry *entry =
-		(struct flow_table_entry *) table_entry;
-
-	/* Read */
-	uint32_t flow_id = entry->flow_id;
-
-	/* Compute */
-
-	/* Write */
-	*flow_id_ptr = flow_id;
-}
-
-static inline void
-pkt4_work_flow_id(
-	struct rte_mbuf **pkts,
-	struct rte_pipeline_table_entry **table_entries,
-	void *arg)
-{
-	struct pipeline_flow_classification *p_fc = arg;
-
-	uint32_t *flow_id_ptr0 =
-		RTE_MBUF_METADATA_UINT32_PTR(pkts[0], p_fc->flow_id_offset);
-	uint32_t *flow_id_ptr1 =
-		RTE_MBUF_METADATA_UINT32_PTR(pkts[1], p_fc->flow_id_offset);
-	uint32_t *flow_id_ptr2 =
-		RTE_MBUF_METADATA_UINT32_PTR(pkts[2], p_fc->flow_id_offset);
-	uint32_t *flow_id_ptr3 =
-		RTE_MBUF_METADATA_UINT32_PTR(pkts[3], p_fc->flow_id_offset);
-
-	struct flow_table_entry *entry0 =
-		(struct flow_table_entry *) table_entries[0];
-	struct flow_table_entry *entry1 =
-		(struct flow_table_entry *) table_entries[1];
-	struct flow_table_entry *entry2 =
-		(struct flow_table_entry *) table_entries[2];
-	struct flow_table_entry *entry3 =
-		(struct flow_table_entry *) table_entries[3];
-
-	/* Read */
-	uint32_t flow_id0 = entry0->flow_id;
-	uint32_t flow_id1 = entry1->flow_id;
-	uint32_t flow_id2 = entry2->flow_id;
-	uint32_t flow_id3 = entry3->flow_id;
-
-	/* Compute */
-
-	/* Write */
-	*flow_id_ptr0 = flow_id0;
-	*flow_id_ptr1 = flow_id1;
-	*flow_id_ptr2 = flow_id2;
-	*flow_id_ptr3 = flow_id3;
-}
-
-PIPELINE_TABLE_AH_HIT(fc_table_ah_hit,
-		pkt_work_flow_id, pkt4_work_flow_id);
-
-static rte_pipeline_table_action_handler_hit
-get_fc_table_ah_hit(struct pipeline_flow_classification *p)
-{
-	if (p->flow_id)
-		return fc_table_ah_hit;
-
-	return NULL;
-}
-
-/*
- * Argument parsing
- */
-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 key_mask_present = 0;
-	uint32_t flow_id_offset_present = 0;
-
-	uint32_t i;
-	char key_mask_str[PIPELINE_FC_FLOW_KEY_MAX_SIZE * 2 + 1];
-
-	p->hash_offset = 0;
-
-	/* default values */
-	p->flow_id = 0;
-
-	for (i = 0; i < params->n_args; i++) {
-		char *arg_name = params->args_name[i];
-		char *arg_value = params->args_value[i];
-
-		/* n_flows */
-		if (strcmp(arg_name, "n_flows") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				n_flows_present == 0, params->name,
-				arg_name);
-			n_flows_present = 1;
-
-			status = parser_read_uint32(&p->n_flows,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL(((status != -EINVAL) &&
-				(p->n_flows != 0)), params->name,
-				arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			continue;
-		}
-
-		/* key_offset */
-		if (strcmp(arg_name, "key_offset") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				key_offset_present == 0, params->name,
-				arg_name);
-			key_offset_present = 1;
-
-			status = parser_read_uint32(&p->key_offset,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			continue;
-		}
-
-		/* key_size */
-		if (strcmp(arg_name, "key_size") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				key_size_present == 0, params->name,
-				arg_name);
-			key_size_present = 1;
-
-			status = parser_read_uint32(&p->key_size,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL(((status != -EINVAL) &&
-				(p->key_size != 0) &&
-				(p->key_size % 8 == 0)),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG(((status != -ERANGE) &&
-				(p->key_size <=
-				PIPELINE_FC_FLOW_KEY_MAX_SIZE)),
-				params->name, arg_name, arg_value);
-
-			continue;
-		}
-
-		/* key_mask */
-		if (strcmp(arg_name, "key_mask") == 0) {
-			int mask_str_len = strlen(arg_value);
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				key_mask_present == 0,
-				params->name, arg_name);
-			key_mask_present = 1;
-
-			PIPELINE_ARG_CHECK((mask_str_len <=
-				(PIPELINE_FC_FLOW_KEY_MAX_SIZE * 2)),
-				"Parse error in section \"%s\": entry "
-				"\"%s\" is too long", params->name,
-				arg_name);
-
-			snprintf(key_mask_str, mask_str_len + 1, "%s",
-				arg_value);
-
-			continue;
-		}
-
-		/* hash_offset */
-		if (strcmp(arg_name, "hash_offset") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				hash_offset_present == 0, params->name,
-				arg_name);
-			hash_offset_present = 1;
-
-			status = parser_read_uint32(&p->hash_offset,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			continue;
-		}
-
-		/* flow_id_offset */
-		if (strcmp(arg_name, "flowid_offset") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				flow_id_offset_present == 0, params->name,
-				arg_name);
-			flow_id_offset_present = 1;
-
-			status = parser_read_uint32(&p->flow_id_offset,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			p->flow_id = 1;
-
-			continue;
-		}
-
-		/* Unknown argument */
-		PIPELINE_PARSE_ERR_INV_ENT(0, params->name, arg_name);
-	}
-
-	/* Check that mandatory arguments are present */
-	PIPELINE_PARSE_ERR_MANDATORY((n_flows_present), params->name,
-		"n_flows");
-	PIPELINE_PARSE_ERR_MANDATORY((key_offset_present), params->name,
-		"key_offset");
-	PIPELINE_PARSE_ERR_MANDATORY((key_size_present), params->name,
-		"key_size");
-
-	if (key_mask_present) {
-		uint32_t key_size = p->key_size;
-		int status;
-
-		PIPELINE_ARG_CHECK(((key_size == 8) || (key_size == 16)),
-			"Parse error in section \"%s\": entry key_mask "
-			"only allowed for key_size of 8 or 16 bytes",
-			params->name);
-
-		PIPELINE_ARG_CHECK((strlen(key_mask_str) ==
-			(key_size * 2)), "Parse error in section "
-			"\"%s\": key_mask should have exactly %u hex "
-			"digits", params->name, (key_size * 2));
-
-		PIPELINE_ARG_CHECK((hash_offset_present == 0), "Parse "
-			"error in section \"%s\": entry hash_offset only "
-			"allowed when key_mask is not present",
-			params->name);
-
-		status = parse_hex_string(key_mask_str, p->key_mask,
-			&p->key_size);
-
-		PIPELINE_PARSE_ERR_INV_VAL(((status == 0) &&
-			(key_size == p->key_size)), params->name,
-			"key_mask", key_mask_str);
-	}
-
-	p->key_mask_present = key_mask_present;
-
-	return 0;
-}
-
-static void *pipeline_fc_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 = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
-	if (p == NULL)
-		return NULL;
-	p_fc = (struct pipeline_flow_classification *) p;
-
-	strcpy(p->name, params->name);
-	p->log_level = params->log_level;
-
-	PLOG(p, HIGH, "Flow classification");
-
-	/* Parse arguments */
-	if (pipeline_fc_parse_args(p_fc, 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,
-			.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_params table_hash_params = {
-			.name = p->name,
-			.key_size = p_fc->key_size,
-			.key_offset = p_fc->key_offset,
-			.key_mask = (p_fc->key_mask_present) ?
-				p_fc->key_mask : NULL,
-			.n_keys = p_fc->n_flows,
-			.n_buckets = rte_align32pow2(p_fc->n_flows / 4),
-			.f_hash = hash_func[(p_fc->key_size / 8) - 1],
-			.seed = 0,
-		};
-
-		struct rte_pipeline_table_params table_params = {
-			.ops = NULL, /* set below */
-			.arg_create = NULL, /* set below */
-			.f_action_hit = get_fc_table_ah_hit(p_fc),
-			.f_action_miss = NULL,
-			.arg_ah = p_fc,
-			.action_data_size = sizeof(struct flow_table_entry) -
-				sizeof(struct rte_pipeline_table_entry),
-		};
-
-		int status;
-
-		switch (p_fc->key_size) {
-		case 8:
-			table_params.ops = &rte_table_hash_key8_ext_ops;
-			break;
-
-		case 16:
-			table_params.ops = &rte_table_hash_key16_ext_ops;
-			break;
-
-		default:
-			table_params.ops = &rte_table_hash_ext_ops;
-		}
-
-		table_params.arg_create = &table_hash_params;
-
-		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_fc_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_fc_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 flow_table_entry entry = {
-		.head = {
-			.action = RTE_PIPELINE_ACTION_PORT,
-			{.port_id = p->port_out_id[req->port_id]},
-		},
-		.flow_id = req->flow_id,
-	};
-
-	rsp->status = rte_pipeline_table_entry_add(p->p,
-		p->table_id[0],
-		&req->key,
-		(struct rte_pipeline_table_entry *) &entry,
-		&rsp->key_found,
-		(struct rte_pipeline_table_entry **) &rsp->entry_ptr);
-
-	return rsp;
-}
-
-static void *
-pipeline_fc_msg_req_add_bulk_handler(struct pipeline *p, void *msg)
-{
-	struct pipeline_fc_add_bulk_msg_req *req = msg;
-	struct pipeline_fc_add_bulk_msg_rsp *rsp = msg;
-	uint32_t i;
-
-	for (i = 0; i < req->n_keys; i++) {
-		struct pipeline_fc_add_bulk_flow_req *flow_req = &req->req[i];
-		struct pipeline_fc_add_bulk_flow_rsp *flow_rsp = &req->rsp[i];
-
-		struct flow_table_entry entry = {
-			.head = {
-				.action = RTE_PIPELINE_ACTION_PORT,
-				{.port_id = p->port_out_id[flow_req->port_id]},
-			},
-			.flow_id = flow_req->flow_id,
-		};
-
-		int status = rte_pipeline_table_entry_add(p->p,
-			p->table_id[0],
-			&flow_req->key,
-			(struct rte_pipeline_table_entry *) &entry,
-			&flow_rsp->key_found,
-			(struct rte_pipeline_table_entry **)
-				&flow_rsp->entry_ptr);
-
-		if (status)
-			break;
-	}
-
-	rsp->n_keys = i;
-
-	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;
-
-	rsp->status = rte_pipeline_table_entry_delete(p->p,
-		p->table_id[0],
-		&req->key,
-		&rsp->key_found,
-		NULL);
-
-	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 flow_table_entry default_entry = {
-		.head = {
-			.action = RTE_PIPELINE_ACTION_PORT,
-			{.port_id = p->port_out_id[req->port_id]},
-		},
-
-		.flow_id = 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;
-}
-
-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;
-}
-
-struct pipeline_be_ops pipeline_flow_classification_be_ops = {
-	.f_init = pipeline_fc_init,
-	.f_free = pipeline_fc_free,
-	.f_run = NULL,
-	.f_timer = pipeline_fc_timer,
-};
diff --git a/examples/ip_pipeline/pipeline/pipeline_flow_classification_be.h b/examples/ip_pipeline/pipeline/pipeline_flow_classification_be.h
deleted file mode 100644
index 18f5bb4..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_flow_classification_be.h
+++ /dev/null
@@ -1,113 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#ifndef __INCLUDE_PIPELINE_FLOW_CLASSIFICATION_BE_H__
-#define __INCLUDE_PIPELINE_FLOW_CLASSIFICATION_BE_H__
-
-#include "pipeline_common_be.h"
-
-enum pipeline_fc_msg_req_type {
-	PIPELINE_FC_MSG_REQ_FLOW_ADD = 0,
-	PIPELINE_FC_MSG_REQ_FLOW_ADD_BULK,
-	PIPELINE_FC_MSG_REQ_FLOW_DEL,
-	PIPELINE_FC_MSG_REQ_FLOW_ADD_DEFAULT,
-	PIPELINE_FC_MSG_REQ_FLOW_DEL_DEFAULT,
-	PIPELINE_FC_MSG_REQS,
-};
-
-#ifndef PIPELINE_FC_FLOW_KEY_MAX_SIZE
-#define PIPELINE_FC_FLOW_KEY_MAX_SIZE            64
-#endif
-
-/*
- * MSG ADD
- */
-struct pipeline_fc_add_msg_req {
-	enum pipeline_msg_req_type type;
-	enum pipeline_fc_msg_req_type subtype;
-
-	uint8_t key[PIPELINE_FC_FLOW_KEY_MAX_SIZE];
-
-	uint32_t port_id;
-	uint32_t flow_id;
-};
-
-struct pipeline_fc_add_msg_rsp {
-	int status;
-	int key_found;
-	void *entry_ptr;
-};
-
-/*
- * MSG ADD BULK
- */
-struct pipeline_fc_add_bulk_flow_req {
-	uint8_t key[PIPELINE_FC_FLOW_KEY_MAX_SIZE];
-	uint32_t port_id;
-	uint32_t flow_id;
-};
-
-struct pipeline_fc_add_bulk_flow_rsp {
-	int key_found;
-	void *entry_ptr;
-};
-
-struct pipeline_fc_add_bulk_msg_req {
-	enum pipeline_msg_req_type type;
-	enum pipeline_fc_msg_req_type subtype;
-
-	struct pipeline_fc_add_bulk_flow_req *req;
-	struct pipeline_fc_add_bulk_flow_rsp *rsp;
-	uint32_t n_keys;
-};
-
-struct pipeline_fc_add_bulk_msg_rsp {
-	uint32_t n_keys;
-};
-
-/*
- * MSG DEL
- */
-struct pipeline_fc_del_msg_req {
-	enum pipeline_msg_req_type type;
-	enum pipeline_fc_msg_req_type subtype;
-
-	uint8_t key[PIPELINE_FC_FLOW_KEY_MAX_SIZE];
-};
-
-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 *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_be_ops pipeline_flow_classification_be_ops;
-
-#endif
diff --git a/examples/ip_pipeline/pipeline/pipeline_master.c b/examples/ip_pipeline/pipeline/pipeline_master.c
deleted file mode 100644
index b0d730a..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_master.c
+++ /dev/null
@@ -1,20 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#include "pipeline_master.h"
-#include "pipeline_master_be.h"
-
-static struct pipeline_fe_ops pipeline_master_fe_ops = {
-	.f_init = NULL,
-	.f_post_init = NULL,
-	.f_free = NULL,
-	.f_track = NULL,
-	.cmds = NULL,
-};
-
-struct pipeline_type pipeline_master = {
-	.name = "MASTER",
-	.be_ops = &pipeline_master_be_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
deleted file mode 100644
index a5183e3..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_master.h
+++ /dev/null
@@ -1,12 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#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_be.c b/examples/ip_pipeline/pipeline/pipeline_master_be.c
deleted file mode 100644
index c72038e..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_master_be.c
+++ /dev/null
@@ -1,141 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#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_be.h"
-
-struct pipeline_master {
-	struct app_params *app;
-	struct cmdline *cl;
-	int post_init_done;
-	int script_file_done;
-} __rte_cache_aligned;
-
-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 (app == NULL)
-		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;
-
-	/* Initialization */
-	p->app = app;
-
-	p->cl = cmdline_stdin_new(app->cmds, "pipeline> ");
-	if (p->cl == NULL) {
-		rte_free(p);
-		return NULL;
-	}
-
-	p->post_init_done = 0;
-	p->script_file_done = 0;
-	if (app->script_file == NULL)
-		p->script_file_done = 1;
-
-	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;
-	struct app_params *app = p->app;
-	int status;
-#ifdef RTE_LIBRTE_KNI
-	uint32_t i;
-#endif /* RTE_LIBRTE_KNI */
-
-	/* Application post-init phase */
-	if (p->post_init_done == 0) {
-		app_post_init(app);
-
-		p->post_init_done = 1;
-	}
-
-	/* Run startup script file */
-	if (p->script_file_done == 0) {
-		struct app_params *app = p->app;
-		int fd = open(app->script_file, O_RDONLY);
-
-		if (fd < 0)
-			printf("Cannot open CLI script file \"%s\"\n",
-				app->script_file);
-		else {
-			struct cmdline *file_cl;
-
-			printf("Running CLI script file \"%s\" ...\n",
-				app->script_file);
-			file_cl = cmdline_new(p->cl->ctx, "", fd, 1);
-			cmdline_interact(file_cl);
-			close(fd);
-		}
-
-		p->script_file_done = 1;
-	}
-
-	/* Command Line Interface (CLI) */
-	status = cmdline_poll(p->cl);
-	if (status < 0)
-		rte_panic("CLI poll error (%" PRId32 ")\n", status);
-	else if (status == RDLINE_EXITED) {
-		cmdline_stdin_exit(p->cl);
-		rte_exit(0, "Bye!\n");
-	}
-
-#ifdef RTE_LIBRTE_KNI
-	/* Handle KNI requests from Linux kernel */
-	for (i = 0; i < app->n_pktq_kni; i++)
-		rte_kni_handle_request(app->kni[i]);
-#endif /* RTE_LIBRTE_KNI */
-
-	return 0;
-}
-
-static int
-pipeline_timer(__rte_unused void *pipeline)
-{
-	return 0;
-}
-
-struct pipeline_be_ops pipeline_master_be_ops = {
-		.f_init = pipeline_init,
-		.f_free = pipeline_free,
-		.f_run = pipeline_run,
-		.f_timer = pipeline_timer,
-};
diff --git a/examples/ip_pipeline/pipeline/pipeline_master_be.h b/examples/ip_pipeline/pipeline/pipeline_master_be.h
deleted file mode 100644
index 847c564..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_master_be.h
+++ /dev/null
@@ -1,12 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#ifndef __INCLUDE_PIPELINE_MASTER_BE_H__
-#define __INCLUDE_PIPELINE_MASTER_BE_H__
-
-#include "pipeline_common_be.h"
-
-extern struct pipeline_be_ops pipeline_master_be_ops;
-
-#endif
diff --git a/examples/ip_pipeline/pipeline/pipeline_passthrough.c b/examples/ip_pipeline/pipeline/pipeline_passthrough.c
deleted file mode 100644
index 031f5f0..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_passthrough.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#include "pipeline_passthrough.h"
-#include "pipeline_passthrough_be.h"
-
-static int
-app_pipeline_passthrough_track(struct pipeline_params *p,
-	uint32_t port_in,
-	uint32_t *port_out)
-{
-	struct pipeline_passthrough_params pp;
-	int status;
-
-	/* Check input arguments */
-	if ((p == NULL) ||
-		(port_in >= p->n_ports_in) ||
-		(port_out == NULL))
-		return -1;
-
-	status = pipeline_passthrough_parse_args(&pp, p);
-	if (status)
-		return -1;
-
-	if (pp.dma_hash_lb_enabled)
-		return -1;
-
-	*port_out = port_in / (p->n_ports_in / p->n_ports_out);
-	return 0;
-}
-
-static struct pipeline_fe_ops pipeline_passthrough_fe_ops = {
-	.f_init = NULL,
-	.f_post_init = NULL,
-	.f_free = NULL,
-	.f_track = app_pipeline_passthrough_track,
-	.cmds = NULL,
-};
-
-struct pipeline_type pipeline_passthrough = {
-	.name = "PASS-THROUGH",
-	.be_ops = &pipeline_passthrough_be_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
deleted file mode 100644
index 7a7a2fc..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_passthrough.h
+++ /dev/null
@@ -1,12 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#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_be.c b/examples/ip_pipeline/pipeline/pipeline_passthrough_be.c
deleted file mode 100644
index b2bbaed..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_passthrough_be.c
+++ /dev/null
@@ -1,929 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2016 Intel Corporation
- */
-
-#include <stdio.h>
-#include <string.h>
-
-#include <rte_common.h>
-#include <rte_malloc.h>
-#include <rte_byteorder.h>
-#include <rte_table_stub.h>
-#include <rte_table_hash.h>
-#include <rte_pipeline.h>
-
-#include "pipeline_passthrough_be.h"
-#include "pipeline_actions_common.h"
-#include "parser.h"
-#include "hash_func.h"
-
-#define SWAP_DIM (PIPELINE_PASSTHROUGH_SWAP_N_FIELDS_MAX * \
-	(PIPELINE_PASSTHROUGH_SWAP_FIELD_SIZE_MAX / sizeof(uint64_t)))
-
-struct pipeline_passthrough {
-	struct pipeline p;
-	struct pipeline_passthrough_params params;
-	rte_table_hash_op_hash f_hash;
-	uint32_t swap_field0_offset[SWAP_DIM];
-	uint32_t swap_field1_offset[SWAP_DIM];
-	uint64_t swap_field_mask[SWAP_DIM];
-	uint32_t swap_n_fields;
-} __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 __rte_always_inline void
-pkt_work_dma(
-	struct rte_mbuf *pkt,
-	void *arg,
-	uint32_t dma_size,
-	uint32_t hash_enabled,
-	uint32_t lb_hash,
-	uint32_t port_out_pow2)
-{
-	struct pipeline_passthrough *p = arg;
-
-	uint64_t *dma_dst = RTE_MBUF_METADATA_UINT64_PTR(pkt,
-		p->params.dma_dst_offset);
-	uint64_t *dma_src = RTE_MBUF_METADATA_UINT64_PTR(pkt,
-		p->params.dma_src_offset);
-	uint64_t *dma_mask = (uint64_t *) p->params.dma_src_mask;
-	uint32_t *dma_hash = RTE_MBUF_METADATA_UINT32_PTR(pkt,
-		p->params.dma_hash_offset);
-	uint32_t i;
-
-	/* Read (dma_src), compute (dma_dst), write (dma_dst) */
-	for (i = 0; i < (dma_size / 8); i++)
-		dma_dst[i] = dma_src[i] & dma_mask[i];
-
-	/* Read (dma_dst), compute (hash), write (hash) */
-	if (hash_enabled) {
-		uint32_t hash = p->f_hash(dma_src, dma_mask, dma_size, 0);
-		*dma_hash = hash;
-
-		if (lb_hash) {
-			uint32_t port_out;
-
-			if (port_out_pow2)
-				port_out
-					= hash & (p->p.n_ports_out - 1);
-			else
-				port_out
-					= hash % p->p.n_ports_out;
-
-			rte_pipeline_port_out_packet_insert(p->p.p,
-				port_out, pkt);
-		}
-	}
-}
-
-static __rte_always_inline void
-pkt4_work_dma(
-	struct rte_mbuf **pkts,
-	void *arg,
-	uint32_t dma_size,
-	uint32_t hash_enabled,
-	uint32_t lb_hash,
-	uint32_t port_out_pow2)
-{
-	struct pipeline_passthrough *p = arg;
-
-	uint64_t *dma_dst0 = RTE_MBUF_METADATA_UINT64_PTR(pkts[0],
-		p->params.dma_dst_offset);
-	uint64_t *dma_dst1 = RTE_MBUF_METADATA_UINT64_PTR(pkts[1],
-		p->params.dma_dst_offset);
-	uint64_t *dma_dst2 = RTE_MBUF_METADATA_UINT64_PTR(pkts[2],
-		p->params.dma_dst_offset);
-	uint64_t *dma_dst3 = RTE_MBUF_METADATA_UINT64_PTR(pkts[3],
-		p->params.dma_dst_offset);
-
-	uint64_t *dma_src0 = RTE_MBUF_METADATA_UINT64_PTR(pkts[0],
-		p->params.dma_src_offset);
-	uint64_t *dma_src1 = RTE_MBUF_METADATA_UINT64_PTR(pkts[1],
-		p->params.dma_src_offset);
-	uint64_t *dma_src2 = RTE_MBUF_METADATA_UINT64_PTR(pkts[2],
-		p->params.dma_src_offset);
-	uint64_t *dma_src3 = RTE_MBUF_METADATA_UINT64_PTR(pkts[3],
-		p->params.dma_src_offset);
-
-	uint64_t *dma_mask = (uint64_t *) p->params.dma_src_mask;
-
-	uint32_t *dma_hash0 = RTE_MBUF_METADATA_UINT32_PTR(pkts[0],
-		p->params.dma_hash_offset);
-	uint32_t *dma_hash1 = RTE_MBUF_METADATA_UINT32_PTR(pkts[1],
-		p->params.dma_hash_offset);
-	uint32_t *dma_hash2 = RTE_MBUF_METADATA_UINT32_PTR(pkts[2],
-		p->params.dma_hash_offset);
-	uint32_t *dma_hash3 = RTE_MBUF_METADATA_UINT32_PTR(pkts[3],
-		p->params.dma_hash_offset);
-
-	uint32_t i;
-
-	/* Read (dma_src), compute (dma_dst), write (dma_dst) */
-	for (i = 0; i < (dma_size / 8); i++) {
-		dma_dst0[i] = dma_src0[i] & dma_mask[i];
-		dma_dst1[i] = dma_src1[i] & dma_mask[i];
-		dma_dst2[i] = dma_src2[i] & dma_mask[i];
-		dma_dst3[i] = dma_src3[i] & dma_mask[i];
-	}
-
-	/* Read (dma_dst), compute (hash), write (hash) */
-	if (hash_enabled) {
-		uint32_t hash0 = p->f_hash(dma_src0, dma_mask, dma_size, 0);
-		uint32_t hash1 = p->f_hash(dma_src1, dma_mask, dma_size, 0);
-		uint32_t hash2 = p->f_hash(dma_src2, dma_mask, dma_size, 0);
-		uint32_t hash3 = p->f_hash(dma_src3, dma_mask, dma_size, 0);
-
-		*dma_hash0 = hash0;
-		*dma_hash1 = hash1;
-		*dma_hash2 = hash2;
-		*dma_hash3 = hash3;
-
-		if (lb_hash) {
-			uint32_t port_out0, port_out1, port_out2, port_out3;
-
-			if (port_out_pow2) {
-				port_out0
-					= hash0 & (p->p.n_ports_out - 1);
-				port_out1
-					= hash1 & (p->p.n_ports_out - 1);
-				port_out2
-					= hash2 & (p->p.n_ports_out - 1);
-				port_out3
-					= hash3 & (p->p.n_ports_out - 1);
-			} else {
-				port_out0
-					= hash0 % p->p.n_ports_out;
-				port_out1
-					= hash1 % p->p.n_ports_out;
-				port_out2
-					= hash2 % p->p.n_ports_out;
-				port_out3
-					= hash3 % p->p.n_ports_out;
-			}
-			rte_pipeline_port_out_packet_insert(p->p.p,
-				port_out0, pkts[0]);
-			rte_pipeline_port_out_packet_insert(p->p.p,
-				port_out1, pkts[1]);
-			rte_pipeline_port_out_packet_insert(p->p.p,
-				port_out2, pkts[2]);
-			rte_pipeline_port_out_packet_insert(p->p.p,
-				port_out3, pkts[3]);
-		}
-	}
-}
-
-static __rte_always_inline void
-pkt_work_swap(
-	struct rte_mbuf *pkt,
-	void *arg)
-{
-	struct pipeline_passthrough *p = arg;
-	uint32_t i;
-
-	/* Read(field0, field1), compute(field0, field1), write(field0, field1) */
-	for (i = 0; i < p->swap_n_fields; i++) {
-		uint64_t *field0_ptr = RTE_MBUF_METADATA_UINT64_PTR(pkt,
-			p->swap_field0_offset[i]);
-		uint64_t *field1_ptr = RTE_MBUF_METADATA_UINT64_PTR(pkt,
-			p->swap_field1_offset[i]);
-		uint64_t mask = p->swap_field_mask[i];
-
-		uint64_t field0 = *field0_ptr;
-		uint64_t field1 = *field1_ptr;
-
-		*field0_ptr = (field0 & (~mask)) + (field1 & mask);
-		*field1_ptr = (field0 & mask) + (field1 & (~mask));
-	}
-}
-
-static __rte_always_inline void
-pkt4_work_swap(
-	struct rte_mbuf **pkts,
-	void *arg)
-{
-	struct pipeline_passthrough *p = arg;
-	uint32_t i;
-
-	/* Read(field0, field1), compute(field0, field1), write(field0, field1) */
-	for (i = 0; i < p->swap_n_fields; i++) {
-		uint64_t *pkt0_field0_ptr = RTE_MBUF_METADATA_UINT64_PTR(pkts[0],
-			p->swap_field0_offset[i]);
-		uint64_t *pkt1_field0_ptr = RTE_MBUF_METADATA_UINT64_PTR(pkts[1],
-			p->swap_field0_offset[i]);
-		uint64_t *pkt2_field0_ptr = RTE_MBUF_METADATA_UINT64_PTR(pkts[2],
-			p->swap_field0_offset[i]);
-		uint64_t *pkt3_field0_ptr = RTE_MBUF_METADATA_UINT64_PTR(pkts[3],
-			p->swap_field0_offset[i]);
-
-		uint64_t *pkt0_field1_ptr = RTE_MBUF_METADATA_UINT64_PTR(pkts[0],
-			p->swap_field1_offset[i]);
-		uint64_t *pkt1_field1_ptr = RTE_MBUF_METADATA_UINT64_PTR(pkts[1],
-			p->swap_field1_offset[i]);
-		uint64_t *pkt2_field1_ptr = RTE_MBUF_METADATA_UINT64_PTR(pkts[2],
-			p->swap_field1_offset[i]);
-		uint64_t *pkt3_field1_ptr = RTE_MBUF_METADATA_UINT64_PTR(pkts[3],
-			p->swap_field1_offset[i]);
-
-		uint64_t mask = p->swap_field_mask[i];
-
-		uint64_t pkt0_field0 = *pkt0_field0_ptr;
-		uint64_t pkt1_field0 = *pkt1_field0_ptr;
-		uint64_t pkt2_field0 = *pkt2_field0_ptr;
-		uint64_t pkt3_field0 = *pkt3_field0_ptr;
-
-		uint64_t pkt0_field1 = *pkt0_field1_ptr;
-		uint64_t pkt1_field1 = *pkt1_field1_ptr;
-		uint64_t pkt2_field1 = *pkt2_field1_ptr;
-		uint64_t pkt3_field1 = *pkt3_field1_ptr;
-
-		*pkt0_field0_ptr = (pkt0_field0 & (~mask)) + (pkt0_field1 & mask);
-		*pkt1_field0_ptr = (pkt1_field0 & (~mask)) + (pkt1_field1 & mask);
-		*pkt2_field0_ptr = (pkt2_field0 & (~mask)) + (pkt2_field1 & mask);
-		*pkt3_field0_ptr = (pkt3_field0 & (~mask)) + (pkt3_field1 & mask);
-
-		*pkt0_field1_ptr = (pkt0_field0 & mask) + (pkt0_field1 & (~mask));
-		*pkt1_field1_ptr = (pkt1_field0 & mask) + (pkt1_field1 & (~mask));
-		*pkt2_field1_ptr = (pkt2_field0 & mask) + (pkt2_field1 & (~mask));
-		*pkt3_field1_ptr = (pkt3_field0 & mask) + (pkt3_field1 & (~mask));
-	}
-}
-
-#define PKT_WORK_DMA(dma_size, hash_enabled, lb_hash, port_pow2)	\
-static inline void						\
-pkt_work_dma_size##dma_size##_hash##hash_enabled		\
-	##_lb##lb_hash##_pw##port_pow2(			\
-	struct rte_mbuf *pkt,					\
-	void *arg)						\
-{								\
-	pkt_work_dma(pkt, arg, dma_size, hash_enabled, lb_hash, port_pow2);	\
-}
-
-#define PKT4_WORK_DMA(dma_size, hash_enabled, lb_hash, port_pow2)	\
-static inline void						\
-pkt4_work_dma_size##dma_size##_hash##hash_enabled			\
-	##_lb##lb_hash##_pw##port_pow2(			\
-	struct rte_mbuf **pkts,					\
-	void *arg)						\
-{								\
-	pkt4_work_dma(pkts, arg, dma_size, hash_enabled, lb_hash, port_pow2); \
-}
-
-#define port_in_ah_dma(dma_size, hash_enabled, lb_hash, port_pow2)	\
-PKT_WORK_DMA(dma_size, hash_enabled, lb_hash, port_pow2)			\
-PKT4_WORK_DMA(dma_size, hash_enabled, lb_hash, port_pow2)			\
-PIPELINE_PORT_IN_AH(port_in_ah_dma_size##dma_size##_hash	\
-	##hash_enabled##_lb##lb_hash##_pw##port_pow2,		\
-	pkt_work_dma_size##dma_size##_hash##hash_enabled		\
-	##_lb##lb_hash##_pw##port_pow2,			\
-	pkt4_work_dma_size##dma_size##_hash##hash_enabled		\
-	##_lb##lb_hash##_pw##port_pow2)
-
-
-#define port_in_ah_lb(dma_size, hash_enabled, lb_hash, port_pow2) \
-PKT_WORK_DMA(dma_size, hash_enabled, lb_hash, port_pow2)		\
-PKT4_WORK_DMA(dma_size, hash_enabled, lb_hash, port_pow2)	\
-PIPELINE_PORT_IN_AH_HIJACK_ALL(						\
-	port_in_ah_lb_size##dma_size##_hash##hash_enabled		\
-	##_lb##lb_hash##_pw##port_pow2,			\
-	pkt_work_dma_size##dma_size##_hash##hash_enabled		\
-	##_lb##lb_hash##_pw##port_pow2,	\
-	pkt4_work_dma_size##dma_size##_hash##hash_enabled		\
-	##_lb##lb_hash##_pw##port_pow2)
-
-PIPELINE_PORT_IN_AH(port_in_ah_swap, pkt_work_swap,	pkt4_work_swap)
-
-
-/* Port in AH DMA(dma_size, hash_enabled, lb_hash, port_pow2) */
-
-port_in_ah_dma(8, 0, 0, 0)
-port_in_ah_dma(8, 1, 0, 0)
-port_in_ah_lb(8, 1, 1, 0)
-port_in_ah_lb(8, 1, 1, 1)
-
-port_in_ah_dma(16, 0, 0, 0)
-port_in_ah_dma(16, 1, 0, 0)
-port_in_ah_lb(16, 1, 1, 0)
-port_in_ah_lb(16, 1, 1, 1)
-
-port_in_ah_dma(24, 0, 0, 0)
-port_in_ah_dma(24, 1, 0, 0)
-port_in_ah_lb(24, 1, 1, 0)
-port_in_ah_lb(24, 1, 1, 1)
-
-port_in_ah_dma(32, 0, 0, 0)
-port_in_ah_dma(32, 1, 0, 0)
-port_in_ah_lb(32, 1, 1, 0)
-port_in_ah_lb(32, 1, 1, 1)
-
-port_in_ah_dma(40, 0, 0, 0)
-port_in_ah_dma(40, 1, 0, 0)
-port_in_ah_lb(40, 1, 1, 0)
-port_in_ah_lb(40, 1, 1, 1)
-
-port_in_ah_dma(48, 0, 0, 0)
-port_in_ah_dma(48, 1, 0, 0)
-port_in_ah_lb(48, 1, 1, 0)
-port_in_ah_lb(48, 1, 1, 1)
-
-port_in_ah_dma(56, 0, 0, 0)
-port_in_ah_dma(56, 1, 0, 0)
-port_in_ah_lb(56, 1, 1, 0)
-port_in_ah_lb(56, 1, 1, 1)
-
-port_in_ah_dma(64, 0, 0, 0)
-port_in_ah_dma(64, 1, 0, 0)
-port_in_ah_lb(64, 1, 1, 0)
-port_in_ah_lb(64, 1, 1, 1)
-
-static rte_pipeline_port_in_action_handler
-get_port_in_ah(struct pipeline_passthrough *p)
-{
-	if ((p->params.dma_enabled == 0) &&
-		(p->params.swap_enabled == 0))
-		return NULL;
-
-	if (p->params.swap_enabled)
-		return port_in_ah_swap;
-
-	if (p->params.dma_hash_enabled) {
-		if (p->params.dma_hash_lb_enabled) {
-			if (rte_is_power_of_2(p->p.n_ports_out))
-				switch (p->params.dma_size) {
-
-				case 8: return port_in_ah_lb_size8_hash1_lb1_pw1;
-				case 16: return port_in_ah_lb_size16_hash1_lb1_pw1;
-				case 24: return port_in_ah_lb_size24_hash1_lb1_pw1;
-				case 32: return port_in_ah_lb_size32_hash1_lb1_pw1;
-				case 40: return port_in_ah_lb_size40_hash1_lb1_pw1;
-				case 48: return port_in_ah_lb_size48_hash1_lb1_pw1;
-				case 56: return port_in_ah_lb_size56_hash1_lb1_pw1;
-				case 64: return port_in_ah_lb_size64_hash1_lb1_pw1;
-				default: return NULL;
-				}
-			else
-				switch (p->params.dma_size) {
-
-				case 8: return port_in_ah_lb_size8_hash1_lb1_pw0;
-				case 16: return port_in_ah_lb_size16_hash1_lb1_pw0;
-				case 24: return port_in_ah_lb_size24_hash1_lb1_pw0;
-				case 32: return port_in_ah_lb_size32_hash1_lb1_pw0;
-				case 40: return port_in_ah_lb_size40_hash1_lb1_pw0;
-				case 48: return port_in_ah_lb_size48_hash1_lb1_pw0;
-				case 56: return port_in_ah_lb_size56_hash1_lb1_pw0;
-				case 64: return port_in_ah_lb_size64_hash1_lb1_pw0;
-				default: return NULL;
-			}
-		} else
-			switch (p->params.dma_size) {
-
-			case 8: return port_in_ah_dma_size8_hash1_lb0_pw0;
-			case 16: return port_in_ah_dma_size16_hash1_lb0_pw0;
-			case 24: return port_in_ah_dma_size24_hash1_lb0_pw0;
-			case 32: return port_in_ah_dma_size32_hash1_lb0_pw0;
-			case 40: return port_in_ah_dma_size40_hash1_lb0_pw0;
-			case 48: return port_in_ah_dma_size48_hash1_lb0_pw0;
-			case 56: return port_in_ah_dma_size56_hash1_lb0_pw0;
-			case 64: return port_in_ah_dma_size64_hash1_lb0_pw0;
-			default: return NULL;
-		}
-	} else
-		switch (p->params.dma_size) {
-
-		case 8: return port_in_ah_dma_size8_hash0_lb0_pw0;
-		case 16: return port_in_ah_dma_size16_hash0_lb0_pw0;
-		case 24: return port_in_ah_dma_size24_hash0_lb0_pw0;
-		case 32: return port_in_ah_dma_size32_hash0_lb0_pw0;
-		case 40: return port_in_ah_dma_size40_hash0_lb0_pw0;
-		case 48: return port_in_ah_dma_size48_hash0_lb0_pw0;
-		case 56: return port_in_ah_dma_size56_hash0_lb0_pw0;
-		case 64: return port_in_ah_dma_size64_hash0_lb0_pw0;
-		default: return NULL;
-		}
-}
-
-int
-pipeline_passthrough_parse_args(struct pipeline_passthrough_params *p,
-	struct pipeline_params *params)
-{
-	uint32_t dma_dst_offset_present = 0;
-	uint32_t dma_src_offset_present = 0;
-	uint32_t dma_src_mask_present = 0;
-	char dma_mask_str[PIPELINE_PASSTHROUGH_DMA_SIZE_MAX * 2 + 1];
-	uint32_t dma_size_present = 0;
-	uint32_t dma_hash_offset_present = 0;
-	uint32_t dma_hash_lb_present = 0;
-	uint32_t i;
-
-	/* default values */
-	p->dma_enabled = 0;
-	p->dma_hash_enabled = 0;
-	p->dma_hash_lb_enabled = 0;
-	memset(p->dma_src_mask, 0xFF, sizeof(p->dma_src_mask));
-	p->swap_enabled = 0;
-	p->swap_n_fields = 0;
-
-	for (i = 0; i < params->n_args; i++) {
-		char *arg_name = params->args_name[i];
-		char *arg_value = params->args_value[i];
-
-		/* dma_dst_offset */
-		if (strcmp(arg_name, "dma_dst_offset") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				dma_dst_offset_present == 0, params->name,
-				arg_name);
-			dma_dst_offset_present = 1;
-
-			status = parser_read_uint32(&p->dma_dst_offset,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			p->dma_enabled = 1;
-
-			continue;
-		}
-
-		/* dma_src_offset */
-		if (strcmp(arg_name, "dma_src_offset") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				dma_src_offset_present == 0, params->name,
-				arg_name);
-			dma_src_offset_present = 1;
-
-			status = parser_read_uint32(&p->dma_src_offset,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			p->dma_enabled = 1;
-
-			continue;
-		}
-
-		/* dma_size */
-		if (strcmp(arg_name, "dma_size") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				dma_size_present == 0, params->name,
-				arg_name);
-			dma_size_present = 1;
-
-			status = parser_read_uint32(&p->dma_size,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL(((status != -EINVAL) &&
-				(p->dma_size != 0) &&
-				((p->dma_size % 8) == 0)),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG(((status != -ERANGE) &&
-				(p->dma_size <=
-				PIPELINE_PASSTHROUGH_DMA_SIZE_MAX)),
-				params->name, arg_name, arg_value);
-
-			p->dma_enabled = 1;
-
-			continue;
-		}
-
-		/* dma_src_mask */
-		if (strcmp(arg_name, "dma_src_mask") == 0) {
-			int mask_str_len = strlen(arg_value);
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				dma_src_mask_present == 0,
-				params->name, arg_name);
-			dma_src_mask_present = 1;
-
-			PIPELINE_ARG_CHECK((mask_str_len <=
-				(PIPELINE_PASSTHROUGH_DMA_SIZE_MAX * 2)),
-				"Parse error in section \"%s\": entry "
-				"\"%s\" too long", params->name,
-				arg_name);
-
-			snprintf(dma_mask_str, mask_str_len + 1,
-				"%s", arg_value);
-
-			p->dma_enabled = 1;
-
-			continue;
-		}
-
-		/* dma_hash_offset */
-		if (strcmp(arg_name, "dma_hash_offset") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				dma_hash_offset_present == 0,
-				params->name, arg_name);
-			dma_hash_offset_present = 1;
-
-			status = parser_read_uint32(&p->dma_hash_offset,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			p->dma_hash_enabled = 1;
-
-			continue;
-		}
-
-		/* load_balance mode */
-		if (strcmp(arg_name, "lb") == 0) {
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				dma_hash_lb_present == 0,
-				params->name, arg_name);
-			dma_hash_lb_present = 1;
-
-			if (strcmp(arg_value, "hash") &&
-				strcmp(arg_value, "HASH"))
-
-				PIPELINE_PARSE_ERR_INV_VAL(0,
-					params->name,
-					arg_name,
-					arg_value);
-
-			p->dma_hash_lb_enabled = 1;
-
-			continue;
-		}
-
-		/* swap */
-		if (strcmp(arg_name, "swap") == 0) {
-			uint32_t a, b, n_args;
-			int len;
-
-			n_args = sscanf(arg_value, "%" SCNu32 " %" SCNu32 "%n",
-				&a, &b, &len);
-			PIPELINE_PARSE_ERR_INV_VAL(((n_args == 2) &&
-				((size_t) len == strlen(arg_value))),
-				params->name, arg_name, arg_value);
-
-			p->swap_field0_offset[p->swap_n_fields] = a;
-			p->swap_field1_offset[p->swap_n_fields] = b;
-			p->swap_n_fields++;
-			p->swap_enabled = 1;
-
-			continue;
-		}
-
-		/* any other */
-		PIPELINE_PARSE_ERR_INV_ENT(0, params->name, arg_name);
-	}
-
-	/* Check correlations between arguments */
-	PIPELINE_ARG_CHECK((p->dma_enabled + p->swap_enabled < 2),
-		"Parse error in section \"%s\": DMA and SWAP actions are both enabled",
-		params->name);
-	PIPELINE_ARG_CHECK((dma_dst_offset_present == p->dma_enabled),
-		"Parse error in section \"%s\": missing entry "
-		"\"dma_dst_offset\"", params->name);
-	PIPELINE_ARG_CHECK((dma_src_offset_present == p->dma_enabled),
-		"Parse error in section \"%s\": missing entry "
-		"\"dma_src_offset\"", params->name);
-	PIPELINE_ARG_CHECK((dma_size_present == p->dma_enabled),
-		"Parse error in section \"%s\": missing entry "
-		"\"dma_size\"", params->name);
-	PIPELINE_ARG_CHECK((p->dma_hash_enabled <= p->dma_enabled),
-		"Parse error in section \"%s\": missing all DMA entries",
-		params->name);
-	PIPELINE_ARG_CHECK((p->dma_hash_lb_enabled <= p->dma_hash_enabled),
-		"Parse error in section \"%s\": missing all DMA hash entries ",
-		params->name);
-
-	if (dma_src_mask_present) {
-		uint32_t dma_size = p->dma_size;
-		int status;
-
-		PIPELINE_ARG_CHECK((strlen(dma_mask_str) ==
-			(dma_size * 2)), "Parse error in section "
-			"\"%s\": dma_src_mask should have exactly %u hex "
-			"digits", params->name, (dma_size * 2));
-
-		status = parse_hex_string(dma_mask_str, p->dma_src_mask,
-			&p->dma_size);
-
-		PIPELINE_PARSE_ERR_INV_VAL(((status == 0) &&
-			(dma_size == p->dma_size)), params->name,
-			"dma_src_mask", dma_mask_str);
-	}
-
-	if (p->dma_hash_lb_enabled)
-		PIPELINE_ARG_CHECK((params->n_ports_out > 1),
-			"Parse error in section \"%s\": entry \"lb\" not "
-			"allowed for single output port pipeline",
-			params->name);
-	else
-		PIPELINE_ARG_CHECK(((params->n_ports_in >= params->n_ports_out)
-			&& ((params->n_ports_in % params->n_ports_out) == 0)),
-			"Parse error in section \"%s\": n_ports_in needs to be "
-			"a multiple of n_ports_out (lb mode disabled)",
-			params->name);
-
-	return 0;
-}
-
-static rte_table_hash_op_hash
-get_hash_function(struct pipeline_passthrough *p)
-{
-	switch (p->params.dma_size) {
-
-	case 8: return hash_default_key8;
-	case 16: return hash_default_key16;
-	case 24: return hash_default_key24;
-	case 32: return hash_default_key32;
-	case 40: return hash_default_key40;
-	case 48: return hash_default_key48;
-	case 56: return hash_default_key56;
-	case 64: return hash_default_key64;
-	default: return NULL;
-	}
-}
-
-static int
-pipeline_passthrough_swap_convert(struct pipeline_passthrough *p)
-{
-	uint32_t i;
-
-	p->swap_n_fields = 0;
-
-	for (i = 0; i < p->params.swap_n_fields; i++) {
-		uint32_t offset0 = p->params.swap_field0_offset[i];
-		uint32_t offset1 = p->params.swap_field1_offset[i];
-		uint32_t size = offset1 - offset0;
-		uint32_t j;
-
-		/* Check */
-		if ((offset0 >= offset1) ||
-			(size > PIPELINE_PASSTHROUGH_SWAP_FIELD_SIZE_MAX) ||
-			(p->swap_n_fields >= SWAP_DIM))
-			return -1;
-
-		for (j = 0; j < (size / sizeof(uint64_t)); j++) {
-			p->swap_field0_offset[p->swap_n_fields] = offset0;
-			p->swap_field1_offset[p->swap_n_fields] = offset1;
-			p->swap_field_mask[p->swap_n_fields] = UINT64_MAX;
-			p->swap_n_fields++;
-			offset0 += sizeof(uint64_t);
-			offset1 += sizeof(uint64_t);
-		}
-		if (size % sizeof(uint64_t)) {
-			uint32_t n_bits = (size % sizeof(uint64_t)) * 8;
-
-			p->swap_field0_offset[p->swap_n_fields] = offset0;
-			p->swap_field1_offset[p->swap_n_fields] = offset1;
-			p->swap_field_mask[p->swap_n_fields] =
-				RTE_LEN2MASK(n_bits, uint64_t);
-			p->swap_n_fields++;
-		}
-	}
-
-	return 0;
-}
-
-static void*
-pipeline_passthrough_init(struct pipeline_params *params,
-	__rte_unused void *arg)
-{
-	struct pipeline *p;
-	struct pipeline_passthrough *p_pt;
-	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_passthrough));
-	p = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
-	p_pt = (struct pipeline_passthrough *) p;
-	if (p == NULL)
-		return NULL;
-
-	strcpy(p->name, params->name);
-	p->log_level = params->log_level;
-
-	PLOG(p, HIGH, "Pass-through");
-
-	/* Parse arguments */
-	if (pipeline_passthrough_parse_args(&p_pt->params, params))
-		return NULL;
-	if (pipeline_passthrough_swap_convert(p_pt))
-		return NULL;
-	p_pt->f_hash = get_hash_function(p_pt);
-
-	/* 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;
-		}
-	}
-
-	p->n_ports_in = params->n_ports_in;
-	p->n_ports_out = params->n_ports_out;
-	p->n_tables = p->n_ports_in;
-
-	/*Input ports*/
-	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 = get_port_in_ah(p_pt),
-			.arg_ah = p_pt,
-			.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 */
-	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,
-			.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 */
-	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++) {
-		uint32_t port_out_id = (p_pt->params.dma_hash_lb_enabled == 0) ?
-			(i / (p->n_ports_in / p->n_ports_out)) :
-			0;
-
-		struct rte_pipeline_table_entry default_entry = {
-			.action = RTE_PIPELINE_ACTION_PORT,
-			{.port_id = p->port_out_id[port_out_id]},
-		};
-
-		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;
-}
-
-struct pipeline_be_ops pipeline_passthrough_be_ops = {
-	.f_init = pipeline_passthrough_init,
-	.f_free = pipeline_passthrough_free,
-	.f_run = NULL,
-	.f_timer = pipeline_passthrough_timer,
-};
diff --git a/examples/ip_pipeline/pipeline/pipeline_passthrough_be.h b/examples/ip_pipeline/pipeline/pipeline_passthrough_be.h
deleted file mode 100644
index 94d1d1c..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_passthrough_be.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#ifndef __INCLUDE_PIPELINE_PASSTHROUGH_BE_H__
-#define __INCLUDE_PIPELINE_PASSTHROUGH_BE_H__
-
-#include "pipeline_common_be.h"
-
-#define PIPELINE_PASSTHROUGH_DMA_SIZE_MAX                             64
-
-#ifndef PIPELINE_PASSTHROUGH_SWAP_N_FIELDS_MAX
-#define PIPELINE_PASSTHROUGH_SWAP_N_FIELDS_MAX                        8
-#endif
-
-#ifndef PIPELINE_PASSTHROUGH_SWAP_FIELD_SIZE_MAX
-#define PIPELINE_PASSTHROUGH_SWAP_FIELD_SIZE_MAX                      16
-#endif
-
-struct pipeline_passthrough_params {
-	uint32_t dma_enabled;
-	uint32_t dma_dst_offset;
-	uint32_t dma_src_offset;
-	uint8_t dma_src_mask[PIPELINE_PASSTHROUGH_DMA_SIZE_MAX];
-	uint32_t dma_size;
-
-	uint32_t dma_hash_enabled;
-	uint32_t dma_hash_offset;
-
-	uint32_t dma_hash_lb_enabled;
-
-	uint32_t swap_enabled;
-	uint32_t swap_field0_offset[PIPELINE_PASSTHROUGH_SWAP_N_FIELDS_MAX];
-	uint32_t swap_field1_offset[PIPELINE_PASSTHROUGH_SWAP_N_FIELDS_MAX];
-	uint32_t swap_n_fields;
-};
-
-int
-pipeline_passthrough_parse_args(struct pipeline_passthrough_params *p,
-	struct pipeline_params *params);
-
-extern struct pipeline_be_ops pipeline_passthrough_be_ops;
-
-#endif
diff --git a/examples/ip_pipeline/pipeline/pipeline_routing.c b/examples/ip_pipeline/pipeline/pipeline_routing.c
deleted file mode 100644
index 0562c63..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_routing.c
+++ /dev/null
@@ -1,1613 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2016 Intel Corporation
- */
-
-#include <cmdline_parse.h>
-#include <cmdline_parse_num.h>
-#include <cmdline_parse_string.h>
-
-#include "app.h"
-#include "pipeline_common_fe.h"
-#include "pipeline_routing.h"
-#include "parser.h"
-
-struct app_pipeline_routing_route {
-	struct pipeline_routing_route_key key;
-	struct pipeline_routing_route_data data;
-	void *entry_ptr;
-
-	TAILQ_ENTRY(app_pipeline_routing_route) node;
-};
-
-struct app_pipeline_routing_arp_entry {
-	struct pipeline_routing_arp_key key;
-	struct ether_addr macaddr;
-	void *entry_ptr;
-
-	TAILQ_ENTRY(app_pipeline_routing_arp_entry) node;
-};
-
-struct pipeline_routing {
-	/* Parameters */
-	struct app_params *app;
-	uint32_t pipeline_id;
-	uint32_t n_ports_in;
-	uint32_t n_ports_out;
-	struct pipeline_routing_params rp;
-
-	/* Links */
-	uint32_t link_id[PIPELINE_MAX_PORT_OUT];
-
-	/* Routes */
-	TAILQ_HEAD(, app_pipeline_routing_route) routes;
-	uint32_t n_routes;
-
-	uint32_t default_route_present;
-	uint32_t default_route_port_id;
-	void *default_route_entry_ptr;
-
-	/* 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;
-};
-
-static int
-app_pipeline_routing_find_link(struct pipeline_routing *p,
-	uint32_t link_id,
-	uint32_t *port_id)
-{
-	uint32_t i;
-
-	for (i = 0; i < p->n_ports_out; i++)
-		if (p->link_id[i] == link_id) {
-			*port_id = i;
-			return 0;
-		}
-
-	return -1;
-}
-
-static void
-app_pipeline_routing_link_op(__rte_unused struct app_params *app,
-	uint32_t link_id,
-	uint32_t up,
-	void *arg)
-{
-	struct pipeline_routing_route_key key0, key1;
-	struct pipeline_routing *p = arg;
-	struct app_link_params *lp;
-	uint32_t port_id, netmask;
-	int status;
-
-	if (app == NULL)
-		return;
-
-	APP_PARAM_FIND_BY_ID(app->link_params, "LINK", link_id, lp);
-	if (lp == NULL)
-		return;
-
-	status = app_pipeline_routing_find_link(p,
-		link_id,
-		&port_id);
-	if (status)
-		return;
-
-	netmask = (~0U) << (32 - lp->depth);
-
-	/* Local network (directly attached network) */
-	key0.type = PIPELINE_ROUTING_ROUTE_IPV4;
-	key0.key.ipv4.ip = lp->ip & netmask;
-	key0.key.ipv4.depth = lp->depth;
-
-	/* Local termination */
-	key1.type = PIPELINE_ROUTING_ROUTE_IPV4;
-	key1.key.ipv4.ip = lp->ip;
-	key1.key.ipv4.depth = 32;
-
-	if (up) {
-		struct pipeline_routing_route_data data0, data1;
-
-		/* Local network (directly attached network) */
-		memset(&data0, 0, sizeof(data0));
-		data0.flags = PIPELINE_ROUTING_ROUTE_LOCAL |
-			PIPELINE_ROUTING_ROUTE_ARP;
-		if (p->rp.encap == PIPELINE_ROUTING_ENCAP_ETHERNET_QINQ)
-			data0.flags |= PIPELINE_ROUTING_ROUTE_QINQ;
-		if (p->rp.encap == PIPELINE_ROUTING_ENCAP_ETHERNET_MPLS) {
-			data0.flags |= PIPELINE_ROUTING_ROUTE_MPLS;
-			data0.l2.mpls.n_labels = 1;
-		}
-		data0.port_id = port_id;
-
-		if (p->rp.n_arp_entries)
-			app_pipeline_routing_add_route(app,
-				p->pipeline_id,
-				&key0,
-				&data0);
-
-		/* Local termination */
-		memset(&data1, 0, sizeof(data1));
-		data1.flags = PIPELINE_ROUTING_ROUTE_LOCAL |
-			PIPELINE_ROUTING_ROUTE_ARP;
-		if (p->rp.encap == PIPELINE_ROUTING_ENCAP_ETHERNET_QINQ)
-			data1.flags |= PIPELINE_ROUTING_ROUTE_QINQ;
-		if (p->rp.encap == PIPELINE_ROUTING_ENCAP_ETHERNET_MPLS) {
-			data1.flags |= PIPELINE_ROUTING_ROUTE_MPLS;
-			data1.l2.mpls.n_labels = 1;
-		}
-		data1.port_id = p->rp.port_local_dest;
-
-		app_pipeline_routing_add_route(app,
-			p->pipeline_id,
-			&key1,
-			&data1);
-	} else {
-		/* Local network (directly attached network) */
-		if (p->rp.n_arp_entries)
-			app_pipeline_routing_delete_route(app,
-				p->pipeline_id,
-				&key0);
-
-		/* Local termination */
-		app_pipeline_routing_delete_route(app,
-			p->pipeline_id,
-			&key1);
-	}
-}
-
-static int
-app_pipeline_routing_set_link_op(
-	struct app_params *app,
-	struct pipeline_routing *p)
-{
-	uint32_t port_id;
-
-	for (port_id = 0; port_id < p->n_ports_out; port_id++) {
-		struct app_link_params *link;
-		uint32_t link_id;
-		int status;
-
-		link = app_pipeline_track_pktq_out_to_link(app,
-			p->pipeline_id,
-			port_id);
-		if (link == NULL)
-			continue;
-
-		link_id = link - app->link_params;
-		p->link_id[port_id] = link_id;
-
-		status = app_link_set_op(app,
-			link_id,
-			p->pipeline_id,
-			app_pipeline_routing_link_op,
-			(void *) p);
-		if (status)
-			return status;
-	}
-
-	return 0;
-}
-
-static void *
-app_pipeline_routing_init(struct pipeline_params *params,
-	void *arg)
-{
-	struct app_params *app = (struct app_params *) arg;
-	struct pipeline_routing *p;
-	uint32_t pipeline_id, size;
-	int status;
-
-	/* Check input arguments */
-	if ((params == NULL) ||
-		(params->n_ports_in == 0) ||
-		(params->n_ports_out == 0))
-		return NULL;
-
-	APP_PARAM_GET_ID(params, "PIPELINE", pipeline_id);
-
-	/* 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->app = app;
-	p->pipeline_id = pipeline_id;
-	p->n_ports_in = params->n_ports_in;
-	p->n_ports_out = params->n_ports_out;
-
-	status = pipeline_routing_parse_args(&p->rp, params);
-	if (status) {
-		rte_free(p);
-		return NULL;
-	}
-	TAILQ_INIT(&p->routes);
-	p->n_routes = 0;
-
-	TAILQ_INIT(&p->arp_entries);
-	p->n_arp_entries = 0;
-
-	app_pipeline_routing_set_link_op(app, p);
-
-	return p;
-}
-
-static int
-app_pipeline_routing_post_init(void *pipeline)
-{
-	struct pipeline_routing *p = pipeline;
-
-	/* Check input arguments */
-	if (p == NULL)
-		return -1;
-
-	return app_pipeline_routing_set_macaddr(p->app, p->pipeline_id);
-}
-
-static int
-app_pipeline_routing_free(void *pipeline)
-{
-	struct pipeline_routing *p = pipeline;
-
-	/* Check input arguments */
-	if (p == NULL)
-		return -1;
-
-	/* Free resources */
-	while (!TAILQ_EMPTY(&p->routes)) {
-		struct app_pipeline_routing_route *route;
-
-		route = TAILQ_FIRST(&p->routes);
-		TAILQ_REMOVE(&p->routes, route, node);
-		rte_free(route);
-	}
-
-	while (!TAILQ_EMPTY(&p->arp_entries)) {
-		struct app_pipeline_routing_arp_entry *arp_entry;
-
-		arp_entry = TAILQ_FIRST(&p->arp_entries);
-		TAILQ_REMOVE(&p->arp_entries, arp_entry, node);
-		rte_free(arp_entry);
-	}
-
-	rte_free(p);
-	return 0;
-}
-
-static struct app_pipeline_routing_route *
-app_pipeline_routing_find_route(struct pipeline_routing *p,
-		const struct pipeline_routing_route_key *key)
-{
-	struct app_pipeline_routing_route *it, *found;
-
-	found = NULL;
-	TAILQ_FOREACH(it, &p->routes, node) {
-		if ((key->type == it->key.type) &&
-			(key->key.ipv4.ip == it->key.key.ipv4.ip) &&
-			(key->key.ipv4.depth == it->key.key.ipv4.depth)) {
-			found = it;
-			break;
-		}
-	}
-
-	return found;
-}
-
-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;
-
-	found = NULL;
-	TAILQ_FOREACH(it, &p->arp_entries, node) {
-		if ((key->type == it->key.type) &&
-			(key->key.ipv4.port_id == it->key.key.ipv4.port_id) &&
-			(key->key.ipv4.ip == it->key.key.ipv4.ip)) {
-			found = it;
-			break;
-		}
-	}
-
-	return found;
-}
-
-static void
-print_route(const struct app_pipeline_routing_route *route)
-{
-	if (route->key.type == PIPELINE_ROUTING_ROUTE_IPV4) {
-		const struct pipeline_routing_route_key_ipv4 *key =
-				&route->key.key.ipv4;
-
-		printf("IP Prefix = %" PRIu32 ".%" PRIu32
-			".%" PRIu32 ".%" PRIu32 "/%" PRIu32
-			" => (Port = %" PRIu32,
-
-			(key->ip >> 24) & 0xFF,
-			(key->ip >> 16) & 0xFF,
-			(key->ip >> 8) & 0xFF,
-			key->ip & 0xFF,
-
-			key->depth,
-			route->data.port_id);
-
-		if (route->data.flags & PIPELINE_ROUTING_ROUTE_LOCAL)
-			printf(", Local");
-		else if (route->data.flags & PIPELINE_ROUTING_ROUTE_ARP)
-			printf(
-				", Next Hop IP = %" PRIu32 ".%" PRIu32
-				".%" PRIu32 ".%" PRIu32,
-
-				(route->data.ethernet.ip >> 24) & 0xFF,
-				(route->data.ethernet.ip >> 16) & 0xFF,
-				(route->data.ethernet.ip >> 8) & 0xFF,
-				route->data.ethernet.ip & 0xFF);
-		else
-			printf(
-				", Next Hop HWaddress = %02" PRIx32
-				":%02" PRIx32 ":%02" PRIx32
-				":%02" PRIx32 ":%02" PRIx32
-				":%02" PRIx32,
-
-				route->data.ethernet.macaddr.addr_bytes[0],
-				route->data.ethernet.macaddr.addr_bytes[1],
-				route->data.ethernet.macaddr.addr_bytes[2],
-				route->data.ethernet.macaddr.addr_bytes[3],
-				route->data.ethernet.macaddr.addr_bytes[4],
-				route->data.ethernet.macaddr.addr_bytes[5]);
-
-		if (route->data.flags & PIPELINE_ROUTING_ROUTE_QINQ)
-			printf(", QinQ SVLAN = %" PRIu32 " CVLAN = %" PRIu32,
-				route->data.l2.qinq.svlan,
-				route->data.l2.qinq.cvlan);
-
-		if (route->data.flags & PIPELINE_ROUTING_ROUTE_MPLS) {
-			uint32_t i;
-
-			printf(", MPLS labels");
-			for (i = 0; i < route->data.l2.mpls.n_labels; i++)
-				printf(" %" PRIu32,
-					route->data.l2.mpls.labels[i]);
-		}
-
-		printf(")\n");
-	}
-}
-
-static void
-print_arp_entry(const struct app_pipeline_routing_arp_entry *entry)
-{
-	printf("(Port = %" PRIu32 ", IP = %" PRIu32 ".%" PRIu32
-		".%" PRIu32 ".%" PRIu32
-		") => HWaddress = %02" PRIx32 ":%02" PRIx32 ":%02" PRIx32
-		":%02" PRIx32 ":%02" PRIx32 ":%02" PRIx32 "\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->macaddr.addr_bytes[0],
-		entry->macaddr.addr_bytes[1],
-		entry->macaddr.addr_bytes[2],
-		entry->macaddr.addr_bytes[3],
-		entry->macaddr.addr_bytes[4],
-		entry->macaddr.addr_bytes[5]);
-}
-
-static int
-app_pipeline_routing_route_ls(struct app_params *app, uint32_t pipeline_id)
-{
-	struct pipeline_routing *p;
-	struct app_pipeline_routing_route *it;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_routing);
-	if (p == NULL)
-		return -EINVAL;
-
-	TAILQ_FOREACH(it, &p->routes, node)
-		print_route(it);
-
-	if (p->default_route_present)
-		printf("Default route: port %" PRIu32 " (entry ptr = %p)\n",
-				p->default_route_port_id,
-				p->default_route_entry_ptr);
-	else
-		printf("Default: DROP\n");
-
-	return 0;
-}
-
-int
-app_pipeline_routing_add_route(struct app_params *app,
-	uint32_t pipeline_id,
-	struct pipeline_routing_route_key *key,
-	struct pipeline_routing_route_data *data)
-{
-	struct pipeline_routing *p;
-
-	struct pipeline_routing_route_add_msg_req *req;
-	struct pipeline_routing_route_add_msg_rsp *rsp;
-
-	struct app_pipeline_routing_route *entry;
-
-	int new_entry;
-
-	/* Check input arguments */
-	if ((app == NULL) ||
-		(key == NULL) ||
-		(data == NULL))
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_routing);
-	if (p == NULL)
-		return -1;
-
-	switch (key->type) {
-	case PIPELINE_ROUTING_ROUTE_IPV4:
-	{
-		uint32_t depth = key->key.ipv4.depth;
-		uint32_t netmask;
-
-		/* key */
-		if ((depth == 0) || (depth > 32))
-			return -1;
-
-		netmask = (~0U) << (32 - depth);
-		key->key.ipv4.ip &= netmask;
-
-		/* data */
-		if (data->port_id >= p->n_ports_out)
-			return -1;
-
-		/* Valid range of VLAN tags 12 bits */
-		if (data->flags & PIPELINE_ROUTING_ROUTE_QINQ)
-			if ((data->l2.qinq.svlan & 0xF000) ||
-					(data->l2.qinq.cvlan & 0xF000))
-				return -1;
-
-		/* Max number of MPLS labels supported */
-		if (data->flags & PIPELINE_ROUTING_ROUTE_MPLS) {
-			uint32_t i;
-
-			if (data->l2.mpls.n_labels >
-					PIPELINE_ROUTING_MPLS_LABELS_MAX)
-				return -1;
-
-			/* Max MPLS label value 20 bits */
-			for (i = 0; i < data->l2.mpls.n_labels; i++)
-				if (data->l2.mpls.labels[i] & 0xFFF00000)
-					return -1;
-		}
-	}
-	break;
-
-	default:
-		return -1;
-	}
-
-	/* 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;
-	}
-
-	/* Allocate and write request */
-	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_ROUTE_ADD;
-	memcpy(&req->key, key, sizeof(*key));
-	memcpy(&req->data, data, sizeof(*data));
-
-	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL) {
-		if (new_entry)
-			rte_free(entry);
-		return -1;
-	}
-
-	/* Read response and write entry */
-	if (rsp->status ||
-		(rsp->entry_ptr == NULL) ||
-		((new_entry == 0) && (rsp->key_found == 0)) ||
-		((new_entry == 1) && (rsp->key_found == 1))) {
-		app_msg_free(app, rsp);
-		if (new_entry)
-			rte_free(entry);
-		return -1;
-	}
-
-	memcpy(&entry->key, key, sizeof(*key));
-	memcpy(&entry->data, data, sizeof(*data));
-	entry->entry_ptr = rsp->entry_ptr;
-
-	/* Commit entry */
-	if (new_entry) {
-		TAILQ_INSERT_TAIL(&p->routes, entry, node);
-		p->n_routes++;
-	}
-
-	/* 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_route *entry;
-
-	/* Check input arguments */
-	if ((app == NULL) ||
-		(key == NULL))
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_routing);
-	if (p == NULL)
-		return -1;
-
-	switch (key->type) {
-	case PIPELINE_ROUTING_ROUTE_IPV4:
-	{
-		uint32_t depth = key->key.ipv4.depth;
-		uint32_t netmask;
-
-		/* key */
-		if ((depth == 0) || (depth > 32))
-			return -1;
-
-		netmask = (~0U) << (32 - depth);
-		key->key.ipv4.ip &= netmask;
-	}
-	break;
-
-	default:
-		return -1;
-	}
-
-	/* 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_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	/* Read response */
-	if (rsp->status || !rsp->key_found) {
-		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;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_routing);
-	if (p == NULL)
-		return -1;
-
-	if (port_id >= p->n_ports_out)
-		return -1;
-
-	/* 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_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	/* Read response and write route */
-	if (rsp->status || (rsp->entry_ptr == NULL)) {
-		app_msg_free(app, rsp);
-		return -1;
-	}
-
-	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;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_routing);
-	if (p == NULL)
-		return -1;
-
-	/* 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_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	/* Read response and write route */
-	if (rsp->status) {
-		app_msg_free(app, rsp);
-		return -1;
-	}
-
-	/* Commit route */
-	p->default_route_present = 0;
-
-	/* Free response */
-	app_msg_free(app, rsp);
-
-	return 0;
-}
-
-static int
-app_pipeline_routing_arp_ls(struct app_params *app, uint32_t pipeline_id)
-{
-	struct pipeline_routing *p;
-	struct app_pipeline_routing_arp_entry *it;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_routing);
-	if (p == NULL)
-		return -EINVAL;
-
-	TAILQ_FOREACH(it, &p->arp_entries, node)
-		print_arp_entry(it);
-
-	if (p->default_arp_entry_present)
-		printf("Default entry: port %" PRIu32 " (entry ptr = %p)\n",
-				p->default_arp_entry_port_id,
-				p->default_arp_entry_ptr);
-	else
-		printf("Default: DROP\n");
-
-	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;
-
-	/* Check input arguments */
-	if ((app == NULL) ||
-		(key == NULL) ||
-		(macaddr == NULL))
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_routing);
-	if (p == NULL)
-		return -1;
-
-	switch (key->type) {
-	case PIPELINE_ROUTING_ARP_IPV4:
-	{
-		uint32_t port_id = key->key.ipv4.port_id;
-
-		/* key */
-		if (port_id >= p->n_ports_out)
-			return -1;
-	}
-	break;
-
-	default:
-		return -1;
-	}
-
-	/* 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_DEFAULT);
-	if (rsp == NULL) {
-		if (new_entry)
-			rte_free(entry);
-		return -1;
-	}
-
-	/* Read response and write entry */
-	if (rsp->status ||
-		(rsp->entry_ptr == NULL) ||
-		((new_entry == 0) && (rsp->key_found == 0)) ||
-		((new_entry == 1) && (rsp->key_found == 1))) {
-		app_msg_free(app, rsp);
-		if (new_entry)
-			rte_free(entry);
-		return -1;
-	}
-
-	memcpy(&entry->key, key, sizeof(*key));
-	ether_addr_copy(macaddr, &entry->macaddr);
-	entry->entry_ptr = rsp->entry_ptr;
-
-	/* Commit entry */
-	if (new_entry) {
-		TAILQ_INSERT_TAIL(&p->arp_entries, entry, node);
-		p->n_arp_entries++;
-	}
-
-	/* Message buffer free */
-	app_msg_free(app, rsp);
-	return 0;
-}
-
-int
-app_pipeline_routing_delete_arp_entry(struct app_params *app,
-	uint32_t pipeline_id,
-	struct pipeline_routing_arp_key *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;
-
-	/* Check input arguments */
-	if ((app == NULL) ||
-		(key == NULL))
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_routing);
-	if (p == NULL)
-		return -EINVAL;
-
-	switch (key->type) {
-	case PIPELINE_ROUTING_ARP_IPV4:
-	{
-		uint32_t port_id = key->key.ipv4.port_id;
-
-		/* key */
-		if (port_id >= p->n_ports_out)
-			return -1;
-	}
-	break;
-
-	default:
-		return -1;
-	}
-
-	/* 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_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	/* Read response */
-	if (rsp->status || !rsp->key_found) {
-		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;
-}
-
-int
-app_pipeline_routing_add_default_arp_entry(struct app_params *app,
-		uint32_t pipeline_id,
-		uint32_t port_id)
-{
-	struct pipeline_routing *p;
-
-	struct pipeline_routing_arp_add_default_msg_req *req;
-	struct pipeline_routing_arp_add_default_msg_rsp *rsp;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_routing);
-	if (p == NULL)
-		return -1;
-
-	if (port_id >= p->n_ports_out)
-		return -1;
-
-	/* 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_DEFAULT);
-	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;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_routing);
-	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_DEFAULT);
-	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;
-}
-
-int
-app_pipeline_routing_set_macaddr(struct app_params *app,
-	uint32_t pipeline_id)
-{
-	struct app_pipeline_params *p;
-	struct pipeline_routing_set_macaddr_msg_req *req;
-	struct pipeline_routing_set_macaddr_msg_rsp *rsp;
-	uint32_t port_id;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -EINVAL;
-
-	APP_PARAM_FIND_BY_ID(app->pipeline_params, "PIPELINE", pipeline_id, p);
-	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_SET_MACADDR;
-
-	memset(req->macaddr, 0, sizeof(req->macaddr));
-	for (port_id = 0; port_id < p->n_pktq_out; port_id++) {
-		struct app_link_params *link;
-
-		link = app_pipeline_track_pktq_out_to_link(app,
-			pipeline_id,
-			port_id);
-		if (link)
-			req->macaddr[port_id] = link->mac_addr;
-	}
-
-	/* Send request and wait for response */
-	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL)
-		return -ETIMEDOUT;
-
-	/* Read response and write entry */
-	if (rsp->status) {
-		app_msg_free(app, rsp);
-		return rsp->status;
-	}
-
-	/* Free response */
-	app_msg_free(app, rsp);
-
-	return 0;
-}
-
-/*
- * route
- *
- * route add (ARP = ON/OFF, MPLS = ON/OFF, QINQ = ON/OFF):
- *    p <pipelineid> route add <ipaddr> <depth> port <portid> ether <nhmacaddr>
- *    p <pipelineid> route add <ipaddr> <depth> port <portid> ether <nhipaddr>
- *    p <pipelineid> route add <ipaddr> <depth> port <portid> ether <nhmacaddr> qinq <svlan> <cvlan>
- *    p <pipelineid> route add <ipaddr> <depth> port <portid> ether <nhipaddr> qinq <svlan> <cvlan>
- *    p <pipelineid> route add <ipaddr> <depth> port <portid> ether <nhmacaddr> mpls <mpls labels>
- *    p <pipelineid> route add <ipaddr> <depth> port <portid> ether <nhipaddr> mpls <mpls labels>
- *
- * route add default:
- *    p <pipelineid> route add default <portid>
- *
- * route del:
- *    p <pipelineid> route del <ipaddr> <depth>
- *
- * route del default:
- *    p <pipelineid> route del default
- *
- * route ls:
- *    p <pipelineid> route ls
- */
-
-struct cmd_route_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t p;
-	cmdline_fixed_string_t route_string;
-	cmdline_multi_string_t multi_string;
-};
-
-static void
-cmd_route_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_route_result *params = parsed_result;
-	struct app_params *app = data;
-
-	char *tokens[16];
-	uint32_t n_tokens = RTE_DIM(tokens);
-	int status;
-
-	status = parse_tokenize_string(params->multi_string, tokens, &n_tokens);
-	if (status != 0) {
-		printf(CMD_MSG_TOO_MANY_ARGS, "route");
-		return;
-	}
-
-	/* route add */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "add") == 0) &&
-		strcmp(tokens[1], "default")) {
-		struct pipeline_routing_route_key key;
-		struct pipeline_routing_route_data route_data;
-		struct in_addr ipv4, nh_ipv4;
-		struct ether_addr mac_addr;
-		uint32_t depth, port_id, svlan, cvlan, i;
-		uint32_t mpls_labels[PIPELINE_ROUTING_MPLS_LABELS_MAX];
-		uint32_t n_labels = RTE_DIM(mpls_labels);
-
-		memset(&key, 0, sizeof(key));
-		memset(&route_data, 0, sizeof(route_data));
-
-		if (n_tokens < 7) {
-			printf(CMD_MSG_NOT_ENOUGH_ARGS, "route add");
-			return;
-		}
-
-		if (parse_ipv4_addr(tokens[1], &ipv4)) {
-			printf(CMD_MSG_INVALID_ARG, "ipaddr");
-			return;
-		}
-
-		if (parser_read_uint32(&depth, tokens[2])) {
-			printf(CMD_MSG_INVALID_ARG, "depth");
-			return;
-		}
-
-		if (strcmp(tokens[3], "port")) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "port");
-			return;
-		}
-
-		if (parser_read_uint32(&port_id, tokens[4])) {
-			printf(CMD_MSG_INVALID_ARG, "portid");
-			return;
-		}
-
-		if (strcmp(tokens[5], "ether")) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "ether");
-			return;
-		}
-
-		if (parse_mac_addr(tokens[6], &mac_addr)) {
-			if (parse_ipv4_addr(tokens[6], &nh_ipv4)) {
-				printf(CMD_MSG_INVALID_ARG, "nhmacaddr or nhipaddr");
-				return;
-			}
-
-			route_data.flags |= PIPELINE_ROUTING_ROUTE_ARP;
-		}
-
-		if (n_tokens > 7) {
-			if (strcmp(tokens[7], "mpls") == 0) {
-				if (n_tokens != 9) {
-					printf(CMD_MSG_MISMATCH_ARGS, "route add mpls");
-					return;
-				}
-
-				if (parse_mpls_labels(tokens[8], mpls_labels, &n_labels)) {
-					printf(CMD_MSG_INVALID_ARG, "mpls labels");
-					return;
-				}
-
-				route_data.flags |= PIPELINE_ROUTING_ROUTE_MPLS;
-			} else if (strcmp(tokens[7], "qinq") == 0) {
-				if (n_tokens != 10) {
-					printf(CMD_MSG_MISMATCH_ARGS, "route add qinq");
-					return;
-				}
-
-				if (parser_read_uint32(&svlan, tokens[8])) {
-					printf(CMD_MSG_INVALID_ARG, "svlan");
-					return;
-				}
-				if (parser_read_uint32(&cvlan, tokens[9])) {
-					printf(CMD_MSG_INVALID_ARG, "cvlan");
-					return;
-				}
-
-				route_data.flags |= PIPELINE_ROUTING_ROUTE_QINQ;
-			} else {
-				printf(CMD_MSG_ARG_NOT_FOUND, "mpls or qinq");
-				return;
-			}
-		}
-
-		switch (route_data.flags) {
-		case 0:
-			route_data.port_id = port_id;
-			route_data.ethernet.macaddr = mac_addr;
-			break;
-
-		case PIPELINE_ROUTING_ROUTE_ARP:
-			route_data.port_id = port_id;
-			route_data.ethernet.ip = rte_be_to_cpu_32(nh_ipv4.s_addr);
-			break;
-
-		case PIPELINE_ROUTING_ROUTE_MPLS:
-			route_data.port_id = port_id;
-			route_data.ethernet.macaddr = mac_addr;
-			for (i = 0; i < n_labels; i++)
-				route_data.l2.mpls.labels[i] = mpls_labels[i];
-			route_data.l2.mpls.n_labels = n_labels;
-			break;
-
-		case PIPELINE_ROUTING_ROUTE_MPLS | PIPELINE_ROUTING_ROUTE_ARP:
-			route_data.port_id = port_id;
-			route_data.ethernet.ip = rte_be_to_cpu_32(nh_ipv4.s_addr);
-			for (i = 0; i < n_labels; i++)
-				route_data.l2.mpls.labels[i] = mpls_labels[i];
-			route_data.l2.mpls.n_labels = n_labels;
-			break;
-
-		case PIPELINE_ROUTING_ROUTE_QINQ:
-			route_data.port_id = port_id;
-			route_data.ethernet.macaddr = mac_addr;
-			route_data.l2.qinq.svlan = svlan;
-			route_data.l2.qinq.cvlan = cvlan;
-			break;
-
-		case PIPELINE_ROUTING_ROUTE_QINQ | PIPELINE_ROUTING_ROUTE_ARP:
-		default:
-			route_data.port_id = port_id;
-			route_data.ethernet.ip = rte_be_to_cpu_32(nh_ipv4.s_addr);
-			route_data.l2.qinq.svlan = svlan;
-			route_data.l2.qinq.cvlan = cvlan;
-			break;
-		}
-
-		key.type = PIPELINE_ROUTING_ROUTE_IPV4;
-		key.key.ipv4.ip = rte_be_to_cpu_32(ipv4.s_addr);
-		key.key.ipv4.depth = depth;
-
-		status = app_pipeline_routing_add_route(app,
-			params->p,
-			&key,
-			&route_data);
-		if (status != 0)
-			printf(CMD_MSG_FAIL, "route add");
-
-		return;
-	} /* route add */
-
-	/* route add default */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "add") == 0) &&
-		(strcmp(tokens[1], "default") == 0)) {
-		uint32_t port_id;
-
-		if (n_tokens != 3) {
-			printf(CMD_MSG_MISMATCH_ARGS, "route add default");
-			return;
-		}
-
-		if (parser_read_uint32(&port_id, tokens[2])) {
-			printf(CMD_MSG_INVALID_ARG, "portid");
-			return;
-		}
-
-		status = app_pipeline_routing_add_default_route(app,
-			params->p,
-			port_id);
-		if (status != 0)
-			printf(CMD_MSG_FAIL, "route add default");
-
-		return;
-	} /* route add default */
-
-	/* route del*/
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "del") == 0) &&
-		strcmp(tokens[1], "default")) {
-		struct pipeline_routing_route_key key;
-		struct in_addr ipv4;
-		uint32_t depth;
-
-		memset(&key, 0, sizeof(key));
-
-		if (n_tokens != 3) {
-			printf(CMD_MSG_MISMATCH_ARGS, "route del");
-			return;
-		}
-
-		if (parse_ipv4_addr(tokens[1], &ipv4)) {
-			printf(CMD_MSG_INVALID_ARG, "ipaddr");
-			return;
-		}
-
-		if (parser_read_uint32(&depth, tokens[2])) {
-			printf(CMD_MSG_INVALID_ARG, "depth");
-			return;
-		}
-
-		key.type = PIPELINE_ROUTING_ROUTE_IPV4;
-		key.key.ipv4.ip = rte_be_to_cpu_32(ipv4.s_addr);
-		key.key.ipv4.depth = depth;
-
-		status = app_pipeline_routing_delete_route(app, params->p, &key);
-		if (status != 0)
-			printf(CMD_MSG_FAIL, "route del");
-
-		return;
-	} /* route del */
-
-	/* route del default */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "del") == 0) &&
-		(strcmp(tokens[1], "default") == 0)) {
-		if (n_tokens != 2) {
-			printf(CMD_MSG_MISMATCH_ARGS, "route del default");
-			return;
-		}
-
-		status = app_pipeline_routing_delete_default_route(app,
-			params->p);
-		if (status != 0)
-			printf(CMD_MSG_FAIL, "route del default");
-
-		return;
-	} /* route del default */
-
-	/* route ls */
-	if ((n_tokens >= 1) && (strcmp(tokens[0], "ls") == 0)) {
-		if (n_tokens != 1) {
-			printf(CMD_MSG_MISMATCH_ARGS, "route ls");
-			return;
-		}
-
-		status = app_pipeline_routing_route_ls(app, params->p);
-		if (status != 0)
-			printf(CMD_MSG_FAIL, "route ls");
-
-		return;
-	} /* route ls */
-
-	printf(CMD_MSG_MISMATCH_ARGS, "route");
-}
-
-static cmdline_parse_token_string_t cmd_route_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_result, p_string, "p");
-
-static cmdline_parse_token_num_t cmd_route_p =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_result, p, UINT32);
-
-static cmdline_parse_token_string_t cmd_route_route_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_result, route_string, "route");
-
-static cmdline_parse_token_string_t cmd_route_multi_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_result, multi_string,
-	TOKEN_STRING_MULTI);
-
-static cmdline_parse_inst_t cmd_route = {
-	.f = cmd_route_parsed,
-	.data = NULL,
-	.help_str = "route add / add default / del / del default / ls",
-	.tokens = {
-		(void *)&cmd_route_p_string,
-		(void *)&cmd_route_p,
-		(void *)&cmd_route_route_string,
-		(void *)&cmd_route_multi_string,
-		NULL,
-	},
-};
-
-/*
- * arp
- *
- * arp add:
- *    p <pipelineid> arp add <portid> <ipaddr> <macaddr>
- *
- * arp add default:
- *    p <pipelineid> arp add default <portid>
- *
- * arp del:
- *    p <pipelineid> arp del <portid> <ipaddr>
- *
- * arp del default:
- *    p <pipelineid> arp del default
- *
- * arp ls:
- *    p <pipelineid> arp ls
- */
-
-struct cmd_arp_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t p;
-	cmdline_fixed_string_t arp_string;
-	cmdline_multi_string_t multi_string;
-};
-
-static void
-cmd_arp_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_arp_result *params = parsed_result;
-	struct app_params *app = data;
-
-	char *tokens[16];
-	uint32_t n_tokens = RTE_DIM(tokens);
-	int status;
-
-	status = parse_tokenize_string(params->multi_string, tokens, &n_tokens);
-	if (status != 0) {
-		printf(CMD_MSG_TOO_MANY_ARGS, "arp");
-		return;
-	}
-
-	/* arp add */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "add") == 0) &&
-		strcmp(tokens[1], "default")) {
-		struct pipeline_routing_arp_key key;
-		struct in_addr ipv4;
-		struct ether_addr mac_addr;
-		uint32_t port_id;
-
-		memset(&key, 0, sizeof(key));
-
-		if (n_tokens != 4) {
-			printf(CMD_MSG_MISMATCH_ARGS, "arp add");
-			return;
-		}
-
-		if (parser_read_uint32(&port_id, tokens[1])) {
-			printf(CMD_MSG_INVALID_ARG, "portid");
-			return;
-		}
-
-		if (parse_ipv4_addr(tokens[2], &ipv4)) {
-			printf(CMD_MSG_INVALID_ARG, "ipaddr");
-			return;
-		}
-
-		if (parse_mac_addr(tokens[3], &mac_addr)) {
-			printf(CMD_MSG_INVALID_ARG, "macaddr");
-			return;
-		}
-
-		key.type = PIPELINE_ROUTING_ARP_IPV4;
-		key.key.ipv4.port_id = port_id;
-		key.key.ipv4.ip = rte_be_to_cpu_32(ipv4.s_addr);
-
-		status = app_pipeline_routing_add_arp_entry(app,
-			params->p,
-			&key,
-			&mac_addr);
-		if (status != 0)
-			printf(CMD_MSG_FAIL, "arp add");
-
-		return;
-	} /* arp add */
-
-	/* arp add default */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "add") == 0) &&
-		(strcmp(tokens[1], "default") == 0)) {
-		uint32_t port_id;
-
-		if (n_tokens != 3) {
-			printf(CMD_MSG_MISMATCH_ARGS, "arp add default");
-			return;
-		}
-
-		if (parser_read_uint32(&port_id, tokens[2])) {
-			printf(CMD_MSG_INVALID_ARG, "portid");
-			return;
-		}
-
-		status = app_pipeline_routing_add_default_arp_entry(app,
-			params->p,
-			port_id);
-		if (status != 0)
-			printf(CMD_MSG_FAIL, "arp add default");
-
-		return;
-	} /* arp add default */
-
-	/* arp del*/
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "del") == 0) &&
-		strcmp(tokens[1], "default")) {
-		struct pipeline_routing_arp_key key;
-		struct in_addr ipv4;
-		uint32_t port_id;
-
-		memset(&key, 0, sizeof(key));
-
-		if (n_tokens != 3) {
-			printf(CMD_MSG_MISMATCH_ARGS, "arp del");
-			return;
-		}
-
-		if (parser_read_uint32(&port_id, tokens[1])) {
-			printf(CMD_MSG_INVALID_ARG, "portid");
-			return;
-		}
-
-		if (parse_ipv4_addr(tokens[2], &ipv4)) {
-			printf(CMD_MSG_INVALID_ARG, "ipaddr");
-			return;
-		}
-
-		key.type = PIPELINE_ROUTING_ARP_IPV4;
-		key.key.ipv4.ip = rte_be_to_cpu_32(ipv4.s_addr);
-		key.key.ipv4.port_id = port_id;
-
-		status = app_pipeline_routing_delete_arp_entry(app,
-			params->p,
-			&key);
-		if (status != 0)
-			printf(CMD_MSG_FAIL, "arp del");
-
-		return;
-	} /* arp del */
-
-	/* arp del default */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "del") == 0) &&
-		(strcmp(tokens[1], "default") == 0)) {
-			if (n_tokens != 2) {
-				printf(CMD_MSG_MISMATCH_ARGS, "arp del default");
-				return;
-			}
-
-			status = app_pipeline_routing_delete_default_arp_entry(app,
-				params->p);
-			if (status != 0)
-				printf(CMD_MSG_FAIL, "arp del default");
-
-			return;
-	} /* arp del default */
-
-	/* arp ls */
-	if ((n_tokens >= 1) && (strcmp(tokens[0], "ls") == 0)) {
-		if (n_tokens != 1) {
-			printf(CMD_MSG_MISMATCH_ARGS, "arp ls");
-			return;
-		}
-
-		status = app_pipeline_routing_arp_ls(app, params->p);
-		if (status != 0)
-			printf(CMD_MSG_FAIL, "arp ls");
-
-		return;
-	} /* arp ls */
-
-	printf(CMD_MSG_FAIL, "arp");
-}
-
-static cmdline_parse_token_string_t cmd_arp_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_result, p_string, "p");
-
-static cmdline_parse_token_num_t cmd_arp_p =
-	TOKEN_NUM_INITIALIZER(struct cmd_arp_result, p, UINT32);
-
-static cmdline_parse_token_string_t cmd_arp_arp_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_result, arp_string, "arp");
-
-static cmdline_parse_token_string_t cmd_arp_multi_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_result, multi_string,
-	TOKEN_STRING_MULTI);
-
-static cmdline_parse_inst_t cmd_arp = {
-	.f = cmd_arp_parsed,
-	.data = NULL,
-	.help_str = "arp add / add default / del / del default / ls",
-	.tokens = {
-		(void *)&cmd_arp_p_string,
-		(void *)&cmd_arp_p,
-		(void *)&cmd_arp_arp_string,
-		(void *)&cmd_arp_multi_string,
-		NULL,
-	},
-};
-
-static cmdline_parse_ctx_t pipeline_cmds[] = {
-	(cmdline_parse_inst_t *)&cmd_route,
-	(cmdline_parse_inst_t *)&cmd_arp,
-	NULL,
-};
-
-static struct pipeline_fe_ops pipeline_routing_fe_ops = {
-	.f_init = app_pipeline_routing_init,
-	.f_post_init = app_pipeline_routing_post_init,
-	.f_free = app_pipeline_routing_free,
-	.f_track = app_pipeline_track_default,
-	.cmds = pipeline_cmds,
-};
-
-struct pipeline_type pipeline_routing = {
-	.name = "ROUTING",
-	.be_ops = &pipeline_routing_be_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
deleted file mode 100644
index f249295..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_routing.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#ifndef __INCLUDE_PIPELINE_ROUTING_H__
-#define __INCLUDE_PIPELINE_ROUTING_H__
-
-#include "pipeline.h"
-#include "pipeline_routing_be.h"
-
-/*
- * Route
- */
-
-int
-app_pipeline_routing_add_route(struct app_params *app,
-	uint32_t pipeline_id,
-	struct pipeline_routing_route_key *key,
-	struct pipeline_routing_route_data *data);
-
-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);
-
-/*
- * SETTINGS
- */
-int
-app_pipeline_routing_set_macaddr(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_be.c b/examples/ip_pipeline/pipeline/pipeline_routing_be.c
deleted file mode 100644
index 6258a1a..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_routing_be.c
+++ /dev/null
@@ -1,1966 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2016 Intel Corporation
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <rte_common.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_routing_be.h"
-#include "pipeline_actions_common.h"
-#include "parser.h"
-#include "hash_func.h"
-
-#define MPLS_LABEL(label, exp, s, ttl)					\
-	(((((uint64_t) (label)) & 0xFFFFFLLU) << 12) |		\
-	((((uint64_t) (exp)) & 0x7LLU) << 9) |				\
-	((((uint64_t) (s)) & 0x1LLU) << 8) |				\
-	(((uint64_t) (ttl)) & 0xFFLU))
-
-#define RTE_SCHED_PORT_HIERARCHY(subport, pipe,		\
-	traffic_class, queue, color)				\
-	((((uint64_t) (queue)) & 0x3) |                \
-	((((uint64_t) (traffic_class)) & 0x3) << 2) |  \
-	((((uint64_t) (color)) & 0x3) << 4) |          \
-	((((uint64_t) (subport)) & 0xFFFF) << 16) |    \
-	((((uint64_t) (pipe)) & 0xFFFFFFFF) << 32))
-
-
-/* Network Byte Order (NBO) */
-#define SLAB_NBO_MACADDRSRC_ETHERTYPE(macaddr, ethertype)	\
-	(((uint64_t) macaddr) | (((uint64_t) rte_cpu_to_be_16(ethertype)) << 48))
-
-#ifndef PIPELINE_ROUTING_LPM_TABLE_NUMBER_TABLE8s
-#define PIPELINE_ROUTING_LPM_TABLE_NUMBER_TABLE8s 256
-#endif
-
-struct pipeline_routing {
-	struct pipeline p;
-	struct pipeline_routing_params params;
-	pipeline_msg_req_handler custom_handlers[PIPELINE_ROUTING_MSG_REQS];
-	uint64_t macaddr[PIPELINE_MAX_PORT_OUT];
-} __rte_cache_aligned;
-
-/*
- * Message handlers
- */
-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 void *
-pipeline_routing_msg_req_set_macaddr_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,
-	[PIPELINE_ROUTING_MSG_REQ_SET_MACADDR] =
-		pipeline_routing_msg_req_set_macaddr_handler,
-};
-
-/*
- * Routing table
- */
-struct routing_table_entry {
-	struct rte_pipeline_table_entry head;
-	uint32_t flags;
-	uint32_t port_id; /* Output port ID */
-	uint32_t ip; /* Next hop IP address (only valid for remote routes) */
-
-	/* ether_l2 */
-	uint16_t data_offset;
-	uint16_t ether_l2_length;
-	uint64_t slab[4];
-	uint16_t slab_offset[4];
-};
-
-struct layout {
-	uint16_t a;
-	uint32_t b;
-	uint16_t c;
-} __attribute__((__packed__));
-
-#define MACADDR_DST_WRITE(slab_ptr, slab)			\
-{								\
-	struct layout *dst = (struct layout *) (slab_ptr);	\
-	struct layout *src = (struct layout *) &(slab);		\
-								\
-	dst->b = src->b;					\
-	dst->c = src->c;					\
-}
-
-static __rte_always_inline void
-pkt_work_routing(
-	struct rte_mbuf *pkt,
-	struct rte_pipeline_table_entry *table_entry,
-	void *arg,
-	int arp,
-	int qinq,
-	int qinq_sched,
-	int mpls,
-	int mpls_color_mark)
-{
-	struct pipeline_routing *p_rt = arg;
-
-	struct routing_table_entry *entry =
-		(struct routing_table_entry *) table_entry;
-
-	struct ipv4_hdr *ip = (struct ipv4_hdr *)
-		RTE_MBUF_METADATA_UINT8_PTR(pkt, p_rt->params.ip_hdr_offset);
-
-	enum rte_meter_color pkt_color = (enum rte_meter_color)
-		RTE_MBUF_METADATA_UINT32(pkt, p_rt->params.color_offset);
-
-	struct pipeline_routing_arp_key_ipv4 *arp_key =
-		(struct pipeline_routing_arp_key_ipv4 *)
-		RTE_MBUF_METADATA_UINT8_PTR(pkt, p_rt->params.arp_key_offset);
-
-	uint64_t *slab0_ptr, *slab1_ptr, *slab2_ptr, *slab3_ptr, sched;
-	uint32_t ip_da, nh_ip, port_id;
-	uint16_t total_length, data_offset, ether_l2_length;
-
-	/* Read */
-	total_length = rte_bswap16(ip->total_length);
-	ip_da = ip->dst_addr;
-	data_offset = entry->data_offset;
-	ether_l2_length = entry->ether_l2_length;
-	slab0_ptr = RTE_MBUF_METADATA_UINT64_PTR(pkt, entry->slab_offset[0]);
-	slab1_ptr = RTE_MBUF_METADATA_UINT64_PTR(pkt, entry->slab_offset[1]);
-	slab2_ptr = RTE_MBUF_METADATA_UINT64_PTR(pkt, entry->slab_offset[2]);
-	slab3_ptr = RTE_MBUF_METADATA_UINT64_PTR(pkt, entry->slab_offset[3]);
-
-	if (arp) {
-		port_id = entry->port_id;
-		nh_ip = entry->ip;
-		if (entry->flags & PIPELINE_ROUTING_ROUTE_LOCAL)
-			nh_ip = ip_da;
-	}
-
-	/* Compute */
-	total_length += ether_l2_length;
-
-	if (qinq && qinq_sched) {
-		uint32_t dscp = ip->type_of_service >> 2;
-		uint32_t svlan, cvlan, tc, tc_q;
-
-		if (qinq_sched == 1) {
-			uint64_t slab_qinq = rte_bswap64(entry->slab[0]);
-
-			svlan = (slab_qinq >> 48) & 0xFFF;
-			cvlan = (slab_qinq >> 16) & 0xFFF;
-			tc = (dscp >> 2) & 0x3;
-			tc_q = dscp & 0x3;
-		} else {
-			uint32_t ip_src = rte_bswap32(ip->src_addr);
-
-			svlan = 0;
-			cvlan = (ip_src >> 16) & 0xFFF;
-			tc = (ip_src >> 2) & 0x3;
-			tc_q = ip_src & 0x3;
-		}
-		sched = RTE_SCHED_PORT_HIERARCHY(svlan,
-			cvlan,
-			tc,
-			tc_q,
-			e_RTE_METER_GREEN);
-	}
-
-	/* Write */
-	pkt->data_off = data_offset;
-	pkt->data_len = total_length;
-	pkt->pkt_len = total_length;
-
-	if ((qinq == 0) && (mpls == 0)) {
-		*slab0_ptr = entry->slab[0];
-
-		if (arp == 0)
-			MACADDR_DST_WRITE(slab1_ptr, entry->slab[1]);
-	}
-
-	if (qinq) {
-		*slab0_ptr = entry->slab[0];
-		*slab1_ptr = entry->slab[1];
-
-		if (arp == 0)
-			MACADDR_DST_WRITE(slab2_ptr, entry->slab[2]);
-
-		if (qinq_sched) {
-			pkt->hash.sched.lo = sched & 0xFFFFFFFF;
-			pkt->hash.sched.hi = sched >> 32;
-		}
-	}
-
-	if (mpls) {
-		if (mpls_color_mark) {
-			uint64_t mpls_exp = rte_bswap64(
-				(MPLS_LABEL(0, pkt_color, 0, 0) << 32) |
-				MPLS_LABEL(0, pkt_color, 0, 0));
-
-			*slab0_ptr = entry->slab[0] | mpls_exp;
-			*slab1_ptr = entry->slab[1] | mpls_exp;
-			*slab2_ptr = entry->slab[2];
-		} else {
-			*slab0_ptr = entry->slab[0];
-			*slab1_ptr = entry->slab[1];
-			*slab2_ptr = entry->slab[2];
-		}
-
-		if (arp == 0)
-			MACADDR_DST_WRITE(slab3_ptr, entry->slab[3]);
-	}
-
-	if (arp) {
-		arp_key->port_id = port_id;
-		arp_key->ip = nh_ip;
-	}
-}
-
-static __rte_always_inline void
-pkt4_work_routing(
-	struct rte_mbuf **pkts,
-	struct rte_pipeline_table_entry **table_entries,
-	void *arg,
-	int arp,
-	int qinq,
-	int qinq_sched,
-	int mpls,
-	int mpls_color_mark)
-{
-	struct pipeline_routing *p_rt = arg;
-
-	struct routing_table_entry *entry0 =
-		(struct routing_table_entry *) table_entries[0];
-	struct routing_table_entry *entry1 =
-		(struct routing_table_entry *) table_entries[1];
-	struct routing_table_entry *entry2 =
-		(struct routing_table_entry *) table_entries[2];
-	struct routing_table_entry *entry3 =
-		(struct routing_table_entry *) table_entries[3];
-
-	struct ipv4_hdr *ip0 = (struct ipv4_hdr *)
-		RTE_MBUF_METADATA_UINT8_PTR(pkts[0],
-			p_rt->params.ip_hdr_offset);
-	struct ipv4_hdr *ip1 = (struct ipv4_hdr *)
-		RTE_MBUF_METADATA_UINT8_PTR(pkts[1],
-			p_rt->params.ip_hdr_offset);
-	struct ipv4_hdr *ip2 = (struct ipv4_hdr *)
-		RTE_MBUF_METADATA_UINT8_PTR(pkts[2],
-			p_rt->params.ip_hdr_offset);
-	struct ipv4_hdr *ip3 = (struct ipv4_hdr *)
-		RTE_MBUF_METADATA_UINT8_PTR(pkts[3],
-			p_rt->params.ip_hdr_offset);
-
-	enum rte_meter_color pkt0_color = (enum rte_meter_color)
-		RTE_MBUF_METADATA_UINT32(pkts[0], p_rt->params.color_offset);
-	enum rte_meter_color pkt1_color = (enum rte_meter_color)
-		RTE_MBUF_METADATA_UINT32(pkts[1], p_rt->params.color_offset);
-	enum rte_meter_color pkt2_color = (enum rte_meter_color)
-		RTE_MBUF_METADATA_UINT32(pkts[2], p_rt->params.color_offset);
-	enum rte_meter_color pkt3_color = (enum rte_meter_color)
-		RTE_MBUF_METADATA_UINT32(pkts[3], p_rt->params.color_offset);
-
-	struct pipeline_routing_arp_key_ipv4 *arp_key0 =
-		(struct pipeline_routing_arp_key_ipv4 *)
-		RTE_MBUF_METADATA_UINT8_PTR(pkts[0],
-			p_rt->params.arp_key_offset);
-	struct pipeline_routing_arp_key_ipv4 *arp_key1 =
-		(struct pipeline_routing_arp_key_ipv4 *)
-		RTE_MBUF_METADATA_UINT8_PTR(pkts[1],
-			p_rt->params.arp_key_offset);
-	struct pipeline_routing_arp_key_ipv4 *arp_key2 =
-		(struct pipeline_routing_arp_key_ipv4 *)
-		RTE_MBUF_METADATA_UINT8_PTR(pkts[2],
-			p_rt->params.arp_key_offset);
-	struct pipeline_routing_arp_key_ipv4 *arp_key3 =
-		(struct pipeline_routing_arp_key_ipv4 *)
-		RTE_MBUF_METADATA_UINT8_PTR(pkts[3],
-			p_rt->params.arp_key_offset);
-
-	uint64_t *slab0_ptr0, *slab1_ptr0, *slab2_ptr0, *slab3_ptr0;
-	uint64_t *slab0_ptr1, *slab1_ptr1, *slab2_ptr1, *slab3_ptr1;
-	uint64_t *slab0_ptr2, *slab1_ptr2, *slab2_ptr2, *slab3_ptr2;
-	uint64_t *slab0_ptr3, *slab1_ptr3, *slab2_ptr3, *slab3_ptr3;
-	uint64_t sched0, sched1, sched2, sched3;
-
-	uint32_t ip_da0, nh_ip0, port_id0;
-	uint32_t ip_da1, nh_ip1, port_id1;
-	uint32_t ip_da2, nh_ip2, port_id2;
-	uint32_t ip_da3, nh_ip3, port_id3;
-
-	uint16_t total_length0, data_offset0, ether_l2_length0;
-	uint16_t total_length1, data_offset1, ether_l2_length1;
-	uint16_t total_length2, data_offset2, ether_l2_length2;
-	uint16_t total_length3, data_offset3, ether_l2_length3;
-
-	/* Read */
-	total_length0 = rte_bswap16(ip0->total_length);
-	total_length1 = rte_bswap16(ip1->total_length);
-	total_length2 = rte_bswap16(ip2->total_length);
-	total_length3 = rte_bswap16(ip3->total_length);
-
-	ip_da0 = ip0->dst_addr;
-	ip_da1 = ip1->dst_addr;
-	ip_da2 = ip2->dst_addr;
-	ip_da3 = ip3->dst_addr;
-
-	data_offset0 = entry0->data_offset;
-	data_offset1 = entry1->data_offset;
-	data_offset2 = entry2->data_offset;
-	data_offset3 = entry3->data_offset;
-
-	ether_l2_length0 = entry0->ether_l2_length;
-	ether_l2_length1 = entry1->ether_l2_length;
-	ether_l2_length2 = entry2->ether_l2_length;
-	ether_l2_length3 = entry3->ether_l2_length;
-
-	slab0_ptr0 = RTE_MBUF_METADATA_UINT64_PTR(pkts[0],
-		entry0->slab_offset[0]);
-	slab1_ptr0 = RTE_MBUF_METADATA_UINT64_PTR(pkts[0],
-		entry0->slab_offset[1]);
-	slab2_ptr0 = RTE_MBUF_METADATA_UINT64_PTR(pkts[0],
-		entry0->slab_offset[2]);
-	slab3_ptr0 = RTE_MBUF_METADATA_UINT64_PTR(pkts[0],
-		entry0->slab_offset[3]);
-
-	slab0_ptr1 = RTE_MBUF_METADATA_UINT64_PTR(pkts[1],
-		entry1->slab_offset[0]);
-	slab1_ptr1 = RTE_MBUF_METADATA_UINT64_PTR(pkts[1],
-		entry1->slab_offset[1]);
-	slab2_ptr1 = RTE_MBUF_METADATA_UINT64_PTR(pkts[1],
-		entry1->slab_offset[2]);
-	slab3_ptr1 = RTE_MBUF_METADATA_UINT64_PTR(pkts[1],
-		entry1->slab_offset[3]);
-
-	slab0_ptr2 = RTE_MBUF_METADATA_UINT64_PTR(pkts[2],
-		entry2->slab_offset[0]);
-	slab1_ptr2 = RTE_MBUF_METADATA_UINT64_PTR(pkts[2],
-		entry2->slab_offset[1]);
-	slab2_ptr2 = RTE_MBUF_METADATA_UINT64_PTR(pkts[2],
-		entry2->slab_offset[2]);
-	slab3_ptr2 = RTE_MBUF_METADATA_UINT64_PTR(pkts[2],
-		entry2->slab_offset[3]);
-
-	slab0_ptr3 = RTE_MBUF_METADATA_UINT64_PTR(pkts[3],
-		entry3->slab_offset[0]);
-	slab1_ptr3 = RTE_MBUF_METADATA_UINT64_PTR(pkts[3],
-		entry3->slab_offset[1]);
-	slab2_ptr3 = RTE_MBUF_METADATA_UINT64_PTR(pkts[3],
-		entry3->slab_offset[2]);
-	slab3_ptr3 = RTE_MBUF_METADATA_UINT64_PTR(pkts[3],
-		entry3->slab_offset[3]);
-
-	if (arp) {
-		port_id0 = entry0->port_id;
-		nh_ip0 = entry0->ip;
-		if (entry0->flags & PIPELINE_ROUTING_ROUTE_LOCAL)
-			nh_ip0 = ip_da0;
-
-		port_id1 = entry1->port_id;
-		nh_ip1 = entry1->ip;
-		if (entry1->flags & PIPELINE_ROUTING_ROUTE_LOCAL)
-			nh_ip1 = ip_da1;
-
-		port_id2 = entry2->port_id;
-		nh_ip2 = entry2->ip;
-		if (entry2->flags & PIPELINE_ROUTING_ROUTE_LOCAL)
-			nh_ip2 = ip_da2;
-
-		port_id3 = entry3->port_id;
-		nh_ip3 = entry3->ip;
-		if (entry3->flags & PIPELINE_ROUTING_ROUTE_LOCAL)
-			nh_ip3 = ip_da3;
-	}
-
-	/* Compute */
-	total_length0 += ether_l2_length0;
-	total_length1 += ether_l2_length1;
-	total_length2 += ether_l2_length2;
-	total_length3 += ether_l2_length3;
-
-	if (qinq && qinq_sched) {
-		uint32_t dscp0 = ip0->type_of_service >> 2;
-		uint32_t dscp1 = ip1->type_of_service >> 2;
-		uint32_t dscp2 = ip2->type_of_service >> 2;
-		uint32_t dscp3 = ip3->type_of_service >> 2;
-		uint32_t svlan0, cvlan0, tc0, tc_q0;
-		uint32_t svlan1, cvlan1, tc1, tc_q1;
-		uint32_t svlan2, cvlan2, tc2, tc_q2;
-		uint32_t svlan3, cvlan3, tc3, tc_q3;
-
-		if (qinq_sched == 1) {
-			uint64_t slab_qinq0 = rte_bswap64(entry0->slab[0]);
-			uint64_t slab_qinq1 = rte_bswap64(entry1->slab[0]);
-			uint64_t slab_qinq2 = rte_bswap64(entry2->slab[0]);
-			uint64_t slab_qinq3 = rte_bswap64(entry3->slab[0]);
-
-			svlan0 = (slab_qinq0 >> 48) & 0xFFF;
-			svlan1 = (slab_qinq1 >> 48) & 0xFFF;
-			svlan2 = (slab_qinq2 >> 48) & 0xFFF;
-			svlan3 = (slab_qinq3 >> 48) & 0xFFF;
-
-			cvlan0 = (slab_qinq0 >> 16) & 0xFFF;
-			cvlan1 = (slab_qinq1 >> 16) & 0xFFF;
-			cvlan2 = (slab_qinq2 >> 16) & 0xFFF;
-			cvlan3 = (slab_qinq3 >> 16) & 0xFFF;
-
-			tc0 = (dscp0 >> 2) & 0x3;
-			tc1 = (dscp1 >> 2) & 0x3;
-			tc2 = (dscp2 >> 2) & 0x3;
-			tc3 = (dscp3 >> 2) & 0x3;
-
-			tc_q0 = dscp0 & 0x3;
-			tc_q1 = dscp1 & 0x3;
-			tc_q2 = dscp2 & 0x3;
-			tc_q3 = dscp3 & 0x3;
-		} else {
-			uint32_t ip_src0 = rte_bswap32(ip0->src_addr);
-			uint32_t ip_src1 = rte_bswap32(ip1->src_addr);
-			uint32_t ip_src2 = rte_bswap32(ip2->src_addr);
-			uint32_t ip_src3 = rte_bswap32(ip3->src_addr);
-
-			svlan0 = 0;
-			svlan1 = 0;
-			svlan2 = 0;
-			svlan3 = 0;
-
-			cvlan0 = (ip_src0 >> 16) & 0xFFF;
-			cvlan1 = (ip_src1 >> 16) & 0xFFF;
-			cvlan2 = (ip_src2 >> 16) & 0xFFF;
-			cvlan3 = (ip_src3 >> 16) & 0xFFF;
-
-			tc0 = (ip_src0 >> 2) & 0x3;
-			tc1 = (ip_src1 >> 2) & 0x3;
-			tc2 = (ip_src2 >> 2) & 0x3;
-			tc3 = (ip_src3 >> 2) & 0x3;
-
-			tc_q0 = ip_src0 & 0x3;
-			tc_q1 = ip_src1 & 0x3;
-			tc_q2 = ip_src2 & 0x3;
-			tc_q3 = ip_src3 & 0x3;
-		}
-
-		sched0 = RTE_SCHED_PORT_HIERARCHY(svlan0,
-			cvlan0,
-			tc0,
-			tc_q0,
-			e_RTE_METER_GREEN);
-		sched1 = RTE_SCHED_PORT_HIERARCHY(svlan1,
-			cvlan1,
-			tc1,
-			tc_q1,
-			e_RTE_METER_GREEN);
-		sched2 = RTE_SCHED_PORT_HIERARCHY(svlan2,
-			cvlan2,
-			tc2,
-			tc_q2,
-			e_RTE_METER_GREEN);
-		sched3 = RTE_SCHED_PORT_HIERARCHY(svlan3,
-			cvlan3,
-			tc3,
-			tc_q3,
-			e_RTE_METER_GREEN);
-
-	}
-
-	/* Write */
-	pkts[0]->data_off = data_offset0;
-	pkts[1]->data_off = data_offset1;
-	pkts[2]->data_off = data_offset2;
-	pkts[3]->data_off = data_offset3;
-
-	pkts[0]->data_len = total_length0;
-	pkts[1]->data_len = total_length1;
-	pkts[2]->data_len = total_length2;
-	pkts[3]->data_len = total_length3;
-
-	pkts[0]->pkt_len = total_length0;
-	pkts[1]->pkt_len = total_length1;
-	pkts[2]->pkt_len = total_length2;
-	pkts[3]->pkt_len = total_length3;
-
-	if ((qinq == 0) && (mpls == 0)) {
-		*slab0_ptr0 = entry0->slab[0];
-		*slab0_ptr1 = entry1->slab[0];
-		*slab0_ptr2 = entry2->slab[0];
-		*slab0_ptr3 = entry3->slab[0];
-
-		if (arp == 0) {
-			MACADDR_DST_WRITE(slab1_ptr0, entry0->slab[1]);
-			MACADDR_DST_WRITE(slab1_ptr1, entry1->slab[1]);
-			MACADDR_DST_WRITE(slab1_ptr2, entry2->slab[1]);
-			MACADDR_DST_WRITE(slab1_ptr3, entry3->slab[1]);
-		}
-	}
-
-	if (qinq) {
-		*slab0_ptr0 = entry0->slab[0];
-		*slab0_ptr1 = entry1->slab[0];
-		*slab0_ptr2 = entry2->slab[0];
-		*slab0_ptr3 = entry3->slab[0];
-
-		*slab1_ptr0 = entry0->slab[1];
-		*slab1_ptr1 = entry1->slab[1];
-		*slab1_ptr2 = entry2->slab[1];
-		*slab1_ptr3 = entry3->slab[1];
-
-		if (arp == 0) {
-			MACADDR_DST_WRITE(slab2_ptr0, entry0->slab[2]);
-			MACADDR_DST_WRITE(slab2_ptr1, entry1->slab[2]);
-			MACADDR_DST_WRITE(slab2_ptr2, entry2->slab[2]);
-			MACADDR_DST_WRITE(slab2_ptr3, entry3->slab[2]);
-		}
-
-		if (qinq_sched) {
-			pkts[0]->hash.sched.lo = sched0 & 0xFFFFFFFF;
-			pkts[0]->hash.sched.hi = sched0 >> 32;
-			pkts[1]->hash.sched.lo = sched1 & 0xFFFFFFFF;
-			pkts[1]->hash.sched.hi = sched1 >> 32;
-			pkts[2]->hash.sched.lo = sched2 & 0xFFFFFFFF;
-			pkts[2]->hash.sched.hi = sched2 >> 32;
-			pkts[3]->hash.sched.lo = sched3 & 0xFFFFFFFF;
-			pkts[3]->hash.sched.hi = sched3 >> 32;
-		}
-	}
-
-	if (mpls) {
-		if (mpls_color_mark) {
-			uint64_t mpls_exp0 = rte_bswap64(
-				(MPLS_LABEL(0, pkt0_color, 0, 0) << 32) |
-				MPLS_LABEL(0, pkt0_color, 0, 0));
-			uint64_t mpls_exp1 = rte_bswap64(
-				(MPLS_LABEL(0, pkt1_color, 0, 0) << 32) |
-				MPLS_LABEL(0, pkt1_color, 0, 0));
-			uint64_t mpls_exp2 = rte_bswap64(
-				(MPLS_LABEL(0, pkt2_color, 0, 0) << 32) |
-				MPLS_LABEL(0, pkt2_color, 0, 0));
-			uint64_t mpls_exp3 = rte_bswap64(
-				(MPLS_LABEL(0, pkt3_color, 0, 0) << 32) |
-				MPLS_LABEL(0, pkt3_color, 0, 0));
-
-			*slab0_ptr0 = entry0->slab[0] | mpls_exp0;
-			*slab0_ptr1 = entry1->slab[0] | mpls_exp1;
-			*slab0_ptr2 = entry2->slab[0] | mpls_exp2;
-			*slab0_ptr3 = entry3->slab[0] | mpls_exp3;
-
-			*slab1_ptr0 = entry0->slab[1] | mpls_exp0;
-			*slab1_ptr1 = entry1->slab[1] | mpls_exp1;
-			*slab1_ptr2 = entry2->slab[1] | mpls_exp2;
-			*slab1_ptr3 = entry3->slab[1] | mpls_exp3;
-
-			*slab2_ptr0 = entry0->slab[2];
-			*slab2_ptr1 = entry1->slab[2];
-			*slab2_ptr2 = entry2->slab[2];
-			*slab2_ptr3 = entry3->slab[2];
-		} else {
-			*slab0_ptr0 = entry0->slab[0];
-			*slab0_ptr1 = entry1->slab[0];
-			*slab0_ptr2 = entry2->slab[0];
-			*slab0_ptr3 = entry3->slab[0];
-
-			*slab1_ptr0 = entry0->slab[1];
-			*slab1_ptr1 = entry1->slab[1];
-			*slab1_ptr2 = entry2->slab[1];
-			*slab1_ptr3 = entry3->slab[1];
-
-			*slab2_ptr0 = entry0->slab[2];
-			*slab2_ptr1 = entry1->slab[2];
-			*slab2_ptr2 = entry2->slab[2];
-			*slab2_ptr3 = entry3->slab[2];
-		}
-
-		if (arp == 0) {
-			MACADDR_DST_WRITE(slab3_ptr0, entry0->slab[3]);
-			MACADDR_DST_WRITE(slab3_ptr1, entry1->slab[3]);
-			MACADDR_DST_WRITE(slab3_ptr2, entry2->slab[3]);
-			MACADDR_DST_WRITE(slab3_ptr3, entry3->slab[3]);
-		}
-	}
-
-	if (arp) {
-		arp_key0->port_id = port_id0;
-		arp_key1->port_id = port_id1;
-		arp_key2->port_id = port_id2;
-		arp_key3->port_id = port_id3;
-
-		arp_key0->ip = nh_ip0;
-		arp_key1->ip = nh_ip1;
-		arp_key2->ip = nh_ip2;
-		arp_key3->ip = nh_ip3;
-	}
-}
-
-#define PKT_WORK_ROUTING_ETHERNET(arp)				\
-static inline void						\
-pkt_work_routing_ether_arp##arp(				\
-	struct rte_mbuf *pkt,					\
-	struct rte_pipeline_table_entry *table_entry,		\
-	void *arg)						\
-{								\
-	pkt_work_routing(pkt, table_entry, arg, arp, 0, 0, 0, 0);\
-}
-
-#define PKT4_WORK_ROUTING_ETHERNET(arp)				\
-static inline void						\
-pkt4_work_routing_ether_arp##arp(				\
-	struct rte_mbuf **pkts,					\
-	struct rte_pipeline_table_entry **table_entries,	\
-	void *arg)						\
-{								\
-	pkt4_work_routing(pkts, table_entries, arg, arp, 0, 0, 0, 0);\
-}
-
-#define routing_table_ah_hit_ether(arp)				\
-PKT_WORK_ROUTING_ETHERNET(arp)					\
-PKT4_WORK_ROUTING_ETHERNET(arp)					\
-PIPELINE_TABLE_AH_HIT(routing_table_ah_hit_ether_arp##arp,	\
-	pkt_work_routing_ether_arp##arp,			\
-	pkt4_work_routing_ether_arp##arp)
-
-routing_table_ah_hit_ether(0)
-routing_table_ah_hit_ether(1)
-
-#define PKT_WORK_ROUTING_ETHERNET_QINQ(sched, arp)		\
-static inline void						\
-pkt_work_routing_ether_qinq_sched##sched##_arp##arp(		\
-	struct rte_mbuf *pkt,					\
-	struct rte_pipeline_table_entry *table_entry,		\
-	void *arg)						\
-{								\
-	pkt_work_routing(pkt, table_entry, arg, arp, 1, sched, 0, 0);\
-}
-
-#define PKT4_WORK_ROUTING_ETHERNET_QINQ(sched, arp)		\
-static inline void						\
-pkt4_work_routing_ether_qinq_sched##sched##_arp##arp(		\
-	struct rte_mbuf **pkts,					\
-	struct rte_pipeline_table_entry **table_entries,	\
-	void *arg)						\
-{								\
-	pkt4_work_routing(pkts, table_entries, arg, arp, 1, sched, 0, 0);\
-}
-
-#define routing_table_ah_hit_ether_qinq(sched, arp)		\
-PKT_WORK_ROUTING_ETHERNET_QINQ(sched, arp)			\
-PKT4_WORK_ROUTING_ETHERNET_QINQ(sched, arp)			\
-PIPELINE_TABLE_AH_HIT(routing_table_ah_hit_ether_qinq_sched##sched##_arp##arp,\
-	pkt_work_routing_ether_qinq_sched##sched##_arp##arp,	\
-	pkt4_work_routing_ether_qinq_sched##sched##_arp##arp)
-
-routing_table_ah_hit_ether_qinq(0, 0)
-routing_table_ah_hit_ether_qinq(1, 0)
-routing_table_ah_hit_ether_qinq(2, 0)
-routing_table_ah_hit_ether_qinq(0, 1)
-routing_table_ah_hit_ether_qinq(1, 1)
-routing_table_ah_hit_ether_qinq(2, 1)
-
-#define PKT_WORK_ROUTING_ETHERNET_MPLS(color, arp)		\
-static inline void						\
-pkt_work_routing_ether_mpls_color##color##_arp##arp(		\
-	struct rte_mbuf *pkt,					\
-	struct rte_pipeline_table_entry *table_entry,		\
-	void *arg)						\
-{								\
-	pkt_work_routing(pkt, table_entry, arg, arp, 0, 0, 1, color);\
-}
-
-#define PKT4_WORK_ROUTING_ETHERNET_MPLS(color, arp)		\
-static inline void						\
-pkt4_work_routing_ether_mpls_color##color##_arp##arp(		\
-	struct rte_mbuf **pkts,					\
-	struct rte_pipeline_table_entry **table_entries,	\
-	void *arg)						\
-{								\
-	pkt4_work_routing(pkts, table_entries, arg, arp, 0, 0, 1, color);\
-}
-
-#define routing_table_ah_hit_ether_mpls(color, arp)		\
-PKT_WORK_ROUTING_ETHERNET_MPLS(color, arp)			\
-PKT4_WORK_ROUTING_ETHERNET_MPLS(color, arp)			\
-PIPELINE_TABLE_AH_HIT(routing_table_ah_hit_ether_mpls_color##color##_arp##arp,\
-	pkt_work_routing_ether_mpls_color##color##_arp##arp,	\
-	pkt4_work_routing_ether_mpls_color##color##_arp##arp)
-
-routing_table_ah_hit_ether_mpls(0, 0)
-routing_table_ah_hit_ether_mpls(1, 0)
-routing_table_ah_hit_ether_mpls(0, 1)
-routing_table_ah_hit_ether_mpls(1, 1)
-
-static rte_pipeline_table_action_handler_hit
-get_routing_table_ah_hit(struct pipeline_routing *p)
-{
-	if (p->params.dbg_ah_disable)
-		return NULL;
-
-	switch (p->params.encap) {
-	case PIPELINE_ROUTING_ENCAP_ETHERNET:
-		return (p->params.n_arp_entries) ?
-			routing_table_ah_hit_ether_arp1 :
-			routing_table_ah_hit_ether_arp0;
-
-	case PIPELINE_ROUTING_ENCAP_ETHERNET_QINQ:
-		if (p->params.n_arp_entries)
-			switch (p->params.qinq_sched) {
-			case 0:
-				return routing_table_ah_hit_ether_qinq_sched0_arp1;
-			case 1:
-				return routing_table_ah_hit_ether_qinq_sched1_arp1;
-			case 2:
-				return routing_table_ah_hit_ether_qinq_sched2_arp1;
-			default:
-				return NULL;
-			}
-		 else
-			switch (p->params.qinq_sched) {
-			case 0:
-				return routing_table_ah_hit_ether_qinq_sched0_arp0;
-			case 1:
-				return routing_table_ah_hit_ether_qinq_sched1_arp0;
-			case 2:
-				return routing_table_ah_hit_ether_qinq_sched2_arp0;
-			default:
-				return NULL;
-			}
-
-	case PIPELINE_ROUTING_ENCAP_ETHERNET_MPLS:
-		if (p->params.n_arp_entries)
-			if (p->params.mpls_color_mark)
-				return routing_table_ah_hit_ether_mpls_color1_arp1;
-			else
-				return routing_table_ah_hit_ether_mpls_color0_arp1;
-		else
-			if (p->params.mpls_color_mark)
-				return routing_table_ah_hit_ether_mpls_color1_arp0;
-			else
-				return routing_table_ah_hit_ether_mpls_color0_arp0;
-
-	default:
-		return NULL;
-	}
-}
-
-/*
- * ARP table
- */
-struct arp_table_entry {
-	struct rte_pipeline_table_entry head;
-	uint64_t macaddr;
-};
-
-/**
- * ARP table AH
- */
-static inline void
-pkt_work_arp(
-	struct rte_mbuf *pkt,
-	struct rte_pipeline_table_entry *table_entry,
-	__rte_unused void *arg)
-{
-	struct arp_table_entry *entry = (struct arp_table_entry *) table_entry;
-
-	/* Read */
-	uint64_t macaddr_dst = entry->macaddr;
-	uint64_t *slab_ptr = (uint64_t *) ((char *) pkt->buf_addr +
-		(pkt->data_off - 2));
-
-	/* Compute */
-
-	/* Write */
-	MACADDR_DST_WRITE(slab_ptr, macaddr_dst);
-}
-
-static inline void
-pkt4_work_arp(
-	struct rte_mbuf **pkts,
-	struct rte_pipeline_table_entry **table_entries,
-	__rte_unused void *arg)
-{
-	struct arp_table_entry *entry0 =
-		(struct arp_table_entry *) table_entries[0];
-	struct arp_table_entry *entry1 =
-		(struct arp_table_entry *) table_entries[1];
-	struct arp_table_entry *entry2 =
-		(struct arp_table_entry *) table_entries[2];
-	struct arp_table_entry *entry3 =
-		(struct arp_table_entry *) table_entries[3];
-
-	/* Read */
-	uint64_t macaddr_dst0 = entry0->macaddr;
-	uint64_t macaddr_dst1 = entry1->macaddr;
-	uint64_t macaddr_dst2 = entry2->macaddr;
-	uint64_t macaddr_dst3 = entry3->macaddr;
-
-	uint64_t *slab_ptr0 = (uint64_t *) ((char *) pkts[0]->buf_addr +
-		(pkts[0]->data_off - 2));
-	uint64_t *slab_ptr1 = (uint64_t *) ((char *) pkts[1]->buf_addr +
-		(pkts[1]->data_off - 2));
-	uint64_t *slab_ptr2 = (uint64_t *) ((char *) pkts[2]->buf_addr +
-		(pkts[2]->data_off - 2));
-	uint64_t *slab_ptr3 = (uint64_t *) ((char *) pkts[3]->buf_addr +
-		(pkts[3]->data_off - 2));
-
-	/* Compute */
-
-	/* Write */
-	MACADDR_DST_WRITE(slab_ptr0, macaddr_dst0);
-	MACADDR_DST_WRITE(slab_ptr1, macaddr_dst1);
-	MACADDR_DST_WRITE(slab_ptr2, macaddr_dst2);
-	MACADDR_DST_WRITE(slab_ptr3, macaddr_dst3);
-}
-
-PIPELINE_TABLE_AH_HIT(arp_table_ah_hit,
-	pkt_work_arp,
-	pkt4_work_arp);
-
-static rte_pipeline_table_action_handler_hit
-get_arp_table_ah_hit(struct pipeline_routing *p)
-{
-	if (p->params.dbg_ah_disable)
-		return NULL;
-
-	return arp_table_ah_hit;
-}
-
-/*
- * Argument parsing
- */
-int
-pipeline_routing_parse_args(struct pipeline_routing_params *p,
-	struct pipeline_params *params)
-{
-	uint32_t n_routes_present = 0;
-	uint32_t port_local_dest_present = 0;
-	uint32_t encap_present = 0;
-	uint32_t qinq_sched_present = 0;
-	uint32_t mpls_color_mark_present = 0;
-	uint32_t n_arp_entries_present = 0;
-	uint32_t ip_hdr_offset_present = 0;
-	uint32_t arp_key_offset_present = 0;
-	uint32_t color_offset_present = 0;
-	uint32_t dbg_ah_disable_present = 0;
-	uint32_t i;
-
-	/* default values */
-	p->n_routes = PIPELINE_ROUTING_N_ROUTES_DEFAULT;
-	p->port_local_dest = params->n_ports_out - 1;
-	p->encap = PIPELINE_ROUTING_ENCAP_ETHERNET;
-	p->qinq_sched = 0;
-	p->mpls_color_mark = 0;
-	p->n_arp_entries = 0;
-	p->dbg_ah_disable = 0;
-
-	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) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				n_routes_present == 0, params->name,
-				arg_name);
-			n_routes_present = 1;
-
-			status = parser_read_uint32(&p->n_routes,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL(((status != -EINVAL) &&
-				(p->n_routes != 0)), params->name,
-				arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			continue;
-		}
-		/* port_local_dest */
-		if (strcmp(arg_name, "port_local_dest") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				port_local_dest_present == 0, params->name,
-				arg_name);
-			port_local_dest_present = 1;
-
-			status = parser_read_uint32(&p->port_local_dest,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL(((status == 0) &&
-				(p->port_local_dest < params->n_ports_out)),
-				params->name, arg_name, arg_value);
-
-			continue;
-		}
-
-		/* encap */
-		if (strcmp(arg_name, "encap") == 0) {
-			PIPELINE_PARSE_ERR_DUPLICATE(encap_present == 0,
-				params->name, arg_name);
-			encap_present = 1;
-
-			/* ethernet */
-			if (strcmp(arg_value, "ethernet") == 0) {
-				p->encap = PIPELINE_ROUTING_ENCAP_ETHERNET;
-				continue;
-			}
-
-			/* ethernet_qinq */
-			if (strcmp(arg_value, "ethernet_qinq") == 0) {
-				p->encap = PIPELINE_ROUTING_ENCAP_ETHERNET_QINQ;
-				continue;
-			}
-
-			/* ethernet_mpls */
-			if (strcmp(arg_value, "ethernet_mpls") == 0) {
-				p->encap = PIPELINE_ROUTING_ENCAP_ETHERNET_MPLS;
-				continue;
-			}
-
-			/* any other */
-			PIPELINE_PARSE_ERR_INV_VAL(0, params->name,
-				arg_name, arg_value);
-		}
-
-		/* qinq_sched */
-		if (strcmp(arg_name, "qinq_sched") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				qinq_sched_present == 0, params->name,
-				arg_name);
-			qinq_sched_present = 1;
-
-			status = parser_read_arg_bool(arg_value);
-			if (status == -EINVAL) {
-				if (strcmp(arg_value, "test") == 0) {
-					p->qinq_sched = 2;
-					continue;
-				}
-			} else {
-				p->qinq_sched = status;
-				continue;
-			}
-
-			PIPELINE_PARSE_ERR_INV_VAL(0, params->name,
-				arg_name, arg_value);
-		}
-
-		/* mpls_color_mark */
-		if (strcmp(arg_name, "mpls_color_mark") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				mpls_color_mark_present == 0,
-				params->name, arg_name);
-			mpls_color_mark_present = 1;
-
-
-			status = parser_read_arg_bool(arg_value);
-			if (status >= 0) {
-				p->mpls_color_mark = status;
-				continue;
-			}
-
-			PIPELINE_PARSE_ERR_INV_VAL(0, params->name,
-				arg_name, arg_value);
-		}
-
-		/* n_arp_entries */
-		if (strcmp(arg_name, "n_arp_entries") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				n_arp_entries_present == 0, params->name,
-				arg_name);
-			n_arp_entries_present = 1;
-
-			status = parser_read_uint32(&p->n_arp_entries,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			continue;
-		}
-
-		/* ip_hdr_offset */
-		if (strcmp(arg_name, "ip_hdr_offset") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				ip_hdr_offset_present == 0, params->name,
-				arg_name);
-			ip_hdr_offset_present = 1;
-
-			status = parser_read_uint32(&p->ip_hdr_offset,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			continue;
-		}
-
-		/* arp_key_offset */
-		if (strcmp(arg_name, "arp_key_offset") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				arp_key_offset_present == 0, params->name,
-				arg_name);
-			arp_key_offset_present = 1;
-
-			status = parser_read_uint32(&p->arp_key_offset,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			continue;
-		}
-
-		/* color_offset */
-		if (strcmp(arg_name, "color_offset") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				color_offset_present == 0, params->name,
-				arg_name);
-			color_offset_present = 1;
-
-			status = parser_read_uint32(&p->color_offset,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			continue;
-		}
-
-		/* debug */
-		if (strcmp(arg_name, "dbg_ah_disable") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				dbg_ah_disable_present == 0, params->name,
-				arg_name);
-			dbg_ah_disable_present = 1;
-
-			status = parser_read_arg_bool(arg_value);
-			if (status >= 0) {
-				p->dbg_ah_disable = status;
-				continue;
-			}
-
-			PIPELINE_PARSE_ERR_INV_VAL(0, params->name,
-				arg_name, arg_value);
-
-			continue;
-		}
-
-		/* any other */
-		PIPELINE_PARSE_ERR_INV_ENT(0, params->name, arg_name);
-	}
-
-	/* Check that mandatory arguments are present */
-	PIPELINE_PARSE_ERR_MANDATORY(ip_hdr_offset_present, params->name,
-		"ip_hdr_offset");
-
-	/* Check relations between arguments */
-	switch (p->encap) {
-	case PIPELINE_ROUTING_ENCAP_ETHERNET:
-		PIPELINE_ARG_CHECK((!p->qinq_sched), "Parse error in "
-			"section \"%s\": encap = ethernet, therefore "
-			"qinq_sched = yes/test is not allowed",
-			params->name);
-		PIPELINE_ARG_CHECK((!p->mpls_color_mark), "Parse error "
-			"in section \"%s\": encap = ethernet, therefore "
-			"mpls_color_mark = yes is not allowed",
-			params->name);
-		PIPELINE_ARG_CHECK((!color_offset_present), "Parse error "
-			"in section \"%s\": encap = ethernet, therefore "
-			"color_offset is not allowed",
-			params->name);
-		break;
-
-	case PIPELINE_ROUTING_ENCAP_ETHERNET_QINQ:
-		PIPELINE_ARG_CHECK((!p->mpls_color_mark), "Parse error "
-			"in section \"%s\": encap = ethernet_qinq, "
-			"therefore mpls_color_mark = yes is not allowed",
-			params->name);
-		PIPELINE_ARG_CHECK((!color_offset_present), "Parse error "
-			"in section \"%s\": encap = ethernet_qinq, "
-			"therefore color_offset is not allowed",
-			params->name);
-		break;
-
-	case PIPELINE_ROUTING_ENCAP_ETHERNET_MPLS:
-		PIPELINE_ARG_CHECK((!p->qinq_sched), "Parse error in "
-			"section \"%s\": encap = ethernet_mpls, therefore "
-			"qinq_sched  = yes/test is not allowed",
-			params->name);
-		break;
-	}
-
-	PIPELINE_ARG_CHECK((!(p->n_arp_entries &&
-		(!arp_key_offset_present))), "Parse error in section "
-			"\"%s\": n_arp_entries is set while "
-			"arp_key_offset is not set", params->name);
-
-	PIPELINE_ARG_CHECK((!((p->n_arp_entries == 0) &&
-		arp_key_offset_present)), "Parse error in section "
-			"\"%s\": arp_key_offset present while "
-			"n_arp_entries is not set", params->name);
-
-	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);
-	p->log_level = params->log_level;
-
-	PLOG(p, HIGH, "Routing");
-
-	/* Parse arguments */
-	if (pipeline_routing_parse_args(&p_rt->params, 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,
-			.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 = {
-			.name = p->name,
-			.n_rules = p_rt->params.n_routes,
-			.number_tbl8s = PIPELINE_ROUTING_LPM_TABLE_NUMBER_TABLE8s,
-			.flags = 0,
-			.entry_unique_size = sizeof(struct routing_table_entry),
-			.offset = p_rt->params.ip_hdr_offset +
-				__builtin_offsetof(struct ipv4_hdr, dst_addr),
-		};
-
-		struct rte_pipeline_table_params table_params = {
-				.ops = &rte_table_lpm_ops,
-				.arg_create = &table_lpm_params,
-				.f_action_hit = get_routing_table_ah_hit(p_rt),
-				.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->params.n_arp_entries) {
-		struct rte_table_hash_params table_arp_params = {
-			.name = p->name,
-			.key_size = 8,
-			.key_offset = p_rt->params.arp_key_offset,
-			.key_mask = NULL,
-			.n_keys = p_rt->params.n_arp_entries,
-			.n_buckets =
-				rte_align32pow2(p_rt->params.n_arp_entries / 4),
-			.f_hash = hash_default_key8,
-			.seed = 0,
-		};
-
-		struct rte_pipeline_table_params table_params = {
-			.ops = &rte_table_hash_key8_ext_ops,
-			.arg_create = &table_arp_params,
-			.f_action_hit = get_arp_table_ah_hit(p_rt),
-			.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_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 *p_rt = (struct pipeline_routing *) p;
-	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_arp0 = {
-		.head = {
-			.action = RTE_PIPELINE_ACTION_PORT,
-			{.port_id = p->port_out_id[req->data.port_id]},
-		},
-
-		.flags = req->data.flags,
-		.port_id = req->data.port_id,
-		.ip = 0,
-		.data_offset = 0,
-		.ether_l2_length = 0,
-		.slab = {0},
-		.slab_offset = {0},
-	};
-
-	struct routing_table_entry entry_arp1 = {
-		.head = {
-			.action = RTE_PIPELINE_ACTION_TABLE,
-			{.table_id = p->table_id[1]},
-		},
-
-		.flags = req->data.flags,
-		.port_id = req->data.port_id,
-		.ip = rte_bswap32(req->data.ethernet.ip),
-		.data_offset = 0,
-		.ether_l2_length = 0,
-		.slab = {0},
-		.slab_offset = {0},
-	};
-
-	struct rte_pipeline_table_entry *entry = (p_rt->params.n_arp_entries) ?
-		(struct rte_pipeline_table_entry *) &entry_arp1 :
-		(struct rte_pipeline_table_entry *) &entry_arp0;
-
-	if ((req->key.type != PIPELINE_ROUTING_ROUTE_IPV4) ||
-		((p_rt->params.n_arp_entries == 0) &&
-			(req->data.flags & PIPELINE_ROUTING_ROUTE_ARP)) ||
-		(p_rt->params.n_arp_entries &&
-			((req->data.flags & PIPELINE_ROUTING_ROUTE_ARP) == 0)) ||
-		((p_rt->params.encap != PIPELINE_ROUTING_ENCAP_ETHERNET_QINQ) &&
-			(req->data.flags & PIPELINE_ROUTING_ROUTE_QINQ)) ||
-		((p_rt->params.encap == PIPELINE_ROUTING_ENCAP_ETHERNET_QINQ) &&
-			((req->data.flags & PIPELINE_ROUTING_ROUTE_QINQ) == 0)) ||
-		((p_rt->params.encap != PIPELINE_ROUTING_ENCAP_ETHERNET_MPLS) &&
-			(req->data.flags & PIPELINE_ROUTING_ROUTE_MPLS)) ||
-		((p_rt->params.encap == PIPELINE_ROUTING_ENCAP_ETHERNET_MPLS) &&
-			((req->data.flags & PIPELINE_ROUTING_ROUTE_MPLS) == 0))) {
-		rsp->status = -1;
-		return rsp;
-	}
-
-	/* Ether - ARP off */
-	if ((p_rt->params.encap == PIPELINE_ROUTING_ENCAP_ETHERNET) &&
-		(p_rt->params.n_arp_entries == 0)) {
-		uint64_t macaddr_src = p_rt->macaddr[req->data.port_id];
-		uint64_t macaddr_dst;
-		uint64_t ethertype = ETHER_TYPE_IPv4;
-
-		macaddr_dst = *((uint64_t *)&(req->data.ethernet.macaddr));
-		macaddr_dst = rte_bswap64(macaddr_dst << 16);
-
-		entry_arp0.slab[0] =
-			SLAB_NBO_MACADDRSRC_ETHERTYPE(macaddr_src, ethertype);
-		entry_arp0.slab_offset[0] = p_rt->params.ip_hdr_offset - 8;
-
-		entry_arp0.slab[1] = rte_bswap64(macaddr_dst);
-		entry_arp0.slab_offset[1] = p_rt->params.ip_hdr_offset - 2 * 8;
-
-		entry_arp0.data_offset = entry_arp0.slab_offset[1] + 2
-			- sizeof(struct rte_mbuf);
-		entry_arp0.ether_l2_length = 14;
-	}
-
-	/* Ether - ARP on */
-	if ((p_rt->params.encap == PIPELINE_ROUTING_ENCAP_ETHERNET) &&
-		p_rt->params.n_arp_entries) {
-		uint64_t macaddr_src = p_rt->macaddr[req->data.port_id];
-		uint64_t ethertype = ETHER_TYPE_IPv4;
-
-		entry_arp1.slab[0] =
-			SLAB_NBO_MACADDRSRC_ETHERTYPE(macaddr_src, ethertype);
-		entry_arp1.slab_offset[0] = p_rt->params.ip_hdr_offset - 8;
-
-		entry_arp1.data_offset = entry_arp1.slab_offset[0] - 6
-			- sizeof(struct rte_mbuf);
-		entry_arp1.ether_l2_length = 14;
-	}
-
-	/* Ether QinQ - ARP off */
-	if ((p_rt->params.encap == PIPELINE_ROUTING_ENCAP_ETHERNET_QINQ) &&
-		(p_rt->params.n_arp_entries == 0)) {
-		uint64_t macaddr_src = p_rt->macaddr[req->data.port_id];
-		uint64_t macaddr_dst;
-		uint64_t ethertype_ipv4 = ETHER_TYPE_IPv4;
-		uint64_t ethertype_vlan = 0x8100;
-		uint64_t ethertype_qinq = 0x9100;
-		uint64_t svlan = req->data.l2.qinq.svlan;
-		uint64_t cvlan = req->data.l2.qinq.cvlan;
-
-		macaddr_dst = *((uint64_t *)&(req->data.ethernet.macaddr));
-		macaddr_dst = rte_bswap64(macaddr_dst << 16);
-
-		entry_arp0.slab[0] = rte_bswap64((svlan << 48) |
-			(ethertype_vlan << 32) |
-			(cvlan << 16) |
-			ethertype_ipv4);
-		entry_arp0.slab_offset[0] = p_rt->params.ip_hdr_offset - 8;
-
-		entry_arp0.slab[1] =
-			SLAB_NBO_MACADDRSRC_ETHERTYPE(macaddr_src, ethertype_qinq);
-		entry_arp0.slab_offset[1] = p_rt->params.ip_hdr_offset - 2 * 8;
-
-		entry_arp0.slab[2] = rte_bswap64(macaddr_dst);
-		entry_arp0.slab_offset[2] = p_rt->params.ip_hdr_offset - 3 * 8;
-
-		entry_arp0.data_offset = entry_arp0.slab_offset[2] + 2
-			- sizeof(struct rte_mbuf);
-		entry_arp0.ether_l2_length = 22;
-	}
-
-	/* Ether QinQ - ARP on */
-	if ((p_rt->params.encap == PIPELINE_ROUTING_ENCAP_ETHERNET_QINQ) &&
-		p_rt->params.n_arp_entries) {
-		uint64_t macaddr_src = p_rt->macaddr[req->data.port_id];
-		uint64_t ethertype_ipv4 = ETHER_TYPE_IPv4;
-		uint64_t ethertype_vlan = 0x8100;
-		uint64_t ethertype_qinq = 0x9100;
-		uint64_t svlan = req->data.l2.qinq.svlan;
-		uint64_t cvlan = req->data.l2.qinq.cvlan;
-
-		entry_arp1.slab[0] = rte_bswap64((svlan << 48) |
-			(ethertype_vlan << 32) |
-			(cvlan << 16) |
-			ethertype_ipv4);
-		entry_arp1.slab_offset[0] = p_rt->params.ip_hdr_offset - 8;
-
-		entry_arp1.slab[1] =
-			SLAB_NBO_MACADDRSRC_ETHERTYPE(macaddr_src, ethertype_qinq);
-		entry_arp1.slab_offset[1] = p_rt->params.ip_hdr_offset - 2 * 8;
-
-		entry_arp1.data_offset = entry_arp1.slab_offset[1] - 6
-			- sizeof(struct rte_mbuf);
-		entry_arp1.ether_l2_length = 22;
-	}
-
-	/* Ether MPLS - ARP off */
-	if ((p_rt->params.encap == PIPELINE_ROUTING_ENCAP_ETHERNET_MPLS) &&
-		(p_rt->params.n_arp_entries == 0)) {
-		uint64_t macaddr_src = p_rt->macaddr[req->data.port_id];
-		uint64_t macaddr_dst;
-		uint64_t ethertype_mpls = 0x8847;
-
-		uint64_t label0 = req->data.l2.mpls.labels[0];
-		uint64_t label1 = req->data.l2.mpls.labels[1];
-		uint64_t label2 = req->data.l2.mpls.labels[2];
-		uint64_t label3 = req->data.l2.mpls.labels[3];
-		uint32_t n_labels = req->data.l2.mpls.n_labels;
-
-		macaddr_dst = *((uint64_t *)&(req->data.ethernet.macaddr));
-		macaddr_dst = rte_bswap64(macaddr_dst << 16);
-
-		switch (n_labels) {
-		case 1:
-			entry_arp0.slab[0] = 0;
-			entry_arp0.slab_offset[0] =
-				p_rt->params.ip_hdr_offset - 8;
-
-			entry_arp0.slab[1] = rte_bswap64(
-				MPLS_LABEL(label0, 0, 1, 0));
-			entry_arp0.slab_offset[1] =
-				p_rt->params.ip_hdr_offset - 8;
-			break;
-
-		case 2:
-			entry_arp0.slab[0] = 0;
-			entry_arp0.slab_offset[0] =
-				p_rt->params.ip_hdr_offset - 8;
-
-			entry_arp0.slab[1] = rte_bswap64(
-				(MPLS_LABEL(label0, 0, 0, 0) << 32) |
-				MPLS_LABEL(label1, 0, 1, 0));
-			entry_arp0.slab_offset[1] =
-				p_rt->params.ip_hdr_offset - 8;
-			break;
-
-		case 3:
-			entry_arp0.slab[0] = rte_bswap64(
-				(MPLS_LABEL(label1, 0, 0, 0) << 32) |
-				MPLS_LABEL(label2, 0, 1, 0));
-			entry_arp0.slab_offset[0] =
-				p_rt->params.ip_hdr_offset - 8;
-
-			entry_arp0.slab[1] = rte_bswap64(
-				MPLS_LABEL(label0, 0, 0, 0));
-			entry_arp0.slab_offset[1] =
-				p_rt->params.ip_hdr_offset - 2 * 8;
-			break;
-
-		case 4:
-			entry_arp0.slab[0] = rte_bswap64(
-				(MPLS_LABEL(label2, 0, 0, 0) << 32) |
-				MPLS_LABEL(label3, 0, 1, 0));
-			entry_arp0.slab_offset[0] =
-				p_rt->params.ip_hdr_offset - 8;
-
-			entry_arp0.slab[1] = rte_bswap64(
-				(MPLS_LABEL(label0, 0, 0, 0) << 32) |
-				MPLS_LABEL(label1, 0, 0, 0));
-			entry_arp0.slab_offset[1] =
-				p_rt->params.ip_hdr_offset - 2 * 8;
-			break;
-
-		default:
-			rsp->status = -1;
-			return rsp;
-		}
-
-		entry_arp0.slab[2] =
-			SLAB_NBO_MACADDRSRC_ETHERTYPE(macaddr_src, ethertype_mpls);
-		entry_arp0.slab_offset[2] = p_rt->params.ip_hdr_offset -
-			(n_labels * 4 + 8);
-
-		entry_arp0.slab[3] = rte_bswap64(macaddr_dst);
-		entry_arp0.slab_offset[3] = p_rt->params.ip_hdr_offset -
-			(n_labels * 4 + 2 * 8);
-
-		entry_arp0.data_offset = entry_arp0.slab_offset[3] + 2
-			- sizeof(struct rte_mbuf);
-		entry_arp0.ether_l2_length = n_labels * 4 + 14;
-	}
-
-	/* Ether MPLS - ARP on */
-	if ((p_rt->params.encap == PIPELINE_ROUTING_ENCAP_ETHERNET_MPLS) &&
-		p_rt->params.n_arp_entries) {
-		uint64_t macaddr_src = p_rt->macaddr[req->data.port_id];
-		uint64_t ethertype_mpls = 0x8847;
-
-		uint64_t label0 = req->data.l2.mpls.labels[0];
-		uint64_t label1 = req->data.l2.mpls.labels[1];
-		uint64_t label2 = req->data.l2.mpls.labels[2];
-		uint64_t label3 = req->data.l2.mpls.labels[3];
-		uint32_t n_labels = req->data.l2.mpls.n_labels;
-
-		switch (n_labels) {
-		case 1:
-			entry_arp1.slab[0] = 0;
-			entry_arp1.slab_offset[0] =
-				p_rt->params.ip_hdr_offset - 8;
-
-			entry_arp1.slab[1] = rte_bswap64(
-				MPLS_LABEL(label0, 0, 1, 0));
-			entry_arp1.slab_offset[1] =
-				p_rt->params.ip_hdr_offset - 8;
-			break;
-
-		case 2:
-			entry_arp1.slab[0] = 0;
-			entry_arp1.slab_offset[0] =
-				p_rt->params.ip_hdr_offset - 8;
-
-			entry_arp1.slab[1] = rte_bswap64(
-				(MPLS_LABEL(label0, 0, 0, 0) << 32) |
-				MPLS_LABEL(label1, 0, 1, 0));
-			entry_arp1.slab_offset[1] =
-				p_rt->params.ip_hdr_offset - 8;
-			break;
-
-		case 3:
-			entry_arp1.slab[0] = rte_bswap64(
-				(MPLS_LABEL(label1, 0, 0, 0) << 32) |
-				MPLS_LABEL(label2, 0, 1, 0));
-			entry_arp1.slab_offset[0] =
-				p_rt->params.ip_hdr_offset - 8;
-
-			entry_arp1.slab[1] = rte_bswap64(
-				MPLS_LABEL(label0, 0, 0, 0));
-			entry_arp1.slab_offset[1] =
-				p_rt->params.ip_hdr_offset - 2 * 8;
-			break;
-
-		case 4:
-			entry_arp1.slab[0] = rte_bswap64(
-				(MPLS_LABEL(label2, 0, 0, 0) << 32) |
-				MPLS_LABEL(label3, 0, 1, 0));
-			entry_arp1.slab_offset[0] =
-				p_rt->params.ip_hdr_offset - 8;
-
-			entry_arp1.slab[1] = rte_bswap64(
-				(MPLS_LABEL(label0, 0, 0, 0) << 32) |
-				MPLS_LABEL(label1, 0, 0, 0));
-			entry_arp1.slab_offset[1] =
-				p_rt->params.ip_hdr_offset - 2 * 8;
-			break;
-
-		default:
-			rsp->status = -1;
-			return rsp;
-		}
-
-		entry_arp1.slab[2] =
-			SLAB_NBO_MACADDRSRC_ETHERTYPE(macaddr_src, ethertype_mpls);
-		entry_arp1.slab_offset[2] = p_rt->params.ip_hdr_offset -
-			(n_labels * 4 + 8);
-
-		entry_arp1.data_offset = entry_arp1.slab_offset[2] - 6
-			- sizeof(struct rte_mbuf);
-		entry_arp1.ether_l2_length = n_labels * 4 + 14;
-	}
-
-	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);
-
-	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);
-
-	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_ipv4 key = {
-		.port_id = req->key.key.ipv4.port_id,
-		.ip = rte_bswap32(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, /* set below */
-	};
-
-	if (req->key.type != PIPELINE_ROUTING_ARP_IPV4) {
-		rsp->status = -1;
-		return rsp;
-	}
-
-	entry.macaddr = *((uint64_t *)&(req->macaddr));
-	entry.macaddr = entry.macaddr << 16;
-
-	rsp->status = rte_pipeline_table_entry_add(p->p,
-		p->table_id[1],
-		&key,
-		(struct rte_pipeline_table_entry *) &entry,
-		&rsp->key_found,
-		(struct rte_pipeline_table_entry **) &rsp->entry_ptr);
-
-	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_ipv4 key = {
-		.port_id = req->key.key.ipv4.port_id,
-		.ip = rte_bswap32(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);
-
-	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;
-}
-
-void *
-pipeline_routing_msg_req_set_macaddr_handler(struct pipeline *p, void *msg)
-{
-	struct pipeline_routing *p_rt = (struct pipeline_routing *) p;
-	struct pipeline_routing_set_macaddr_msg_req *req = msg;
-	struct pipeline_routing_set_macaddr_msg_rsp *rsp = msg;
-	uint32_t port_id;
-
-	for (port_id = 0; port_id < p->n_ports_out; port_id++)
-		p_rt->macaddr[port_id] = req->macaddr[port_id];
-
-	rsp->status = 0;
-
-	return rsp;
-}
-
-struct pipeline_be_ops pipeline_routing_be_ops = {
-	.f_init = pipeline_routing_init,
-	.f_free = pipeline_routing_free,
-	.f_run = NULL,
-	.f_timer = pipeline_routing_timer,
-};
diff --git a/examples/ip_pipeline/pipeline/pipeline_routing_be.h b/examples/ip_pipeline/pipeline/pipeline_routing_be.h
deleted file mode 100644
index 7140ee4..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_routing_be.h
+++ /dev/null
@@ -1,283 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#ifndef __INCLUDE_PIPELINE_ROUTING_BE_H__
-#define __INCLUDE_PIPELINE_ROUTING_BE_H__
-
-#include <rte_ether.h>
-
-#include "pipeline_common_be.h"
-
-/*
- * Pipeline argument parsing
- */
-#ifndef PIPELINE_ROUTING_N_ROUTES_DEFAULT
-#define PIPELINE_ROUTING_N_ROUTES_DEFAULT                  4096
-#endif
-
-enum pipeline_routing_encap {
-	PIPELINE_ROUTING_ENCAP_ETHERNET = 0,
-	PIPELINE_ROUTING_ENCAP_ETHERNET_QINQ,
-	PIPELINE_ROUTING_ENCAP_ETHERNET_MPLS,
-};
-
-struct pipeline_routing_params {
-	/* routing */
-	uint32_t n_routes;
-	uint32_t port_local_dest;
-
-	/* routing packet encapsulation */
-	enum pipeline_routing_encap encap;
-	uint32_t qinq_sched;
-	uint32_t mpls_color_mark;
-
-	/* arp */
-	uint32_t n_arp_entries;
-
-	/* packet buffer offsets */
-	uint32_t ip_hdr_offset;
-	uint32_t arp_key_offset;
-	uint32_t color_offset;
-
-	/* debug */
-	uint32_t dbg_ah_disable;
-};
-
-int
-pipeline_routing_parse_args(struct pipeline_routing_params *p,
-	struct pipeline_params *params);
-
-/*
- * Route
- */
-enum pipeline_routing_route_key_type {
-	PIPELINE_ROUTING_ROUTE_IPV4,
-};
-
-struct pipeline_routing_route_key_ipv4 {
-	uint32_t ip;
-	uint32_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 */
-	PIPELINE_ROUTING_ROUTE_ARP = 1 << 1, /* 0 = ARP OFF; 1 = ARP ON */
-	PIPELINE_ROUTING_ROUTE_QINQ = 1 << 2, /* 0 = QINQ OFF; 1 = QINQ ON */
-	PIPELINE_ROUTING_ROUTE_MPLS = 1 << 3, /* 0 = MPLS OFF; 1 = MPLS ON */
-};
-
-#define PIPELINE_ROUTING_MPLS_LABELS_MAX         4
-
-struct pipeline_routing_route_data {
-	uint32_t flags;
-	uint32_t port_id; /* Output port ID */
-
-	union {
-		/* Next hop IP (valid only when ARP is enabled) */
-		uint32_t ip;
-
-		/* Next hop MAC address (valid only when ARP disabled */
-		struct ether_addr macaddr;
-	} ethernet;
-
-	union {
-		struct {
-			uint16_t svlan;
-			uint16_t cvlan;
-		} qinq;
-
-		struct {
-			uint32_t labels[PIPELINE_ROUTING_MPLS_LABELS_MAX];
-			uint32_t n_labels;
-		} mpls;
-	} l2;
-};
-
-/*
- * 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_REQ_SET_MACADDR,
-	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 */
-	struct pipeline_routing_route_data data;
-};
-
-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;
-};
-
-/*
- * MSG SET MACADDR
- */
-struct pipeline_routing_set_macaddr_msg_req {
-	enum pipeline_msg_req_type type;
-	enum pipeline_routing_msg_req_type subtype;
-
-	uint64_t macaddr[PIPELINE_MAX_PORT_OUT];
-};
-
-struct pipeline_routing_set_macaddr_msg_rsp {
-	int status;
-};
-
-extern struct pipeline_be_ops pipeline_routing_be_ops;
-
-#endif
diff --git a/examples/ip_pipeline/pipeline_be.h b/examples/ip_pipeline/pipeline_be.h
deleted file mode 100644
index 6c0c97a..0000000
--- a/examples/ip_pipeline/pipeline_be.h
+++ /dev/null
@@ -1,322 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2016 Intel Corporation
- */
-
-#ifndef __INCLUDE_PIPELINE_BE_H__
-#define __INCLUDE_PIPELINE_BE_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_fd.h>
-#include <rte_port_source_sink.h>
-#ifdef RTE_LIBRTE_KNI
-#include <rte_port_kni.h>
-#endif
-#include <rte_pipeline.h>
-
-enum pipeline_port_in_type {
-	PIPELINE_PORT_IN_ETHDEV_READER,
-	PIPELINE_PORT_IN_RING_READER,
-	PIPELINE_PORT_IN_RING_MULTI_READER,
-	PIPELINE_PORT_IN_RING_READER_IPV4_FRAG,
-	PIPELINE_PORT_IN_RING_READER_IPV6_FRAG,
-	PIPELINE_PORT_IN_SCHED_READER,
-	PIPELINE_PORT_IN_FD_READER,
-	PIPELINE_PORT_IN_KNI_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_multi_reader_params ring_multi;
-		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_fd_reader_params fd;
-#ifdef RTE_LIBRTE_KNI
-		struct rte_port_kni_reader_params kni;
-#endif
-		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_MULTI_READER:
-		return (void *) &p->params.ring_multi;
-	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_FD_READER:
-		return (void *) &p->params.fd;
-#ifdef RTE_LIBRTE_KNI
-	case PIPELINE_PORT_IN_KNI_READER:
-		return (void *) &p->params.kni;
-#endif
-	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_MULTI_READER:
-		return &rte_port_ring_multi_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_FD_READER:
-		return &rte_port_fd_reader_ops;
-#ifdef RTE_LIBRTE_KNI
-	case PIPELINE_PORT_IN_KNI_READER:
-		return &rte_port_kni_reader_ops;
-#endif
-	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_MULTI_WRITER,
-	PIPELINE_PORT_OUT_RING_WRITER_NODROP,
-	PIPELINE_PORT_OUT_RING_MULTI_WRITER_NODROP,
-	PIPELINE_PORT_OUT_RING_WRITER_IPV4_RAS,
-	PIPELINE_PORT_OUT_RING_WRITER_IPV6_RAS,
-	PIPELINE_PORT_OUT_SCHED_WRITER,
-	PIPELINE_PORT_OUT_FD_WRITER,
-	PIPELINE_PORT_OUT_KNI_WRITER,
-	PIPELINE_PORT_OUT_KNI_WRITER_NODROP,
-	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_multi_writer_params ring_multi;
-		struct rte_port_ring_writer_nodrop_params ring_nodrop;
-		struct rte_port_ring_multi_writer_nodrop_params ring_multi_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;
-		struct rte_port_fd_writer_params fd;
-#ifdef RTE_LIBRTE_KNI
-		struct rte_port_kni_writer_params kni;
-		struct rte_port_kni_writer_nodrop_params kni_nodrop;
-#endif
-		struct rte_port_sink_params sink;
-	} 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_MULTI_WRITER:
-		return (void *) &p->params.ring_multi;
-	case PIPELINE_PORT_OUT_RING_WRITER_NODROP:
-		return (void *) &p->params.ring_nodrop;
-	case PIPELINE_PORT_OUT_RING_MULTI_WRITER_NODROP:
-		return (void *) &p->params.ring_multi_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_FD_WRITER:
-		return (void *) &p->params.fd;
-#ifdef RTE_LIBRTE_KNI
-	case PIPELINE_PORT_OUT_KNI_WRITER:
-		return (void *) &p->params.kni;
-	case PIPELINE_PORT_OUT_KNI_WRITER_NODROP:
-		return (void *) &p->params.kni_nodrop;
-#endif
-	case PIPELINE_PORT_OUT_SINK:
-		return (void *) &p->params.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_MULTI_WRITER:
-		return &rte_port_ring_multi_writer_ops;
-	case PIPELINE_PORT_OUT_RING_WRITER_NODROP:
-		return &rte_port_ring_writer_nodrop_ops;
-	case PIPELINE_PORT_OUT_RING_MULTI_WRITER_NODROP:
-		return &rte_port_ring_multi_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_FD_WRITER:
-		return &rte_port_fd_writer_ops;
-#ifdef RTE_LIBRTE_KNI
-	case PIPELINE_PORT_OUT_KNI_WRITER:
-		return &rte_port_kni_writer_ops;
-	case PIPELINE_PORT_OUT_KNI_WRITER_NODROP:
-		return &rte_port_kni_writer_nodrop_ops;
-#endif
-	case PIPELINE_PORT_OUT_SINK:
-		return &rte_port_sink_ops;
-	default:
-		return NULL;
-	}
-}
-
-#ifndef PIPELINE_NAME_SIZE
-#define PIPELINE_NAME_SIZE                       64
-#endif
-
-#ifndef PIPELINE_TYPE_SIZE
-#define PIPELINE_TYPE_SIZE                       64
-#endif
-
-#ifndef PIPELINE_MAX_PORT_IN
-#define PIPELINE_MAX_PORT_IN                     64
-#endif
-
-#ifndef PIPELINE_MAX_PORT_OUT
-#define PIPELINE_MAX_PORT_OUT                    64
-#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                        64
-#endif
-
-struct pipeline_params {
-	char name[PIPELINE_NAME_SIZE];
-	char type[PIPELINE_TYPE_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;
-
-	uint32_t log_level;
-};
-
-/*
- * Pipeline type back-end operations
- */
-
-typedef void* (*pipeline_be_op_init)(struct pipeline_params *params,
-	void *arg);
-
-typedef int (*pipeline_be_op_free)(void *pipeline);
-
-typedef int (*pipeline_be_op_run)(void *pipeline);
-
-typedef int (*pipeline_be_op_timer)(void *pipeline);
-
-struct pipeline_be_ops {
-	pipeline_be_op_init f_init;
-	pipeline_be_op_free f_free;
-	pipeline_be_op_run f_run;
-	pipeline_be_op_timer f_timer;
-};
-
-/* Pipeline specific config parse error messages */
-#define PIPELINE_ARG_CHECK(exp, fmt, ...)				\
-do {									\
-	if (!(exp)) {							\
-		fprintf(stderr, fmt "\n", ## __VA_ARGS__);		\
-		return -1;						\
-	}								\
-} while (0)
-
-#define PIPELINE_PARSE_ERR_INV_VAL(exp, section, entry, val)		\
-PIPELINE_ARG_CHECK(exp, "Parse error in section \"%s\": entry \"%s\" "	\
-	"has invalid value (\"%s\")", section, entry, val)
-
-#define PIPELINE_PARSE_ERR_OUT_RNG(exp, section, entry, val)		\
-PIPELINE_ARG_CHECK(exp, "Parse error in section \"%s\": entry \"%s\" "	\
-	"value is out of range (\"%s\")", section, entry, val)
-
-#define PIPELINE_PARSE_ERR_DUPLICATE(exp, section, entry)		\
-PIPELINE_ARG_CHECK(exp, "Parse error in section \"%s\": duplicated "	\
-	"entry \"%s\"", section, entry)
-
-#define PIPELINE_PARSE_ERR_INV_ENT(exp, section, entry)			\
-PIPELINE_ARG_CHECK(exp, "Parse error in section \"%s\": invalid entry "	\
-	"\"%s\"", section, entry)
-
-#define PIPELINE_PARSE_ERR_MANDATORY(exp, section, entry)		\
-PIPELINE_ARG_CHECK(exp, "Parse error in section \"%s\": mandatory "	\
-	"entry \"%s\" is missing", section, entry)
-
-#endif
diff --git a/examples/ip_pipeline/thread.c b/examples/ip_pipeline/thread.c
deleted file mode 100644
index 9013afd..0000000
--- a/examples/ip_pipeline/thread.c
+++ /dev/null
@@ -1,293 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#include <rte_common.h>
-#include <rte_cycles.h>
-#include <rte_pipeline.h>
-
-#include "pipeline_common_be.h"
-#include "app.h"
-#include "thread.h"
-
-#if APP_THREAD_HEADROOM_STATS_COLLECT
-
-#define PIPELINE_RUN_REGULAR(thread, pipeline)		\
-do {							\
-	uint64_t t0 = rte_rdtsc_precise();		\
-	int n_pkts = rte_pipeline_run(pipeline->p);	\
-							\
-	if (n_pkts == 0) {				\
-		uint64_t t1 = rte_rdtsc_precise();	\
-							\
-		thread->headroom_cycles += t1 - t0;	\
-	}						\
-} while (0)
-
-
-#define PIPELINE_RUN_CUSTOM(thread, data)		\
-do {							\
-	uint64_t t0 = rte_rdtsc_precise();		\
-	int n_pkts = data->f_run(data->be);		\
-							\
-	if (n_pkts == 0) {				\
-		uint64_t t1 = rte_rdtsc_precise();	\
-							\
-		thread->headroom_cycles += t1 - t0;	\
-	}						\
-} while (0)
-
-#else
-
-#define PIPELINE_RUN_REGULAR(thread, pipeline)		\
-	rte_pipeline_run(pipeline->p)
-
-#define PIPELINE_RUN_CUSTOM(thread, data)		\
-	data->f_run(data->be)
-
-#endif
-
-static inline void *
-thread_msg_recv(struct rte_ring *r)
-{
-	void *msg;
-	int status = rte_ring_sc_dequeue(r, &msg);
-
-	if (status != 0)
-		return NULL;
-
-	return msg;
-}
-
-static inline void
-thread_msg_send(struct rte_ring *r,
-	void *msg)
-{
-	int status;
-
-	do {
-		status = rte_ring_sp_enqueue(r, msg);
-	} while (status == -ENOBUFS);
-}
-
-static int
-thread_pipeline_enable(struct app_thread_data *t,
-		struct thread_pipeline_enable_msg_req *req)
-{
-	struct app_thread_pipeline_data *p;
-
-	if (req->f_run == NULL) {
-		if (t->n_regular >= APP_MAX_THREAD_PIPELINES)
-			return -1;
-	} else {
-		if (t->n_custom >= APP_MAX_THREAD_PIPELINES)
-			return -1;
-	}
-
-	p = (req->f_run == NULL) ?
-		&t->regular[t->n_regular] :
-		&t->custom[t->n_custom];
-
-	p->pipeline_id = req->pipeline_id;
-	p->be = req->be;
-	p->f_run = req->f_run;
-	p->f_timer = req->f_timer;
-	p->timer_period = req->timer_period;
-	p->deadline = 0;
-
-	if (req->f_run == NULL)
-		t->n_regular++;
-	else
-		t->n_custom++;
-
-	return 0;
-}
-
-static int
-thread_pipeline_disable(struct app_thread_data *t,
-		struct thread_pipeline_disable_msg_req *req)
-{
-	uint32_t n_regular = RTE_MIN(t->n_regular, RTE_DIM(t->regular));
-	uint32_t n_custom = RTE_MIN(t->n_custom, RTE_DIM(t->custom));
-	uint32_t i;
-
-	/* search regular pipelines of current thread */
-	for (i = 0; i < n_regular; i++) {
-		if (t->regular[i].pipeline_id != req->pipeline_id)
-			continue;
-
-		if (i < n_regular - 1)
-			memcpy(&t->regular[i],
-			  &t->regular[i+1],
-			  (n_regular - 1 - i) * sizeof(struct app_thread_pipeline_data));
-
-		n_regular--;
-		t->n_regular = n_regular;
-
-		return 0;
-	}
-
-	/* search custom pipelines of current thread */
-	for (i = 0; i < n_custom; i++) {
-		if (t->custom[i].pipeline_id != req->pipeline_id)
-			continue;
-
-		if (i < n_custom - 1)
-			memcpy(&t->custom[i],
-			  &t->custom[i+1],
-			  (n_custom - 1 - i) * sizeof(struct app_thread_pipeline_data));
-
-		n_custom--;
-		t->n_custom = n_custom;
-
-		return 0;
-	}
-
-	/* return if pipeline not found */
-	return -1;
-}
-
-static int
-thread_msg_req_handle(struct app_thread_data *t)
-{
-	void *msg_ptr;
-	struct thread_msg_req *req;
-	struct thread_msg_rsp *rsp;
-
-	msg_ptr = thread_msg_recv(t->msgq_in);
-	req = msg_ptr;
-	rsp = msg_ptr;
-
-	if (req != NULL)
-		switch (req->type) {
-		case THREAD_MSG_REQ_PIPELINE_ENABLE: {
-			rsp->status = thread_pipeline_enable(t,
-					(struct thread_pipeline_enable_msg_req *) req);
-			thread_msg_send(t->msgq_out, rsp);
-			break;
-		}
-
-		case THREAD_MSG_REQ_PIPELINE_DISABLE: {
-			rsp->status = thread_pipeline_disable(t,
-					(struct thread_pipeline_disable_msg_req *) req);
-			thread_msg_send(t->msgq_out, rsp);
-			break;
-		}
-
-		case THREAD_MSG_REQ_HEADROOM_READ: {
-			struct thread_headroom_read_msg_rsp *rsp =
-				(struct thread_headroom_read_msg_rsp *)
-				req;
-
-			rsp->headroom_ratio = t->headroom_ratio;
-			rsp->status = 0;
-			thread_msg_send(t->msgq_out, rsp);
-			break;
-		}
-		default:
-			break;
-		}
-
-	return 0;
-}
-
-static void
-thread_headroom_update(struct app_thread_data *t, uint64_t time)
-{
-	uint64_t time_diff = time - t->headroom_time;
-
-	t->headroom_ratio =
-		((double) t->headroom_cycles) / ((double) time_diff);
-
-	t->headroom_cycles = 0;
-	t->headroom_time = rte_rdtsc_precise();
-}
-
-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++) {
-		uint32_t n_regular = RTE_MIN(t->n_regular, RTE_DIM(t->regular));
-		uint32_t n_custom = RTE_MIN(t->n_custom, RTE_DIM(t->custom));
-
-		/* Run regular pipelines */
-		for (j = 0; j < n_regular; j++) {
-			struct app_thread_pipeline_data *data = &t->regular[j];
-			struct pipeline *p = data->be;
-
-			PIPELINE_RUN_REGULAR(t, p);
-		}
-
-		/* Run custom pipelines */
-		for (j = 0; j < n_custom; j++) {
-			struct app_thread_pipeline_data *data = &t->custom[j];
-
-			PIPELINE_RUN_CUSTOM(t, data);
-		}
-
-		/* 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 < 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 < 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;
-			}
-
-			/* Timer for thread message request */
-			{
-				uint64_t deadline = t->thread_req_deadline;
-
-				if (deadline <= time) {
-					thread_msg_req_handle(t);
-					thread_headroom_update(t, time);
-					deadline = time + t->timer_period;
-					t->thread_req_deadline = deadline;
-				}
-
-				if (deadline < t_deadline)
-					t_deadline = deadline;
-			}
-
-
-			t->deadline = t_deadline;
-		}
-	}
-
-	return 0;
-}
diff --git a/examples/ip_pipeline/thread.h b/examples/ip_pipeline/thread.h
deleted file mode 100644
index 2c4fb6a..0000000
--- a/examples/ip_pipeline/thread.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#ifndef THREAD_H_
-#define THREAD_H_
-
-#include "app.h"
-#include "pipeline_be.h"
-
-enum thread_msg_req_type {
-	THREAD_MSG_REQ_PIPELINE_ENABLE = 0,
-	THREAD_MSG_REQ_PIPELINE_DISABLE,
-	THREAD_MSG_REQ_HEADROOM_READ,
-	THREAD_MSG_REQS
-};
-
-struct thread_msg_req {
-	enum thread_msg_req_type type;
-};
-
-struct thread_msg_rsp {
-	int status;
-};
-
-/*
- * PIPELINE ENABLE
- */
-struct thread_pipeline_enable_msg_req {
-	enum thread_msg_req_type type;
-
-	uint32_t pipeline_id;
-	void *be;
-	pipeline_be_op_run f_run;
-	pipeline_be_op_timer f_timer;
-	uint64_t timer_period;
-};
-
-struct thread_pipeline_enable_msg_rsp {
-	int status;
-};
-
-/*
- * PIPELINE DISABLE
- */
-struct thread_pipeline_disable_msg_req {
-	enum thread_msg_req_type type;
-
-	uint32_t pipeline_id;
-};
-
-struct thread_pipeline_disable_msg_rsp {
-	int status;
-};
-
-/*
- * THREAD HEADROOM
- */
-struct thread_headroom_read_msg_req {
-	enum thread_msg_req_type type;
-};
-
-struct thread_headroom_read_msg_rsp {
-	int status;
-
-	double headroom_ratio;
-};
-
-#endif /* THREAD_H_ */
diff --git a/examples/ip_pipeline/thread_fe.c b/examples/ip_pipeline/thread_fe.c
deleted file mode 100644
index 4590c2b..0000000
--- a/examples/ip_pipeline/thread_fe.c
+++ /dev/null
@@ -1,457 +0,0 @@
-#include <rte_common.h>
-#include <rte_ring.h>
-#include <rte_malloc.h>
-#include <cmdline_rdline.h>
-#include <cmdline_parse.h>
-#include <cmdline_parse_num.h>
-#include <cmdline_parse_string.h>
-
-#include "thread.h"
-#include "thread_fe.h"
-#include "pipeline.h"
-#include "pipeline_common_fe.h"
-#include "app.h"
-
-static inline void *
-thread_msg_send_recv(struct app_params *app,
-	uint32_t socket_id, uint32_t core_id, uint32_t ht_id,
-	void *msg,
-	uint32_t timeout_ms)
-{
-	struct rte_ring *r_req = app_thread_msgq_in_get(app,
-		socket_id, core_id, ht_id);
-	struct rte_ring *r_rsp = app_thread_msgq_out_get(app,
-		socket_id, core_id, ht_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_enable(struct app_params *app,
-		uint32_t socket_id,
-		uint32_t core_id,
-		uint32_t hyper_th_id,
-		uint32_t pipeline_id)
-{
-	struct thread_pipeline_enable_msg_req *req;
-	struct thread_pipeline_enable_msg_rsp *rsp;
-	int thread_id;
-	struct app_pipeline_data *p;
-	struct app_pipeline_params *p_params;
-	struct pipeline_type *p_type;
-	int status;
-
-	if (app == NULL)
-		return -1;
-
-	thread_id = cpu_core_map_get_lcore_id(app->core_map,
-			socket_id,
-			core_id,
-			hyper_th_id);
-
-	if ((thread_id < 0) || !app_core_is_enabled(app, thread_id))
-		return -1;
-
-	if (app_pipeline_data(app, pipeline_id) == NULL)
-		return -1;
-
-	p = &app->pipeline_data[pipeline_id];
-	p_params = &app->pipeline_params[pipeline_id];
-	p_type = app_pipeline_type_find(app, p_params->type);
-
-	if (p_type == NULL)
-		return -1;
-
-	if (p->enabled == 1)
-		return -1;
-
-	req = app_msg_alloc(app);
-	if (req == NULL)
-		return -1;
-
-	req->type = THREAD_MSG_REQ_PIPELINE_ENABLE;
-	req->pipeline_id = pipeline_id;
-	req->be = p->be;
-	req->f_run = p_type->be_ops->f_run;
-	req->f_timer = p_type->be_ops->f_timer;
-	req->timer_period = p->timer_period;
-
-	rsp = thread_msg_send_recv(app,
-		socket_id, core_id, hyper_th_id, req, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	status = rsp->status;
-	app_msg_free(app, rsp);
-
-	if (status != 0)
-		return -1;
-
-	p->enabled = 1;
-	return 0;
-}
-
-int
-app_pipeline_disable(struct app_params *app,
-		uint32_t socket_id,
-		uint32_t core_id,
-		uint32_t hyper_th_id,
-		uint32_t pipeline_id)
-{
-	struct thread_pipeline_disable_msg_req *req;
-	struct thread_pipeline_disable_msg_rsp *rsp;
-	int thread_id;
-	struct app_pipeline_data *p;
-	int status;
-
-	if (app == NULL)
-		return -1;
-
-	thread_id = cpu_core_map_get_lcore_id(app->core_map,
-			socket_id,
-			core_id,
-			hyper_th_id);
-
-	if ((thread_id < 0) || !app_core_is_enabled(app, thread_id))
-		return -1;
-
-	if (app_pipeline_data(app, pipeline_id) == NULL)
-		return -1;
-
-	p = &app->pipeline_data[pipeline_id];
-
-	if (p->enabled == 0)
-		return -1;
-
-	req = app_msg_alloc(app);
-	if (req == NULL)
-		return -1;
-
-	req->type = THREAD_MSG_REQ_PIPELINE_DISABLE;
-	req->pipeline_id = pipeline_id;
-
-	rsp = thread_msg_send_recv(app,
-		socket_id, core_id, hyper_th_id, req, MSG_TIMEOUT_DEFAULT);
-
-	if (rsp == NULL)
-		return -1;
-
-	status = rsp->status;
-	app_msg_free(app, rsp);
-
-	if (status != 0)
-		return -1;
-
-	p->enabled = 0;
-	return 0;
-}
-
-int
-app_thread_headroom(struct app_params *app,
-		uint32_t socket_id,
-		uint32_t core_id,
-		uint32_t hyper_th_id)
-{
-	struct thread_headroom_read_msg_req *req;
-	struct thread_headroom_read_msg_rsp *rsp;
-	int thread_id;
-	int status;
-
-	if (app == NULL)
-		return -1;
-
-	thread_id = cpu_core_map_get_lcore_id(app->core_map,
-			socket_id,
-			core_id,
-			hyper_th_id);
-
-	if ((thread_id < 0) || !app_core_is_enabled(app, thread_id))
-		return -1;
-
-	req = app_msg_alloc(app);
-	if (req == NULL)
-		return -1;
-
-	req->type = THREAD_MSG_REQ_HEADROOM_READ;
-
-	rsp = thread_msg_send_recv(app,
-		socket_id, core_id, hyper_th_id, req, MSG_TIMEOUT_DEFAULT);
-
-	if (rsp == NULL)
-		return -1;
-
-	status = rsp->status;
-
-	if (status != 0)
-		return -1;
-
-	printf("%.3f%%\n", rsp->headroom_ratio * 100);
-
-
-	app_msg_free(app, rsp);
-
-	return 0;
-}
-
-/*
- * pipeline enable
- */
-
-struct cmd_pipeline_enable_result {
-	cmdline_fixed_string_t t_string;
-	cmdline_fixed_string_t t_id_string;
-	cmdline_fixed_string_t pipeline_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t enable_string;
-};
-
-static void
-cmd_pipeline_enable_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	 void *data)
-{
-	struct cmd_pipeline_enable_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
-	uint32_t core_id, socket_id, hyper_th_id;
-
-	if (parse_pipeline_core(&socket_id,
-			&core_id,
-			&hyper_th_id,
-			params->t_id_string) != 0) {
-		printf("Command failed\n");
-		return;
-	}
-
-	status = app_pipeline_enable(app,
-			socket_id,
-			core_id,
-			hyper_th_id,
-			params->pipeline_id);
-
-	if (status != 0)
-		printf("Command failed\n");
-}
-
-static cmdline_parse_token_string_t cmd_pipeline_enable_t_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_pipeline_enable_result, t_string, "t");
-
-static cmdline_parse_token_string_t cmd_pipeline_enable_t_id_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_pipeline_enable_result, t_id_string,
-		NULL);
-
-static cmdline_parse_token_string_t cmd_pipeline_enable_pipeline_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_pipeline_enable_result, pipeline_string,
-		"pipeline");
-
-static cmdline_parse_token_num_t cmd_pipeline_enable_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_pipeline_enable_result, pipeline_id,
-		UINT32);
-
-static cmdline_parse_token_string_t cmd_pipeline_enable_enable_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_pipeline_enable_result, enable_string,
-		"enable");
-
-static cmdline_parse_inst_t cmd_pipeline_enable = {
-	.f = cmd_pipeline_enable_parsed,
-	.data = NULL,
-	.help_str = "Enable pipeline on specified core",
-	.tokens = {
-		(void *)&cmd_pipeline_enable_t_string,
-		(void *)&cmd_pipeline_enable_t_id_string,
-		(void *)&cmd_pipeline_enable_pipeline_string,
-		(void *)&cmd_pipeline_enable_pipeline_id,
-		(void *)&cmd_pipeline_enable_enable_string,
-		NULL,
-	},
-};
-
-/*
- * pipeline disable
- */
-
-struct cmd_pipeline_disable_result {
-	cmdline_fixed_string_t t_string;
-	cmdline_fixed_string_t t_id_string;
-	cmdline_fixed_string_t pipeline_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t disable_string;
-};
-
-static void
-cmd_pipeline_disable_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	 void *data)
-{
-	struct cmd_pipeline_disable_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
-	uint32_t core_id, socket_id, hyper_th_id;
-
-	if (parse_pipeline_core(&socket_id,
-			&core_id,
-			&hyper_th_id,
-			params->t_id_string) != 0) {
-		printf("Command failed\n");
-		return;
-	}
-
-	status = app_pipeline_disable(app,
-			socket_id,
-			core_id,
-			hyper_th_id,
-			params->pipeline_id);
-
-	if (status != 0)
-		printf("Command failed\n");
-}
-
-static cmdline_parse_token_string_t cmd_pipeline_disable_t_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_pipeline_disable_result, t_string, "t");
-
-static cmdline_parse_token_string_t cmd_pipeline_disable_t_id_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_pipeline_disable_result, t_id_string,
-		NULL);
-
-static cmdline_parse_token_string_t cmd_pipeline_disable_pipeline_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_pipeline_disable_result,
-		pipeline_string, "pipeline");
-
-static cmdline_parse_token_num_t cmd_pipeline_disable_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_pipeline_disable_result, pipeline_id,
-		UINT32);
-
-static cmdline_parse_token_string_t cmd_pipeline_disable_disable_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_pipeline_disable_result, disable_string,
-		"disable");
-
-static cmdline_parse_inst_t cmd_pipeline_disable = {
-	.f = cmd_pipeline_disable_parsed,
-	.data = NULL,
-	.help_str = "Disable pipeline on specified core",
-	.tokens = {
-		(void *)&cmd_pipeline_disable_t_string,
-		(void *)&cmd_pipeline_disable_t_id_string,
-		(void *)&cmd_pipeline_disable_pipeline_string,
-		(void *)&cmd_pipeline_disable_pipeline_id,
-		(void *)&cmd_pipeline_disable_disable_string,
-		NULL,
-	},
-};
-
-
-/*
- * thread headroom
- */
-
-struct cmd_thread_headroom_result {
-	cmdline_fixed_string_t t_string;
-	cmdline_fixed_string_t t_id_string;
-	cmdline_fixed_string_t headroom_string;
-};
-
-static void
-cmd_thread_headroom_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	 void *data)
-{
-	struct cmd_thread_headroom_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
-	uint32_t core_id, socket_id, hyper_th_id;
-
-	if (parse_pipeline_core(&socket_id,
-			&core_id,
-			&hyper_th_id,
-			params->t_id_string) != 0) {
-		printf("Command failed\n");
-		return;
-	}
-
-	status = app_thread_headroom(app,
-			socket_id,
-			core_id,
-			hyper_th_id);
-
-	if (status != 0)
-		printf("Command failed\n");
-}
-
-static cmdline_parse_token_string_t cmd_thread_headroom_t_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_thread_headroom_result,
-	t_string, "t");
-
-static cmdline_parse_token_string_t cmd_thread_headroom_t_id_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_thread_headroom_result,
-	t_id_string, NULL);
-
-static cmdline_parse_token_string_t cmd_thread_headroom_headroom_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_thread_headroom_result,
-		headroom_string, "headroom");
-
-static cmdline_parse_inst_t cmd_thread_headroom = {
-	.f = cmd_thread_headroom_parsed,
-	.data = NULL,
-	.help_str = "Display thread headroom",
-	.tokens = {
-		(void *)&cmd_thread_headroom_t_string,
-		(void *)&cmd_thread_headroom_t_id_string,
-		(void *)&cmd_thread_headroom_headroom_string,
-		NULL,
-	},
-};
-
-
-static cmdline_parse_ctx_t thread_cmds[] = {
-	(cmdline_parse_inst_t *) &cmd_pipeline_enable,
-	(cmdline_parse_inst_t *) &cmd_pipeline_disable,
-	(cmdline_parse_inst_t *) &cmd_thread_headroom,
-	NULL,
-};
-
-int
-app_pipeline_thread_cmd_push(struct app_params *app)
-{
-	uint32_t n_cmds, i;
-
-	/* Check for available slots in the application commands array */
-	n_cmds = RTE_DIM(thread_cmds) - 1;
-	if (n_cmds > APP_MAX_CMDS - app->n_cmds)
-		return -ENOMEM;
-
-	/* Push thread commands into the application */
-	memcpy(&app->cmds[app->n_cmds], thread_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;
-}
diff --git a/examples/ip_pipeline/thread_fe.h b/examples/ip_pipeline/thread_fe.h
deleted file mode 100644
index 056a5e8..0000000
--- a/examples/ip_pipeline/thread_fe.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#ifndef THREAD_FE_H_
-#define THREAD_FE_H_
-
-static inline struct rte_ring *
-app_thread_msgq_in_get(struct app_params *app,
-		uint32_t socket_id, uint32_t core_id, uint32_t ht_id)
-{
-	char msgq_name[32];
-	ssize_t param_idx;
-
-	snprintf(msgq_name, sizeof(msgq_name),
-		"MSGQ-REQ-CORE-s%" PRIu32 "c%" PRIu32 "%s",
-		socket_id,
-		core_id,
-		(ht_id) ? "h" : "");
-	param_idx = APP_PARAM_FIND(app->msgq_params, msgq_name);
-
-	if (param_idx < 0)
-		return NULL;
-
-	return app->msgq[param_idx];
-}
-
-static inline struct rte_ring *
-app_thread_msgq_out_get(struct app_params *app,
-		uint32_t socket_id, uint32_t core_id, uint32_t ht_id)
-{
-	char msgq_name[32];
-	ssize_t param_idx;
-
-	snprintf(msgq_name, sizeof(msgq_name),
-		"MSGQ-RSP-CORE-s%" PRIu32 "c%" PRIu32 "%s",
-		socket_id,
-		core_id,
-		(ht_id) ? "h" : "");
-	param_idx = APP_PARAM_FIND(app->msgq_params, msgq_name);
-
-	if (param_idx < 0)
-		return NULL;
-
-	return app->msgq[param_idx];
-
-}
-
-int
-app_pipeline_thread_cmd_push(struct app_params *app);
-
-int
-app_pipeline_enable(struct app_params *app,
-		uint32_t core_id,
-		uint32_t socket_id,
-		uint32_t hyper_th_id,
-		uint32_t pipeline_id);
-
-int
-app_pipeline_disable(struct app_params *app,
-		uint32_t core_id,
-		uint32_t socket_id,
-		uint32_t hyper_th_id,
-		uint32_t pipeline_id);
-
-int
-app_thread_headroom(struct app_params *app,
-		uint32_t core_id,
-		uint32_t socket_id,
-		uint32_t hyper_th_id);
-
-#endif /* THREAD_FE_H_ */
-- 
2.9.3

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

* [dpdk-dev] [PATCH 11/37] ip_pipeline: add cli interface
  2018-03-09 18:23 [dpdk-dev] [PATCH 00/37] ip_pipeline: refactoring Jasvinder Singh
                   ` (9 preceding siblings ...)
  2018-03-09 18:23 ` [dpdk-dev] [PATCH 10/37] ip_pipeline: rework and improvements Jasvinder Singh
@ 2018-03-09 18:24 ` Jasvinder Singh
  2018-03-09 18:24 ` [dpdk-dev] [PATCH 12/37] ip_pipeline: add mempool object for pipeline Jasvinder Singh
                   ` (25 subsequent siblings)
  36 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-09 18:24 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

CLI interface allowing connectivity with external agent(e.g. telnet,
netcat, Python script, etc) is added to the application.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/Makefile    |   4 +-
 examples/ip_pipeline/cli.c       |  85 ++++++++++
 examples/ip_pipeline/cli.h       |  18 +++
 examples/ip_pipeline/conn.c      | 326 +++++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/conn.h      |  47 ++++++
 examples/ip_pipeline/main.c      | 151 +++++++++++++++++-
 examples/ip_pipeline/meson.build |   5 +-
 7 files changed, 632 insertions(+), 4 deletions(-)
 create mode 100644 examples/ip_pipeline/cli.c
 create mode 100644 examples/ip_pipeline/cli.h
 create mode 100644 examples/ip_pipeline/conn.c
 create mode 100644 examples/ip_pipeline/conn.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index 981c4f7..0c5b6b1 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -5,7 +5,9 @@
 APP = ip_pipeline
 
 # all source are stored in SRCS-y
-SRCS-y := main.c
+SRCS-y := cli.c
+SRCS-y += conn.c
+SRCS-y += main.c
 SRCS-y += parser.c
 #SRCS-y += thread.c
 
diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
new file mode 100644
index 0000000..3e97b29
--- /dev/null
+++ b/examples/ip_pipeline/cli.c
@@ -0,0 +1,85 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <rte_common.h>
+
+#include "cli.h"
+
+static int
+is_comment(char *in)
+{
+	if ((strlen(in) && index("!#%;", in[0])) ||
+		(strncmp(in, "//", 2) == 0) ||
+		(strncmp(in, "--", 2) == 0))
+		return 1;
+
+	return 0;
+}
+
+void
+cli_process(char *in, char *out __rte_unused, size_t out_size __rte_unused)
+{
+	if (is_comment(in))
+		return;
+
+}
+
+int
+cli_script_process(const char *file_name,
+	size_t msg_in_len_max,
+	size_t msg_out_len_max)
+{
+	char *msg_in = NULL, *msg_out = NULL;
+	FILE *f = NULL;
+
+	/* Check input arguments */
+	if ((file_name == NULL) ||
+		(strlen(file_name) == 0) ||
+		(msg_in_len_max == 0) ||
+		(msg_out_len_max == 0))
+		return -EINVAL;
+
+	msg_in = malloc(msg_in_len_max + 1);
+	msg_out = malloc(msg_out_len_max + 1);
+	if ((msg_in == NULL) ||
+		(msg_out == NULL)) {
+		free(msg_out);
+		free(msg_in);
+		return -ENOMEM;
+	}
+
+	/* Open input file */
+	f = fopen(file_name, "r");
+	if (f == NULL) {
+		free(msg_out);
+		free(msg_in);
+		return -EIO;
+	}
+
+	/* Read file */
+	for ( ; ; ) {
+		if (fgets(msg_in, msg_in_len_max + 1, f) == NULL)
+			break;
+
+		printf("%s", msg_in);
+
+		cli_process(msg_in,
+			msg_out,
+			msg_out_len_max);
+
+		if (strlen(msg_out))
+			printf("%s", msg_out);
+	}
+
+	/* Close file */
+	fclose(f);
+	free(msg_out);
+	free(msg_in);
+	return 0;
+}
diff --git a/examples/ip_pipeline/cli.h b/examples/ip_pipeline/cli.h
new file mode 100644
index 0000000..992e4c3
--- /dev/null
+++ b/examples/ip_pipeline/cli.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#ifndef __INCLUDE_CLI_H__
+#define __INCLUDE_CLI_H__
+
+#include <stddef.h>
+
+void
+cli_process(char *in, char *out, size_t out_size);
+
+int
+cli_script_process(const char *file_name,
+	size_t msg_in_len_max,
+	size_t msg_out_len_max);
+
+#endif
diff --git a/examples/ip_pipeline/conn.c b/examples/ip_pipeline/conn.c
new file mode 100644
index 0000000..2a9fa15
--- /dev/null
+++ b/examples/ip_pipeline/conn.c
@@ -0,0 +1,326 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+#define __USE_GNU
+#include <sys/socket.h>
+
+#include <sys/epoll.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <errno.h>
+
+#include "conn.h"
+
+#define MSG_CMD_TOO_LONG "Command too long."
+
+struct conn {
+	char *welcome;
+	char *prompt;
+	char *buf;
+	char *msg_in;
+	char *msg_out;
+	size_t buf_size;
+	size_t msg_in_len_max;
+	size_t msg_out_len_max;
+	size_t msg_in_len;
+	int fd_server;
+	int fd_client_group;
+	conn_msg_handle_t msg_handle;
+};
+
+struct conn *
+conn_init(struct conn_params *p)
+{
+	struct sockaddr_in server_address;
+	struct conn *conn;
+	int fd_server, fd_client_group, status;
+
+	memset(&server_address, 0, sizeof(server_address));
+
+	/* Check input arguments */
+	if ((p == NULL) ||
+		(p->welcome == NULL) ||
+		(p->prompt == NULL) ||
+		(p->addr == NULL) ||
+		(p->buf_size == 0) ||
+		(p->msg_in_len_max == 0) ||
+		(p->msg_out_len_max == 0) ||
+		(p->msg_handle == NULL))
+		return NULL;
+
+	status = inet_aton(p->addr, &server_address.sin_addr);
+	if (status == 0)
+		return NULL;
+
+	/* Memory allocation */
+	conn = calloc(1, sizeof(struct conn));
+	if (conn == NULL)
+		return NULL;
+
+	conn->welcome = calloc(1, CONN_WELCOME_LEN_MAX + 1);
+	conn->prompt = calloc(1, CONN_PROMPT_LEN_MAX + 1);
+	conn->buf = calloc(1, p->buf_size);
+	conn->msg_in = calloc(1, p->msg_in_len_max + 1);
+	conn->msg_out = calloc(1, p->msg_out_len_max + 1);
+
+	if ((conn->welcome == NULL) ||
+		(conn->prompt == NULL) ||
+		(conn->buf == NULL) ||
+		(conn->msg_in == NULL) ||
+		(conn->msg_out == NULL)) {
+		conn_free(conn);
+		return NULL;
+	}
+
+	/* Server socket */
+	server_address.sin_family = AF_INET;
+	server_address.sin_port = htons(p->port);
+
+	fd_server = socket(AF_INET,
+		SOCK_STREAM | SOCK_NONBLOCK,
+		0);
+	if (fd_server == -1) {
+		conn_free(conn);
+		return NULL;
+	}
+
+	status = bind(fd_server,
+		(struct sockaddr *) &server_address,
+		sizeof(server_address));
+	if (status == -1) {
+		conn_free(conn);
+		return NULL;
+	}
+
+	status = listen(fd_server, 16);
+	if (status == -1) {
+		conn_free(conn);
+		return NULL;
+	}
+
+	/* Client group */
+	fd_client_group = epoll_create(1);
+	if (fd_client_group == -1) {
+		conn_free(conn);
+		return NULL;
+	}
+
+	/* Fill in */
+	strncpy(conn->welcome, p->welcome, CONN_WELCOME_LEN_MAX);
+	strncpy(conn->prompt, p->prompt, CONN_PROMPT_LEN_MAX);
+	conn->buf_size = p->buf_size;
+	conn->msg_in_len_max = p->msg_in_len_max;
+	conn->msg_out_len_max = p->msg_out_len_max;
+	conn->msg_in_len = 0;
+	conn->fd_server = fd_server;
+	conn->fd_client_group = fd_client_group;
+	conn->msg_handle = p->msg_handle;
+
+	return conn;
+}
+
+void
+conn_free(struct conn *conn)
+{
+	if (conn == NULL)
+		return;
+
+	if (conn->fd_client_group)
+		close(conn->fd_client_group);
+
+	if (conn->fd_server)
+		close(conn->fd_server);
+
+	free(conn->msg_out);
+	free(conn->msg_in);
+	free(conn->prompt);
+	free(conn->welcome);
+	free(conn);
+}
+
+int
+conn_poll_for_conn(struct conn *conn)
+{
+	struct sockaddr_in client_address;
+	struct epoll_event event;
+	socklen_t client_address_length;
+	int fd_client, status;
+
+	/* Check input arguments */
+	if (conn == NULL)
+		return -1;
+
+	/* Server socket */
+	client_address_length = sizeof(client_address);
+	fd_client = accept4(conn->fd_server,
+		(struct sockaddr *) &client_address,
+		&client_address_length,
+		SOCK_NONBLOCK);
+	if (fd_client == -1) {
+		if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
+			return 0;
+
+		return -1;
+	}
+
+	/* Client group */
+	event.events = EPOLLIN | EPOLLRDHUP | EPOLLHUP;
+	event.data.fd = fd_client;
+
+	status = epoll_ctl(conn->fd_client_group,
+		EPOLL_CTL_ADD,
+		fd_client,
+		&event);
+	if (status == -1) {
+		close(fd_client);
+		return -1;
+	}
+
+	/* Client */
+	status = write(fd_client,
+		conn->welcome,
+		strlen(conn->welcome));
+	if (status == -1) {
+		close(fd_client);
+		return -1;
+	}
+
+	status = write(fd_client,
+		conn->prompt,
+		strlen(conn->prompt));
+	if (status == -1) {
+		close(fd_client);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+data_event_handle(struct conn *conn,
+	int fd_client)
+{
+	ssize_t len, i, status;
+
+	/* Read input message */
+
+	len = read(fd_client,
+		conn->buf,
+		conn->buf_size);
+	if (len == -1) {
+		if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
+			return 0;
+
+		return -1;
+	}
+	if (len == 0)
+		return 0;
+
+	/* Handle input messages */
+	for (i = 0; i < len; i++) {
+		if (conn->buf[i] == '\n') {
+			size_t n;
+
+			conn->msg_in[conn->msg_in_len] = 0;
+			conn->msg_out[0] = 0;
+
+			conn->msg_handle(conn->msg_in,
+				conn->msg_out,
+				conn->msg_out_len_max);
+
+			n = strlen(conn->msg_out);
+			if (n) {
+				status = write(fd_client,
+					conn->msg_out,
+					n);
+				if (status == -1)
+					return status;
+			}
+
+			conn->msg_in_len = 0;
+		} else if (conn->msg_in_len < conn->msg_in_len_max) {
+			conn->msg_in[conn->msg_in_len] = conn->buf[i];
+			conn->msg_in_len++;
+		} else {
+			status = write(fd_client,
+				MSG_CMD_TOO_LONG,
+				strlen(MSG_CMD_TOO_LONG));
+			if (status == -1)
+				return status;
+
+			conn->msg_in_len = 0;
+		}
+	}
+
+	/* Write prompt */
+	status = write(fd_client,
+		conn->prompt,
+		strlen(conn->prompt));
+	if (status == -1)
+		return status;
+
+	return 0;
+}
+
+static int
+control_event_handle(struct conn *conn,
+	int fd_client)
+{
+	int status;
+
+	status = epoll_ctl(conn->fd_client_group,
+		EPOLL_CTL_DEL,
+		fd_client,
+		NULL);
+	if (status == -1)
+		return -1;
+
+	status = close(fd_client);
+	if (status == -1)
+		return -1;
+
+	return 0;
+}
+
+int
+conn_poll_for_msg(struct conn *conn)
+{
+	struct epoll_event event;
+	int fd_client, status, status_data, status_control;
+
+	/* Check input arguments */
+	if (conn == NULL)
+		return -1;
+
+	/* Client group */
+	status = epoll_wait(conn->fd_client_group,
+		&event,
+		1,
+		0);
+	if (status == -1)
+		return -1;
+	if (status == 0)
+		return 0;
+
+	fd_client = event.data.fd;
+
+	/* Data available */
+	if (event.events & EPOLLIN)
+		status_data = data_event_handle(conn, fd_client);
+
+	/* Control events */
+	if (event.events & (EPOLLRDHUP | EPOLLERR | EPOLLHUP))
+		status_control = control_event_handle(conn, fd_client);
+
+	if (status_data || status_control)
+		return -1;
+
+	return 0;
+}
diff --git a/examples/ip_pipeline/conn.h b/examples/ip_pipeline/conn.h
new file mode 100644
index 0000000..46f9f95
--- /dev/null
+++ b/examples/ip_pipeline/conn.h
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#ifndef __INCLUDE_CONN_H__
+#define __INCLUDE_CONN_H__
+
+#include <stdint.h>
+
+struct conn;
+
+#ifndef CONN_WELCOME_LEN_MAX
+#define CONN_WELCOME_LEN_MAX                               1024
+#endif
+
+#ifndef CONN_PROMPT_LEN_MAX
+#define CONN_PROMPT_LEN_MAX                                16
+#endif
+
+typedef void (*conn_msg_handle_t)(char *msg_in,
+	char *msg_out,
+	size_t msg_out_len_max);
+
+struct conn_params {
+	const char *welcome;
+	const char *prompt;
+	const char *addr;
+	uint16_t port;
+	size_t buf_size;
+	size_t msg_in_len_max;
+	size_t msg_out_len_max;
+	conn_msg_handle_t msg_handle;
+};
+
+struct conn *
+conn_init(struct conn_params *p);
+
+void
+conn_free(struct conn *conn);
+
+int
+conn_poll_for_conn(struct conn *conn);
+
+int
+conn_poll_for_msg(struct conn *conn);
+
+#endif
diff --git a/examples/ip_pipeline/main.c b/examples/ip_pipeline/main.c
index 1696e36..60936f4 100644
--- a/examples/ip_pipeline/main.c
+++ b/examples/ip_pipeline/main.c
@@ -1,5 +1,5 @@
 /* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
+ * Copyright(c) 2010-2018 Intel Corporation
  */
 
 #include <stdio.h>
@@ -10,11 +10,140 @@
 
 #include <rte_eal.h>
 
+#include "cli.h"
+#include "conn.h"
+
+static const char usage[] =
+	"%s EAL_ARGS -- [-h HOST] [-p PORT] [-s SCRIPT]\n";
+
+static const char welcome[] =
+	"\n"
+	"Welcome to IP Pipeline!\n"
+	"\n";
+
+static const char prompt[] = "pipeline> ";
+
+static struct app_params {
+	struct conn_params conn;
+	char *script_name;
+} app = {
+	.conn = {
+		.welcome = welcome,
+		.prompt = prompt,
+		.addr = "0.0.0.0",
+		.port = 8086,
+		.buf_size = 1024 * 1024,
+		.msg_in_len_max = 1024,
+		.msg_out_len_max = 1024 * 1024,
+		.msg_handle = cli_process,
+	},
+	.script_name = NULL,
+};
+
+static int
+parse_args(int argc, char **argv)
+{
+	char *app_name = argv[0];
+	struct option lgopts[] = {
+		{ NULL,  0, 0, 0 }
+	};
+	int opt, option_index;
+	int h_present, p_present, s_present, n_args, i;
+
+	/* Skip EAL input args */
+	n_args = argc;
+	for (i = 0; i < n_args; i++)
+		if (strcmp(argv[i], "--") == 0) {
+			argc -= i;
+			argv += i;
+			break;
+		}
+
+	if (i == n_args)
+		return 0;
+
+	/* Parse args */
+	h_present = 0;
+	p_present = 0;
+	s_present = 0;
+
+	while ((opt = getopt_long(argc, argv, "h:p:s:", lgopts, &option_index))
+			!= EOF)
+		switch (opt) {
+		case 'h':
+			if (h_present) {
+				printf("Error: Multiple -h arguments\n");
+				return -1;
+			}
+			h_present = 1;
+
+			if (!strlen(optarg)) {
+				printf("Error: Argument for -h not provided\n");
+				return -1;
+			}
+
+			app.conn.addr = strdup(optarg);
+			if (app.conn.addr == NULL) {
+				printf("Error: Not enough memory\n");
+				return -1;
+			}
+			break;
+
+		case 'p':
+			if (p_present) {
+				printf("Error: Multiple -p arguments\n");
+				return -1;
+			}
+			p_present = 1;
+
+			if (!strlen(optarg)) {
+				printf("Error: Argument for -p not provided\n");
+				return -1;
+			}
+
+			app.conn.port = (uint16_t) atoi(optarg);
+			break;
+
+		case 's':
+			if (s_present) {
+				printf("Error: Multiple -s arguments\n");
+				return -1;
+			}
+			s_present = 1;
+
+			if (!strlen(optarg)) {
+				printf("Error: Argument for -s not provided\n");
+				return -1;
+			}
+
+			app.script_name = strdup(optarg);
+			if (app.script_name == NULL) {
+				printf("Error: Not enough memory\n");
+				return -1;
+			}
+			break;
+
+		default:
+			printf(usage, app_name);
+			return -1;
+		}
+
+	optind = 1; /* reset getopt lib */
+
+	return 0;
+}
+
 int
 main(int argc, char **argv)
 {
+	struct conn *conn;
 	int status;
 
+	/* Parse application arguments */
+	status = parse_args(argc, argv);
+	if (status < 0)
+		return status;
+
 	/* EAL */
 	status = rte_eal_init(argc, argv);
 	if (status < 0) {
@@ -22,4 +151,24 @@ main(int argc, char **argv)
 		return status;
 	};
 
+	/* Connectivity */
+	conn = conn_init(&app.conn);
+	if (conn == NULL) {
+		printf("Error: Connectivity initialization failed (%d)\n",
+			status);
+		return status;
+	};
+
+	/* Script */
+	if (app.script_name)
+		cli_script_process(app.script_name,
+			app.conn.msg_in_len_max,
+			app.conn.msg_out_len_max);
+
+	/* Dispatch loop */
+	for ( ; ; ) {
+		conn_poll_for_conn(conn);
+
+		conn_poll_for_msg(conn);
+	}
 }
diff --git a/examples/ip_pipeline/meson.build b/examples/ip_pipeline/meson.build
index ea89460..a89cb30 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -1,5 +1,5 @@
 # SPDX-License-Identifier: BSD-3-Clause
-# Copyright(c) 2017 Intel Corporation
+# Copyright(c) 2017-2018 Intel Corporation
 
 # meson file, for building this example as part of a main DPDK build.
 #
@@ -7,8 +7,9 @@
 # DPDK instance, use 'make'
 
 deps += ['pipeline', 'bus_pci']
-includes += include_directories('pipeline')
 sources = files(
+	'cli.c',
+	'conn.c',
 	'main.c',
 	'parser.c',
 )
-- 
2.9.3

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

* [dpdk-dev] [PATCH 12/37] ip_pipeline: add mempool object for pipeline
  2018-03-09 18:23 [dpdk-dev] [PATCH 00/37] ip_pipeline: refactoring Jasvinder Singh
                   ` (10 preceding siblings ...)
  2018-03-09 18:24 ` [dpdk-dev] [PATCH 11/37] ip_pipeline: add cli interface Jasvinder Singh
@ 2018-03-09 18:24 ` Jasvinder Singh
  2018-03-09 18:24 ` [dpdk-dev] [PATCH 13/37] ip_pipeline: add link object Jasvinder Singh
                   ` (24 subsequent siblings)
  36 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-09 18:24 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Fan Zhang

Add mempool object implementation to the application.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Fan Zhang <roy.fan.zhang@intel.com>
---
 examples/ip_pipeline/Makefile    |   1 +
 examples/ip_pipeline/cli.c       | 109 ++++++++++++++++++++++++++++++++++++++-
 examples/ip_pipeline/common.h    |  12 +++++
 examples/ip_pipeline/main.c      |   8 +++
 examples/ip_pipeline/mempool.c   |  81 +++++++++++++++++++++++++++++
 examples/ip_pipeline/mempool.h   |  40 ++++++++++++++
 examples/ip_pipeline/meson.build |   1 +
 7 files changed, 251 insertions(+), 1 deletion(-)
 create mode 100644 examples/ip_pipeline/common.h
 create mode 100644 examples/ip_pipeline/mempool.c
 create mode 100644 examples/ip_pipeline/mempool.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index 0c5b6b1..fca28c5 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -8,6 +8,7 @@ APP = ip_pipeline
 SRCS-y := cli.c
 SRCS-y += conn.c
 SRCS-y += main.c
+SRCS-y += mempool.c
 SRCS-y += parser.c
 #SRCS-y += thread.c
 
diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index 3e97b29..1c67749 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -10,6 +10,23 @@
 #include <rte_common.h>
 
 #include "cli.h"
+#include "mempool.h"
+#include "parser.h"
+
+#ifndef CMD_MAX_TOKENS
+#define CMD_MAX_TOKENS     256
+#endif
+
+#define MSG_OUT_OF_MEMORY  "Not enough memory.\n"
+#define MSG_CMD_UNKNOWN    "Unknown command \"%s\".\n"
+#define MSG_CMD_UNIMPLEM   "Command \"%s\" not implemented.\n"
+#define MSG_ARG_NOT_ENOUGH "Not enough arguments for command \"%s\".\n"
+#define MSG_ARG_TOO_MANY   "Too many arguments for command \"%s\".\n"
+#define MSG_ARG_MISMATCH   "Wrong number of arguments for command \"%s\".\n"
+#define MSG_ARG_NOT_FOUND  "Argument \"%s\" not found.\n"
+#define MSG_ARG_INVALID    "Invalid value for argument \"%s\".\n"
+#define MSG_FILE_ERR       "Error in file \"%s\" at line %u.\n"
+#define MSG_CMD_FAIL       "Command \"%s\" failed.\n"
 
 static int
 is_comment(char *in)
@@ -22,12 +39,102 @@ is_comment(char *in)
 	return 0;
 }
 
+/**
+ * mempool <mempool_name>
+ *  buffer <buffer_size>
+ *  pool <pool_size>
+ * 	cache <cache_size>
+ * 	cpu <cpu_id>
+ */
+static void
+cmd_mempool(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct mempool_params p;
+	char *name;
+	struct mempool *mempool;
+
+	if (n_tokens != 10) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	name = tokens[1];
+
+	if (strcmp(tokens[2], "buffer") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "buffer");
+		return;
+	}
+
+	if (parser_read_uint32(&p.buffer_size, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "buffer_size");
+		return;
+	}
+
+	if (strcmp(tokens[4], "pool") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pool");
+		return;
+	}
+
+	if (parser_read_uint32(&p.pool_size, tokens[5]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "pool_size");
+		return;
+	}
+
+	if (strcmp(tokens[6], "cache") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cache");
+		return;
+	}
+
+	if (parser_read_uint32(&p.cache_size, tokens[7]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "cache_size");
+		return;
+	}
+
+	if (strcmp(tokens[8], "cpu") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu");
+		return;
+	}
+
+	if (parser_read_uint32(&p.cpu_id, tokens[9]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id");
+		return;
+	}
+
+	mempool = mempool_create(name, &p);
+	if (mempool == NULL) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
 void
-cli_process(char *in, char *out __rte_unused, size_t out_size __rte_unused)
+cli_process(char *in, char *out, size_t out_size)
 {
+	char *tokens[CMD_MAX_TOKENS];
+	uint32_t n_tokens = RTE_DIM(tokens);
+	int status;
+
 	if (is_comment(in))
 		return;
 
+	status = parse_tokenize_string(in, tokens, &n_tokens);
+	if (status) {
+		snprintf(out, out_size, MSG_ARG_TOO_MANY, "");
+		return;
+	}
+
+	if (n_tokens == 0)
+		return;
+
+	if (strcmp(tokens[0], "mempool") == 0) {
+		cmd_mempool(tokens, n_tokens, out, out_size);
+		return;
+	}
+
+	snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
 }
 
 int
diff --git a/examples/ip_pipeline/common.h b/examples/ip_pipeline/common.h
new file mode 100644
index 0000000..0886dfb
--- /dev/null
+++ b/examples/ip_pipeline/common.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#ifndef _INCLUDE_COMMON_H_
+#define _INCLUDE_COMMON_H_
+
+#ifndef NAME_SIZE
+#define NAME_SIZE                                            64
+#endif
+
+#endif /* _INCLUDE_COMMON_H_ */
diff --git a/examples/ip_pipeline/main.c b/examples/ip_pipeline/main.c
index 60936f4..b53f623 100644
--- a/examples/ip_pipeline/main.c
+++ b/examples/ip_pipeline/main.c
@@ -12,6 +12,7 @@
 
 #include "cli.h"
 #include "conn.h"
+#include "mempool.h"
 
 static const char usage[] =
 	"%s EAL_ARGS -- [-h HOST] [-p PORT] [-s SCRIPT]\n";
@@ -159,6 +160,13 @@ main(int argc, char **argv)
 		return status;
 	};
 
+	/* Mempool */
+	status = mempool_init();
+	if (status) {
+		printf("Error: Mempool initialization failed (%d)\n", status);
+		return status;
+	}
+
 	/* Script */
 	if (app.script_name)
 		cli_script_process(app.script_name,
diff --git a/examples/ip_pipeline/mempool.c b/examples/ip_pipeline/mempool.c
new file mode 100644
index 0000000..33b9243
--- /dev/null
+++ b/examples/ip_pipeline/mempool.c
@@ -0,0 +1,81 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <rte_mbuf.h>
+
+#include "mempool.h"
+
+#define BUFFER_SIZE_MIN        (sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM)
+
+static struct mempool_list mempool_list;
+
+int
+mempool_init(void)
+{
+	TAILQ_INIT(&mempool_list);
+
+	return 0;
+}
+
+struct mempool *
+mempool_find(const char *name)
+{
+	struct mempool *mempool;
+
+	if (name == NULL)
+		return NULL;
+
+	TAILQ_FOREACH(mempool, &mempool_list, node)
+		if (strcmp(mempool->name, name) == 0)
+			return mempool;
+
+	return NULL;
+}
+
+struct mempool *
+mempool_create(const char *name, struct mempool_params *params)
+{
+	struct mempool *mempool;
+	struct rte_mempool *m;
+
+	/* Check input params */
+	if ((name == NULL) ||
+		mempool_find(name) ||
+		(params == NULL) ||
+		(params->buffer_size < BUFFER_SIZE_MIN) ||
+		(params->pool_size == 0))
+		return NULL;
+
+	/* Resource create */
+	m = rte_pktmbuf_pool_create(
+		name,
+		params->pool_size,
+		params->cache_size,
+		0,
+		params->buffer_size - sizeof(struct rte_mbuf),
+		params->cpu_id);
+
+	if (m == NULL)
+		return NULL;
+
+	/* Node allocation */
+	mempool = calloc(1, sizeof(struct mempool));
+	if (mempool == NULL) {
+		rte_mempool_free(m);
+		return NULL;
+	}
+
+	/* Node fill in */
+	strncpy(mempool->name, name, sizeof(mempool->name));
+	mempool->m = m;
+	mempool->buffer_size = params->buffer_size;
+
+	/* Node add to list */
+	TAILQ_INSERT_TAIL(&mempool_list, mempool, node);
+
+	return mempool;
+}
diff --git a/examples/ip_pipeline/mempool.h b/examples/ip_pipeline/mempool.h
new file mode 100644
index 0000000..bd46a11
--- /dev/null
+++ b/examples/ip_pipeline/mempool.h
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#ifndef _INCLUDE_MEMPOOL_H_
+#define _INCLUDE_MEMPOOL_H_
+
+#include <stdint.h>
+#include <sys/queue.h>
+
+#include <rte_mempool.h>
+
+#include "common.h"
+
+struct mempool {
+	TAILQ_ENTRY(mempool) node;
+	char name[NAME_SIZE];
+	struct rte_mempool *m;
+	uint32_t buffer_size;
+};
+
+TAILQ_HEAD(mempool_list, mempool);
+
+int
+mempool_init(void);
+
+struct mempool *
+mempool_find(const char *name);
+
+struct mempool_params {
+	uint32_t buffer_size;
+	uint32_t pool_size;
+	uint32_t cache_size;
+	uint32_t cpu_id;
+};
+
+struct mempool *
+mempool_create(const char *name, struct mempool_params *params);
+
+#endif /* _INCLUDE_MEMPOOL_H_ */
diff --git a/examples/ip_pipeline/meson.build b/examples/ip_pipeline/meson.build
index a89cb30..f8a450f 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -11,5 +11,6 @@ sources = files(
 	'cli.c',
 	'conn.c',
 	'main.c',
+	'mempool.c',
 	'parser.c',
 )
-- 
2.9.3

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

* [dpdk-dev] [PATCH 13/37] ip_pipeline: add link object
  2018-03-09 18:23 [dpdk-dev] [PATCH 00/37] ip_pipeline: refactoring Jasvinder Singh
                   ` (11 preceding siblings ...)
  2018-03-09 18:24 ` [dpdk-dev] [PATCH 12/37] ip_pipeline: add mempool object for pipeline Jasvinder Singh
@ 2018-03-09 18:24 ` Jasvinder Singh
  2018-03-09 18:24 ` [dpdk-dev] [PATCH 14/37] ip_pipeline: add software queue object Jasvinder Singh
                   ` (23 subsequent siblings)
  36 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-09 18:24 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Fan Zhang

Add link object implementation to the application.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Fan Zhang <roy.fan.zhang@intel.com>
---
 examples/ip_pipeline/Makefile    |   1 +
 examples/ip_pipeline/cli.c       | 122 ++++++++++++++++++
 examples/ip_pipeline/link.c      | 268 +++++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/link.h      |  63 +++++++++
 examples/ip_pipeline/main.c      |   8 ++
 examples/ip_pipeline/meson.build |   1 +
 6 files changed, 463 insertions(+)
 create mode 100644 examples/ip_pipeline/link.c
 create mode 100644 examples/ip_pipeline/link.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index fca28c5..3dab932 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -7,6 +7,7 @@ APP = ip_pipeline
 # all source are stored in SRCS-y
 SRCS-y := cli.c
 SRCS-y += conn.c
+SRCS-y += link.c
 SRCS-y += main.c
 SRCS-y += mempool.c
 SRCS-y += parser.c
diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index 1c67749..385470d 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -10,6 +10,7 @@
 #include <rte_common.h>
 
 #include "cli.h"
+#include "link.h"
 #include "mempool.h"
 #include "parser.h"
 
@@ -110,6 +111,122 @@ cmd_mempool(char **tokens,
 	}
 }
 
+/**
+ * link <link_name>
+ * 	dev <device_name> | port <port_id>
+ * 	rxq <n_queues> <queue_size> <mempool_name>
+ * 	txq <n_queues> <queue_size>
+ * 	promiscuous on | off
+ * 	[rss <qid_0> ... <qid_n>]
+*/
+static void
+cmd_link(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct link_params p;
+	struct link_params_rss rss;
+	struct link *link;
+	char *name;
+
+	if ((n_tokens < 13) || (n_tokens > 14 + LINK_RXQ_RSS_MAX)) {
+	snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+	name = tokens[1];
+
+	if (strcmp(tokens[2], "dev") == 0)
+		p.dev_name = tokens[3];
+	else if (strcmp(tokens[2], "port") == 0) {
+		p.dev_name = NULL;
+
+		if (parser_read_uint16(&p.port_id, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
+			return;
+		}
+	} else {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "dev or port");
+		return;
+	}
+
+	if (strcmp(tokens[4], "rxq") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rxq");
+	return;
+	}
+
+	if (parser_read_uint32(&p.rx.n_queues, tokens[5]) != 0) {
+	snprintf(out, out_size, MSG_ARG_INVALID, "n_queues");
+		return;
+	}
+	if (parser_read_uint32(&p.rx.queue_size, tokens[6]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "queue_size");
+		return;
+}
+
+	p.rx.mempool_name = tokens[7];
+
+	if (strcmp(tokens[8], "txq") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "txq");
+		return;
+	}
+
+	if (parser_read_uint32(&p.tx.n_queues, tokens[9]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "n_queues");
+		return;
+	}
+
+	if (parser_read_uint32(&p.tx.queue_size, tokens[10]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "queue_size");
+		return;
+	}
+
+	if (strcmp(tokens[11], "promiscuous") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "promiscuous");
+		return;
+	}
+
+	if (strcmp(tokens[12], "on") == 0)
+		p.promiscuous = 1;
+	else if (strcmp(tokens[12], "off") == 0)
+		p.promiscuous = 0;
+	else {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "on or off");
+		return;
+	}
+
+	/* RSS */
+	p.rx.rss = NULL;
+	if (n_tokens > 13) {
+		uint32_t queue_id, i;
+
+		if (strcmp(tokens[13], "rss") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rss");
+			return;
+		}
+
+		p.rx.rss = &rss;
+
+		rss.n_queues = 0;
+		for (i = 14; i < n_tokens; i++) {
+			if (parser_read_uint32(&queue_id, tokens[i]) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID,
+					"queue_id");
+				return;
+			}
+
+			rss.queue_id[rss.n_queues] = queue_id;
+			rss.n_queues++;
+		}
+	}
+
+	link = link_create(name, &p);
+	if (link == NULL) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
 void
 cli_process(char *in, char *out, size_t out_size)
 {
@@ -134,6 +251,11 @@ cli_process(char *in, char *out, size_t out_size)
 		return;
 	}
 
+	if (strcmp(tokens[0], "link") == 0) {
+		cmd_link(tokens, n_tokens, out, out_size);
+		return;
+	}
+
 	snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
 }
 
diff --git a/examples/ip_pipeline/link.c b/examples/ip_pipeline/link.c
new file mode 100644
index 0000000..26ff41b
--- /dev/null
+++ b/examples/ip_pipeline/link.c
@@ -0,0 +1,268 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <rte_ethdev.h>
+
+#include "link.h"
+#include "mempool.h"
+
+static struct link_list link_list;
+
+int
+link_init(void)
+{
+	TAILQ_INIT(&link_list);
+
+	return 0;
+}
+
+struct link *
+link_find(const char *name)
+{
+	struct link *link;
+
+	if (name == NULL)
+		return NULL;
+
+	TAILQ_FOREACH(link, &link_list, node)
+		if (strcmp(link->name, name) == 0)
+			return link;
+
+	return NULL;
+}
+
+static struct rte_eth_conf port_conf_default = {
+	.link_speeds = 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   = 1, /* CRC strip by HW */
+		.enable_scatter = 0, /* Scattered packets RX handler */
+
+		.max_rx_pkt_len = 9000, /* Jumbo frame max packet len */
+		.split_hdr_size = 0, /* Header split buffer size */
+	},
+	.rx_adv_conf = {
+		.rss_conf = {
+			.rss_key = NULL,
+			.rss_key_len = 40,
+			.rss_hf = 0,
+		},
+	},
+	.txmode = {
+		.mq_mode = ETH_MQ_TX_NONE,
+	},
+	.lpbk_mode = 0,
+};
+
+#define RETA_CONF_SIZE     (ETH_RSS_RETA_SIZE_512 / RTE_RETA_GROUP_SIZE)
+
+static int
+rss_setup(uint16_t port_id,
+	uint16_t reta_size,
+	struct link_params_rss *rss)
+{
+	struct rte_eth_rss_reta_entry64 reta_conf[RETA_CONF_SIZE];
+	uint32_t i;
+	int status;
+
+	/* RETA setting */
+	memset(reta_conf, 0, sizeof(reta_conf));
+
+	for (i = 0; i < reta_size; i++)
+		reta_conf[i / RTE_RETA_GROUP_SIZE].mask = UINT64_MAX;
+
+	for (i = 0; i < reta_size; i++) {
+		uint32_t reta_id = i / RTE_RETA_GROUP_SIZE;
+		uint32_t reta_pos = i % RTE_RETA_GROUP_SIZE;
+		uint32_t rss_qs_pos = i % rss->n_queues;
+
+		reta_conf[reta_id].reta[reta_pos] =
+			(uint16_t) rss->queue_id[rss_qs_pos];
+	}
+
+	/* RETA update */
+	status = rte_eth_dev_rss_reta_update(port_id,
+		reta_conf,
+		reta_size);
+
+	return status;
+}
+
+struct link *
+link_create(const char *name, struct link_params *params)
+{
+	struct rte_eth_dev_info port_info;
+	struct rte_eth_conf port_conf;
+	struct link *link;
+	struct link_params_rss *rss;
+	struct mempool *mempool;
+	uint32_t cpu_id, i;
+	int status;
+	uint16_t port_id;
+
+	/* Check input params */
+	if ((name == NULL) ||
+		link_find(name) ||
+		(params == NULL) ||
+		(params->rx.n_queues == 0) ||
+		(params->rx.queue_size == 0) ||
+		(params->tx.n_queues == 0) ||
+		(params->tx.queue_size == 0))
+		return NULL;
+
+	port_id = params->port_id;
+	if (params->dev_name) {
+		status = rte_eth_dev_get_port_by_name(params->dev_name,
+			&port_id);
+
+		if (status)
+			return NULL;
+	} else
+		if (!rte_eth_dev_is_valid_port(port_id))
+			return NULL;
+
+	rte_eth_dev_info_get(port_id, &port_info);
+
+	mempool = mempool_find(params->rx.mempool_name);
+	if (mempool == NULL)
+		return NULL;
+
+	rss = params->rx.rss;
+	if (rss) {
+		if ((port_info.reta_size == 0) ||
+			(port_info.reta_size > ETH_RSS_RETA_SIZE_512))
+			return NULL;
+
+		if ((rss->n_queues == 0) ||
+			(rss->n_queues >= LINK_RXQ_RSS_MAX))
+			return NULL;
+
+		for (i = 0; i < rss->n_queues; i++)
+			if (rss->queue_id[i] >= port_info.max_rx_queues)
+				return NULL;
+	}
+
+	/**
+	 * Resource create
+	 */
+	/* Port */
+	memcpy(&port_conf, &port_conf_default, sizeof(port_conf));
+	if (rss) {
+		port_conf.rxmode.mq_mode = ETH_MQ_RX_RSS;
+		port_conf.rx_adv_conf.rss_conf.rss_hf =
+			ETH_RSS_IPV4 | ETH_RSS_IPV6;
+	}
+
+	cpu_id = (uint32_t) rte_eth_dev_socket_id(port_id);
+	if (cpu_id == (uint32_t) SOCKET_ID_ANY)
+		cpu_id = 0;
+
+	status = rte_eth_dev_configure(
+		port_id,
+		params->rx.n_queues,
+		params->tx.n_queues,
+		&port_conf);
+
+	if (status < 0)
+		return NULL;
+
+	if (params->promiscuous)
+		rte_eth_promiscuous_enable(port_id);
+
+	/* Port RX */
+	for (i = 0; i < params->rx.n_queues; i++) {
+		status = rte_eth_rx_queue_setup(
+			port_id,
+			i,
+			params->rx.queue_size,
+			cpu_id,
+			NULL,
+			mempool->m);
+
+		if (status < 0)
+			return NULL;
+	}
+
+	/* Port TX */
+	for (i = 0; i < params->tx.n_queues; i++) {
+		status = rte_eth_tx_queue_setup(
+			port_id,
+			i,
+			params->tx.queue_size,
+			cpu_id,
+			NULL);
+
+		if (status < 0)
+			return NULL;
+	}
+
+	/* Port start */
+	status = rte_eth_dev_start(port_id);
+	if (status < 0)
+		return NULL;
+
+	if (rss) {
+		status = rss_setup(port_id, port_info.reta_size, rss);
+
+		if (status) {
+			rte_eth_dev_stop(port_id);
+			return NULL;
+		}
+	}
+
+	/* Port link up */
+	status = rte_eth_dev_set_link_up(port_id);
+	if ((status < 0) && (status != -ENOTSUP)) {
+		rte_eth_dev_stop(port_id);
+		return NULL;
+	}
+
+	/* Node allocation */
+	link = calloc(1, sizeof(struct link));
+	if (link == NULL) {
+		rte_eth_dev_stop(port_id);
+		return NULL;
+	}
+
+	/* Node fill in */
+	strncpy(link->name, name, sizeof(link->name));
+	link->port_id = port_id;
+	link->n_rxq = params->rx.n_queues;
+	link->n_txq = params->tx.n_queues;
+
+	/* Node add to list */
+	TAILQ_INSERT_TAIL(&link_list, link, node);
+
+	return link;
+}
+
+int
+link_is_up(const char *name)
+{
+	struct rte_eth_link link_params;
+	struct link *link;
+
+	/* Check input params */
+	if (name == NULL)
+		return 0;
+
+	link = link_find(name);
+	if (link == NULL)
+		return 0;
+
+	/* Resource */
+	rte_eth_link_get(link->port_id, &link_params);
+
+	return (link_params.link_status == ETH_LINK_DOWN) ? 0 : 1;
+}
diff --git a/examples/ip_pipeline/link.h b/examples/ip_pipeline/link.h
new file mode 100644
index 0000000..37d3dc4
--- /dev/null
+++ b/examples/ip_pipeline/link.h
@@ -0,0 +1,63 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#ifndef _INCLUDE_LINK_H_
+#define _INCLUDE_LINK_H_
+
+#include <stdint.h>
+#include <sys/queue.h>
+
+#include "common.h"
+
+#ifndef LINK_RXQ_RSS_MAX
+#define LINK_RXQ_RSS_MAX                                   16
+#endif
+
+struct link {
+	TAILQ_ENTRY(link) node;
+	char name[NAME_SIZE];
+	uint16_t port_id;
+	uint32_t n_rxq;
+	uint32_t n_txq;
+};
+
+TAILQ_HEAD(link_list, link);
+
+int
+link_init(void);
+
+struct link *
+link_find(const char *name);
+
+struct link_params_rss {
+	uint32_t queue_id[LINK_RXQ_RSS_MAX];
+	uint32_t n_queues;
+};
+
+struct link_params {
+	const char *dev_name;
+	uint16_t port_id; /**< Valid only when *dev_name* is NULL. */
+
+	struct {
+		uint32_t n_queues;
+		uint32_t queue_size;
+		const char *mempool_name;
+		struct link_params_rss *rss;
+	} rx;
+
+	struct {
+		uint32_t n_queues;
+		uint32_t queue_size;
+	} tx;
+
+	int promiscuous;
+};
+
+struct link *
+link_create(const char *name, struct link_params *params);
+
+int
+link_is_up(const char *name);
+
+#endif /* _INCLUDE_LINK_H_ */
diff --git a/examples/ip_pipeline/main.c b/examples/ip_pipeline/main.c
index b53f623..edfb523 100644
--- a/examples/ip_pipeline/main.c
+++ b/examples/ip_pipeline/main.c
@@ -12,6 +12,7 @@
 
 #include "cli.h"
 #include "conn.h"
+#include "link.h"
 #include "mempool.h"
 
 static const char usage[] =
@@ -167,6 +168,13 @@ main(int argc, char **argv)
 		return status;
 	}
 
+	/* Link */
+	status = link_init();
+	if (status) {
+		printf("Error: Link initialization failed (%d)\n", status);
+		return status;
+	}
+
 	/* Script */
 	if (app.script_name)
 		cli_script_process(app.script_name,
diff --git a/examples/ip_pipeline/meson.build b/examples/ip_pipeline/meson.build
index f8a450f..a2f9bb6 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -10,6 +10,7 @@ deps += ['pipeline', 'bus_pci']
 sources = files(
 	'cli.c',
 	'conn.c',
+	'link.c',
 	'main.c',
 	'mempool.c',
 	'parser.c',
-- 
2.9.3

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

* [dpdk-dev] [PATCH 14/37] ip_pipeline: add software queue object
  2018-03-09 18:23 [dpdk-dev] [PATCH 00/37] ip_pipeline: refactoring Jasvinder Singh
                   ` (12 preceding siblings ...)
  2018-03-09 18:24 ` [dpdk-dev] [PATCH 13/37] ip_pipeline: add link object Jasvinder Singh
@ 2018-03-09 18:24 ` Jasvinder Singh
  2018-03-09 18:24 ` [dpdk-dev] [PATCH 15/37] ip_pipeline: add traffic manager object Jasvinder Singh
                   ` (22 subsequent siblings)
  36 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-09 18:24 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Kevin Laatz

Add swq object implementation to the application.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
---
 examples/ip_pipeline/Makefile    |  1 +
 examples/ip_pipeline/cli.c       | 55 +++++++++++++++++++++++++++++
 examples/ip_pipeline/main.c      |  8 +++++
 examples/ip_pipeline/meson.build |  1 +
 examples/ip_pipeline/swq.c       | 74 ++++++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/swq.h       | 37 ++++++++++++++++++++
 6 files changed, 176 insertions(+)
 create mode 100644 examples/ip_pipeline/swq.c
 create mode 100644 examples/ip_pipeline/swq.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index 3dab932..0dc8442 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -11,6 +11,7 @@ SRCS-y += link.c
 SRCS-y += main.c
 SRCS-y += mempool.c
 SRCS-y += parser.c
+SRCS-y += swq.c
 #SRCS-y += thread.c
 
 # Build using pkg-config variables if possible
diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index 385470d..8e78a40 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -13,6 +13,7 @@
 #include "link.h"
 #include "mempool.h"
 #include "parser.h"
+#include "swq.h"
 
 #ifndef CMD_MAX_TOKENS
 #define CMD_MAX_TOKENS     256
@@ -227,6 +228,55 @@ cmd_link(char **tokens,
 	}
 }
 
+/**
+ * swq <swq_name>
+ * 	size <size>
+ * 	cpu <cpu_id>
+ */
+static void
+cmd_swq(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct swq_params p;
+	char *name;
+	struct swq *swq;
+
+	if (n_tokens != 6) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	name = tokens[1];
+
+	if (strcmp(tokens[2], "size") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
+		return;
+	}
+
+	if (parser_read_uint32(&p.size, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "size");
+		return;
+	}
+
+	if (strcmp(tokens[4], "cpu") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu");
+		return;
+	}
+
+	if (parser_read_uint32(&p.cpu_id, tokens[5]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id");
+		return;
+	}
+
+	swq = swq_create(name, &p);
+	if (swq == NULL) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
 void
 cli_process(char *in, char *out, size_t out_size)
 {
@@ -256,6 +306,11 @@ cli_process(char *in, char *out, size_t out_size)
 		return;
 	}
 
+	if (strcmp(tokens[0], "swq") == 0) {
+		cmd_swq(tokens, n_tokens, out, out_size);
+		return;
+	}
+
 	snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
 }
 
diff --git a/examples/ip_pipeline/main.c b/examples/ip_pipeline/main.c
index edfb523..456f016 100644
--- a/examples/ip_pipeline/main.c
+++ b/examples/ip_pipeline/main.c
@@ -14,6 +14,7 @@
 #include "conn.h"
 #include "link.h"
 #include "mempool.h"
+#include "swq.h"
 
 static const char usage[] =
 	"%s EAL_ARGS -- [-h HOST] [-p PORT] [-s SCRIPT]\n";
@@ -175,6 +176,13 @@ main(int argc, char **argv)
 		return status;
 	}
 
+	/* SWQ */
+	status = swq_init();
+	if (status) {
+		printf("Error: SWQ initialization failed (%d)\n", status);
+		return status;
+	}
+
 	/* Script */
 	if (app.script_name)
 		cli_script_process(app.script_name,
diff --git a/examples/ip_pipeline/meson.build b/examples/ip_pipeline/meson.build
index a2f9bb6..442f3e3 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -14,4 +14,5 @@ sources = files(
 	'main.c',
 	'mempool.c',
 	'parser.c',
+	'swq.c',
 )
diff --git a/examples/ip_pipeline/swq.c b/examples/ip_pipeline/swq.c
new file mode 100644
index 0000000..c11bbf2
--- /dev/null
+++ b/examples/ip_pipeline/swq.c
@@ -0,0 +1,74 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "swq.h"
+
+static struct swq_list swq_list;
+
+int
+swq_init(void)
+{
+	TAILQ_INIT(&swq_list);
+
+	return 0;
+}
+
+struct swq *
+swq_find(const char *name)
+{
+	struct swq *swq;
+
+	if (name == NULL)
+		return NULL;
+
+	TAILQ_FOREACH(swq, &swq_list, node)
+		if (strcmp(swq->name, name) == 0)
+			return swq;
+
+	return NULL;
+}
+
+struct swq *
+swq_create(const char *name, struct swq_params *params)
+{
+	struct swq *swq;
+	struct rte_ring *r;
+	unsigned int flags = RING_F_SP_ENQ | RING_F_SC_DEQ;
+
+	/* Check input params */
+	if ((name == NULL) ||
+		swq_find(name) ||
+		(params == NULL) ||
+		(params->size == 0))
+		return NULL;
+
+	/* Resource create */
+	r = rte_ring_create(
+		name,
+		params->size,
+		params->cpu_id,
+		flags);
+
+	if (r == NULL)
+		return NULL;
+
+	/* Node allocation */
+	swq = calloc(1, sizeof(struct swq));
+	if (swq == NULL) {
+		rte_ring_free(r);
+		return NULL;
+	}
+
+	/* Node fill in */
+	strncpy(swq->name, name, sizeof(swq->name));
+	swq->r = r;
+
+	/* Node add to list */
+	TAILQ_INSERT_TAIL(&swq_list, swq, node);
+
+	return swq;
+}
diff --git a/examples/ip_pipeline/swq.h b/examples/ip_pipeline/swq.h
new file mode 100644
index 0000000..c8440ee
--- /dev/null
+++ b/examples/ip_pipeline/swq.h
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#ifndef _INCLUDE_SWQ_H_
+#define _INCLUDE_SWQ_H_
+
+#include <stdint.h>
+#include <sys/queue.h>
+
+#include <rte_ring.h>
+
+#include "common.h"
+
+struct swq {
+	TAILQ_ENTRY(swq) node;
+	char name[NAME_SIZE];
+	struct rte_ring *r;
+};
+
+TAILQ_HEAD(swq_list, swq);
+
+int
+swq_init(void);
+
+struct swq *
+swq_find(const char *name);
+
+struct swq_params {
+	uint32_t size;
+	uint32_t cpu_id;
+};
+
+struct swq *
+swq_create(const char *name, struct swq_params *params);
+
+#endif /* _INCLUDE_SWQ_H_ */
-- 
2.9.3

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

* [dpdk-dev] [PATCH 15/37] ip_pipeline: add traffic manager object
  2018-03-09 18:23 [dpdk-dev] [PATCH 00/37] ip_pipeline: refactoring Jasvinder Singh
                   ` (13 preceding siblings ...)
  2018-03-09 18:24 ` [dpdk-dev] [PATCH 14/37] ip_pipeline: add software queue object Jasvinder Singh
@ 2018-03-09 18:24 ` Jasvinder Singh
  2018-03-09 18:24 ` [dpdk-dev] [PATCH 16/37] ip_pipeline: add tap object Jasvinder Singh
                   ` (21 subsequent siblings)
  36 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-09 18:24 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add traffic manager object implementation to the application.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/Makefile    |   1 +
 examples/ip_pipeline/cli.c       | 360 +++++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/main.c      |   8 +
 examples/ip_pipeline/meson.build |   1 +
 examples/ip_pipeline/tmgr.c      | 227 ++++++++++++++++++++++++
 examples/ip_pipeline/tmgr.h      |  70 ++++++++
 6 files changed, 667 insertions(+)
 create mode 100644 examples/ip_pipeline/tmgr.c
 create mode 100644 examples/ip_pipeline/tmgr.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index 0dc8442..35e4302 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -12,6 +12,7 @@ SRCS-y += main.c
 SRCS-y += mempool.c
 SRCS-y += parser.c
 SRCS-y += swq.c
+SRCS-y += tmgr.c
 #SRCS-y += thread.c
 
 # Build using pkg-config variables if possible
diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index 8e78a40..99e42c9 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -14,6 +14,7 @@
 #include "mempool.h"
 #include "parser.h"
 #include "swq.h"
+#include "tmgr.h"
 
 #ifndef CMD_MAX_TOKENS
 #define CMD_MAX_TOKENS     256
@@ -277,6 +278,331 @@ cmd_swq(char **tokens,
 	}
 }
 
+/**
+ * tmgr subport profile
+ * 	<tb_rate> <tb_size>
+ * 	<tc0_rate> <tc1_rate> <tc2_rate> <tc3_rate>
+ *	<tc_period>
+ */
+static void
+cmd_tmgr_subport_profile(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct rte_sched_subport_params p;
+	int status, i;
+
+	if (n_tokens != 10) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	if (parser_read_uint32(&p.tb_rate, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "tb_rate");
+		return;
+	}
+
+	if (parser_read_uint32(&p.tb_size, tokens[4]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "tb_size");
+		return;
+	}
+
+	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
+		if (parser_read_uint32(&p.tc_rate[i], tokens[5 + i]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "tc_rate");
+			return;
+		}
+
+	if (parser_read_uint32(&p.tc_period, tokens[9]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "tc_period");
+		return;
+	}
+
+	status = tmgr_subport_profile_add(&p);
+	if (status != 0) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
+ * tmgr pipe profile
+ * 	<tb_rate> <tb_size>
+ * 	<tc0_rate> <tc1_rate> <tc2_rate> <tc3_rate>
+ * 	<tc_period>
+ * 	<tc_ov_weight>
+ * 	<wrr_weight0..15>
+ */
+static void
+cmd_tmgr_pipe_profile(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct rte_sched_pipe_params p;
+	int status, i;
+
+	if (n_tokens != 27) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	if (parser_read_uint32(&p.tb_rate, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "tb_rate");
+		return;
+	}
+
+	if (parser_read_uint32(&p.tb_size, tokens[4]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "tb_size");
+		return;
+	}
+
+	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
+		if (parser_read_uint32(&p.tc_rate[i], tokens[5 + i]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "tc_rate");
+			return;
+		}
+
+	if (parser_read_uint32(&p.tc_period, tokens[9]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "tc_period");
+		return;
+	}
+
+#ifdef RTE_SCHED_SUBPORT_TC_OV
+	if (parser_read_uint32(&p.tc_ov_weight, tokens[10]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "tc_ov_weight");
+		return;
+	}
+#endif
+
+	for (i = 0; i < RTE_SCHED_QUEUES_PER_PIPE; i++)
+		if (parser_read_uint8(&p.wrr_weights[i], tokens[11 + i]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "wrr_weights");
+			return;
+		}
+
+	status = tmgr_pipe_profile_add(&p);
+	if (status != 0) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
+ * tmgr <tmgr_name>
+ * 	rate <rate>
+ * 	spp <n_subports_per_port>
+ * 	pps <n_pipes_per_subport>
+ * 	qsize <qsize_tc0> <qsize_tc1> <qsize_tc2> <qsize_tc3>
+ * 	fo <frame_overhead>
+ * 	mtu <mtu>
+ * 	cpu <cpu_id>
+ */
+static void
+cmd_tmgr(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct tmgr_port_params p;
+	char *name;
+	struct tmgr_port *tmgr_port;
+	int i;
+
+	if (n_tokens != 19) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	name = tokens[1];
+
+	if (strcmp(tokens[2], "rate") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rate");
+		return;
+	}
+
+	if (parser_read_uint32(&p.rate, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "rate");
+		return;
+	}
+
+	if (strcmp(tokens[4], "spp") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "spp");
+		return;
+	}
+
+	if (parser_read_uint32(&p.n_subports_per_port, tokens[5]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "n_subports_per_port");
+		return;
+	}
+
+	if (strcmp(tokens[6], "pps") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pps");
+		return;
+	}
+
+	if (parser_read_uint32(&p.n_pipes_per_subport, tokens[7]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "n_pipes_per_subport");
+		return;
+	}
+
+	if (strcmp(tokens[8], "qsize") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "qsize");
+		return;
+	}
+
+	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
+		if (parser_read_uint16(&p.qsize[i], tokens[9 + i]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "qsize");
+			return;
+		}
+
+	if (strcmp(tokens[13], "fo") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "fo");
+		return;
+	}
+
+	if (parser_read_uint32(&p.frame_overhead, tokens[14]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "frame_overhead");
+		return;
+	}
+
+	if (strcmp(tokens[15], "mtu") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mtu");
+		return;
+	}
+
+	if (parser_read_uint32(&p.mtu, tokens[16]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "mtu");
+		return;
+	}
+
+	if (strcmp(tokens[17], "cpu") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu");
+		return;
+	}
+
+	if (parser_read_uint32(&p.cpu_id, tokens[18]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id");
+		return;
+	}
+
+	tmgr_port = tmgr_port_create(name, &p);
+	if (tmgr_port == NULL) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
+ * tmgr <tmgr_name> subport <subport_id>
+ *	profile <subport_profile_id>
+ */
+static void
+cmd_tmgr_subport(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	uint32_t subport_id, subport_profile_id;
+	int status;
+	char *name;
+
+	if (n_tokens != 6) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	name = tokens[1];
+
+	if (parser_read_uint32(&subport_id, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "subport_id");
+		return;
+	}
+
+	if (parser_read_uint32(&subport_profile_id, tokens[5]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "subport_profile_id");
+		return;
+	}
+
+	status = tmgr_subport_config(name, subport_id, subport_profile_id);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
+ * tmgr <tmgr_name> subport <subport_id> pipe
+ * 	from <pipe_id_first> to <pipe_id_last>
+ * 	profile <pipe_profile_id>
+ */
+static void
+cmd_tmgr_subport_pipe(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	uint32_t subport_id, pipe_id_first, pipe_id_last, pipe_profile_id;
+	int status;
+	char *name;
+
+	if (n_tokens != 11) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	name = tokens[1];
+
+	if (parser_read_uint32(&subport_id, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "subport_id");
+		return;
+	}
+
+	if (strcmp(tokens[4], "pipe") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipe");
+		return;
+	}
+
+	if (strcmp(tokens[5], "from") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "from");
+		return;
+	}
+
+	if (parser_read_uint32(&pipe_id_first, tokens[6]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "pipe_id_first");
+		return;
+	}
+
+	if (strcmp(tokens[7], "to") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "to");
+		return;
+	}
+
+	if (parser_read_uint32(&pipe_id_last, tokens[8]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "pipe_id_last");
+		return;
+	}
+
+	if (strcmp(tokens[9], "profile") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
+		return;
+	}
+
+	if (parser_read_uint32(&pipe_profile_id, tokens[10]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "pipe_profile_id");
+		return;
+	}
+
+	status = tmgr_pipe_config(name, subport_id, pipe_id_first,
+			pipe_id_last, pipe_profile_id);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
 void
 cli_process(char *in, char *out, size_t out_size)
 {
@@ -311,6 +637,40 @@ cli_process(char *in, char *out, size_t out_size)
 		return;
 	}
 
+	if (strcmp(tokens[0], "tmgr") == 0) {
+		if ((n_tokens >= 3) &&
+			(strcmp(tokens[1], "subport") == 0) &&
+			(strcmp(tokens[2], "profile") == 0)) {
+			cmd_tmgr_subport_profile(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
+
+		if ((n_tokens >= 3) &&
+			(strcmp(tokens[1], "pipe") == 0) &&
+			(strcmp(tokens[2], "profile") == 0)) {
+			cmd_tmgr_pipe_profile(tokens, n_tokens, out, out_size);
+			return;
+		}
+
+		if ((n_tokens >= 5) &&
+			(strcmp(tokens[2], "subport") == 0) &&
+			(strcmp(tokens[4], "profile") == 0)) {
+			cmd_tmgr_subport(tokens, n_tokens, out, out_size);
+			return;
+		}
+
+		if ((n_tokens >= 5) &&
+			(strcmp(tokens[2], "subport") == 0) &&
+			(strcmp(tokens[4], "pipe") == 0)) {
+			cmd_tmgr_subport_pipe(tokens, n_tokens, out, out_size);
+			return;
+		}
+
+		cmd_tmgr(tokens, n_tokens, out, out_size);
+		return;
+	}
+
 	snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
 }
 
diff --git a/examples/ip_pipeline/main.c b/examples/ip_pipeline/main.c
index 456f016..490991f 100644
--- a/examples/ip_pipeline/main.c
+++ b/examples/ip_pipeline/main.c
@@ -15,6 +15,7 @@
 #include "link.h"
 #include "mempool.h"
 #include "swq.h"
+#include "tmgr.h"
 
 static const char usage[] =
 	"%s EAL_ARGS -- [-h HOST] [-p PORT] [-s SCRIPT]\n";
@@ -183,6 +184,13 @@ main(int argc, char **argv)
 		return status;
 	}
 
+	/* Traffic Manager */
+	status = tmgr_init();
+	if (status) {
+		printf("Error: TMGR initialization failed (%d)\n", status);
+		return status;
+	}
+
 	/* Script */
 	if (app.script_name)
 		cli_script_process(app.script_name,
diff --git a/examples/ip_pipeline/meson.build b/examples/ip_pipeline/meson.build
index 442f3e3..cb2154c 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -15,4 +15,5 @@ sources = files(
 	'mempool.c',
 	'parser.c',
 	'swq.c',
+	'tmgr.c'
 )
diff --git a/examples/ip_pipeline/tmgr.c b/examples/ip_pipeline/tmgr.c
new file mode 100644
index 0000000..b46ca96
--- /dev/null
+++ b/examples/ip_pipeline/tmgr.c
@@ -0,0 +1,227 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#include <stdlib.h>
+
+#include "tmgr.h"
+
+static struct rte_sched_subport_params
+	subport_profile[TMGR_SUBPORT_PROFILE_MAX];
+
+static uint32_t n_subport_profiles;
+
+static struct rte_sched_pipe_params
+	pipe_profile[TMGR_PIPE_PROFILE_MAX];
+
+static uint32_t n_pipe_profiles;
+
+static struct tmgr_port_list tmgr_port_list;
+
+int
+tmgr_init(void)
+{
+	TAILQ_INIT(&tmgr_port_list);
+
+	return 0;
+}
+
+struct tmgr_port *
+tmgr_port_find(const char *name)
+{
+	struct tmgr_port *tmgr_port;
+
+	if (name == NULL)
+		return NULL;
+
+	TAILQ_FOREACH(tmgr_port, &tmgr_port_list, node)
+		if (strcmp(tmgr_port->name, name) == 0)
+			return tmgr_port;
+
+	return NULL;
+}
+
+int
+tmgr_subport_profile_add(struct rte_sched_subport_params *p)
+{
+	/* Check input params */
+	if (p == NULL)
+		return -1;
+
+	/* Save profile */
+	memcpy(&subport_profile[n_subport_profiles],
+		p,
+		sizeof(*p));
+
+	n_subport_profiles++;
+
+	return 0;
+}
+
+int
+tmgr_pipe_profile_add(struct rte_sched_pipe_params *p)
+{
+	/* Check input params */
+	if (p == NULL)
+		return -1;
+
+	/* Save profile */
+	memcpy(&pipe_profile[n_pipe_profiles],
+		p,
+		sizeof(*p));
+
+	n_pipe_profiles++;
+
+	return 0;
+}
+
+struct tmgr_port *
+tmgr_port_create(const char *name, struct tmgr_port_params *params)
+{
+	struct rte_sched_port_params p;
+	struct tmgr_port *tmgr_port;
+	struct rte_sched_port *s;
+	uint32_t i, j;
+
+	/* Check input params */
+	if ((name == NULL) ||
+		tmgr_port_find(name) ||
+		(params == NULL) ||
+		(params->n_subports_per_port == 0) ||
+		(params->n_pipes_per_subport == 0) ||
+		(params->cpu_id >= RTE_MAX_NUMA_NODES) ||
+		(n_subport_profiles == 0) ||
+		(n_pipe_profiles == 0))
+		return NULL;
+
+	/* Resource create */
+	p.name = name;
+	p.socket = (int) params->cpu_id;
+	p.rate = params->rate;
+	p.mtu = params->mtu;
+	p.frame_overhead = params->frame_overhead;
+	p.n_subports_per_port = params->n_subports_per_port;
+	p.n_pipes_per_subport = params->n_pipes_per_subport;
+
+	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
+		p.qsize[i] = params->qsize[i];
+
+	p.pipe_profiles = pipe_profile;
+	p.n_pipe_profiles = n_pipe_profiles;
+
+	s = rte_sched_port_config(&p);
+	if (s == NULL)
+		return NULL;
+
+	for (i = 0; i < params->n_subports_per_port; i++) {
+		int status;
+
+		status = rte_sched_subport_config(
+			s,
+			i,
+			&subport_profile[0]);
+
+		if (status) {
+			rte_sched_port_free(s);
+			return NULL;
+		}
+
+		for (j = 0; j < params->n_pipes_per_subport; j++) {
+			status = rte_sched_pipe_config(
+				s,
+				i,
+				j,
+				0);
+
+			if (status) {
+				rte_sched_port_free(s);
+				return NULL;
+			}
+		}
+	}
+
+	/* Node allocation */
+	tmgr_port = calloc(1, sizeof(struct tmgr_port));
+	if (tmgr_port == NULL) {
+		rte_sched_port_free(s);
+		return NULL;
+	}
+
+	/* Node fill in */
+	strncpy(tmgr_port->name, name, sizeof(tmgr_port->name));
+	tmgr_port->s = s;
+	tmgr_port->n_subports_per_port = params->n_subports_per_port;
+	tmgr_port->n_pipes_per_subport = params->n_pipes_per_subport;
+
+	/* Node add to list */
+	TAILQ_INSERT_TAIL(&tmgr_port_list, tmgr_port, node);
+
+	return tmgr_port;
+}
+
+int
+tmgr_subport_config(const char *port_name,
+	uint32_t subport_id,
+	uint32_t subport_profile_id)
+{
+	struct tmgr_port *port;
+	int status;
+
+	/* Check input params */
+	if (port_name == NULL)
+		return -1;
+
+	port = tmgr_port_find(port_name);
+	if ((port == NULL) ||
+		(subport_id >= port->n_subports_per_port) ||
+		(subport_profile_id >= n_subport_profiles))
+		return -1;
+
+	/* Resource config */
+	status = rte_sched_subport_config(
+		port->s,
+		subport_id,
+		&subport_profile[subport_profile_id]);
+
+	return status;
+}
+
+int
+tmgr_pipe_config(const char *port_name,
+	uint32_t subport_id,
+	uint32_t pipe_id_first,
+	uint32_t pipe_id_last,
+	uint32_t pipe_profile_id)
+{
+	struct tmgr_port *port;
+	uint32_t i;
+
+	/* Check input params */
+	if (port_name == NULL)
+		return -1;
+
+	port = tmgr_port_find(port_name);
+	if ((port == NULL) ||
+		(subport_id >= port->n_subports_per_port) ||
+		(pipe_id_first >= port->n_pipes_per_subport) ||
+		(pipe_id_last >= port->n_pipes_per_subport) ||
+		(pipe_id_first > pipe_id_last) ||
+		(pipe_profile_id >= n_pipe_profiles))
+		return -1;
+
+	/* Resource config */
+	for (i = pipe_id_first; i <= pipe_id_last; i++) {
+		int status;
+
+		status = rte_sched_pipe_config(
+			port->s,
+			subport_id,
+			i,
+			(int) pipe_profile_id);
+
+		if (status)
+			return status;
+	}
+
+	return 0;
+}
diff --git a/examples/ip_pipeline/tmgr.h b/examples/ip_pipeline/tmgr.h
new file mode 100644
index 0000000..0b497e7
--- /dev/null
+++ b/examples/ip_pipeline/tmgr.h
@@ -0,0 +1,70 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#ifndef _INCLUDE_TMGR_H_
+#define _INCLUDE_TMGR_H_
+
+#include <stdint.h>
+#include <sys/queue.h>
+
+#include <rte_sched.h>
+
+#include "common.h"
+
+#ifndef TMGR_SUBPORT_PROFILE_MAX
+#define TMGR_SUBPORT_PROFILE_MAX                           256
+#endif
+
+#ifndef TMGR_PIPE_PROFILE_MAX
+#define TMGR_PIPE_PROFILE_MAX                              256
+#endif
+
+struct tmgr_port {
+	TAILQ_ENTRY(tmgr_port) node;
+	char name[NAME_SIZE];
+	struct rte_sched_port *s;
+	uint32_t n_subports_per_port;
+	uint32_t n_pipes_per_subport;
+};
+
+TAILQ_HEAD(tmgr_port_list, tmgr_port);
+
+int
+tmgr_init(void);
+
+struct tmgr_port *
+tmgr_port_find(const char *name);
+
+struct tmgr_port_params {
+	uint32_t rate;
+	uint32_t n_subports_per_port;
+	uint32_t n_pipes_per_subport;
+	uint16_t qsize[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
+	uint32_t frame_overhead;
+	uint32_t mtu;
+	uint32_t cpu_id;
+};
+
+int
+tmgr_subport_profile_add(struct rte_sched_subport_params *p);
+
+int
+tmgr_pipe_profile_add(struct rte_sched_pipe_params *p);
+
+struct tmgr_port *
+tmgr_port_create(const char *name, struct tmgr_port_params *params);
+
+int
+tmgr_subport_config(const char *port_name,
+	uint32_t subport_id,
+	uint32_t subport_profile_id);
+
+int
+tmgr_pipe_config(const char *port_name,
+	uint32_t subport_id,
+	uint32_t pipe_id_first,
+	uint32_t pipe_id_last,
+	uint32_t pipe_profile_id);
+
+#endif /* _INCLUDE_TMGR_H_ */
-- 
2.9.3

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

* [dpdk-dev] [PATCH 16/37] ip_pipeline: add tap object
  2018-03-09 18:23 [dpdk-dev] [PATCH 00/37] ip_pipeline: refactoring Jasvinder Singh
                   ` (14 preceding siblings ...)
  2018-03-09 18:24 ` [dpdk-dev] [PATCH 15/37] ip_pipeline: add traffic manager object Jasvinder Singh
@ 2018-03-09 18:24 ` Jasvinder Singh
  2018-03-09 18:24 ` [dpdk-dev] [PATCH 17/37] ip_pipeline: add kni object Jasvinder Singh
                   ` (20 subsequent siblings)
  36 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-09 18:24 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Kevin Laatz

Add tap object implementation to the application

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
---
 examples/ip_pipeline/Makefile    |  1 +
 examples/ip_pipeline/cli.c       | 32 +++++++++++++
 examples/ip_pipeline/main.c      |  8 ++++
 examples/ip_pipeline/meson.build |  1 +
 examples/ip_pipeline/tap.c       | 97 ++++++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/tap.h       | 29 ++++++++++++
 6 files changed, 168 insertions(+)
 create mode 100644 examples/ip_pipeline/tap.c
 create mode 100644 examples/ip_pipeline/tap.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index 35e4302..0f6bb78 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -12,6 +12,7 @@ SRCS-y += main.c
 SRCS-y += mempool.c
 SRCS-y += parser.c
 SRCS-y += swq.c
+SRCS-y += tap.c
 SRCS-y += tmgr.c
 #SRCS-y += thread.c
 
diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index 99e42c9..5dbd576 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -14,6 +14,7 @@
 #include "mempool.h"
 #include "parser.h"
 #include "swq.h"
+#include "tap.h"
 #include "tmgr.h"
 
 #ifndef CMD_MAX_TOKENS
@@ -603,6 +604,32 @@ cmd_tmgr_subport_pipe(char **tokens,
 	}
 }
 
+/**
+ * tap <tap_name>
+ */
+static void
+cmd_tap(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	char *name;
+	struct tap *tap;
+
+	if (n_tokens != 2) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	name = tokens[1];
+
+	tap = tap_create(name);
+	if (tap == NULL) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
 void
 cli_process(char *in, char *out, size_t out_size)
 {
@@ -671,6 +698,11 @@ cli_process(char *in, char *out, size_t out_size)
 		return;
 	}
 
+	if (strcmp(tokens[0], "tap") == 0) {
+		cmd_tap(tokens, n_tokens, out, out_size);
+		return;
+	}
+
 	snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
 }
 
diff --git a/examples/ip_pipeline/main.c b/examples/ip_pipeline/main.c
index 490991f..33c3354 100644
--- a/examples/ip_pipeline/main.c
+++ b/examples/ip_pipeline/main.c
@@ -15,6 +15,7 @@
 #include "link.h"
 #include "mempool.h"
 #include "swq.h"
+#include "tap.h"
 #include "tmgr.h"
 
 static const char usage[] =
@@ -191,6 +192,13 @@ main(int argc, char **argv)
 		return status;
 	}
 
+	/* TAP */
+	status = tap_init();
+	if (status) {
+		printf("Error: TAP initialization failed (%d)\n", status);
+		return status;
+	}
+
 	/* Script */
 	if (app.script_name)
 		cli_script_process(app.script_name,
diff --git a/examples/ip_pipeline/meson.build b/examples/ip_pipeline/meson.build
index cb2154c..e875811 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -15,5 +15,6 @@ sources = files(
 	'mempool.c',
 	'parser.c',
 	'swq.c',
+	'tap.c',
 	'tmgr.c'
 )
diff --git a/examples/ip_pipeline/tap.c b/examples/ip_pipeline/tap.c
new file mode 100644
index 0000000..5b34032
--- /dev/null
+++ b/examples/ip_pipeline/tap.c
@@ -0,0 +1,97 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#include <netinet/in.h>
+#ifdef RTE_EXEC_ENV_LINUXAPP
+#include <linux/if.h>
+#include <linux/if_tun.h>
+#endif
+#include <sys/ioctl.h>
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "tap.h"
+
+#define TAP_DEV                                            "/dev/net/tun"
+
+static struct tap_list tap_list;
+
+int
+tap_init(void)
+{
+	TAILQ_INIT(&tap_list);
+
+	return 0;
+}
+
+struct tap *
+tap_find(const char *name)
+{
+	struct tap *tap;
+
+	if (name == NULL)
+		return NULL;
+
+	TAILQ_FOREACH(tap, &tap_list, node)
+		if (strcmp(tap->name, name) == 0)
+			return tap;
+
+	return NULL;
+}
+
+#ifndef RTE_EXEC_ENV_LINUXAPP
+
+struct tap *
+tap_create(const char *name __rte_unused)
+{
+	return NULL;
+}
+
+#else
+
+struct tap *
+tap_create(const char *name)
+{
+	struct tap *tap;
+	struct ifreq ifr;
+	int fd, status;
+
+	/* Check input params */
+	if ((name == NULL) ||
+		tap_find(name))
+		return NULL;
+
+	/* Resource create */
+	fd = open(TAP_DEV, O_RDWR | O_NONBLOCK);
+	if (fd < 0)
+		return NULL;
+
+	memset(&ifr, 0, sizeof(ifr));
+	ifr.ifr_flags = IFF_TAP | IFF_NO_PI; /* No packet information */
+	snprintf(ifr.ifr_name, IFNAMSIZ, "%s", name);
+
+	status = ioctl(fd, TUNSETIFF, (void *) &ifr);
+	if (status < 0)
+		return NULL;
+
+	/* Node allocation */
+	tap = calloc(1, sizeof(struct tap));
+	if (tap == NULL)
+		return NULL;
+
+	/* Node fill in */
+	strncpy(tap->name, name, sizeof(tap->name));
+	tap->fd = fd;
+
+	/* Node add to list */
+	TAILQ_INSERT_TAIL(&tap_list, tap, node);
+
+	return tap;
+}
+
+#endif
diff --git a/examples/ip_pipeline/tap.h b/examples/ip_pipeline/tap.h
new file mode 100644
index 0000000..0dce72f
--- /dev/null
+++ b/examples/ip_pipeline/tap.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#ifndef _INCLUDE_TAP_H_
+#define _INCLUDE_TAP_H_
+
+#include <sys/queue.h>
+
+#include "common.h"
+
+struct tap {
+	TAILQ_ENTRY(tap) node;
+	char name[NAME_SIZE];
+	int fd;
+};
+
+TAILQ_HEAD(tap_list, tap);
+
+int
+tap_init(void);
+
+struct tap *
+tap_find(const char *name);
+
+struct tap *
+tap_create(const char *name);
+
+#endif /* _INCLUDE_TAP_H_ */
-- 
2.9.3

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

* [dpdk-dev] [PATCH 17/37] ip_pipeline: add kni object
  2018-03-09 18:23 [dpdk-dev] [PATCH 00/37] ip_pipeline: refactoring Jasvinder Singh
                   ` (15 preceding siblings ...)
  2018-03-09 18:24 ` [dpdk-dev] [PATCH 16/37] ip_pipeline: add tap object Jasvinder Singh
@ 2018-03-09 18:24 ` Jasvinder Singh
  2018-03-09 18:24 ` [dpdk-dev] [PATCH 18/37] ip_pipeline: add action profile object Jasvinder Singh
                   ` (19 subsequent siblings)
  36 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-09 18:24 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Kevin Laatz

Add kni object implementation to the application.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
---
 examples/ip_pipeline/Makefile    |   1 +
 examples/ip_pipeline/cli.c       |  65 +++++++++++++++
 examples/ip_pipeline/kni.c       | 165 +++++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/kni.h       |  44 +++++++++++
 examples/ip_pipeline/main.c      |  10 +++
 examples/ip_pipeline/meson.build |   1 +
 6 files changed, 286 insertions(+)
 create mode 100644 examples/ip_pipeline/kni.c
 create mode 100644 examples/ip_pipeline/kni.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index 0f6bb78..dc56ebf 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -7,6 +7,7 @@ APP = ip_pipeline
 # all source are stored in SRCS-y
 SRCS-y := cli.c
 SRCS-y += conn.c
+SRCS-y += kni.c
 SRCS-y += link.c
 SRCS-y += main.c
 SRCS-y += mempool.c
diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index 5dbd576..a5308bc 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -10,6 +10,7 @@
 #include <rte_common.h>
 
 #include "cli.h"
+#include "kni.h"
 #include "link.h"
 #include "mempool.h"
 #include "parser.h"
@@ -630,6 +631,65 @@ cmd_tap(char **tokens,
 	}
 }
 
+/**
+ * kni <kni_name>
+ * 	link <link_name>
+ *	mempool <mempool_name>
+ * 	[thread <thread_id>]
+ */
+static void
+cmd_kni(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct kni_params p;
+	char *name;
+	struct kni *kni;
+
+	if ((n_tokens != 6) && (n_tokens != 8)) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	name = tokens[1];
+
+	if (strcmp(tokens[2], "link") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "link");
+		return;
+	}
+
+	p.link_name = tokens[3];
+
+	if (strcmp(tokens[4], "mempool") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mempool");
+		return;
+	}
+
+	p.mempool_name = tokens[5];
+
+	if (n_tokens == 8) {
+		if (strcmp(tokens[6], "thread") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "thread");
+			return;
+		}
+
+		if (parser_read_uint32(&p.thread_id, tokens[7]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
+			return;
+		}
+
+		p.force_bind = 1;
+	} else
+		p.force_bind = 0;
+
+	kni = kni_create(name, &p);
+	if (kni == NULL) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
 void
 cli_process(char *in, char *out, size_t out_size)
 {
@@ -703,6 +763,11 @@ cli_process(char *in, char *out, size_t out_size)
 		return;
 	}
 
+	if (strcmp(tokens[0], "kni") == 0) {
+		cmd_kni(tokens, n_tokens, out, out_size);
+		return;
+	}
+
 	snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
 }
 
diff --git a/examples/ip_pipeline/kni.c b/examples/ip_pipeline/kni.c
new file mode 100644
index 0000000..8a14aca
--- /dev/null
+++ b/examples/ip_pipeline/kni.c
@@ -0,0 +1,165 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <rte_ethdev.h>
+#include <rte_bus_pci.h>
+
+#include "kni.h"
+#include "mempool.h"
+#include "link.h"
+
+static struct kni_list kni_list;
+
+#ifndef KNI_MAX
+#define KNI_MAX                                            16
+#endif
+
+int
+kni_init(void)
+{
+	TAILQ_INIT(&kni_list);
+
+#ifdef RTE_LIBRTE_KNI
+	rte_kni_init(KNI_MAX);
+#endif
+
+	return 0;
+}
+
+struct kni *
+kni_find(const char *name)
+{
+	struct kni *kni;
+
+	if (name == NULL)
+		return NULL;
+
+	TAILQ_FOREACH(kni, &kni_list, node)
+		if (strcmp(kni->name, name) == 0)
+			return kni;
+
+	return NULL;
+}
+
+#ifndef RTE_LIBRTE_KNI
+
+struct kni *
+kni_create(const char *name __rte_unused,
+	struct kni_params *params __rte_unused)
+{
+	return NULL;
+}
+
+void
+kni_handle_request(void)
+{
+	return 0;
+}
+
+#else
+
+static int
+kni_config_network_interface(uint16_t port_id, uint8_t if_up) {
+	int ret = 0;
+
+	if (port_id >= rte_eth_dev_count())
+		return -EINVAL;
+
+	ret = (if_up) ?
+		rte_eth_dev_set_link_up(port_id) :
+		rte_eth_dev_set_link_down(port_id);
+
+	return ret;
+}
+
+static int
+kni_change_mtu(uint16_t port_id, unsigned int new_mtu) {
+	int ret;
+
+	if (port_id >= rte_eth_dev_count())
+		return -EINVAL;
+
+	if (new_mtu > ETHER_MAX_LEN)
+		return -EINVAL;
+
+	/* Set new MTU */
+	ret = rte_eth_dev_set_mtu(port_id, new_mtu);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+struct kni *
+kni_create(const char *name, struct kni_params *params)
+{
+	struct rte_eth_dev_info dev_info;
+	struct rte_kni_conf kni_conf;
+	struct rte_kni_ops kni_ops;
+	struct kni *kni;
+	struct mempool *mempool;
+	struct link *link;
+	struct rte_kni *k;
+
+	/* Check input params */
+	if ((name == NULL) ||
+		kni_find(name) ||
+		(params == NULL))
+		return NULL;
+
+	mempool = mempool_find(params->mempool_name);
+	link = link_find(params->link_name);
+	if ((mempool == NULL) ||
+		(link == NULL))
+		return NULL;
+
+	/* Resource create */
+	rte_eth_dev_info_get(link->port_id, &dev_info);
+
+	memset(&kni_conf, 0, sizeof(kni_conf));
+	snprintf(kni_conf.name, RTE_KNI_NAMESIZE, "%s", name);
+	kni_conf.force_bind = params->force_bind;
+	kni_conf.core_id = params->thread_id;
+	kni_conf.group_id = link->port_id;
+	kni_conf.mbuf_size = mempool->buffer_size;
+	kni_conf.addr = dev_info.pci_dev->addr;
+	kni_conf.id = dev_info.pci_dev->id;
+
+	memset(&kni_ops, 0, sizeof(kni_ops));
+	kni_ops.port_id = link->port_id;
+	kni_ops.config_network_if = kni_config_network_interface;
+	kni_ops.change_mtu = kni_change_mtu;
+
+	k = rte_kni_alloc(mempool->m, &kni_conf, &kni_ops);
+	if (k == NULL)
+		return NULL;
+
+	/* Node allocation */
+	kni = calloc(1, sizeof(struct kni));
+	if (kni == NULL)
+		return NULL;
+
+	/* Node fill in */
+	strncpy(kni->name, name, sizeof(kni->name));
+	kni->k = k;
+
+	/* Node add to list */
+	TAILQ_INSERT_TAIL(&kni_list, kni, node);
+
+	return kni;
+}
+
+void
+kni_handle_request(void)
+{
+	struct kni *kni;
+
+	TAILQ_FOREACH(kni, &kni_list, node)
+		rte_kni_handle_request(kni->k);
+}
+
+#endif
diff --git a/examples/ip_pipeline/kni.h b/examples/ip_pipeline/kni.h
new file mode 100644
index 0000000..e53de12
--- /dev/null
+++ b/examples/ip_pipeline/kni.h
@@ -0,0 +1,44 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#ifndef _INCLUDE_KNI_H_
+#define _INCLUDE_KNI_H_
+
+#include <stdint.h>
+#include <sys/queue.h>
+
+#ifdef RTE_LIBRTE_KNI
+#include <rte_kni.h>
+#endif
+
+#include "common.h"
+
+struct kni {
+	TAILQ_ENTRY(kni) node;
+	char name[NAME_SIZE];
+	struct rte_kni *k;
+};
+
+TAILQ_HEAD(kni_list, kni);
+
+int
+kni_init(void);
+
+struct kni *
+kni_find(const char *name);
+
+struct kni_params {
+	const char *link_name;
+	const char *mempool_name;
+	int force_bind;
+	uint32_t thread_id;
+};
+
+struct kni *
+kni_create(const char *name, struct kni_params *params);
+
+void
+kni_handle_request(void);
+
+#endif /* _INCLUDE_KNI_H_ */
diff --git a/examples/ip_pipeline/main.c b/examples/ip_pipeline/main.c
index 33c3354..b65762e 100644
--- a/examples/ip_pipeline/main.c
+++ b/examples/ip_pipeline/main.c
@@ -12,6 +12,7 @@
 
 #include "cli.h"
 #include "conn.h"
+#include "kni.h"
 #include "link.h"
 #include "mempool.h"
 #include "swq.h"
@@ -199,6 +200,13 @@ main(int argc, char **argv)
 		return status;
 	}
 
+	/* KNI */
+	status = kni_init();
+	if (status) {
+		printf("Error: KNI initialization failed (%d)\n", status);
+		return status;
+	}
+
 	/* Script */
 	if (app.script_name)
 		cli_script_process(app.script_name,
@@ -210,5 +218,7 @@ main(int argc, char **argv)
 		conn_poll_for_conn(conn);
 
 		conn_poll_for_msg(conn);
+
+		kni_handle_request();
 	}
 }
diff --git a/examples/ip_pipeline/meson.build b/examples/ip_pipeline/meson.build
index e875811..5ad79b2 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -10,6 +10,7 @@ deps += ['pipeline', 'bus_pci']
 sources = files(
 	'cli.c',
 	'conn.c',
+	'kni.c',
 	'link.c',
 	'main.c',
 	'mempool.c',
-- 
2.9.3

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

* [dpdk-dev] [PATCH 18/37] ip_pipeline: add action profile object
  2018-03-09 18:23 [dpdk-dev] [PATCH 00/37] ip_pipeline: refactoring Jasvinder Singh
                   ` (16 preceding siblings ...)
  2018-03-09 18:24 ` [dpdk-dev] [PATCH 17/37] ip_pipeline: add kni object Jasvinder Singh
@ 2018-03-09 18:24 ` Jasvinder Singh
  2018-03-09 18:24 ` [dpdk-dev] [PATCH 19/37] ip_pipeline: add pipeline object Jasvinder Singh
                   ` (18 subsequent siblings)
  36 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-09 18:24 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Fan Zhang

Add action profile object implementation to the application.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Fan Zhang <roy.fan.zhang@intel.com>
---
 examples/ip_pipeline/Makefile    |   3 +-
 examples/ip_pipeline/cli.c       | 309 +++++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/cli.h       |   2 +
 examples/ip_pipeline/main.c      |   8 +
 examples/ip_pipeline/meson.build |   1 +
 5 files changed, 322 insertions(+), 1 deletion(-)

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index dc56ebf..3d7c288 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -5,7 +5,8 @@
 APP = ip_pipeline
 
 # all source are stored in SRCS-y
-SRCS-y := cli.c
+SRCS-y := action.c
+SRCS-y += cli.c
 SRCS-y += conn.c
 SRCS-y += kni.c
 SRCS-y += link.c
diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index a5308bc..df8445e 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -690,6 +690,310 @@ cmd_kni(char **tokens,
 	}
 }
 
+/**
+ * table action profile <profile_name>
+ * 	ipv4 | ipv6
+ * 	offset <ip_offset>
+ *      fwd
+ * 	[meter srtcm | trtcm
+ * 		tc <n_tc>
+ * 		stats none | pkts | bytes | both]
+ *      [tm spp <n_subports_per_port> pps <n_pipes_per_subport>]
+ * 	[encap ether | vlan | qinq | mpls | pppoe | esp | gre | gtpu]
+ * 	[nat src | dst
+ * 		proto udp | tcp]
+ * 	[ttl drop | fwd
+ *              stats none | pkts]
+ * 	[stats pkts | bytes | both]
+ *      [time]
+ */
+static void
+cmd_table_action_profile(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct table_action_profile_params p;
+	struct table_action_profile *ap;
+	char *name;
+	uint32_t t0;
+
+	memset(&p, 0, sizeof(p));
+
+	if (n_tokens < 8) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	if (strcmp(tokens[1], "action") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "action");
+		return;
+	}
+
+	if (strcmp(tokens[2], "profile") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
+		return;
+	}
+
+	name = tokens[3];
+
+	if (strcmp(tokens[4], "ipv4") == 0)
+		p.common.ip_version = 1;
+	else if (strcmp(tokens[4], "ipv6") == 0)
+		p.common.ip_version = 0;
+	else {
+		snprintf(out, out_size, MSG_ARG_INVALID, "ipv4 or ipv6");
+		return;
+	}
+
+	if (strcmp(tokens[5], "offset") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
+		return;
+	}
+
+	if (parser_read_uint32(&p.common.ip_offset, tokens[6]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "ip_offset");
+		return;
+	}
+
+	if (strcmp(tokens[7], "fwd") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "fwd");
+		return;
+	}
+
+	p.action_mask |= 1LLU << RTE_TABLE_ACTION_FWD;
+
+	t0 = 8;
+	if ((t0 < n_tokens) && (strcmp(tokens[t0], "meter") == 0)) {
+		if (n_tokens < t0 + 6) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"table action profile meter");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 1], "srtcm") == 0)
+			p.mtr.alg = RTE_TABLE_ACTION_METER_SRTCM;
+		else if (strcmp(tokens[t0 + 1], "trtcm") == 0)
+			p.mtr.alg = RTE_TABLE_ACTION_METER_TRTCM;
+		else {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+				"srtcm or trtcm");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 2], "tc") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc");
+			return;
+		}
+
+		if (parser_read_uint32(&p.mtr.n_tc, tokens[t0 + 3]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "n_tc");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 4], "stats") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 5], "none") == 0) {
+			p.mtr.n_packets_enabled = 0;
+			p.mtr.n_bytes_enabled = 0;
+		} else if (strcmp(tokens[t0 + 5], "pkts") == 0) {
+			p.mtr.n_packets_enabled = 1;
+			p.mtr.n_bytes_enabled = 0;
+		} else if (strcmp(tokens[t0 + 5], "bytes") == 0) {
+			p.mtr.n_packets_enabled = 0;
+			p.mtr.n_bytes_enabled = 1;
+		} else if (strcmp(tokens[t0 + 5], "both") == 0) {
+			p.mtr.n_packets_enabled = 1;
+			p.mtr.n_bytes_enabled = 1;
+		} else {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+				"none or pkts or bytes or both");
+			return;
+		}
+
+		p.action_mask |= 1LLU << RTE_TABLE_ACTION_MTR;
+		t0 += 6;
+	} /* meter */
+
+	if ((t0 < n_tokens) && (strcmp(tokens[t0], "tm") == 0)) {
+		if (n_tokens < t0 + 5) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"table action profile tm");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 1], "spp") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "spp");
+			return;
+		}
+
+		if (parser_read_uint32(&p.tm.n_subports_per_port,
+			tokens[t0 + 2]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID,
+				"n_subports_per_port");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 3], "pps") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pps");
+			return;
+		}
+
+		if (parser_read_uint32(&p.tm.n_pipes_per_subport,
+			tokens[t0 + 4]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID,
+				"n_pipes_per_subport");
+			return;
+		}
+
+		p.action_mask |= 1LLU << RTE_TABLE_ACTION_TM;
+		t0 += 5;
+	} /* tm */
+
+	if ((t0 < n_tokens) && (strcmp(tokens[t0], "encap") == 0)) {
+		if (n_tokens < t0 + 2) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"action profile encap");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 1], "ether") == 0)
+			p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_ETHER;
+		else if (strcmp(tokens[t0 + 1], "vlan") == 0)
+			p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_VLAN;
+		else if (strcmp(tokens[t0 + 1], "qinq") == 0)
+			p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_QINQ;
+		else if (strcmp(tokens[t0 + 1], "mpls") == 0)
+			p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_MPLS;
+		else if (strcmp(tokens[t0 + 1], "pppoe") == 0)
+			p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_PPPOE;
+		else {
+			snprintf(out, out_size, MSG_ARG_MISMATCH, "encap");
+			return;
+		}
+
+		p.action_mask |= 1LLU << RTE_TABLE_ACTION_ENCAP;
+		t0 += 2;
+	} /* encap */
+
+	if ((t0 < n_tokens) && (strcmp(tokens[t0], "nat") == 0)) {
+		if (n_tokens < t0 + 4) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"table action profile nat");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 1], "src") == 0)
+			p.nat.source_nat = 1;
+		else if (strcmp(tokens[t0 + 1], "dst") == 0)
+			p.nat.source_nat = 0;
+		else {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+				"src or dst");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 2], "proto") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "proto");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 3], "tcp") == 0)
+			p.nat.proto = 0x06;
+		else if (strcmp(tokens[t0 + 3], "udp") == 0)
+			p.nat.proto = 0x11;
+		else {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+				"tcp or udp");
+			return;
+		}
+
+		p.action_mask |= 1LLU << RTE_TABLE_ACTION_NAT;
+		t0 += 4;
+	} /* nat */
+
+	if ((t0 < n_tokens) && (strcmp(tokens[t0], "ttl") == 0)) {
+		if (n_tokens < t0 + 4) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"table action profile ttl");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 1], "drop") == 0)
+			p.ttl.drop = 1;
+		else if (strcmp(tokens[t0 + 1], "fwd") == 0)
+			p.ttl.drop = 0;
+		else {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+				"drop or fwd");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 2], "stats") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 3], "none") == 0)
+			p.ttl.n_packets_enabled = 0;
+		else if (strcmp(tokens[t0 + 3], "pkts") == 0)
+			p.ttl.n_packets_enabled = 1;
+		else {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+				"none or pkts");
+			return;
+		}
+
+		p.action_mask |= 1LLU << RTE_TABLE_ACTION_TTL;
+		t0 += 4;
+	} /* ttl */
+
+	if ((t0 < n_tokens) && (strcmp(tokens[t0], "stats") == 0)) {
+		if (n_tokens < t0 + 2) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"table action profile stats");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 1], "pkts") == 0) {
+			p.stats.n_packets_enabled = 1;
+			p.stats.n_bytes_enabled = 0;
+		} else if (strcmp(tokens[t0 + 1], "bytes") == 0) {
+			p.stats.n_packets_enabled = 0;
+			p.stats.n_bytes_enabled = 1;
+		} else if (strcmp(tokens[t0 + 1], "both") == 0) {
+			p.stats.n_packets_enabled = 1;
+			p.stats.n_bytes_enabled = 1;
+		} else {
+			snprintf(out, out_size,	MSG_ARG_NOT_FOUND,
+				"pkts or bytes or both");
+			return;
+		}
+
+		p.action_mask |= 1LLU << RTE_TABLE_ACTION_STATS;
+		t0 += 2;
+	} /* stats */
+
+	if ((t0 < n_tokens) && (strcmp(tokens[t0], "time") == 0)) {
+		p.action_mask |= 1LLU << RTE_TABLE_ACTION_TIME;
+		t0 += 1;
+	} /* time */
+
+	if (t0 < n_tokens) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	ap = table_action_profile_create(name, &p);
+	if (ap == NULL) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
 void
 cli_process(char *in, char *out, size_t out_size)
 {
@@ -768,6 +1072,11 @@ cli_process(char *in, char *out, size_t out_size)
 		return;
 	}
 
+	if (strcmp(tokens[0], "action") == 0) {
+		cmd_table_action_profile(tokens, n_tokens, out, out_size);
+		return;
+	}
+
 	snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
 }
 
diff --git a/examples/ip_pipeline/cli.h b/examples/ip_pipeline/cli.h
index 992e4c3..02564a6 100644
--- a/examples/ip_pipeline/cli.h
+++ b/examples/ip_pipeline/cli.h
@@ -7,6 +7,8 @@
 
 #include <stddef.h>
 
+#include "action.h"
+
 void
 cli_process(char *in, char *out, size_t out_size);
 
diff --git a/examples/ip_pipeline/main.c b/examples/ip_pipeline/main.c
index b65762e..24b74cf 100644
--- a/examples/ip_pipeline/main.c
+++ b/examples/ip_pipeline/main.c
@@ -207,6 +207,14 @@ main(int argc, char **argv)
 		return status;
 	}
 
+	/* Action profile */
+	status = table_action_profile_init();
+	if (status) {
+		printf("Error: Action profile initialization failed (%d)\n",
+			status);
+		return status;
+	}
+
 	/* Script */
 	if (app.script_name)
 		cli_script_process(app.script_name,
diff --git a/examples/ip_pipeline/meson.build b/examples/ip_pipeline/meson.build
index 5ad79b2..38a1189 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -8,6 +8,7 @@
 
 deps += ['pipeline', 'bus_pci']
 sources = files(
+	'action.c',
 	'cli.c',
 	'conn.c',
 	'kni.c',
-- 
2.9.3

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

* [dpdk-dev] [PATCH 19/37] ip_pipeline: add pipeline object
  2018-03-09 18:23 [dpdk-dev] [PATCH 00/37] ip_pipeline: refactoring Jasvinder Singh
                   ` (17 preceding siblings ...)
  2018-03-09 18:24 ` [dpdk-dev] [PATCH 18/37] ip_pipeline: add action profile object Jasvinder Singh
@ 2018-03-09 18:24 ` Jasvinder Singh
  2018-03-09 18:24 ` [dpdk-dev] [PATCH 20/37] ip_pipeline: add threads Jasvinder Singh
                   ` (17 subsequent siblings)
  36 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-09 18:24 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add pipeline object implementation to the application.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/Makefile    |   1 +
 examples/ip_pipeline/cli.c       | 786 +++++++++++++++++++++++++++++++++
 examples/ip_pipeline/cli.h       |   2 -
 examples/ip_pipeline/main.c      |   8 +
 examples/ip_pipeline/meson.build |   1 +
 examples/ip_pipeline/pipeline.c  | 930 +++++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/pipeline.h  | 265 +++++++++++
 7 files changed, 1991 insertions(+), 2 deletions(-)
 create mode 100644 examples/ip_pipeline/pipeline.c
 create mode 100644 examples/ip_pipeline/pipeline.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index 3d7c288..b1cfc2d 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -13,6 +13,7 @@ SRCS-y += link.c
 SRCS-y += main.c
 SRCS-y += mempool.c
 SRCS-y += parser.c
+SRCS-y += pipeline.c
 SRCS-y += swq.c
 SRCS-y += tap.c
 SRCS-y += tmgr.c
diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index df8445e..96fc33e 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -14,6 +14,7 @@
 #include "link.h"
 #include "mempool.h"
 #include "parser.h"
+#include "pipeline.h"
 #include "swq.h"
 #include "tap.h"
 #include "tmgr.h"
@@ -994,6 +995,751 @@ cmd_table_action_profile(char **tokens,
 	}
 }
 
+/**
+ * pipeline <pipeline_name>
+ * 	period <timer_period_ms>
+ * 	offset_port_id <offset_port_id>
+ * 	cpu <cpu_id>
+ */
+static void
+cmd_pipeline(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct pipeline_params p;
+	char *name;
+	struct pipeline *pipeline;
+
+	if (n_tokens != 8) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	name = tokens[1];
+
+	if (strcmp(tokens[2], "period") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "period");
+		return;
+	}
+
+	if (parser_read_uint32(&p.timer_period_ms, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "timer_period_ms");
+		return;
+	}
+
+	if (strcmp(tokens[4], "offset_port_id") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset_port_id");
+		return;
+	}
+
+	if (parser_read_uint32(&p.offset_port_id, tokens[5]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "offset_port_id");
+		return;
+	}
+
+	if (strcmp(tokens[6], "cpu") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu");
+		return;
+	}
+
+	if (parser_read_uint32(&p.cpu_id, tokens[7]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id");
+		return;
+	}
+
+	pipeline = pipeline_create(name, &p);
+	if (pipeline == NULL) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
+ * pipeline <pipeline_name> port in
+ * 	bsz <burst_size>
+ * 	link <link_name> rxq <queue_id>
+ * 	| swq <swq_name>
+ * 	| tmgr <tmgr_name>
+ * 	| tap <tap_name> mempool <mempool_name> mtu <mtu>
+ * 	| kni <kni_name>
+ * 	| source <source_name> mempool <mempool_name> file <file_name>
+ *      [disabled]
+ */
+static void
+cmd_pipeline_port_in(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct port_in_params p;
+	char *pipeline_name;
+	uint32_t t0;
+	int enabled, status;
+
+	if (n_tokens < 7) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "port") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
+		return;
+	}
+
+	if (strcmp(tokens[3], "in") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
+		return;
+	}
+
+	if (strcmp(tokens[4], "bsz") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
+		return;
+	}
+
+	if (parser_read_uint32(&p.burst_size, tokens[5]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "burst_size");
+		return;
+	}
+
+	t0 = 6;
+
+	if (strcmp(tokens[t0], "link") == 0) {
+		if (n_tokens < t0 + 4) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline port in link");
+			return;
+		}
+
+		p.type = PORT_IN_RXQ;
+
+		p.dev_name = tokens[t0 + 1];
+
+		if (strcmp(tokens[t0 + 2], "rxq") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rxq");
+			return;
+		}
+
+		if (parser_read_uint16(&p.rxq.queue_id, tokens[t0 + 3]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID,
+				"queue_id");
+			return;
+		}
+		t0 += 4;
+	} else if (strcmp(tokens[t0], "swq") == 0) {
+		if (n_tokens < t0 + 2) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline port in swq");
+			return;
+		}
+
+		p.type = PORT_IN_SWQ;
+
+		p.dev_name = tokens[t0 + 1];
+
+		t0 += 2;
+	} else if (strcmp(tokens[t0], "tmgr") == 0) {
+		if (n_tokens < t0 + 2) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline port in tmgr");
+			return;
+		}
+
+		p.type = PORT_IN_TMGR;
+
+		p.dev_name = tokens[t0 + 1];
+
+		t0 += 2;
+	} else if (strcmp(tokens[t0], "tap") == 0) {
+		if (n_tokens < t0 + 6) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline port in tap");
+			return;
+		}
+
+		p.type = PORT_IN_TAP;
+
+		p.dev_name = tokens[t0 + 1];
+
+		if (strcmp(tokens[t0 + 2], "mempool") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+				"mempool");
+			return;
+		}
+
+		p.tap.mempool_name = tokens[t0 + 3];
+
+		if (strcmp(tokens[t0 + 4], "mtu") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+				"mtu");
+			return;
+		}
+
+		if (parser_read_uint32(&p.tap.mtu, tokens[t0 + 5]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "mtu");
+			return;
+		}
+
+		t0 += 6;
+	} else if (strcmp(tokens[t0], "kni") == 0) {
+		if (n_tokens < t0 + 2) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline port in kni");
+			return;
+		}
+
+		p.type = PORT_IN_KNI;
+
+		p.dev_name = tokens[t0 + 1];
+
+		t0 += 2;
+	} else if (strcmp(tokens[t0], "source") == 0) {
+		if (n_tokens < t0 + 6) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline port in source");
+			return;
+		}
+
+		p.type = PORT_IN_SOURCE;
+
+		p.dev_name = tokens[t0 + 1];
+
+		if (strcmp(tokens[t0 + 2], "mempool") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+				"mempool");
+			return;
+		}
+
+		p.source.mempool_name = tokens[t0 + 3];
+
+		if (strcmp(tokens[t0 + 4], "file") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+				"file");
+			return;
+		}
+
+		p.source.file_name = tokens[t0 + 5];
+
+		p.source.n_bytes_per_pkt = 0;
+
+		t0 += 6;
+	} else {
+		snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
+		return;
+	}
+
+	enabled = 1;
+	if ((n_tokens > t0) &&
+		(strcmp(tokens[t0], "disabled") == 0)) {
+		enabled = 0;
+
+		t0 += 1;
+	}
+
+	if (n_tokens != t0) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	status = pipeline_port_in_create(pipeline_name,
+		&p, enabled);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
+ * pipeline <pipeline_name> port out
+ * 	bsz <burst_size>
+ * 	link <link_name> txq <txq_id>
+ * 	| swq <swq_name>
+ * 	| tmgr <tmgr_name>
+ * 	| tap <tap_name>
+ * 	| kni <kni_name>
+ * 	| sink <sink_name> [file <file_name>]
+ */
+static void
+cmd_pipeline_port_out(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct port_out_params p;
+	char *pipeline_name;
+	int status;
+
+	memset(&p, 0, sizeof(p));
+
+	if (n_tokens < 7) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "port") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
+		return;
+	}
+
+	if (strcmp(tokens[3], "out") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "out");
+		return;
+	}
+
+	if (strcmp(tokens[4], "bsz") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
+		return;
+	}
+
+	if (parser_read_uint32(&p.burst_size, tokens[5]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "burst_size");
+		return;
+	}
+
+	if (strcmp(tokens[6], "link") == 0) {
+		if (n_tokens != 10) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline port out link");
+			return;
+		}
+
+		p.type = PORT_OUT_TXQ;
+
+		p.dev_name = tokens[7];
+
+		if (strcmp(tokens[8], "txq") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "txq");
+			return;
+		}
+
+		if (parser_read_uint16(&p.txq.queue_id, tokens[9]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "queue_id");
+			return;
+		}
+	} else if (strcmp(tokens[6], "swq") == 0) {
+		if (n_tokens != 8) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline port out swq");
+			return;
+		}
+
+		p.type = PORT_OUT_SWQ;
+
+		p.dev_name = tokens[7];
+	} else if (strcmp(tokens[6], "tmgr") == 0) {
+		if (n_tokens != 8) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline port out tmgr");
+			return;
+		}
+
+		p.type = PORT_OUT_TMGR;
+
+		p.dev_name = tokens[7];
+	} else if (strcmp(tokens[6], "tap") == 0) {
+		if (n_tokens != 8) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline port out tap");
+			return;
+		}
+
+		p.type = PORT_OUT_TAP;
+
+		p.dev_name = tokens[7];
+	} else if (strcmp(tokens[6], "kni") == 0) {
+		if (n_tokens != 8) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline port out kni");
+			return;
+		}
+
+		p.type = PORT_OUT_KNI;
+
+		p.dev_name = tokens[7];
+	} else if (strcmp(tokens[6], "sink") == 0) {
+		if ((n_tokens != 8) && (n_tokens != 10)) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline port out sink");
+			return;
+		}
+
+		p.type = PORT_OUT_SINK;
+
+		p.dev_name = tokens[7];
+
+		if (n_tokens == 8)
+			p.sink.file_name = NULL;
+		else {
+			if (strcmp(tokens[8], "file") != 0) {
+				snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+					"file");
+				return;
+			}
+
+			p.sink.file_name = tokens[9];
+		}
+
+		p.sink.max_n_pkts = 0;
+	} else {
+		snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
+		return;
+	}
+
+	status = pipeline_port_out_create(pipeline_name, &p);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
+ * pipeline <pipeline_name> table
+ *      match
+ * 		acl
+ * 			ipv4 | ipv6
+ * 			offset <ip_header_offset>
+ * 			size <n_rules>
+ * 		| array
+ * 			offset <key_offset>
+ * 			size <n_keys>
+ * 		| hash
+ * 			ext | lru
+ * 			key <key_size>
+ * 			mask <key_mask>
+ * 			offset <key_offset>
+ * 			buckets <n_buckets>
+ * 			size <n_keys>
+ * 		| lpm
+ * 			ipv4 | ipv6
+ * 			offset <ip_header_offset>
+ * 			size <n_rules>
+ * 		| stub
+ * 	action <action_profile_name>
+ */
+static void
+cmd_pipeline_table(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	uint8_t key_mask[TABLE_RULE_MATCH_SIZE_MAX];
+	struct table_params p;
+	char *pipeline_name;
+	uint32_t t0;
+	int status;
+
+	if (n_tokens < 5) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "table") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
+		return;
+	}
+
+	if (strcmp(tokens[3], "match") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match");
+		return;
+	}
+
+	t0 = 4;
+	if (strcmp(tokens[t0], "acl") == 0) {
+		if (n_tokens < t0 + 6) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline table acl");
+			return;
+		}
+
+		p.match_type = TABLE_ACL;
+
+		if (strcmp(tokens[t0 + 1], "ipv4") == 0)
+			p.match.acl.ip_version = 1;
+		else if (strcmp(tokens[t0 + 1], "ipv6") == 0)
+			p.match.acl.ip_version = 0;
+		else {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+				"ipv4 or ipv6");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 2], "offset") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
+			return;
+		}
+
+		if (parser_read_uint32(&p.match.acl.ip_header_offset,
+			tokens[t0 + 3]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID,
+				"ip_header_offset");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 4], "size") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
+			return;
+		}
+
+		if (parser_read_uint32(&p.match.acl.n_rules,
+			tokens[t0 + 5]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "n_rules");
+			return;
+		}
+
+		t0 += 6;
+	} else if (strcmp(tokens[t0], "array") == 0) {
+		if (n_tokens < t0 + 5) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline table array");
+			return;
+		}
+
+		p.match_type = TABLE_ARRAY;
+
+		if (strcmp(tokens[t0 + 1], "offset") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
+			return;
+		}
+
+		if (parser_read_uint32(&p.match.array.key_offset,
+			tokens[t0 + 2]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 3], "size") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
+			return;
+		}
+
+		if (parser_read_uint32(&p.match.array.n_keys,
+			tokens[t0 + 4]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "n_keys");
+			return;
+		}
+
+		t0 += 5;
+	} else if (strcmp(tokens[t0], "hash") == 0) {
+		uint32_t key_mask_size = TABLE_RULE_MATCH_SIZE_MAX;
+
+		if (n_tokens < t0 + 12) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline table hash");
+			return;
+		}
+
+		p.match_type = TABLE_HASH;
+
+		if (strcmp(tokens[t0 + 1], "ext") == 0)
+			p.match.hash.extendable_bucket = 1;
+		else if (strcmp(tokens[t0 + 1], "lru") == 0)
+			p.match.hash.extendable_bucket = 0;
+		else {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+				"ext or lru");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 2], "key") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "key");
+			return;
+		}
+
+		if ((parser_read_uint32(&p.match.hash.key_size,
+			tokens[t0 + 3]) != 0) ||
+			(p.match.hash.key_size == 0) ||
+			(p.match.hash.key_size > TABLE_RULE_MATCH_SIZE_MAX)) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "key_size");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 4], "mask") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask");
+			return;
+		}
+
+		if ((parse_hex_string(tokens[t0 + 5],
+			key_mask, &key_mask_size) != 0) ||
+			(key_mask_size != p.match.hash.key_size)) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "key_mask");
+			return;
+		}
+		p.match.hash.key_mask = key_mask;
+
+		if (strcmp(tokens[t0 + 6], "offset") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
+			return;
+		}
+
+		if (parser_read_uint32(&p.match.hash.key_offset,
+			tokens[t0 + 7]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 8], "buckets") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "buckets");
+			return;
+		}
+
+		if (parser_read_uint32(&p.match.hash.n_buckets,
+			tokens[t0 + 9]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "n_buckets");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 10], "size") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
+			return;
+		}
+
+		if (parser_read_uint32(&p.match.hash.n_keys,
+			tokens[t0 + 11]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "n_keys");
+			return;
+		}
+
+		t0 += 12;
+	} else if (strcmp(tokens[t0], "lpm") == 0) {
+		if (n_tokens < t0 + 6) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline table lpm");
+			return;
+		}
+
+		p.match_type = TABLE_LPM;
+
+		if (strcmp(tokens[t0 + 1], "ipv4") == 0)
+			p.match.lpm.key_size = 4;
+		else if (strcmp(tokens[t0 + 1], "ipv6") == 0)
+			p.match.lpm.key_size = 16;
+		else {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+				"ipv4 or ipv6");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 2], "offset") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
+			return;
+		}
+
+		if (parser_read_uint32(&p.match.lpm.key_offset,
+			tokens[t0 + 3]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 4], "size") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
+			return;
+		}
+
+		if (parser_read_uint32(&p.match.lpm.n_rules,
+			tokens[t0 + 5]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "n_rules");
+			return;
+		}
+
+		t0 += 6;
+	} else if (strcmp(tokens[t0], "stub") == 0) {
+		if (n_tokens < t0 + 1) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline table stub");
+			return;
+		}
+
+		p.match_type = TABLE_STUB;
+
+		t0 += 1;
+	} else {
+		snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
+		return;
+	}
+
+	if (n_tokens >= t0 + 2) {
+		if (strcmp(tokens[t0], "action") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "action");
+			return;
+		}
+
+		p.action_profile_name = tokens[t0 + 1];
+
+		t0 += 2;
+	}
+
+	if (n_tokens > t0) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	status = pipeline_table_create(pipeline_name, &p);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
+ * pipeline <pipeline_name> port in <port_id> table <table_id>
+ */
+static void
+cmd_pipeline_port_in_table(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	char *pipeline_name;
+	uint32_t port_id, table_id;
+	int status;
+
+	if (n_tokens != 7) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "port") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
+		return;
+	}
+
+	if (strcmp(tokens[3], "in") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
+		return;
+	}
+
+	if (parser_read_uint32(&port_id, tokens[4]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
+		return;
+	}
+
+	if (strcmp(tokens[5], "table") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
+		return;
+	}
+
+	if (parser_read_uint32(&table_id, tokens[6]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
+		return;
+	}
+
+	status = pipeline_port_in_connect_to_table(pipeline_name,
+		port_id,
+		table_id);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
 void
 cli_process(char *in, char *out, size_t out_size)
 {
@@ -1077,6 +1823,46 @@ cli_process(char *in, char *out, size_t out_size)
 		return;
 	}
 
+	if (strcmp(tokens[0], "pipeline") == 0) {
+		if ((n_tokens >= 3) &&
+			(strcmp(tokens[2], "period") == 0)) {
+			cmd_pipeline(tokens, n_tokens, out, out_size);
+			return;
+		}
+
+		if ((n_tokens >= 5) &&
+			(strcmp(tokens[2], "port") == 0) &&
+			(strcmp(tokens[3], "in") == 0) &&
+			(strcmp(tokens[4], "bsz") == 0)) {
+			cmd_pipeline_port_in(tokens, n_tokens, out, out_size);
+			return;
+		}
+
+		if ((n_tokens >= 5) &&
+			(strcmp(tokens[2], "port") == 0) &&
+			(strcmp(tokens[3], "out") == 0) &&
+			(strcmp(tokens[4], "bsz") == 0)) {
+			cmd_pipeline_port_out(tokens, n_tokens, out, out_size);
+			return;
+		}
+
+		if ((n_tokens >= 4) &&
+			(strcmp(tokens[2], "table") == 0) &&
+			(strcmp(tokens[3], "match") == 0)) {
+			cmd_pipeline_table(tokens, n_tokens, out, out_size);
+			return;
+		}
+
+		if ((n_tokens >= 6) &&
+			(strcmp(tokens[2], "port") == 0) &&
+			(strcmp(tokens[3], "in") == 0) &&
+			(strcmp(tokens[5], "table") == 0)) {
+			cmd_pipeline_port_in_table(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
+	}
+
 	snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
 }
 
diff --git a/examples/ip_pipeline/cli.h b/examples/ip_pipeline/cli.h
index 02564a6..992e4c3 100644
--- a/examples/ip_pipeline/cli.h
+++ b/examples/ip_pipeline/cli.h
@@ -7,8 +7,6 @@
 
 #include <stddef.h>
 
-#include "action.h"
-
 void
 cli_process(char *in, char *out, size_t out_size);
 
diff --git a/examples/ip_pipeline/main.c b/examples/ip_pipeline/main.c
index 24b74cf..a7f4486 100644
--- a/examples/ip_pipeline/main.c
+++ b/examples/ip_pipeline/main.c
@@ -15,6 +15,7 @@
 #include "kni.h"
 #include "link.h"
 #include "mempool.h"
+#include "pipeline.h"
 #include "swq.h"
 #include "tap.h"
 #include "tmgr.h"
@@ -215,6 +216,13 @@ main(int argc, char **argv)
 		return status;
 	}
 
+	/* Pipeline */
+	status = pipeline_init();
+	if (status) {
+		printf("Error: Pipeline initialization failed (%d)\n", status);
+		return status;
+	}
+
 	/* Script */
 	if (app.script_name)
 		cli_script_process(app.script_name,
diff --git a/examples/ip_pipeline/meson.build b/examples/ip_pipeline/meson.build
index 38a1189..ea6c704 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -16,6 +16,7 @@ sources = files(
 	'main.c',
 	'mempool.c',
 	'parser.c',
+	'pipeline.c',
 	'swq.c',
 	'tap.c',
 	'tmgr.c'
diff --git a/examples/ip_pipeline/pipeline.c b/examples/ip_pipeline/pipeline.c
new file mode 100644
index 0000000..8efc70d
--- /dev/null
+++ b/examples/ip_pipeline/pipeline.c
@@ -0,0 +1,930 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <rte_common.h>
+#include <rte_ip.h>
+#include <rte_tcp.h>
+
+#include <rte_port_ethdev.h>
+#include <rte_port_kni.h>
+#include <rte_port_ring.h>
+#include <rte_port_source_sink.h>
+#include <rte_port_fd.h>
+#include <rte_port_sched.h>
+
+#include <rte_table_acl.h>
+#include <rte_table_array.h>
+#include <rte_table_hash.h>
+#include <rte_table_lpm.h>
+#include <rte_table_lpm_ipv6.h>
+#include <rte_table_stub.h>
+
+#include "kni.h"
+#include "link.h"
+#include "mempool.h"
+#include "pipeline.h"
+#include "tap.h"
+#include "tmgr.h"
+#include "swq.h"
+
+#include "hash_func.h"
+
+#ifndef PIPELINE_MSGQ_SIZE
+#define PIPELINE_MSGQ_SIZE                                 64
+#endif
+
+#ifndef TABLE_LPM_NUMBER_TBL8
+#define TABLE_LPM_NUMBER_TBL8                              256
+#endif
+
+static struct pipeline_list pipeline_list;
+
+int
+pipeline_init(void)
+{
+	TAILQ_INIT(&pipeline_list);
+
+	return 0;
+}
+
+struct pipeline *
+pipeline_find(const char *name)
+{
+	struct pipeline *pipeline;
+
+	if (name == NULL)
+		return NULL;
+
+	TAILQ_FOREACH(pipeline, &pipeline_list, node)
+		if (strcmp(name, pipeline->name) == 0)
+			return pipeline;
+
+	return NULL;
+}
+
+struct pipeline *
+pipeline_create(const char *name, struct pipeline_params *params)
+{
+	char msgq_name[NAME_MAX];
+	struct rte_pipeline_params pp;
+	struct pipeline *pipeline;
+	struct rte_pipeline *p;
+	struct rte_ring *msgq_req;
+	struct rte_ring *msgq_rsp;
+
+	/* Check input params */
+	if ((name == NULL) ||
+		pipeline_find(name) ||
+		(params == NULL) ||
+		(params->timer_period_ms == 0))
+		return NULL;
+
+	/* Resource create */
+	snprintf(msgq_name, sizeof(msgq_name), "%s-MSGQ-REQ", name);
+
+	msgq_req = rte_ring_create(msgq_name,
+		PIPELINE_MSGQ_SIZE,
+		params->cpu_id,
+		RING_F_SP_ENQ | RING_F_SC_DEQ);
+	if (msgq_req == NULL)
+		return NULL;
+
+	snprintf(msgq_name, sizeof(msgq_name), "%s-MSGQ-RSP", name);
+
+	msgq_rsp = rte_ring_create(msgq_name,
+		PIPELINE_MSGQ_SIZE,
+		params->cpu_id,
+		RING_F_SP_ENQ | RING_F_SC_DEQ);
+	if (msgq_rsp == NULL) {
+		rte_ring_free(msgq_req);
+		return NULL;
+	}
+
+	pp.name = name;
+	pp.socket_id = (int) params->cpu_id;
+	pp.offset_port_id = params->offset_port_id;
+
+	p = rte_pipeline_create(&pp);
+	if (p == NULL) {
+		rte_ring_free(msgq_rsp);
+		rte_ring_free(msgq_req);
+		return NULL;
+	}
+
+	/* Node allocation */
+	pipeline = calloc(1, sizeof(struct pipeline));
+	if (pipeline == NULL) {
+		rte_pipeline_free(p);
+		rte_ring_free(msgq_rsp);
+		rte_ring_free(msgq_req);
+		return NULL;
+	}
+
+	/* Node fill in */
+	strncpy(pipeline->name, name, sizeof(pipeline->name));
+	pipeline->p = p;
+	pipeline->n_ports_in = 0;
+	pipeline->n_ports_out = 0;
+	pipeline->n_tables = 0;
+	pipeline->msgq_req = msgq_req;
+	pipeline->msgq_rsp = msgq_rsp;
+	pipeline->timer_period_ms = params->timer_period_ms;
+	pipeline->enabled = 0;
+	pipeline->cpu_id = params->cpu_id;
+
+	/* Node add to list */
+	TAILQ_INSERT_TAIL(&pipeline_list, pipeline, node);
+
+	return pipeline;
+}
+
+int
+pipeline_port_in_create(const char *pipeline_name,
+	struct port_in_params *params,
+	int enabled)
+{
+	struct rte_pipeline_port_in_params p;
+
+	union {
+		struct rte_port_ethdev_reader_params ethdev;
+		struct rte_port_ring_reader_params ring;
+		struct rte_port_sched_reader_params sched;
+		struct rte_port_fd_reader_params fd;
+		struct rte_port_kni_reader_params kni;
+		struct rte_port_source_params source;
+	} pp;
+
+	struct pipeline *pipeline;
+	uint32_t port_id;
+	int status;
+
+	memset(&pp, 0, sizeof(pp));
+
+	/* Check input params */
+	if ((pipeline_name == NULL) ||
+		(params == NULL) ||
+		(params->burst_size == 0) ||
+		(params->burst_size > RTE_PORT_IN_BURST_SIZE_MAX))
+		return -1;
+
+	pipeline = pipeline_find(pipeline_name);
+	if (pipeline == NULL)
+		return -1;
+
+	switch (params->type) {
+	case PORT_IN_RXQ:
+	{
+		struct link *link;
+
+		link = link_find(params->dev_name);
+		if (link == NULL)
+			return -1;
+
+		if (params->rxq.queue_id >= link->n_rxq)
+			return -1;
+
+		pp.ethdev.port_id = link->port_id;
+		pp.ethdev.queue_id = params->rxq.queue_id;
+
+		p.ops = &rte_port_ethdev_reader_ops;
+		p.arg_create = &pp.ethdev;
+		break;
+	}
+
+	case PORT_IN_SWQ:
+	{
+		struct swq *swq;
+
+		swq = swq_find(params->dev_name);
+		if (swq == NULL)
+			return -1;
+
+		pp.ring.ring = swq->r;
+
+		p.ops = &rte_port_ring_reader_ops;
+		p.arg_create = &pp.ring;
+		break;
+	}
+
+	case PORT_IN_TMGR:
+	{
+		struct tmgr_port *tmgr_port;
+
+		tmgr_port = tmgr_port_find(params->dev_name);
+		if (tmgr_port == NULL)
+			return -1;
+
+		pp.sched.sched = tmgr_port->s;
+
+		p.ops = &rte_port_sched_reader_ops;
+		p.arg_create = &pp.sched;
+		break;
+	}
+
+	case PORT_IN_TAP:
+	{
+		struct tap *tap;
+		struct mempool *mempool;
+
+		tap = tap_find(params->dev_name);
+		mempool = mempool_find(params->tap.mempool_name);
+		if ((tap == NULL) || (mempool == NULL))
+			return -1;
+
+		pp.fd.fd = tap->fd;
+		pp.fd.mempool = mempool->m;
+		pp.fd.mtu = params->tap.mtu;
+
+		p.ops = &rte_port_fd_reader_ops;
+		p.arg_create = &pp.fd;
+		break;
+	}
+
+	case PORT_IN_KNI:
+	{
+		struct kni *kni;
+
+		kni = kni_find(params->dev_name);
+		if (kni == NULL)
+			return -1;
+
+		pp.kni.kni = kni->k;
+
+		p.ops = &rte_port_kni_reader_ops;
+		p.arg_create = &pp.kni;
+		break;
+	}
+
+	case PORT_IN_SOURCE:
+	{
+		struct mempool *mempool;
+
+		mempool = mempool_find(params->source.mempool_name);
+		if (mempool == NULL)
+			return -1;
+
+		pp.source.mempool = mempool->m;
+		pp.source.file_name = params->source.file_name;
+		pp.source.n_bytes_per_pkt = params->source.n_bytes_per_pkt;
+
+		p.ops = &rte_port_source_ops;
+		p.arg_create = &pp.source;
+		break;
+	}
+
+	default:
+		return -1;
+	}
+
+	p.f_action = NULL;
+	p.arg_ah = NULL;
+	p.burst_size = params->burst_size;
+
+	/* Resource create */
+	status = rte_pipeline_port_in_create(pipeline->p,
+		&p,
+		&port_id);
+
+	if (status)
+		return -1;
+
+	if (enabled)
+		rte_pipeline_port_in_enable(pipeline->p, port_id);
+
+	/* Pipeline */
+	pipeline->n_ports_in++;
+
+	return 0;
+}
+
+int
+pipeline_port_in_connect_to_table(const char *pipeline_name,
+	uint32_t port_id,
+	uint32_t table_id)
+{
+	struct pipeline *pipeline;
+	int status;
+
+	/* Check input params */
+	if (pipeline_name == NULL)
+		return -1;
+
+	pipeline = pipeline_find(pipeline_name);
+	if ((pipeline == NULL) ||
+		(port_id >= pipeline->n_ports_in) ||
+		(table_id >= pipeline->n_tables))
+		return -1;
+
+	/* Resource */
+	status = rte_pipeline_port_in_connect_to_table(pipeline->p,
+		port_id,
+		table_id);
+
+	return status;
+
+}
+
+int
+pipeline_port_out_create(const char *pipeline_name,
+	struct port_out_params *params)
+{
+	struct rte_pipeline_port_out_params p;
+
+	union {
+		struct rte_port_ethdev_writer_params ethdev;
+		struct rte_port_ring_writer_params ring;
+		struct rte_port_sched_writer_params sched;
+		struct rte_port_fd_writer_params fd;
+		struct rte_port_kni_writer_params kni;
+		struct rte_port_sink_params sink;
+	} pp;
+
+	union {
+		struct rte_port_ethdev_writer_nodrop_params ethdev;
+		struct rte_port_ring_writer_nodrop_params ring;
+		struct rte_port_fd_writer_nodrop_params fd;
+		struct rte_port_kni_writer_nodrop_params kni;
+	} pp_nodrop;
+
+	struct pipeline *pipeline;
+	uint32_t port_id;
+	int status;
+
+	memset(&pp, 0, sizeof(pp));
+	memset(&pp_nodrop, 0, sizeof(pp_nodrop));
+
+	/* Check input params */
+	if ((pipeline_name == NULL) ||
+		(params == NULL) ||
+		(params->burst_size == 0) ||
+		(params->burst_size > RTE_PORT_IN_BURST_SIZE_MAX))
+		return -1;
+
+	pipeline = pipeline_find(pipeline_name);
+	if (pipeline == NULL)
+		return -1;
+
+	switch (params->type) {
+	case PORT_OUT_TXQ:
+	{
+		struct link *link;
+
+		link = link_find(params->dev_name);
+		if (link == NULL)
+			return -1;
+
+		if (params->txq.queue_id >= link->n_txq)
+			return -1;
+
+		pp.ethdev.port_id = link->port_id;
+		pp.ethdev.queue_id = params->txq.queue_id;
+		pp.ethdev.tx_burst_sz = params->burst_size;
+
+		pp_nodrop.ethdev.port_id = link->port_id;
+		pp_nodrop.ethdev.queue_id = params->txq.queue_id;
+		pp_nodrop.ethdev.tx_burst_sz = params->burst_size;
+		pp_nodrop.ethdev.n_retries = params->n_retries;
+
+		if (params->retry == 0) {
+			p.ops = &rte_port_ethdev_writer_ops;
+			p.arg_create = &pp.ethdev;
+		} else {
+			p.ops = &rte_port_ethdev_writer_nodrop_ops;
+			p.arg_create = &pp_nodrop.ethdev;
+		}
+		break;
+	}
+
+	case PORT_OUT_SWQ:
+	{
+		struct swq *swq;
+
+		swq = swq_find(params->dev_name);
+		if (swq == NULL)
+			return -1;
+
+		pp.ring.ring = swq->r;
+		pp.ring.tx_burst_sz = params->burst_size;
+
+		pp_nodrop.ring.ring = swq->r;
+		pp_nodrop.ring.tx_burst_sz = params->burst_size;
+		pp_nodrop.ring.n_retries = params->n_retries;
+
+		if (params->retry == 0) {
+			p.ops = &rte_port_ring_writer_ops;
+			p.arg_create = &pp.ring;
+		} else {
+			p.ops = &rte_port_ring_writer_nodrop_ops;
+			p.arg_create = &pp_nodrop.ring;
+		}
+		break;
+	}
+
+	case PORT_OUT_TMGR:
+	{
+		struct tmgr_port *tmgr_port;
+
+		tmgr_port = tmgr_port_find(params->dev_name);
+		if (tmgr_port == NULL)
+			return -1;
+
+		pp.sched.sched = tmgr_port->s;
+		pp.sched.tx_burst_sz = params->burst_size;
+
+		p.ops = &rte_port_sched_writer_ops;
+		p.arg_create = &pp.sched;
+		break;
+	}
+
+	case PORT_OUT_TAP:
+	{
+		struct tap *tap;
+
+		tap = tap_find(params->dev_name);
+		if (tap == NULL)
+			return -1;
+
+		pp.fd.fd = tap->fd;
+		pp.fd.tx_burst_sz = params->burst_size;
+
+		pp_nodrop.fd.fd = tap->fd;
+		pp_nodrop.fd.tx_burst_sz = params->burst_size;
+		pp_nodrop.fd.n_retries = params->n_retries;
+
+		if (params->retry == 0) {
+			p.ops = &rte_port_fd_writer_ops;
+			p.arg_create = &pp.fd;
+		} else {
+			p.ops = &rte_port_fd_writer_nodrop_ops;
+			p.arg_create = &pp_nodrop.fd;
+		}
+		break;
+	}
+
+	case PORT_OUT_KNI:
+	{
+		struct kni *kni;
+
+		kni = kni_find(params->dev_name);
+		if (kni == NULL)
+			return -1;
+
+		pp.kni.kni = kni->k;
+		pp.kni.tx_burst_sz = params->burst_size;
+
+		pp_nodrop.kni.kni = kni->k;
+		pp_nodrop.kni.tx_burst_sz = params->burst_size;
+		pp_nodrop.kni.n_retries = params->n_retries;
+
+		if (params->retry == 0) {
+			p.ops = &rte_port_kni_writer_ops;
+			p.arg_create = &pp.kni;
+		} else {
+			p.ops = &rte_port_kni_writer_nodrop_ops;
+			p.arg_create = &pp_nodrop.kni;
+		}
+		break;
+	}
+
+	case PORT_OUT_SINK:
+	{
+		pp.sink.file_name = params->sink.file_name;
+		pp.sink.max_n_pkts = params->sink.max_n_pkts;
+
+		p.ops = &rte_port_sink_ops;
+		p.arg_create = &pp.sink;
+		break;
+	}
+
+	default:
+		return -1;
+	}
+
+	p.f_action = NULL;
+	p.arg_ah = NULL;
+
+	/* Resource create */
+	status = rte_pipeline_port_out_create(pipeline->p,
+		&p,
+		&port_id);
+
+	if (status)
+		return -1;
+
+	/* Pipeline */
+	pipeline->n_ports_out++;
+
+	return 0;
+}
+
+static const struct rte_acl_field_def table_acl_field_format_ipv4[] = {
+	/* Protocol */
+	[0] = {
+		.type = RTE_ACL_FIELD_TYPE_BITMASK,
+		.size = sizeof(uint8_t),
+		.field_index = 0,
+		.input_index = 0,
+		.offset = offsetof(struct ipv4_hdr, next_proto_id),
+	},
+
+	/* Source IP address (IPv4) */
+	[1] = {
+		.type = RTE_ACL_FIELD_TYPE_MASK,
+		.size = sizeof(uint32_t),
+		.field_index = 1,
+		.input_index = 1,
+		.offset = offsetof(struct ipv4_hdr, src_addr),
+	},
+
+	/* Destination IP address (IPv4) */
+	[2] = {
+		.type = RTE_ACL_FIELD_TYPE_MASK,
+		.size = sizeof(uint32_t),
+		.field_index = 2,
+		.input_index = 2,
+		.offset = offsetof(struct ipv4_hdr, dst_addr),
+	},
+
+	/* Source Port */
+	[3] = {
+		.type = RTE_ACL_FIELD_TYPE_RANGE,
+		.size = sizeof(uint16_t),
+		.field_index = 3,
+		.input_index = 3,
+		.offset = sizeof(struct ipv4_hdr) +
+			offsetof(struct tcp_hdr, src_port),
+	},
+
+	/* Destination Port */
+	[4] = {
+		.type = RTE_ACL_FIELD_TYPE_RANGE,
+		.size = sizeof(uint16_t),
+		.field_index = 4,
+		.input_index = 3,
+		.offset = sizeof(struct ipv4_hdr) +
+			offsetof(struct tcp_hdr, dst_port),
+	},
+};
+
+static const struct rte_acl_field_def table_acl_field_format_ipv6[] = {
+	/* Protocol */
+	[0] = {
+		.type = RTE_ACL_FIELD_TYPE_BITMASK,
+		.size = sizeof(uint8_t),
+		.field_index = 0,
+		.input_index = 0,
+		.offset = offsetof(struct ipv6_hdr, proto),
+	},
+
+	/* Source IP address (IPv6) */
+	[1] = {
+		.type = RTE_ACL_FIELD_TYPE_MASK,
+		.size = sizeof(uint32_t),
+		.field_index = 1,
+		.input_index = 1,
+		.offset = offsetof(struct ipv6_hdr, src_addr[0]),
+	},
+
+	[2] = {
+		.type = RTE_ACL_FIELD_TYPE_MASK,
+		.size = sizeof(uint32_t),
+		.field_index = 2,
+		.input_index = 2,
+		.offset = offsetof(struct ipv6_hdr, src_addr[4]),
+	},
+
+	[3] = {
+		.type = RTE_ACL_FIELD_TYPE_MASK,
+		.size = sizeof(uint32_t),
+		.field_index = 3,
+		.input_index = 3,
+		.offset = offsetof(struct ipv6_hdr, src_addr[8]),
+	},
+
+	[4] = {
+		.type = RTE_ACL_FIELD_TYPE_MASK,
+		.size = sizeof(uint32_t),
+		.field_index = 4,
+		.input_index = 4,
+		.offset = offsetof(struct ipv6_hdr, src_addr[12]),
+	},
+
+	/* Destination IP address (IPv6) */
+	[5] = {
+		.type = RTE_ACL_FIELD_TYPE_MASK,
+		.size = sizeof(uint32_t),
+		.field_index = 5,
+		.input_index = 5,
+		.offset = offsetof(struct ipv6_hdr, dst_addr[0]),
+	},
+
+	[6] = {
+		.type = RTE_ACL_FIELD_TYPE_MASK,
+		.size = sizeof(uint32_t),
+		.field_index = 6,
+		.input_index = 6,
+		.offset = offsetof(struct ipv6_hdr, dst_addr[4]),
+	},
+
+	[7] = {
+		.type = RTE_ACL_FIELD_TYPE_MASK,
+		.size = sizeof(uint32_t),
+		.field_index = 7,
+		.input_index = 7,
+		.offset = offsetof(struct ipv6_hdr, dst_addr[8]),
+	},
+
+	[8] = {
+		.type = RTE_ACL_FIELD_TYPE_MASK,
+		.size = sizeof(uint32_t),
+		.field_index = 8,
+		.input_index = 8,
+		.offset = offsetof(struct ipv6_hdr, dst_addr[12]),
+	},
+
+	/* Source Port */
+	[9] = {
+		.type = RTE_ACL_FIELD_TYPE_RANGE,
+		.size = sizeof(uint16_t),
+		.field_index = 9,
+		.input_index = 9,
+		.offset = sizeof(struct ipv6_hdr) +
+			offsetof(struct tcp_hdr, src_port),
+	},
+
+	/* Destination Port */
+	[10] = {
+		.type = RTE_ACL_FIELD_TYPE_RANGE,
+		.size = sizeof(uint16_t),
+		.field_index = 10,
+		.input_index = 9,
+		.offset = sizeof(struct ipv6_hdr) +
+			offsetof(struct tcp_hdr, dst_port),
+	},
+};
+
+int
+pipeline_table_create(const char *pipeline_name,
+	struct table_params *params)
+{
+	char name[NAME_MAX];
+	struct rte_pipeline_table_params p;
+
+	union {
+		struct rte_table_acl_params acl;
+		struct rte_table_array_params array;
+		struct rte_table_hash_params hash;
+		struct rte_table_lpm_params lpm;
+		struct rte_table_lpm_ipv6_params lpm_ipv6;
+	} pp;
+
+	struct pipeline *pipeline;
+	struct table *table;
+	struct table_action_profile *ap;
+	struct rte_table_action *action;
+	uint32_t table_id;
+	int status;
+
+	memset(&p, 0, sizeof(p));
+	memset(&pp, 0, sizeof(pp));
+
+	/* Check input params */
+	if ((pipeline_name == NULL) ||
+		(params == NULL) ||
+		(params->action_profile_name == NULL))
+		return -1;
+
+	pipeline = pipeline_find(pipeline_name);
+	if ((pipeline == NULL) ||
+		(pipeline->n_tables >= PIPELINE_TABLE_MAX))
+		return -1;
+
+	ap = table_action_profile_find(params->action_profile_name);
+	if (ap == NULL)
+		return -1;
+
+	snprintf(name, NAME_MAX, "%s_table%u",
+		pipeline_name, pipeline->n_tables);
+
+	switch (params->match_type) {
+	case TABLE_ACL:
+	{
+		uint32_t ip_header_offset = params->match.acl.ip_header_offset -
+			(sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM);
+		uint32_t i;
+
+		if (params->match.acl.n_rules == 0)
+			return -1;
+
+		pp.acl.name = name;
+		pp.acl.n_rules = params->match.acl.n_rules;
+		if (params->match.acl.ip_version) {
+			memcpy(&pp.acl.field_format,
+				&table_acl_field_format_ipv4,
+				sizeof(table_acl_field_format_ipv4));
+			pp.acl.n_rule_fields =
+				RTE_DIM(table_acl_field_format_ipv4);
+		} else {
+			memcpy(&pp.acl.field_format,
+				&table_acl_field_format_ipv6,
+				sizeof(table_acl_field_format_ipv6));
+			pp.acl.n_rule_fields =
+				RTE_DIM(table_acl_field_format_ipv6);
+		}
+
+		for (i = 0; i < pp.acl.n_rule_fields; i++)
+			pp.acl.field_format[i].offset += ip_header_offset;
+
+		p.ops = &rte_table_acl_ops;
+		p.arg_create = &pp.acl;
+		break;
+	}
+
+	case TABLE_ARRAY:
+	{
+		if (params->match.array.n_keys == 0)
+			return -1;
+
+		pp.array.n_entries = params->match.array.n_keys;
+		pp.array.offset = params->match.array.key_offset;
+
+		p.ops = &rte_table_array_ops;
+		p.arg_create = &pp.array;
+		break;
+	}
+
+	case TABLE_HASH:
+	{
+		struct rte_table_ops *ops;
+		rte_table_hash_op_hash f_hash;
+
+		if (params->match.hash.n_keys == 0)
+			return -1;
+
+		switch (params->match.hash.key_size) {
+		case  8:
+			f_hash = hash_default_key8;
+			break;
+		case 16:
+			f_hash = hash_default_key16;
+			break;
+		case 24:
+			f_hash = hash_default_key24;
+			break;
+		case 32:
+			f_hash = hash_default_key32;
+			break;
+		case 40:
+			f_hash = hash_default_key40;
+			break;
+		case 48:
+			f_hash = hash_default_key48;
+			break;
+		case 56:
+			f_hash = hash_default_key56;
+			break;
+		case 64:
+			f_hash = hash_default_key64;
+			break;
+		default:
+			return -1;
+		}
+
+		pp.hash.name = name;
+		pp.hash.key_size = params->match.hash.key_size;
+		pp.hash.key_offset = params->match.hash.key_offset;
+		pp.hash.key_mask = params->match.hash.key_mask;
+		pp.hash.n_keys = params->match.hash.n_keys;
+		pp.hash.n_buckets = params->match.hash.n_buckets;
+		pp.hash.f_hash = f_hash;
+		pp.hash.seed = 0;
+
+		if (params->match.hash.extendable_bucket)
+			switch (params->match.hash.key_size) {
+			case  8:
+				ops = &rte_table_hash_key8_ext_ops;
+				break;
+			case 16:
+				ops = &rte_table_hash_key16_ext_ops;
+				break;
+			default:
+				ops = &rte_table_hash_ext_ops;
+			}
+		else
+			switch (params->match.hash.key_size) {
+			case  8:
+				ops = &rte_table_hash_key8_lru_ops;
+				break;
+			case 16:
+				ops = &rte_table_hash_key16_lru_ops;
+				break;
+			default:
+				ops = &rte_table_hash_lru_ops;
+			}
+
+		p.ops = ops;
+		p.arg_create = &pp.hash;
+		break;
+	}
+
+	case TABLE_LPM:
+	{
+		if (params->match.lpm.n_rules == 0)
+			return -1;
+
+		switch (params->match.lpm.key_size) {
+		case 4:
+		{
+			pp.lpm.name = name;
+			pp.lpm.n_rules = params->match.lpm.n_rules;
+			pp.lpm.number_tbl8s = TABLE_LPM_NUMBER_TBL8;
+			pp.lpm.flags = 0;
+			pp.lpm.entry_unique_size = p.action_data_size +
+				sizeof(struct rte_pipeline_table_entry);
+			pp.lpm.offset = params->match.lpm.key_offset;
+
+			p.ops = &rte_table_lpm_ops;
+			p.arg_create = &pp.lpm;
+			break;
+		}
+
+		case 16:
+		{
+			pp.lpm_ipv6.name = name;
+			pp.lpm_ipv6.n_rules = params->match.lpm.n_rules;
+			pp.lpm_ipv6.number_tbl8s = TABLE_LPM_NUMBER_TBL8;
+			pp.lpm_ipv6.entry_unique_size = p.action_data_size +
+				sizeof(struct rte_pipeline_table_entry);
+			pp.lpm_ipv6.offset = params->match.lpm.key_offset;
+
+			p.ops = &rte_table_lpm_ipv6_ops;
+			p.arg_create = &pp.lpm_ipv6;
+			break;
+		}
+
+		default:
+			return -1;
+		}
+
+		break;
+	}
+
+	case TABLE_STUB:
+	{
+		p.ops = &rte_table_stub_ops;
+		p.arg_create = NULL;
+		break;
+	}
+
+	default:
+		return -1;
+	}
+
+	/* Resource create */
+	action = rte_table_action_create(ap->ap,
+		pipeline->cpu_id);
+	if (action == NULL)
+		return -1;
+
+	status = rte_table_action_table_params_get(
+		action,
+		&p);
+	if (status ||
+		((p.action_data_size +
+		sizeof(struct rte_pipeline_table_entry)) >
+		TABLE_RULE_ACTION_SIZE_MAX)) {
+		rte_table_action_free(action);
+		return -1;
+	}
+
+	if (params->match_type == TABLE_LPM) {
+		if (params->match.lpm.key_size == 4)
+			pp.lpm.entry_unique_size = p.action_data_size +
+				sizeof(struct rte_pipeline_table_entry);
+
+		if (params->match.lpm.key_size == 16)
+			pp.lpm_ipv6.entry_unique_size = p.action_data_size +
+				sizeof(struct rte_pipeline_table_entry);
+	}
+
+	status = rte_pipeline_table_create(pipeline->p,
+		&p,
+		&table_id);
+	if (status) {
+		rte_table_action_free(action);
+		return -1;
+	}
+
+	/* Pipeline */
+	table = &pipeline->table[pipeline->n_tables];
+	memcpy(&table->params, params, sizeof(*params));
+	table->ap = ap;
+	table->a = action;
+	pipeline->n_tables++;
+
+	return 0;
+}
diff --git a/examples/ip_pipeline/pipeline.h b/examples/ip_pipeline/pipeline.h
new file mode 100644
index 0000000..dbc6f77
--- /dev/null
+++ b/examples/ip_pipeline/pipeline.h
@@ -0,0 +1,265 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#ifndef _INCLUDE_PIPELINE_H_
+#define _INCLUDE_PIPELINE_H_
+
+#include <stdint.h>
+#include <sys/queue.h>
+
+#include <rte_pipeline.h>
+#include <rte_table_action.h>
+
+#include "common.h"
+#include "action.h"
+
+struct pipeline_params {
+	uint32_t timer_period_ms;
+	uint32_t offset_port_id;
+	uint32_t cpu_id;
+};
+
+enum port_in_type {
+	PORT_IN_RXQ,
+	PORT_IN_SWQ,
+	PORT_IN_TMGR,
+	PORT_IN_TAP,
+	PORT_IN_KNI,
+	PORT_IN_SOURCE,
+};
+
+struct port_in_params {
+	enum port_in_type type;
+	const char *dev_name;
+	union {
+		struct {
+			uint16_t queue_id;
+		} rxq;
+
+		struct {
+			const char *mempool_name;
+			uint32_t mtu;
+		} tap;
+
+		struct {
+			const char *mempool_name;
+			const char *file_name;
+			uint32_t n_bytes_per_pkt;
+		} source;
+	};
+	uint32_t burst_size;
+};
+
+enum port_out_type {
+	PORT_OUT_TXQ,
+	PORT_OUT_SWQ,
+	PORT_OUT_TMGR,
+	PORT_OUT_TAP,
+	PORT_OUT_KNI,
+	PORT_OUT_SINK,
+};
+
+struct port_out_params {
+	enum port_out_type type;
+	const char *dev_name;
+	union {
+		struct {
+			uint16_t queue_id;
+		} txq;
+
+		struct {
+			const char *file_name;
+			uint32_t max_n_pkts;
+		} sink;
+	};
+	uint32_t burst_size;
+	int retry;
+	uint32_t n_retries;
+};
+
+enum table_type {
+	TABLE_ACL,
+	TABLE_ARRAY,
+	TABLE_HASH,
+	TABLE_LPM,
+	TABLE_STUB,
+};
+
+struct table_acl_params {
+	uint32_t n_rules;
+	uint32_t ip_header_offset;
+	int ip_version;
+};
+
+struct table_array_params {
+	uint32_t n_keys;
+	uint32_t key_offset;
+};
+
+struct table_hash_params {
+	uint32_t n_keys;
+	uint32_t key_offset;
+	uint32_t key_size;
+	uint8_t *key_mask;
+	uint32_t n_buckets;
+	int extendable_bucket;
+};
+
+struct table_lpm_params {
+	uint32_t n_rules;
+	uint32_t key_offset;
+	uint32_t key_size;
+};
+
+struct table_params {
+	/* Match */
+	enum table_type match_type;
+	union {
+		struct table_acl_params acl;
+		struct table_array_params array;
+		struct table_hash_params hash;
+		struct table_lpm_params lpm;
+	} match;
+
+	/* Action */
+	const char *action_profile_name;
+};
+
+struct table {
+	struct table_params params;
+	struct table_action_profile *ap;
+	struct rte_table_action *a;
+};
+
+#ifndef PIPELINE_TABLE_MAX
+#define PIPELINE_TABLE_MAX                                 256
+#endif
+
+struct pipeline {
+	TAILQ_ENTRY(pipeline) node;
+	char name[NAME_SIZE];
+
+	struct rte_pipeline *p;
+	struct table table[PIPELINE_TABLE_MAX];
+	uint32_t n_ports_in;
+	uint32_t n_ports_out;
+	uint32_t n_tables;
+
+	struct rte_ring *msgq_req;
+	struct rte_ring *msgq_rsp;
+	uint32_t timer_period_ms;
+
+	int enabled;
+	uint32_t thread_id;
+	uint32_t cpu_id;
+};
+
+TAILQ_HEAD(pipeline_list, pipeline);
+
+int
+pipeline_init(void);
+
+struct pipeline *
+pipeline_find(const char *name);
+
+struct pipeline *
+pipeline_create(const char *name, struct pipeline_params *params);
+
+int
+pipeline_port_in_create(const char *pipeline_name,
+	struct port_in_params *params,
+	int enabled);
+
+int
+pipeline_port_in_connect_to_table(const char *pipeline_name,
+	uint32_t port_id,
+	uint32_t table_id);
+
+int
+pipeline_port_out_create(const char *pipeline_name,
+	struct port_out_params *params);
+
+int
+pipeline_table_create(const char *pipeline_name,
+	struct table_params *params);
+
+struct table_rule_match_acl {
+	int ip_version;
+
+	RTE_STD_C11
+	union {
+		struct {
+			uint32_t sa;
+			uint32_t da;
+		} ipv4;
+
+		struct {
+			uint8_t sa[16];
+			uint8_t da[16];
+		} ipv6;
+	};
+
+	uint32_t sa_depth;
+	uint32_t da_depth;
+	uint16_t sp0;
+	uint16_t sp1;
+	uint16_t dp0;
+	uint16_t dp1;
+	uint8_t proto;
+	uint8_t proto_mask;
+	uint32_t priority;
+};
+
+struct table_rule_match_array {
+	uint32_t pos;
+};
+
+#ifndef TABLE_RULE_MATCH_SIZE_MAX
+#define TABLE_RULE_MATCH_SIZE_MAX                          256
+#endif
+
+#ifndef TABLE_RULE_ACTION_SIZE_MAX
+#define TABLE_RULE_ACTION_SIZE_MAX                         2048
+#endif
+
+struct table_rule_match_hash {
+	uint8_t key[TABLE_RULE_MATCH_SIZE_MAX];
+};
+
+struct table_rule_match_lpm {
+	int ip_version;
+
+	RTE_STD_C11
+	union {
+		uint32_t ipv4;
+		uint8_t ipv6[16];
+	};
+
+	uint8_t depth;
+};
+
+struct table_rule_match {
+	enum table_type match_type;
+
+	union {
+		struct table_rule_match_acl acl;
+		struct table_rule_match_array array;
+		struct table_rule_match_hash hash;
+		struct table_rule_match_lpm lpm;
+	} match;
+};
+
+struct table_rule_action {
+	uint64_t action_mask;
+	struct rte_table_action_fwd_params fwd;
+	struct rte_table_action_mtr_params mtr;
+	struct rte_table_action_tm_params tm;
+	struct rte_table_action_encap_params encap;
+	struct rte_table_action_nat_params nat;
+	struct rte_table_action_ttl_params ttl;
+	struct rte_table_action_stats_params stats;
+	struct rte_table_action_time_params time;
+};
+
+#endif /* _INCLUDE_PIPELINE_H_ */
-- 
2.9.3

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

* [dpdk-dev] [PATCH 20/37] ip_pipeline: add threads
  2018-03-09 18:23 [dpdk-dev] [PATCH 00/37] ip_pipeline: refactoring Jasvinder Singh
                   ` (18 preceding siblings ...)
  2018-03-09 18:24 ` [dpdk-dev] [PATCH 19/37] ip_pipeline: add pipeline object Jasvinder Singh
@ 2018-03-09 18:24 ` Jasvinder Singh
  2018-03-09 18:24 ` [dpdk-dev] [PATCH 21/37] ip_pipeline: add thread runtime Jasvinder Singh
                   ` (16 subsequent siblings)
  36 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-09 18:24 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add threads data structure and initialisation functions to run
the pipeline.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/Makefile    |   2 +-
 examples/ip_pipeline/main.c      |   8 ++
 examples/ip_pipeline/meson.build |   1 +
 examples/ip_pipeline/thread.c    | 159 +++++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/thread.h    |  13 ++++
 5 files changed, 182 insertions(+), 1 deletion(-)
 create mode 100644 examples/ip_pipeline/thread.c
 create mode 100644 examples/ip_pipeline/thread.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index b1cfc2d..5a19737 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -16,8 +16,8 @@ SRCS-y += parser.c
 SRCS-y += pipeline.c
 SRCS-y += swq.c
 SRCS-y += tap.c
+SRCS-y += thread.c
 SRCS-y += tmgr.c
-#SRCS-y += thread.c
 
 # Build using pkg-config variables if possible
 $(shell pkg-config --exists libdpdk)
diff --git a/examples/ip_pipeline/main.c b/examples/ip_pipeline/main.c
index a7f4486..d139290 100644
--- a/examples/ip_pipeline/main.c
+++ b/examples/ip_pipeline/main.c
@@ -18,6 +18,7 @@
 #include "pipeline.h"
 #include "swq.h"
 #include "tap.h"
+#include "thread.h"
 #include "tmgr.h"
 
 static const char usage[] =
@@ -223,6 +224,13 @@ main(int argc, char **argv)
 		return status;
 	}
 
+	/* Thread */
+	status = thread_init();
+	if (status) {
+		printf("Error: Thread initialization failed (%d)\n", status);
+		return status;
+	}
+
 	/* Script */
 	if (app.script_name)
 		cli_script_process(app.script_name,
diff --git a/examples/ip_pipeline/meson.build b/examples/ip_pipeline/meson.build
index ea6c704..0021c89 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -19,5 +19,6 @@ sources = files(
 	'pipeline.c',
 	'swq.c',
 	'tap.c',
+	'thread.c',
 	'tmgr.c'
 )
diff --git a/examples/ip_pipeline/thread.c b/examples/ip_pipeline/thread.c
new file mode 100644
index 0000000..4da8db9
--- /dev/null
+++ b/examples/ip_pipeline/thread.c
@@ -0,0 +1,159 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#include <stdlib.h>
+
+#include <rte_common.h>
+#include <rte_cycles.h>
+#include <rte_lcore.h>
+#include <rte_ring.h>
+
+#include <rte_table_acl.h>
+#include <rte_table_array.h>
+#include <rte_table_hash.h>
+#include <rte_table_lpm.h>
+#include <rte_table_lpm_ipv6.h>
+
+#include "common.h"
+#include "thread.h"
+#include "pipeline.h"
+
+#ifndef THREAD_PIPELINES_MAX
+#define THREAD_PIPELINES_MAX                               256
+#endif
+
+#ifndef THREAD_MSGQ_SIZE
+#define THREAD_MSGQ_SIZE                                   64
+#endif
+
+#ifndef THREAD_TIMER_PERIOD_MS
+#define THREAD_TIMER_PERIOD_MS                             100
+#endif
+
+/**
+ * Master thead: data plane thread context
+ */
+struct thread {
+	struct rte_ring *msgq_req;
+	struct rte_ring *msgq_rsp;
+
+	uint32_t enabled;
+};
+
+static struct thread thread[RTE_MAX_LCORE];
+
+/**
+ * Data plane threads: context
+ */
+struct table_data {
+	void *ap_instance;
+};
+
+struct pipeline_data {
+	struct rte_pipeline *p;
+	struct table_data table_data[PIPELINE_TABLE_MAX];
+	uint32_t n_tables;
+
+	struct rte_ring *msgq_req;
+	struct rte_ring *msgq_rsp;
+	uint64_t timer_period; /* Measured in CPU cycles. */
+	uint64_t time_next;
+
+	uint8_t buffer[TABLE_RULE_ACTION_SIZE_MAX];
+};
+
+struct thread_data {
+	struct rte_pipeline *p[THREAD_PIPELINES_MAX];
+	uint32_t n_pipelines;
+
+	struct pipeline_data pipeline_data[THREAD_PIPELINES_MAX];
+	struct rte_ring *msgq_req;
+	struct rte_ring *msgq_rsp;
+	uint64_t timer_period; /* Measured in CPU cycles. */
+	uint64_t time_next;
+	uint64_t time_next_min;
+} __rte_cache_aligned;
+
+static struct thread_data thread_data[RTE_MAX_LCORE];
+
+/**
+ * Master thread: data plane thread init
+ */
+static void
+thread_free(void)
+{
+	uint32_t i;
+
+	for (i = 0; i < RTE_MAX_LCORE; i++) {
+		struct thread *t = &thread[i];
+
+		if (!rte_lcore_is_enabled(i))
+			continue;
+
+		/* MSGQs */
+		if (t->msgq_req)
+			rte_ring_free(t->msgq_req);
+
+		if (t->msgq_rsp)
+			rte_ring_free(t->msgq_rsp);
+	}
+}
+
+int
+thread_init(void)
+{
+	uint32_t i;
+
+	for (i = 0; i < RTE_MAX_LCORE; i++) {
+		char name[NAME_MAX];
+		struct rte_ring *msgq_req, *msgq_rsp;
+		struct thread *t = &thread[i];
+		struct thread_data *t_data = &thread_data[i];
+		uint32_t cpu_id = rte_lcore_to_socket_id(i);
+
+		if (!rte_lcore_is_enabled(i))
+			continue;
+
+		/* MSGQs */
+		snprintf(name, sizeof(name), "THREAD-%04x-MSGQ-REQ", i);
+
+		msgq_req = rte_ring_create(name,
+			THREAD_MSGQ_SIZE,
+			cpu_id,
+			RING_F_SP_ENQ | RING_F_SC_DEQ);
+
+		if (msgq_req == NULL) {
+			thread_free();
+			return -1;
+		}
+
+		snprintf(name, sizeof(name), "THREAD-%04x-MSGQ-RSP", i);
+
+		msgq_rsp = rte_ring_create(name,
+			THREAD_MSGQ_SIZE,
+			cpu_id,
+			RING_F_SP_ENQ | RING_F_SC_DEQ);
+
+		if (msgq_rsp == NULL) {
+			thread_free();
+			return -1;
+		}
+
+		/* Master thread records */
+		t->msgq_req = msgq_req;
+		t->msgq_rsp = msgq_rsp;
+		t->enabled = 1;
+
+		/* Data plane thread records */
+		t_data->n_pipelines = 0;
+		t_data->msgq_req = msgq_req;
+		t_data->msgq_rsp = msgq_rsp;
+		t_data->timer_period =
+			(rte_get_tsc_hz() * THREAD_TIMER_PERIOD_MS) / 1000;
+		t_data->time_next = rte_get_tsc_cycles() + t_data->timer_period;
+		t_data->time_next_min = t_data->time_next;
+	}
+
+	return 0;
+}
diff --git a/examples/ip_pipeline/thread.h b/examples/ip_pipeline/thread.h
new file mode 100644
index 0000000..39c0d89
--- /dev/null
+++ b/examples/ip_pipeline/thread.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#ifndef _INCLUDE_THREAD_H_
+#define _INCLUDE_THREAD_H_
+
+#include <stdint.h>
+
+int
+thread_init(void);
+
+#endif /* _INCLUDE_THREAD_H_ */
-- 
2.9.3

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

* [dpdk-dev] [PATCH 21/37] ip_pipeline: add thread runtime
  2018-03-09 18:23 [dpdk-dev] [PATCH 00/37] ip_pipeline: refactoring Jasvinder Singh
                   ` (19 preceding siblings ...)
  2018-03-09 18:24 ` [dpdk-dev] [PATCH 20/37] ip_pipeline: add threads Jasvinder Singh
@ 2018-03-09 18:24 ` Jasvinder Singh
  2018-03-09 18:24 ` [dpdk-dev] [PATCH 22/37] ip_pipeline: add cli to enable and disable pipeline Jasvinder Singh
                   ` (15 subsequent siblings)
  36 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-09 18:24 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add runtime thread functions for the pipeline.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/main.c   |   6 ++
 examples/ip_pipeline/thread.c | 193 ++++++++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/thread.h |   5 +-
 3 files changed, 203 insertions(+), 1 deletion(-)

diff --git a/examples/ip_pipeline/main.c b/examples/ip_pipeline/main.c
index d139290..36da679 100644
--- a/examples/ip_pipeline/main.c
+++ b/examples/ip_pipeline/main.c
@@ -8,6 +8,7 @@
 #include <unistd.h>
 #include <getopt.h>
 
+#include <rte_launch.h>
 #include <rte_eal.h>
 
 #include "cli.h"
@@ -231,6 +232,11 @@ main(int argc, char **argv)
 		return status;
 	}
 
+	rte_eal_mp_remote_launch(
+		thread_main,
+		NULL,
+		SKIP_MASTER);
+
 	/* Script */
 	if (app.script_name)
 		cli_script_process(app.script_name,
diff --git a/examples/ip_pipeline/thread.c b/examples/ip_pipeline/thread.c
index 4da8db9..387e9bc 100644
--- a/examples/ip_pipeline/thread.c
+++ b/examples/ip_pipeline/thread.c
@@ -157,3 +157,196 @@ thread_init(void)
 
 	return 0;
 }
+
+/**
+ * Master thread & data plane threads: message passing
+ */
+enum thread_req_type {
+	THREAD_REQ_MAX
+};
+
+struct thread_msg_req {
+	enum thread_req_type type;
+};
+
+struct thread_msg_rsp {
+	int status;
+};
+
+/**
+ * Data plane threads: message handling
+ */
+static inline struct thread_msg_req *
+thread_msg_recv(struct rte_ring *msgq_req)
+{
+	struct thread_msg_req *req;
+
+	int status = rte_ring_sc_dequeue(msgq_req, (void **) &req);
+
+	if (status != 0)
+		return NULL;
+
+	return req;
+}
+
+static inline void
+thread_msg_send(struct rte_ring *msgq_rsp,
+	struct thread_msg_rsp *rsp)
+{
+	int status;
+
+	do {
+		status = rte_ring_sp_enqueue(msgq_rsp, rsp);
+	} while (status == -ENOBUFS);
+}
+
+static void
+thread_msg_handle(struct thread_data *t)
+{
+	for ( ; ; ) {
+		struct thread_msg_req *req;
+		struct thread_msg_rsp *rsp;
+
+		req = thread_msg_recv(t->msgq_req);
+		if (req == NULL)
+			break;
+
+		switch (req->type) {
+		default:
+			rsp = (struct thread_msg_rsp *) req;
+			rsp->status = -1;
+		}
+
+		thread_msg_send(t->msgq_rsp, rsp);
+	}
+}
+
+/**
+ * Master thread & data plane threads: message passing
+ */
+
+enum pipeline_req_type {
+	PIPELINE_REQ_MAX
+};
+
+struct pipeline_msg_req {
+	enum pipeline_req_type type;
+};
+
+struct pipeline_msg_rsp {
+	int status;
+};
+
+/**
+ * Data plane threads: message handling
+ */
+static inline struct pipeline_msg_req *
+pipeline_msg_recv(struct rte_ring *msgq_req)
+{
+	struct pipeline_msg_req *req;
+
+	int status = rte_ring_sc_dequeue(msgq_req, (void **) &req);
+
+	if (status != 0)
+		return NULL;
+
+	return req;
+}
+
+static inline void
+pipeline_msg_send(struct rte_ring *msgq_rsp,
+	struct pipeline_msg_rsp *rsp)
+{
+	int status;
+
+	do {
+		status = rte_ring_sp_enqueue(msgq_rsp, rsp);
+	} while (status == -ENOBUFS);
+}
+
+static void
+pipeline_msg_handle(struct pipeline_data *p)
+{
+	for ( ; ; ) {
+		struct pipeline_msg_req *req;
+		struct pipeline_msg_rsp *rsp;
+
+		req = pipeline_msg_recv(p->msgq_req);
+		if (req == NULL)
+			break;
+
+		switch (req->type) {
+		default:
+			rsp = (struct pipeline_msg_rsp *) req;
+			rsp->status = -1;
+		}
+
+		pipeline_msg_send(p->msgq_rsp, rsp);
+	}
+}
+
+/**
+ * Data plane threads: main
+ */
+int
+thread_main(void *arg __rte_unused)
+{
+	struct thread_data *t;
+	uint32_t thread_id, i;
+
+	thread_id = rte_lcore_id();
+	t = &thread_data[thread_id];
+
+	/* Dispatch loop */
+	for (i = 0; ; i++) {
+		uint32_t j;
+
+		/* Data Plane */
+		for (j = 0; j < t->n_pipelines; j++)
+			rte_pipeline_run(t->p[j]);
+
+		/* Control Plane */
+		if ((i & 0xF) == 0) {
+			uint64_t time = rte_get_tsc_cycles();
+			uint64_t time_next_min = UINT64_MAX;
+
+			if (time < t->time_next_min)
+				continue;
+
+			/* Pipeline message queues */
+			for (j = 0; j < t->n_pipelines; j++) {
+				struct pipeline_data *p =
+					&t->pipeline_data[j];
+				uint64_t time_next = p->time_next;
+
+				if (time_next <= time) {
+					pipeline_msg_handle(p);
+					rte_pipeline_flush(p->p);
+					time_next = time + p->timer_period;
+					p->time_next = time_next;
+				}
+
+				if (time_next < time_next_min)
+					time_next_min = time_next;
+			}
+
+			/* Thread message queues */
+			{
+				uint64_t time_next = t->time_next;
+
+				if (time_next <= time) {
+					thread_msg_handle(t);
+					time_next = time + t->timer_period;
+					t->time_next = time_next;
+				}
+
+				if (time_next < time_next_min)
+					time_next_min = time_next;
+			}
+
+			t->time_next_min = time_next_min;
+		}
+	}
+
+	return 0;
+}
diff --git a/examples/ip_pipeline/thread.h b/examples/ip_pipeline/thread.h
index 39c0d89..44114f3 100644
--- a/examples/ip_pipeline/thread.h
+++ b/examples/ip_pipeline/thread.h
@@ -10,4 +10,7 @@
 int
 thread_init(void);
 
-#endif /* _INCLUDE_THREAD_H_ */
+int
+thread_main(void *arg);
+
+#endif /* _INCLUDE_THREAD_H_ */
\ No newline at end of file
-- 
2.9.3

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

* [dpdk-dev] [PATCH 22/37] ip_pipeline: add cli to enable and disable pipeline
  2018-03-09 18:23 [dpdk-dev] [PATCH 00/37] ip_pipeline: refactoring Jasvinder Singh
                   ` (20 preceding siblings ...)
  2018-03-09 18:24 ` [dpdk-dev] [PATCH 21/37] ip_pipeline: add thread runtime Jasvinder Singh
@ 2018-03-09 18:24 ` Jasvinder Singh
  2018-03-09 18:24 ` [dpdk-dev] [PATCH 23/37] ip_pipeline: add cli to enable and disable pipeline port Jasvinder Singh
                   ` (14 subsequent siblings)
  36 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-09 18:24 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Fan Zhang

Add commands to enable and disable the pipeline on the thread.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Fan Zhang <roy.fan.zhang@intel.com>
---
 examples/ip_pipeline/cli.c    | 102 +++++++++++++++++
 examples/ip_pipeline/thread.c | 260 +++++++++++++++++++++++++++++++++++++++++-
 examples/ip_pipeline/thread.h |   8 ++
 3 files changed, 369 insertions(+), 1 deletion(-)

diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index 96fc33e..4d8d808 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -17,6 +17,7 @@
 #include "pipeline.h"
 #include "swq.h"
 #include "tap.h"
+#include "thread.h"
 #include "tmgr.h"
 
 #ifndef CMD_MAX_TOKENS
@@ -1740,6 +1741,91 @@ cmd_pipeline_port_in_table(char **tokens,
 	}
 }
 
+/**
+ * thread <thread_id> pipeline <pipeline_name> enable
+ */
+static void
+cmd_thread_pipeline_enable(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	char *pipeline_name;
+	uint32_t thread_id;
+	int status;
+
+	if (n_tokens != 5) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	if (parser_read_uint32(&thread_id, tokens[1]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
+		return;
+	}
+
+	if (strcmp(tokens[2], "pipeline") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
+		return;
+	}
+
+	pipeline_name = tokens[3];
+
+	if (strcmp(tokens[4], "enable") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable");
+		return;
+	}
+
+	status = thread_pipeline_enable(thread_id, pipeline_name);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, "thread pipeline enable");
+		return;
+	}
+}
+
+/**
+ * thread <thread_id> pipeline <pipeline_name> disable
+ */
+static void
+cmd_thread_pipeline_disable(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	char *pipeline_name;
+	uint32_t thread_id;
+	int status;
+
+	if (n_tokens != 5) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	if (parser_read_uint32(&thread_id, tokens[1]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
+		return;
+	}
+
+	if (strcmp(tokens[2], "pipeline") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
+		return;
+	}
+
+	pipeline_name = tokens[3];
+
+	if (strcmp(tokens[4], "disable") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable");
+		return;
+	}
+
+	status = thread_pipeline_disable(thread_id, pipeline_name);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL,
+			"thread pipeline disable");
+		return;
+	}
+}
+
 void
 cli_process(char *in, char *out, size_t out_size)
 {
@@ -1863,6 +1949,22 @@ cli_process(char *in, char *out, size_t out_size)
 		}
 	}
 
+	if (strcmp(tokens[0], "thread") == 0) {
+		if ((n_tokens >= 5) &&
+			(strcmp(tokens[4], "enable") == 0)) {
+			cmd_thread_pipeline_enable(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
+
+		if ((n_tokens >= 5) &&
+			(strcmp(tokens[4], "disable") == 0)) {
+			cmd_thread_pipeline_disable(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
+	}
+
 	snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
 }
 
diff --git a/examples/ip_pipeline/thread.c b/examples/ip_pipeline/thread.c
index 387e9bc..d707ad7 100644
--- a/examples/ip_pipeline/thread.c
+++ b/examples/ip_pipeline/thread.c
@@ -47,7 +47,7 @@ static struct thread thread[RTE_MAX_LCORE];
  * Data plane threads: context
  */
 struct table_data {
-	void *ap_instance;
+	struct rte_table_action *a;
 };
 
 struct pipeline_data {
@@ -162,11 +162,30 @@ thread_init(void)
  * Master thread & data plane threads: message passing
  */
 enum thread_req_type {
+	THREAD_REQ_PIPELINE_ENABLE = 0,
+	THREAD_REQ_PIPELINE_DISABLE,
 	THREAD_REQ_MAX
 };
 
 struct thread_msg_req {
 	enum thread_req_type type;
+
+	union {
+		struct {
+			struct rte_pipeline *p;
+			struct {
+				struct rte_table_action *a;
+			} table[PIPELINE_TABLE_MAX];
+			struct rte_ring *msgq_req;
+			struct rte_ring *msgq_rsp;
+			uint32_t timer_period_ms;
+			uint32_t n_tables;
+		} pipeline_enable;
+
+		struct {
+			struct rte_pipeline *p;
+		} pipeline_disable;
+	};
 };
 
 struct thread_msg_rsp {
@@ -174,6 +193,164 @@ struct thread_msg_rsp {
 };
 
 /**
+ * Master thread
+ */
+static struct thread_msg_req *
+thread_msg_alloc(void)
+{
+	size_t size = RTE_MAX(sizeof(struct thread_msg_req),
+		sizeof(struct thread_msg_rsp));
+
+	return calloc(1, size);
+}
+
+static void
+thread_msg_free(struct thread_msg_rsp *rsp)
+{
+	free(rsp);
+}
+
+static struct thread_msg_rsp *
+thread_msg_send_recv(uint32_t thread_id,
+	struct thread_msg_req *req)
+{
+	struct thread *t = &thread[thread_id];
+	struct rte_ring *msgq_req = t->msgq_req;
+	struct rte_ring *msgq_rsp = t->msgq_rsp;
+	struct thread_msg_rsp *rsp;
+	int status;
+
+	/* send */
+	do {
+		status = rte_ring_sp_enqueue(msgq_req, req);
+	} while (status == -ENOBUFS);
+
+	/* recv */
+	do {
+		status = rte_ring_sc_dequeue(msgq_rsp, (void **) &rsp);
+	} while (status != 0);
+
+	return rsp;
+}
+
+int
+thread_pipeline_enable(uint32_t thread_id,
+	const char *pipeline_name)
+{
+	struct pipeline *p = pipeline_find(pipeline_name);
+	struct thread *t;
+	struct thread_msg_req *req;
+	struct thread_msg_rsp *rsp;
+	uint32_t i;
+	int status;
+
+	/* Check input params */
+	if ((thread_id >= RTE_MAX_LCORE) ||
+		(p == NULL) ||
+		(p->n_ports_in == 0) ||
+		(p->n_ports_out == 0) ||
+		(p->n_tables == 0))
+		return -1;
+
+	t = &thread[thread_id];
+	if (t->enabled == 0)
+		return -1;
+
+	if (p->enabled && (p->thread_id == thread_id))
+		return 0;
+
+	/* Allocate request */
+	req = thread_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = THREAD_REQ_PIPELINE_ENABLE;
+	req->pipeline_enable.p = p->p;
+	for (i = 0; i < p->n_tables; i++)
+		req->pipeline_enable.table[i].a =
+			p->table[i].a;
+	req->pipeline_enable.msgq_req = p->msgq_req;
+	req->pipeline_enable.msgq_rsp = p->msgq_rsp;
+	req->pipeline_enable.timer_period_ms = p->timer_period_ms;
+	req->pipeline_enable.n_tables = p->n_tables;
+
+	/* Send request and wait for response */
+	rsp = thread_msg_send_recv(thread_id, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+
+	/* Free response */
+	thread_msg_free(rsp);
+
+	/* Request completion */
+	if (status)
+		return status;
+
+	p->thread_id = thread_id;
+	p->enabled = 1;
+
+	return 0;
+}
+
+int
+thread_pipeline_disable(uint32_t thread_id,
+	const char *pipeline_name)
+{
+	struct pipeline *p = pipeline_find(pipeline_name);
+	struct thread *t;
+	struct thread_msg_req *req;
+	struct thread_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if ((thread_id >= RTE_MAX_LCORE) ||
+		(p == NULL))
+		return -1;
+
+	t = &thread[thread_id];
+	if (t->enabled == 0)
+		return -1;
+
+	if (p->enabled == 0)
+		return 0;
+
+	if (p->thread_id != thread_id)
+		return -1;
+
+	/* Allocate request */
+	req = thread_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = THREAD_REQ_PIPELINE_DISABLE;
+	req->pipeline_disable.p = p->p;
+
+	/* Send request and wait for response */
+	rsp = thread_msg_send_recv(thread_id, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+
+	/* Free response */
+	thread_msg_free(rsp);
+
+	/* Request completion */
+	if (status)
+		return status;
+
+	p->enabled = 0;
+
+	return 0;
+}
+
+/**
  * Data plane threads: message handling
  */
 static inline struct thread_msg_req *
@@ -200,6 +377,79 @@ thread_msg_send(struct rte_ring *msgq_rsp,
 	} while (status == -ENOBUFS);
 }
 
+static struct thread_msg_rsp *
+thread_msg_handle_pipeline_enable(struct thread_data *t,
+	struct thread_msg_req *req)
+{
+	struct thread_msg_rsp *rsp = (struct thread_msg_rsp *) req;
+	struct pipeline_data *p = &t->pipeline_data[t->n_pipelines];
+	uint32_t i;
+
+	/* Request */
+	if (t->n_pipelines >= THREAD_PIPELINES_MAX) {
+		rsp->status = -1;
+		return rsp;
+	}
+
+	t->p[t->n_pipelines] = req->pipeline_enable.p;
+
+	p->p = req->pipeline_enable.p;
+	for (i = 0; i < req->pipeline_enable.n_tables; i++)
+		p->table_data[i].a =
+			req->pipeline_enable.table[i].a;
+
+	p->n_tables = req->pipeline_enable.n_tables;
+
+	p->msgq_req = req->pipeline_enable.msgq_req;
+	p->msgq_rsp = req->pipeline_enable.msgq_rsp;
+	p->timer_period =
+		(rte_get_tsc_hz() * req->pipeline_enable.timer_period_ms) / 1000;
+	p->time_next = rte_get_tsc_cycles() + p->timer_period;
+
+	t->n_pipelines++;
+
+	/* Response */
+	rsp->status = 0;
+	return rsp;
+}
+
+static struct thread_msg_rsp *
+thread_msg_handle_pipeline_disable(struct thread_data *t,
+	struct thread_msg_req *req)
+{
+	struct thread_msg_rsp *rsp = (struct thread_msg_rsp *) req;
+	uint32_t n_pipelines = t->n_pipelines;
+	struct rte_pipeline *pipeline = req->pipeline_disable.p;
+	uint32_t i;
+
+	/* find pipeline */
+	for (i = 0; i < n_pipelines; i++) {
+		struct pipeline_data *p = &t->pipeline_data[i];
+
+		if (p->p != pipeline)
+			continue;
+
+		if (i < n_pipelines - 1) {
+			struct rte_pipeline *pipeline_last =
+				t->p[n_pipelines - 1];
+			struct pipeline_data *p_last =
+				&t->pipeline_data[n_pipelines - 1];
+
+			t->p[i] = pipeline_last;
+			memcpy(p, p_last, sizeof(*p));
+		}
+
+		t->n_pipelines--;
+
+		rsp->status = 0;
+		return rsp;
+	}
+
+	/* should not get here */
+	rsp->status = 0;
+	return rsp;
+}
+
 static void
 thread_msg_handle(struct thread_data *t)
 {
@@ -212,6 +462,14 @@ thread_msg_handle(struct thread_data *t)
 			break;
 
 		switch (req->type) {
+		case THREAD_REQ_PIPELINE_ENABLE:
+			rsp = thread_msg_handle_pipeline_enable(t, req);
+			break;
+
+		case THREAD_REQ_PIPELINE_DISABLE:
+			rsp = thread_msg_handle_pipeline_disable(t, req);
+			break;
+
 		default:
 			rsp = (struct thread_msg_rsp *) req;
 			rsp->status = -1;
diff --git a/examples/ip_pipeline/thread.h b/examples/ip_pipeline/thread.h
index 44114f3..2c82f86 100644
--- a/examples/ip_pipeline/thread.h
+++ b/examples/ip_pipeline/thread.h
@@ -8,6 +8,14 @@
 #include <stdint.h>
 
 int
+thread_pipeline_enable(uint32_t thread_id,
+	const char *pipeline_name);
+
+int
+thread_pipeline_disable(uint32_t thread_id,
+	const char *pipeline_name);
+
+int
 thread_init(void);
 
 int
-- 
2.9.3

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

* [dpdk-dev] [PATCH 23/37] ip_pipeline: add cli to enable and disable pipeline port
  2018-03-09 18:23 [dpdk-dev] [PATCH 00/37] ip_pipeline: refactoring Jasvinder Singh
                   ` (21 preceding siblings ...)
  2018-03-09 18:24 ` [dpdk-dev] [PATCH 22/37] ip_pipeline: add cli to enable and disable pipeline Jasvinder Singh
@ 2018-03-09 18:24 ` Jasvinder Singh
  2018-03-09 18:24 ` [dpdk-dev] [PATCH 24/37] ip_pipeline: add cli to read pipeline port and table stats Jasvinder Singh
                   ` (13 subsequent siblings)
  36 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-09 18:24 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Fan Zhang

Add commands to enable and disable the pipeline ports.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Fan Zhang <roy.fan.zhang@intel.com>
---
 examples/ip_pipeline/cli.c      | 112 +++++++++++++++++++++++++++
 examples/ip_pipeline/pipeline.h |   8 ++
 examples/ip_pipeline/thread.c   | 163 +++++++++++++++++++++++++++++++++++++++-
 3 files changed, 282 insertions(+), 1 deletion(-)

diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index 4d8d808..ac6d6bd 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -1742,6 +1742,100 @@ cmd_pipeline_port_in_table(char **tokens,
 }
 
 /**
+ * pipeline <pipeline_name> port in <port_id> enable
+ */
+static void
+cmd_pipeline_port_in_enable(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	char *pipeline_name;
+	uint32_t port_id;
+	int status;
+
+	if (n_tokens != 6) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "port") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
+		return;
+	}
+
+	if (strcmp(tokens[3], "in") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
+		return;
+	}
+
+	if (parser_read_uint32(&port_id, tokens[4]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
+		return;
+	}
+
+	if (strcmp(tokens[5], "enable") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable");
+		return;
+	}
+
+	status = pipeline_port_in_enable(pipeline_name, port_id);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
+ * pipeline <pipeline_name> port in <port_id> disable
+ */
+static void
+cmd_pipeline_port_in_disable(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	char *pipeline_name;
+	uint32_t port_id;
+	int status;
+
+	if (n_tokens != 6) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "port") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
+		return;
+	}
+
+	if (strcmp(tokens[3], "in") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
+		return;
+	}
+
+	if (parser_read_uint32(&port_id, tokens[4]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
+		return;
+	}
+
+	if (strcmp(tokens[5], "disable") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable");
+		return;
+	}
+
+	status = pipeline_port_in_disable(pipeline_name, port_id);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
  * thread <thread_id> pipeline <pipeline_name> enable
  */
 static void
@@ -1947,6 +2041,24 @@ cli_process(char *in, char *out, size_t out_size)
 				out, out_size);
 			return;
 		}
+
+		if ((n_tokens >= 6) &&
+			(strcmp(tokens[2], "port") == 0) &&
+			(strcmp(tokens[3], "in") == 0) &&
+			(strcmp(tokens[5], "enable") == 0)) {
+			cmd_pipeline_port_in_enable(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
+
+		if ((n_tokens >= 6) &&
+			(strcmp(tokens[2], "port") == 0) &&
+			(strcmp(tokens[3], "in") == 0) &&
+			(strcmp(tokens[5], "disable") == 0)) {
+			cmd_pipeline_port_in_disable(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
 	}
 
 	if (strcmp(tokens[0], "thread") == 0) {
diff --git a/examples/ip_pipeline/pipeline.h b/examples/ip_pipeline/pipeline.h
index dbc6f77..9b79b67 100644
--- a/examples/ip_pipeline/pipeline.h
+++ b/examples/ip_pipeline/pipeline.h
@@ -262,4 +262,12 @@ struct table_rule_action {
 	struct rte_table_action_time_params time;
 };
 
+int
+pipeline_port_in_enable(const char *pipeline_name,
+	uint32_t port_id);
+
+int
+pipeline_port_in_disable(const char *pipeline_name,
+	uint32_t port_id);
+
 #endif /* _INCLUDE_PIPELINE_H_ */
diff --git a/examples/ip_pipeline/thread.c b/examples/ip_pipeline/thread.c
index d707ad7..a47b645 100644
--- a/examples/ip_pipeline/thread.c
+++ b/examples/ip_pipeline/thread.c
@@ -482,13 +482,17 @@ thread_msg_handle(struct thread_data *t)
 /**
  * Master thread & data plane threads: message passing
  */
-
 enum pipeline_req_type {
+	/* Port IN */
+	PIPELINE_REQ_PORT_IN_ENABLE,
+	PIPELINE_REQ_PORT_IN_DISABLE,
+
 	PIPELINE_REQ_MAX
 };
 
 struct pipeline_msg_req {
 	enum pipeline_req_type type;
+	uint32_t id; /* Port IN, port OUT or table ID */
 };
 
 struct pipeline_msg_rsp {
@@ -496,6 +500,129 @@ struct pipeline_msg_rsp {
 };
 
 /**
+ * Master thread
+ */
+static struct pipeline_msg_req *
+pipeline_msg_alloc(void)
+{
+	size_t size = RTE_MAX(sizeof(struct pipeline_msg_req),
+		sizeof(struct pipeline_msg_rsp));
+
+	return calloc(1, size);
+}
+
+static void
+pipeline_msg_free(struct pipeline_msg_rsp *rsp)
+{
+	free(rsp);
+}
+
+static struct pipeline_msg_rsp *
+pipeline_msg_send_recv(struct pipeline *p,
+	struct pipeline_msg_req *req)
+{
+	struct rte_ring *msgq_req = p->msgq_req;
+	struct rte_ring *msgq_rsp = p->msgq_rsp;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* send */
+	do {
+		status = rte_ring_sp_enqueue(msgq_req, req);
+	} while (status == -ENOBUFS);
+
+	/* recv */
+	do {
+		status = rte_ring_sc_dequeue(msgq_rsp, (void **) &rsp);
+	} while (status != 0);
+
+	return rsp;
+}
+
+int
+pipeline_port_in_enable(const char *pipeline_name,
+	uint32_t port_id)
+{
+	struct pipeline *p;
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if (pipeline_name == NULL)
+		return -1;
+
+	p = pipeline_find(pipeline_name);
+	if ((p == NULL) ||
+		(port_id >= p->n_ports_in))
+		return -1;
+
+	/* Allocate request */
+	req = pipeline_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = PIPELINE_REQ_PORT_IN_ENABLE;
+	req->id = port_id;
+
+	/* Send request and wait for response */
+	rsp = pipeline_msg_send_recv(p, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+
+	/* Free response */
+	pipeline_msg_free(rsp);
+
+	return status;
+}
+
+int
+pipeline_port_in_disable(const char *pipeline_name,
+	uint32_t port_id)
+{
+	struct pipeline *p;
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if (pipeline_name == NULL)
+		return -1;
+
+	p = pipeline_find(pipeline_name);
+	if ((p == NULL) ||
+		(port_id >= p->n_ports_in))
+		return -1;
+
+	/* Allocate request */
+	req = pipeline_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = PIPELINE_REQ_PORT_IN_DISABLE;
+	req->id = port_id;
+
+	/* Send request and wait for response */
+	rsp = pipeline_msg_send_recv(p, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+
+	/* Free response */
+	pipeline_msg_free(rsp);
+
+	return status;
+}
+
+
+/**
  * Data plane threads: message handling
  */
 static inline struct pipeline_msg_req *
@@ -522,6 +649,32 @@ pipeline_msg_send(struct rte_ring *msgq_rsp,
 	} while (status == -ENOBUFS);
 }
 
+static struct pipeline_msg_rsp *
+pipeline_msg_handle_port_in_enable(struct pipeline_data *p,
+	struct pipeline_msg_req *req)
+{
+	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+	uint32_t port_id = req->id;
+
+	rsp->status = rte_pipeline_port_in_enable(p->p,
+		port_id);
+
+	return rsp;
+}
+
+static struct pipeline_msg_rsp *
+pipeline_msg_handle_port_in_disable(struct pipeline_data *p,
+	struct pipeline_msg_req *req)
+{
+	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+	uint32_t port_id = req->id;
+
+	rsp->status = rte_pipeline_port_in_disable(p->p,
+		port_id);
+
+	return rsp;
+}
+
 static void
 pipeline_msg_handle(struct pipeline_data *p)
 {
@@ -534,6 +687,14 @@ pipeline_msg_handle(struct pipeline_data *p)
 			break;
 
 		switch (req->type) {
+		case PIPELINE_REQ_PORT_IN_ENABLE:
+			rsp = pipeline_msg_handle_port_in_enable(p, req);
+			break;
+
+		case PIPELINE_REQ_PORT_IN_DISABLE:
+			rsp = pipeline_msg_handle_port_in_disable(p, req);
+			break;
+
 		default:
 			rsp = (struct pipeline_msg_rsp *) req;
 			rsp->status = -1;
-- 
2.9.3

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

* [dpdk-dev] [PATCH 24/37] ip_pipeline: add cli to read pipeline port and table stats
  2018-03-09 18:23 [dpdk-dev] [PATCH 00/37] ip_pipeline: refactoring Jasvinder Singh
                   ` (22 preceding siblings ...)
  2018-03-09 18:24 ` [dpdk-dev] [PATCH 23/37] ip_pipeline: add cli to enable and disable pipeline port Jasvinder Singh
@ 2018-03-09 18:24 ` Jasvinder Singh
  2018-03-09 18:24 ` [dpdk-dev] [PATCH 25/37] ip_pipeline: add cli for pipeline table entries Jasvinder Singh
                   ` (12 subsequent siblings)
  36 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-09 18:24 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Fan Zhang

Add commands to read the pipeline  port in, port out
and table stats.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Fan Zhang <roy.fan.zhang@intel.com>
---
 examples/ip_pipeline/cli.c      | 256 ++++++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/pipeline.h |  18 +++
 examples/ip_pipeline/thread.c   | 246 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 520 insertions(+)

diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index ac6d6bd..dac115a 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -1742,6 +1742,83 @@ cmd_pipeline_port_in_table(char **tokens,
 }
 
 /**
+ * pipeline <pipeline_name> port in <port_id> stats read [clear]
+ */
+
+#define MSG_PIPELINE_PORT_IN_STATS                         \
+	"Pkts in: %" PRIu64 "\n"                           \
+	"Pkts dropped by AH: %" PRIu64 "\n"                \
+	"Pkts dropped by other: %" PRIu64 "\n"
+
+static void
+cmd_pipeline_port_in_stats(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct rte_pipeline_port_in_stats stats;
+	char *pipeline_name;
+	uint32_t port_id;
+	int clear, status;
+
+	if ((n_tokens != 7) && (n_tokens != 8)) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "port") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
+		return;
+	}
+
+	if (strcmp(tokens[3], "in") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
+		return;
+	}
+
+	if (parser_read_uint32(&port_id, tokens[4]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
+		return;
+	}
+
+	if (strcmp(tokens[5], "stats") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
+		return;
+	}
+
+	if (strcmp(tokens[6], "read") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read");
+		return;
+	}
+
+	clear = 0;
+	if (n_tokens == 8) {
+		if (strcmp(tokens[7], "clear") != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "clear");
+			return;
+		}
+
+		clear = 1;
+	}
+
+	status = pipeline_port_in_stats_read(pipeline_name,
+		port_id,
+		&stats,
+		clear);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+
+	snprintf(out, out_size, MSG_PIPELINE_PORT_IN_STATS,
+		stats.stats.n_pkts_in,
+		stats.n_pkts_dropped_by_ah,
+		stats.stats.n_pkts_drop);
+}
+
+/**
  * pipeline <pipeline_name> port in <port_id> enable
  */
 static void
@@ -1836,6 +1913,159 @@ cmd_pipeline_port_in_disable(char **tokens,
 }
 
 /**
+ * pipeline <pipeline_name> port out <port_id> stats read [clear]
+ */
+#define MSG_PIPELINE_PORT_OUT_STATS                        \
+	"Pkts in: %" PRIu64 "\n"                           \
+	"Pkts dropped by AH: %" PRIu64 "\n"                \
+	"Pkts dropped by other: %" PRIu64 "\n"
+
+static void
+cmd_pipeline_port_out_stats(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct rte_pipeline_port_out_stats stats;
+	char *pipeline_name;
+	uint32_t port_id;
+	int clear, status;
+
+	if ((n_tokens != 7) && (n_tokens != 8)) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "port") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
+		return;
+	}
+
+	if (strcmp(tokens[3], "out") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "out");
+		return;
+	}
+
+	if (parser_read_uint32(&port_id, tokens[4]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
+		return;
+	}
+
+	if (strcmp(tokens[5], "stats") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
+		return;
+	}
+
+	if (strcmp(tokens[6], "read") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read");
+		return;
+	}
+
+	clear = 0;
+	if (n_tokens == 8) {
+		if (strcmp(tokens[7], "clear") != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "clear");
+			return;
+		}
+
+		clear = 1;
+	}
+
+	status = pipeline_port_out_stats_read(pipeline_name,
+		port_id,
+		&stats,
+		clear);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+
+	snprintf(out, out_size, MSG_PIPELINE_PORT_OUT_STATS,
+		stats.stats.n_pkts_in,
+		stats.n_pkts_dropped_by_ah,
+		stats.stats.n_pkts_drop);
+}
+
+/**
+ * pipeline <pipeline_name> table <table_id> stats read [clear]
+ */
+#define MSG_PIPELINE_TABLE_STATS                                     \
+	"Pkts in: %" PRIu64 "\n"                                     \
+	"Pkts in with lookup miss: %" PRIu64 "\n"                    \
+	"Pkts in with lookup hit dropped by AH: %" PRIu64 "\n"       \
+	"Pkts in with lookup hit dropped by others: %" PRIu64 "\n"   \
+	"Pkts in with lookup miss dropped by AH: %" PRIu64 "\n"      \
+	"Pkts in with lookup miss dropped by others: %" PRIu64 "\n"
+
+static void
+cmd_pipeline_table_stats(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct rte_pipeline_table_stats stats;
+	char *pipeline_name;
+	uint32_t table_id;
+	int clear, status;
+
+	if ((n_tokens != 6) && (n_tokens != 7)) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "table") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
+		return;
+	}
+
+	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
+		return;
+	}
+
+	if (strcmp(tokens[4], "stats") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
+		return;
+	}
+
+	if (strcmp(tokens[5], "read") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read");
+		return;
+	}
+
+	clear = 0;
+	if (n_tokens == 7) {
+		if (strcmp(tokens[6], "clear") != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "clear");
+			return;
+		}
+
+		clear = 1;
+	}
+
+	status = pipeline_table_stats_read(pipeline_name,
+		table_id,
+		&stats,
+		clear);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+
+	snprintf(out, out_size, MSG_PIPELINE_TABLE_STATS,
+		stats.stats.n_pkts_in,
+		stats.stats.n_pkts_lookup_miss,
+		stats.n_pkts_dropped_by_lkp_hit_ah,
+		stats.n_pkts_dropped_lkp_hit,
+		stats.n_pkts_dropped_by_lkp_miss_ah,
+		stats.n_pkts_dropped_lkp_miss);
+}
+
+/**
  * thread <thread_id> pipeline <pipeline_name> enable
  */
 static void
@@ -2045,6 +2275,15 @@ cli_process(char *in, char *out, size_t out_size)
 		if ((n_tokens >= 6) &&
 			(strcmp(tokens[2], "port") == 0) &&
 			(strcmp(tokens[3], "in") == 0) &&
+			(strcmp(tokens[5], "stats") == 0)) {
+			cmd_pipeline_port_in_stats(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
+
+		if ((n_tokens >= 6) &&
+			(strcmp(tokens[2], "port") == 0) &&
+			(strcmp(tokens[3], "in") == 0) &&
 			(strcmp(tokens[5], "enable") == 0)) {
 			cmd_pipeline_port_in_enable(tokens, n_tokens,
 				out, out_size);
@@ -2059,6 +2298,23 @@ cli_process(char *in, char *out, size_t out_size)
 				out, out_size);
 			return;
 		}
+
+		if ((n_tokens >= 6) &&
+			(strcmp(tokens[2], "port") == 0) &&
+			(strcmp(tokens[3], "out") == 0) &&
+			(strcmp(tokens[5], "stats") == 0)) {
+			cmd_pipeline_port_out_stats(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
+
+		if ((n_tokens >= 5) &&
+			(strcmp(tokens[2], "table") == 0) &&
+			(strcmp(tokens[4], "stats") == 0)) {
+			cmd_pipeline_table_stats(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
 	}
 
 	if (strcmp(tokens[0], "thread") == 0) {
diff --git a/examples/ip_pipeline/pipeline.h b/examples/ip_pipeline/pipeline.h
index 9b79b67..9b2c295 100644
--- a/examples/ip_pipeline/pipeline.h
+++ b/examples/ip_pipeline/pipeline.h
@@ -263,6 +263,12 @@ struct table_rule_action {
 };
 
 int
+pipeline_port_in_stats_read(const char *pipeline_name,
+	uint32_t port_id,
+	struct rte_pipeline_port_in_stats *stats,
+	int clear);
+
+int
 pipeline_port_in_enable(const char *pipeline_name,
 	uint32_t port_id);
 
@@ -270,4 +276,16 @@ int
 pipeline_port_in_disable(const char *pipeline_name,
 	uint32_t port_id);
 
+int
+pipeline_port_out_stats_read(const char *pipeline_name,
+	uint32_t port_id,
+	struct rte_pipeline_port_out_stats *stats,
+	int clear);
+
+int
+pipeline_table_stats_read(const char *pipeline_name,
+	uint32_t table_id,
+	struct rte_pipeline_table_stats *stats,
+	int clear);
+
 #endif /* _INCLUDE_PIPELINE_H_ */
diff --git a/examples/ip_pipeline/thread.c b/examples/ip_pipeline/thread.c
index a47b645..a18a820 100644
--- a/examples/ip_pipeline/thread.c
+++ b/examples/ip_pipeline/thread.c
@@ -484,19 +484,64 @@ thread_msg_handle(struct thread_data *t)
  */
 enum pipeline_req_type {
 	/* Port IN */
+	PIPELINE_REQ_PORT_IN_STATS_READ,
 	PIPELINE_REQ_PORT_IN_ENABLE,
 	PIPELINE_REQ_PORT_IN_DISABLE,
 
+	/* Port OUT */
+	PIPELINE_REQ_PORT_OUT_STATS_READ,
+
+	/* Table */
+	PIPELINE_REQ_TABLE_STATS_READ,
+
 	PIPELINE_REQ_MAX
 };
 
+struct pipeline_msg_req_port_in_stats_read {
+	int clear;
+};
+
+struct pipeline_msg_req_port_out_stats_read {
+	int clear;
+};
+
+struct pipeline_msg_req_table_stats_read {
+	int clear;
+};
+
 struct pipeline_msg_req {
 	enum pipeline_req_type type;
 	uint32_t id; /* Port IN, port OUT or table ID */
+
+	RTE_STD_C11
+	union {
+		struct pipeline_msg_req_port_in_stats_read port_in_stats_read;
+		struct pipeline_msg_req_port_out_stats_read port_out_stats_read;
+		struct pipeline_msg_req_table_stats_read table_stats_read;
+	};
+};
+
+struct pipeline_msg_rsp_port_in_stats_read {
+	struct rte_pipeline_port_in_stats stats;
+};
+
+struct pipeline_msg_rsp_port_out_stats_read {
+	struct rte_pipeline_port_out_stats stats;
+};
+
+struct pipeline_msg_rsp_table_stats_read {
+	struct rte_pipeline_table_stats stats;
 };
 
 struct pipeline_msg_rsp {
 	int status;
+
+	RTE_STD_C11
+	union {
+		struct pipeline_msg_rsp_port_in_stats_read port_in_stats_read;
+		struct pipeline_msg_rsp_port_out_stats_read port_out_stats_read;
+		struct pipeline_msg_rsp_table_stats_read table_stats_read;
+	};
 };
 
 /**
@@ -540,6 +585,53 @@ pipeline_msg_send_recv(struct pipeline *p,
 }
 
 int
+pipeline_port_in_stats_read(const char *pipeline_name,
+	uint32_t port_id,
+	struct rte_pipeline_port_in_stats *stats,
+	int clear)
+{
+	struct pipeline *p;
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if ((pipeline_name == NULL) ||
+		(stats == NULL))
+		return -1;
+
+	p = pipeline_find(pipeline_name);
+	if ((p == NULL) ||
+		(port_id >= p->n_ports_in))
+		return -1;
+
+	/* Allocate request */
+	req = pipeline_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = PIPELINE_REQ_PORT_IN_STATS_READ;
+	req->id = port_id;
+	req->port_in_stats_read.clear = clear;
+
+	/* Send request and wait for response */
+	rsp = pipeline_msg_send_recv(p, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+	if (status)
+		memcpy(stats, &rsp->port_in_stats_read.stats, sizeof(*stats));
+
+	/* Free response */
+	pipeline_msg_free(rsp);
+
+	return status;
+}
+
+int
 pipeline_port_in_enable(const char *pipeline_name,
 	uint32_t port_id)
 {
@@ -621,6 +713,99 @@ pipeline_port_in_disable(const char *pipeline_name,
 	return status;
 }
 
+int
+pipeline_port_out_stats_read(const char *pipeline_name,
+	uint32_t port_id,
+	struct rte_pipeline_port_out_stats *stats,
+	int clear)
+{
+	struct pipeline *p;
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if ((pipeline_name == NULL) ||
+		(stats == NULL))
+		return -1;
+
+	p = pipeline_find(pipeline_name);
+	if ((p == NULL) ||
+		(port_id >= p->n_ports_out))
+		return -1;
+
+	/* Allocate request */
+	req = pipeline_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = PIPELINE_REQ_PORT_OUT_STATS_READ;
+	req->id = port_id;
+	req->port_out_stats_read.clear = clear;
+
+	/* Send request and wait for response */
+	rsp = pipeline_msg_send_recv(p, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+	if (status)
+		memcpy(stats, &rsp->port_out_stats_read.stats, sizeof(*stats));
+
+	/* Free response */
+	pipeline_msg_free(rsp);
+
+	return status;
+}
+
+int
+pipeline_table_stats_read(const char *pipeline_name,
+	uint32_t table_id,
+	struct rte_pipeline_table_stats *stats,
+	int clear)
+{
+	struct pipeline *p;
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if ((pipeline_name == NULL) ||
+		(stats == NULL))
+		return -1;
+
+	p = pipeline_find(pipeline_name);
+	if ((p == NULL) ||
+		(table_id >= p->n_tables))
+		return -1;
+
+	/* Allocate request */
+	req = pipeline_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = PIPELINE_REQ_TABLE_STATS_READ;
+	req->id = table_id;
+	req->table_stats_read.clear = clear;
+
+	/* Send request and wait for response */
+	rsp = pipeline_msg_send_recv(p, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+	if (status)
+		memcpy(stats, &rsp->table_stats_read.stats, sizeof(*stats));
+
+	/* Free response */
+	pipeline_msg_free(rsp);
+
+	return status;
+}
 
 /**
  * Data plane threads: message handling
@@ -650,6 +835,22 @@ pipeline_msg_send(struct rte_ring *msgq_rsp,
 }
 
 static struct pipeline_msg_rsp *
+pipeline_msg_handle_port_in_stats_read(struct pipeline_data *p,
+	struct pipeline_msg_req *req)
+{
+	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+	uint32_t port_id = req->id;
+	int clear = req->port_in_stats_read.clear;
+
+	rsp->status = rte_pipeline_port_in_stats_read(p->p,
+		port_id,
+		&rsp->port_in_stats_read.stats,
+		clear);
+
+	return rsp;
+}
+
+static struct pipeline_msg_rsp *
 pipeline_msg_handle_port_in_enable(struct pipeline_data *p,
 	struct pipeline_msg_req *req)
 {
@@ -675,6 +876,38 @@ pipeline_msg_handle_port_in_disable(struct pipeline_data *p,
 	return rsp;
 }
 
+static struct pipeline_msg_rsp *
+pipeline_msg_handle_port_out_stats_read(struct pipeline_data *p,
+	struct pipeline_msg_req *req)
+{
+	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+	uint32_t port_id = req->id;
+	int clear = req->port_out_stats_read.clear;
+
+	rsp->status = rte_pipeline_port_out_stats_read(p->p,
+		port_id,
+		&rsp->port_out_stats_read.stats,
+		clear);
+
+	return rsp;
+}
+
+static struct pipeline_msg_rsp *
+pipeline_msg_handle_table_stats_read(struct pipeline_data *p,
+	struct pipeline_msg_req *req)
+{
+	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+	uint32_t port_id = req->id;
+	int clear = req->table_stats_read.clear;
+
+	rsp->status = rte_pipeline_table_stats_read(p->p,
+		port_id,
+		&rsp->table_stats_read.stats,
+		clear);
+
+	return rsp;
+}
+
 static void
 pipeline_msg_handle(struct pipeline_data *p)
 {
@@ -687,6 +920,10 @@ pipeline_msg_handle(struct pipeline_data *p)
 			break;
 
 		switch (req->type) {
+		case PIPELINE_REQ_PORT_IN_STATS_READ:
+			rsp = pipeline_msg_handle_port_in_stats_read(p, req);
+			break;
+
 		case PIPELINE_REQ_PORT_IN_ENABLE:
 			rsp = pipeline_msg_handle_port_in_enable(p, req);
 			break;
@@ -695,6 +932,15 @@ pipeline_msg_handle(struct pipeline_data *p)
 			rsp = pipeline_msg_handle_port_in_disable(p, req);
 			break;
 
+		case PIPELINE_REQ_PORT_OUT_STATS_READ:
+			rsp = pipeline_msg_handle_port_out_stats_read(p, req);
+			break;
+
+		case PIPELINE_REQ_TABLE_STATS_READ:
+			rsp = pipeline_msg_handle_table_stats_read(p, req);
+			break;
+
+
 		default:
 			rsp = (struct pipeline_msg_rsp *) req;
 			rsp->status = -1;
-- 
2.9.3

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

* [dpdk-dev] [PATCH 25/37] ip_pipeline: add cli for pipeline table entries
  2018-03-09 18:23 [dpdk-dev] [PATCH 00/37] ip_pipeline: refactoring Jasvinder Singh
                   ` (23 preceding siblings ...)
  2018-03-09 18:24 ` [dpdk-dev] [PATCH 24/37] ip_pipeline: add cli to read pipeline port and table stats Jasvinder Singh
@ 2018-03-09 18:24 ` Jasvinder Singh
  2018-03-09 18:24 ` [dpdk-dev] [PATCH 26/37] ip_pipeline: add cli to delete pipeline table entry Jasvinder Singh
                   ` (11 subsequent siblings)
  36 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-09 18:24 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add commands to add pipeline table entries which contains match and
action part.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/cli.c      | 1273 +++++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/pipeline.h |   13 +
 examples/ip_pipeline/thread.c   |  749 +++++++++++++++++++++++
 3 files changed, 2035 insertions(+)

diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index dac115a..c0aa8c4 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -8,6 +8,7 @@
 #include <string.h>
 
 #include <rte_common.h>
+#include <rte_cycles.h>
 
 #include "cli.h"
 #include "kni.h"
@@ -2066,6 +2067,1261 @@ cmd_pipeline_table_stats(char **tokens,
 }
 
 /**
+ * <match> ::=
+ *
+ * match
+ *    acl
+ *       priority <priority>
+ *       ipv4 | ipv6 <sa> <sa_depth> <da> <da_depth>
+ *       <sp0> <sp1> <dp0> <dp1> <proto>
+ *    | array
+ *       pos
+ *    | hash
+ *       raw <key>
+ *       | ipv4_5tuple <sa> <da> <sp> <dp> <proto>
+ *       | ipv6_5tuple <sa> <da> <sp> <dp> <proto>
+ *       | ipv4_addr <addr>
+ *       | ipv6_addr <addr>
+ *       | qinq <svlan> <cvlan>
+ *    | lpm
+ *       ipv4 | ipv6 <addr> <depth>
+ */
+struct pkt_key_qinq {
+	uint16_t ethertype_svlan;
+	uint16_t svlan;
+	uint16_t ethertype_cvlan;
+	uint16_t cvlan;
+} __attribute__((__packed__));
+
+struct pkt_key_ipv4_5tuple {
+	uint8_t time_to_live;
+	uint8_t proto;
+	uint16_t hdr_checksum;
+	uint32_t sa;
+	uint32_t da;
+	uint16_t sp;
+	uint16_t dp;
+} __attribute__((__packed__));
+
+struct pkt_key_ipv6_5tuple {
+	uint16_t payload_length;
+	uint8_t proto;
+	uint8_t hop_limit;
+	uint8_t sa[16];
+	uint8_t da[16];
+	uint16_t sp;
+	uint16_t dp;
+} __attribute__((__packed__));
+
+struct pkt_key_ipv4_addr {
+	uint32_t addr;
+} __attribute__((__packed__));
+
+struct pkt_key_ipv6_addr {
+	uint8_t addr[16];
+} __attribute__((__packed__));
+
+static uint32_t
+parse_match(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size,
+	struct table_rule_match *m)
+{
+	memset(m, 0, sizeof(*m));
+
+	if (n_tokens < 2)
+		return 0;
+
+	if (strcmp(tokens[0], "match") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match");
+		return 0;
+	}
+
+	if (strcmp(tokens[1], "acl") == 0) {
+		if (n_tokens < 14) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+			return 0;
+		}
+
+		m->match_type = TABLE_ACL;
+
+		if (strcmp(tokens[2], "priority") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "priority");
+			return 0;
+		}
+
+		if (parser_read_uint32(&m->match.acl.priority,
+			tokens[3]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "priority");
+			return 0;
+		}
+
+		if (strcmp(tokens[4], "ipv4") == 0) {
+			struct in_addr saddr, daddr;
+
+			m->match.acl.ip_version = 1;
+
+			if (parse_ipv4_addr(tokens[5], &saddr) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID, "sa");
+				return 0;
+			}
+			m->match.acl.ipv4.sa = rte_be_to_cpu_32(saddr.s_addr);
+
+			if (parse_ipv4_addr(tokens[7], &daddr) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID, "da");
+				return 0;
+			}
+			m->match.acl.ipv4.da = rte_be_to_cpu_32(daddr.s_addr);
+		} else if (strcmp(tokens[4], "ipv6") == 0) {
+			struct in6_addr saddr, daddr;
+
+			m->match.acl.ip_version = 0;
+
+			if (parse_ipv6_addr(tokens[5], &saddr) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID, "sa");
+				return 0;
+			}
+			memcpy(m->match.acl.ipv6.sa, saddr.s6_addr, 16);
+
+			if (parse_ipv6_addr(tokens[7], &daddr) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID, "da");
+				return 0;
+			}
+			memcpy(m->match.acl.ipv6.da, daddr.s6_addr, 16);
+		} else {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+				"ipv4 or ipv6");
+			return 0;
+		}
+
+		if (parser_read_uint32(&m->match.acl.sa_depth,
+			tokens[6]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "sa_depth");
+			return 0;
+		}
+
+		if (parser_read_uint32(&m->match.acl.da_depth,
+			tokens[8]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "da_depth");
+			return 0;
+		}
+
+		if (parser_read_uint16(&m->match.acl.sp0, tokens[9]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "sp0");
+			return 0;
+		}
+
+		if (parser_read_uint16(&m->match.acl.sp1, tokens[10]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "sp1");
+			return 0;
+		}
+
+		if (parser_read_uint16(&m->match.acl.dp0, tokens[11]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "dp0");
+			return 0;
+		}
+
+		if (parser_read_uint16(&m->match.acl.dp1, tokens[12]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "dp1");
+			return 0;
+		}
+
+		if (parser_read_uint8(&m->match.acl.proto, tokens[13]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "proto");
+			return 0;
+		}
+
+		m->match.acl.proto_mask = 0xff;
+
+		return 14;
+	} /* acl */
+
+	if (strcmp(tokens[1], "array") == 0) {
+		if (n_tokens < 3) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+			return 0;
+		}
+
+		m->match_type = TABLE_ARRAY;
+
+		if (parser_read_uint32(&m->match.array.pos, tokens[2]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "pos");
+			return 0;
+		}
+
+		return 3;
+	} /* array */
+
+	if (strcmp(tokens[1], "hash") == 0) {
+		if (n_tokens < 3) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+			return 0;
+		}
+
+		m->match_type = TABLE_HASH;
+
+		if (strcmp(tokens[2], "raw") == 0) {
+			uint32_t key_size = TABLE_RULE_MATCH_SIZE_MAX;
+
+			if (n_tokens < 4) {
+				snprintf(out, out_size, MSG_ARG_MISMATCH,
+					tokens[0]);
+				return 0;
+			}
+
+			if (parse_hex_string(tokens[3],
+				m->match.hash.key, &key_size) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID, "key");
+				return 0;
+			}
+
+			return 4;
+		} /* hash raw */
+
+		if (strcmp(tokens[2], "ipv4_5tuple") == 0) {
+			struct pkt_key_ipv4_5tuple *ipv4 =
+				(struct pkt_key_ipv4_5tuple *) m->match.hash.key;
+			struct in_addr saddr, daddr;
+			uint16_t sp, dp;
+			uint8_t proto;
+
+			if (n_tokens < 8) {
+				snprintf(out, out_size, MSG_ARG_MISMATCH,
+					tokens[0]);
+				return 0;
+			}
+
+			if (parse_ipv4_addr(tokens[3], &saddr) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID, "sa");
+				return 0;
+			}
+
+			if (parse_ipv4_addr(tokens[4], &daddr) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID, "da");
+				return 0;
+			}
+
+			if (parser_read_uint16(&sp, tokens[5]) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID, "sp");
+				return 0;
+			}
+
+			if (parser_read_uint16(&dp, tokens[6]) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID, "dp");
+				return 0;
+			}
+
+			if (parser_read_uint8(&proto, tokens[7]) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID,
+					"proto");
+				return 0;
+			}
+
+			ipv4->sa = saddr.s_addr;
+			ipv4->da = daddr.s_addr;
+			ipv4->sp = rte_cpu_to_be_16(sp);
+			ipv4->dp = rte_cpu_to_be_16(dp);
+			ipv4->proto = proto;
+
+			return 8;
+		} /* hash ipv4_5tuple */
+
+		if (strcmp(tokens[2], "ipv6_5tuple") == 0) {
+			struct pkt_key_ipv6_5tuple *ipv6 =
+				(struct pkt_key_ipv6_5tuple *) m->match.hash.key;
+			struct in6_addr saddr, daddr;
+			uint16_t sp, dp;
+			uint8_t proto;
+
+			if (n_tokens < 8) {
+				snprintf(out, out_size, MSG_ARG_MISMATCH,
+					tokens[0]);
+				return 0;
+			}
+
+			if (parse_ipv6_addr(tokens[3], &saddr) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID, "sa");
+				return 0;
+			}
+
+			if (parse_ipv6_addr(tokens[4], &daddr) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID, "da");
+				return 0;
+			}
+
+			if (parser_read_uint16(&sp, tokens[5]) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID, "sp");
+				return 0;
+			}
+
+			if (parser_read_uint16(&dp, tokens[6]) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID, "dp");
+				return 0;
+			}
+
+			if (parser_read_uint8(&proto, tokens[7]) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID,
+					"proto");
+				return 0;
+			}
+
+			memcpy(ipv6->sa, saddr.s6_addr, 16);
+			memcpy(ipv6->da, daddr.s6_addr, 16);
+			ipv6->sp = rte_cpu_to_be_16(sp);
+			ipv6->dp = rte_cpu_to_be_16(dp);
+			ipv6->proto = proto;
+
+			return 8;
+		} /* hash ipv6_5tuple */
+
+		if (strcmp(tokens[2], "ipv4_addr") == 0) {
+			struct pkt_key_ipv4_addr *ipv4_addr =
+				(struct pkt_key_ipv4_addr *) m->match.hash.key;
+			struct in_addr addr;
+
+			if (n_tokens < 4) {
+				snprintf(out, out_size, MSG_ARG_MISMATCH,
+					tokens[0]);
+				return 0;
+			}
+
+			if (parse_ipv4_addr(tokens[3], &addr) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID,
+					"addr");
+				return 0;
+			}
+
+			ipv4_addr->addr = addr.s_addr;
+
+			return 4;
+		} /* hash ipv4_addr */
+
+		if (strcmp(tokens[2], "ipv6_addr") == 0) {
+			struct pkt_key_ipv6_addr *ipv6_addr =
+				(struct pkt_key_ipv6_addr *) m->match.hash.key;
+			struct in6_addr addr;
+
+			if (n_tokens < 4) {
+				snprintf(out, out_size, MSG_ARG_MISMATCH,
+					tokens[0]);
+				return 0;
+			}
+
+			if (parse_ipv6_addr(tokens[3], &addr) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID,
+					"addr");
+				return 0;
+			}
+
+			memcpy(ipv6_addr->addr, addr.s6_addr, 16);
+
+			return 4;
+		} /* hash ipv6_5tuple */
+
+		if (strcmp(tokens[2], "qinq") == 0) {
+			struct pkt_key_qinq *qinq =
+				(struct pkt_key_qinq *) m->match.hash.key;
+			uint16_t svlan, cvlan;
+
+			if (n_tokens < 5) {
+				snprintf(out, out_size, MSG_ARG_MISMATCH,
+					tokens[0]);
+				return 0;
+			}
+
+			if ((parser_read_uint16(&svlan, tokens[3]) != 0) ||
+				(svlan > 0xFFF)) {
+				snprintf(out, out_size, MSG_ARG_INVALID,
+					"svlan");
+				return 0;
+			}
+
+			if ((parser_read_uint16(&cvlan, tokens[4]) != 0) ||
+				(cvlan > 0xFFF)) {
+				snprintf(out, out_size, MSG_ARG_INVALID,
+					"cvlan");
+				return 0;
+			}
+
+			qinq->svlan = rte_cpu_to_be_16(svlan);
+			qinq->cvlan = rte_cpu_to_be_16(cvlan);
+
+			return 5;
+		} /* hash qinq */
+
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return 0;
+	} /* hash */
+
+	if (strcmp(tokens[1], "lpm") == 0) {
+		if (n_tokens < 5) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+			return 0;
+		}
+
+		m->match_type = TABLE_LPM;
+
+		if (strcmp(tokens[2], "ipv4") == 0) {
+			struct in_addr addr;
+
+			m->match.lpm.ip_version = 1;
+
+			if (parse_ipv4_addr(tokens[3], &addr) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID,
+					"addr");
+				return 0;
+			}
+
+			m->match.lpm.ipv4 = rte_be_to_cpu_32(addr.s_addr);
+		} else if (strcmp(tokens[2], "ipv6") == 0) {
+			struct in6_addr addr;
+
+			m->match.lpm.ip_version = 0;
+
+			if (parse_ipv6_addr(tokens[3], &addr) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID,
+					"addr");
+				return 0;
+			}
+
+			memcpy(m->match.lpm.ipv6, addr.s6_addr, 16);
+		} else {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"ipv4 or ipv6");
+			return 0;
+		}
+
+		if (parser_read_uint8(&m->match.lpm.depth, tokens[4]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "depth");
+			return 0;
+		}
+
+		return 5;
+	} /* lpm */
+
+	snprintf(out, out_size, MSG_ARG_MISMATCH,
+		"acl or array or hash or lpm");
+	return 0;
+}
+
+/**
+ * table_action ::=
+ *
+ * action
+ *    fwd drop | port <port_id> | table <table_id>
+ *    [meter
+ *       tc0 meter <meter_profile_id> policer g <pa> y <pa> r <pa>
+ *       [tc1 meter <meter_profile_id> policer g <pa> y <pa> r <pa>
+ *        tc2 meter <meter_profile_id> policer g <pa> y <pa> r <pa>
+ *        tc3 meter <meter_profile_id> policer g <pa> y <pa> r <pa>]]
+ *    [tm subport <subport_id> pipe <pipe_id>]
+ *    [encap
+ *       ether <da> <sa>
+ *       | vlan <da> <sa> <pcp> <dei> <vid>
+ *       | qinq <da> <sa> <pcp> <dei> <vid> <pcp> <dei> <vid>
+ *       | mpls unicast | multicast
+ *          <da> <sa>
+ *          label0 <label> <tc> <ttl>
+ *          [label1 <label> <tc> <ttl>
+ *          [label2 <label> <tc> <ttl>
+ *          [label3 <label> <tc> <ttl>]]]
+ *       | pppoe <da> <sa> <session_id>]
+ *    [nat ipv4 | ipv6 <addr> <port>]
+ *    [ttl dec | keep]
+ *    [stats]
+ *    [time]
+ *
+ * where:
+ *    <pa> ::= g | y | r | drop
+ */
+static uint32_t
+parse_table_action_fwd(char **tokens,
+	uint32_t n_tokens,
+	struct table_rule_action *a)
+{
+	if ((n_tokens == 0) || (strcmp(tokens[0], "fwd") != 0))
+		return 0;
+
+	tokens++;
+	n_tokens--;
+
+	if (n_tokens && (strcmp(tokens[0], "drop") == 0)) {
+		a->fwd.action = RTE_PIPELINE_ACTION_DROP;
+		a->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
+		return 1 + 1;
+	}
+
+	if (n_tokens && (strcmp(tokens[0], "port") == 0)) {
+		uint32_t id;
+
+		if ((n_tokens < 2) ||
+			parser_read_uint32(&id, tokens[1]))
+			return 0;
+
+		a->fwd.action = RTE_PIPELINE_ACTION_PORT;
+		a->fwd.id = id;
+		a->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
+		return 1 + 2;
+	}
+
+	if (n_tokens && (strcmp(tokens[0], "table") == 0)) {
+		uint32_t id;
+
+		if ((n_tokens < 2) ||
+			parser_read_uint32(&id, tokens[1]))
+			return 0;
+
+		a->fwd.action = RTE_PIPELINE_ACTION_TABLE;
+		a->fwd.id = id;
+		a->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
+		return 1 + 2;
+	}
+
+	return 0;
+}
+
+static int
+parse_policer_action(char *token, enum rte_table_action_policer *a)
+{
+	if (strcmp(token, "g") == 0) {
+		*a = RTE_TABLE_ACTION_POLICER_COLOR_GREEN;
+		return 0;
+	}
+
+	if (strcmp(token, "y") == 0) {
+		*a = RTE_TABLE_ACTION_POLICER_COLOR_YELLOW;
+		return 0;
+	}
+
+	if (strcmp(token, "r") == 0) {
+		*a = RTE_TABLE_ACTION_POLICER_COLOR_RED;
+		return 0;
+	}
+
+	if (strcmp(token, "drop") == 0) {
+		*a = RTE_TABLE_ACTION_POLICER_DROP;
+		return 0;
+	}
+
+	return -1;
+}
+
+static uint32_t
+parse_table_action_meter_tc(char **tokens,
+	uint32_t n_tokens,
+	struct rte_table_action_mtr_tc_params *mtr)
+{
+	if ((n_tokens < 9) ||
+		strcmp(tokens[0], "meter") ||
+		parser_read_uint32(&mtr->meter_profile_id, tokens[1]) ||
+		strcmp(tokens[2], "policer") ||
+		strcmp(tokens[3], "g") ||
+		parse_policer_action(tokens[4], &mtr->policer[e_RTE_METER_GREEN]) ||
+		strcmp(tokens[5], "y") ||
+		parse_policer_action(tokens[6], &mtr->policer[e_RTE_METER_YELLOW]) ||
+		strcmp(tokens[7], "r") ||
+		parse_policer_action(tokens[8], &mtr->policer[e_RTE_METER_RED]))
+		return 0;
+
+	return 9;
+}
+
+static uint32_t
+parse_table_action_meter(char **tokens,
+	uint32_t n_tokens,
+	struct table_rule_action *a)
+{
+	if ((n_tokens == 0) || strcmp(tokens[0], "meter"))
+		return 0;
+
+	tokens++;
+	n_tokens--;
+
+	if ((n_tokens < 10) ||
+		strcmp(tokens[0], "tc0") ||
+		(parse_table_action_meter_tc(tokens + 1,
+			n_tokens - 1,
+			&a->mtr.mtr[0]) == 0))
+		return 0;
+
+	tokens += 10;
+	n_tokens -= 10;
+
+	if ((n_tokens == 0) || strcmp(tokens[0], "tc1")) {
+		a->mtr.tc_mask = 1;
+		a->action_mask |= 1 << RTE_TABLE_ACTION_MTR;
+		return 1 + 10;
+	}
+
+	if ((n_tokens < 30) ||
+		(parse_table_action_meter_tc(tokens + 1,
+			n_tokens - 1, &a->mtr.mtr[1]) == 0) ||
+		strcmp(tokens[10], "tc2") ||
+		(parse_table_action_meter_tc(tokens + 11,
+			n_tokens - 11, &a->mtr.mtr[2]) == 0) ||
+		strcmp(tokens[20], "tc3") ||
+		(parse_table_action_meter_tc(tokens + 21,
+			n_tokens - 21, &a->mtr.mtr[3]) == 0))
+		return 0;
+
+	a->mtr.tc_mask = 0xF;
+	a->action_mask |= 1 << RTE_TABLE_ACTION_MTR;
+	return 1 + 10 + 3 * 10;
+}
+
+static uint32_t
+parse_table_action_tm(char **tokens,
+	uint32_t n_tokens,
+	struct table_rule_action *a)
+{
+	uint32_t subport_id, pipe_id;
+
+	if ((n_tokens < 5) ||
+		strcmp(tokens[0], "tm") ||
+		strcmp(tokens[1], "subport") ||
+		parser_read_uint32(&subport_id, tokens[2]) ||
+		strcmp(tokens[3], "pipe") ||
+		parser_read_uint32(&pipe_id, tokens[4]))
+		return 0;
+
+	a->tm.subport_id = subport_id;
+	a->tm.pipe_id = pipe_id;
+	a->action_mask |= 1 << RTE_TABLE_ACTION_TM;
+	return 5;
+}
+
+static uint32_t
+parse_table_action_encap(char **tokens,
+	uint32_t n_tokens,
+	struct table_rule_action *a)
+{
+	if ((n_tokens == 0) || strcmp(tokens[0], "encap"))
+		return 0;
+
+	tokens++;
+	n_tokens--;
+
+	/* ether */
+	if (n_tokens && (strcmp(tokens[0], "ether") == 0)) {
+		if ((n_tokens < 3) ||
+			parse_mac_addr(tokens[1], &a->encap.ether.ether.da) ||
+			parse_mac_addr(tokens[2], &a->encap.ether.ether.sa))
+			return 0;
+
+		a->encap.type = RTE_TABLE_ACTION_ENCAP_ETHER;
+		a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
+		return 1 + 3;
+	}
+
+	/* vlan */
+	if (n_tokens && (strcmp(tokens[0], "vlan") == 0)) {
+		uint32_t pcp, dei, vid;
+
+		if ((n_tokens < 6) ||
+			parse_mac_addr(tokens[1], &a->encap.vlan.ether.da) ||
+			parse_mac_addr(tokens[2], &a->encap.vlan.ether.sa) ||
+			parser_read_uint32(&pcp, tokens[3]) ||
+			(pcp > 0x7) ||
+			parser_read_uint32(&dei, tokens[4]) ||
+			(dei > 0x1) ||
+			parser_read_uint32(&vid, tokens[5]) ||
+			(vid > 0xFFF))
+			return 0;
+
+		a->encap.vlan.vlan.pcp = pcp & 0x7;
+		a->encap.vlan.vlan.dei = dei & 0x1;
+		a->encap.vlan.vlan.vid = vid & 0xFFF;
+		a->encap.type = RTE_TABLE_ACTION_ENCAP_VLAN;
+		a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
+		return 1 + 6;
+	}
+
+	/* qinq */
+	if (n_tokens && (strcmp(tokens[0], "qinq") == 0)) {
+		uint32_t svlan_pcp, svlan_dei, svlan_vid;
+		uint32_t cvlan_pcp, cvlan_dei, cvlan_vid;
+
+		if ((n_tokens < 9) ||
+			parse_mac_addr(tokens[1], &a->encap.qinq.ether.da) ||
+			parse_mac_addr(tokens[2], &a->encap.qinq.ether.sa) ||
+			parser_read_uint32(&svlan_pcp, tokens[3]) ||
+			(svlan_pcp > 0x7) ||
+			parser_read_uint32(&svlan_dei, tokens[4]) ||
+			(svlan_dei > 0x1) ||
+			parser_read_uint32(&svlan_vid, tokens[5]) ||
+			(svlan_vid > 0xFFF) ||
+			parser_read_uint32(&cvlan_pcp, tokens[6]) ||
+			(cvlan_pcp > 0x7) ||
+			parser_read_uint32(&cvlan_dei, tokens[7]) ||
+			(cvlan_dei > 0x1) ||
+			parser_read_uint32(&cvlan_vid, tokens[8]) ||
+			(cvlan_vid > 0xFFF))
+			return 0;
+
+		a->encap.qinq.svlan.pcp = svlan_pcp & 0x7;
+		a->encap.qinq.svlan.dei = svlan_dei & 0x1;
+		a->encap.qinq.svlan.vid = svlan_vid & 0xFFF;
+		a->encap.qinq.cvlan.pcp = cvlan_pcp & 0x7;
+		a->encap.qinq.cvlan.dei = cvlan_dei & 0x1;
+		a->encap.qinq.cvlan.vid = cvlan_vid & 0xFFF;
+		a->encap.type = RTE_TABLE_ACTION_ENCAP_QINQ;
+		a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
+		return 1 + 9;
+	}
+
+	/* mpls */
+	if (n_tokens && (strcmp(tokens[0], "mpls") == 0)) {
+		uint32_t label, tc, ttl;
+
+		if (n_tokens < 8)
+			return 0;
+
+		if (strcmp(tokens[1], "unicast") == 0)
+			a->encap.mpls.unicast = 1;
+		else if (strcmp(tokens[1], "multicast") == 0)
+			a->encap.mpls.unicast = 0;
+		else
+			return 0;
+
+		if (parse_mac_addr(tokens[2], &a->encap.mpls.ether.da) ||
+			parse_mac_addr(tokens[3], &a->encap.mpls.ether.sa) ||
+			strcmp(tokens[4], "label0") ||
+			parser_read_uint32(&label, tokens[5]) ||
+			(label > 0xFFFFF) ||
+			parser_read_uint32(&tc, tokens[6]) ||
+			(tc > 0x7) ||
+			parser_read_uint32(&ttl, tokens[7]) ||
+			(ttl > 0x3F))
+			return 0;
+
+		a->encap.mpls.mpls[0].label = label;
+		a->encap.mpls.mpls[0].tc = tc;
+		a->encap.mpls.mpls[0].ttl = ttl;
+
+		tokens += 8;
+		n_tokens -= 8;
+
+		if ((n_tokens == 0) || strcmp(tokens[0], "label1")) {
+			a->encap.mpls.mpls_count = 1;
+			a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS;
+			a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
+			return 1 + 8;
+		}
+
+		if ((n_tokens < 4) ||
+			parser_read_uint32(&label, tokens[1]) ||
+			(label > 0xFFFFF) ||
+			parser_read_uint32(&tc, tokens[2]) ||
+			(tc > 0x7) ||
+			parser_read_uint32(&ttl, tokens[3]) ||
+			(ttl > 0x3F))
+			return 0;
+
+		a->encap.mpls.mpls[1].label = label;
+		a->encap.mpls.mpls[1].tc = tc;
+		a->encap.mpls.mpls[1].ttl = ttl;
+
+		tokens += 4;
+		n_tokens -= 4;
+
+		if ((n_tokens == 0) || strcmp(tokens[0], "label2")) {
+			a->encap.mpls.mpls_count = 2;
+			a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS;
+			a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
+			return 1 + 8 + 4;
+		}
+
+		if ((n_tokens < 4) ||
+			parser_read_uint32(&label, tokens[1]) ||
+			(label > 0xFFFFF) ||
+			parser_read_uint32(&tc, tokens[2]) ||
+			(tc > 0x7) ||
+			parser_read_uint32(&ttl, tokens[3]) ||
+			(ttl > 0x3F))
+			return 0;
+
+		a->encap.mpls.mpls[2].label = label;
+		a->encap.mpls.mpls[2].tc = tc;
+		a->encap.mpls.mpls[2].ttl = ttl;
+
+		tokens += 4;
+		n_tokens -= 4;
+
+		if ((n_tokens == 0) || strcmp(tokens[0], "label3")) {
+			a->encap.mpls.mpls_count = 3;
+			a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS;
+			a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
+			return 1 + 8 + 4 + 4;
+		}
+
+		if ((n_tokens < 4) ||
+			parser_read_uint32(&label, tokens[1]) ||
+			(label > 0xFFFFF) ||
+			parser_read_uint32(&tc, tokens[2]) ||
+			(tc > 0x7) ||
+			parser_read_uint32(&ttl, tokens[3]) ||
+			(ttl > 0x3F))
+			return 0;
+
+		a->encap.mpls.mpls[3].label = label;
+		a->encap.mpls.mpls[3].tc = tc;
+		a->encap.mpls.mpls[3].ttl = ttl;
+
+		a->encap.mpls.mpls_count = 4;
+		a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS;
+		a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
+		return 1 + 8 + 4 + 4 + 4;
+	}
+
+	/* pppoe */
+	if (n_tokens && (strcmp(tokens[0], "pppoe") == 0)) {
+		if ((n_tokens < 4) ||
+			parse_mac_addr(tokens[1], &a->encap.pppoe.ether.da) ||
+			parse_mac_addr(tokens[2], &a->encap.pppoe.ether.sa) ||
+			parser_read_uint16(&a->encap.pppoe.pppoe.session_id,
+				tokens[3]))
+			return 0;
+
+		a->encap.type = RTE_TABLE_ACTION_ENCAP_PPPOE;
+		a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
+		return 1 + 4;
+	}
+
+	return 0;
+}
+
+static uint32_t
+parse_table_action_nat(char **tokens,
+	uint32_t n_tokens,
+	struct table_rule_action *a)
+{
+	if ((n_tokens < 4) ||
+		strcmp(tokens[0], "nat"))
+		return 0;
+
+	if (strcmp(tokens[1], "ipv4") == 0) {
+		struct in_addr addr;
+		uint16_t port;
+
+		if (parse_ipv4_addr(tokens[2], &addr) ||
+			parser_read_uint16(&port, tokens[3]))
+			return 0;
+
+		a->nat.ip_version = 1;
+		a->nat.addr.ipv4 = rte_be_to_cpu_32(addr.s_addr);
+		a->nat.port = port;
+		a->action_mask |= 1 << RTE_TABLE_ACTION_NAT;
+		return 4;
+	}
+
+	if (strcmp(tokens[1], "ipv6") == 0) {
+		struct in6_addr addr;
+		uint16_t port;
+
+		if (parse_ipv6_addr(tokens[2], &addr) ||
+			parser_read_uint16(&port, tokens[3]))
+			return 0;
+
+		a->nat.ip_version = 0;
+		memcpy(a->nat.addr.ipv6, addr.s6_addr, 16);
+		a->nat.port = port;
+		a->action_mask |= 1 << RTE_TABLE_ACTION_NAT;
+		return 4;
+	}
+
+	return 0;
+}
+
+static uint32_t
+parse_table_action_ttl(char **tokens,
+	uint32_t n_tokens,
+	struct table_rule_action *a)
+{
+	if ((n_tokens < 2) ||
+		strcmp(tokens[0], "ttl"))
+		return 0;
+
+	if (strcmp(tokens[1], "dec") == 0)
+		a->ttl.decrement = 1;
+	else if (strcmp(tokens[1], "keep") == 0)
+		a->ttl.decrement = 0;
+	else
+		return 0;
+
+	a->action_mask |= 1 << RTE_TABLE_ACTION_TTL;
+	return 2;
+}
+
+static uint32_t
+parse_table_action_stats(char **tokens,
+	uint32_t n_tokens,
+	struct table_rule_action *a)
+{
+	if ((n_tokens < 1) ||
+		strcmp(tokens[0], "stats"))
+		return 0;
+
+	a->stats.n_packets = 0;
+	a->stats.n_bytes = 0;
+	a->action_mask |= 1 << RTE_TABLE_ACTION_STATS;
+	return 1;
+}
+
+static uint32_t
+parse_table_action_time(char **tokens,
+	uint32_t n_tokens,
+	struct table_rule_action *a)
+{
+	if ((n_tokens < 1) ||
+		strcmp(tokens[0], "time"))
+		return 0;
+
+	a->time.time = rte_rdtsc();
+	a->action_mask |= 1 << RTE_TABLE_ACTION_TIME;
+	return 1;
+}
+
+static uint32_t
+parse_table_action(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size,
+	struct table_rule_action *a)
+{
+	uint32_t n_tokens0 = n_tokens;
+
+	memset(a, 0, sizeof(*a));
+
+	if ((n_tokens < 2) ||
+		strcmp(tokens[0], "action"))
+		return 0;
+
+	tokens++;
+	n_tokens--;
+
+	if (n_tokens && (strcmp(tokens[0], "fwd") == 0)) {
+		uint32_t n;
+
+		n = parse_table_action_fwd(tokens, n_tokens, a);
+		if (n == 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID,
+				"action fwd");
+			return 0;
+		}
+
+		tokens += n;
+		n_tokens -= n;
+	}
+
+	if (n_tokens && (strcmp(tokens[0], "meter") == 0)) {
+		uint32_t n;
+
+		n = parse_table_action_meter(tokens, n_tokens, a);
+		if (n == 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID,
+				"action meter");
+			return 0;
+		}
+
+		tokens += n;
+		n_tokens -= n;
+	}
+
+	if (n_tokens && (strcmp(tokens[0], "tm") == 0)) {
+		uint32_t n;
+
+		n = parse_table_action_tm(tokens, n_tokens, a);
+		if (n == 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID,
+				"action tm");
+			return 0;
+		}
+
+		tokens += n;
+		n_tokens -= n;
+	}
+
+	if (n_tokens && (strcmp(tokens[0], "encap") == 0)) {
+		uint32_t n;
+
+		n = parse_table_action_encap(tokens, n_tokens, a);
+		if (n == 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID,
+				"action encap");
+			return 0;
+		}
+
+		tokens += n;
+		n_tokens -= n;
+	}
+
+	if (n_tokens && (strcmp(tokens[0], "nat") == 0)) {
+		uint32_t n;
+
+		n = parse_table_action_nat(tokens, n_tokens, a);
+		if (n == 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID,
+				"action nat");
+			return 0;
+		}
+
+		tokens += n;
+		n_tokens -= n;
+	}
+
+	if (n_tokens && (strcmp(tokens[0], "ttl") == 0)) {
+		uint32_t n;
+
+		n = parse_table_action_ttl(tokens, n_tokens, a);
+		if (n == 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID,
+				"action ttl");
+			return 0;
+		}
+
+		tokens += n;
+		n_tokens -= n;
+	}
+
+	if (n_tokens && (strcmp(tokens[0], "stats") == 0)) {
+		uint32_t n;
+
+		n = parse_table_action_stats(tokens, n_tokens, a);
+		if (n == 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID,
+				"action stats");
+			return 0;
+		}
+
+		tokens += n;
+		n_tokens -= n;
+	}
+
+	if (n_tokens && (strcmp(tokens[0], "time") == 0)) {
+		uint32_t n;
+
+		n = parse_table_action_time(tokens, n_tokens, a);
+		if (n == 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID,
+				"action time");
+			return 0;
+		}
+
+		tokens += n;
+		n_tokens -= n;
+	}
+
+	if (n_tokens0 - n_tokens == 1) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "action");
+		return 0;
+	}
+
+	return n_tokens0 - n_tokens;
+}
+
+/**
+ * pipeline <pipeline_name> table <table_id> rule add
+ *    match <match>
+ *    action <table_action>
+ */
+static void
+cmd_pipeline_table_rule_add(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct table_rule_match m;
+	struct table_rule_action a;
+	char *pipeline_name;
+	void *data;
+	uint32_t table_id, t0, n_tokens_parsed;
+	int status;
+
+	if (n_tokens < 8) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "table") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
+		return;
+	}
+
+	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
+		return;
+	}
+
+	if (strcmp(tokens[4], "rule") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
+		return;
+	}
+
+	if (strcmp(tokens[5], "add") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
+		return;
+	}
+
+	t0 = 6;
+
+	/* match */
+	n_tokens_parsed = parse_match(tokens + t0,
+		n_tokens - t0,
+		out,
+		out_size,
+		&m);
+	if (n_tokens_parsed == 0)
+		return;
+	t0 += n_tokens_parsed;
+
+	/* action */
+	n_tokens_parsed = parse_table_action(tokens + t0,
+		n_tokens - t0,
+		out,
+		out_size,
+		&a);
+	if (n_tokens_parsed == 0)
+		return;
+	t0 += n_tokens_parsed;
+
+	if (t0 != n_tokens) {
+		snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
+		return;
+	}
+
+	status = pipeline_table_rule_add(pipeline_name, table_id,
+		&m, &a, &data);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
+ * pipeline <pipeline_name> table <table_id> rule add
+ *    match
+ *       default
+ *    action
+ *       fwd drop | port <port_id> | table <table_id>
+ */
+static void
+cmd_pipeline_table_rule_add_default(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct table_rule_action action;
+	void *data;
+	char *pipeline_name;
+	uint32_t table_id;
+	int status;
+
+	if ((n_tokens != 11) && (n_tokens != 12)) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "table") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
+		return;
+	}
+
+	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
+		return;
+	}
+
+	if (strcmp(tokens[4], "rule") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
+		return;
+	}
+
+	if (strcmp(tokens[5], "add") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
+		return;
+	}
+
+	if (strcmp(tokens[6], "match") != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "match");
+		return;
+	}
+
+	if (strcmp(tokens[7], "default") != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "default");
+		return;
+	}
+
+	if (strcmp(tokens[8], "action") != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "action");
+		return;
+	}
+
+	if (strcmp(tokens[9], "fwd") != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "fwd");
+		return;
+	}
+
+	action.action_mask = 1 << RTE_TABLE_ACTION_FWD;
+
+	if (strcmp(tokens[10], "drop") == 0) {
+		if (n_tokens != 11) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+			return;
+		}
+
+		action.fwd.action = RTE_PIPELINE_ACTION_DROP;
+	} else if (strcmp(tokens[10], "port") == 0) {
+		uint32_t id;
+
+		if (n_tokens != 12) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+			return;
+		}
+
+		if (parser_read_uint32(&id, tokens[11]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
+			return;
+		}
+
+		action.fwd.action = RTE_PIPELINE_ACTION_PORT;
+		action.fwd.id = id;
+	} else if (strcmp(tokens[10], "table") == 0) {
+		uint32_t id;
+
+		if (n_tokens != 12) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+			return;
+		}
+
+		if (parser_read_uint32(&id, tokens[11]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
+			return;
+		}
+
+		action.fwd.action = RTE_PIPELINE_ACTION_TABLE;
+		action.fwd.id = id;
+	} else {
+		snprintf(out, out_size, MSG_ARG_INVALID,
+			"drop or port or table");
+		return;
+	}
+
+	status = pipeline_table_rule_add_default(pipeline_name,
+		table_id,
+		&action,
+		&data);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
  * thread <thread_id> pipeline <pipeline_name> enable
  */
 static void
@@ -2315,6 +3571,23 @@ cli_process(char *in, char *out, size_t out_size)
 				out, out_size);
 			return;
 		}
+
+		if ((n_tokens >= 7) &&
+			(strcmp(tokens[2], "table") == 0) &&
+			(strcmp(tokens[4], "rule") == 0) &&
+			(strcmp(tokens[5], "add") == 0) &&
+			(strcmp(tokens[6], "match") == 0)) {
+			if ((n_tokens >= 8) &&
+				(strcmp(tokens[7], "default") == 0)) {
+				cmd_pipeline_table_rule_add_default(tokens,
+					n_tokens, out, out_size);
+				return;
+			}
+
+			cmd_pipeline_table_rule_add(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
 	}
 
 	if (strcmp(tokens[0], "thread") == 0) {
diff --git a/examples/ip_pipeline/pipeline.h b/examples/ip_pipeline/pipeline.h
index 9b2c295..9351024 100644
--- a/examples/ip_pipeline/pipeline.h
+++ b/examples/ip_pipeline/pipeline.h
@@ -288,4 +288,17 @@ pipeline_table_stats_read(const char *pipeline_name,
 	struct rte_pipeline_table_stats *stats,
 	int clear);
 
+int
+pipeline_table_rule_add(const char *pipeline_name,
+	uint32_t table_id,
+	struct table_rule_match *match,
+	struct table_rule_action *action,
+	void **data);
+
+int
+pipeline_table_rule_add_default(const char *pipeline_name,
+	uint32_t table_id,
+	struct table_rule_action *action,
+	void **data);
+
 #endif /* _INCLUDE_PIPELINE_H_ */
diff --git a/examples/ip_pipeline/thread.c b/examples/ip_pipeline/thread.c
index a18a820..be12d20 100644
--- a/examples/ip_pipeline/thread.c
+++ b/examples/ip_pipeline/thread.c
@@ -493,6 +493,8 @@ enum pipeline_req_type {
 
 	/* Table */
 	PIPELINE_REQ_TABLE_STATS_READ,
+	PIPELINE_REQ_TABLE_RULE_ADD,
+	PIPELINE_REQ_TABLE_RULE_ADD_DEFAULT,
 
 	PIPELINE_REQ_MAX
 };
@@ -509,6 +511,15 @@ struct pipeline_msg_req_table_stats_read {
 	int clear;
 };
 
+struct pipeline_msg_req_table_rule_add {
+	struct table_rule_match match;
+	struct table_rule_action action;
+};
+
+struct pipeline_msg_req_table_rule_add_default {
+	struct table_rule_action action;
+};
+
 struct pipeline_msg_req {
 	enum pipeline_req_type type;
 	uint32_t id; /* Port IN, port OUT or table ID */
@@ -518,6 +529,8 @@ struct pipeline_msg_req {
 		struct pipeline_msg_req_port_in_stats_read port_in_stats_read;
 		struct pipeline_msg_req_port_out_stats_read port_out_stats_read;
 		struct pipeline_msg_req_table_stats_read table_stats_read;
+		struct pipeline_msg_req_table_rule_add table_rule_add;
+		struct pipeline_msg_req_table_rule_add_default table_rule_add_default;
 	};
 };
 
@@ -533,6 +546,14 @@ struct pipeline_msg_rsp_table_stats_read {
 	struct rte_pipeline_table_stats stats;
 };
 
+struct pipeline_msg_rsp_table_rule_add {
+	void *data;
+};
+
+struct pipeline_msg_rsp_table_rule_add_default {
+	void *data;
+};
+
 struct pipeline_msg_rsp {
 	int status;
 
@@ -541,6 +562,8 @@ struct pipeline_msg_rsp {
 		struct pipeline_msg_rsp_port_in_stats_read port_in_stats_read;
 		struct pipeline_msg_rsp_port_out_stats_read port_out_stats_read;
 		struct pipeline_msg_rsp_table_stats_read table_stats_read;
+		struct pipeline_msg_rsp_table_rule_add table_rule_add;
+		struct pipeline_msg_rsp_table_rule_add_default table_rule_add_default;
 	};
 };
 
@@ -807,6 +830,270 @@ pipeline_table_stats_read(const char *pipeline_name,
 	return status;
 }
 
+static int
+match_check(struct table_rule_match *match,
+	struct pipeline *p,
+	uint32_t table_id)
+{
+	struct table *table;
+
+	if ((match == NULL) ||
+		(p == NULL) ||
+		(table_id >= p->n_tables))
+		return -1;
+
+	table = &p->table[table_id];
+	if (match->match_type != table->params.match_type)
+		return -1;
+
+	switch (match->match_type) {
+	case TABLE_ACL:
+	{
+		struct table_acl_params *t = &table->params.match.acl;
+		struct table_rule_match_acl *r = &match->match.acl;
+
+		if ((r->ip_version && (t->ip_version == 0)) ||
+			((r->ip_version == 0) && t->ip_version))
+			return -1;
+
+		if (r->ip_version) {
+			if ((r->sa_depth > 32) ||
+				(r->da_depth > 32))
+				return -1;
+		} else {
+			if ((r->sa_depth > 128) ||
+				(r->da_depth > 128))
+				return -1;
+		}
+		return 0;
+	}
+
+	case TABLE_ARRAY:
+		return 0;
+
+	case TABLE_HASH:
+		return 0;
+
+	case TABLE_LPM:
+	{
+		struct table_lpm_params *t = &table->params.match.lpm;
+		struct table_rule_match_lpm *r = &match->match.lpm;
+
+		if ((r->ip_version && (t->key_size != 4)) ||
+			((r->ip_version == 0) && (t->key_size != 16)))
+			return -1;
+
+		if (r->ip_version) {
+			if (r->depth > 32)
+				return -1;
+		} else {
+			if (r->depth > 128)
+				return -1;
+		}
+		return 0;
+	}
+
+	case TABLE_STUB:
+		return -1;
+
+	default:
+		return -1;
+	}
+}
+
+static int
+action_check(struct table_rule_action *action,
+	struct pipeline *p,
+	uint32_t table_id)
+{
+	struct table_action_profile *ap;
+
+	if ((action == NULL) ||
+		(p == NULL) ||
+		(table_id >= p->n_tables))
+		return -1;
+
+	ap = p->table[table_id].ap;
+	if (action->action_mask != ap->params.action_mask)
+		return -1;
+
+	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_FWD)) {
+		if ((action->fwd.action == RTE_PIPELINE_ACTION_PORT) &&
+			(action->fwd.id >= p->n_ports_out))
+			return -1;
+
+		if ((action->fwd.action == RTE_PIPELINE_ACTION_TABLE) &&
+			(action->fwd.id >= p->n_tables))
+			return -1;
+	}
+
+	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) {
+		uint32_t tc_mask0 = (1 << ap->params.mtr.n_tc) - 1;
+		uint32_t tc_mask1 = action->mtr.tc_mask;
+
+		if (tc_mask1 != tc_mask0)
+			return -1;
+	}
+
+	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_TM)) {
+		uint32_t n_subports_per_port =
+			ap->params.tm.n_subports_per_port;
+		uint32_t n_pipes_per_subport =
+			ap->params.tm.n_pipes_per_subport;
+		uint32_t subport_id = action->tm.subport_id;
+		uint32_t pipe_id = action->tm.pipe_id;
+
+		if ((subport_id >= n_subports_per_port) ||
+			(pipe_id >= n_pipes_per_subport))
+			return -1;
+	}
+
+	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_ENCAP)) {
+		uint64_t encap_mask = ap->params.encap.encap_mask;
+		enum rte_table_action_encap_type type = action->encap.type;
+
+		if ((encap_mask & (1LLU << type)) == 0)
+			return -1;
+	}
+
+	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_NAT)) {
+		int ip_version0 = ap->params.common.ip_version;
+		int ip_version1 = action->nat.ip_version;
+
+		if ((ip_version1 && (ip_version0 == 0)) ||
+			((ip_version1 == 0) && ip_version0))
+			return -1;
+	}
+
+	return 0;
+}
+
+static int
+action_default_check(struct table_rule_action *action,
+	struct pipeline *p,
+	uint32_t table_id)
+{
+	if ((action == NULL) ||
+		(action->action_mask != (1LLU << RTE_TABLE_ACTION_FWD)) ||
+		(p == NULL) ||
+		(table_id >= p->n_tables))
+		return -1;
+
+	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_FWD)) {
+		if ((action->fwd.action == RTE_PIPELINE_ACTION_PORT) &&
+			(action->fwd.id >= p->n_ports_out))
+			return -1;
+
+		if ((action->fwd.action == RTE_PIPELINE_ACTION_TABLE) &&
+			(action->fwd.id >= p->n_tables))
+			return -1;
+	}
+
+	return 0;
+}
+
+int
+pipeline_table_rule_add(const char *pipeline_name,
+	uint32_t table_id,
+	struct table_rule_match *match,
+	struct table_rule_action *action,
+	void **data)
+{
+	struct pipeline *p;
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if ((pipeline_name == NULL) ||
+		(match == NULL) ||
+		(action == NULL) ||
+		(data == NULL))
+		return -1;
+
+	p = pipeline_find(pipeline_name);
+	if ((p == NULL) ||
+		(table_id >= p->n_tables) ||
+		match_check(match, p, table_id) ||
+		action_check(action, p, table_id))
+		return -1;
+
+	/* Allocate request */
+	req = pipeline_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = PIPELINE_REQ_TABLE_RULE_ADD;
+	req->id = table_id;
+	memcpy(&req->table_rule_add.match, match, sizeof(*match));
+	memcpy(&req->table_rule_add.action, action, sizeof(*action));
+
+	/* Send request and wait for response */
+	rsp = pipeline_msg_send_recv(p, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+	if (status == 0)
+		*data = rsp->table_rule_add.data;
+
+	/* Free response */
+	pipeline_msg_free(rsp);
+
+	return status;
+}
+
+int
+pipeline_table_rule_add_default(const char *pipeline_name,
+	uint32_t table_id,
+	struct table_rule_action *action,
+	void **data)
+{
+	struct pipeline *p;
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if ((pipeline_name == NULL) ||
+		(action == NULL) ||
+		(data == NULL))
+		return -1;
+
+	p = pipeline_find(pipeline_name);
+	if ((p == NULL) ||
+		(table_id >= p->n_tables) ||
+		action_default_check(action, p, table_id))
+		return -1;
+
+	/* Allocate request */
+	req = pipeline_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = PIPELINE_REQ_TABLE_RULE_ADD_DEFAULT;
+	req->id = table_id;
+	memcpy(&req->table_rule_add_default.action, action, sizeof(*action));
+
+	/* Send request and wait for response */
+	rsp = pipeline_msg_send_recv(p, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+	if (status == 0)
+		*data = rsp->table_rule_add_default.data;
+
+	/* Free response */
+	pipeline_msg_free(rsp);
+
+	return status;
+}
+
 /**
  * Data plane threads: message handling
  */
@@ -908,6 +1195,461 @@ pipeline_msg_handle_table_stats_read(struct pipeline_data *p,
 	return rsp;
 }
 
+union table_rule_match_low_level {
+	struct rte_table_acl_rule_add_params acl_add;
+	struct rte_table_acl_rule_delete_params acl_delete;
+	struct rte_table_array_key array;
+	uint8_t hash[TABLE_RULE_MATCH_SIZE_MAX];
+	struct rte_table_lpm_key lpm_ipv4;
+	struct rte_table_lpm_ipv6_key lpm_ipv6;
+};
+
+static int
+match_convert_ipv6_depth(uint32_t depth, uint32_t *depth32)
+{
+	if (depth > 128)
+		return -1;
+
+	switch (depth / 32) {
+	case 0:
+		depth32[0] = depth;
+		depth32[1] = 0;
+		depth32[2] = 0;
+		depth32[3] = 0;
+		return 0;
+
+	case 1:
+		depth32[0] = 32;
+		depth32[1] = depth - 32;
+		depth32[2] = 0;
+		depth32[3] = 0;
+		return 0;
+
+	case 2:
+		depth32[0] = 32;
+		depth32[1] = 32;
+		depth32[2] = depth - 64;
+		depth32[3] = 0;
+		return 0;
+
+	case 3:
+		depth32[0] = 32;
+		depth32[1] = 32;
+		depth32[2] = 32;
+		depth32[3] = depth - 96;
+		return 0;
+
+	case 4:
+		depth32[0] = 32;
+		depth32[1] = 32;
+		depth32[2] = 32;
+		depth32[3] = 32;
+		return 0;
+
+	default:
+		return -1;
+	}
+}
+
+static int
+match_convert(struct table_rule_match *mh,
+	union table_rule_match_low_level *ml,
+	int add)
+{
+	memset(ml, 0, sizeof(*ml));
+
+	switch (mh->match_type) {
+	case TABLE_ACL:
+		if (mh->match.acl.ip_version)
+			if (add) {
+				ml->acl_add.field_value[0].value.u8 =
+					mh->match.acl.proto;
+				ml->acl_add.field_value[0].mask_range.u8 =
+					mh->match.acl.proto_mask;
+
+				ml->acl_add.field_value[1].value.u32 =
+					mh->match.acl.ipv4.sa;
+				ml->acl_add.field_value[1].mask_range.u32 =
+					mh->match.acl.sa_depth;
+
+				ml->acl_add.field_value[2].value.u32 =
+					mh->match.acl.ipv4.da;
+				ml->acl_add.field_value[2].mask_range.u32 =
+					mh->match.acl.da_depth;
+
+				ml->acl_add.field_value[3].value.u16 =
+					mh->match.acl.sp0;
+				ml->acl_add.field_value[3].mask_range.u16 =
+					mh->match.acl.sp1;
+
+				ml->acl_add.field_value[4].value.u16 =
+					mh->match.acl.dp0;
+				ml->acl_add.field_value[4].mask_range.u16 =
+					mh->match.acl.dp1;
+
+				ml->acl_add.priority =
+					(int32_t) mh->match.acl.priority;
+			} else {
+				ml->acl_delete.field_value[0].value.u8 =
+					mh->match.acl.proto;
+				ml->acl_delete.field_value[0].mask_range.u8 =
+					mh->match.acl.proto_mask;
+
+				ml->acl_delete.field_value[1].value.u32 =
+					mh->match.acl.ipv4.sa;
+				ml->acl_delete.field_value[1].mask_range.u32 =
+					mh->match.acl.sa_depth;
+
+				ml->acl_delete.field_value[2].value.u32 =
+					mh->match.acl.ipv4.da;
+				ml->acl_delete.field_value[2].mask_range.u32 =
+					mh->match.acl.da_depth;
+
+				ml->acl_delete.field_value[3].value.u16 =
+					mh->match.acl.sp0;
+				ml->acl_delete.field_value[3].mask_range.u16 =
+					mh->match.acl.sp1;
+
+				ml->acl_delete.field_value[4].value.u16 =
+					mh->match.acl.dp0;
+				ml->acl_delete.field_value[4].mask_range.u16 =
+					mh->match.acl.dp1;
+			}
+		else
+			if (add) {
+				uint32_t *sa32 =
+					(uint32_t *) mh->match.acl.ipv6.sa;
+				uint32_t *da32 =
+					(uint32_t *) mh->match.acl.ipv6.da;
+				uint32_t sa32_depth[4], da32_depth[4];
+				int status;
+
+				status = match_convert_ipv6_depth(
+					mh->match.acl.sa_depth,
+					sa32_depth);
+				if (status)
+					return status;
+
+				status = match_convert_ipv6_depth(
+					mh->match.acl.da_depth,
+					da32_depth);
+				if (status)
+					return status;
+
+				ml->acl_add.field_value[0].value.u8 =
+					mh->match.acl.proto;
+				ml->acl_add.field_value[0].mask_range.u8 =
+					mh->match.acl.proto_mask;
+
+				ml->acl_add.field_value[1].value.u32 = sa32[0];
+				ml->acl_add.field_value[1].mask_range.u32 =
+					sa32_depth[0];
+				ml->acl_add.field_value[2].value.u32 = sa32[1];
+				ml->acl_add.field_value[2].mask_range.u32 =
+					sa32_depth[1];
+				ml->acl_add.field_value[3].value.u32 = sa32[2];
+				ml->acl_add.field_value[3].mask_range.u32 =
+					sa32_depth[2];
+				ml->acl_add.field_value[4].value.u32 = sa32[3];
+				ml->acl_add.field_value[4].mask_range.u32 =
+					sa32_depth[3];
+
+				ml->acl_add.field_value[5].value.u32 = da32[0];
+				ml->acl_add.field_value[5].mask_range.u32 =
+					da32_depth[0];
+				ml->acl_add.field_value[6].value.u32 = da32[1];
+				ml->acl_add.field_value[6].mask_range.u32 =
+					da32_depth[1];
+				ml->acl_add.field_value[7].value.u32 = da32[2];
+				ml->acl_add.field_value[7].mask_range.u32 =
+					da32_depth[2];
+				ml->acl_add.field_value[8].value.u32 = da32[3];
+				ml->acl_add.field_value[8].mask_range.u32 =
+					da32_depth[3];
+
+				ml->acl_add.field_value[9].value.u16 =
+					mh->match.acl.sp0;
+				ml->acl_add.field_value[9].mask_range.u16 =
+					mh->match.acl.sp1;
+
+				ml->acl_add.field_value[10].value.u16 =
+					mh->match.acl.dp0;
+				ml->acl_add.field_value[10].mask_range.u16 =
+					mh->match.acl.dp1;
+
+				ml->acl_add.priority =
+					(int32_t) mh->match.acl.priority;
+			} else {
+				uint32_t *sa32 =
+					(uint32_t *) mh->match.acl.ipv6.sa;
+				uint32_t *da32 =
+					(uint32_t *) mh->match.acl.ipv6.da;
+				uint32_t sa32_depth[4], da32_depth[4];
+				int status;
+
+				status = match_convert_ipv6_depth(
+					mh->match.acl.sa_depth,
+					sa32_depth);
+				if (status)
+					return status;
+
+				status = match_convert_ipv6_depth(
+					mh->match.acl.da_depth,
+					da32_depth);
+				if (status)
+					return status;
+
+				ml->acl_delete.field_value[0].value.u8 =
+					mh->match.acl.proto;
+				ml->acl_delete.field_value[0].mask_range.u8 =
+					mh->match.acl.proto_mask;
+
+				ml->acl_delete.field_value[1].value.u32 =
+					sa32[0];
+				ml->acl_delete.field_value[1].mask_range.u32 =
+					sa32_depth[0];
+				ml->acl_delete.field_value[2].value.u32 =
+					sa32[1];
+				ml->acl_delete.field_value[2].mask_range.u32 =
+					sa32_depth[1];
+				ml->acl_delete.field_value[3].value.u32 =
+					sa32[2];
+				ml->acl_delete.field_value[3].mask_range.u32 =
+					sa32_depth[2];
+				ml->acl_delete.field_value[4].value.u32 =
+					sa32[3];
+				ml->acl_delete.field_value[4].mask_range.u32 =
+					sa32_depth[3];
+
+				ml->acl_delete.field_value[5].value.u32 =
+					da32[0];
+				ml->acl_delete.field_value[5].mask_range.u32 =
+					da32_depth[0];
+				ml->acl_delete.field_value[6].value.u32 =
+					da32[1];
+				ml->acl_delete.field_value[6].mask_range.u32 =
+					da32_depth[1];
+				ml->acl_delete.field_value[7].value.u32 =
+					da32[2];
+				ml->acl_delete.field_value[7].mask_range.u32 =
+					da32_depth[2];
+				ml->acl_delete.field_value[8].value.u32 =
+					da32[3];
+				ml->acl_delete.field_value[8].mask_range.u32 =
+					da32_depth[3];
+
+				ml->acl_delete.field_value[9].value.u16 =
+					mh->match.acl.sp0;
+				ml->acl_delete.field_value[9].mask_range.u16 =
+					mh->match.acl.sp1;
+
+				ml->acl_delete.field_value[10].value.u16 =
+					mh->match.acl.dp0;
+				ml->acl_delete.field_value[10].mask_range.u16 =
+					mh->match.acl.dp1;
+			}
+		return 0;
+
+	case TABLE_ARRAY:
+		ml->array.pos = mh->match.array.pos;
+		return 0;
+
+	case TABLE_HASH:
+		memcpy(ml->hash, mh->match.hash.key, sizeof(ml->hash));
+		return 0;
+
+	case TABLE_LPM:
+		if (mh->match.lpm.ip_version) {
+			ml->lpm_ipv4.ip = mh->match.lpm.ipv4;
+			ml->lpm_ipv4.depth = mh->match.lpm.depth;
+		} else {
+			memcpy(ml->lpm_ipv6.ip,
+				mh->match.lpm.ipv6, sizeof(ml->lpm_ipv6.ip));
+			ml->lpm_ipv6.depth = mh->match.lpm.depth;
+		}
+
+		return 0;
+
+	default:
+		return -1;
+	}
+}
+
+static struct pipeline_msg_rsp *
+pipeline_msg_handle_table_rule_add(struct pipeline_data *p,
+	struct pipeline_msg_req *req)
+{
+	union table_rule_match_low_level match_ll;
+	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+	struct table_rule_match *match = &req->table_rule_add.match;
+	struct table_rule_action *action = &req->table_rule_add.action;
+	struct rte_pipeline_table_entry *data_in, *data_out;
+	uint32_t table_id = req->id;
+	int key_found, status;
+	struct rte_table_action *a = p->table_data[table_id].a;
+
+	/* Apply actions */
+	memset(p->buffer, 0, sizeof(p->buffer));
+	data_in = (struct rte_pipeline_table_entry *) p->buffer;
+
+	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_FWD)) {
+		status = rte_table_action_apply(a,
+			data_in,
+			RTE_TABLE_ACTION_FWD,
+			&action->fwd);
+
+		if (status) {
+			rsp->status = -1;
+			return rsp;
+		}
+	}
+
+	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) {
+		status = rte_table_action_apply(a,
+			data_in,
+			RTE_TABLE_ACTION_MTR,
+			&action->mtr);
+
+		if (status) {
+			rsp->status = -1;
+			return rsp;
+		}
+	}
+
+	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_TM)) {
+		status = rte_table_action_apply(a,
+			data_in,
+			RTE_TABLE_ACTION_TM,
+			&action->tm);
+
+		if (status) {
+			rsp->status = -1;
+			return rsp;
+		}
+	}
+
+	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_ENCAP)) {
+		status = rte_table_action_apply(a,
+			data_in,
+			RTE_TABLE_ACTION_ENCAP,
+			&action->encap);
+
+		if (status) {
+			rsp->status = -1;
+			return rsp;
+		}
+	}
+
+	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_NAT)) {
+		status = rte_table_action_apply(a,
+			data_in,
+			RTE_TABLE_ACTION_NAT,
+			&action->nat);
+
+		if (status) {
+			rsp->status = -1;
+			return rsp;
+		}
+	}
+
+	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_TTL)) {
+		status = rte_table_action_apply(a,
+			data_in,
+			RTE_TABLE_ACTION_TTL,
+			&action->ttl);
+
+		if (status) {
+			rsp->status = -1;
+			return rsp;
+		}
+	}
+
+	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_STATS)) {
+		status = rte_table_action_apply(a,
+			data_in,
+			RTE_TABLE_ACTION_STATS,
+			&action->stats);
+
+		if (status) {
+			rsp->status = -1;
+			return rsp;
+		}
+	}
+
+	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_TIME)) {
+		status = rte_table_action_apply(a,
+			data_in,
+			RTE_TABLE_ACTION_TIME,
+			&action->time);
+
+		if (status) {
+			rsp->status = -1;
+			return rsp;
+		}
+	}
+
+	/* Add rule (match, action) to table */
+	status = match_convert(match, &match_ll, 1);
+	if (status) {
+		rsp->status = -1;
+		return rsp;
+	}
+
+	status = rte_pipeline_table_entry_add(p->p,
+		table_id,
+		&match_ll,
+		data_in,
+		&key_found,
+		&data_out);
+	if (status) {
+		rsp->status = -1;
+		return rsp;
+	}
+
+	/* Write response */
+	rsp->status = 0;
+	rsp->table_rule_add.data = data_out;
+
+	return rsp;
+}
+
+static struct pipeline_msg_rsp *
+pipeline_msg_handle_table_rule_add_default(struct pipeline_data *p,
+	struct pipeline_msg_req *req)
+{
+	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+	struct table_rule_action *action = &req->table_rule_add_default.action;
+	struct rte_pipeline_table_entry *data_in, *data_out;
+	uint32_t table_id = req->id;
+	int status;
+
+	/* Apply actions */
+	memset(p->buffer, 0, sizeof(p->buffer));
+	data_in = (struct rte_pipeline_table_entry *) p->buffer;
+
+	data_in->action = action->fwd.action;
+	if (action->fwd.action == RTE_PIPELINE_ACTION_PORT)
+		data_in->port_id = action->fwd.id;
+	if (action->fwd.action == RTE_PIPELINE_ACTION_TABLE)
+		data_in->table_id = action->fwd.id;
+
+	/* Add default rule to table */
+	status = rte_pipeline_table_default_entry_add(p->p,
+		table_id,
+		data_in,
+		&data_out);
+	if (status) {
+		rsp->status = -1;
+		return rsp;
+	}
+
+	/* Write response */
+	rsp->status = 0;
+	rsp->table_rule_add_default.data = data_out;
+
+	return rsp;
+}
+
 static void
 pipeline_msg_handle(struct pipeline_data *p)
 {
@@ -940,6 +1682,13 @@ pipeline_msg_handle(struct pipeline_data *p)
 			rsp = pipeline_msg_handle_table_stats_read(p, req);
 			break;
 
+		case PIPELINE_REQ_TABLE_RULE_ADD:
+			rsp = pipeline_msg_handle_table_rule_add(p, req);
+			break;
+
+		case PIPELINE_REQ_TABLE_RULE_ADD_DEFAULT:
+			rsp = pipeline_msg_handle_table_rule_add_default(p,	req);
+			break;
 
 		default:
 			rsp = (struct pipeline_msg_rsp *) req;
-- 
2.9.3

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

* [dpdk-dev] [PATCH 26/37] ip_pipeline: add cli to delete pipeline table entry
  2018-03-09 18:23 [dpdk-dev] [PATCH 00/37] ip_pipeline: refactoring Jasvinder Singh
                   ` (24 preceding siblings ...)
  2018-03-09 18:24 ` [dpdk-dev] [PATCH 25/37] ip_pipeline: add cli for pipeline table entries Jasvinder Singh
@ 2018-03-09 18:24 ` Jasvinder Singh
  2018-03-09 18:24 ` [dpdk-dev] [PATCH 27/37] ip_pipeline: add cli to read pipeline table entry stats Jasvinder Singh
                   ` (10 subsequent siblings)
  36 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-09 18:24 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add command to delete the pipeline table entry.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/cli.c      | 145 ++++++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/pipeline.h |   9 +++
 examples/ip_pipeline/thread.c   | 140 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 294 insertions(+)

diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index c0aa8c4..774d1b1 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -3322,6 +3322,134 @@ cmd_pipeline_table_rule_add_default(char **tokens,
 }
 
 /**
+ * pipeline <pipeline_name> table <table_id> rule delete
+ *    match <match>
+ */
+static void
+cmd_pipeline_table_rule_delete(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct table_rule_match m;
+	char *pipeline_name;
+	uint32_t table_id, n_tokens_parsed, t0;
+	int status;
+
+	if (n_tokens < 8) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "table") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
+		return;
+	}
+
+	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
+		return;
+	}
+
+	if (strcmp(tokens[4], "rule") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
+		return;
+	}
+
+	if (strcmp(tokens[5], "delete") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete");
+		return;
+	}
+
+	t0 = 6;
+
+	/* match */
+	n_tokens_parsed = parse_match(tokens + t0,
+		n_tokens - t0,
+		out,
+		out_size,
+		&m);
+	if (n_tokens_parsed == 0)
+		return;
+	t0 += n_tokens_parsed;
+
+	if (n_tokens != t0) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	status = pipeline_table_rule_delete(pipeline_name,
+		table_id,
+		&m);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
+ * pipeline <pipeline_name> table <table_id> rule delete
+ *    match
+ *       default
+*/
+static void
+cmd_pipeline_table_rule_delete_default(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	char *pipeline_name;
+	uint32_t table_id;
+	int status;
+
+	if (n_tokens != 8) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "table") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
+		return;
+	}
+
+	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
+		return;
+	}
+
+	if (strcmp(tokens[4], "rule") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
+		return;
+	}
+
+	if (strcmp(tokens[5], "delete") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete");
+		return;
+	}
+
+	if (strcmp(tokens[6], "match") != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "match");
+		return;
+	}
+
+	if (strcmp(tokens[7], "default") != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "default");
+		return;
+	}
+
+	status = pipeline_table_rule_delete_default(pipeline_name,
+		table_id);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
  * thread <thread_id> pipeline <pipeline_name> enable
  */
 static void
@@ -3588,6 +3716,23 @@ cli_process(char *in, char *out, size_t out_size)
 				out, out_size);
 			return;
 		}
+
+		if ((n_tokens >= 7) &&
+			(strcmp(tokens[2], "table") == 0) &&
+			(strcmp(tokens[4], "rule") == 0) &&
+			(strcmp(tokens[5], "delete") == 0) &&
+			(strcmp(tokens[6], "match") == 0)) {
+			if ((n_tokens >= 8) &&
+				(strcmp(tokens[7], "default") == 0)) {
+				cmd_pipeline_table_rule_delete_default(tokens,
+					n_tokens, out, out_size);
+				return;
+				}
+
+			cmd_pipeline_table_rule_delete(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
 	}
 
 	if (strcmp(tokens[0], "thread") == 0) {
diff --git a/examples/ip_pipeline/pipeline.h b/examples/ip_pipeline/pipeline.h
index 9351024..2bf6360 100644
--- a/examples/ip_pipeline/pipeline.h
+++ b/examples/ip_pipeline/pipeline.h
@@ -301,4 +301,13 @@ pipeline_table_rule_add_default(const char *pipeline_name,
 	struct table_rule_action *action,
 	void **data);
 
+int
+pipeline_table_rule_delete(const char *pipeline_name,
+	uint32_t table_id,
+	struct table_rule_match *match);
+
+int
+pipeline_table_rule_delete_default(const char *pipeline_name,
+	uint32_t table_id);
+
 #endif /* _INCLUDE_PIPELINE_H_ */
diff --git a/examples/ip_pipeline/thread.c b/examples/ip_pipeline/thread.c
index be12d20..7f29f2d 100644
--- a/examples/ip_pipeline/thread.c
+++ b/examples/ip_pipeline/thread.c
@@ -495,6 +495,8 @@ enum pipeline_req_type {
 	PIPELINE_REQ_TABLE_STATS_READ,
 	PIPELINE_REQ_TABLE_RULE_ADD,
 	PIPELINE_REQ_TABLE_RULE_ADD_DEFAULT,
+	PIPELINE_REQ_TABLE_RULE_DELETE,
+	PIPELINE_REQ_TABLE_RULE_DELETE_DEFAULT,
 
 	PIPELINE_REQ_MAX
 };
@@ -520,6 +522,10 @@ struct pipeline_msg_req_table_rule_add_default {
 	struct table_rule_action action;
 };
 
+struct pipeline_msg_req_table_rule_delete {
+	struct table_rule_match match;
+};
+
 struct pipeline_msg_req {
 	enum pipeline_req_type type;
 	uint32_t id; /* Port IN, port OUT or table ID */
@@ -531,6 +537,7 @@ struct pipeline_msg_req {
 		struct pipeline_msg_req_table_stats_read table_stats_read;
 		struct pipeline_msg_req_table_rule_add table_rule_add;
 		struct pipeline_msg_req_table_rule_add_default table_rule_add_default;
+		struct pipeline_msg_req_table_rule_delete table_rule_delete;
 	};
 };
 
@@ -1094,6 +1101,92 @@ pipeline_table_rule_add_default(const char *pipeline_name,
 	return status;
 }
 
+int
+pipeline_table_rule_delete(const char *pipeline_name,
+	uint32_t table_id,
+	struct table_rule_match *match)
+{
+	struct pipeline *p;
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if ((pipeline_name == NULL) ||
+		(match == NULL))
+		return -1;
+
+	p = pipeline_find(pipeline_name);
+	if ((p == NULL) ||
+		(table_id >= p->n_tables) ||
+		match_check(match, p, table_id))
+		return -1;
+
+	/* Allocate request */
+	req = pipeline_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = PIPELINE_REQ_TABLE_RULE_DELETE;
+	req->id = table_id;
+	memcpy(&req->table_rule_delete.match, match, sizeof(*match));
+
+	/* Send request and wait for response */
+	rsp = pipeline_msg_send_recv(p, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+
+	/* Free response */
+	pipeline_msg_free(rsp);
+
+	return status;
+}
+
+int
+pipeline_table_rule_delete_default(const char *pipeline_name,
+	uint32_t table_id)
+{
+	struct pipeline *p;
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if (pipeline_name == NULL)
+		return -1;
+
+	p = pipeline_find(pipeline_name);
+	if ((p == NULL) ||
+		(table_id >= p->n_tables))
+		return -1;
+
+	/* Allocate request */
+	req = pipeline_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = PIPELINE_REQ_TABLE_RULE_DELETE_DEFAULT;
+	req->id = table_id;
+
+	/* Send request and wait for response */
+	rsp = pipeline_msg_send_recv(p, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+
+	/* Free response */
+	pipeline_msg_free(rsp);
+
+	return status;
+}
+
 /**
  * Data plane threads: message handling
  */
@@ -1650,6 +1743,45 @@ pipeline_msg_handle_table_rule_add_default(struct pipeline_data *p,
 	return rsp;
 }
 
+static struct pipeline_msg_rsp *
+pipeline_msg_handle_table_rule_delete(struct pipeline_data *p,
+	struct pipeline_msg_req *req)
+{
+	union table_rule_match_low_level match_ll;
+	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+	struct table_rule_match *match = &req->table_rule_delete.match;
+	uint32_t table_id = req->id;
+	int key_found, status;
+
+	status = match_convert(match, &match_ll, 0);
+	if (status) {
+		rsp->status = -1;
+		return rsp;
+	}
+
+	rsp->status = rte_pipeline_table_entry_delete(p->p,
+		table_id,
+		&match_ll,
+		&key_found,
+		NULL);
+
+	return rsp;
+}
+
+static struct pipeline_msg_rsp *
+pipeline_msg_handle_table_rule_delete_default(struct pipeline_data *p,
+	struct pipeline_msg_req *req)
+{
+	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+	uint32_t table_id = req->id;
+
+	rsp->status = rte_pipeline_table_default_entry_delete(p->p,
+		table_id,
+		NULL);
+
+	return rsp;
+}
+
 static void
 pipeline_msg_handle(struct pipeline_data *p)
 {
@@ -1690,6 +1822,14 @@ pipeline_msg_handle(struct pipeline_data *p)
 			rsp = pipeline_msg_handle_table_rule_add_default(p,	req);
 			break;
 
+		case PIPELINE_REQ_TABLE_RULE_DELETE:
+			rsp = pipeline_msg_handle_table_rule_delete(p, req);
+			break;
+
+		case PIPELINE_REQ_TABLE_RULE_DELETE_DEFAULT:
+			rsp = pipeline_msg_handle_table_rule_delete_default(p, req);
+			break;
+
 		default:
 			rsp = (struct pipeline_msg_rsp *) req;
 			rsp->status = -1;
-- 
2.9.3

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

* [dpdk-dev] [PATCH 27/37] ip_pipeline: add cli to read pipeline table entry stats
  2018-03-09 18:23 [dpdk-dev] [PATCH 00/37] ip_pipeline: refactoring Jasvinder Singh
                   ` (25 preceding siblings ...)
  2018-03-09 18:24 ` [dpdk-dev] [PATCH 26/37] ip_pipeline: add cli to delete pipeline table entry Jasvinder Singh
@ 2018-03-09 18:24 ` Jasvinder Singh
  2018-03-09 18:24 ` [dpdk-dev] [PATCH 28/37] ip_pipeline: add cli to configure meter profile Jasvinder Singh
                   ` (9 subsequent siblings)
  36 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-09 18:24 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Fan Zhang

Add command to read the pipeline table entry stats.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Fan Zhang <roy.fan.zhang@intel.com>
---
 examples/ip_pipeline/cli.c      | 22 +++++++++++
 examples/ip_pipeline/pipeline.h |  7 ++++
 examples/ip_pipeline/thread.c   | 84 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 113 insertions(+)

diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index 774d1b1..48c4b7c 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -3450,6 +3450,18 @@ cmd_pipeline_table_rule_delete_default(char **tokens,
 }
 
 /**
+ * pipeline <pipeline_name> table <table_id> rule read stats [clear]
+ */
+static void
+cmd_pipeline_table_rule_stats_read(char **tokens,
+	uint32_t n_tokens __rte_unused,
+	char *out,
+	size_t out_size)
+{
+	snprintf(out, out_size, MSG_CMD_UNIMPLEM, tokens[0]);
+}
+
+/**
  * thread <thread_id> pipeline <pipeline_name> enable
  */
 static void
@@ -3733,6 +3745,16 @@ cli_process(char *in, char *out, size_t out_size)
 				out, out_size);
 			return;
 		}
+
+		if ((n_tokens >= 7) &&
+			(strcmp(tokens[2], "table") == 0) &&
+			(strcmp(tokens[4], "rule") == 0) &&
+			(strcmp(tokens[5], "read") == 0) &&
+			(strcmp(tokens[6], "stats") == 0)) {
+			cmd_pipeline_table_rule_stats_read(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
 	}
 
 	if (strcmp(tokens[0], "thread") == 0) {
diff --git a/examples/ip_pipeline/pipeline.h b/examples/ip_pipeline/pipeline.h
index 2bf6360..296e4da 100644
--- a/examples/ip_pipeline/pipeline.h
+++ b/examples/ip_pipeline/pipeline.h
@@ -310,4 +310,11 @@ int
 pipeline_table_rule_delete_default(const char *pipeline_name,
 	uint32_t table_id);
 
+int
+pipeline_table_rule_stats_read(const char *pipeline_name,
+	uint32_t table_id,
+	void *data,
+	struct rte_table_action_stats_counters *stats,
+	int clear);
+
 #endif /* _INCLUDE_PIPELINE_H_ */
diff --git a/examples/ip_pipeline/thread.c b/examples/ip_pipeline/thread.c
index 7f29f2d..21f36ca 100644
--- a/examples/ip_pipeline/thread.c
+++ b/examples/ip_pipeline/thread.c
@@ -497,6 +497,7 @@ enum pipeline_req_type {
 	PIPELINE_REQ_TABLE_RULE_ADD_DEFAULT,
 	PIPELINE_REQ_TABLE_RULE_DELETE,
 	PIPELINE_REQ_TABLE_RULE_DELETE_DEFAULT,
+	PIPELINE_REQ_TABLE_RULE_STATS_READ,
 
 	PIPELINE_REQ_MAX
 };
@@ -526,6 +527,11 @@ struct pipeline_msg_req_table_rule_delete {
 	struct table_rule_match match;
 };
 
+struct pipeline_msg_req_table_rule_stats_read {
+	void *data;
+	int clear;
+};
+
 struct pipeline_msg_req {
 	enum pipeline_req_type type;
 	uint32_t id; /* Port IN, port OUT or table ID */
@@ -538,6 +544,7 @@ struct pipeline_msg_req {
 		struct pipeline_msg_req_table_rule_add table_rule_add;
 		struct pipeline_msg_req_table_rule_add_default table_rule_add_default;
 		struct pipeline_msg_req_table_rule_delete table_rule_delete;
+		struct pipeline_msg_req_table_rule_stats_read table_rule_stats_read;
 	};
 };
 
@@ -561,6 +568,10 @@ struct pipeline_msg_rsp_table_rule_add_default {
 	void *data;
 };
 
+struct pipeline_msg_rsp_table_rule_stats_read {
+	struct rte_table_action_stats_counters stats;
+};
+
 struct pipeline_msg_rsp {
 	int status;
 
@@ -571,6 +582,7 @@ struct pipeline_msg_rsp {
 		struct pipeline_msg_rsp_table_stats_read table_stats_read;
 		struct pipeline_msg_rsp_table_rule_add table_rule_add;
 		struct pipeline_msg_rsp_table_rule_add_default table_rule_add_default;
+		struct pipeline_msg_rsp_table_rule_stats_read table_rule_stats_read;
 	};
 };
 
@@ -1187,6 +1199,56 @@ pipeline_table_rule_delete_default(const char *pipeline_name,
 	return status;
 }
 
+int
+pipeline_table_rule_stats_read(const char *pipeline_name,
+	uint32_t table_id,
+	void *data,
+	struct rte_table_action_stats_counters *stats,
+	int clear)
+{
+	struct pipeline *p;
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if ((pipeline_name == NULL) ||
+		(data == NULL) ||
+		(stats == NULL))
+		return -1;
+
+	p = pipeline_find(pipeline_name);
+	if ((p == NULL) ||
+		(table_id >= p->n_tables))
+		return -1;
+
+	/* Allocate request */
+	req = pipeline_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = PIPELINE_REQ_TABLE_RULE_STATS_READ;
+	req->id = table_id;
+	req->table_rule_stats_read.data = data;
+	req->table_rule_stats_read.clear = clear;
+
+	/* Send request and wait for response */
+	rsp = pipeline_msg_send_recv(p, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+	if (status)
+		memcpy(stats, &rsp->table_rule_stats_read.stats, sizeof(*stats));
+
+	/* Free response */
+	pipeline_msg_free(rsp);
+
+	return status;
+}
+
 /**
  * Data plane threads: message handling
  */
@@ -1782,6 +1844,24 @@ pipeline_msg_handle_table_rule_delete_default(struct pipeline_data *p,
 	return rsp;
 }
 
+static struct pipeline_msg_rsp *
+pipeline_msg_handle_table_rule_stats_read(struct pipeline_data *p,
+	struct pipeline_msg_req *req)
+{
+	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+	uint32_t table_id = req->id;
+	void *data = req->table_rule_stats_read.data;
+	int clear = req->table_rule_stats_read.clear;
+	struct rte_table_action *a = p->table_data[table_id].a;
+
+	rsp->status = rte_table_action_stats_read(a,
+		data,
+		&rsp->table_rule_stats_read.stats,
+		clear);
+
+	return rsp;
+}
+
 static void
 pipeline_msg_handle(struct pipeline_data *p)
 {
@@ -1830,6 +1910,10 @@ pipeline_msg_handle(struct pipeline_data *p)
 			rsp = pipeline_msg_handle_table_rule_delete_default(p, req);
 			break;
 
+		case PIPELINE_REQ_TABLE_RULE_STATS_READ:
+			rsp = pipeline_msg_handle_table_rule_stats_read(p, req);
+			break;
+
 		default:
 			rsp = (struct pipeline_msg_rsp *) req;
 			rsp->status = -1;
-- 
2.9.3

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

* [dpdk-dev] [PATCH 28/37] ip_pipeline: add cli to configure meter profile
  2018-03-09 18:23 [dpdk-dev] [PATCH 00/37] ip_pipeline: refactoring Jasvinder Singh
                   ` (26 preceding siblings ...)
  2018-03-09 18:24 ` [dpdk-dev] [PATCH 27/37] ip_pipeline: add cli to read pipeline table entry stats Jasvinder Singh
@ 2018-03-09 18:24 ` Jasvinder Singh
  2018-03-09 18:24 ` [dpdk-dev] [PATCH 29/37] ip_pipeline: add cli to read meter stats Jasvinder Singh
                   ` (8 subsequent siblings)
  36 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-09 18:24 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add commands to configure the traffic meter profile.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/cli.c      | 232 ++++++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/pipeline.h |  11 ++
 examples/ip_pipeline/thread.c   | 144 ++++++++++++++++++++++++-
 3 files changed, 386 insertions(+), 1 deletion(-)

diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index 48c4b7c..46fe69b 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -3462,6 +3462,218 @@ cmd_pipeline_table_rule_stats_read(char **tokens,
 }
 
 /**
+ * pipeline <pipeline_name> table <table_id> meter profile <meter_profile_id>
+ *  add srtcm cir <cir> cbs <cbs> ebs <ebs>
+ * 	| trtcm cir <cir> pir <pir> cbs <cbs> pbs <pbs>
+ */
+static void
+cmd_pipeline_table_meter_profile_add(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct rte_table_action_meter_profile p;
+	char *pipeline_name;
+	uint32_t table_id, meter_profile_id;
+	int status;
+
+	if (n_tokens < 9) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "table") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
+		return;
+	}
+
+	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
+		return;
+	}
+
+	if (strcmp(tokens[4], "meter") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
+		return;
+	}
+
+	if (strcmp(tokens[5], "profile") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
+		return;
+	}
+
+	if (parser_read_uint32(&meter_profile_id, tokens[6]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "meter_profile_id");
+		return;
+	}
+
+	if (strcmp(tokens[7], "add") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
+		return;
+	}
+
+	if (strcmp(tokens[8], "srtcm") == 0) {
+		if (n_tokens != 15) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				tokens[0]);
+			return;
+		}
+
+		p.alg = RTE_TABLE_ACTION_METER_SRTCM;
+
+		if (strcmp(tokens[9], "cir") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cir");
+			return;
+		}
+
+		if (parser_read_uint64(&p.srtcm.cir, tokens[10]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "cir");
+			return;
+		}
+
+		if (strcmp(tokens[11], "cbs") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cbs");
+			return;
+		}
+
+		if (parser_read_uint64(&p.srtcm.cbs, tokens[12]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "cbs");
+			return;
+		}
+
+		if (strcmp(tokens[13], "ebs") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "ebs");
+			return;
+		}
+
+		if (parser_read_uint64(&p.srtcm.ebs, tokens[14]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "ebs");
+			return;
+		}
+	} else if (strcmp(tokens[8], "trtcm") == 0) {
+		if (n_tokens != 17) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+			return;
+		}
+
+		p.alg = RTE_TABLE_ACTION_METER_TRTCM;
+
+		if (strcmp(tokens[9], "cir") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cir");
+			return;
+		}
+
+		if (parser_read_uint64(&p.trtcm.cir, tokens[10]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "cir");
+			return;
+		}
+
+		if (strcmp(tokens[11], "pir") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pir");
+			return;
+		}
+
+		if (parser_read_uint64(&p.trtcm.pir, tokens[12]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "pir");
+			return;
+		}
+		if (strcmp(tokens[13], "cbs") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cbs");
+			return;
+		}
+
+		if (parser_read_uint64(&p.trtcm.cbs, tokens[14]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "cbs");
+			return;
+		}
+
+		if (strcmp(tokens[15], "pbs") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pbs");
+			return;
+		}
+
+		if (parser_read_uint64(&p.trtcm.pbs, tokens[16]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "pbs");
+			return;
+		}
+	} else {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	status = pipeline_table_mtr_profile_add(pipeline_name,
+		table_id,
+		meter_profile_id,
+		&p);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
+ * pipeline <pipeline_name> table <table_id>
+ *  meter profile <meter_profile_id> delete
+ */
+static void
+cmd_pipeline_table_meter_profile_delete(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	char *pipeline_name;
+	uint32_t table_id, meter_profile_id;
+	int status;
+
+	if (n_tokens != 8) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "table") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
+		return;
+	}
+
+	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
+		return;
+	}
+
+	if (strcmp(tokens[4], "meter") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
+		return;
+	}
+
+	if (strcmp(tokens[5], "profile") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
+		return;
+	}
+
+	if (parser_read_uint32(&meter_profile_id, tokens[6]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "meter_profile_id");
+		return;
+	}
+
+	if (strcmp(tokens[7], "delete") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete");
+		return;
+	}
+
+	status = pipeline_table_mtr_profile_delete(pipeline_name,
+		table_id,
+		meter_profile_id);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
  * thread <thread_id> pipeline <pipeline_name> enable
  */
 static void
@@ -3755,6 +3967,26 @@ cli_process(char *in, char *out, size_t out_size)
 				out, out_size);
 			return;
 		}
+
+		if ((n_tokens >= 8) &&
+			(strcmp(tokens[2], "table") == 0) &&
+			(strcmp(tokens[4], "meter") == 0) &&
+			(strcmp(tokens[5], "profile") == 0) &&
+			(strcmp(tokens[7], "add") == 0)) {
+			cmd_pipeline_table_meter_profile_add(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
+
+		if ((n_tokens >= 8) &&
+			(strcmp(tokens[2], "table") == 0) &&
+			(strcmp(tokens[4], "meter") == 0) &&
+			(strcmp(tokens[5], "profile") == 0) &&
+			(strcmp(tokens[7], "delete") == 0)) {
+			cmd_pipeline_table_meter_profile_delete(tokens,
+				n_tokens, out, out_size);
+			return;
+		}
 	}
 
 	if (strcmp(tokens[0], "thread") == 0) {
diff --git a/examples/ip_pipeline/pipeline.h b/examples/ip_pipeline/pipeline.h
index 296e4da..d524145 100644
--- a/examples/ip_pipeline/pipeline.h
+++ b/examples/ip_pipeline/pipeline.h
@@ -317,4 +317,15 @@ pipeline_table_rule_stats_read(const char *pipeline_name,
 	struct rte_table_action_stats_counters *stats,
 	int clear);
 
+int
+pipeline_table_mtr_profile_add(const char *pipeline_name,
+	uint32_t table_id,
+	uint32_t meter_profile_id,
+	struct rte_table_action_meter_profile *profile);
+
+int
+pipeline_table_mtr_profile_delete(const char *pipeline_name,
+	uint32_t table_id,
+	uint32_t meter_profile_id);
+
 #endif /* _INCLUDE_PIPELINE_H_ */
diff --git a/examples/ip_pipeline/thread.c b/examples/ip_pipeline/thread.c
index 21f36ca..4e326f2 100644
--- a/examples/ip_pipeline/thread.c
+++ b/examples/ip_pipeline/thread.c
@@ -498,7 +498,8 @@ enum pipeline_req_type {
 	PIPELINE_REQ_TABLE_RULE_DELETE,
 	PIPELINE_REQ_TABLE_RULE_DELETE_DEFAULT,
 	PIPELINE_REQ_TABLE_RULE_STATS_READ,
-
+	PIPELINE_REQ_TABLE_MTR_PROFILE_ADD,
+	PIPELINE_REQ_TABLE_MTR_PROFILE_DELETE,
 	PIPELINE_REQ_MAX
 };
 
@@ -532,6 +533,15 @@ struct pipeline_msg_req_table_rule_stats_read {
 	int clear;
 };
 
+struct pipeline_msg_req_table_mtr_profile_add {
+	uint32_t meter_profile_id;
+	struct rte_table_action_meter_profile profile;
+};
+
+struct pipeline_msg_req_table_mtr_profile_delete {
+	uint32_t meter_profile_id;
+};
+
 struct pipeline_msg_req {
 	enum pipeline_req_type type;
 	uint32_t id; /* Port IN, port OUT or table ID */
@@ -545,6 +555,8 @@ struct pipeline_msg_req {
 		struct pipeline_msg_req_table_rule_add_default table_rule_add_default;
 		struct pipeline_msg_req_table_rule_delete table_rule_delete;
 		struct pipeline_msg_req_table_rule_stats_read table_rule_stats_read;
+		struct pipeline_msg_req_table_mtr_profile_add table_mtr_profile_add;
+		struct pipeline_msg_req_table_mtr_profile_delete table_mtr_profile_delete;
 	};
 };
 
@@ -1249,6 +1261,95 @@ pipeline_table_rule_stats_read(const char *pipeline_name,
 	return status;
 }
 
+int
+pipeline_table_mtr_profile_add(const char *pipeline_name,
+	uint32_t table_id,
+	uint32_t meter_profile_id,
+	struct rte_table_action_meter_profile *profile)
+{
+	struct pipeline *p;
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if ((pipeline_name == NULL) ||
+		(profile == NULL))
+		return -1;
+
+	p = pipeline_find(pipeline_name);
+	if ((p == NULL) ||
+		(table_id >= p->n_tables))
+		return -1;
+
+	/* Allocate request */
+	req = pipeline_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = PIPELINE_REQ_TABLE_MTR_PROFILE_ADD;
+	req->id = table_id;
+	req->table_mtr_profile_add.meter_profile_id = meter_profile_id;
+	memcpy(&req->table_mtr_profile_add.profile, profile, sizeof(*profile));
+
+	/* Send request and wait for response */
+	rsp = pipeline_msg_send_recv(p, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+
+	/* Free response */
+	pipeline_msg_free(rsp);
+
+	return status;
+}
+
+int
+pipeline_table_mtr_profile_delete(const char *pipeline_name,
+	uint32_t table_id,
+	uint32_t meter_profile_id)
+{
+	struct pipeline *p;
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if (pipeline_name == NULL)
+		return -1;
+
+	p = pipeline_find(pipeline_name);
+	if ((p == NULL) ||
+		(table_id >= p->n_tables))
+		return -1;
+
+	/* Allocate request */
+	req = pipeline_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = PIPELINE_REQ_TABLE_MTR_PROFILE_DELETE;
+	req->id = table_id;
+	req->table_mtr_profile_delete.meter_profile_id = meter_profile_id;
+
+	/* Send request and wait for response */
+	rsp = pipeline_msg_send_recv(p, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+
+	/* Free response */
+	pipeline_msg_free(rsp);
+
+	return status;
+}
+
 /**
  * Data plane threads: message handling
  */
@@ -1862,6 +1963,39 @@ pipeline_msg_handle_table_rule_stats_read(struct pipeline_data *p,
 	return rsp;
 }
 
+static struct pipeline_msg_rsp *
+pipeline_msg_handle_table_mtr_profile_add(struct pipeline_data *p,
+	struct pipeline_msg_req *req)
+{
+	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+	uint32_t table_id = req->id;
+	uint32_t meter_profile_id = req->table_mtr_profile_add.meter_profile_id;
+	struct rte_table_action_meter_profile *profile = &req->table_mtr_profile_add.profile;
+	struct rte_table_action *a = p->table_data[table_id].a;
+
+	rsp->status = rte_table_action_meter_profile_add(a,
+		meter_profile_id,
+		profile);
+
+	return rsp;
+}
+
+static struct pipeline_msg_rsp *
+pipeline_msg_handle_table_mtr_profile_delete(struct pipeline_data *p,
+	struct pipeline_msg_req *req)
+{
+	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+	uint32_t table_id = req->id;
+	uint32_t meter_profile_id =
+		req->table_mtr_profile_delete.meter_profile_id;
+	struct rte_table_action *a = p->table_data[table_id].a;
+
+	rsp->status = rte_table_action_meter_profile_delete(a,
+		meter_profile_id);
+
+	return rsp;
+}
+
 static void
 pipeline_msg_handle(struct pipeline_data *p)
 {
@@ -1914,6 +2048,14 @@ pipeline_msg_handle(struct pipeline_data *p)
 			rsp = pipeline_msg_handle_table_rule_stats_read(p, req);
 			break;
 
+		case PIPELINE_REQ_TABLE_MTR_PROFILE_ADD:
+			rsp = pipeline_msg_handle_table_mtr_profile_add(p, req);
+			break;
+
+		case PIPELINE_REQ_TABLE_MTR_PROFILE_DELETE:
+			rsp = pipeline_msg_handle_table_mtr_profile_delete(p, req);
+			break;
+
 		default:
 			rsp = (struct pipeline_msg_rsp *) req;
 			rsp->status = -1;
-- 
2.9.3

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

* [dpdk-dev] [PATCH 29/37] ip_pipeline: add cli to read meter stats
  2018-03-09 18:23 [dpdk-dev] [PATCH 00/37] ip_pipeline: refactoring Jasvinder Singh
                   ` (27 preceding siblings ...)
  2018-03-09 18:24 ` [dpdk-dev] [PATCH 28/37] ip_pipeline: add cli to configure meter profile Jasvinder Singh
@ 2018-03-09 18:24 ` Jasvinder Singh
  2018-03-09 18:24 ` [dpdk-dev] [PATCH 30/37] ip_pipeline: add cli to update dscp table Jasvinder Singh
                   ` (7 subsequent siblings)
  36 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-09 18:24 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add command to read traffic meter stats.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/cli.c      | 22 +++++++++++
 examples/ip_pipeline/pipeline.h |  8 ++++
 examples/ip_pipeline/thread.c   | 88 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 118 insertions(+)

diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index 46fe69b..09a1acf 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -3674,6 +3674,18 @@ cmd_pipeline_table_meter_profile_delete(char **tokens,
 }
 
 /**
+ * pipeline <pipeline_name> table <table_id> rule read meter [clear]
+ */
+static void
+cmd_pipeline_table_rule_meter_read(char **tokens,
+	uint32_t n_tokens __rte_unused,
+	char *out,
+	size_t out_size)
+{
+	snprintf(out, out_size, MSG_CMD_UNIMPLEM, tokens[0]);
+}
+
+/**
  * thread <thread_id> pipeline <pipeline_name> enable
  */
 static void
@@ -3987,6 +3999,16 @@ cli_process(char *in, char *out, size_t out_size)
 				n_tokens, out, out_size);
 			return;
 		}
+
+		if ((n_tokens >= 7) &&
+			(strcmp(tokens[2], "table") == 0) &&
+			(strcmp(tokens[4], "rule") == 0) &&
+			(strcmp(tokens[5], "read") == 0) &&
+			(strcmp(tokens[6], "meter") == 0)) {
+			cmd_pipeline_table_rule_meter_read(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
 	}
 
 	if (strcmp(tokens[0], "thread") == 0) {
diff --git a/examples/ip_pipeline/pipeline.h b/examples/ip_pipeline/pipeline.h
index d524145..4978555 100644
--- a/examples/ip_pipeline/pipeline.h
+++ b/examples/ip_pipeline/pipeline.h
@@ -328,4 +328,12 @@ pipeline_table_mtr_profile_delete(const char *pipeline_name,
 	uint32_t table_id,
 	uint32_t meter_profile_id);
 
+int
+pipeline_table_rule_mtr_read(const char *pipeline_name,
+	uint32_t table_id,
+	void *data,
+	uint32_t tc_mask,
+	struct rte_table_action_mtr_counters *stats,
+	int clear);
+
 #endif /* _INCLUDE_PIPELINE_H_ */
diff --git a/examples/ip_pipeline/thread.c b/examples/ip_pipeline/thread.c
index 4e326f2..0d435fb 100644
--- a/examples/ip_pipeline/thread.c
+++ b/examples/ip_pipeline/thread.c
@@ -500,6 +500,7 @@ enum pipeline_req_type {
 	PIPELINE_REQ_TABLE_RULE_STATS_READ,
 	PIPELINE_REQ_TABLE_MTR_PROFILE_ADD,
 	PIPELINE_REQ_TABLE_MTR_PROFILE_DELETE,
+	PIPELINE_REQ_TABLE_RULE_MTR_READ,
 	PIPELINE_REQ_MAX
 };
 
@@ -542,6 +543,11 @@ struct pipeline_msg_req_table_mtr_profile_delete {
 	uint32_t meter_profile_id;
 };
 
+struct pipeline_msg_req_table_rule_mtr_read {
+	void *data;
+	uint32_t tc_mask;
+	int clear;
+};
 struct pipeline_msg_req {
 	enum pipeline_req_type type;
 	uint32_t id; /* Port IN, port OUT or table ID */
@@ -557,6 +563,7 @@ struct pipeline_msg_req {
 		struct pipeline_msg_req_table_rule_stats_read table_rule_stats_read;
 		struct pipeline_msg_req_table_mtr_profile_add table_mtr_profile_add;
 		struct pipeline_msg_req_table_mtr_profile_delete table_mtr_profile_delete;
+		struct pipeline_msg_req_table_rule_mtr_read table_rule_mtr_read;
 	};
 };
 
@@ -584,6 +591,10 @@ struct pipeline_msg_rsp_table_rule_stats_read {
 	struct rte_table_action_stats_counters stats;
 };
 
+struct pipeline_msg_rsp_table_rule_mtr_read {
+	struct rte_table_action_mtr_counters stats;
+};
+
 struct pipeline_msg_rsp {
 	int status;
 
@@ -595,6 +606,7 @@ struct pipeline_msg_rsp {
 		struct pipeline_msg_rsp_table_rule_add table_rule_add;
 		struct pipeline_msg_rsp_table_rule_add_default table_rule_add_default;
 		struct pipeline_msg_rsp_table_rule_stats_read table_rule_stats_read;
+		struct pipeline_msg_rsp_table_rule_mtr_read table_rule_mtr_read;
 	};
 };
 
@@ -1350,6 +1362,58 @@ pipeline_table_mtr_profile_delete(const char *pipeline_name,
 	return status;
 }
 
+int
+pipeline_table_rule_mtr_read(const char *pipeline_name,
+	uint32_t table_id,
+	void *data,
+	uint32_t tc_mask,
+	struct rte_table_action_mtr_counters *stats,
+	int clear)
+{
+	struct pipeline *p;
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if ((pipeline_name == NULL) ||
+		(data == NULL) ||
+		(stats == NULL))
+		return -1;
+
+	p = pipeline_find(pipeline_name);
+	if ((p == NULL) ||
+		(table_id >= p->n_tables))
+		return -1;
+
+	/* Allocate request */
+	req = pipeline_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = PIPELINE_REQ_TABLE_RULE_MTR_READ;
+	req->id = table_id;
+	req->table_rule_mtr_read.data = data;
+	req->table_rule_mtr_read.tc_mask = tc_mask;
+	req->table_rule_mtr_read.clear = clear;
+
+	/* Send request and wait for response */
+	rsp = pipeline_msg_send_recv(p, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+	if (status)
+		memcpy(stats, &rsp->table_rule_mtr_read.stats, sizeof(*stats));
+
+	/* Free response */
+	pipeline_msg_free(rsp);
+
+	return status;
+}
+
 /**
  * Data plane threads: message handling
  */
@@ -1996,6 +2060,26 @@ pipeline_msg_handle_table_mtr_profile_delete(struct pipeline_data *p,
 	return rsp;
 }
 
+static struct pipeline_msg_rsp *
+pipeline_msg_handle_table_rule_mtr_read(struct pipeline_data *p,
+	struct pipeline_msg_req *req)
+{
+	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+	uint32_t table_id = req->id;
+	void *data = req->table_rule_mtr_read.data;
+	uint32_t tc_mask = req->table_rule_mtr_read.tc_mask;
+	int clear = req->table_rule_mtr_read.clear;
+	struct rte_table_action *a = p->table_data[table_id].a;
+
+	rsp->status = rte_table_action_meter_read(a,
+		data,
+		tc_mask,
+		&rsp->table_rule_mtr_read.stats,
+		clear);
+
+	return rsp;
+}
+
 static void
 pipeline_msg_handle(struct pipeline_data *p)
 {
@@ -2056,6 +2140,10 @@ pipeline_msg_handle(struct pipeline_data *p)
 			rsp = pipeline_msg_handle_table_mtr_profile_delete(p, req);
 			break;
 
+		case PIPELINE_REQ_TABLE_RULE_MTR_READ:
+			rsp = pipeline_msg_handle_table_rule_mtr_read(p, req);
+			break;
+
 		default:
 			rsp = (struct pipeline_msg_rsp *) req;
 			rsp->status = -1;
-- 
2.9.3

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

* [dpdk-dev] [PATCH 30/37] ip_pipeline: add cli to update dscp table
  2018-03-09 18:23 [dpdk-dev] [PATCH 00/37] ip_pipeline: refactoring Jasvinder Singh
                   ` (28 preceding siblings ...)
  2018-03-09 18:24 ` [dpdk-dev] [PATCH 29/37] ip_pipeline: add cli to read meter stats Jasvinder Singh
@ 2018-03-09 18:24 ` Jasvinder Singh
  2018-03-09 18:24 ` [dpdk-dev] [PATCH 31/37] ip_pipeline: add cli to read ttl stats Jasvinder Singh
                   ` (6 subsequent siblings)
  36 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-09 18:24 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add command to update the dscp table for traffic meter and traffic
manager.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/cli.c      | 154 ++++++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/pipeline.h |   6 ++
 examples/ip_pipeline/thread.c   |  77 ++++++++++++++++++++
 3 files changed, 237 insertions(+)

diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index 09a1acf..8d5c191 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -3686,6 +3686,152 @@ cmd_pipeline_table_rule_meter_read(char **tokens,
 }
 
 /**
+ * pipeline <pipeline_name> table <table_id> dscp <file_name>
+ *
+ * File <file_name>:
+ *  - exactly 64 lines
+ *  - line format: <tc_id> <tc_queue_id> <color>, with <color> as: g | y | r
+ */
+static int
+load_dscp_table(struct rte_table_action_dscp_table *dscp_table,
+	const char *file_name,
+	uint32_t *line_number)
+{
+	FILE *f = NULL;
+	uint32_t dscp, l;
+
+	/* Check input arguments */
+	if ((dscp_table == NULL) ||
+		(file_name == NULL) ||
+		(line_number == NULL)) {
+		if (line_number)
+			*line_number = 0;
+		return -EINVAL;
+	}
+
+	/* Open input file */
+	f = fopen(file_name, "r");
+	if (f == NULL) {
+		*line_number = 0;
+		return -EINVAL;
+	}
+
+	/* Read file */
+	for (dscp = 0, l = 1; ; l++) {
+		char line[64];
+		char *tokens[3];
+		enum rte_meter_color color;
+		uint32_t tc_id, tc_queue_id, n_tokens = RTE_DIM(tokens);
+
+		if (fgets(line, sizeof(line), f) == NULL)
+			break;
+
+		if (is_comment(line))
+			continue;
+
+		if (parse_tokenize_string(line, tokens, &n_tokens)) {
+			*line_number = l;
+			return -EINVAL;
+		}
+
+		if (n_tokens == 0)
+			continue;
+
+		if ((dscp >= RTE_DIM(dscp_table->entry)) ||
+			(n_tokens != RTE_DIM(tokens)) ||
+			parser_read_uint32(&tc_id, tokens[0]) ||
+			(tc_id >= RTE_TABLE_ACTION_TC_MAX) ||
+			parser_read_uint32(&tc_queue_id, tokens[1]) ||
+			(tc_queue_id >= RTE_TABLE_ACTION_TC_QUEUE_MAX) ||
+			(strlen(tokens[2]) != 1)) {
+			*line_number = l;
+			return -EINVAL;
+		}
+
+		switch (tokens[2][0]) {
+		case 'g':
+		case 'G':
+			color = e_RTE_METER_GREEN;
+			break;
+
+		case 'y':
+		case 'Y':
+			color = e_RTE_METER_YELLOW;
+			break;
+
+		case 'r':
+		case 'R':
+			color = e_RTE_METER_RED;
+			break;
+
+		default:
+			*line_number = l;
+			return -EINVAL;
+		}
+
+		dscp_table->entry[dscp].tc_id = tc_id;
+		dscp_table->entry[dscp].tc_queue_id = tc_queue_id;
+		dscp_table->entry[dscp].color = color;
+		dscp++;
+	}
+
+	/* Close file */
+	fclose(f);
+	return 0;
+}
+
+static void
+cmd_pipeline_table_dscp(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct rte_table_action_dscp_table dscp_table;
+	char *pipeline_name, *file_name;
+	uint32_t table_id, line_number;
+	int status;
+
+	if (n_tokens != 6) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "table") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
+		return;
+	}
+
+	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
+		return;
+	}
+
+	if (strcmp(tokens[4], "dscp") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "dscp");
+		return;
+	}
+
+	file_name = tokens[5];
+
+	status = load_dscp_table(&dscp_table, file_name, &line_number);
+	if (status) {
+		snprintf(out, out_size, MSG_FILE_ERR, file_name, line_number);
+		return;
+	}
+
+	status = pipeline_table_dscp_table_update(pipeline_name,
+		table_id,
+		UINT64_MAX,
+		&dscp_table);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
  * thread <thread_id> pipeline <pipeline_name> enable
  */
 static void
@@ -4009,6 +4155,14 @@ cli_process(char *in, char *out, size_t out_size)
 				out, out_size);
 			return;
 		}
+
+		if ((n_tokens >= 5) &&
+			(strcmp(tokens[2], "table") == 0) &&
+			(strcmp(tokens[4], "dscp") == 0)) {
+			cmd_pipeline_table_dscp(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
 	}
 
 	if (strcmp(tokens[0], "thread") == 0) {
diff --git a/examples/ip_pipeline/pipeline.h b/examples/ip_pipeline/pipeline.h
index 4978555..598bed0 100644
--- a/examples/ip_pipeline/pipeline.h
+++ b/examples/ip_pipeline/pipeline.h
@@ -336,4 +336,10 @@ pipeline_table_rule_mtr_read(const char *pipeline_name,
 	struct rte_table_action_mtr_counters *stats,
 	int clear);
 
+int
+pipeline_table_dscp_table_update(const char *pipeline_name,
+	uint32_t table_id,
+	uint64_t dscp_mask,
+	struct rte_table_action_dscp_table *dscp_table);
+
 #endif /* _INCLUDE_PIPELINE_H_ */
diff --git a/examples/ip_pipeline/thread.c b/examples/ip_pipeline/thread.c
index 0d435fb..11d72cf 100644
--- a/examples/ip_pipeline/thread.c
+++ b/examples/ip_pipeline/thread.c
@@ -501,6 +501,7 @@ enum pipeline_req_type {
 	PIPELINE_REQ_TABLE_MTR_PROFILE_ADD,
 	PIPELINE_REQ_TABLE_MTR_PROFILE_DELETE,
 	PIPELINE_REQ_TABLE_RULE_MTR_READ,
+	PIPELINE_REQ_TABLE_DSCP_TABLE_UPDATE,
 	PIPELINE_REQ_MAX
 };
 
@@ -548,6 +549,12 @@ struct pipeline_msg_req_table_rule_mtr_read {
 	uint32_t tc_mask;
 	int clear;
 };
+
+struct pipeline_msg_req_table_dscp_table_update {
+	uint64_t dscp_mask;
+	struct rte_table_action_dscp_table dscp_table;
+};
+
 struct pipeline_msg_req {
 	enum pipeline_req_type type;
 	uint32_t id; /* Port IN, port OUT or table ID */
@@ -564,6 +571,7 @@ struct pipeline_msg_req {
 		struct pipeline_msg_req_table_mtr_profile_add table_mtr_profile_add;
 		struct pipeline_msg_req_table_mtr_profile_delete table_mtr_profile_delete;
 		struct pipeline_msg_req_table_rule_mtr_read table_rule_mtr_read;
+		struct pipeline_msg_req_table_dscp_table_update table_dscp_table_update;
 	};
 };
 
@@ -1414,6 +1422,53 @@ pipeline_table_rule_mtr_read(const char *pipeline_name,
 	return status;
 }
 
+int
+pipeline_table_dscp_table_update(const char *pipeline_name,
+	uint32_t table_id,
+	uint64_t dscp_mask,
+	struct rte_table_action_dscp_table *dscp_table)
+{
+	struct pipeline *p;
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if ((pipeline_name == NULL) ||
+		(dscp_table == NULL))
+		return -1;
+
+	p = pipeline_find(pipeline_name);
+	if ((p == NULL) ||
+		(table_id >= p->n_tables))
+		return -1;
+
+	/* Allocate request */
+	req = pipeline_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = PIPELINE_REQ_TABLE_DSCP_TABLE_UPDATE;
+	req->id = table_id;
+	req->table_dscp_table_update.dscp_mask = dscp_mask;
+	memcpy(&req->table_dscp_table_update.dscp_table,
+		dscp_table, sizeof(*dscp_table));
+
+	/* Send request and wait for response */
+	rsp = pipeline_msg_send_recv(p, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+
+	/* Free response */
+	pipeline_msg_free(rsp);
+
+	return status;
+}
+
 /**
  * Data plane threads: message handling
  */
@@ -2080,6 +2135,24 @@ pipeline_msg_handle_table_rule_mtr_read(struct pipeline_data *p,
 	return rsp;
 }
 
+static struct pipeline_msg_rsp *
+pipeline_msg_handle_table_dscp_table_update(struct pipeline_data *p,
+	struct pipeline_msg_req *req)
+{
+	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+	uint32_t table_id = req->id;
+	uint64_t dscp_mask = req->table_dscp_table_update.dscp_mask;
+	struct rte_table_action_dscp_table *dscp_table =
+		&req->table_dscp_table_update.dscp_table;
+	struct rte_table_action *a = p->table_data[table_id].a;
+
+	rsp->status = rte_table_action_dscp_table_update(a,
+		dscp_mask,
+		dscp_table);
+
+	return rsp;
+}
+
 static void
 pipeline_msg_handle(struct pipeline_data *p)
 {
@@ -2144,6 +2217,10 @@ pipeline_msg_handle(struct pipeline_data *p)
 			rsp = pipeline_msg_handle_table_rule_mtr_read(p, req);
 			break;
 
+		case PIPELINE_REQ_TABLE_DSCP_TABLE_UPDATE:
+			rsp = pipeline_msg_handle_table_dscp_table_update(p, req);
+			break;
+
 		default:
 			rsp = (struct pipeline_msg_rsp *) req;
 			rsp->status = -1;
-- 
2.9.3

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

* [dpdk-dev] [PATCH 31/37] ip_pipeline: add cli to read ttl stats
  2018-03-09 18:23 [dpdk-dev] [PATCH 00/37] ip_pipeline: refactoring Jasvinder Singh
                   ` (29 preceding siblings ...)
  2018-03-09 18:24 ` [dpdk-dev] [PATCH 30/37] ip_pipeline: add cli to update dscp table Jasvinder Singh
@ 2018-03-09 18:24 ` Jasvinder Singh
  2018-03-09 18:24 ` [dpdk-dev] [PATCH 32/37] ip_pipeline: add l2fwd example Jasvinder Singh
                   ` (5 subsequent siblings)
  36 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-09 18:24 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add command to read the ttl stats.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/cli.c      | 22 +++++++++++
 examples/ip_pipeline/pipeline.h |  7 ++++
 examples/ip_pipeline/thread.c   | 84 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 113 insertions(+)

diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index 8d5c191..925af70 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -3832,6 +3832,18 @@ cmd_pipeline_table_dscp(char **tokens,
 }
 
 /**
+ * pipeline <pipeline_name> table <table_id> rule read ttl [clear]
+ */
+static void
+cmd_pipeline_table_rule_ttl_read(char **tokens,
+	uint32_t n_tokens __rte_unused,
+	char *out,
+	size_t out_size)
+{
+	snprintf(out, out_size, MSG_CMD_UNIMPLEM, tokens[0]);
+}
+
+/**
  * thread <thread_id> pipeline <pipeline_name> enable
  */
 static void
@@ -4163,6 +4175,16 @@ cli_process(char *in, char *out, size_t out_size)
 				out, out_size);
 			return;
 		}
+
+		if ((n_tokens >= 7) &&
+			(strcmp(tokens[2], "table") == 0) &&
+			(strcmp(tokens[4], "rule") == 0) &&
+			(strcmp(tokens[5], "read") == 0) &&
+			(strcmp(tokens[6], "ttl") == 0)) {
+			cmd_pipeline_table_rule_ttl_read(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
 	}
 
 	if (strcmp(tokens[0], "thread") == 0) {
diff --git a/examples/ip_pipeline/pipeline.h b/examples/ip_pipeline/pipeline.h
index 598bed0..208e407 100644
--- a/examples/ip_pipeline/pipeline.h
+++ b/examples/ip_pipeline/pipeline.h
@@ -342,4 +342,11 @@ pipeline_table_dscp_table_update(const char *pipeline_name,
 	uint64_t dscp_mask,
 	struct rte_table_action_dscp_table *dscp_table);
 
+int
+pipeline_table_rule_ttl_read(const char *pipeline_name,
+	uint32_t table_id,
+	void *data,
+	struct rte_table_action_ttl_counters *stats,
+	int clear);
+
 #endif /* _INCLUDE_PIPELINE_H_ */
diff --git a/examples/ip_pipeline/thread.c b/examples/ip_pipeline/thread.c
index 11d72cf..55d8a17 100644
--- a/examples/ip_pipeline/thread.c
+++ b/examples/ip_pipeline/thread.c
@@ -502,6 +502,7 @@ enum pipeline_req_type {
 	PIPELINE_REQ_TABLE_MTR_PROFILE_DELETE,
 	PIPELINE_REQ_TABLE_RULE_MTR_READ,
 	PIPELINE_REQ_TABLE_DSCP_TABLE_UPDATE,
+	PIPELINE_REQ_TABLE_RULE_TTL_READ,
 	PIPELINE_REQ_MAX
 };
 
@@ -555,6 +556,11 @@ struct pipeline_msg_req_table_dscp_table_update {
 	struct rte_table_action_dscp_table dscp_table;
 };
 
+struct pipeline_msg_req_table_rule_ttl_read {
+	void *data;
+	int clear;
+};
+
 struct pipeline_msg_req {
 	enum pipeline_req_type type;
 	uint32_t id; /* Port IN, port OUT or table ID */
@@ -572,6 +578,7 @@ struct pipeline_msg_req {
 		struct pipeline_msg_req_table_mtr_profile_delete table_mtr_profile_delete;
 		struct pipeline_msg_req_table_rule_mtr_read table_rule_mtr_read;
 		struct pipeline_msg_req_table_dscp_table_update table_dscp_table_update;
+		struct pipeline_msg_req_table_rule_ttl_read table_rule_ttl_read;
 	};
 };
 
@@ -603,6 +610,10 @@ struct pipeline_msg_rsp_table_rule_mtr_read {
 	struct rte_table_action_mtr_counters stats;
 };
 
+struct pipeline_msg_rsp_table_rule_ttl_read {
+	struct rte_table_action_ttl_counters stats;
+};
+
 struct pipeline_msg_rsp {
 	int status;
 
@@ -615,6 +626,7 @@ struct pipeline_msg_rsp {
 		struct pipeline_msg_rsp_table_rule_add_default table_rule_add_default;
 		struct pipeline_msg_rsp_table_rule_stats_read table_rule_stats_read;
 		struct pipeline_msg_rsp_table_rule_mtr_read table_rule_mtr_read;
+		struct pipeline_msg_rsp_table_rule_ttl_read table_rule_ttl_read;
 	};
 };
 
@@ -1469,6 +1481,56 @@ pipeline_table_dscp_table_update(const char *pipeline_name,
 	return status;
 }
 
+int
+pipeline_table_rule_ttl_read(const char *pipeline_name,
+	uint32_t table_id,
+	void *data,
+	struct rte_table_action_ttl_counters *stats,
+	int clear)
+{
+	struct pipeline *p;
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if ((pipeline_name == NULL) ||
+		(data == NULL) ||
+		(stats == NULL))
+		return -1;
+
+	p = pipeline_find(pipeline_name);
+	if ((p == NULL) ||
+		(table_id >= p->n_tables))
+		return -1;
+
+	/* Allocate request */
+	req = pipeline_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = PIPELINE_REQ_TABLE_RULE_TTL_READ;
+	req->id = table_id;
+	req->table_rule_ttl_read.data = data;
+	req->table_rule_ttl_read.clear = clear;
+
+	/* Send request and wait for response */
+	rsp = pipeline_msg_send_recv(p, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+	if (status)
+		memcpy(stats, &rsp->table_rule_ttl_read.stats, sizeof(*stats));
+
+	/* Free response */
+	pipeline_msg_free(rsp);
+
+	return status;
+}
+
 /**
  * Data plane threads: message handling
  */
@@ -2153,6 +2215,24 @@ pipeline_msg_handle_table_dscp_table_update(struct pipeline_data *p,
 	return rsp;
 }
 
+static struct pipeline_msg_rsp *
+pipeline_msg_handle_table_rule_ttl_read(struct pipeline_data *p,
+	struct pipeline_msg_req *req)
+{
+	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+	uint32_t table_id = req->id;
+	void *data = req->table_rule_ttl_read.data;
+	int clear = req->table_rule_ttl_read.clear;
+	struct rte_table_action *a = p->table_data[table_id].a;
+
+	rsp->status = rte_table_action_ttl_read(a,
+		data,
+		&rsp->table_rule_ttl_read.stats,
+		clear);
+
+	return rsp;
+}
+
 static void
 pipeline_msg_handle(struct pipeline_data *p)
 {
@@ -2221,6 +2301,10 @@ pipeline_msg_handle(struct pipeline_data *p)
 			rsp = pipeline_msg_handle_table_dscp_table_update(p, req);
 			break;
 
+		case PIPELINE_REQ_TABLE_RULE_TTL_READ:
+			rsp = pipeline_msg_handle_table_rule_ttl_read(p, req);
+			break;
+
 		default:
 			rsp = (struct pipeline_msg_rsp *) req;
 			rsp->status = -1;
-- 
2.9.3

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

* [dpdk-dev] [PATCH 32/37] ip_pipeline: add l2fwd example
  2018-03-09 18:23 [dpdk-dev] [PATCH 00/37] ip_pipeline: refactoring Jasvinder Singh
                   ` (30 preceding siblings ...)
  2018-03-09 18:24 ` [dpdk-dev] [PATCH 31/37] ip_pipeline: add cli to read ttl stats Jasvinder Singh
@ 2018-03-09 18:24 ` Jasvinder Singh
  2018-03-09 18:24 ` [dpdk-dev] [PATCH 33/37] ip_pipeline: add KNI port example Jasvinder Singh
                   ` (4 subsequent siblings)
  36 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-09 18:24 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Kevin Laatz

This patch add the configuration file for l2fwd example. It
includes commands to build the packet processing stage (pipeline),
defining action, add rules to its table, etc.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
---
 examples/ip_pipeline/examples/l2fwd.cli | 53 +++++++++++++++++++++++++++++++++
 1 file changed, 53 insertions(+)
 create mode 100644 examples/ip_pipeline/examples/l2fwd.cli

diff --git a/examples/ip_pipeline/examples/l2fwd.cli b/examples/ip_pipeline/examples/l2fwd.cli
new file mode 100644
index 0000000..5b9d529
--- /dev/null
+++ b/examples/ip_pipeline/examples/l2fwd.cli
@@ -0,0 +1,53 @@
+; SPDX-License-Identifier: BSD-3-Clause
+; Copyright(c) 2010-2018 Intel Corporation
+
+; The pipeline below implements a simple pass-through connection between the
+; input ports to the output ports, as in this diagram:
+;                 ________________
+; LINK0 RXQ0 --->|................|---> LINK1 TXQ0
+;                |                |
+; LINK1 RXQ0 --->|................|---> LINK0 TXQ0
+;                |    PIPELINE0   |
+; LINK2 RXQ0 --->|................|---> LINK3 TXQ0
+;                |                |
+; LINK3 RXQ0 --->|................|---> LINK2 TXQ0
+;                |________________|
+;
+
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+
+link LINK0 dev 0000:02:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+link LINK1 dev 0000:02:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+link LINK2 dev 0000:06:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+link LINK3 dev 0000:06:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+
+table action profile AP0 ipv4 offset 270 fwd
+
+pipeline PIPELINE0 period 10 offset_port_id 0 cpu 0
+
+pipeline PIPELINE0 port in bsz 32 link LINK0 rxq 0
+pipeline PIPELINE0 port in bsz 32 link LINK1 rxq 0
+pipeline PIPELINE0 port in bsz 32 link LINK2 rxq 0
+pipeline PIPELINE0 port in bsz 32 link LINK3 rxq 0
+
+pipeline PIPELINE0 port out bsz 32 link LINK0 txq 0
+pipeline PIPELINE0 port out bsz 32 link LINK1 txq 0
+pipeline PIPELINE0 port out bsz 32 link LINK2 txq 0
+pipeline PIPELINE0 port out bsz 32 link LINK3 txq 0
+
+pipeline PIPELINE0 table match stub action AP0
+pipeline PIPELINE0 table match stub action AP0
+pipeline PIPELINE0 table match stub action AP0
+pipeline PIPELINE0 table match stub action AP0
+
+pipeline PIPELINE0 port in 0 table 0
+pipeline PIPELINE0 port in 1 table 1
+pipeline PIPELINE0 port in 2 table 2
+pipeline PIPELINE0 port in 3 table 3
+
+thread 1 pipeline PIPELINE0 enable
+
+pipeline PIPELINE0 table 0 rule add match default action fwd port 1
+pipeline PIPELINE0 table 1 rule add match default action fwd port 0
+pipeline PIPELINE0 table 2 rule add match default action fwd port 3
+pipeline PIPELINE0 table 3 rule add match default action fwd port 2
-- 
2.9.3

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

* [dpdk-dev] [PATCH 33/37] ip_pipeline: add KNI port example
  2018-03-09 18:23 [dpdk-dev] [PATCH 00/37] ip_pipeline: refactoring Jasvinder Singh
                   ` (31 preceding siblings ...)
  2018-03-09 18:24 ` [dpdk-dev] [PATCH 32/37] ip_pipeline: add l2fwd example Jasvinder Singh
@ 2018-03-09 18:24 ` Jasvinder Singh
  2018-03-09 18:24 ` [dpdk-dev] [PATCH 34/37] ip_pipeline: add TAP " Jasvinder Singh
                   ` (3 subsequent siblings)
  36 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-09 18:24 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Kevin Laatz

Add example to illustrate the pipeline functioning with KNI
interface.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
---
 examples/ip_pipeline/examples/kni.cli | 69 +++++++++++++++++++++++++++++++++++
 1 file changed, 69 insertions(+)
 create mode 100644 examples/ip_pipeline/examples/kni.cli

diff --git a/examples/ip_pipeline/examples/kni.cli b/examples/ip_pipeline/examples/kni.cli
new file mode 100644
index 0000000..1438340
--- /dev/null
+++ b/examples/ip_pipeline/examples/kni.cli
@@ -0,0 +1,69 @@
+; SPDX-License-Identifier: BSD-3-Clause
+; Copyright(c) 2010-2018 Intel Corporation
+
+;                 _______________          ______________________
+;                |               |  KNI0  |                      |
+; LINK0 RXQ0 --->|...............|------->|--+                   |
+;                |               |  KNI1  |  | br0               |
+; LINK1 TXQ0 <---|...............|<-------|<-+                   |
+;                |               |        |     Linux Kernel     |
+;                |   PIPELINE0   |        |     Network Stack    |
+;                |               |  KNI1  |                      |
+; LINK1 RXQ0 --->|...............|------->|--+                   |
+;                |               |  KNI0  |  | br0               |
+; LINK0 TXQ0 <---|...............|<-------|<-+                   |
+;                |_______________|        |______________________|
+;
+; Insert Linux kernel KNI module:
+;    [Linux]$ insmod rte_kni.ko
+;
+; Configure Linux kernel bridge between KNI0 and KNI1 interfaces:
+;    [Linux]$ brctl addbr br0
+;    [Linux]$ brctl addif br0 KNI0
+;    [Linux]$ brctl addif br0 KNI1
+;    [Linux]$ ifconfig br0 up
+;    [Linux]$ ifconfig KNI0 up
+;    [Linux]$ ifconfig KNI1 up
+;
+; Monitor packet forwarding performed by Linux kernel between KNI0 and KNI1:
+;    [Linux]$ tcpdump -i KNI0
+;    [Linux]$ tcpdump -i KNI1
+
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+
+link LINK0 dev 0000:02:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+link LINK1 dev 0000:02:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+
+kni KNI0 link LINK0 mempool MEMPOOL0
+kni KNI1 link LINK1 mempool MEMPOOL0
+
+table action profile AP0 ipv4 offset 270 fwd
+
+pipeline PIPELINE0 period 10 offset_port_id 0 cpu 0
+
+pipeline PIPELINE0 port in bsz 32 link LINK0 rxq 0
+pipeline PIPELINE0 port in bsz 32 kni KNI1
+pipeline PIPELINE0 port in bsz 32 link LINK1 rxq 0
+pipeline PIPELINE0 port in bsz 32 kni KNI0
+
+pipeline PIPELINE0 port out bsz 32 kni KNI0
+pipeline PIPELINE0 port out bsz 32 link LINK1 txq 0
+pipeline PIPELINE0 port out bsz 32 kni KNI1
+pipeline PIPELINE0 port out bsz 32 link LINK0 txq 0
+
+pipeline PIPELINE0 table match stub action AP0
+pipeline PIPELINE0 table match stub action AP0
+pipeline PIPELINE0 table match stub action AP0
+pipeline PIPELINE0 table match stub action AP0
+
+pipeline PIPELINE0 port in 0 table 0
+pipeline PIPELINE0 port in 1 table 1
+pipeline PIPELINE0 port in 2 table 2
+pipeline PIPELINE0 port in 3 table 3
+
+thread 1 pipeline PIPELINE0 enable
+
+pipeline PIPELINE0 table 0 rule add match default action fwd port 0
+pipeline PIPELINE0 table 1 rule add match default action fwd port 1
+pipeline PIPELINE0 table 2 rule add match default action fwd port 2
+pipeline PIPELINE0 table 3 rule add match default action fwd port 3
-- 
2.9.3

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

* [dpdk-dev] [PATCH 34/37] ip_pipeline: add TAP port example
  2018-03-09 18:23 [dpdk-dev] [PATCH 00/37] ip_pipeline: refactoring Jasvinder Singh
                   ` (32 preceding siblings ...)
  2018-03-09 18:24 ` [dpdk-dev] [PATCH 33/37] ip_pipeline: add KNI port example Jasvinder Singh
@ 2018-03-09 18:24 ` Jasvinder Singh
  2018-03-09 18:24 ` [dpdk-dev] [PATCH 35/37] ip_pipeline: add route example Jasvinder Singh
                   ` (2 subsequent siblings)
  36 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-09 18:24 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Kevin Laatz

Add example to illustrate the pipeline functioning with TAP
interface.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
---
 examples/ip_pipeline/examples/tap.cli | 66 +++++++++++++++++++++++++++++++++++
 1 file changed, 66 insertions(+)
 create mode 100644 examples/ip_pipeline/examples/tap.cli

diff --git a/examples/ip_pipeline/examples/tap.cli b/examples/ip_pipeline/examples/tap.cli
new file mode 100644
index 0000000..600cea2
--- /dev/null
+++ b/examples/ip_pipeline/examples/tap.cli
@@ -0,0 +1,66 @@
+; SPDX-License-Identifier: BSD-3-Clause
+; Copyright(c) 2010-2018 Intel Corporation
+
+;                 _______________          ______________________
+;                |               |  TAP0  |                      |
+; LINK0 RXQ0 --->|...............|------->|--+                   |
+;                |               |  TAP1  |  | br0               |
+; LINK1 TXQ0 <---|...............|<-------|<-+                   |
+;                |               |        |     Linux Kernel     |
+;                |   PIPELINE0   |        |     Network Stack    |
+;                |               |  TAP1  |                      |
+; LINK1 RXQ0 --->|...............|------->|--+                   |
+;                |               |  TAP0  |  | br0               |
+; LINK0 TXQ0 <---|...............|<-------|<-+                   |
+;                |_______________|        |______________________|
+;
+; Configure Linux kernel bridge between TAP0 and TAP1 interfaces:
+;    [Linux]$ brctl addbr br0
+;    [Linux]$ brctl addif br0 TAP0
+;    [Linux]$ brctl addif br0 TAP1
+;    [Linux]$ ifconfig TAP0 up
+;    [Linux]$ ifconfig TAP1 up
+;    [Linux]$ ifconfig br0 up
+;
+; Monitor packet forwarding performed by Linux kernel between TAP0 and TAP1:
+;    [Linux]$ tcpdump -i TAP0
+;    [Linux]$ tcpdump -i TAP1
+
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+
+link LINK0 dev 0000:02:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+link LINK1 dev 0000:02:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+
+tap TAP0
+tap TAP1
+
+table action profile AP0 ipv4 offset 270 fwd
+
+pipeline PIPELINE0 period 10 offset_port_id 0 cpu 0
+
+pipeline PIPELINE0 port in bsz 32 link LINK0 rxq 0
+pipeline PIPELINE0 port in bsz 32 tap TAP1 mempool MEMPOOL0 mtu 1500
+pipeline PIPELINE0 port in bsz 32 link LINK1 rxq 0
+pipeline PIPELINE0 port in bsz 32 tap TAP0 mempool MEMPOOL0 mtu 1500
+
+pipeline PIPELINE0 port out bsz 32 tap TAP0
+pipeline PIPELINE0 port out bsz 32 link LINK1 txq 0
+pipeline PIPELINE0 port out bsz 32 tap TAP1
+pipeline PIPELINE0 port out bsz 32 link LINK0 txq 0
+
+pipeline PIPELINE0 table match stub action AP0
+pipeline PIPELINE0 table match stub action AP0
+pipeline PIPELINE0 table match stub action AP0
+pipeline PIPELINE0 table match stub action AP0
+
+pipeline PIPELINE0 port in 0 table 0
+pipeline PIPELINE0 port in 1 table 1
+pipeline PIPELINE0 port in 2 table 2
+pipeline PIPELINE0 port in 3 table 3
+
+thread 1 pipeline PIPELINE0 enable
+
+pipeline PIPELINE0 table 0 rule add match default action fwd port 0
+pipeline PIPELINE0 table 1 rule add match default action fwd port 1
+pipeline PIPELINE0 table 2 rule add match default action fwd port 2
+pipeline PIPELINE0 table 3 rule add match default action fwd port 3
-- 
2.9.3

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

* [dpdk-dev] [PATCH 35/37] ip_pipeline: add route example
  2018-03-09 18:23 [dpdk-dev] [PATCH 00/37] ip_pipeline: refactoring Jasvinder Singh
                   ` (33 preceding siblings ...)
  2018-03-09 18:24 ` [dpdk-dev] [PATCH 34/37] ip_pipeline: add TAP " Jasvinder Singh
@ 2018-03-09 18:24 ` Jasvinder Singh
  2018-03-09 18:24 ` [dpdk-dev] [PATCH 36/37] ip_pipeline: add firewall example Jasvinder Singh
  2018-03-09 18:24 ` [dpdk-dev] [PATCH 37/37] ip_pipeline: add flow classification example Jasvinder Singh
  36 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-09 18:24 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Reshma Pattan

Add example to built pipeline with LPM table to demonstrate layer 3
routing.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Reshma Pattan <reshma.pattan@intel.com>
---
 examples/ip_pipeline/examples/route.cli | 60 +++++++++++++++++++++++++++++++++
 1 file changed, 60 insertions(+)
 create mode 100644 examples/ip_pipeline/examples/route.cli

diff --git a/examples/ip_pipeline/examples/route.cli b/examples/ip_pipeline/examples/route.cli
new file mode 100644
index 0000000..50f0a10
--- /dev/null
+++ b/examples/ip_pipeline/examples/route.cli
@@ -0,0 +1,60 @@
+; SPDX-License-Identifier: BSD-3-Clause
+; Copyright(c) 2010-2018 Intel Corporation
+
+;                 _______________
+; LINK0 RXQ0 --->|               |---> LINK0 TXQ0
+;                |               |
+; LINK1 RXQ0 --->|               |---> LINK1 TXQ0
+;                |    Routing    |
+; LINK2 RXQ0 --->|               |---> LINK2 TXQ0
+;                |               |
+; LINK3 RXQ0 --->|               |---> LINK3 TXQ0
+;                |_______________|
+;                        |
+;                        +-----------> SINK0 (route miss)
+;
+; Input packet: Ethernet/IPv4
+;
+; Packet buffer layout:
+; #   Field Name       Offset (Bytes)   Size (Bytes)
+; 0   Mbuf             0                128
+; 1   Headroom         128              128
+; 2   Ethernet header  256              14
+; 3   IPv4 header      270              20
+
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+
+link LINK0 dev 0000:02:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+link LINK1 dev 0000:02:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+link LINK2 dev 0000:06:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+link LINK3 dev 0000:06:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+
+table action profile AP0 ipv4 offset 270 fwd encap ether
+
+pipeline PIPELINE0 period 10 offset_port_id 0 cpu 0
+
+pipeline PIPELINE0 port in bsz 32 link LINK0 rxq 0
+pipeline PIPELINE0 port in bsz 32 link LINK1 rxq 0
+pipeline PIPELINE0 port in bsz 32 link LINK2 rxq 0
+pipeline PIPELINE0 port in bsz 32 link LINK3 rxq 0
+
+pipeline PIPELINE0 port out bsz 32 link LINK0 txq 0
+pipeline PIPELINE0 port out bsz 32 link LINK1 txq 0
+pipeline PIPELINE0 port out bsz 32 link LINK2 txq 0
+pipeline PIPELINE0 port out bsz 32 link LINK3 txq 0
+pipeline PIPELINE0 port out bsz 32 sink SINK0
+
+pipeline PIPELINE0 table match lpm ipv4 offset 286 size 4K action AP0
+
+pipeline PIPELINE0 port in 0 table 0
+pipeline PIPELINE0 port in 1 table 0
+pipeline PIPELINE0 port in 2 table 0
+pipeline PIPELINE0 port in 3 table 0
+
+thread 1 pipeline PIPELINE0 enable
+
+pipeline PIPELINE0 table 0 rule add match default action fwd port 4
+pipeline PIPELINE0 table 0 rule add match lpm ipv4 100.0.0.0 10 action fwd port 0 encap ether a0:a1:a2:a3:a4:a5 00:01:02:03:04:05
+pipeline PIPELINE0 table 0 rule add match lpm ipv4 100.64.0.0 10 action fwd port 1 encap ether b0:b1:b2:b3:b4:b5 10:11:12:13:14:15
+pipeline PIPELINE0 table 0 rule add match lpm ipv4 100.128.0.0 10 action fwd port 2 encap ether c0:c1:c2:c3:c4:c5 20:21:22:23:24:25
+pipeline PIPELINE0 table 0 rule add match lpm ipv4 100.192.0.0 10 action fwd port 3 encap ether d0:d1:d2:d3:d4:d5 30:31:32:33:34:35
-- 
2.9.3

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

* [dpdk-dev] [PATCH 36/37] ip_pipeline: add firewall example
  2018-03-09 18:23 [dpdk-dev] [PATCH 00/37] ip_pipeline: refactoring Jasvinder Singh
                   ` (34 preceding siblings ...)
  2018-03-09 18:24 ` [dpdk-dev] [PATCH 35/37] ip_pipeline: add route example Jasvinder Singh
@ 2018-03-09 18:24 ` Jasvinder Singh
  2018-03-09 18:24 ` [dpdk-dev] [PATCH 37/37] ip_pipeline: add flow classification example Jasvinder Singh
  36 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-09 18:24 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add example to built pipeline with ACL table to demonstrate
the firewall operation.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/examples/firewall.cli | 59 ++++++++++++++++++++++++++++++
 1 file changed, 59 insertions(+)
 create mode 100644 examples/ip_pipeline/examples/firewall.cli

diff --git a/examples/ip_pipeline/examples/firewall.cli b/examples/ip_pipeline/examples/firewall.cli
new file mode 100644
index 0000000..269256c
--- /dev/null
+++ b/examples/ip_pipeline/examples/firewall.cli
@@ -0,0 +1,59 @@
+; SPDX-License-Identifier: BSD-3-Clause
+; Copyright(c) 2010-2018 Intel Corporation
+
+;                 _______________
+; LINK0 RXQ0 --->|               |---> LINK0 TXQ0
+;                |               |
+; LINK1 RXQ0 --->|               |---> LINK1 TXQ0
+;                |   Firewall    |
+; LINK2 RXQ0 --->|               |---> LINK2 TXQ0
+;                |               |
+; LINK3 RXQ0 --->|               |---> LINK3 TXQ0
+;                |_______________|
+;                        |
+;                       -+-
+;
+; Input packet: Ethernet/IPv4
+;
+; Packet buffer layout:
+; #   Field Name            Offset (Bytes)      Size (Bytes)
+; 0   Mbuf                  0                   128
+; 1   Headroom              128                 128
+; 2   Ethernet header       256                 14
+; 3   IPv4 header           270                 20
+
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+
+link LINK0 dev 0000:02:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+link LINK1 dev 0000:02:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+link LINK2 dev 0000:06:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+link LINK3 dev 0000:06:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+
+table action profile AP0 ipv4 offset 270 fwd
+
+pipeline PIPELINE0 period 10 offset_port_id 0 cpu 0
+
+pipeline PIPELINE0 port in bsz 32 link LINK0 rxq 0
+pipeline PIPELINE0 port in bsz 32 link LINK1 rxq 0
+pipeline PIPELINE0 port in bsz 32 link LINK2 rxq 0
+pipeline PIPELINE0 port in bsz 32 link LINK3 rxq 0
+
+pipeline PIPELINE0 port out bsz 32 link LINK0 txq 0
+pipeline PIPELINE0 port out bsz 32 link LINK1 txq 0
+pipeline PIPELINE0 port out bsz 32 link LINK2 txq 0
+pipeline PIPELINE0 port out bsz 32 link LINK3 txq 0
+
+pipeline PIPELINE0 table match acl ipv4 offset 270 size 4K action AP0
+
+pipeline PIPELINE0 port in 0 table 0
+pipeline PIPELINE0 port in 1 table 0
+pipeline PIPELINE0 port in 2 table 0
+pipeline PIPELINE0 port in 3 table 0
+
+thread 1 pipeline PIPELINE0 enable
+
+pipeline PIPELINE0 table 0 rule add match default action fwd drop
+pipeline PIPELINE0 table 0 rule add match acl priority 0 ipv4 0.0.0.0 0 100.0.0.0 10 0 65535 0 65535 6 action fwd port 0
+pipeline PIPELINE0 table 0 rule add match acl priority 0 ipv4 0.0.0.0 0 100.64.0.0 10 0 65535 0 65535 6 action fwd port 1
+pipeline PIPELINE0 table 0 rule add match acl priority 0 ipv4 0.0.0.0 0 100.128.0.0 10 0 65535 0 65535 6 action fwd port 2
+pipeline PIPELINE0 table 0 rule add match acl priority 0 ipv4 0.0.0.0 0 100.192.0.0 10 0 65535 0 65535 6 action fwd port 3
-- 
2.9.3

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

* [dpdk-dev] [PATCH 37/37] ip_pipeline: add flow classification example
  2018-03-09 18:23 [dpdk-dev] [PATCH 00/37] ip_pipeline: refactoring Jasvinder Singh
                   ` (35 preceding siblings ...)
  2018-03-09 18:24 ` [dpdk-dev] [PATCH 36/37] ip_pipeline: add firewall example Jasvinder Singh
@ 2018-03-09 18:24 ` Jasvinder Singh
  36 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-09 18:24 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Fan Zhang

Add example to build pipeline with hash table to classify the
ingress traffic.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Fan Zhang <roy.fan.zhang@intel.com>
---
 examples/ip_pipeline/examples/flow.cli | 60 ++++++++++++++++++++++++++++++++++
 1 file changed, 60 insertions(+)
 create mode 100644 examples/ip_pipeline/examples/flow.cli

diff --git a/examples/ip_pipeline/examples/flow.cli b/examples/ip_pipeline/examples/flow.cli
new file mode 100644
index 0000000..60b8445
--- /dev/null
+++ b/examples/ip_pipeline/examples/flow.cli
@@ -0,0 +1,60 @@
+; SPDX-License-Identifier: BSD-3-Clause
+; Copyright(c) 2010-2018 Intel Corporation
+
+;                 ________________
+; LINK0 RXQ0 --->|                |---> LINK0 TXQ0
+;                |                |
+; LINK1 RXQ0 --->|                |---> LINK1 TXQ0
+;                |      Flow      |
+; LINK2 RXQ0 --->| Classification |---> LINK2 TXQ0
+;                |                |
+; LINK3 RXQ0 --->|                |---> LINK3 TXQ0
+;                |________________|
+;                        |
+;                        +-----------> SINK0 (flow lookup miss)
+;
+; Input packet: Ethernet/IPv4
+;
+; Packet buffer layout:
+; #   Field Name       Offset (Bytes)   Size (Bytes)
+; 0   Mbuf             0                128
+; 1   Headroom         128              128
+; 2   Ethernet header  256              14
+; 3   IPv4 header      270              20
+
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+
+link LINK0 dev 0000:02:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+link LINK1 dev 0000:02:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+link LINK2 dev 0000:06:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+link LINK3 dev 0000:06:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+
+table action profile AP0 ipv4 offset 270 fwd
+
+pipeline PIPELINE0 period 10 offset_port_id 0 cpu 0
+
+pipeline PIPELINE0 port in bsz 32 link LINK0 rxq 0
+pipeline PIPELINE0 port in bsz 32 link LINK1 rxq 0
+pipeline PIPELINE0 port in bsz 32 link LINK2 rxq 0
+pipeline PIPELINE0 port in bsz 32 link LINK3 rxq 0
+
+pipeline PIPELINE0 port out bsz 32 link LINK0 txq 0
+pipeline PIPELINE0 port out bsz 32 link LINK1 txq 0
+pipeline PIPELINE0 port out bsz 32 link LINK2 txq 0
+pipeline PIPELINE0 port out bsz 32 link LINK3 txq 0
+pipeline PIPELINE0 port out bsz 32 sink SINK0
+
+pipeline PIPELINE0 table match hash ext key 16 mask 00FF0000FFFFFFFFFFFFFFFFFFFFFFFF offset 278 buckets 16K size 65K action AP0
+
+pipeline PIPELINE0 port in 0 table 0
+pipeline PIPELINE0 port in 1 table 0
+pipeline PIPELINE0 port in 2 table 0
+pipeline PIPELINE0 port in 3 table 0
+
+thread 1 pipeline PIPELINE0 enable
+
+pipeline PIPELINE0 table 0 rule add match default action fwd port 4
+pipeline PIPELINE0 table 0 rule add match hash ipv4_5tuple 100.0.0.10 200.0.0.10 100 200 6 action fwd port 0
+pipeline PIPELINE0 table 0 rule add match hash ipv4_5tuple 100.0.0.11 200.0.0.11 101 201 6 action fwd port 1
+pipeline PIPELINE0 table 0 rule add match hash ipv4_5tuple 100.0.0.12 200.0.0.12 102 202 6 action fwd port 2
+pipeline PIPELINE0 table 0 rule add match hash ipv4_5tuple 100.0.0.13 200.0.0.13 103 203 6 action fwd port 3
-- 
2.9.3

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

* [dpdk-dev] [PATCH v2 00/44] ip_pipeline: refactoring
  2018-03-09 18:23 ` [dpdk-dev] [PATCH 01/37] pipeline: add pipeline table action APIs Jasvinder Singh
@ 2018-03-12 17:25   ` Jasvinder Singh
  2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 01/44] pipeline: add pipeline table action APIs Jasvinder Singh
                       ` (43 more replies)
  0 siblings, 44 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-12 17:25 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Refactored the IP pipeline application. As result, the code base
size (lines of code) reduces by ~60%.

1. Moved table actions into the librte_pipeline library. As result,
   the pre-fabricated pipelines from the application pipeline folder
   were removed. The flexibility is greatly improved, as now any
   action can be combined with any match (i.e. table type), which
   was not possible before.

2. Removed configuration file as the initialization method. Now
   all the pipelines are set up and assigned to threads through
   CLI commands for improved flexibility.

3. Replaced the local CLI with remote CLI. Any standard TCP
   client (e.g. telnet, netcat) can now connect to the app,
   send request as command string through the network and wait
   for the response string before pushing the next command.
   Results in better flexibility and automation.

v2:
- split the patch that removes the existing pipeline components
  into multiple patches.
- fix checkpatch errors.

Jasvinder Singh (44):
  pipeline: add pipeline table action APIs
  pipeline: get pipeline table action params
  pipeline: add traffic metering action
  pipeline: add traffic manager action
  pipeline: add packet encapsulation action
  pipeline: add nat action
  pipeline: add ttl update action
  pipeline: add statistics read action
  pipeline: add timestamp action
  ip_pipeline: remove passthrough pipeline
  ip_pipeline: remove routing pipeline
  ip_pipeline: remove flow classification pipeline
  ip_pipeline: remove flow actions pipeline
  ip_pipeline: remove firewall pipeline
  ip_pipeline: remove master pipeline
  ip_pipeline: remove config
  ip_pipeline: rework and improvements
  ip_pipeline: add cli interface
  ip_pipeline: add mempool object for pipeline
  ip_pipeline: add link object
  ip_pipeline: add software queue object
  ip_pipeline: add traffic manager object
  ip_pipeline: add tap object
  ip_pipeline: add kni object
  ip_pipeline: add action profile object
  ip_pipeline: add pipeline object
  ip_pipeline: add threads
  ip_pipeline: add thread runtime
  ip_pipeline: add cli to enable and disable pipeline
  ip_pipeline: add cli to enable and disable pipeline port
  ip_pipeline: add cli to read pipeline port and table stats
  ip_pipeline: add cli for pipeline table entries
  ip_pipeline: add cli to delete pipeline table entry
  ip_pipeline: add cli to read pipeline table entry stats
  ip_pipeline: add cli to configure meter profile
  ip_pipeline: add cli to read meter stats
  ip_pipeline: add cli to update dscp table
  ip_pipeline: add cli to read ttl stats
  ip_pipeline: add l2fwd example
  ip_pipeline: add KNI port example
  ip_pipeline: add TAP port example
  ip_pipeline: add route example
  ip_pipeline: add firewall example
  ip_pipeline: add flow classification example

 doc/api/doxy-api-index.md                          |    1 +
 examples/ip_pipeline/Makefile                      |   49 +-
 examples/ip_pipeline/action.c                      |  165 +
 examples/ip_pipeline/action.h                      |   44 +
 examples/ip_pipeline/app.h                         | 1401 -------
 examples/ip_pipeline/cli.c                         | 4261 ++++++++++++++++++++
 examples/ip_pipeline/cli.h                         |   18 +
 examples/ip_pipeline/common.h                      |   12 +
 examples/ip_pipeline/config/action.cfg             |   68 -
 examples/ip_pipeline/config/action.sh              |  119 -
 examples/ip_pipeline/config/action.txt             |    8 -
 examples/ip_pipeline/config/diagram-generator.py   |  317 --
 .../ip_pipeline/config/edge_router_downstream.cfg  |   97 -
 .../ip_pipeline/config/edge_router_downstream.sh   |   13 -
 .../ip_pipeline/config/edge_router_upstream.cfg    |  124 -
 .../ip_pipeline/config/edge_router_upstream.sh     |   33 -
 examples/ip_pipeline/config/firewall.cfg           |   68 -
 examples/ip_pipeline/config/firewall.sh            |   13 -
 examples/ip_pipeline/config/firewall.txt           |    9 -
 examples/ip_pipeline/config/flow.cfg               |   72 -
 examples/ip_pipeline/config/flow.sh                |   25 -
 examples/ip_pipeline/config/flow.txt               |   17 -
 examples/ip_pipeline/config/ip_pipeline.cfg        |    9 -
 examples/ip_pipeline/config/ip_pipeline.sh         |    5 -
 examples/ip_pipeline/config/kni.cfg                |   67 -
 examples/ip_pipeline/config/l2fwd.cfg              |   58 -
 examples/ip_pipeline/config/l3fwd.cfg              |   68 -
 examples/ip_pipeline/config/l3fwd.sh               |   33 -
 examples/ip_pipeline/config/l3fwd_arp.cfg          |   70 -
 examples/ip_pipeline/config/l3fwd_arp.sh           |   43 -
 examples/ip_pipeline/config/network_layers.cfg     |  227 --
 examples/ip_pipeline/config/network_layers.sh      |   79 -
 .../ip_pipeline/config/pipeline-to-core-mapping.py |  906 -----
 examples/ip_pipeline/config/tap.cfg                |   64 -
 examples/ip_pipeline/config/tm_profile.cfg         |  105 -
 examples/ip_pipeline/config_check.c                |  488 ---
 examples/ip_pipeline/config_parse.c                | 3395 ----------------
 examples/ip_pipeline/config_parse_tm.c             |  419 --
 examples/ip_pipeline/conn.c                        |  326 ++
 examples/ip_pipeline/conn.h                        |   47 +
 examples/ip_pipeline/cpu_core_map.c                |  471 ---
 examples/ip_pipeline/cpu_core_map.h                |   40 -
 examples/ip_pipeline/examples/firewall.cli         |   59 +
 examples/ip_pipeline/examples/flow.cli             |   60 +
 examples/ip_pipeline/examples/kni.cli              |   69 +
 examples/ip_pipeline/examples/l2fwd.cli            |   53 +
 examples/ip_pipeline/examples/route.cli            |   60 +
 examples/ip_pipeline/examples/tap.cli              |   66 +
 examples/ip_pipeline/{pipeline => }/hash_func.h    |    3 +-
 .../ip_pipeline/{pipeline => }/hash_func_arm64.h   |    0
 examples/ip_pipeline/init.c                        | 1927 ---------
 examples/ip_pipeline/kni.c                         |  167 +
 examples/ip_pipeline/kni.h                         |   44 +
 examples/ip_pipeline/link.c                        |  268 ++
 examples/ip_pipeline/link.h                        |   63 +
 examples/ip_pipeline/main.c                        |  253 +-
 examples/ip_pipeline/mempool.c                     |   81 +
 examples/ip_pipeline/mempool.h                     |   40 +
 examples/ip_pipeline/meson.build                   |   36 +-
 examples/ip_pipeline/parser.c                      |   16 +-
 examples/ip_pipeline/parser.h                      |    8 +
 examples/ip_pipeline/pipeline.c                    |  930 +++++
 examples/ip_pipeline/pipeline.h                    |  373 +-
 .../ip_pipeline/pipeline/pipeline_actions_common.h |  202 -
 examples/ip_pipeline/pipeline/pipeline_common_be.c |  176 -
 examples/ip_pipeline/pipeline/pipeline_common_be.h |  134 -
 examples/ip_pipeline/pipeline/pipeline_common_fe.c | 1455 -------
 examples/ip_pipeline/pipeline/pipeline_common_fe.h |  231 --
 examples/ip_pipeline/pipeline/pipeline_firewall.c  | 1421 -------
 examples/ip_pipeline/pipeline/pipeline_firewall.h  |   60 -
 .../ip_pipeline/pipeline/pipeline_firewall_be.c    |  856 ----
 .../ip_pipeline/pipeline/pipeline_firewall_be.h    |  147 -
 .../ip_pipeline/pipeline/pipeline_flow_actions.c   | 1286 ------
 .../ip_pipeline/pipeline/pipeline_flow_actions.h   |   60 -
 .../pipeline/pipeline_flow_actions_be.c            |  983 -----
 .../pipeline/pipeline_flow_actions_be.h            |  139 -
 .../pipeline/pipeline_flow_classification.c        | 1878 ---------
 .../pipeline/pipeline_flow_classification.h        |  106 -
 .../pipeline/pipeline_flow_classification_be.c     |  723 ----
 .../pipeline/pipeline_flow_classification_be.h     |  113 -
 examples/ip_pipeline/pipeline/pipeline_master.c    |   20 -
 examples/ip_pipeline/pipeline/pipeline_master.h    |   12 -
 examples/ip_pipeline/pipeline/pipeline_master_be.c |  141 -
 examples/ip_pipeline/pipeline/pipeline_master_be.h |   12 -
 .../ip_pipeline/pipeline/pipeline_passthrough.c    |   45 -
 .../ip_pipeline/pipeline/pipeline_passthrough.h    |   12 -
 .../ip_pipeline/pipeline/pipeline_passthrough_be.c |  929 -----
 .../ip_pipeline/pipeline/pipeline_passthrough_be.h |   44 -
 examples/ip_pipeline/pipeline/pipeline_routing.c   | 1613 --------
 examples/ip_pipeline/pipeline/pipeline_routing.h   |   71 -
 .../ip_pipeline/pipeline/pipeline_routing_be.c     | 1966 ---------
 .../ip_pipeline/pipeline/pipeline_routing_be.h     |  283 --
 examples/ip_pipeline/pipeline_be.h                 |  322 --
 examples/ip_pipeline/swq.c                         |   74 +
 examples/ip_pipeline/swq.h                         |   37 +
 examples/ip_pipeline/tap.c                         |   97 +
 examples/ip_pipeline/tap.h                         |   29 +
 examples/ip_pipeline/thread.c                      | 2485 +++++++++++-
 examples/ip_pipeline/thread.h                      |   75 +-
 examples/ip_pipeline/thread_fe.c                   |  457 ---
 examples/ip_pipeline/thread_fe.h                   |   72 -
 examples/ip_pipeline/tmgr.c                        |  227 ++
 examples/ip_pipeline/tmgr.h                        |   70 +
 lib/librte_pipeline/Makefile                       |    6 +-
 lib/librte_pipeline/meson.build                    |    7 +-
 lib/librte_pipeline/rte_pipeline_version.map       |   21 +
 lib/librte_pipeline/rte_table_action.c             | 2086 ++++++++++
 lib/librte_pipeline/rte_table_action.h             |  853 ++++
 108 files changed, 13248 insertions(+), 27218 deletions(-)
 create mode 100644 examples/ip_pipeline/action.c
 create mode 100644 examples/ip_pipeline/action.h
 delete mode 100644 examples/ip_pipeline/app.h
 create mode 100644 examples/ip_pipeline/cli.c
 create mode 100644 examples/ip_pipeline/cli.h
 create mode 100644 examples/ip_pipeline/common.h
 delete mode 100644 examples/ip_pipeline/config/action.cfg
 delete mode 100644 examples/ip_pipeline/config/action.sh
 delete mode 100644 examples/ip_pipeline/config/action.txt
 delete mode 100755 examples/ip_pipeline/config/diagram-generator.py
 delete mode 100644 examples/ip_pipeline/config/edge_router_downstream.cfg
 delete mode 100644 examples/ip_pipeline/config/edge_router_downstream.sh
 delete mode 100644 examples/ip_pipeline/config/edge_router_upstream.cfg
 delete mode 100644 examples/ip_pipeline/config/edge_router_upstream.sh
 delete mode 100644 examples/ip_pipeline/config/firewall.cfg
 delete mode 100644 examples/ip_pipeline/config/firewall.sh
 delete mode 100644 examples/ip_pipeline/config/firewall.txt
 delete mode 100644 examples/ip_pipeline/config/flow.cfg
 delete mode 100644 examples/ip_pipeline/config/flow.sh
 delete mode 100644 examples/ip_pipeline/config/flow.txt
 delete mode 100644 examples/ip_pipeline/config/ip_pipeline.cfg
 delete mode 100644 examples/ip_pipeline/config/ip_pipeline.sh
 delete mode 100644 examples/ip_pipeline/config/kni.cfg
 delete mode 100644 examples/ip_pipeline/config/l2fwd.cfg
 delete mode 100644 examples/ip_pipeline/config/l3fwd.cfg
 delete mode 100644 examples/ip_pipeline/config/l3fwd.sh
 delete mode 100644 examples/ip_pipeline/config/l3fwd_arp.cfg
 delete mode 100644 examples/ip_pipeline/config/l3fwd_arp.sh
 delete mode 100644 examples/ip_pipeline/config/network_layers.cfg
 delete mode 100644 examples/ip_pipeline/config/network_layers.sh
 delete mode 100755 examples/ip_pipeline/config/pipeline-to-core-mapping.py
 delete mode 100644 examples/ip_pipeline/config/tap.cfg
 delete mode 100644 examples/ip_pipeline/config/tm_profile.cfg
 delete mode 100644 examples/ip_pipeline/config_check.c
 delete mode 100644 examples/ip_pipeline/config_parse.c
 delete mode 100644 examples/ip_pipeline/config_parse_tm.c
 create mode 100644 examples/ip_pipeline/conn.c
 create mode 100644 examples/ip_pipeline/conn.h
 delete mode 100644 examples/ip_pipeline/cpu_core_map.c
 delete mode 100644 examples/ip_pipeline/cpu_core_map.h
 create mode 100644 examples/ip_pipeline/examples/firewall.cli
 create mode 100644 examples/ip_pipeline/examples/flow.cli
 create mode 100644 examples/ip_pipeline/examples/kni.cli
 create mode 100644 examples/ip_pipeline/examples/l2fwd.cli
 create mode 100644 examples/ip_pipeline/examples/route.cli
 create mode 100644 examples/ip_pipeline/examples/tap.cli
 rename examples/ip_pipeline/{pipeline => }/hash_func.h (99%)
 rename examples/ip_pipeline/{pipeline => }/hash_func_arm64.h (100%)
 delete mode 100644 examples/ip_pipeline/init.c
 create mode 100644 examples/ip_pipeline/kni.c
 create mode 100644 examples/ip_pipeline/kni.h
 create mode 100644 examples/ip_pipeline/link.c
 create mode 100644 examples/ip_pipeline/link.h
 create mode 100644 examples/ip_pipeline/mempool.c
 create mode 100644 examples/ip_pipeline/mempool.h
 create mode 100644 examples/ip_pipeline/pipeline.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_actions_common.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_common_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_common_be.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_common_fe.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_common_fe.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_firewall.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_firewall.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_firewall_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_firewall_be.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_actions.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_actions.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_actions_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_actions_be.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_classification.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_classification.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_classification_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_classification_be.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_master.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_master.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_master_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_master_be.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_passthrough.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_passthrough.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_passthrough_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_passthrough_be.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_routing.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_routing.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_routing_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_routing_be.h
 delete mode 100644 examples/ip_pipeline/pipeline_be.h
 create mode 100644 examples/ip_pipeline/swq.c
 create mode 100644 examples/ip_pipeline/swq.h
 create mode 100644 examples/ip_pipeline/tap.c
 create mode 100644 examples/ip_pipeline/tap.h
 delete mode 100644 examples/ip_pipeline/thread_fe.c
 delete mode 100644 examples/ip_pipeline/thread_fe.h
 create mode 100644 examples/ip_pipeline/tmgr.c
 create mode 100644 examples/ip_pipeline/tmgr.h
 create mode 100644 lib/librte_pipeline/rte_table_action.c
 create mode 100644 lib/librte_pipeline/rte_table_action.h

-- 
2.9.3

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

* [dpdk-dev] [PATCH v2 01/44] pipeline: add pipeline table action APIs
  2018-03-12 17:25   ` [dpdk-dev] [PATCH v2 00/44] ip_pipeline: refactoring Jasvinder Singh
@ 2018-03-12 17:25     ` Jasvinder Singh
  2018-03-16 17:56       ` [dpdk-dev] [PATCH v3 00/44] ip_pipeline: refactoring Jasvinder Singh
  2018-03-16 17:58       ` [dpdk-dev] [PATCH v3 00/44] ip_pipeline: refactoring Jasvinder Singh
  2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 02/44] pipeline: get pipeline table action params Jasvinder Singh
                       ` (42 subsequent siblings)
  43 siblings, 2 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-12 17:25 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

This API provides a common set of actions for pipeline tables to speed up
application development.

Each match-action rule added to a pipeline table has associated data
that stores the action context. This data is input to the table
action handler called for every input packet that hits the rule as
part of the table lookup during the pipeline execution.

The pipeline library allows the user to define his own table
actions by providing customized table action handlers (table
lookup) and complete freedom of setting the rules and their data
(table rule add/delete). While the user can still follow this
process, this API is intended to provide a quicker development
alternative for a set of predefined actions.

The typical steps to use this API are:
* Define a table action profile.
* Instantiate the table action profile to create table action objects.
* Use the table action object to generate the pipeline table action
  handlers (invoked by the pipeline table lookup operation).
* Use the table action object to generate the rule data (for the
  pipeline table rule add operation) based on given action parameters.
* Use the table action object to read action data (e.g. stats counters)
  for any given rule.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 doc/api/doxy-api-index.md                    |   1 +
 lib/librte_pipeline/Makefile                 |   3 +-
 lib/librte_pipeline/meson.build              |   5 +-
 lib/librte_pipeline/rte_pipeline_version.map |  13 ++
 lib/librte_pipeline/rte_table_action.c       | 278 +++++++++++++++++++++++++++
 lib/librte_pipeline/rte_table_action.h       | 224 +++++++++++++++++++++
 6 files changed, 521 insertions(+), 3 deletions(-)
 create mode 100644 lib/librte_pipeline/rte_table_action.c
 create mode 100644 lib/librte_pipeline/rte_table_action.h

diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md
index d77f205..e24b70e 100644
--- a/doc/api/doxy-api-index.md
+++ b/doc/api/doxy-api-index.md
@@ -159,6 +159,7 @@ The public API headers are grouped by topics:
     [array]            (@ref rte_table_array.h),
     [stub]             (@ref rte_table_stub.h)
   * [pipeline]         (@ref rte_pipeline.h)
+    [table_action].....(@ref rte_table_action.h)
 
 - **basic**:
   [approx fraction]    (@ref rte_approx.h),
diff --git a/lib/librte_pipeline/Makefile b/lib/librte_pipeline/Makefile
index e94fbc0..e8c43c7 100644
--- a/lib/librte_pipeline/Makefile
+++ b/lib/librte_pipeline/Makefile
@@ -21,8 +21,9 @@ LIBABIVER := 3
 # all source are stored in SRCS-y
 #
 SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) := rte_pipeline.c
+SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += rte_table_action.c
 
 # install includes
-SYMLINK-$(CONFIG_RTE_LIBRTE_PIPELINE)-include += rte_pipeline.h
+SYMLINK-$(CONFIG_RTE_LIBRTE_PIPELINE)-include += rte_pipeline.h rte_table_action.h
 
 include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_pipeline/meson.build b/lib/librte_pipeline/meson.build
index a35b622..4dda560 100644
--- a/lib/librte_pipeline/meson.build
+++ b/lib/librte_pipeline/meson.build
@@ -2,6 +2,7 @@
 # Copyright(c) 2017 Intel Corporation
 
 version = 3
-sources = files('rte_pipeline.c')
-headers = files('rte_pipeline.h')
+allow_experimental_apis = true
+sources = files('rte_pipeline.c', 'rte_table_action.c')
+headers = files('rte_pipeline.h', 'rte_table_action.h')
 deps += ['port', 'table']
diff --git a/lib/librte_pipeline/rte_pipeline_version.map b/lib/librte_pipeline/rte_pipeline_version.map
index e4ee154..4bc414c 100644
--- a/lib/librte_pipeline/rte_pipeline_version.map
+++ b/lib/librte_pipeline/rte_pipeline_version.map
@@ -45,3 +45,16 @@ DPDK_16.04 {
 	rte_pipeline_ah_packet_drop;
 
 } DPDK_2.2;
+
+EXPERIMENTAL {
+	global:
+
+	rte_table_action_apply;
+	rte_table_action_create;
+	rte_table_action_free;
+	rte_table_action_profile_action_register;
+	rte_table_action_profile_create;
+	rte_table_action_profile_free;
+	rte_table_action_profile_freeze;
+
+} DPDK_16.04;
diff --git a/lib/librte_pipeline/rte_table_action.c b/lib/librte_pipeline/rte_table_action.c
new file mode 100644
index 0000000..45e22a4
--- /dev/null
+++ b/lib/librte_pipeline/rte_table_action.c
@@ -0,0 +1,278 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <rte_malloc.h>
+
+#include <rte_common.h>
+#include <rte_malloc.h>
+
+#include "rte_table_action.h"
+
+/**
+ * RTE_TABLE_ACTION_FWD
+ */
+#define fwd_data rte_pipeline_table_entry
+
+static int
+fwd_apply(struct fwd_data *data,
+	struct rte_table_action_fwd_params *p)
+{
+	data->action = p->action;
+
+	if (p->action == RTE_PIPELINE_ACTION_PORT)
+		data->port_id = p->id;
+
+	if (p->action == RTE_PIPELINE_ACTION_TABLE)
+		data->table_id = p->id;
+
+	return 0;
+}
+
+/**
+ * Action profile
+ */
+static int
+action_valid(enum rte_table_action_type action)
+{
+	switch (action) {
+	case RTE_TABLE_ACTION_FWD:
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+
+#define RTE_TABLE_ACTION_MAX                                   64
+
+struct ap_config {
+	uint64_t action_mask;
+	struct rte_table_action_common_config common;
+};
+
+static size_t
+action_cfg_size(enum rte_table_action_type action)
+{
+	switch (action) {
+	default:
+		return 0;
+	}
+}
+
+static void*
+action_cfg_get(struct ap_config *ap_config __rte_unused,
+	enum rte_table_action_type type)
+{
+	switch (type) {
+	default:
+		return NULL;
+	}
+}
+
+static void
+action_cfg_set(struct ap_config *ap_config,
+	enum rte_table_action_type type,
+	void *action_cfg)
+{
+	void *dst = action_cfg_get(ap_config, type);
+
+	if (dst)
+		memcpy(dst, action_cfg, action_cfg_size(type));
+
+	ap_config->action_mask |= 1LLU << type;
+}
+
+struct ap_data {
+	size_t offset[RTE_TABLE_ACTION_MAX];
+	size_t total_size;
+};
+
+static size_t
+action_data_size(enum rte_table_action_type action,
+	struct ap_config *ap_config __rte_unused)
+{
+	switch (action) {
+	case RTE_TABLE_ACTION_FWD:
+		return sizeof(struct fwd_data);
+
+	default:
+		return 0;
+	}
+}
+
+
+static void
+action_data_offset_set(struct ap_data *ap_data,
+	struct ap_config *ap_config)
+{
+	uint64_t action_mask = ap_config->action_mask;
+	size_t offset;
+	enum rte_table_action_type action;
+
+	memset(ap_data->offset, 0, sizeof(ap_data->offset));
+
+	offset = 0;
+	for (action = 0; action < RTE_TABLE_ACTION_MAX; action++)
+		if (action_mask & (1LLU << action)) {
+			ap_data->offset[action] = offset;
+			offset += action_data_size(action, ap_config);
+		}
+
+	ap_data->total_size = offset;
+}
+
+struct rte_table_action_profile {
+	struct ap_config cfg;
+	struct ap_data data;
+	int frozen;
+};
+
+struct rte_table_action_profile *
+rte_table_action_profile_create(struct rte_table_action_common_config *common)
+{
+	struct rte_table_action_profile *ap;
+
+	/* Check input arguments */
+	if (common == NULL)
+		return NULL;
+
+	/* Memory allocation */
+	ap = calloc(1, sizeof(struct rte_table_action_profile));
+	if (ap == NULL)
+		return NULL;
+
+	/* Initialization */
+	memcpy(&ap->cfg.common, common, sizeof(*common));
+
+	return ap;
+}
+
+
+int
+rte_table_action_profile_action_register(struct rte_table_action_profile *profile,
+	enum rte_table_action_type type,
+	void *action_config)
+{
+	/* Check input arguments */
+	if ((profile == NULL) ||
+		profile->frozen ||
+		(action_valid(type) == 0) ||
+		(profile->cfg.action_mask & (1LLU << type)) ||
+		((action_cfg_size(type) == 0) && action_config) ||
+		(action_cfg_size(type) && (action_config == NULL)))
+		return -EINVAL;
+
+	/* Action enable */
+	action_cfg_set(&profile->cfg, type, action_config);
+
+	return 0;
+}
+
+int
+rte_table_action_profile_freeze(struct rte_table_action_profile *profile)
+{
+	if (profile->frozen)
+		return -EBUSY;
+
+	profile->cfg.action_mask |= 1LLU << RTE_TABLE_ACTION_FWD;
+	action_data_offset_set(&profile->data, &profile->cfg);
+	profile->frozen = 1;
+
+	return 0;
+}
+
+int
+rte_table_action_profile_free(struct rte_table_action_profile *profile)
+{
+	if (profile == NULL)
+		return 0;
+
+	free(profile);
+	return 0;
+}
+
+struct rte_table_action {
+	struct ap_config cfg;
+	struct ap_data data;
+};
+
+struct rte_table_action *
+rte_table_action_create(struct rte_table_action_profile *profile,
+	uint32_t socket_id)
+{
+	struct rte_table_action *action;
+
+	/* Check input arguments */
+	if ((profile == NULL) ||
+		(profile->frozen == 0))
+		return NULL;
+
+	/* Memory allocation */
+	action = rte_zmalloc_socket(NULL,
+		sizeof(struct rte_table_action),
+		RTE_CACHE_LINE_SIZE,
+		socket_id);
+	if (action == NULL)
+		return NULL;
+
+	/* Initialization */
+	memcpy(&action->cfg, &profile->cfg, sizeof(profile->cfg));
+	memcpy(&action->data, &profile->data, sizeof(profile->data));
+
+	return action;
+}
+
+static __rte_always_inline void *
+action_data_get(void *data,
+	struct rte_table_action *action,
+	enum rte_table_action_type type)
+{
+	size_t offset = action->data.offset[type];
+	uint8_t *data_bytes = data;
+
+	return &data_bytes[offset];
+}
+
+int
+rte_table_action_apply(struct rte_table_action *action,
+	void *data,
+	enum rte_table_action_type type,
+	void *action_params)
+{
+	void *action_data;
+
+	/* Check input arguments */
+	if ((action == NULL) ||
+		(data == NULL) ||
+		(action_valid(type) == 0) ||
+		((action->cfg.action_mask & (1LLU << type)) == 0) ||
+		(action_params == NULL))
+		return -EINVAL;
+
+	/* Data update */
+	action_data = action_data_get(data, action, type);
+
+	switch (type) {
+	case RTE_TABLE_ACTION_FWD:
+		return fwd_apply(action_data,
+			action_params);
+
+	default:
+		return -EINVAL;
+	}
+}
+
+int
+rte_table_action_free(struct rte_table_action *action)
+{
+	if (action == NULL)
+		return 0;
+
+	rte_free(action);
+
+	return 0;
+}
\ No newline at end of file
diff --git a/lib/librte_pipeline/rte_table_action.h b/lib/librte_pipeline/rte_table_action.h
new file mode 100644
index 0000000..da7f12c
--- /dev/null
+++ b/lib/librte_pipeline/rte_table_action.h
@@ -0,0 +1,224 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation
+ */
+
+#ifndef __INCLUDE_RTE_TABLE_ACTION_H__
+#define __INCLUDE_RTE_TABLE_ACTION_H__
+
+/**
+ * @file
+ * RTE Pipeline Table Actions
+ *
+ * This API provides a common set of actions for pipeline tables to speed up
+ * application development.
+ *
+ * Each match-action rule added to a pipeline table has associated data that
+ * stores the action context. This data is input to the table action handler
+ * called for every input packet that hits the rule as part of the table lookup
+ * during the pipeline execution. The pipeline library allows the user to define
+ * his own table actions by providing customized table action handlers (table
+ * lookup) and complete freedom of setting the rules and their data (table rule
+ * add/delete). While the user can still follow this process, this API is
+ * intended to provide a quicker development alternative for a set of predefined
+ * actions.
+ *
+ * The typical steps to use this API are:
+ *  - Define a table action profile. This is a configuration template that can
+ *    potentially be shared by multiple tables from the same or different
+ *    pipelines, with different tables from the same pipeline likely to use
+ *    different action profiles. For every table using a given action profile,
+ *    the profile defines the set of actions and the action configuration to be
+ *    implemented for all the table rules. API functions:
+ *    rte_table_action_profile_create(),
+ *    rte_table_action_profile_action_register(),
+ *    rte_table_action_profile_freeze().
+ *
+ *  - Instantiate the table action profile to create table action objects. Each
+ *    pipeline table has its own table action object. API functions:
+ *    rte_table_action_create().
+ *
+ *  - Use the table action object to generate the pipeline table action handlers
+ *    (invoked by the pipeline table lookup operation). API functions:
+ *    rte_table_action_table_params_get().
+ *
+ *  - Use the table action object to generate the rule data (for the pipeline
+ *    table rule add operation) based on given action parameters. API functions:
+ *    rte_table_action_apply().
+ *
+ *  - Use the table action object to read action data (e.g. stats counters) for
+ *    any given rule. API functions: rte_table_action_XYZ_read().
+ *
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+
+#include <rte_compat.h>
+
+#include "rte_pipeline.h"
+
+/** Table actions. */
+enum rte_table_action_type {
+	/** Forward to next pipeline table, output port or drop. */
+	RTE_TABLE_ACTION_FWD = 0,
+};
+
+/** Common action configuration (per table action profile). */
+struct rte_table_action_common_config {
+	/** Input packet Internet Protocol (IP) version. Non-zero for IPv4, zero
+	 * for IPv6.
+	 */
+	int ip_version;
+
+	/** IP header offset within the input packet buffer. Offset 0 points to
+	 * the first byte of the MBUF structure.
+	 */
+	uint32_t ip_offset;
+};
+
+/**
+ * RTE_TABLE_ACTION_FWD
+ */
+/** Forward action parameters (per table rule). */
+struct rte_table_action_fwd_params {
+	/** Forward action. */
+	enum rte_pipeline_action action;
+
+	/** Pipeline table ID or output port ID. */
+	uint32_t id;
+};
+
+/**
+ * Table action profile.
+ */
+struct rte_table_action_profile;
+
+/**
+ * Table action profile create.
+ *
+ * @param[in] common
+ *   Common action configuration.
+ * @return
+ *   Table action profile handle on success, NULL otherwise.
+ */
+struct rte_table_action_profile * __rte_experimental
+rte_table_action_profile_create(struct rte_table_action_common_config *common);
+
+/**
+ * Table action profile free.
+ *
+ * @param[in] profile
+ *   Table profile action handle (needs to be valid).
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_table_action_profile_free(struct rte_table_action_profile *profile);
+
+/**
+ * Table action profile action register.
+ *
+ * @param[in] profile
+ *   Table profile action handle (needs to be valid and not in frozen state).
+ * @param[in] type
+ *   Specific table action to be registered for *profile*.
+ * @param[in] action_config
+ *   Configuration for the *type* action.
+ *   If struct rte_table_action_*type*_config is defined by the Table Action
+ *   API, it needs to point to a valid instance of this structure, otherwise it
+ *   needs to be set to NULL.
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_table_action_profile_action_register(struct rte_table_action_profile *profile,
+	enum rte_table_action_type type,
+	void *action_config);
+
+/**
+ * Table action profile freeze.
+ *
+ * Once this function is called successfully, the given profile enters the
+ * frozen state with the following immediate effects: no more actions can be
+ * registered for this profile, so the profile can be instantiated to create
+ * table action objects.
+ *
+ * @param[in] profile
+ *   Table profile action handle (needs to be valid and not in frozen state).
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ *
+ * @see rte_table_action_create()
+ */
+int __rte_experimental
+rte_table_action_profile_freeze(struct rte_table_action_profile *profile);
+
+/**
+ * Table action.
+ */
+struct rte_table_action;
+
+/**
+ * Table action create.
+ *
+ * Instantiates the given table action profile to create a table action object.
+ *
+ * @param[in] profile
+ *   Table profile action handle (needs to be valid and in frozen state).
+ * @param[in] socket_id
+ *   CPU socket ID where the internal data structures required by the new table
+ *   action object should be allocated.
+ * @return
+ *   Handle to table action object on success, NULL on error.
+ *
+ * @see rte_table_action_create()
+ */
+struct rte_table_action * __rte_experimental
+rte_table_action_create(struct rte_table_action_profile *profile,
+	uint32_t socket_id);
+
+/**
+ * Table action free.
+ *
+ * @param[in] action
+ *   Handle to table action object (needs to be valid).
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_table_action_free(struct rte_table_action *action);
+
+/**
+ * Table action apply.
+ *
+ * @param[in] action
+ *   Handle to table action object (needs to be valid).
+ * @param[in] data
+ *   Data byte array (typically table rule data) to apply action *type* on.
+ * @param[in] type
+ *   Specific table action previously registered for the table action profile of
+ *   the *action* object.
+ * @param[in] action_params
+ *   Parameters for the *type* action.
+ *   If struct rte_table_action_*type*_params is defined by the Table Action
+ *   API, it needs to point to a valid instance of this structure, otherwise it
+ *   needs to be set to NULL.
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_table_action_apply(struct rte_table_action *action,
+	void *data,
+	enum rte_table_action_type type,
+	void *action_params);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __INCLUDE_RTE_TABLE_ACTION_H__ */
-- 
2.9.3

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

* [dpdk-dev] [PATCH v2 02/44] pipeline: get pipeline table action params
  2018-03-12 17:25   ` [dpdk-dev] [PATCH v2 00/44] ip_pipeline: refactoring Jasvinder Singh
  2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 01/44] pipeline: add pipeline table action APIs Jasvinder Singh
@ 2018-03-12 17:25     ` Jasvinder Singh
  2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 03/44] pipeline: add traffic metering action Jasvinder Singh
                       ` (41 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-12 17:25 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add API to specify action related parameters such as action
handler, table entry data size, etc. for the pipeline table.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 lib/librte_pipeline/rte_pipeline_version.map |   1 +
 lib/librte_pipeline/rte_table_action.c       | 132 ++++++++++++++++++++++++++-
 lib/librte_pipeline/rte_table_action.h       |  14 +++
 3 files changed, 146 insertions(+), 1 deletion(-)

diff --git a/lib/librte_pipeline/rte_pipeline_version.map b/lib/librte_pipeline/rte_pipeline_version.map
index 4bc414c..13337de 100644
--- a/lib/librte_pipeline/rte_pipeline_version.map
+++ b/lib/librte_pipeline/rte_pipeline_version.map
@@ -56,5 +56,6 @@ EXPERIMENTAL {
 	rte_table_action_profile_create;
 	rte_table_action_profile_free;
 	rte_table_action_profile_freeze;
+	rte_table_action_table_params_get;
 
 } DPDK_16.04;
diff --git a/lib/librte_pipeline/rte_table_action.c b/lib/librte_pipeline/rte_table_action.c
index 45e22a4..ce484e4 100644
--- a/lib/librte_pipeline/rte_table_action.c
+++ b/lib/librte_pipeline/rte_table_action.c
@@ -266,6 +266,136 @@ rte_table_action_apply(struct rte_table_action *action,
 	}
 }
 
+static __rte_always_inline uint64_t
+pkt_work(struct rte_mbuf *mbuf __rte_unused,
+	struct rte_pipeline_table_entry *table_entry __rte_unused,
+	uint64_t time __rte_unused,
+	struct rte_table_action *action __rte_unused,
+	struct ap_config *cfg __rte_unused)
+{
+	return 0;
+}
+
+static __rte_always_inline uint64_t
+pkt4_work(struct rte_mbuf **mbufs __rte_unused,
+	struct rte_pipeline_table_entry **table_entries __rte_unused,
+	uint64_t time __rte_unused,
+	struct rte_table_action *action __rte_unused,
+	struct ap_config *cfg __rte_unused)
+{
+	return 0;
+}
+
+static __rte_always_inline int
+ah(struct rte_pipeline *p,
+	struct rte_mbuf **pkts,
+	uint64_t pkts_mask,
+	struct rte_pipeline_table_entry **entries,
+	struct rte_table_action *action,
+	struct ap_config *cfg)
+{
+	uint64_t pkts_drop_mask = 0;
+	uint64_t time = 0;
+
+	if ((pkts_mask & (pkts_mask + 1)) == 0) {
+		uint64_t n_pkts = __builtin_popcountll(pkts_mask);
+		uint32_t i;
+
+		for (i = 0; i < (n_pkts & (~0x3LLU)); i += 4) {
+			uint64_t drop_mask;
+
+			drop_mask = pkt4_work(&pkts[i],
+				&entries[i],
+				time,
+				action,
+				cfg);
+
+			pkts_drop_mask |= drop_mask << i;
+		}
+
+		for ( ; i < n_pkts; i++) {
+			uint64_t drop_mask;
+
+			drop_mask = pkt_work(pkts[i],
+				entries[i],
+				time,
+				action,
+				cfg);
+
+			pkts_drop_mask |= drop_mask << i;
+		}
+	} else
+		for ( ; pkts_mask; ) {
+			uint32_t pos = __builtin_ctzll(pkts_mask);
+			uint64_t pkt_mask = 1LLU << pos;
+			uint64_t drop_mask;
+
+			drop_mask = pkt_work(pkts[pos],
+				entries[pos],
+				time,
+				action,
+				cfg);
+
+			pkts_mask &= ~pkt_mask;
+			pkts_drop_mask |= drop_mask << pos;
+		}
+
+	rte_pipeline_ah_packet_drop(p, pkts_drop_mask);
+
+	return 0;
+}
+
+static int
+ah_default(struct rte_pipeline *p,
+	struct rte_mbuf **pkts,
+	uint64_t pkts_mask,
+	struct rte_pipeline_table_entry **entries,
+	void *arg)
+{
+	struct rte_table_action *action = arg;
+
+	return ah(p,
+		pkts,
+		pkts_mask,
+		entries,
+		action,
+		&action->cfg);
+}
+
+static rte_pipeline_table_action_handler_hit
+ah_selector(struct rte_table_action *action)
+{
+	if (action->cfg.action_mask == (1LLU << RTE_TABLE_ACTION_FWD))
+		return NULL;
+
+	return ah_default;
+}
+
+int
+rte_table_action_table_params_get(struct rte_table_action *action,
+	struct rte_pipeline_table_params *params)
+{
+	rte_pipeline_table_action_handler_hit f_action_hit;
+	uint32_t total_size;
+
+	/* Check input arguments */
+	if ((action == NULL) ||
+		(params == NULL))
+		return -EINVAL;
+
+	f_action_hit = ah_selector(action);
+	total_size = rte_align32pow2(action->data.total_size);
+
+	/* Fill in params */
+	params->f_action_hit = f_action_hit;
+	params->f_action_miss = NULL;
+	params->arg_ah = (f_action_hit) ? action : NULL;
+	params->action_data_size = total_size -
+		sizeof(struct rte_pipeline_table_entry);
+
+	return 0;
+}
+
 int
 rte_table_action_free(struct rte_table_action *action)
 {
@@ -275,4 +405,4 @@ rte_table_action_free(struct rte_table_action *action)
 	rte_free(action);
 
 	return 0;
-}
\ No newline at end of file
+}
diff --git a/lib/librte_pipeline/rte_table_action.h b/lib/librte_pipeline/rte_table_action.h
index da7f12c..03b77ca 100644
--- a/lib/librte_pipeline/rte_table_action.h
+++ b/lib/librte_pipeline/rte_table_action.h
@@ -194,6 +194,20 @@ int __rte_experimental
 rte_table_action_free(struct rte_table_action *action);
 
 /**
+ * Table action table params get.
+ *
+ * @param[in] action
+ *   Handle to table action object (needs to be valid).
+ * @param[inout] params
+ *   Pipeline table parameters (needs to be pre-allocated).
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_table_action_table_params_get(struct rte_table_action *action,
+	struct rte_pipeline_table_params *params);
+
+/**
  * Table action apply.
  *
  * @param[in] action
-- 
2.9.3

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

* [dpdk-dev] [PATCH v2 03/44] pipeline: add traffic metering action
  2018-03-12 17:25   ` [dpdk-dev] [PATCH v2 00/44] ip_pipeline: refactoring Jasvinder Singh
  2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 01/44] pipeline: add pipeline table action APIs Jasvinder Singh
  2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 02/44] pipeline: get pipeline table action params Jasvinder Singh
@ 2018-03-12 17:25     ` Jasvinder Singh
  2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 04/44] pipeline: add traffic manager action Jasvinder Singh
                       ` (40 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-12 17:25 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add traffic metering action implementation.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 lib/librte_pipeline/Makefile                 |   3 +-
 lib/librte_pipeline/meson.build              |   2 +-
 lib/librte_pipeline/rte_pipeline_version.map |   4 +
 lib/librte_pipeline/rte_table_action.c       | 640 ++++++++++++++++++++++++++-
 lib/librte_pipeline/rte_table_action.h       | 248 +++++++++++
 5 files changed, 879 insertions(+), 18 deletions(-)

diff --git a/lib/librte_pipeline/Makefile b/lib/librte_pipeline/Makefile
index e8c43c7..72e4c7c 100644
--- a/lib/librte_pipeline/Makefile
+++ b/lib/librte_pipeline/Makefile
@@ -8,10 +8,11 @@ include $(RTE_SDK)/mk/rte.vars.mk
 #
 LIB = librte_pipeline.a
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
 LDLIBS += -lrte_eal -lrte_mempool -lrte_mbuf -lrte_table
-LDLIBS += -lrte_port
+LDLIBS += -lrte_port -lrte_meter
 
 EXPORT_MAP := rte_pipeline_version.map
 
diff --git a/lib/librte_pipeline/meson.build b/lib/librte_pipeline/meson.build
index 4dda560..71da295 100644
--- a/lib/librte_pipeline/meson.build
+++ b/lib/librte_pipeline/meson.build
@@ -5,4 +5,4 @@ version = 3
 allow_experimental_apis = true
 sources = files('rte_pipeline.c', 'rte_table_action.c')
 headers = files('rte_pipeline.h', 'rte_table_action.h')
-deps += ['port', 'table']
+deps += ['port', 'table', 'meter']
diff --git a/lib/librte_pipeline/rte_pipeline_version.map b/lib/librte_pipeline/rte_pipeline_version.map
index 13337de..c7106dc 100644
--- a/lib/librte_pipeline/rte_pipeline_version.map
+++ b/lib/librte_pipeline/rte_pipeline_version.map
@@ -51,7 +51,11 @@ EXPERIMENTAL {
 
 	rte_table_action_apply;
 	rte_table_action_create;
+	rte_table_action_dscp_table_update;
 	rte_table_action_free;
+	rte_table_action_meter_profile_add;
+	rte_table_action_meter_profile_delete;
+	rte_table_action_meter_read;
 	rte_table_action_profile_action_register;
 	rte_table_action_profile_create;
 	rte_table_action_profile_free;
diff --git a/lib/librte_pipeline/rte_table_action.c b/lib/librte_pipeline/rte_table_action.c
index ce484e4..3a2268d 100644
--- a/lib/librte_pipeline/rte_table_action.c
+++ b/lib/librte_pipeline/rte_table_action.c
@@ -5,13 +5,21 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include <rte_malloc.h>
-
 #include <rte_common.h>
+#include <rte_byteorder.h>
+#include <rte_cycles.h>
 #include <rte_malloc.h>
+#include <rte_ip.h>
+
 
 #include "rte_table_action.h"
 
+#define rte_htons rte_cpu_to_be_16
+#define rte_htonl rte_cpu_to_be_32
+
+#define rte_ntohs rte_be_to_cpu_16
+#define rte_ntohl rte_be_to_cpu_32
+
 /**
  * RTE_TABLE_ACTION_FWD
  */
@@ -33,6 +41,264 @@ fwd_apply(struct fwd_data *data,
 }
 
 /**
+ * RTE_TABLE_ACTION_MTR
+ */
+static int
+mtr_cfg_check(struct rte_table_action_mtr_config *mtr)
+{
+	if ((mtr->alg == RTE_TABLE_ACTION_METER_SRTCM) ||
+		((mtr->n_tc != 1) && (mtr->n_tc != 4)) ||
+		(mtr->n_bytes_enabled != 0))
+		return -ENOTSUP;
+	return 0;
+}
+
+#define MBUF_SCHED_QUEUE_TC_COLOR(queue, tc, color)        \
+	((uint16_t)((((uint64_t)(queue)) & 0x3) |          \
+	((((uint64_t)(tc)) & 0x3) << 2) |                  \
+	((((uint64_t)(color)) & 0x3) << 4)))
+
+#define MBUF_SCHED_COLOR(sched, color)                     \
+	(((sched) & (~0x30LLU)) | ((color) << 4))
+
+struct mtr_trtcm_data {
+	struct rte_meter_trtcm trtcm;
+	uint64_t stats[e_RTE_METER_COLORS];
+} __attribute__((__packed__));
+
+#define MTR_TRTCM_DATA_METER_PROFILE_ID_GET(data)          \
+	(((data)->stats[e_RTE_METER_GREEN] & 0xF8LLU) >> 3)
+
+static void
+mtr_trtcm_data_meter_profile_id_set(struct mtr_trtcm_data *data,
+	uint32_t profile_id)
+{
+	data->stats[e_RTE_METER_GREEN] &= ~0xF8LLU;
+	data->stats[e_RTE_METER_GREEN] |= (profile_id % 32) << 3;
+}
+
+#define MTR_TRTCM_DATA_POLICER_ACTION_DROP_GET(data, color)\
+	(((data)->stats[(color)] & 4LLU) >> 2)
+
+#define MTR_TRTCM_DATA_POLICER_ACTION_COLOR_GET(data, color)\
+	((enum rte_meter_color)((data)->stats[(color)] & 3LLU))
+
+static void
+mtr_trtcm_data_policer_action_set(struct mtr_trtcm_data *data,
+	enum rte_meter_color color,
+	enum rte_table_action_policer action)
+{
+	if (action == RTE_TABLE_ACTION_POLICER_DROP) {
+		data->stats[color] |= 4LLU;
+	} else {
+		data->stats[color] &= ~7LLU;
+		data->stats[color] |= color & 3LLU;
+	}
+}
+
+static uint64_t
+mtr_trtcm_data_stats_get(struct mtr_trtcm_data *data,
+	enum rte_meter_color color)
+{
+	return data->stats[color] >> 8;
+}
+
+static void
+mtr_trtcm_data_stats_reset(struct mtr_trtcm_data *data,
+	enum rte_meter_color color)
+{
+	data->stats[color] &= 0xFFLU;
+}
+
+#define MTR_TRTCM_DATA_STATS_INC(data, color)              \
+	((data)->stats[(color)] += (1LLU << 8))
+
+static size_t
+mtr_data_size(struct rte_table_action_mtr_config *mtr)
+{
+	return mtr->n_tc * sizeof(struct mtr_trtcm_data);
+}
+
+struct dscp_table_entry_data {
+	enum rte_meter_color color;
+	uint16_t tc;
+	uint16_t queue_tc_color;
+};
+
+struct dscp_table_data {
+	struct dscp_table_entry_data entry[64];
+};
+
+struct meter_profile_data {
+	struct rte_meter_trtcm_profile profile;
+	uint32_t profile_id;
+	int valid;
+};
+
+static struct meter_profile_data *
+meter_profile_data_find(struct meter_profile_data *mp,
+	uint32_t mp_size,
+	uint32_t profile_id)
+{
+	uint32_t i;
+
+	for (i = 0; i < mp_size; i++) {
+		struct meter_profile_data *mp_data = &mp[i];
+
+		if (mp_data->valid && (mp_data->profile_id == profile_id))
+			return mp_data;
+	}
+
+	return NULL;
+}
+
+static struct meter_profile_data *
+meter_profile_data_find_unused(struct meter_profile_data *mp,
+	uint32_t mp_size)
+{
+	uint32_t i;
+
+	for (i = 0; i < mp_size; i++) {
+		struct meter_profile_data *mp_data = &mp[i];
+
+		if (!mp_data->valid)
+			return mp_data;
+	}
+
+	return NULL;
+}
+
+static int
+mtr_apply_check(struct rte_table_action_mtr_params *p,
+	struct rte_table_action_mtr_config *cfg,
+	struct meter_profile_data *mp,
+	uint32_t mp_size)
+{
+	uint32_t i;
+
+	if (p->tc_mask > RTE_LEN2MASK(cfg->n_tc, uint32_t))
+		return -EINVAL;
+
+	for (i = 0; i < RTE_TABLE_ACTION_TC_MAX; i++) {
+		struct rte_table_action_mtr_tc_params *p_tc = &p->mtr[i];
+		struct meter_profile_data *mp_data;
+
+		if ((p->tc_mask & (1LLU << i)) == 0)
+			continue;
+
+		mp_data = meter_profile_data_find(mp,
+			mp_size,
+			p_tc->meter_profile_id);
+		if (!mp_data)
+			return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int
+mtr_apply(struct mtr_trtcm_data *data,
+	struct rte_table_action_mtr_params *p,
+	struct rte_table_action_mtr_config *cfg,
+	struct meter_profile_data *mp,
+	uint32_t mp_size)
+{
+	uint32_t i;
+	int status;
+
+	/* Check input arguments */
+	status = mtr_apply_check(p, cfg, mp, mp_size);
+	if (status)
+		return status;
+
+	/* Apply */
+	for (i = 0; i < RTE_TABLE_ACTION_TC_MAX; i++) {
+		struct rte_table_action_mtr_tc_params *p_tc = &p->mtr[i];
+		struct mtr_trtcm_data *data_tc = &data[i];
+		struct meter_profile_data *mp_data;
+
+		if ((p->tc_mask & (1LLU << i)) == 0)
+			continue;
+
+		/* Find profile */
+		mp_data = meter_profile_data_find(mp,
+			mp_size,
+			p_tc->meter_profile_id);
+		if (!mp_data)
+			return -EINVAL;
+
+		memset(data_tc, 0, sizeof(*data_tc));
+
+		/* Meter object */
+		status = rte_meter_trtcm_config(&data_tc->trtcm,
+			&mp_data->profile);
+		if (status)
+			return status;
+
+		/* Meter profile */
+		mtr_trtcm_data_meter_profile_id_set(data_tc,
+			mp_data - mp);
+
+		/* Policer actions */
+		mtr_trtcm_data_policer_action_set(data_tc,
+			e_RTE_METER_GREEN,
+			p_tc->policer[e_RTE_METER_GREEN]);
+
+		mtr_trtcm_data_policer_action_set(data_tc,
+			e_RTE_METER_YELLOW,
+			p_tc->policer[e_RTE_METER_YELLOW]);
+
+		mtr_trtcm_data_policer_action_set(data_tc,
+			e_RTE_METER_RED,
+			p_tc->policer[e_RTE_METER_RED]);
+	}
+
+	return 0;
+}
+
+static __rte_always_inline uint64_t
+pkt_work_mtr(struct rte_mbuf *mbuf,
+	struct mtr_trtcm_data *data,
+	struct dscp_table_data *dscp_table,
+	struct meter_profile_data *mp,
+	uint64_t time,
+	uint32_t dscp,
+	uint16_t total_length)
+{
+	uint64_t drop_mask, sched;
+	uint64_t *sched_ptr = (uint64_t *) &mbuf->hash.sched;
+	struct dscp_table_entry_data *dscp_entry = &dscp_table->entry[dscp];
+	enum rte_meter_color color_in, color_meter, color_policer;
+	uint32_t tc, mp_id;
+
+	tc = dscp_entry->tc;
+	color_in = dscp_entry->color;
+	data += tc;
+	mp_id = MTR_TRTCM_DATA_METER_PROFILE_ID_GET(data);
+	sched = *sched_ptr;
+
+	/* Meter */
+	color_meter = rte_meter_trtcm_color_aware_check(
+		&data->trtcm,
+		&mp[mp_id].profile,
+		time,
+		total_length,
+		color_in);
+
+	/* Stats */
+	MTR_TRTCM_DATA_STATS_INC(data, color_meter);
+
+	/* Police */
+	drop_mask = MTR_TRTCM_DATA_POLICER_ACTION_DROP_GET(data, color_meter);
+	color_policer =
+		MTR_TRTCM_DATA_POLICER_ACTION_COLOR_GET(data, color_meter);
+	*sched_ptr = MBUF_SCHED_COLOR(sched, color_policer);
+
+	return drop_mask;
+}
+
+
+/**
  * Action profile
  */
 static int
@@ -40,6 +306,7 @@ action_valid(enum rte_table_action_type action)
 {
 	switch (action) {
 	case RTE_TABLE_ACTION_FWD:
+	case RTE_TABLE_ACTION_MTR:
 		return 1;
 	default:
 		return 0;
@@ -52,22 +319,28 @@ action_valid(enum rte_table_action_type action)
 struct ap_config {
 	uint64_t action_mask;
 	struct rte_table_action_common_config common;
+	struct rte_table_action_mtr_config mtr;
 };
 
 static size_t
 action_cfg_size(enum rte_table_action_type action)
 {
 	switch (action) {
+	case RTE_TABLE_ACTION_MTR:
+		return sizeof(struct rte_table_action_mtr_config);
 	default:
 		return 0;
 	}
 }
 
 static void*
-action_cfg_get(struct ap_config *ap_config __rte_unused,
+action_cfg_get(struct ap_config *ap_config,
 	enum rte_table_action_type type)
 {
 	switch (type) {
+	case RTE_TABLE_ACTION_MTR:
+		return &ap_config->mtr;
+
 	default:
 		return NULL;
 	}
@@ -93,12 +366,15 @@ struct ap_data {
 
 static size_t
 action_data_size(enum rte_table_action_type action,
-	struct ap_config *ap_config __rte_unused)
+	struct ap_config *ap_config)
 {
 	switch (action) {
 	case RTE_TABLE_ACTION_FWD:
 		return sizeof(struct fwd_data);
 
+	case RTE_TABLE_ACTION_MTR:
+		return mtr_data_size(&ap_config->mtr);
+
 	default:
 		return 0;
 	}
@@ -157,6 +433,8 @@ rte_table_action_profile_action_register(struct rte_table_action_profile *profil
 	enum rte_table_action_type type,
 	void *action_config)
 {
+	int status;
+
 	/* Check input arguments */
 	if ((profile == NULL) ||
 		profile->frozen ||
@@ -166,6 +444,19 @@ rte_table_action_profile_action_register(struct rte_table_action_profile *profil
 		(action_cfg_size(type) && (action_config == NULL)))
 		return -EINVAL;
 
+	switch (type) {
+	case RTE_TABLE_ACTION_MTR:
+		status = mtr_cfg_check(action_config);
+		break;
+
+	default:
+		status = 0;
+		break;
+	}
+
+	if (status)
+		return status;
+
 	/* Action enable */
 	action_cfg_set(&profile->cfg, type, action_config);
 
@@ -195,9 +486,16 @@ rte_table_action_profile_free(struct rte_table_action_profile *profile)
 	return 0;
 }
 
+/**
+ * Action
+ */
+#define METER_PROFILES_MAX                                 32
+
 struct rte_table_action {
 	struct ap_config cfg;
 	struct ap_data data;
+	struct dscp_table_data dscp_table;
+	struct meter_profile_data mp[METER_PROFILES_MAX];
 };
 
 struct rte_table_action *
@@ -261,31 +559,338 @@ rte_table_action_apply(struct rte_table_action *action,
 		return fwd_apply(action_data,
 			action_params);
 
+	case RTE_TABLE_ACTION_MTR:
+		return mtr_apply(action_data,
+			action_params,
+			&action->cfg.mtr,
+			action->mp,
+			RTE_DIM(action->mp));
+
 	default:
 		return -EINVAL;
 	}
 }
 
-static __rte_always_inline uint64_t
-pkt_work(struct rte_mbuf *mbuf __rte_unused,
-	struct rte_pipeline_table_entry *table_entry __rte_unused,
-	uint64_t time __rte_unused,
-	struct rte_table_action *action __rte_unused,
-	struct ap_config *cfg __rte_unused)
+int
+rte_table_action_dscp_table_update(struct rte_table_action *action,
+	uint64_t dscp_mask,
+	struct rte_table_action_dscp_table *table)
 {
+	uint32_t i;
+
+	/* Check input arguments */
+	if ((action == NULL) ||
+		(action->cfg.action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) ||
+		(dscp_mask == 0) ||
+		(table == NULL))
+		return -EINVAL;
+
+	for (i = 0; i < RTE_DIM(table->entry); i++) {
+		struct dscp_table_entry_data *data =
+			&action->dscp_table.entry[i];
+		struct rte_table_action_dscp_table_entry *entry =
+			&table->entry[i];
+		uint16_t queue_tc_color =
+			MBUF_SCHED_QUEUE_TC_COLOR(entry->tc_queue_id,
+				entry->tc_id,
+				entry->color);
+
+		if ((dscp_mask & (1LLU << i)) == 0)
+			continue;
+
+		data->color = entry->color;
+		data->tc = entry->tc_id;
+		data->queue_tc_color = queue_tc_color;
+	}
+
 	return 0;
 }
 
-static __rte_always_inline uint64_t
-pkt4_work(struct rte_mbuf **mbufs __rte_unused,
-	struct rte_pipeline_table_entry **table_entries __rte_unused,
-	uint64_t time __rte_unused,
-	struct rte_table_action *action __rte_unused,
-	struct ap_config *cfg __rte_unused)
+int
+rte_table_action_meter_profile_add(struct rte_table_action *action,
+	uint32_t meter_profile_id,
+	struct rte_table_action_meter_profile *profile)
 {
+	struct meter_profile_data *mp_data;
+	uint32_t status;
+
+	/* Check input arguments */
+	if ((action == NULL) ||
+		((action->cfg.action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) == 0) ||
+		(profile == NULL))
+		return -EINVAL;
+
+	if (profile->alg != RTE_TABLE_ACTION_METER_TRTCM)
+		return -ENOTSUP;
+
+	mp_data = meter_profile_data_find(action->mp,
+		RTE_DIM(action->mp),
+		meter_profile_id);
+	if (mp_data)
+		return -EEXIST;
+
+	mp_data = meter_profile_data_find_unused(action->mp,
+		RTE_DIM(action->mp));
+	if (!mp_data)
+		return -ENOSPC;
+
+	/* Install new profile */
+	status = rte_meter_trtcm_profile_config(&mp_data->profile,
+		&profile->trtcm);
+	if (status)
+		return status;
+
+	mp_data->profile_id = meter_profile_id;
+	mp_data->valid = 1;
+
 	return 0;
 }
 
+int
+rte_table_action_meter_profile_delete(struct rte_table_action *action,
+	uint32_t meter_profile_id)
+{
+	struct meter_profile_data *mp_data;
+
+	/* Check input arguments */
+	if ((action == NULL) ||
+		((action->cfg.action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) == 0))
+		return -EINVAL;
+
+	mp_data = meter_profile_data_find(action->mp,
+		RTE_DIM(action->mp),
+		meter_profile_id);
+	if (!mp_data)
+		return 0;
+
+	/* Uninstall profile */
+	mp_data->valid = 0;
+
+	return 0;
+}
+
+int
+rte_table_action_meter_read(struct rte_table_action *action,
+	void *data,
+	uint32_t tc_mask,
+	struct rte_table_action_mtr_counters *stats,
+	int clear)
+{
+	struct mtr_trtcm_data *mtr_data;
+	uint32_t i;
+
+	/* Check input arguments */
+	if ((action == NULL) ||
+		((action->cfg.action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) == 0) ||
+		(data == NULL) ||
+		(tc_mask > RTE_LEN2MASK(action->cfg.mtr.n_tc, uint32_t)))
+		return -EINVAL;
+
+	mtr_data = action_data_get(data, action, RTE_TABLE_ACTION_MTR);
+
+	/* Read */
+	if (stats) {
+		for (i = 0; i < RTE_TABLE_ACTION_TC_MAX; i++) {
+			struct rte_table_action_mtr_counters_tc *dst =
+				&stats->stats[i];
+			struct mtr_trtcm_data *src = &mtr_data[i];
+
+			if ((tc_mask & (1 << i)) == 0)
+				continue;
+
+			dst->n_packets[e_RTE_METER_GREEN] =
+				mtr_trtcm_data_stats_get(src, e_RTE_METER_GREEN);
+
+			dst->n_packets[e_RTE_METER_YELLOW] =
+				mtr_trtcm_data_stats_get(src, e_RTE_METER_YELLOW);
+
+			dst->n_packets[e_RTE_METER_RED] =
+				mtr_trtcm_data_stats_get(src, e_RTE_METER_RED);
+
+			dst->n_packets_valid = 1;
+			dst->n_bytes_valid = 0;
+		}
+
+		stats->tc_mask = tc_mask;
+	}
+
+	/* Clear */
+	if (clear)
+		for (i = 0; i < RTE_TABLE_ACTION_TC_MAX; i++) {
+			struct mtr_trtcm_data *src = &mtr_data[i];
+
+			if ((tc_mask & (1 << i)) == 0)
+				continue;
+
+			mtr_trtcm_data_stats_reset(src, e_RTE_METER_GREEN);
+			mtr_trtcm_data_stats_reset(src, e_RTE_METER_YELLOW);
+			mtr_trtcm_data_stats_reset(src, e_RTE_METER_RED);
+		}
+
+
+	return 0;
+}
+
+static __rte_always_inline uint64_t
+pkt_work(struct rte_mbuf *mbuf,
+	struct rte_pipeline_table_entry *table_entry,
+	uint64_t time,
+	struct rte_table_action *action,
+	struct ap_config *cfg)
+{
+	uint64_t drop_mask = 0;
+
+	uint32_t ip_offset = action->cfg.common.ip_offset;
+	void *ip = RTE_MBUF_METADATA_UINT32_PTR(mbuf, ip_offset);
+
+	uint32_t dscp;
+	uint16_t total_length;
+
+	if (cfg->common.ip_version) {
+		struct ipv4_hdr *hdr = ip;
+
+		dscp = hdr->type_of_service >> 2;
+		total_length = rte_ntohs(hdr->total_length);
+	} else {
+		struct ipv6_hdr *hdr = ip;
+
+		dscp = (rte_ntohl(hdr->vtc_flow) & 0x0F600000) >> 18;
+		total_length =
+			rte_ntohs(hdr->payload_len) + sizeof(struct ipv6_hdr);
+	}
+
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) {
+		void *data =
+			action_data_get(table_entry, action, RTE_TABLE_ACTION_MTR);
+
+		drop_mask |= pkt_work_mtr(mbuf,
+			data,
+			&action->dscp_table,
+			action->mp,
+			time,
+			dscp,
+			total_length);
+	}
+
+	return drop_mask;
+}
+
+static __rte_always_inline uint64_t
+pkt4_work(struct rte_mbuf **mbufs,
+	struct rte_pipeline_table_entry **table_entries,
+	uint64_t time,
+	struct rte_table_action *action,
+	struct ap_config *cfg)
+{
+	uint64_t drop_mask0 = 0;
+	uint64_t drop_mask1 = 0;
+	uint64_t drop_mask2 = 0;
+	uint64_t drop_mask3 = 0;
+
+	struct rte_mbuf *mbuf0 = mbufs[0];
+	struct rte_mbuf *mbuf1 = mbufs[1];
+	struct rte_mbuf *mbuf2 = mbufs[2];
+	struct rte_mbuf *mbuf3 = mbufs[3];
+
+	struct rte_pipeline_table_entry *table_entry0 = table_entries[0];
+	struct rte_pipeline_table_entry *table_entry1 = table_entries[1];
+	struct rte_pipeline_table_entry *table_entry2 = table_entries[2];
+	struct rte_pipeline_table_entry *table_entry3 = table_entries[3];
+
+	uint32_t ip_offset = action->cfg.common.ip_offset;
+	void *ip0 = RTE_MBUF_METADATA_UINT32_PTR(mbuf0, ip_offset);
+	void *ip1 = RTE_MBUF_METADATA_UINT32_PTR(mbuf1, ip_offset);
+	void *ip2 = RTE_MBUF_METADATA_UINT32_PTR(mbuf2, ip_offset);
+	void *ip3 = RTE_MBUF_METADATA_UINT32_PTR(mbuf3, ip_offset);
+
+	uint32_t dscp0, dscp1, dscp2, dscp3;
+	uint16_t total_length0, total_length1, total_length2, total_length3;
+
+	if (cfg->common.ip_version) {
+		struct ipv4_hdr *hdr0 = ip0;
+		struct ipv4_hdr *hdr1 = ip1;
+		struct ipv4_hdr *hdr2 = ip2;
+		struct ipv4_hdr *hdr3 = ip3;
+
+		dscp0 = hdr0->type_of_service >> 2;
+		dscp1 = hdr1->type_of_service >> 2;
+		dscp2 = hdr2->type_of_service >> 2;
+		dscp3 = hdr3->type_of_service >> 2;
+
+		total_length0 = rte_ntohs(hdr0->total_length);
+		total_length1 = rte_ntohs(hdr1->total_length);
+		total_length2 = rte_ntohs(hdr2->total_length);
+		total_length3 = rte_ntohs(hdr3->total_length);
+	} else {
+		struct ipv6_hdr *hdr0 = ip0;
+		struct ipv6_hdr *hdr1 = ip1;
+		struct ipv6_hdr *hdr2 = ip2;
+		struct ipv6_hdr *hdr3 = ip3;
+
+		dscp0 = (rte_ntohl(hdr0->vtc_flow) & 0x0F600000) >> 18;
+		dscp1 = (rte_ntohl(hdr1->vtc_flow) & 0x0F600000) >> 18;
+		dscp2 = (rte_ntohl(hdr2->vtc_flow) & 0x0F600000) >> 18;
+		dscp3 = (rte_ntohl(hdr3->vtc_flow) & 0x0F600000) >> 18;
+
+		total_length0 =
+			rte_ntohs(hdr0->payload_len) + sizeof(struct ipv6_hdr);
+		total_length1 =
+			rte_ntohs(hdr1->payload_len) + sizeof(struct ipv6_hdr);
+		total_length2 =
+			rte_ntohs(hdr2->payload_len) + sizeof(struct ipv6_hdr);
+		total_length3 =
+			rte_ntohs(hdr3->payload_len) + sizeof(struct ipv6_hdr);
+	}
+
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) {
+		void *data0 =
+			action_data_get(table_entry0, action, RTE_TABLE_ACTION_MTR);
+		void *data1 =
+			action_data_get(table_entry1, action, RTE_TABLE_ACTION_MTR);
+		void *data2 =
+			action_data_get(table_entry2, action, RTE_TABLE_ACTION_MTR);
+		void *data3 =
+			action_data_get(table_entry3, action, RTE_TABLE_ACTION_MTR);
+
+		drop_mask0 |= pkt_work_mtr(mbuf0,
+			data0,
+			&action->dscp_table,
+			action->mp,
+			time,
+			dscp0,
+			total_length0);
+
+		drop_mask1 |= pkt_work_mtr(mbuf1,
+			data1,
+			&action->dscp_table,
+			action->mp,
+			time,
+			dscp1,
+			total_length1);
+
+		drop_mask2 |= pkt_work_mtr(mbuf2,
+			data2,
+			&action->dscp_table,
+			action->mp,
+			time,
+			dscp2,
+			total_length2);
+
+		drop_mask3 |= pkt_work_mtr(mbuf3,
+			data3,
+			&action->dscp_table,
+			action->mp,
+			time,
+			dscp3,
+			total_length3);
+	}
+
+	return drop_mask0 |
+		(drop_mask1 << 1) |
+		(drop_mask2 << 2) |
+		(drop_mask3 << 3);
+}
+
 static __rte_always_inline int
 ah(struct rte_pipeline *p,
 	struct rte_mbuf **pkts,
@@ -297,6 +902,9 @@ ah(struct rte_pipeline *p,
 	uint64_t pkts_drop_mask = 0;
 	uint64_t time = 0;
 
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_MTR))
+		time = rte_rdtsc();
+
 	if ((pkts_mask & (pkts_mask + 1)) == 0) {
 		uint64_t n_pkts = __builtin_popcountll(pkts_mask);
 		uint32_t i;
diff --git a/lib/librte_pipeline/rte_table_action.h b/lib/librte_pipeline/rte_table_action.h
index 03b77ca..c2f4a55 100644
--- a/lib/librte_pipeline/rte_table_action.h
+++ b/lib/librte_pipeline/rte_table_action.h
@@ -59,6 +59,7 @@ extern "C" {
 #include <stdint.h>
 
 #include <rte_compat.h>
+#include <rte_meter.h>
 
 #include "rte_pipeline.h"
 
@@ -66,6 +67,9 @@ extern "C" {
 enum rte_table_action_type {
 	/** Forward to next pipeline table, output port or drop. */
 	RTE_TABLE_ACTION_FWD = 0,
+
+	/**  Traffic Metering and Policing. */
+	RTE_TABLE_ACTION_MTR,
 };
 
 /** Common action configuration (per table action profile). */
@@ -94,6 +98,164 @@ struct rte_table_action_fwd_params {
 };
 
 /**
+ * RTE_TABLE_ACTION_MTR
+ */
+/** Max number of traffic classes (TCs). */
+#define RTE_TABLE_ACTION_TC_MAX                                  4
+
+/** Max number of queues per traffic class. */
+#define RTE_TABLE_ACTION_TC_QUEUE_MAX                            4
+
+/** Differentiated Services Code Point (DSCP) translation table entry. */
+struct rte_table_action_dscp_table_entry {
+	/** Traffic class. Used by the meter or the traffic management actions.
+	 * Has to be strictly smaller than *RTE_TABLE_ACTION_TC_MAX*. Traffic
+	 * class 0 is the highest priority.
+	 */
+	uint32_t tc_id;
+
+	/** Traffic class queue. Used by the traffic management action. Has to
+	 * be strictly smaller than *RTE_TABLE_ACTION_TC_QUEUE_MAX*.
+	 */
+	uint32_t tc_queue_id;
+
+	/** Packet color. Used by the meter action as the packet input color
+	 * for the color aware mode of the traffic metering algorithm.
+	 */
+	enum rte_meter_color color;
+};
+
+/** DSCP translation table. */
+struct rte_table_action_dscp_table {
+	/** Array of DSCP table entries */
+	struct rte_table_action_dscp_table_entry entry[64];
+};
+
+/** Supported traffic metering algorithms. */
+enum rte_table_action_meter_algorithm {
+	/** Single Rate Three Color Marker (srTCM) - IETF RFC 2697. */
+	RTE_TABLE_ACTION_METER_SRTCM,
+
+	/** Two Rate Three Color Marker (trTCM) - IETF RFC 2698. */
+	RTE_TABLE_ACTION_METER_TRTCM,
+};
+
+/** Traffic metering profile (configuration template). */
+struct rte_table_action_meter_profile {
+	/** Traffic metering algorithm. */
+	enum rte_table_action_meter_algorithm alg;
+
+	RTE_STD_C11
+	union {
+		/** Only valid when *alg* is set to srTCM - IETF RFC 2697. */
+		struct rte_meter_srtcm_params srtcm;
+
+		/** Only valid when *alg* is set to trTCM - IETF RFC 2698. */
+		struct rte_meter_trtcm_params trtcm;
+	};
+};
+
+/** Policer actions. */
+enum rte_table_action_policer {
+	/** Recolor the packet as green. */
+	RTE_TABLE_ACTION_POLICER_COLOR_GREEN = 0,
+
+	/** Recolor the packet as yellow. */
+	RTE_TABLE_ACTION_POLICER_COLOR_YELLOW,
+
+	/** Recolor the packet as red. */
+	RTE_TABLE_ACTION_POLICER_COLOR_RED,
+
+	/** Drop the packet. */
+	RTE_TABLE_ACTION_POLICER_DROP,
+
+	/** Number of policer actions. */
+	RTE_TABLE_ACTION_POLICER_MAX
+};
+
+/** Meter action configuration per traffic class. */
+struct rte_table_action_mtr_tc_params {
+	/** Meter profile ID. */
+	uint32_t meter_profile_id;
+
+	/** Policer actions. */
+	enum rte_table_action_policer policer[e_RTE_METER_COLORS];
+};
+
+/** Meter action statistics counters per traffic class. */
+struct rte_table_action_mtr_counters_tc {
+	/** Number of packets per color at the output of the traffic metering
+	 * and before the policer actions are executed. Only valid when
+	 * *n_packets_valid* is non-zero.
+	 */
+	uint64_t n_packets[e_RTE_METER_COLORS];
+
+	/** Number of packet bytes per color at the output of the traffic
+	 * metering and before the policer actions are executed. Only valid when
+	 * *n_bytes_valid* is non-zero.
+	 */
+	uint64_t n_bytes[e_RTE_METER_COLORS];
+
+	/** When non-zero, the *n_packets* field is valid. */
+	int n_packets_valid;
+
+	/** When non-zero, the *n_bytes* field is valid. */
+	int n_bytes_valid;
+};
+
+/** Meter action configuration (per table action profile). */
+struct rte_table_action_mtr_config {
+	/** Meter algorithm. */
+	enum rte_table_action_meter_algorithm alg;
+
+	/** Number of traffic classes. Each traffic class has its own traffic
+	 * meter and policer instances. Needs to be equal to either 1 or to
+	 * *RTE_TABLE_ACTION_TC_MAX*.
+	 */
+	uint32_t n_tc;
+
+	/** When non-zero, the *n_packets* meter stats counter is enabled,
+	 * otherwise it is disabled.
+	 *
+	 * @see struct rte_table_action_mtr_counters_tc
+	 */
+	int n_packets_enabled;
+
+	/** When non-zero, the *n_bytes* meter stats counter is enabled,
+	 * otherwise it is disabled.
+	 *
+	 * @see struct rte_table_action_mtr_counters_tc
+	 */
+	int n_bytes_enabled;
+};
+
+/** Meter action parameters (per table rule). */
+struct rte_table_action_mtr_params {
+	/** Traffic meter and policer parameters for each of the *tc_mask*
+	 * traffic classes.
+	 */
+	struct rte_table_action_mtr_tc_params mtr[RTE_TABLE_ACTION_TC_MAX];
+
+	/** Bit mask defining which traffic class parameters are valid in *mtr*.
+	 * If bit N is set in *tc_mask*, then parameters for traffic class N are
+	 * valid in *mtr*.
+	 */
+	uint32_t tc_mask;
+};
+
+/** Meter action statistics counters (per table rule). */
+struct rte_table_action_mtr_counters {
+	/** Stats counters for each of the *tc_mask* traffic classes. */
+	struct rte_table_action_mtr_counters_tc stats[RTE_TABLE_ACTION_TC_MAX];
+
+	/** Bit mask defining which traffic class parameters are valid in *mtr*.
+	 * If bit N is set in *tc_mask*, then parameters for traffic class N are
+	 * valid in *mtr*.
+	 */
+	uint32_t tc_mask;
+};
+
+/**
  * Table action profile.
  */
 struct rte_table_action_profile;
@@ -231,6 +393,92 @@ rte_table_action_apply(struct rte_table_action *action,
 	enum rte_table_action_type type,
 	void *action_params);
 
+/**
+ * Table action DSCP table update.
+ *
+ * @param[in] action
+ *   Handle to table action object (needs to be valid).
+ * @param[in] dscp_mask
+ *   64-bit mask defining the DSCP table entries to be updated. If bit N is set
+ *   in this bit mask, then DSCP table entry N is to be updated, otherwise not.
+ * @param[in] table
+ *   DSCP table.
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_table_action_dscp_table_update(struct rte_table_action *action,
+	uint64_t dscp_mask,
+	struct rte_table_action_dscp_table *table);
+
+/**
+ * Table action meter profile add.
+ *
+ * @param[in] action
+ *   Handle to table action object (needs to be valid).
+ * @param[in] meter_profile_id
+ *   Meter profile ID to be used for the *profile* once it is successfully added
+ *   to the *action* object (needs to be unused by the set of meter profiles
+ *   currently registered for the *action* object).
+ * @param[in] profile
+ *   Meter profile to be added.
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_table_action_meter_profile_add(struct rte_table_action *action,
+	uint32_t meter_profile_id,
+	struct rte_table_action_meter_profile *profile);
+
+/**
+ * Table action meter profile delete.
+ *
+ * @param[in] action
+ *   Handle to table action object (needs to be valid).
+ * @param[in] meter_profile_id
+ *   Meter profile ID of the meter profile to be deleted from the *action*
+ *   object (needs to be valid for the *action* object).
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_table_action_meter_profile_delete(struct rte_table_action *action,
+	uint32_t meter_profile_id);
+
+/**
+ * Table action meter read.
+ *
+ * @param[in] action
+ *   Handle to table action object (needs to be valid).
+ * @param[in] data
+ *   Data byte array (typically table rule data) with meter action previously
+ *   applied on it.
+ * @param[in] tc_mask
+ *   Bit mask defining which traffic classes should have the meter stats
+ *   counters read from *data* and stored into *stats*. If bit N is set in this
+ *   bit mask, then traffic class N is part of this operation, otherwise it is
+ *   not. If bit N is set in this bit mask, then traffic class N must be one of
+ *   the traffic classes that are enabled for the meter action in the table
+ *   action profile used by the *action* object.
+ * @param[inout] stats
+ *   When non-NULL, it points to the area where the meter stats counters read
+ *   from *data* are saved. Only the meter stats counters for the *tc_mask*
+ *   traffic classes are read and stored to *stats*.
+ * @param[in] clear
+ *   When non-zero, the meter stats counters are cleared (i.e. set to zero),
+ *   otherwise the counters are not modified. When the read operation is enabled
+ *   (*stats* is non-NULL), the clear operation is performed after the read
+ *   operation is completed.
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_table_action_meter_read(struct rte_table_action *action,
+	void *data,
+	uint32_t tc_mask,
+	struct rte_table_action_mtr_counters *stats,
+	int clear);
+
 #ifdef __cplusplus
 }
 #endif
-- 
2.9.3

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

* [dpdk-dev] [PATCH v2 04/44] pipeline: add traffic manager action
  2018-03-12 17:25   ` [dpdk-dev] [PATCH v2 00/44] ip_pipeline: refactoring Jasvinder Singh
                       ` (2 preceding siblings ...)
  2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 03/44] pipeline: add traffic metering action Jasvinder Singh
@ 2018-03-12 17:25     ` Jasvinder Singh
  2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 05/44] pipeline: add packet encapsulation action Jasvinder Singh
                       ` (39 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-12 17:25 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add implementation of traffic manager action.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 lib/librte_pipeline/Makefile           |   2 +-
 lib/librte_pipeline/meson.build        |   2 +-
 lib/librte_pipeline/rte_table_action.c | 130 ++++++++++++++++++++++++++++++++-
 lib/librte_pipeline/rte_table_action.h |  24 ++++++
 4 files changed, 155 insertions(+), 3 deletions(-)

diff --git a/lib/librte_pipeline/Makefile b/lib/librte_pipeline/Makefile
index 72e4c7c..c0eaa09 100644
--- a/lib/librte_pipeline/Makefile
+++ b/lib/librte_pipeline/Makefile
@@ -12,7 +12,7 @@ CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
 LDLIBS += -lrte_eal -lrte_mempool -lrte_mbuf -lrte_table
-LDLIBS += -lrte_port -lrte_meter
+LDLIBS += -lrte_port -lrte_meter -lrte_sched
 
 EXPORT_MAP := rte_pipeline_version.map
 
diff --git a/lib/librte_pipeline/meson.build b/lib/librte_pipeline/meson.build
index 71da295..1ee276f 100644
--- a/lib/librte_pipeline/meson.build
+++ b/lib/librte_pipeline/meson.build
@@ -5,4 +5,4 @@ version = 3
 allow_experimental_apis = true
 sources = files('rte_pipeline.c', 'rte_table_action.c')
 headers = files('rte_pipeline.h', 'rte_table_action.h')
-deps += ['port', 'table', 'meter']
+deps += ['port', 'table', 'meter', 'sched']
diff --git a/lib/librte_pipeline/rte_table_action.c b/lib/librte_pipeline/rte_table_action.c
index 3a2268d..cbf9a29 100644
--- a/lib/librte_pipeline/rte_table_action.c
+++ b/lib/librte_pipeline/rte_table_action.c
@@ -297,6 +297,73 @@ pkt_work_mtr(struct rte_mbuf *mbuf,
 	return drop_mask;
 }
 
+/**
+ * RTE_TABLE_ACTION_TM
+ */
+static int
+tm_cfg_check(struct rte_table_action_tm_config *tm)
+{
+	if ((tm->n_subports_per_port == 0) ||
+		(rte_is_power_of_2(tm->n_subports_per_port) == 0) ||
+		(tm->n_subports_per_port > UINT16_MAX) ||
+		(tm->n_pipes_per_subport == 0) ||
+		(rte_is_power_of_2(tm->n_pipes_per_subport) == 0))
+		return -ENOTSUP;
+
+	return 0;
+}
+
+struct tm_data {
+	uint16_t queue_tc_color;
+	uint16_t subport;
+	uint32_t pipe;
+} __attribute__((__packed__));
+
+static int
+tm_apply_check(struct rte_table_action_tm_params *p,
+	struct rte_table_action_tm_config *cfg)
+{
+	if ((p->subport_id >= cfg->n_subports_per_port) ||
+		(p->pipe_id >= cfg->n_pipes_per_subport))
+		return -EINVAL;
+
+	return 0;
+}
+
+static int
+tm_apply(struct tm_data *data,
+	struct rte_table_action_tm_params *p,
+	struct rte_table_action_tm_config *cfg)
+{
+	int status;
+
+	/* Check input arguments */
+	status = tm_apply_check(p, cfg);
+	if (status)
+		return status;
+
+	/* Apply */
+	data->queue_tc_color = 0;
+	data->subport = (uint16_t) p->subport_id;
+	data->pipe = p->pipe_id;
+
+	return 0;
+}
+
+static __rte_always_inline void
+pkt_work_tm(struct rte_mbuf *mbuf,
+	struct tm_data *data,
+	struct dscp_table_data *dscp_table,
+	uint32_t dscp)
+{
+	struct dscp_table_entry_data *dscp_entry = &dscp_table->entry[dscp];
+	struct tm_data *sched_ptr = (struct tm_data *) &mbuf->hash.sched;
+	struct tm_data sched;
+
+	sched = *data;
+	sched.queue_tc_color = dscp_entry->queue_tc_color;
+	*sched_ptr = sched;
+}
 
 /**
  * Action profile
@@ -307,6 +374,7 @@ action_valid(enum rte_table_action_type action)
 	switch (action) {
 	case RTE_TABLE_ACTION_FWD:
 	case RTE_TABLE_ACTION_MTR:
+	case RTE_TABLE_ACTION_TM:
 		return 1;
 	default:
 		return 0;
@@ -320,6 +388,7 @@ struct ap_config {
 	uint64_t action_mask;
 	struct rte_table_action_common_config common;
 	struct rte_table_action_mtr_config mtr;
+	struct rte_table_action_tm_config tm;
 };
 
 static size_t
@@ -328,6 +397,8 @@ action_cfg_size(enum rte_table_action_type action)
 	switch (action) {
 	case RTE_TABLE_ACTION_MTR:
 		return sizeof(struct rte_table_action_mtr_config);
+	case RTE_TABLE_ACTION_TM:
+		return sizeof(struct rte_table_action_tm_config);
 	default:
 		return 0;
 	}
@@ -341,6 +412,9 @@ action_cfg_get(struct ap_config *ap_config,
 	case RTE_TABLE_ACTION_MTR:
 		return &ap_config->mtr;
 
+	case RTE_TABLE_ACTION_TM:
+		return &ap_config->tm;
+
 	default:
 		return NULL;
 	}
@@ -375,6 +449,9 @@ action_data_size(enum rte_table_action_type action,
 	case RTE_TABLE_ACTION_MTR:
 		return mtr_data_size(&ap_config->mtr);
 
+	case RTE_TABLE_ACTION_TM:
+		return sizeof(struct tm_data);
+
 	default:
 		return 0;
 	}
@@ -449,6 +526,10 @@ rte_table_action_profile_action_register(struct rte_table_action_profile *profil
 		status = mtr_cfg_check(action_config);
 		break;
 
+	case RTE_TABLE_ACTION_TM:
+		status = tm_cfg_check(action_config);
+		break;
+
 	default:
 		status = 0;
 		break;
@@ -566,6 +647,11 @@ rte_table_action_apply(struct rte_table_action *action,
 			action->mp,
 			RTE_DIM(action->mp));
 
+	case RTE_TABLE_ACTION_TM:
+		return tm_apply(action_data,
+			action_params,
+			&action->cfg.tm);
+
 	default:
 		return -EINVAL;
 	}
@@ -580,7 +666,8 @@ rte_table_action_dscp_table_update(struct rte_table_action *action,
 
 	/* Check input arguments */
 	if ((action == NULL) ||
-		(action->cfg.action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) ||
+		((action->cfg.action_mask & ((1LLU << RTE_TABLE_ACTION_MTR) |
+		(1LLU << RTE_TABLE_ACTION_TM))) == 0) ||
 		(dscp_mask == 0) ||
 		(table == NULL))
 		return -EINVAL;
@@ -772,6 +859,16 @@ pkt_work(struct rte_mbuf *mbuf,
 			total_length);
 	}
 
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_TM)) {
+		void *data =
+			action_data_get(table_entry, action, RTE_TABLE_ACTION_TM);
+
+		pkt_work_tm(mbuf,
+			data,
+			&action->dscp_table,
+			dscp);
+	}
+
 	return drop_mask;
 }
 
@@ -885,6 +982,37 @@ pkt4_work(struct rte_mbuf **mbufs,
 			total_length3);
 	}
 
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_TM)) {
+		void *data0 =
+			action_data_get(table_entry0, action, RTE_TABLE_ACTION_TM);
+		void *data1 =
+			action_data_get(table_entry1, action, RTE_TABLE_ACTION_TM);
+		void *data2 =
+			action_data_get(table_entry2, action, RTE_TABLE_ACTION_TM);
+		void *data3 =
+			action_data_get(table_entry3, action, RTE_TABLE_ACTION_TM);
+
+		pkt_work_tm(mbuf0,
+			data0,
+			&action->dscp_table,
+			dscp0);
+
+		pkt_work_tm(mbuf1,
+			data1,
+			&action->dscp_table,
+			dscp1);
+
+		pkt_work_tm(mbuf2,
+			data2,
+			&action->dscp_table,
+			dscp2);
+
+		pkt_work_tm(mbuf3,
+			data3,
+			&action->dscp_table,
+			dscp3);
+	}
+
 	return drop_mask0 |
 		(drop_mask1 << 1) |
 		(drop_mask2 << 2) |
diff --git a/lib/librte_pipeline/rte_table_action.h b/lib/librte_pipeline/rte_table_action.h
index c2f4a55..98babc5 100644
--- a/lib/librte_pipeline/rte_table_action.h
+++ b/lib/librte_pipeline/rte_table_action.h
@@ -70,6 +70,9 @@ enum rte_table_action_type {
 
 	/**  Traffic Metering and Policing. */
 	RTE_TABLE_ACTION_MTR,
+
+	/**  Traffic Management. */
+	RTE_TABLE_ACTION_TM,
 };
 
 /** Common action configuration (per table action profile). */
@@ -256,6 +259,27 @@ struct rte_table_action_mtr_counters {
 };
 
 /**
+ * RTE_TABLE_ACTION_TM
+ */
+/** Traffic management action configuration (per table action profile). */
+struct rte_table_action_tm_config {
+	/** Number of subports per port. */
+	uint32_t n_subports_per_port;
+
+	/** Number of pipes per subport. */
+	uint32_t n_pipes_per_subport;
+};
+
+/** Traffic management action parameters (per table rule). */
+struct rte_table_action_tm_params {
+	/** Subport ID. */
+	uint32_t subport_id;
+
+	/** Pipe ID. */
+	uint32_t pipe_id;
+};
+
+/**
  * Table action profile.
  */
 struct rte_table_action_profile;
-- 
2.9.3

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

* [dpdk-dev] [PATCH v2 05/44] pipeline: add packet encapsulation action
  2018-03-12 17:25   ` [dpdk-dev] [PATCH v2 00/44] ip_pipeline: refactoring Jasvinder Singh
                       ` (3 preceding siblings ...)
  2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 04/44] pipeline: add traffic manager action Jasvinder Singh
@ 2018-03-12 17:25     ` Jasvinder Singh
  2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 06/44] pipeline: add nat action Jasvinder Singh
                       ` (38 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-12 17:25 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add implementation of different type of packet encap
such as vlan, qinq, mpls, pppoe, etc.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 lib/librte_pipeline/rte_table_action.c | 440 ++++++++++++++++++++++++++++++++-
 lib/librte_pipeline/rte_table_action.h | 129 ++++++++++
 2 files changed, 568 insertions(+), 1 deletion(-)

diff --git a/lib/librte_pipeline/rte_table_action.c b/lib/librte_pipeline/rte_table_action.c
index cbf9a29..cd8e7d1 100644
--- a/lib/librte_pipeline/rte_table_action.c
+++ b/lib/librte_pipeline/rte_table_action.c
@@ -9,8 +9,12 @@
 #include <rte_byteorder.h>
 #include <rte_cycles.h>
 #include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_ether.h>
 #include <rte_ip.h>
-
+#include <rte_esp.h>
+#include <rte_tcp.h>
+#include <rte_udp.h>
 
 #include "rte_table_action.h"
 
@@ -366,6 +370,369 @@ pkt_work_tm(struct rte_mbuf *mbuf,
 }
 
 /**
+ * RTE_TABLE_ACTION_ENCAP
+ */
+static int
+encap_valid(enum rte_table_action_encap_type encap)
+{
+	switch (encap) {
+	case RTE_TABLE_ACTION_ENCAP_ETHER:
+	case RTE_TABLE_ACTION_ENCAP_VLAN:
+	case RTE_TABLE_ACTION_ENCAP_QINQ:
+	case RTE_TABLE_ACTION_ENCAP_MPLS:
+	case RTE_TABLE_ACTION_ENCAP_PPPOE:
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+static int
+encap_cfg_check(struct rte_table_action_encap_config *encap)
+{
+	if ((encap->encap_mask == 0) ||
+		(__builtin_popcountll(encap->encap_mask) != 1))
+		return -ENOTSUP;
+
+	return 0;
+}
+
+struct encap_ether_data {
+	struct ether_hdr ether;
+} __attribute__((__packed__));
+
+#define VLAN(pcp, dei, vid)                                \
+	((uint16_t)((((uint64_t)(pcp)) & 0x7LLU) << 13) |  \
+	((((uint64_t)(dei)) & 0x1LLU) << 12) |             \
+	(((uint64_t)(vid)) & 0xFFFLLU))                    \
+
+struct encap_vlan_data {
+	struct ether_hdr ether;
+	struct vlan_hdr vlan;
+} __attribute__((__packed__));
+
+struct encap_qinq_data {
+	struct ether_hdr ether;
+	struct vlan_hdr svlan;
+	struct vlan_hdr cvlan;
+} __attribute__((__packed__));
+
+#define ETHER_TYPE_MPLS_UNICAST                            0x8847
+
+#define ETHER_TYPE_MPLS_MULTICAST                          0x8848
+
+#define MPLS(label, tc, s, ttl)                            \
+	((uint32_t)(((((uint64_t)(label)) & 0xFFFFFLLU) << 12) |\
+	((((uint64_t)(tc)) & 0x7LLU) << 9) |               \
+	((((uint64_t)(s)) & 0x1LLU) << 8) |                \
+	(((uint64_t)(ttl)) & 0xFFLLU)))
+
+struct encap_mpls_data {
+	struct ether_hdr ether;
+	uint32_t mpls[RTE_TABLE_ACTION_MPLS_LABELS_MAX];
+	uint32_t mpls_count;
+} __attribute__((__packed__));
+
+#define ETHER_TYPE_PPPOE_SESSION                           0x8864
+
+#define PPP_PROTOCOL_IP                                    0x0021
+
+struct pppoe_ppp_hdr {
+	uint16_t ver_type_code;
+	uint16_t session_id;
+	uint16_t length;
+	uint16_t protocol;
+} __attribute__((__packed__));
+
+struct encap_pppoe_data {
+	struct ether_hdr ether;
+	struct pppoe_ppp_hdr pppoe_ppp;
+} __attribute__((__packed__));
+
+static size_t
+encap_data_size(struct rte_table_action_encap_config *encap)
+{
+	switch (encap->encap_mask) {
+	case 1LLU << RTE_TABLE_ACTION_ENCAP_ETHER:
+		return sizeof(struct encap_ether_data);
+
+	case 1LLU << RTE_TABLE_ACTION_ENCAP_VLAN:
+		return sizeof(struct encap_vlan_data);
+
+	case 1LLU << RTE_TABLE_ACTION_ENCAP_QINQ:
+		return sizeof(struct encap_qinq_data);
+
+	case 1LLU << RTE_TABLE_ACTION_ENCAP_MPLS:
+		return sizeof(struct encap_mpls_data);
+
+	case 1LLU << RTE_TABLE_ACTION_ENCAP_PPPOE:
+		return sizeof(struct encap_pppoe_data);
+
+	default:
+		return 0;
+	}
+}
+
+static int
+encap_apply_check(struct rte_table_action_encap_params *p,
+	struct rte_table_action_encap_config *cfg)
+{
+	if ((encap_valid(p->type) == 0) ||
+		((cfg->encap_mask & (1LLU << p->type)) == 0))
+		return -EINVAL;
+
+	switch (p->type) {
+	case RTE_TABLE_ACTION_ENCAP_ETHER:
+		return 0;
+
+	case RTE_TABLE_ACTION_ENCAP_VLAN:
+		return 0;
+
+	case RTE_TABLE_ACTION_ENCAP_QINQ:
+		return 0;
+
+	case RTE_TABLE_ACTION_ENCAP_MPLS:
+		if ((p->mpls.mpls_count == 0) ||
+			(p->mpls.mpls_count > RTE_TABLE_ACTION_MPLS_LABELS_MAX))
+			return -EINVAL;
+
+		return 0;
+
+	case RTE_TABLE_ACTION_ENCAP_PPPOE:
+		return 0;
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static int
+encap_ether_apply(void *data,
+	struct rte_table_action_encap_params *p,
+	struct rte_table_action_common_config *common_cfg)
+{
+	struct encap_ether_data *d = data;
+	uint16_t ethertype = (common_cfg->ip_version) ?
+		ETHER_TYPE_IPv4 :
+		ETHER_TYPE_IPv6;
+
+	/* Ethernet */
+	ether_addr_copy(&p->ether.ether.da, &d->ether.d_addr);
+	ether_addr_copy(&p->ether.ether.sa, &d->ether.s_addr);
+	d->ether.ether_type = rte_htons(ethertype);
+
+	return 0;
+}
+
+static int
+encap_vlan_apply(void *data,
+	struct rte_table_action_encap_params *p,
+	struct rte_table_action_common_config *common_cfg)
+{
+	struct encap_vlan_data *d = data;
+	uint16_t ethertype = (common_cfg->ip_version) ?
+		ETHER_TYPE_IPv4 :
+		ETHER_TYPE_IPv6;
+
+	/* Ethernet */
+	ether_addr_copy(&p->vlan.ether.da, &d->ether.d_addr);
+	ether_addr_copy(&p->vlan.ether.sa, &d->ether.s_addr);
+	d->ether.ether_type = rte_htons(ETHER_TYPE_VLAN);
+
+	/* VLAN */
+	d->vlan.vlan_tci = rte_htons(VLAN(p->vlan.vlan.pcp,
+		p->vlan.vlan.dei,
+		p->vlan.vlan.vid));
+	d->vlan.eth_proto = rte_htons(ethertype);
+
+	return 0;
+}
+
+static int
+encap_qinq_apply(void *data,
+	struct rte_table_action_encap_params *p,
+	struct rte_table_action_common_config *common_cfg)
+{
+	struct encap_qinq_data *d = data;
+	uint16_t ethertype = (common_cfg->ip_version) ?
+		ETHER_TYPE_IPv4 :
+		ETHER_TYPE_IPv6;
+
+	/* Ethernet */
+	ether_addr_copy(&p->qinq.ether.da, &d->ether.d_addr);
+	ether_addr_copy(&p->qinq.ether.sa, &d->ether.s_addr);
+	d->ether.ether_type = rte_htons(ETHER_TYPE_QINQ);
+
+	/* SVLAN */
+	d->svlan.vlan_tci = rte_htons(VLAN(p->qinq.svlan.pcp,
+		p->qinq.svlan.dei,
+		p->qinq.svlan.vid));
+	d->svlan.eth_proto = rte_htons(ETHER_TYPE_VLAN);
+
+	/* CVLAN */
+	d->cvlan.vlan_tci = rte_htons(VLAN(p->qinq.cvlan.pcp,
+		p->qinq.cvlan.dei,
+		p->qinq.cvlan.vid));
+	d->cvlan.eth_proto = rte_htons(ethertype);
+
+	return 0;
+}
+
+static int
+encap_mpls_apply(void *data,
+	struct rte_table_action_encap_params *p)
+{
+	struct encap_mpls_data *d = data;
+	uint16_t ethertype = (p->mpls.unicast) ?
+		ETHER_TYPE_MPLS_UNICAST :
+		ETHER_TYPE_MPLS_MULTICAST;
+	uint32_t i;
+
+	/* Ethernet */
+	ether_addr_copy(&p->mpls.ether.da, &d->ether.d_addr);
+	ether_addr_copy(&p->mpls.ether.sa, &d->ether.s_addr);
+	d->ether.ether_type = rte_htons(ethertype);
+
+	/* MPLS */
+	for (i = 0; i < p->mpls.mpls_count - 1; i++)
+		d->mpls[i] = rte_htonl(MPLS(p->mpls.mpls[i].label,
+			p->mpls.mpls[i].tc,
+			0,
+			p->mpls.mpls[i].ttl));
+
+	d->mpls[i] = rte_htonl(MPLS(p->mpls.mpls[i].label,
+		p->mpls.mpls[i].tc,
+		1,
+		p->mpls.mpls[i].ttl));
+
+	d->mpls_count = p->mpls.mpls_count;
+	return 0;
+}
+
+static int
+encap_pppoe_apply(void *data,
+	struct rte_table_action_encap_params *p)
+{
+	struct encap_pppoe_data *d = data;
+
+	/* Ethernet */
+	ether_addr_copy(&p->pppoe.ether.da, &d->ether.d_addr);
+	ether_addr_copy(&p->pppoe.ether.sa, &d->ether.s_addr);
+	d->ether.ether_type = rte_htons(ETHER_TYPE_PPPOE_SESSION);
+
+	/* PPPoE and PPP*/
+	d->pppoe_ppp.ver_type_code = rte_htons(0x1100);
+	d->pppoe_ppp.session_id = rte_htons(p->pppoe.pppoe.session_id);
+	d->pppoe_ppp.length = 0; /* not pre-computed */
+	d->pppoe_ppp.protocol = rte_htons(PPP_PROTOCOL_IP);
+
+	return 0;
+}
+
+static int
+encap_apply(void *data,
+	struct rte_table_action_encap_params *p,
+	struct rte_table_action_encap_config *cfg,
+	struct rte_table_action_common_config *common_cfg)
+{
+	int status;
+
+	/* Check input arguments */
+	status = encap_apply_check(p, cfg);
+	if (status)
+		return status;
+
+	switch (p->type) {
+	case RTE_TABLE_ACTION_ENCAP_ETHER:
+		return encap_ether_apply(data, p, common_cfg);
+
+	case RTE_TABLE_ACTION_ENCAP_VLAN:
+		return encap_vlan_apply(data, p, common_cfg);
+
+	case RTE_TABLE_ACTION_ENCAP_QINQ:
+		return encap_qinq_apply(data, p, common_cfg);
+
+	case RTE_TABLE_ACTION_ENCAP_MPLS:
+		return encap_mpls_apply(data, p);
+
+	case RTE_TABLE_ACTION_ENCAP_PPPOE:
+		return encap_pppoe_apply(data, p);
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static __rte_always_inline void *
+encap(void *dst, const void *src, size_t n)
+{
+	dst = ((uint8_t *) dst) - n;
+	return rte_memcpy(dst, src, n);
+}
+
+static __rte_always_inline void
+pkt_work_encap(struct rte_mbuf *mbuf,
+	void *data,
+	struct rte_table_action_encap_config *cfg,
+	void *ip,
+	uint16_t total_length,
+	uint32_t ip_offset)
+{
+	switch (cfg->encap_mask) {
+	case 1LLU << RTE_TABLE_ACTION_ENCAP_ETHER:
+		encap(ip, data, sizeof(struct encap_ether_data));
+		mbuf->data_off = ip_offset - (sizeof(struct rte_mbuf) +
+			sizeof(struct encap_ether_data));
+		mbuf->pkt_len = mbuf->data_len = total_length +
+			sizeof(struct encap_ether_data);
+		break;
+
+	case 1LLU << RTE_TABLE_ACTION_ENCAP_VLAN:
+		encap(ip, data, sizeof(struct encap_vlan_data));
+		mbuf->data_off = ip_offset - (sizeof(struct rte_mbuf) +
+			sizeof(struct encap_vlan_data));
+		mbuf->pkt_len = mbuf->data_len = total_length +
+			sizeof(struct encap_vlan_data);
+		break;
+
+	case 1LLU << RTE_TABLE_ACTION_ENCAP_QINQ:
+		encap(ip, data, sizeof(struct encap_qinq_data));
+		mbuf->data_off = ip_offset - (sizeof(struct rte_mbuf) +
+			sizeof(struct encap_qinq_data));
+		mbuf->pkt_len = mbuf->data_len = total_length +
+			sizeof(struct encap_qinq_data);
+		break;
+
+	case 1LLU << RTE_TABLE_ACTION_ENCAP_MPLS:
+	{
+		struct encap_mpls_data *mpls = data;
+		size_t size = sizeof(struct ether_hdr) +
+			mpls->mpls_count * 4;
+
+		encap(ip, data, size);
+		mbuf->data_off = ip_offset - (sizeof(struct rte_mbuf) + size);
+		mbuf->pkt_len = mbuf->data_len = total_length + size;
+		break;
+	}
+
+	case 1LLU << RTE_TABLE_ACTION_ENCAP_PPPOE:
+	{
+		struct encap_pppoe_data *pppoe =
+			encap(ip, data, sizeof(struct encap_pppoe_data));
+		pppoe->pppoe_ppp.length = rte_htons(total_length + 2);
+		mbuf->data_off = ip_offset - (sizeof(struct rte_mbuf) +
+			sizeof(struct encap_pppoe_data));
+		mbuf->pkt_len = mbuf->data_len = total_length +
+			sizeof(struct encap_pppoe_data);
+		break;
+	}
+
+	default:
+		break;
+	}
+}
+
+/**
  * Action profile
  */
 static int
@@ -375,6 +742,7 @@ action_valid(enum rte_table_action_type action)
 	case RTE_TABLE_ACTION_FWD:
 	case RTE_TABLE_ACTION_MTR:
 	case RTE_TABLE_ACTION_TM:
+	case RTE_TABLE_ACTION_ENCAP:
 		return 1;
 	default:
 		return 0;
@@ -389,6 +757,7 @@ struct ap_config {
 	struct rte_table_action_common_config common;
 	struct rte_table_action_mtr_config mtr;
 	struct rte_table_action_tm_config tm;
+	struct rte_table_action_encap_config encap;
 };
 
 static size_t
@@ -399,6 +768,8 @@ action_cfg_size(enum rte_table_action_type action)
 		return sizeof(struct rte_table_action_mtr_config);
 	case RTE_TABLE_ACTION_TM:
 		return sizeof(struct rte_table_action_tm_config);
+	case RTE_TABLE_ACTION_ENCAP:
+		return sizeof(struct rte_table_action_encap_config);
 	default:
 		return 0;
 	}
@@ -415,6 +786,9 @@ action_cfg_get(struct ap_config *ap_config,
 	case RTE_TABLE_ACTION_TM:
 		return &ap_config->tm;
 
+	case RTE_TABLE_ACTION_ENCAP:
+		return &ap_config->encap;
+
 	default:
 		return NULL;
 	}
@@ -452,6 +826,9 @@ action_data_size(enum rte_table_action_type action,
 	case RTE_TABLE_ACTION_TM:
 		return sizeof(struct tm_data);
 
+	case RTE_TABLE_ACTION_ENCAP:
+		return encap_data_size(&ap_config->encap);
+
 	default:
 		return 0;
 	}
@@ -530,6 +907,10 @@ rte_table_action_profile_action_register(struct rte_table_action_profile *profil
 		status = tm_cfg_check(action_config);
 		break;
 
+	case RTE_TABLE_ACTION_ENCAP:
+		status = encap_cfg_check(action_config);
+		break;
+
 	default:
 		status = 0;
 		break;
@@ -652,6 +1033,12 @@ rte_table_action_apply(struct rte_table_action *action,
 			action_params,
 			&action->cfg.tm);
 
+	case RTE_TABLE_ACTION_ENCAP:
+		return encap_apply(action_data,
+			action_params,
+			&action->cfg.encap,
+			&action->cfg.common);
+
 	default:
 		return -EINVAL;
 	}
@@ -869,6 +1256,18 @@ pkt_work(struct rte_mbuf *mbuf,
 			dscp);
 	}
 
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_ENCAP)) {
+		void *data =
+			action_data_get(table_entry, action, RTE_TABLE_ACTION_ENCAP);
+
+		pkt_work_encap(mbuf,
+			data,
+			&cfg->encap,
+			ip,
+			total_length,
+			ip_offset);
+	}
+
 	return drop_mask;
 }
 
@@ -1013,6 +1412,45 @@ pkt4_work(struct rte_mbuf **mbufs,
 			dscp3);
 	}
 
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_ENCAP)) {
+		void *data0 =
+			action_data_get(table_entry0, action, RTE_TABLE_ACTION_ENCAP);
+		void *data1 =
+			action_data_get(table_entry1, action, RTE_TABLE_ACTION_ENCAP);
+		void *data2 =
+			action_data_get(table_entry2, action, RTE_TABLE_ACTION_ENCAP);
+		void *data3 =
+			action_data_get(table_entry3, action, RTE_TABLE_ACTION_ENCAP);
+
+		pkt_work_encap(mbuf0,
+			data0,
+			&cfg->encap,
+			ip0,
+			total_length0,
+			ip_offset);
+
+		pkt_work_encap(mbuf1,
+			data1,
+			&cfg->encap,
+			ip1,
+			total_length1,
+			ip_offset);
+
+		pkt_work_encap(mbuf2,
+			data2,
+			&cfg->encap,
+			ip2,
+			total_length2,
+			ip_offset);
+
+		pkt_work_encap(mbuf3,
+			data3,
+			&cfg->encap,
+			ip3,
+			total_length3,
+			ip_offset);
+	}
+
 	return drop_mask0 |
 		(drop_mask1 << 1) |
 		(drop_mask2 << 2) |
diff --git a/lib/librte_pipeline/rte_table_action.h b/lib/librte_pipeline/rte_table_action.h
index 98babc5..c5c987d 100644
--- a/lib/librte_pipeline/rte_table_action.h
+++ b/lib/librte_pipeline/rte_table_action.h
@@ -59,6 +59,7 @@ extern "C" {
 #include <stdint.h>
 
 #include <rte_compat.h>
+#include <rte_ether.h>
 #include <rte_meter.h>
 
 #include "rte_pipeline.h"
@@ -73,6 +74,9 @@ enum rte_table_action_type {
 
 	/**  Traffic Management. */
 	RTE_TABLE_ACTION_TM,
+
+	/** Packet encapsulations. */
+	RTE_TABLE_ACTION_ENCAP,
 };
 
 /** Common action configuration (per table action profile). */
@@ -280,6 +284,131 @@ struct rte_table_action_tm_params {
 };
 
 /**
+ * RTE_TABLE_ACTION_ENCAP
+ */
+/** Supported packet encapsulation types. */
+enum rte_table_action_encap_type {
+	/** IP -> { Ether | IP } */
+	RTE_TABLE_ACTION_ENCAP_ETHER = 0,
+
+	/** IP -> { Ether | VLAN | IP } */
+	RTE_TABLE_ACTION_ENCAP_VLAN,
+
+	/** IP -> { Ether | S-VLAN | C-VLAN | IP } */
+	RTE_TABLE_ACTION_ENCAP_QINQ,
+
+	/** IP -> { Ether | MPLS | IP } */
+	RTE_TABLE_ACTION_ENCAP_MPLS,
+
+	/** IP -> { Ether | PPPoE | PPP | IP } */
+	RTE_TABLE_ACTION_ENCAP_PPPOE,
+};
+
+/** Pre-computed Ethernet header fields for encapsulation action. */
+struct rte_table_action_ether_hdr {
+	struct ether_addr da; /**< Destination address. */
+	struct ether_addr sa; /**< Source address. */
+};
+
+/** Pre-computed VLAN header fields for encapsulation action. */
+struct rte_table_action_vlan_hdr {
+	uint8_t pcp; /**< Priority Code Point (PCP). */
+	uint8_t dei; /**< Drop Eligibility Indicator (DEI). */
+	uint16_t vid; /**< VLAN Identifier (VID). */
+};
+
+/** Pre-computed MPLS header fields for encapsulation action. */
+struct rte_table_action_mpls_hdr {
+	uint32_t label; /**< Label. */
+	uint8_t tc; /**< Traffic Class (TC). */
+	uint8_t ttl; /**< Time to Live (TTL). */
+};
+
+/** Pre-computed PPPoE header fields for encapsulation action. */
+struct rte_table_action_pppoe_hdr {
+	uint16_t session_id; /**< Session ID. */
+};
+
+/** Ether encap parameters. */
+struct rte_table_action_encap_ether_params {
+	struct rte_table_action_ether_hdr ether; /**< Ethernet header. */
+};
+
+/** VLAN encap parameters. */
+struct rte_table_action_encap_vlan_params {
+	struct rte_table_action_ether_hdr ether; /**< Ethernet header. */
+	struct rte_table_action_vlan_hdr vlan; /**< VLAN header. */
+};
+
+/** QinQ encap parameters. */
+struct rte_table_action_encap_qinq_params {
+	struct rte_table_action_ether_hdr ether; /**< Ethernet header. */
+	struct rte_table_action_vlan_hdr svlan; /**< Service VLAN header. */
+	struct rte_table_action_vlan_hdr cvlan; /**< Customer VLAN header. */
+};
+
+/** Max number of MPLS labels per output packet for MPLS encapsulation. */
+#ifndef RTE_TABLE_ACTION_MPLS_LABELS_MAX
+#define RTE_TABLE_ACTION_MPLS_LABELS_MAX                   4
+#endif
+
+/** MPLS encap parameters. */
+struct rte_table_action_encap_mpls_params {
+	/** Ethernet header. */
+	struct rte_table_action_ether_hdr ether;
+
+	/** MPLS header. */
+	struct rte_table_action_mpls_hdr mpls[RTE_TABLE_ACTION_MPLS_LABELS_MAX];
+
+	/** Number of MPLS labels in MPLS header. */
+	uint32_t mpls_count;
+
+	/** Non-zero for MPLS unicast, zero for MPLS multicast. */
+	int unicast;
+};
+
+/** PPPoE encap parameters. */
+struct rte_table_action_encap_pppoe_params {
+	struct rte_table_action_ether_hdr ether; /**< Ethernet header. */
+	struct rte_table_action_pppoe_hdr pppoe; /**< PPPoE/PPP headers. */
+};
+
+/** Encap action configuration (per table action profile). */
+struct rte_table_action_encap_config {
+	/** Bit mask defining the set of packet encapsulations enabled for the
+	 * current table action profile. If bit (1 << N) is set in *encap_mask*,
+	 * then packet encapsulation N is enabled, otherwise it is disabled.
+	 *
+	 * @see enum rte_table_action_encap_type
+	 */
+	uint64_t encap_mask;
+};
+
+/** Encap action parameters (per table rule). */
+struct rte_table_action_encap_params {
+	/** Encapsulation type. */
+	enum rte_table_action_encap_type type;
+
+	RTE_STD_C11
+	union {
+		/** Only valid when *type* is set to Ether. */
+		struct rte_table_action_encap_ether_params ether;
+
+		/** Only valid when *type* is set to VLAN. */
+		struct rte_table_action_encap_vlan_params vlan;
+
+		/** Only valid when *type* is set to QinQ. */
+		struct rte_table_action_encap_qinq_params qinq;
+
+		/** Only valid when *type* is set to MPLS. */
+		struct rte_table_action_encap_mpls_params mpls;
+
+		/** Only valid when *type* is set to PPPoE. */
+		struct rte_table_action_encap_pppoe_params pppoe;
+	};
+};
+
+/**
  * Table action profile.
  */
 struct rte_table_action_profile;
-- 
2.9.3

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

* [dpdk-dev] [PATCH v2 06/44] pipeline: add nat action
  2018-03-12 17:25   ` [dpdk-dev] [PATCH v2 00/44] ip_pipeline: refactoring Jasvinder Singh
                       ` (4 preceding siblings ...)
  2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 05/44] pipeline: add packet encapsulation action Jasvinder Singh
@ 2018-03-12 17:25     ` Jasvinder Singh
  2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 07/44] pipeline: add ttl update action Jasvinder Singh
                       ` (37 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-12 17:25 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add implementation of Network Address Translation(NAT) action.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 lib/librte_pipeline/rte_table_action.c | 162 +++++++++++++++++++++++++++++++++
 lib/librte_pipeline/rte_table_action.h |  39 ++++++++
 2 files changed, 201 insertions(+)

diff --git a/lib/librte_pipeline/rte_table_action.c b/lib/librte_pipeline/rte_table_action.c
index cd8e7d1..ddffe18 100644
--- a/lib/librte_pipeline/rte_table_action.c
+++ b/lib/librte_pipeline/rte_table_action.c
@@ -733,6 +733,115 @@ pkt_work_encap(struct rte_mbuf *mbuf,
 }
 
 /**
+ * RTE_TABLE_ACTION_NAT
+ */
+static int
+nat_cfg_check(struct rte_table_action_nat_config *nat)
+{
+	if ((nat->proto != 0x06) &&
+		(nat->proto != 0x11))
+		return -ENOTSUP;
+
+	return 0;
+}
+
+struct nat_ipv4_data {
+	uint32_t addr;
+	uint16_t port;
+	uint16_t checksum;
+} __attribute__((__packed__));
+
+struct nat_ipv6_data {
+	uint8_t addr[16];
+	uint16_t port;
+	uint16_t checksum;
+} __attribute__((__packed__));
+
+static size_t
+nat_data_size(struct rte_table_action_nat_config *nat __rte_unused,
+	struct rte_table_action_common_config *common)
+{
+	int ip_version = common->ip_version;
+
+	return (ip_version) ?
+		sizeof(struct nat_ipv4_data) :
+		sizeof(struct nat_ipv6_data);
+}
+
+static int
+nat_apply_check(struct rte_table_action_nat_params *p,
+	struct rte_table_action_common_config *cfg)
+{
+	if ((p->ip_version && (cfg->ip_version == 0)) ||
+		((p->ip_version == 0) && cfg->ip_version))
+		return -EINVAL;
+
+	return 0;
+}
+
+static int
+nat_apply(void *data,
+	struct rte_table_action_nat_params *p,
+	struct rte_table_action_common_config *cfg)
+{
+	int status;
+
+	/* Check input arguments */
+	status = nat_apply_check(p, cfg);
+	if (status)
+		return status;
+
+	/* Apply */
+	if (p->ip_version) {
+		struct nat_ipv4_data *d = data;
+
+		d->addr = rte_htonl(p->addr.ipv4);
+		d->port = rte_htons(p->port);
+		d->checksum = 0;
+	} else {
+		struct nat_ipv6_data *d = data;
+
+		memcpy(d->addr, p->addr.ipv6, sizeof(d->addr));
+		d->port = rte_htons(p->port);
+		d->checksum = 0;
+	}
+
+	return 0;
+}
+
+static __rte_always_inline void
+pkt_ipv4_work_nat(struct ipv4_hdr *ip,
+	struct nat_ipv4_data *data,
+	struct rte_table_action_nat_config *cfg)
+{
+	struct tcp_hdr *tcp = (struct tcp_hdr *) &ip[1];
+
+	if (cfg->source_nat) {
+		ip->src_addr = data->addr;
+		tcp->src_port = data->port;
+	} else {
+		ip->dst_addr = data->addr;
+		tcp->dst_port = data->port;
+	}
+}
+
+static __rte_always_inline void
+pkt_ipv6_work_nat(struct ipv6_hdr *ip,
+	struct nat_ipv6_data *data,
+	struct rte_table_action_nat_config *cfg)
+{
+	struct tcp_hdr *tcp = (struct tcp_hdr *) &ip[1];
+
+	if (cfg->source_nat) {
+		rte_memcpy(ip->src_addr, data->addr, 16);
+		tcp->src_port = data->port;
+	} else {
+		rte_memcpy(ip->dst_addr, data->addr, 16);
+		tcp->dst_port = data->port;
+	}
+}
+
+/**
  * Action profile
  */
 static int
@@ -743,6 +852,7 @@ action_valid(enum rte_table_action_type action)
 	case RTE_TABLE_ACTION_MTR:
 	case RTE_TABLE_ACTION_TM:
 	case RTE_TABLE_ACTION_ENCAP:
+	case RTE_TABLE_ACTION_NAT:
 		return 1;
 	default:
 		return 0;
@@ -758,6 +868,7 @@ struct ap_config {
 	struct rte_table_action_mtr_config mtr;
 	struct rte_table_action_tm_config tm;
 	struct rte_table_action_encap_config encap;
+	struct rte_table_action_nat_config nat;
 };
 
 static size_t
@@ -770,6 +881,8 @@ action_cfg_size(enum rte_table_action_type action)
 		return sizeof(struct rte_table_action_tm_config);
 	case RTE_TABLE_ACTION_ENCAP:
 		return sizeof(struct rte_table_action_encap_config);
+	case RTE_TABLE_ACTION_NAT:
+		return sizeof(struct rte_table_action_nat_config);
 	default:
 		return 0;
 	}
@@ -789,6 +902,9 @@ action_cfg_get(struct ap_config *ap_config,
 	case RTE_TABLE_ACTION_ENCAP:
 		return &ap_config->encap;
 
+	case RTE_TABLE_ACTION_NAT:
+		return &ap_config->nat;
+
 	default:
 		return NULL;
 	}
@@ -829,6 +945,10 @@ action_data_size(enum rte_table_action_type action,
 	case RTE_TABLE_ACTION_ENCAP:
 		return encap_data_size(&ap_config->encap);
 
+	case RTE_TABLE_ACTION_NAT:
+		return nat_data_size(&ap_config->nat,
+			&ap_config->common);
+
 	default:
 		return 0;
 	}
@@ -911,6 +1031,10 @@ rte_table_action_profile_action_register(struct rte_table_action_profile *profil
 		status = encap_cfg_check(action_config);
 		break;
 
+	case RTE_TABLE_ACTION_NAT:
+		status = nat_cfg_check(action_config);
+		break;
+
 	default:
 		status = 0;
 		break;
@@ -1039,6 +1163,11 @@ rte_table_action_apply(struct rte_table_action *action,
 			&action->cfg.encap,
 			&action->cfg.common);
 
+	case RTE_TABLE_ACTION_NAT:
+		return nat_apply(action_data,
+			action_params,
+			&action->cfg.common);
+
 	default:
 		return -EINVAL;
 	}
@@ -1268,6 +1397,16 @@ pkt_work(struct rte_mbuf *mbuf,
 			ip_offset);
 	}
 
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_NAT)) {
+		void *data =
+			action_data_get(table_entry, action, RTE_TABLE_ACTION_NAT);
+
+		if (cfg->common.ip_version)
+			pkt_ipv4_work_nat(ip, data, &cfg->nat);
+		else
+			pkt_ipv6_work_nat(ip, data, &cfg->nat);
+	}
+
 	return drop_mask;
 }
 
@@ -1451,6 +1590,29 @@ pkt4_work(struct rte_mbuf **mbufs,
 			ip_offset);
 	}
 
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_NAT)) {
+		void *data0 =
+			action_data_get(table_entry0, action, RTE_TABLE_ACTION_NAT);
+		void *data1 =
+			action_data_get(table_entry1, action, RTE_TABLE_ACTION_NAT);
+		void *data2 =
+			action_data_get(table_entry2, action, RTE_TABLE_ACTION_NAT);
+		void *data3 =
+			action_data_get(table_entry3, action, RTE_TABLE_ACTION_NAT);
+
+		if (cfg->common.ip_version) {
+			pkt_ipv4_work_nat(ip0, data0, &cfg->nat);
+			pkt_ipv4_work_nat(ip1, data1, &cfg->nat);
+			pkt_ipv4_work_nat(ip2, data2, &cfg->nat);
+			pkt_ipv4_work_nat(ip3, data3, &cfg->nat);
+		} else {
+			pkt_ipv6_work_nat(ip0, data0, &cfg->nat);
+			pkt_ipv6_work_nat(ip1, data1, &cfg->nat);
+			pkt_ipv6_work_nat(ip2, data2, &cfg->nat);
+			pkt_ipv6_work_nat(ip3, data3, &cfg->nat);
+		}
+	}
+
 	return drop_mask0 |
 		(drop_mask1 << 1) |
 		(drop_mask2 << 2) |
diff --git a/lib/librte_pipeline/rte_table_action.h b/lib/librte_pipeline/rte_table_action.h
index c5c987d..5204511 100644
--- a/lib/librte_pipeline/rte_table_action.h
+++ b/lib/librte_pipeline/rte_table_action.h
@@ -77,6 +77,9 @@ enum rte_table_action_type {
 
 	/** Packet encapsulations. */
 	RTE_TABLE_ACTION_ENCAP,
+
+	/** Network Address Translation (NAT). */
+	RTE_TABLE_ACTION_NAT,
 };
 
 /** Common action configuration (per table action profile). */
@@ -409,6 +412,42 @@ struct rte_table_action_encap_params {
 };
 
 /**
+ * RTE_TABLE_ACTION_NAT
+ */
+/** NAT action configuration (per table action profile). */
+struct rte_table_action_nat_config {
+	/** When non-zero, the IP source address and L4 protocol source port are
+	 * translated. When zero, the IP destination address and L4 protocol
+	 * destination port are translated.
+	 */
+	int source_nat;
+
+	/** Layer 4 protocol, for example TCP (0x06) or UDP (0x11). The checksum
+	 * field is computed differently and placed at different header offset
+	 * by each layer 4 protocol.
+	 */
+	uint8_t proto;
+};
+
+/** NAT action parameters (per table rule). */
+struct rte_table_action_nat_params {
+	/** IP version for *addr*: non-zero for IPv4, zero for IPv6. */
+	int ip_version;
+
+	/** IP address. */
+	union {
+		/** IPv4 address; only valid when *ip_version* is non-zero. */
+		uint32_t ipv4;
+
+		/** IPv6 address; only valid when *ip_version* is set to 0. */
+		uint8_t ipv6[16];
+	} addr;
+
+	/** Port. */
+	uint16_t port;
+};
+
+/**
  * Table action profile.
  */
 struct rte_table_action_profile;
-- 
2.9.3

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

* [dpdk-dev] [PATCH v2 07/44] pipeline: add ttl update action
  2018-03-12 17:25   ` [dpdk-dev] [PATCH v2 00/44] ip_pipeline: refactoring Jasvinder Singh
                       ` (5 preceding siblings ...)
  2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 06/44] pipeline: add nat action Jasvinder Singh
@ 2018-03-12 17:25     ` Jasvinder Singh
  2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 08/44] pipeline: add statistics read action Jasvinder Singh
                       ` (36 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-12 17:25 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add implementation of ttl update action.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 lib/librte_pipeline/rte_pipeline_version.map |   1 +
 lib/librte_pipeline/rte_table_action.c       | 155 +++++++++++++++++++++++++++
 lib/librte_pipeline/rte_table_action.h       |  66 ++++++++++++
 3 files changed, 222 insertions(+)

diff --git a/lib/librte_pipeline/rte_pipeline_version.map b/lib/librte_pipeline/rte_pipeline_version.map
index c7106dc..9388585 100644
--- a/lib/librte_pipeline/rte_pipeline_version.map
+++ b/lib/librte_pipeline/rte_pipeline_version.map
@@ -61,5 +61,6 @@ EXPERIMENTAL {
 	rte_table_action_profile_free;
 	rte_table_action_profile_freeze;
 	rte_table_action_table_params_get;
+	rte_table_action_ttl_read;
 
 } DPDK_16.04;
diff --git a/lib/librte_pipeline/rte_table_action.c b/lib/librte_pipeline/rte_table_action.c
index ddffe18..f26bec3 100644
--- a/lib/librte_pipeline/rte_table_action.c
+++ b/lib/librte_pipeline/rte_table_action.c
@@ -842,6 +842,82 @@ pkt_ipv6_work_nat(struct ipv6_hdr *ip,
 }
 
 /**
+ * RTE_TABLE_ACTION_TTL
+ */
+static int
+ttl_cfg_check(struct rte_table_action_ttl_config *ttl)
+{
+	if (ttl->drop == 0)
+		return -ENOTSUP;
+
+	return 0;
+}
+
+struct ttl_data {
+	uint32_t n_packets;
+} __attribute__((__packed__));
+
+#define TTL_INIT(data, decrement)                         \
+	((data)->n_packets = (decrement) ? 1 : 0)
+
+#define TTL_DEC_GET(data)                                  \
+	((uint8_t)((data)->n_packets & 1))
+
+#define TTL_STATS_RESET(data)                             \
+	((data)->n_packets = ((data)->n_packets & 1))
+
+#define TTL_STATS_READ(data)                               \
+	((data)->n_packets >> 1)
+
+#define TTL_STATS_ADD(data, value)                        \
+	((data)->n_packets =                                  \
+		(((((data)->n_packets >> 1) + (value)) << 1) |    \
+		((data)->n_packets & 1)))
+
+static int
+ttl_apply(void *data,
+	struct rte_table_action_ttl_params *p)
+{
+	struct ttl_data *d = data;
+
+	TTL_INIT(d, p->decrement);
+
+	return 0;
+}
+
+static __rte_always_inline uint64_t
+pkt_ipv4_work_ttl(struct ipv4_hdr *ip,
+	struct ttl_data *data)
+{
+	uint32_t drop;
+	uint8_t ttl = ip->time_to_live;
+
+	ttl -= TTL_DEC_GET(data);
+	ip->time_to_live = ttl;
+
+	drop = (ttl == 0) ? 1 : 0;
+	TTL_STATS_ADD(data, drop);
+
+	return drop;
+}
+
+static __rte_always_inline uint64_t
+pkt_ipv6_work_ttl(struct ipv6_hdr *ip,
+	struct ttl_data *data)
+{
+	uint32_t drop;
+	uint8_t ttl = ip->hop_limits;
+
+	ttl -= TTL_DEC_GET(data);
+	ip->hop_limits = ttl;
+
+	drop = (ttl == 0) ? 1 : 0;
+	TTL_STATS_ADD(data, drop);
+
+	return drop;
+}
+
+/**
  * Action profile
  */
 static int
@@ -853,6 +929,7 @@ action_valid(enum rte_table_action_type action)
 	case RTE_TABLE_ACTION_TM:
 	case RTE_TABLE_ACTION_ENCAP:
 	case RTE_TABLE_ACTION_NAT:
+	case RTE_TABLE_ACTION_TTL:
 		return 1;
 	default:
 		return 0;
@@ -869,6 +946,7 @@ struct ap_config {
 	struct rte_table_action_tm_config tm;
 	struct rte_table_action_encap_config encap;
 	struct rte_table_action_nat_config nat;
+	struct rte_table_action_ttl_config ttl;
 };
 
 static size_t
@@ -883,6 +961,8 @@ action_cfg_size(enum rte_table_action_type action)
 		return sizeof(struct rte_table_action_encap_config);
 	case RTE_TABLE_ACTION_NAT:
 		return sizeof(struct rte_table_action_nat_config);
+	case RTE_TABLE_ACTION_TTL:
+		return sizeof(struct rte_table_action_ttl_config);
 	default:
 		return 0;
 	}
@@ -905,6 +985,9 @@ action_cfg_get(struct ap_config *ap_config,
 	case RTE_TABLE_ACTION_NAT:
 		return &ap_config->nat;
 
+	case RTE_TABLE_ACTION_TTL:
+		return &ap_config->ttl;
+
 	default:
 		return NULL;
 	}
@@ -949,6 +1032,9 @@ action_data_size(enum rte_table_action_type action,
 		return nat_data_size(&ap_config->nat,
 			&ap_config->common);
 
+	case RTE_TABLE_ACTION_TTL:
+		return sizeof(struct ttl_data);
+
 	default:
 		return 0;
 	}
@@ -1035,6 +1121,10 @@ rte_table_action_profile_action_register(struct rte_table_action_profile *profil
 		status = nat_cfg_check(action_config);
 		break;
 
+	case RTE_TABLE_ACTION_TTL:
+		status = ttl_cfg_check(action_config);
+		break;
+
 	default:
 		status = 0;
 		break;
@@ -1168,6 +1258,10 @@ rte_table_action_apply(struct rte_table_action *action,
 			action_params,
 			&action->cfg.common);
 
+	case RTE_TABLE_ACTION_TTL:
+		return ttl_apply(action_data,
+			action_params);
+
 	default:
 		return -EINVAL;
 	}
@@ -1334,6 +1428,34 @@ rte_table_action_meter_read(struct rte_table_action *action,
 	return 0;
 }
 
+int
+rte_table_action_ttl_read(struct rte_table_action *action,
+	void *data,
+	struct rte_table_action_ttl_counters *stats,
+	int clear)
+{
+	struct ttl_data *ttl_data;
+
+	/* Check input arguments */
+	if ((action == NULL) ||
+		((action->cfg.action_mask &
+		(1LLU << RTE_TABLE_ACTION_TTL)) == 0) ||
+		(data == NULL))
+		return -EINVAL;
+
+	ttl_data = action_data_get(data, action, RTE_TABLE_ACTION_TTL);
+
+	/* Read */
+	if (stats)
+		stats->n_packets = TTL_STATS_READ(ttl_data);
+
+	/* Clear */
+	if (clear)
+		TTL_STATS_RESET(ttl_data);
+
+	return 0;
+}
+
 static __rte_always_inline uint64_t
 pkt_work(struct rte_mbuf *mbuf,
 	struct rte_pipeline_table_entry *table_entry,
@@ -1407,6 +1529,16 @@ pkt_work(struct rte_mbuf *mbuf,
 			pkt_ipv6_work_nat(ip, data, &cfg->nat);
 	}
 
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_TTL)) {
+		void *data =
+			action_data_get(table_entry, action, RTE_TABLE_ACTION_TTL);
+
+		if (cfg->common.ip_version)
+			drop_mask |= pkt_ipv4_work_ttl(ip, data);
+		else
+			drop_mask |= pkt_ipv6_work_ttl(ip, data);
+	}
+
 	return drop_mask;
 }
 
@@ -1613,6 +1745,29 @@ pkt4_work(struct rte_mbuf **mbufs,
 		}
 	}
 
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_TTL)) {
+		void *data0 =
+				action_data_get(table_entry0, action, RTE_TABLE_ACTION_TTL);
+		void *data1 =
+				action_data_get(table_entry1, action, RTE_TABLE_ACTION_TTL);
+		void *data2 =
+				action_data_get(table_entry2, action, RTE_TABLE_ACTION_TTL);
+		void *data3 =
+				action_data_get(table_entry3, action, RTE_TABLE_ACTION_TTL);
+
+		if (cfg->common.ip_version) {
+			drop_mask0 |= pkt_ipv4_work_ttl(ip0, data0);
+			drop_mask1 |= pkt_ipv4_work_ttl(ip1, data1);
+			drop_mask2 |= pkt_ipv4_work_ttl(ip2, data2);
+			drop_mask3 |= pkt_ipv4_work_ttl(ip3, data3);
+		} else {
+			drop_mask0 |= pkt_ipv6_work_ttl(ip0, data0);
+			drop_mask1 |= pkt_ipv6_work_ttl(ip1, data1);
+			drop_mask2 |= pkt_ipv6_work_ttl(ip2, data2);
+			drop_mask3 |= pkt_ipv6_work_ttl(ip3, data3);
+		}
+	}
+
 	return drop_mask0 |
 		(drop_mask1 << 1) |
 		(drop_mask2 << 2) |
diff --git a/lib/librte_pipeline/rte_table_action.h b/lib/librte_pipeline/rte_table_action.h
index 5204511..57ac4f9 100644
--- a/lib/librte_pipeline/rte_table_action.h
+++ b/lib/librte_pipeline/rte_table_action.h
@@ -80,6 +80,9 @@ enum rte_table_action_type {
 
 	/** Network Address Translation (NAT). */
 	RTE_TABLE_ACTION_NAT,
+
+	/** Time to Live (TTL) update. */
+	RTE_TABLE_ACTION_TTL,
 };
 
 /** Common action configuration (per table action profile). */
@@ -448,6 +451,44 @@ struct rte_table_action_nat_params {
 };
 
 /**
+ * RTE_TABLE_ACTION_TTL
+ */
+/** TTL action configuration (per table action profile). */
+struct rte_table_action_ttl_config {
+	/** When non-zero, the input packets whose updated IPv4 Time to Live
+	 * (TTL) field or IPv6 Hop Limit (HL) field is zero are dropped.
+	 * When zero, the input packets whose updated IPv4 TTL field or IPv6 HL
+	 * field is zero are forwarded as usual (typically for debugging
+	 * purpose).
+	 */
+	int drop;
+
+	/** When non-zero, the *n_packets* stats counter for TTL action is
+	 * enabled, otherwise disabled.
+	 *
+	 * @see struct rte_table_action_ttl_counters
+	 */
+	int n_packets_enabled;
+};
+
+/** TTL action parameters (per table rule). */
+struct rte_table_action_ttl_params {
+	/** When non-zero, decrement the IPv4 TTL field and update the checksum
+	 * field, or decrement the IPv6 HL field. When zero, the IPv4 TTL field
+	 * or the IPv6 HL field is not changed.
+	 */
+	int decrement;
+};
+
+/** TTL action statistics packets (per table rule). */
+struct rte_table_action_ttl_counters {
+	/** Number of IPv4 packets whose updated TTL field is zero or IPv6
+	 * packets whose updated HL field is zero.
+	 */
+	uint64_t n_packets;
+};
+
+/**
  * Table action profile.
  */
 struct rte_table_action_profile;
@@ -671,6 +712,31 @@ rte_table_action_meter_read(struct rte_table_action *action,
 	struct rte_table_action_mtr_counters *stats,
 	int clear);
 
+/**
+ * Table action TTL read.
+ *
+ * @param[in] action
+ *   Handle to table action object (needs to be valid).
+ * @param[in] data
+ *   Data byte array (typically table rule data) with TTL action previously
+ *   applied on it.
+ * @param[inout] stats
+ *   When non-NULL, it points to the area where the TTL stats counters read from
+ *   *data* are saved.
+ * @param[in] clear
+ *   When non-zero, the TTL stats counters are cleared (i.e. set to zero),
+ *   otherwise the counters are not modified. When the read operation is enabled
+ *   (*stats* is non-NULL), the clear operation is performed after the read
+ *   operation is completed.
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_table_action_ttl_read(struct rte_table_action *action,
+	void *data,
+	struct rte_table_action_ttl_counters *stats,
+	int clear);
+
 #ifdef __cplusplus
 }
 #endif
-- 
2.9.3

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

* [dpdk-dev] [PATCH v2 08/44] pipeline: add statistics read action
  2018-03-12 17:25   ` [dpdk-dev] [PATCH v2 00/44] ip_pipeline: refactoring Jasvinder Singh
                       ` (6 preceding siblings ...)
  2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 07/44] pipeline: add ttl update action Jasvinder Singh
@ 2018-03-12 17:25     ` Jasvinder Singh
  2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 09/44] pipeline: add timestamp action Jasvinder Singh
                       ` (35 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-12 17:25 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add implementation of stats read action

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 lib/librte_pipeline/rte_pipeline_version.map |   1 +
 lib/librte_pipeline/rte_table_action.c       | 112 ++++++++++++++++++++++++++-
 lib/librte_pipeline/rte_table_action.h       |  78 +++++++++++++++++++
 3 files changed, 190 insertions(+), 1 deletion(-)

diff --git a/lib/librte_pipeline/rte_pipeline_version.map b/lib/librte_pipeline/rte_pipeline_version.map
index 9388585..8241efc 100644
--- a/lib/librte_pipeline/rte_pipeline_version.map
+++ b/lib/librte_pipeline/rte_pipeline_version.map
@@ -61,6 +61,7 @@ EXPERIMENTAL {
 	rte_table_action_profile_free;
 	rte_table_action_profile_freeze;
 	rte_table_action_table_params_get;
+	rte_table_action_stats_read;
 	rte_table_action_ttl_read;
 
 } DPDK_16.04;
diff --git a/lib/librte_pipeline/rte_table_action.c b/lib/librte_pipeline/rte_table_action.c
index f26bec3..c0e2ebb 100644
--- a/lib/librte_pipeline/rte_table_action.c
+++ b/lib/librte_pipeline/rte_table_action.c
@@ -918,6 +918,41 @@ pkt_ipv6_work_ttl(struct ipv6_hdr *ip,
 }
 
 /**
+ * RTE_TABLE_ACTION_STATS
+ */
+static int
+stats_cfg_check(struct rte_table_action_stats_config *stats)
+{
+	if ((stats->n_packets_enabled == 0) && (stats->n_bytes_enabled == 0))
+		return -EINVAL;
+
+	return 0;
+}
+
+struct stats_data {
+	uint64_t n_packets;
+	uint64_t n_bytes;
+} __attribute__((__packed__));
+
+static int
+stats_apply(struct stats_data *data,
+	struct rte_table_action_stats_params *p)
+{
+	data->n_packets = p->n_packets;
+	data->n_bytes = p->n_bytes;
+
+	return 0;
+}
+
+static __rte_always_inline void
+pkt_work_stats(struct stats_data *data,
+	uint16_t total_length)
+{
+	data->n_packets++;
+	data->n_bytes += total_length;
+}
+
+/**
  * Action profile
  */
 static int
@@ -930,13 +965,13 @@ action_valid(enum rte_table_action_type action)
 	case RTE_TABLE_ACTION_ENCAP:
 	case RTE_TABLE_ACTION_NAT:
 	case RTE_TABLE_ACTION_TTL:
+	case RTE_TABLE_ACTION_STATS:
 		return 1;
 	default:
 		return 0;
 	}
 }
 
-
 #define RTE_TABLE_ACTION_MAX                                   64
 
 struct ap_config {
@@ -947,6 +982,7 @@ struct ap_config {
 	struct rte_table_action_encap_config encap;
 	struct rte_table_action_nat_config nat;
 	struct rte_table_action_ttl_config ttl;
+	struct rte_table_action_stats_config stats;
 };
 
 static size_t
@@ -963,6 +999,8 @@ action_cfg_size(enum rte_table_action_type action)
 		return sizeof(struct rte_table_action_nat_config);
 	case RTE_TABLE_ACTION_TTL:
 		return sizeof(struct rte_table_action_ttl_config);
+	case RTE_TABLE_ACTION_STATS:
+		return sizeof(struct rte_table_action_stats_config);
 	default:
 		return 0;
 	}
@@ -988,6 +1026,9 @@ action_cfg_get(struct ap_config *ap_config,
 	case RTE_TABLE_ACTION_TTL:
 		return &ap_config->ttl;
 
+	case RTE_TABLE_ACTION_STATS:
+		return &ap_config->stats;
+
 	default:
 		return NULL;
 	}
@@ -1035,6 +1076,9 @@ action_data_size(enum rte_table_action_type action,
 	case RTE_TABLE_ACTION_TTL:
 		return sizeof(struct ttl_data);
 
+	case RTE_TABLE_ACTION_STATS:
+		return sizeof(struct stats_data);
+
 	default:
 		return 0;
 	}
@@ -1125,6 +1169,10 @@ rte_table_action_profile_action_register(struct rte_table_action_profile *profil
 		status = ttl_cfg_check(action_config);
 		break;
 
+	case RTE_TABLE_ACTION_STATS:
+		status = stats_cfg_check(action_config);
+		break;
+
 	default:
 		status = 0;
 		break;
@@ -1262,6 +1310,10 @@ rte_table_action_apply(struct rte_table_action *action,
 		return ttl_apply(action_data,
 			action_params);
 
+	case RTE_TABLE_ACTION_STATS:
+		return stats_apply(action_data,
+			action_params);
+
 	default:
 		return -EINVAL;
 	}
@@ -1456,6 +1508,41 @@ rte_table_action_ttl_read(struct rte_table_action *action,
 	return 0;
 }
 
+int
+rte_table_action_stats_read(struct rte_table_action *action,
+	void *data,
+	struct rte_table_action_stats_counters *stats,
+	int clear)
+{
+	struct stats_data *stats_data;
+
+	/* Check input arguments */
+	if ((action == NULL) ||
+		((action->cfg.action_mask &
+		(1LLU << RTE_TABLE_ACTION_STATS)) == 0) ||
+		(data == NULL))
+		return -EINVAL;
+
+	stats_data = action_data_get(data, action,
+		RTE_TABLE_ACTION_STATS);
+
+	/* Read */
+	if (stats) {
+		stats->n_packets = stats_data->n_packets;
+		stats->n_bytes = stats_data->n_bytes;
+		stats->n_packets_valid = 1;
+		stats->n_bytes_valid = 1;
+	}
+
+	/* Clear */
+	if (clear) {
+		stats_data->n_packets = 0;
+		stats_data->n_bytes = 0;
+	}
+
+	return 0;
+}
+
 static __rte_always_inline uint64_t
 pkt_work(struct rte_mbuf *mbuf,
 	struct rte_pipeline_table_entry *table_entry,
@@ -1539,6 +1626,13 @@ pkt_work(struct rte_mbuf *mbuf,
 			drop_mask |= pkt_ipv6_work_ttl(ip, data);
 	}
 
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_STATS)) {
+		void *data =
+			action_data_get(table_entry, action, RTE_TABLE_ACTION_STATS);
+
+		pkt_work_stats(data, total_length);
+	}
+
 	return drop_mask;
 }
 
@@ -1768,6 +1862,22 @@ pkt4_work(struct rte_mbuf **mbufs,
 		}
 	}
 
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_STATS)) {
+		void *data0 =
+			action_data_get(table_entry0, action, RTE_TABLE_ACTION_STATS);
+		void *data1 =
+			action_data_get(table_entry1, action, RTE_TABLE_ACTION_STATS);
+		void *data2 =
+			action_data_get(table_entry2, action, RTE_TABLE_ACTION_STATS);
+		void *data3 =
+			action_data_get(table_entry3, action, RTE_TABLE_ACTION_STATS);
+
+		pkt_work_stats(data0, total_length0);
+		pkt_work_stats(data1, total_length1);
+		pkt_work_stats(data2, total_length2);
+		pkt_work_stats(data3, total_length3);
+	}
+
 	return drop_mask0 |
 		(drop_mask1 << 1) |
 		(drop_mask2 << 2) |
diff --git a/lib/librte_pipeline/rte_table_action.h b/lib/librte_pipeline/rte_table_action.h
index 57ac4f9..53b9866 100644
--- a/lib/librte_pipeline/rte_table_action.h
+++ b/lib/librte_pipeline/rte_table_action.h
@@ -83,6 +83,9 @@ enum rte_table_action_type {
 
 	/** Time to Live (TTL) update. */
 	RTE_TABLE_ACTION_TTL,
+
+	/** Statistics. */
+	RTE_TABLE_ACTION_STATS,
 };
 
 /** Common action configuration (per table action profile). */
@@ -489,6 +492,56 @@ struct rte_table_action_ttl_counters {
 };
 
 /**
+ * RTE_TABLE_ACTION_STATS
+ */
+/** Stats action configuration (per table action profile). */
+struct rte_table_action_stats_config {
+	/** When non-zero, the *n_packets* stats counter is enabled, otherwise
+	 * disabled.
+	 *
+	 * @see struct rte_table_action_stats_counters
+	 */
+	int n_packets_enabled;
+
+	/** When non-zero, the *n_bytes* stats counter is enabled, otherwise
+	 * disabled.
+	 *
+	 * @see struct rte_table_action_stats_counters
+	 */
+	int n_bytes_enabled;
+};
+
+/** Stats action parameters (per table rule). */
+struct rte_table_action_stats_params {
+	/** Initial value for the *n_packets* stats counter. Typically set to 0.
+	 *
+	 * @see struct rte_table_action_stats_counters
+	 */
+	uint64_t n_packets;
+
+	/** Initial value for the *n_bytes* stats counter. Typically set to 0.
+	 *
+	 * @see struct rte_table_action_stats_counters
+	 */
+	uint64_t n_bytes;
+};
+
+/** Stats action counters (per table rule). */
+struct rte_table_action_stats_counters {
+	/** Number of packets. Valid only when *n_packets_valid* is non-zero. */
+	uint64_t n_packets;
+
+	/** Number of bytes. Valid only when *n_bytes_valid* is non-zero. */
+	uint64_t n_bytes;
+
+	/** When non-zero, the *n_packets* field is valid, otherwise invalid. */
+	int n_packets_valid;
+
+	/** When non-zero, the *n_bytes* field is valid, otherwise invalid. */
+	int n_bytes_valid;
+};
+
+/**
  * Table action profile.
  */
 struct rte_table_action_profile;
@@ -737,6 +790,31 @@ rte_table_action_ttl_read(struct rte_table_action *action,
 	struct rte_table_action_ttl_counters *stats,
 	int clear);
 
+/**
+ * Table action stats read.
+ *
+ * @param[in] action
+ *   Handle to table action object (needs to be valid).
+ * @param[in] data
+ *   Data byte array (typically table rule data) with stats action previously
+ *   applied on it.
+ * @param[inout] stats
+ *   When non-NULL, it points to the area where the stats counters read from
+ *   *data* are saved.
+ * @param[in] clear
+ *   When non-zero, the stats counters are cleared (i.e. set to zero), otherwise
+ *   the counters are not modified. When the read operation is enabled (*stats*
+ *   is non-NULL), the clear operation is performed after the read operation is
+ *   completed.
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_table_action_stats_read(struct rte_table_action *action,
+	void *data,
+	struct rte_table_action_stats_counters *stats,
+	int clear);
+
 #ifdef __cplusplus
 }
 #endif
-- 
2.9.3

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

* [dpdk-dev] [PATCH v2 09/44] pipeline: add timestamp action
  2018-03-12 17:25   ` [dpdk-dev] [PATCH v2 00/44] ip_pipeline: refactoring Jasvinder Singh
                       ` (7 preceding siblings ...)
  2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 08/44] pipeline: add statistics read action Jasvinder Singh
@ 2018-03-12 17:25     ` Jasvinder Singh
  2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 10/44] ip_pipeline: remove passthrough pipeline Jasvinder Singh
                       ` (34 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-12 17:25 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add implementation of timestamp action.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 lib/librte_pipeline/rte_pipeline_version.map |  1 +
 lib/librte_pipeline/rte_table_action.c       | 79 +++++++++++++++++++++++++++-
 lib/librte_pipeline/rte_table_action.h       | 31 +++++++++++
 3 files changed, 110 insertions(+), 1 deletion(-)

diff --git a/lib/librte_pipeline/rte_pipeline_version.map b/lib/librte_pipeline/rte_pipeline_version.map
index 8241efc..4e948b8 100644
--- a/lib/librte_pipeline/rte_pipeline_version.map
+++ b/lib/librte_pipeline/rte_pipeline_version.map
@@ -62,6 +62,7 @@ EXPERIMENTAL {
 	rte_table_action_profile_freeze;
 	rte_table_action_table_params_get;
 	rte_table_action_stats_read;
+	rte_table_action_time_read;
 	rte_table_action_ttl_read;
 
 } DPDK_16.04;
diff --git a/lib/librte_pipeline/rte_table_action.c b/lib/librte_pipeline/rte_table_action.c
index c0e2ebb..12be4ab 100644
--- a/lib/librte_pipeline/rte_table_action.c
+++ b/lib/librte_pipeline/rte_table_action.c
@@ -953,6 +953,28 @@ pkt_work_stats(struct stats_data *data,
 }
 
 /**
+ * RTE_TABLE_ACTION_TIME
+ */
+struct time_data {
+	uint64_t time;
+} __attribute__((__packed__));
+
+static int
+time_apply(struct time_data *data,
+	struct rte_table_action_time_params *p)
+{
+	data->time = p->time;
+	return 0;
+}
+
+static __rte_always_inline void
+pkt_work_time(struct time_data *data,
+	uint64_t time)
+{
+	data->time = time;
+}
+
+/**
  * Action profile
  */
 static int
@@ -966,6 +988,7 @@ action_valid(enum rte_table_action_type action)
 	case RTE_TABLE_ACTION_NAT:
 	case RTE_TABLE_ACTION_TTL:
 	case RTE_TABLE_ACTION_STATS:
+	case RTE_TABLE_ACTION_TIME:
 		return 1;
 	default:
 		return 0;
@@ -1079,6 +1102,9 @@ action_data_size(enum rte_table_action_type action,
 	case RTE_TABLE_ACTION_STATS:
 		return sizeof(struct stats_data);
 
+	case RTE_TABLE_ACTION_TIME:
+		return sizeof(struct time_data);
+
 	default:
 		return 0;
 	}
@@ -1314,6 +1340,10 @@ rte_table_action_apply(struct rte_table_action *action,
 		return stats_apply(action_data,
 			action_params);
 
+	case RTE_TABLE_ACTION_TIME:
+		return time_apply(action_data,
+			action_params);
+
 	default:
 		return -EINVAL;
 	}
@@ -1543,6 +1573,29 @@ rte_table_action_stats_read(struct rte_table_action *action,
 	return 0;
 }
 
+int
+rte_table_action_time_read(struct rte_table_action *action,
+	void *data,
+	uint64_t *timestamp)
+{
+	struct time_data *time_data;
+
+	/* Check input arguments */
+	if ((action == NULL) ||
+		((action->cfg.action_mask &
+		(1LLU << RTE_TABLE_ACTION_TIME)) == 0) ||
+		(data == NULL) ||
+		(timestamp == NULL))
+		return -EINVAL;
+
+	time_data = action_data_get(data, action, RTE_TABLE_ACTION_TIME);
+
+	/* Read */
+	*timestamp = time_data->time;
+
+	return 0;
+}
+
 static __rte_always_inline uint64_t
 pkt_work(struct rte_mbuf *mbuf,
 	struct rte_pipeline_table_entry *table_entry,
@@ -1633,6 +1686,13 @@ pkt_work(struct rte_mbuf *mbuf,
 		pkt_work_stats(data, total_length);
 	}
 
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_TIME)) {
+		void *data =
+			action_data_get(table_entry, action, RTE_TABLE_ACTION_TIME);
+
+		pkt_work_time(data, time);
+	}
+
 	return drop_mask;
 }
 
@@ -1878,6 +1938,22 @@ pkt4_work(struct rte_mbuf **mbufs,
 		pkt_work_stats(data3, total_length3);
 	}
 
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_TIME)) {
+		void *data0 =
+			action_data_get(table_entry0, action, RTE_TABLE_ACTION_TIME);
+		void *data1 =
+			action_data_get(table_entry1, action, RTE_TABLE_ACTION_TIME);
+		void *data2 =
+			action_data_get(table_entry2, action, RTE_TABLE_ACTION_TIME);
+		void *data3 =
+			action_data_get(table_entry3, action, RTE_TABLE_ACTION_TIME);
+
+		pkt_work_time(data0, time);
+		pkt_work_time(data1, time);
+		pkt_work_time(data2, time);
+		pkt_work_time(data3, time);
+	}
+
 	return drop_mask0 |
 		(drop_mask1 << 1) |
 		(drop_mask2 << 2) |
@@ -1895,7 +1971,8 @@ ah(struct rte_pipeline *p,
 	uint64_t pkts_drop_mask = 0;
 	uint64_t time = 0;
 
-	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_MTR))
+	if (cfg->action_mask & ((1LLU << RTE_TABLE_ACTION_MTR) |
+		(1LLU << RTE_TABLE_ACTION_TIME)))
 		time = rte_rdtsc();
 
 	if ((pkts_mask & (pkts_mask + 1)) == 0) {
diff --git a/lib/librte_pipeline/rte_table_action.h b/lib/librte_pipeline/rte_table_action.h
index 53b9866..e9b30ab 100644
--- a/lib/librte_pipeline/rte_table_action.h
+++ b/lib/librte_pipeline/rte_table_action.h
@@ -86,6 +86,9 @@ enum rte_table_action_type {
 
 	/** Statistics. */
 	RTE_TABLE_ACTION_STATS,
+
+	/** Timestamp. */
+	RTE_TABLE_ACTION_TIME,
 };
 
 /** Common action configuration (per table action profile). */
@@ -542,6 +545,15 @@ struct rte_table_action_stats_counters {
 };
 
 /**
+ * RTE_TABLE_ACTION_TIME
+ */
+/** Timestamp action parameters (per table rule). */
+struct rte_table_action_time_params {
+	/** Initial timestamp value. Typically set to current time. */
+	uint64_t time;
+};
+
+/**
  * Table action profile.
  */
 struct rte_table_action_profile;
@@ -815,6 +827,25 @@ rte_table_action_stats_read(struct rte_table_action *action,
 	struct rte_table_action_stats_counters *stats,
 	int clear);
 
+/**
+ * Table action timestamp read.
+ *
+ * @param[in] action
+ *   Handle to table action object (needs to be valid).
+ * @param[in] data
+ *   Data byte array (typically table rule data) with timestamp action
+ *   previously applied on it.
+ * @param[inout] timestamp
+ *   Pre-allocated memory where the timestamp read from *data* is saved (has to
+ *   be non-NULL).
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_table_action_time_read(struct rte_table_action *action,
+	void *data,
+	uint64_t *timestamp);
+
 #ifdef __cplusplus
 }
 #endif
-- 
2.9.3

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

* [dpdk-dev] [PATCH v2 10/44] ip_pipeline: remove passthrough pipeline
  2018-03-12 17:25   ` [dpdk-dev] [PATCH v2 00/44] ip_pipeline: refactoring Jasvinder Singh
                       ` (8 preceding siblings ...)
  2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 09/44] pipeline: add timestamp action Jasvinder Singh
@ 2018-03-12 17:25     ` Jasvinder Singh
  2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 11/44] ip_pipeline: remove routing pipeline Jasvinder Singh
                       ` (33 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-12 17:25 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

remove passthrough pipeline.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/Makefile                      |   2 -
 examples/ip_pipeline/init.c                        |   2 -
 examples/ip_pipeline/meson.build                   |   2 -
 .../ip_pipeline/pipeline/pipeline_passthrough.c    |  45 -
 .../ip_pipeline/pipeline/pipeline_passthrough.h    |  12 -
 .../ip_pipeline/pipeline/pipeline_passthrough_be.c | 929 ---------------------
 .../ip_pipeline/pipeline/pipeline_passthrough_be.h |  44 -
 7 files changed, 1036 deletions(-)
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_passthrough.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_passthrough.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_passthrough_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_passthrough_be.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index 85fbbaf..089c269 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -19,8 +19,6 @@ SRCS-y += pipeline_common_be.c
 SRCS-y += pipeline_common_fe.c
 SRCS-y += pipeline_master_be.c
 SRCS-y += pipeline_master.c
-SRCS-y += pipeline_passthrough_be.c
-SRCS-y += pipeline_passthrough.c
 SRCS-y += pipeline_firewall_be.c
 SRCS-y += pipeline_firewall.c
 SRCS-y += pipeline_flow_classification_be.c
diff --git a/examples/ip_pipeline/init.c b/examples/ip_pipeline/init.c
index bb07efa..73b93d7 100644
--- a/examples/ip_pipeline/init.c
+++ b/examples/ip_pipeline/init.c
@@ -26,7 +26,6 @@
 #include "pipeline.h"
 #include "pipeline_common_fe.h"
 #include "pipeline_master.h"
-#include "pipeline_passthrough.h"
 #include "pipeline_firewall.h"
 #include "pipeline_flow_classification.h"
 #include "pipeline_flow_actions.h"
@@ -1822,7 +1821,6 @@ int app_init(struct app_params *app)
 	app_pipeline_common_cmd_push(app);
 	app_pipeline_thread_cmd_push(app);
 	app_pipeline_type_register(app, &pipeline_master);
-	app_pipeline_type_register(app, &pipeline_passthrough);
 	app_pipeline_type_register(app, &pipeline_flow_classification);
 	app_pipeline_type_register(app, &pipeline_flow_actions);
 	app_pipeline_type_register(app, &pipeline_firewall);
diff --git a/examples/ip_pipeline/meson.build b/examples/ip_pipeline/meson.build
index 748c9ae..db80078 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -28,8 +28,6 @@ sources = files(
 	'pipeline/pipeline_flow_classification.c',
 	'pipeline/pipeline_master_be.c',
 	'pipeline/pipeline_master.c',
-	'pipeline/pipeline_passthrough_be.c',
-	'pipeline/pipeline_passthrough.c',
 	'pipeline/pipeline_routing_be.c',
 	'pipeline/pipeline_routing.c',
 )
diff --git a/examples/ip_pipeline/pipeline/pipeline_passthrough.c b/examples/ip_pipeline/pipeline/pipeline_passthrough.c
deleted file mode 100644
index 031f5f0..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_passthrough.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#include "pipeline_passthrough.h"
-#include "pipeline_passthrough_be.h"
-
-static int
-app_pipeline_passthrough_track(struct pipeline_params *p,
-	uint32_t port_in,
-	uint32_t *port_out)
-{
-	struct pipeline_passthrough_params pp;
-	int status;
-
-	/* Check input arguments */
-	if ((p == NULL) ||
-		(port_in >= p->n_ports_in) ||
-		(port_out == NULL))
-		return -1;
-
-	status = pipeline_passthrough_parse_args(&pp, p);
-	if (status)
-		return -1;
-
-	if (pp.dma_hash_lb_enabled)
-		return -1;
-
-	*port_out = port_in / (p->n_ports_in / p->n_ports_out);
-	return 0;
-}
-
-static struct pipeline_fe_ops pipeline_passthrough_fe_ops = {
-	.f_init = NULL,
-	.f_post_init = NULL,
-	.f_free = NULL,
-	.f_track = app_pipeline_passthrough_track,
-	.cmds = NULL,
-};
-
-struct pipeline_type pipeline_passthrough = {
-	.name = "PASS-THROUGH",
-	.be_ops = &pipeline_passthrough_be_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
deleted file mode 100644
index 7a7a2fc..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_passthrough.h
+++ /dev/null
@@ -1,12 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#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_be.c b/examples/ip_pipeline/pipeline/pipeline_passthrough_be.c
deleted file mode 100644
index b2bbaed..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_passthrough_be.c
+++ /dev/null
@@ -1,929 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2016 Intel Corporation
- */
-
-#include <stdio.h>
-#include <string.h>
-
-#include <rte_common.h>
-#include <rte_malloc.h>
-#include <rte_byteorder.h>
-#include <rte_table_stub.h>
-#include <rte_table_hash.h>
-#include <rte_pipeline.h>
-
-#include "pipeline_passthrough_be.h"
-#include "pipeline_actions_common.h"
-#include "parser.h"
-#include "hash_func.h"
-
-#define SWAP_DIM (PIPELINE_PASSTHROUGH_SWAP_N_FIELDS_MAX * \
-	(PIPELINE_PASSTHROUGH_SWAP_FIELD_SIZE_MAX / sizeof(uint64_t)))
-
-struct pipeline_passthrough {
-	struct pipeline p;
-	struct pipeline_passthrough_params params;
-	rte_table_hash_op_hash f_hash;
-	uint32_t swap_field0_offset[SWAP_DIM];
-	uint32_t swap_field1_offset[SWAP_DIM];
-	uint64_t swap_field_mask[SWAP_DIM];
-	uint32_t swap_n_fields;
-} __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 __rte_always_inline void
-pkt_work_dma(
-	struct rte_mbuf *pkt,
-	void *arg,
-	uint32_t dma_size,
-	uint32_t hash_enabled,
-	uint32_t lb_hash,
-	uint32_t port_out_pow2)
-{
-	struct pipeline_passthrough *p = arg;
-
-	uint64_t *dma_dst = RTE_MBUF_METADATA_UINT64_PTR(pkt,
-		p->params.dma_dst_offset);
-	uint64_t *dma_src = RTE_MBUF_METADATA_UINT64_PTR(pkt,
-		p->params.dma_src_offset);
-	uint64_t *dma_mask = (uint64_t *) p->params.dma_src_mask;
-	uint32_t *dma_hash = RTE_MBUF_METADATA_UINT32_PTR(pkt,
-		p->params.dma_hash_offset);
-	uint32_t i;
-
-	/* Read (dma_src), compute (dma_dst), write (dma_dst) */
-	for (i = 0; i < (dma_size / 8); i++)
-		dma_dst[i] = dma_src[i] & dma_mask[i];
-
-	/* Read (dma_dst), compute (hash), write (hash) */
-	if (hash_enabled) {
-		uint32_t hash = p->f_hash(dma_src, dma_mask, dma_size, 0);
-		*dma_hash = hash;
-
-		if (lb_hash) {
-			uint32_t port_out;
-
-			if (port_out_pow2)
-				port_out
-					= hash & (p->p.n_ports_out - 1);
-			else
-				port_out
-					= hash % p->p.n_ports_out;
-
-			rte_pipeline_port_out_packet_insert(p->p.p,
-				port_out, pkt);
-		}
-	}
-}
-
-static __rte_always_inline void
-pkt4_work_dma(
-	struct rte_mbuf **pkts,
-	void *arg,
-	uint32_t dma_size,
-	uint32_t hash_enabled,
-	uint32_t lb_hash,
-	uint32_t port_out_pow2)
-{
-	struct pipeline_passthrough *p = arg;
-
-	uint64_t *dma_dst0 = RTE_MBUF_METADATA_UINT64_PTR(pkts[0],
-		p->params.dma_dst_offset);
-	uint64_t *dma_dst1 = RTE_MBUF_METADATA_UINT64_PTR(pkts[1],
-		p->params.dma_dst_offset);
-	uint64_t *dma_dst2 = RTE_MBUF_METADATA_UINT64_PTR(pkts[2],
-		p->params.dma_dst_offset);
-	uint64_t *dma_dst3 = RTE_MBUF_METADATA_UINT64_PTR(pkts[3],
-		p->params.dma_dst_offset);
-
-	uint64_t *dma_src0 = RTE_MBUF_METADATA_UINT64_PTR(pkts[0],
-		p->params.dma_src_offset);
-	uint64_t *dma_src1 = RTE_MBUF_METADATA_UINT64_PTR(pkts[1],
-		p->params.dma_src_offset);
-	uint64_t *dma_src2 = RTE_MBUF_METADATA_UINT64_PTR(pkts[2],
-		p->params.dma_src_offset);
-	uint64_t *dma_src3 = RTE_MBUF_METADATA_UINT64_PTR(pkts[3],
-		p->params.dma_src_offset);
-
-	uint64_t *dma_mask = (uint64_t *) p->params.dma_src_mask;
-
-	uint32_t *dma_hash0 = RTE_MBUF_METADATA_UINT32_PTR(pkts[0],
-		p->params.dma_hash_offset);
-	uint32_t *dma_hash1 = RTE_MBUF_METADATA_UINT32_PTR(pkts[1],
-		p->params.dma_hash_offset);
-	uint32_t *dma_hash2 = RTE_MBUF_METADATA_UINT32_PTR(pkts[2],
-		p->params.dma_hash_offset);
-	uint32_t *dma_hash3 = RTE_MBUF_METADATA_UINT32_PTR(pkts[3],
-		p->params.dma_hash_offset);
-
-	uint32_t i;
-
-	/* Read (dma_src), compute (dma_dst), write (dma_dst) */
-	for (i = 0; i < (dma_size / 8); i++) {
-		dma_dst0[i] = dma_src0[i] & dma_mask[i];
-		dma_dst1[i] = dma_src1[i] & dma_mask[i];
-		dma_dst2[i] = dma_src2[i] & dma_mask[i];
-		dma_dst3[i] = dma_src3[i] & dma_mask[i];
-	}
-
-	/* Read (dma_dst), compute (hash), write (hash) */
-	if (hash_enabled) {
-		uint32_t hash0 = p->f_hash(dma_src0, dma_mask, dma_size, 0);
-		uint32_t hash1 = p->f_hash(dma_src1, dma_mask, dma_size, 0);
-		uint32_t hash2 = p->f_hash(dma_src2, dma_mask, dma_size, 0);
-		uint32_t hash3 = p->f_hash(dma_src3, dma_mask, dma_size, 0);
-
-		*dma_hash0 = hash0;
-		*dma_hash1 = hash1;
-		*dma_hash2 = hash2;
-		*dma_hash3 = hash3;
-
-		if (lb_hash) {
-			uint32_t port_out0, port_out1, port_out2, port_out3;
-
-			if (port_out_pow2) {
-				port_out0
-					= hash0 & (p->p.n_ports_out - 1);
-				port_out1
-					= hash1 & (p->p.n_ports_out - 1);
-				port_out2
-					= hash2 & (p->p.n_ports_out - 1);
-				port_out3
-					= hash3 & (p->p.n_ports_out - 1);
-			} else {
-				port_out0
-					= hash0 % p->p.n_ports_out;
-				port_out1
-					= hash1 % p->p.n_ports_out;
-				port_out2
-					= hash2 % p->p.n_ports_out;
-				port_out3
-					= hash3 % p->p.n_ports_out;
-			}
-			rte_pipeline_port_out_packet_insert(p->p.p,
-				port_out0, pkts[0]);
-			rte_pipeline_port_out_packet_insert(p->p.p,
-				port_out1, pkts[1]);
-			rte_pipeline_port_out_packet_insert(p->p.p,
-				port_out2, pkts[2]);
-			rte_pipeline_port_out_packet_insert(p->p.p,
-				port_out3, pkts[3]);
-		}
-	}
-}
-
-static __rte_always_inline void
-pkt_work_swap(
-	struct rte_mbuf *pkt,
-	void *arg)
-{
-	struct pipeline_passthrough *p = arg;
-	uint32_t i;
-
-	/* Read(field0, field1), compute(field0, field1), write(field0, field1) */
-	for (i = 0; i < p->swap_n_fields; i++) {
-		uint64_t *field0_ptr = RTE_MBUF_METADATA_UINT64_PTR(pkt,
-			p->swap_field0_offset[i]);
-		uint64_t *field1_ptr = RTE_MBUF_METADATA_UINT64_PTR(pkt,
-			p->swap_field1_offset[i]);
-		uint64_t mask = p->swap_field_mask[i];
-
-		uint64_t field0 = *field0_ptr;
-		uint64_t field1 = *field1_ptr;
-
-		*field0_ptr = (field0 & (~mask)) + (field1 & mask);
-		*field1_ptr = (field0 & mask) + (field1 & (~mask));
-	}
-}
-
-static __rte_always_inline void
-pkt4_work_swap(
-	struct rte_mbuf **pkts,
-	void *arg)
-{
-	struct pipeline_passthrough *p = arg;
-	uint32_t i;
-
-	/* Read(field0, field1), compute(field0, field1), write(field0, field1) */
-	for (i = 0; i < p->swap_n_fields; i++) {
-		uint64_t *pkt0_field0_ptr = RTE_MBUF_METADATA_UINT64_PTR(pkts[0],
-			p->swap_field0_offset[i]);
-		uint64_t *pkt1_field0_ptr = RTE_MBUF_METADATA_UINT64_PTR(pkts[1],
-			p->swap_field0_offset[i]);
-		uint64_t *pkt2_field0_ptr = RTE_MBUF_METADATA_UINT64_PTR(pkts[2],
-			p->swap_field0_offset[i]);
-		uint64_t *pkt3_field0_ptr = RTE_MBUF_METADATA_UINT64_PTR(pkts[3],
-			p->swap_field0_offset[i]);
-
-		uint64_t *pkt0_field1_ptr = RTE_MBUF_METADATA_UINT64_PTR(pkts[0],
-			p->swap_field1_offset[i]);
-		uint64_t *pkt1_field1_ptr = RTE_MBUF_METADATA_UINT64_PTR(pkts[1],
-			p->swap_field1_offset[i]);
-		uint64_t *pkt2_field1_ptr = RTE_MBUF_METADATA_UINT64_PTR(pkts[2],
-			p->swap_field1_offset[i]);
-		uint64_t *pkt3_field1_ptr = RTE_MBUF_METADATA_UINT64_PTR(pkts[3],
-			p->swap_field1_offset[i]);
-
-		uint64_t mask = p->swap_field_mask[i];
-
-		uint64_t pkt0_field0 = *pkt0_field0_ptr;
-		uint64_t pkt1_field0 = *pkt1_field0_ptr;
-		uint64_t pkt2_field0 = *pkt2_field0_ptr;
-		uint64_t pkt3_field0 = *pkt3_field0_ptr;
-
-		uint64_t pkt0_field1 = *pkt0_field1_ptr;
-		uint64_t pkt1_field1 = *pkt1_field1_ptr;
-		uint64_t pkt2_field1 = *pkt2_field1_ptr;
-		uint64_t pkt3_field1 = *pkt3_field1_ptr;
-
-		*pkt0_field0_ptr = (pkt0_field0 & (~mask)) + (pkt0_field1 & mask);
-		*pkt1_field0_ptr = (pkt1_field0 & (~mask)) + (pkt1_field1 & mask);
-		*pkt2_field0_ptr = (pkt2_field0 & (~mask)) + (pkt2_field1 & mask);
-		*pkt3_field0_ptr = (pkt3_field0 & (~mask)) + (pkt3_field1 & mask);
-
-		*pkt0_field1_ptr = (pkt0_field0 & mask) + (pkt0_field1 & (~mask));
-		*pkt1_field1_ptr = (pkt1_field0 & mask) + (pkt1_field1 & (~mask));
-		*pkt2_field1_ptr = (pkt2_field0 & mask) + (pkt2_field1 & (~mask));
-		*pkt3_field1_ptr = (pkt3_field0 & mask) + (pkt3_field1 & (~mask));
-	}
-}
-
-#define PKT_WORK_DMA(dma_size, hash_enabled, lb_hash, port_pow2)	\
-static inline void						\
-pkt_work_dma_size##dma_size##_hash##hash_enabled		\
-	##_lb##lb_hash##_pw##port_pow2(			\
-	struct rte_mbuf *pkt,					\
-	void *arg)						\
-{								\
-	pkt_work_dma(pkt, arg, dma_size, hash_enabled, lb_hash, port_pow2);	\
-}
-
-#define PKT4_WORK_DMA(dma_size, hash_enabled, lb_hash, port_pow2)	\
-static inline void						\
-pkt4_work_dma_size##dma_size##_hash##hash_enabled			\
-	##_lb##lb_hash##_pw##port_pow2(			\
-	struct rte_mbuf **pkts,					\
-	void *arg)						\
-{								\
-	pkt4_work_dma(pkts, arg, dma_size, hash_enabled, lb_hash, port_pow2); \
-}
-
-#define port_in_ah_dma(dma_size, hash_enabled, lb_hash, port_pow2)	\
-PKT_WORK_DMA(dma_size, hash_enabled, lb_hash, port_pow2)			\
-PKT4_WORK_DMA(dma_size, hash_enabled, lb_hash, port_pow2)			\
-PIPELINE_PORT_IN_AH(port_in_ah_dma_size##dma_size##_hash	\
-	##hash_enabled##_lb##lb_hash##_pw##port_pow2,		\
-	pkt_work_dma_size##dma_size##_hash##hash_enabled		\
-	##_lb##lb_hash##_pw##port_pow2,			\
-	pkt4_work_dma_size##dma_size##_hash##hash_enabled		\
-	##_lb##lb_hash##_pw##port_pow2)
-
-
-#define port_in_ah_lb(dma_size, hash_enabled, lb_hash, port_pow2) \
-PKT_WORK_DMA(dma_size, hash_enabled, lb_hash, port_pow2)		\
-PKT4_WORK_DMA(dma_size, hash_enabled, lb_hash, port_pow2)	\
-PIPELINE_PORT_IN_AH_HIJACK_ALL(						\
-	port_in_ah_lb_size##dma_size##_hash##hash_enabled		\
-	##_lb##lb_hash##_pw##port_pow2,			\
-	pkt_work_dma_size##dma_size##_hash##hash_enabled		\
-	##_lb##lb_hash##_pw##port_pow2,	\
-	pkt4_work_dma_size##dma_size##_hash##hash_enabled		\
-	##_lb##lb_hash##_pw##port_pow2)
-
-PIPELINE_PORT_IN_AH(port_in_ah_swap, pkt_work_swap,	pkt4_work_swap)
-
-
-/* Port in AH DMA(dma_size, hash_enabled, lb_hash, port_pow2) */
-
-port_in_ah_dma(8, 0, 0, 0)
-port_in_ah_dma(8, 1, 0, 0)
-port_in_ah_lb(8, 1, 1, 0)
-port_in_ah_lb(8, 1, 1, 1)
-
-port_in_ah_dma(16, 0, 0, 0)
-port_in_ah_dma(16, 1, 0, 0)
-port_in_ah_lb(16, 1, 1, 0)
-port_in_ah_lb(16, 1, 1, 1)
-
-port_in_ah_dma(24, 0, 0, 0)
-port_in_ah_dma(24, 1, 0, 0)
-port_in_ah_lb(24, 1, 1, 0)
-port_in_ah_lb(24, 1, 1, 1)
-
-port_in_ah_dma(32, 0, 0, 0)
-port_in_ah_dma(32, 1, 0, 0)
-port_in_ah_lb(32, 1, 1, 0)
-port_in_ah_lb(32, 1, 1, 1)
-
-port_in_ah_dma(40, 0, 0, 0)
-port_in_ah_dma(40, 1, 0, 0)
-port_in_ah_lb(40, 1, 1, 0)
-port_in_ah_lb(40, 1, 1, 1)
-
-port_in_ah_dma(48, 0, 0, 0)
-port_in_ah_dma(48, 1, 0, 0)
-port_in_ah_lb(48, 1, 1, 0)
-port_in_ah_lb(48, 1, 1, 1)
-
-port_in_ah_dma(56, 0, 0, 0)
-port_in_ah_dma(56, 1, 0, 0)
-port_in_ah_lb(56, 1, 1, 0)
-port_in_ah_lb(56, 1, 1, 1)
-
-port_in_ah_dma(64, 0, 0, 0)
-port_in_ah_dma(64, 1, 0, 0)
-port_in_ah_lb(64, 1, 1, 0)
-port_in_ah_lb(64, 1, 1, 1)
-
-static rte_pipeline_port_in_action_handler
-get_port_in_ah(struct pipeline_passthrough *p)
-{
-	if ((p->params.dma_enabled == 0) &&
-		(p->params.swap_enabled == 0))
-		return NULL;
-
-	if (p->params.swap_enabled)
-		return port_in_ah_swap;
-
-	if (p->params.dma_hash_enabled) {
-		if (p->params.dma_hash_lb_enabled) {
-			if (rte_is_power_of_2(p->p.n_ports_out))
-				switch (p->params.dma_size) {
-
-				case 8: return port_in_ah_lb_size8_hash1_lb1_pw1;
-				case 16: return port_in_ah_lb_size16_hash1_lb1_pw1;
-				case 24: return port_in_ah_lb_size24_hash1_lb1_pw1;
-				case 32: return port_in_ah_lb_size32_hash1_lb1_pw1;
-				case 40: return port_in_ah_lb_size40_hash1_lb1_pw1;
-				case 48: return port_in_ah_lb_size48_hash1_lb1_pw1;
-				case 56: return port_in_ah_lb_size56_hash1_lb1_pw1;
-				case 64: return port_in_ah_lb_size64_hash1_lb1_pw1;
-				default: return NULL;
-				}
-			else
-				switch (p->params.dma_size) {
-
-				case 8: return port_in_ah_lb_size8_hash1_lb1_pw0;
-				case 16: return port_in_ah_lb_size16_hash1_lb1_pw0;
-				case 24: return port_in_ah_lb_size24_hash1_lb1_pw0;
-				case 32: return port_in_ah_lb_size32_hash1_lb1_pw0;
-				case 40: return port_in_ah_lb_size40_hash1_lb1_pw0;
-				case 48: return port_in_ah_lb_size48_hash1_lb1_pw0;
-				case 56: return port_in_ah_lb_size56_hash1_lb1_pw0;
-				case 64: return port_in_ah_lb_size64_hash1_lb1_pw0;
-				default: return NULL;
-			}
-		} else
-			switch (p->params.dma_size) {
-
-			case 8: return port_in_ah_dma_size8_hash1_lb0_pw0;
-			case 16: return port_in_ah_dma_size16_hash1_lb0_pw0;
-			case 24: return port_in_ah_dma_size24_hash1_lb0_pw0;
-			case 32: return port_in_ah_dma_size32_hash1_lb0_pw0;
-			case 40: return port_in_ah_dma_size40_hash1_lb0_pw0;
-			case 48: return port_in_ah_dma_size48_hash1_lb0_pw0;
-			case 56: return port_in_ah_dma_size56_hash1_lb0_pw0;
-			case 64: return port_in_ah_dma_size64_hash1_lb0_pw0;
-			default: return NULL;
-		}
-	} else
-		switch (p->params.dma_size) {
-
-		case 8: return port_in_ah_dma_size8_hash0_lb0_pw0;
-		case 16: return port_in_ah_dma_size16_hash0_lb0_pw0;
-		case 24: return port_in_ah_dma_size24_hash0_lb0_pw0;
-		case 32: return port_in_ah_dma_size32_hash0_lb0_pw0;
-		case 40: return port_in_ah_dma_size40_hash0_lb0_pw0;
-		case 48: return port_in_ah_dma_size48_hash0_lb0_pw0;
-		case 56: return port_in_ah_dma_size56_hash0_lb0_pw0;
-		case 64: return port_in_ah_dma_size64_hash0_lb0_pw0;
-		default: return NULL;
-		}
-}
-
-int
-pipeline_passthrough_parse_args(struct pipeline_passthrough_params *p,
-	struct pipeline_params *params)
-{
-	uint32_t dma_dst_offset_present = 0;
-	uint32_t dma_src_offset_present = 0;
-	uint32_t dma_src_mask_present = 0;
-	char dma_mask_str[PIPELINE_PASSTHROUGH_DMA_SIZE_MAX * 2 + 1];
-	uint32_t dma_size_present = 0;
-	uint32_t dma_hash_offset_present = 0;
-	uint32_t dma_hash_lb_present = 0;
-	uint32_t i;
-
-	/* default values */
-	p->dma_enabled = 0;
-	p->dma_hash_enabled = 0;
-	p->dma_hash_lb_enabled = 0;
-	memset(p->dma_src_mask, 0xFF, sizeof(p->dma_src_mask));
-	p->swap_enabled = 0;
-	p->swap_n_fields = 0;
-
-	for (i = 0; i < params->n_args; i++) {
-		char *arg_name = params->args_name[i];
-		char *arg_value = params->args_value[i];
-
-		/* dma_dst_offset */
-		if (strcmp(arg_name, "dma_dst_offset") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				dma_dst_offset_present == 0, params->name,
-				arg_name);
-			dma_dst_offset_present = 1;
-
-			status = parser_read_uint32(&p->dma_dst_offset,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			p->dma_enabled = 1;
-
-			continue;
-		}
-
-		/* dma_src_offset */
-		if (strcmp(arg_name, "dma_src_offset") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				dma_src_offset_present == 0, params->name,
-				arg_name);
-			dma_src_offset_present = 1;
-
-			status = parser_read_uint32(&p->dma_src_offset,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			p->dma_enabled = 1;
-
-			continue;
-		}
-
-		/* dma_size */
-		if (strcmp(arg_name, "dma_size") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				dma_size_present == 0, params->name,
-				arg_name);
-			dma_size_present = 1;
-
-			status = parser_read_uint32(&p->dma_size,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL(((status != -EINVAL) &&
-				(p->dma_size != 0) &&
-				((p->dma_size % 8) == 0)),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG(((status != -ERANGE) &&
-				(p->dma_size <=
-				PIPELINE_PASSTHROUGH_DMA_SIZE_MAX)),
-				params->name, arg_name, arg_value);
-
-			p->dma_enabled = 1;
-
-			continue;
-		}
-
-		/* dma_src_mask */
-		if (strcmp(arg_name, "dma_src_mask") == 0) {
-			int mask_str_len = strlen(arg_value);
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				dma_src_mask_present == 0,
-				params->name, arg_name);
-			dma_src_mask_present = 1;
-
-			PIPELINE_ARG_CHECK((mask_str_len <=
-				(PIPELINE_PASSTHROUGH_DMA_SIZE_MAX * 2)),
-				"Parse error in section \"%s\": entry "
-				"\"%s\" too long", params->name,
-				arg_name);
-
-			snprintf(dma_mask_str, mask_str_len + 1,
-				"%s", arg_value);
-
-			p->dma_enabled = 1;
-
-			continue;
-		}
-
-		/* dma_hash_offset */
-		if (strcmp(arg_name, "dma_hash_offset") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				dma_hash_offset_present == 0,
-				params->name, arg_name);
-			dma_hash_offset_present = 1;
-
-			status = parser_read_uint32(&p->dma_hash_offset,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			p->dma_hash_enabled = 1;
-
-			continue;
-		}
-
-		/* load_balance mode */
-		if (strcmp(arg_name, "lb") == 0) {
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				dma_hash_lb_present == 0,
-				params->name, arg_name);
-			dma_hash_lb_present = 1;
-
-			if (strcmp(arg_value, "hash") &&
-				strcmp(arg_value, "HASH"))
-
-				PIPELINE_PARSE_ERR_INV_VAL(0,
-					params->name,
-					arg_name,
-					arg_value);
-
-			p->dma_hash_lb_enabled = 1;
-
-			continue;
-		}
-
-		/* swap */
-		if (strcmp(arg_name, "swap") == 0) {
-			uint32_t a, b, n_args;
-			int len;
-
-			n_args = sscanf(arg_value, "%" SCNu32 " %" SCNu32 "%n",
-				&a, &b, &len);
-			PIPELINE_PARSE_ERR_INV_VAL(((n_args == 2) &&
-				((size_t) len == strlen(arg_value))),
-				params->name, arg_name, arg_value);
-
-			p->swap_field0_offset[p->swap_n_fields] = a;
-			p->swap_field1_offset[p->swap_n_fields] = b;
-			p->swap_n_fields++;
-			p->swap_enabled = 1;
-
-			continue;
-		}
-
-		/* any other */
-		PIPELINE_PARSE_ERR_INV_ENT(0, params->name, arg_name);
-	}
-
-	/* Check correlations between arguments */
-	PIPELINE_ARG_CHECK((p->dma_enabled + p->swap_enabled < 2),
-		"Parse error in section \"%s\": DMA and SWAP actions are both enabled",
-		params->name);
-	PIPELINE_ARG_CHECK((dma_dst_offset_present == p->dma_enabled),
-		"Parse error in section \"%s\": missing entry "
-		"\"dma_dst_offset\"", params->name);
-	PIPELINE_ARG_CHECK((dma_src_offset_present == p->dma_enabled),
-		"Parse error in section \"%s\": missing entry "
-		"\"dma_src_offset\"", params->name);
-	PIPELINE_ARG_CHECK((dma_size_present == p->dma_enabled),
-		"Parse error in section \"%s\": missing entry "
-		"\"dma_size\"", params->name);
-	PIPELINE_ARG_CHECK((p->dma_hash_enabled <= p->dma_enabled),
-		"Parse error in section \"%s\": missing all DMA entries",
-		params->name);
-	PIPELINE_ARG_CHECK((p->dma_hash_lb_enabled <= p->dma_hash_enabled),
-		"Parse error in section \"%s\": missing all DMA hash entries ",
-		params->name);
-
-	if (dma_src_mask_present) {
-		uint32_t dma_size = p->dma_size;
-		int status;
-
-		PIPELINE_ARG_CHECK((strlen(dma_mask_str) ==
-			(dma_size * 2)), "Parse error in section "
-			"\"%s\": dma_src_mask should have exactly %u hex "
-			"digits", params->name, (dma_size * 2));
-
-		status = parse_hex_string(dma_mask_str, p->dma_src_mask,
-			&p->dma_size);
-
-		PIPELINE_PARSE_ERR_INV_VAL(((status == 0) &&
-			(dma_size == p->dma_size)), params->name,
-			"dma_src_mask", dma_mask_str);
-	}
-
-	if (p->dma_hash_lb_enabled)
-		PIPELINE_ARG_CHECK((params->n_ports_out > 1),
-			"Parse error in section \"%s\": entry \"lb\" not "
-			"allowed for single output port pipeline",
-			params->name);
-	else
-		PIPELINE_ARG_CHECK(((params->n_ports_in >= params->n_ports_out)
-			&& ((params->n_ports_in % params->n_ports_out) == 0)),
-			"Parse error in section \"%s\": n_ports_in needs to be "
-			"a multiple of n_ports_out (lb mode disabled)",
-			params->name);
-
-	return 0;
-}
-
-static rte_table_hash_op_hash
-get_hash_function(struct pipeline_passthrough *p)
-{
-	switch (p->params.dma_size) {
-
-	case 8: return hash_default_key8;
-	case 16: return hash_default_key16;
-	case 24: return hash_default_key24;
-	case 32: return hash_default_key32;
-	case 40: return hash_default_key40;
-	case 48: return hash_default_key48;
-	case 56: return hash_default_key56;
-	case 64: return hash_default_key64;
-	default: return NULL;
-	}
-}
-
-static int
-pipeline_passthrough_swap_convert(struct pipeline_passthrough *p)
-{
-	uint32_t i;
-
-	p->swap_n_fields = 0;
-
-	for (i = 0; i < p->params.swap_n_fields; i++) {
-		uint32_t offset0 = p->params.swap_field0_offset[i];
-		uint32_t offset1 = p->params.swap_field1_offset[i];
-		uint32_t size = offset1 - offset0;
-		uint32_t j;
-
-		/* Check */
-		if ((offset0 >= offset1) ||
-			(size > PIPELINE_PASSTHROUGH_SWAP_FIELD_SIZE_MAX) ||
-			(p->swap_n_fields >= SWAP_DIM))
-			return -1;
-
-		for (j = 0; j < (size / sizeof(uint64_t)); j++) {
-			p->swap_field0_offset[p->swap_n_fields] = offset0;
-			p->swap_field1_offset[p->swap_n_fields] = offset1;
-			p->swap_field_mask[p->swap_n_fields] = UINT64_MAX;
-			p->swap_n_fields++;
-			offset0 += sizeof(uint64_t);
-			offset1 += sizeof(uint64_t);
-		}
-		if (size % sizeof(uint64_t)) {
-			uint32_t n_bits = (size % sizeof(uint64_t)) * 8;
-
-			p->swap_field0_offset[p->swap_n_fields] = offset0;
-			p->swap_field1_offset[p->swap_n_fields] = offset1;
-			p->swap_field_mask[p->swap_n_fields] =
-				RTE_LEN2MASK(n_bits, uint64_t);
-			p->swap_n_fields++;
-		}
-	}
-
-	return 0;
-}
-
-static void*
-pipeline_passthrough_init(struct pipeline_params *params,
-	__rte_unused void *arg)
-{
-	struct pipeline *p;
-	struct pipeline_passthrough *p_pt;
-	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_passthrough));
-	p = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
-	p_pt = (struct pipeline_passthrough *) p;
-	if (p == NULL)
-		return NULL;
-
-	strcpy(p->name, params->name);
-	p->log_level = params->log_level;
-
-	PLOG(p, HIGH, "Pass-through");
-
-	/* Parse arguments */
-	if (pipeline_passthrough_parse_args(&p_pt->params, params))
-		return NULL;
-	if (pipeline_passthrough_swap_convert(p_pt))
-		return NULL;
-	p_pt->f_hash = get_hash_function(p_pt);
-
-	/* 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;
-		}
-	}
-
-	p->n_ports_in = params->n_ports_in;
-	p->n_ports_out = params->n_ports_out;
-	p->n_tables = p->n_ports_in;
-
-	/*Input ports*/
-	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 = get_port_in_ah(p_pt),
-			.arg_ah = p_pt,
-			.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 */
-	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,
-			.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 */
-	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++) {
-		uint32_t port_out_id = (p_pt->params.dma_hash_lb_enabled == 0) ?
-			(i / (p->n_ports_in / p->n_ports_out)) :
-			0;
-
-		struct rte_pipeline_table_entry default_entry = {
-			.action = RTE_PIPELINE_ACTION_PORT,
-			{.port_id = p->port_out_id[port_out_id]},
-		};
-
-		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;
-}
-
-struct pipeline_be_ops pipeline_passthrough_be_ops = {
-	.f_init = pipeline_passthrough_init,
-	.f_free = pipeline_passthrough_free,
-	.f_run = NULL,
-	.f_timer = pipeline_passthrough_timer,
-};
diff --git a/examples/ip_pipeline/pipeline/pipeline_passthrough_be.h b/examples/ip_pipeline/pipeline/pipeline_passthrough_be.h
deleted file mode 100644
index 94d1d1c..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_passthrough_be.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#ifndef __INCLUDE_PIPELINE_PASSTHROUGH_BE_H__
-#define __INCLUDE_PIPELINE_PASSTHROUGH_BE_H__
-
-#include "pipeline_common_be.h"
-
-#define PIPELINE_PASSTHROUGH_DMA_SIZE_MAX                             64
-
-#ifndef PIPELINE_PASSTHROUGH_SWAP_N_FIELDS_MAX
-#define PIPELINE_PASSTHROUGH_SWAP_N_FIELDS_MAX                        8
-#endif
-
-#ifndef PIPELINE_PASSTHROUGH_SWAP_FIELD_SIZE_MAX
-#define PIPELINE_PASSTHROUGH_SWAP_FIELD_SIZE_MAX                      16
-#endif
-
-struct pipeline_passthrough_params {
-	uint32_t dma_enabled;
-	uint32_t dma_dst_offset;
-	uint32_t dma_src_offset;
-	uint8_t dma_src_mask[PIPELINE_PASSTHROUGH_DMA_SIZE_MAX];
-	uint32_t dma_size;
-
-	uint32_t dma_hash_enabled;
-	uint32_t dma_hash_offset;
-
-	uint32_t dma_hash_lb_enabled;
-
-	uint32_t swap_enabled;
-	uint32_t swap_field0_offset[PIPELINE_PASSTHROUGH_SWAP_N_FIELDS_MAX];
-	uint32_t swap_field1_offset[PIPELINE_PASSTHROUGH_SWAP_N_FIELDS_MAX];
-	uint32_t swap_n_fields;
-};
-
-int
-pipeline_passthrough_parse_args(struct pipeline_passthrough_params *p,
-	struct pipeline_params *params);
-
-extern struct pipeline_be_ops pipeline_passthrough_be_ops;
-
-#endif
-- 
2.9.3

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

* [dpdk-dev] [PATCH v2 11/44] ip_pipeline: remove routing pipeline
  2018-03-12 17:25   ` [dpdk-dev] [PATCH v2 00/44] ip_pipeline: refactoring Jasvinder Singh
                       ` (9 preceding siblings ...)
  2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 10/44] ip_pipeline: remove passthrough pipeline Jasvinder Singh
@ 2018-03-12 17:25     ` Jasvinder Singh
  2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 12/44] ip_pipeline: remove flow classification pipeline Jasvinder Singh
                       ` (32 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-12 17:25 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Remove routing pipeline.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/Makefile                      |    2 -
 examples/ip_pipeline/init.c                        |    2 -
 examples/ip_pipeline/meson.build                   |    2 -
 examples/ip_pipeline/pipeline/pipeline_routing.c   | 1613 ----------------
 examples/ip_pipeline/pipeline/pipeline_routing.h   |   71 -
 .../ip_pipeline/pipeline/pipeline_routing_be.c     | 1966 --------------------
 .../ip_pipeline/pipeline/pipeline_routing_be.h     |  283 ---
 7 files changed, 3939 deletions(-)
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_routing.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_routing.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_routing_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_routing_be.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index 089c269..f67cfe6 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -25,8 +25,6 @@ SRCS-y += pipeline_flow_classification_be.c
 SRCS-y += pipeline_flow_classification.c
 SRCS-y += pipeline_flow_actions_be.c
 SRCS-y += pipeline_flow_actions.c
-SRCS-y += pipeline_routing_be.c
-SRCS-y += pipeline_routing.c
 
 # Build using pkg-config variables if possible
 $(shell pkg-config --exists libdpdk)
diff --git a/examples/ip_pipeline/init.c b/examples/ip_pipeline/init.c
index 73b93d7..241d80a 100644
--- a/examples/ip_pipeline/init.c
+++ b/examples/ip_pipeline/init.c
@@ -29,7 +29,6 @@
 #include "pipeline_firewall.h"
 #include "pipeline_flow_classification.h"
 #include "pipeline_flow_actions.h"
-#include "pipeline_routing.h"
 #include "thread_fe.h"
 
 #define APP_NAME_SIZE	32
@@ -1824,7 +1823,6 @@ int app_init(struct app_params *app)
 	app_pipeline_type_register(app, &pipeline_flow_classification);
 	app_pipeline_type_register(app, &pipeline_flow_actions);
 	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/meson.build b/examples/ip_pipeline/meson.build
index db80078..53d36df 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -28,6 +28,4 @@ sources = files(
 	'pipeline/pipeline_flow_classification.c',
 	'pipeline/pipeline_master_be.c',
 	'pipeline/pipeline_master.c',
-	'pipeline/pipeline_routing_be.c',
-	'pipeline/pipeline_routing.c',
 )
diff --git a/examples/ip_pipeline/pipeline/pipeline_routing.c b/examples/ip_pipeline/pipeline/pipeline_routing.c
deleted file mode 100644
index 0562c63..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_routing.c
+++ /dev/null
@@ -1,1613 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2016 Intel Corporation
- */
-
-#include <cmdline_parse.h>
-#include <cmdline_parse_num.h>
-#include <cmdline_parse_string.h>
-
-#include "app.h"
-#include "pipeline_common_fe.h"
-#include "pipeline_routing.h"
-#include "parser.h"
-
-struct app_pipeline_routing_route {
-	struct pipeline_routing_route_key key;
-	struct pipeline_routing_route_data data;
-	void *entry_ptr;
-
-	TAILQ_ENTRY(app_pipeline_routing_route) node;
-};
-
-struct app_pipeline_routing_arp_entry {
-	struct pipeline_routing_arp_key key;
-	struct ether_addr macaddr;
-	void *entry_ptr;
-
-	TAILQ_ENTRY(app_pipeline_routing_arp_entry) node;
-};
-
-struct pipeline_routing {
-	/* Parameters */
-	struct app_params *app;
-	uint32_t pipeline_id;
-	uint32_t n_ports_in;
-	uint32_t n_ports_out;
-	struct pipeline_routing_params rp;
-
-	/* Links */
-	uint32_t link_id[PIPELINE_MAX_PORT_OUT];
-
-	/* Routes */
-	TAILQ_HEAD(, app_pipeline_routing_route) routes;
-	uint32_t n_routes;
-
-	uint32_t default_route_present;
-	uint32_t default_route_port_id;
-	void *default_route_entry_ptr;
-
-	/* 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;
-};
-
-static int
-app_pipeline_routing_find_link(struct pipeline_routing *p,
-	uint32_t link_id,
-	uint32_t *port_id)
-{
-	uint32_t i;
-
-	for (i = 0; i < p->n_ports_out; i++)
-		if (p->link_id[i] == link_id) {
-			*port_id = i;
-			return 0;
-		}
-
-	return -1;
-}
-
-static void
-app_pipeline_routing_link_op(__rte_unused struct app_params *app,
-	uint32_t link_id,
-	uint32_t up,
-	void *arg)
-{
-	struct pipeline_routing_route_key key0, key1;
-	struct pipeline_routing *p = arg;
-	struct app_link_params *lp;
-	uint32_t port_id, netmask;
-	int status;
-
-	if (app == NULL)
-		return;
-
-	APP_PARAM_FIND_BY_ID(app->link_params, "LINK", link_id, lp);
-	if (lp == NULL)
-		return;
-
-	status = app_pipeline_routing_find_link(p,
-		link_id,
-		&port_id);
-	if (status)
-		return;
-
-	netmask = (~0U) << (32 - lp->depth);
-
-	/* Local network (directly attached network) */
-	key0.type = PIPELINE_ROUTING_ROUTE_IPV4;
-	key0.key.ipv4.ip = lp->ip & netmask;
-	key0.key.ipv4.depth = lp->depth;
-
-	/* Local termination */
-	key1.type = PIPELINE_ROUTING_ROUTE_IPV4;
-	key1.key.ipv4.ip = lp->ip;
-	key1.key.ipv4.depth = 32;
-
-	if (up) {
-		struct pipeline_routing_route_data data0, data1;
-
-		/* Local network (directly attached network) */
-		memset(&data0, 0, sizeof(data0));
-		data0.flags = PIPELINE_ROUTING_ROUTE_LOCAL |
-			PIPELINE_ROUTING_ROUTE_ARP;
-		if (p->rp.encap == PIPELINE_ROUTING_ENCAP_ETHERNET_QINQ)
-			data0.flags |= PIPELINE_ROUTING_ROUTE_QINQ;
-		if (p->rp.encap == PIPELINE_ROUTING_ENCAP_ETHERNET_MPLS) {
-			data0.flags |= PIPELINE_ROUTING_ROUTE_MPLS;
-			data0.l2.mpls.n_labels = 1;
-		}
-		data0.port_id = port_id;
-
-		if (p->rp.n_arp_entries)
-			app_pipeline_routing_add_route(app,
-				p->pipeline_id,
-				&key0,
-				&data0);
-
-		/* Local termination */
-		memset(&data1, 0, sizeof(data1));
-		data1.flags = PIPELINE_ROUTING_ROUTE_LOCAL |
-			PIPELINE_ROUTING_ROUTE_ARP;
-		if (p->rp.encap == PIPELINE_ROUTING_ENCAP_ETHERNET_QINQ)
-			data1.flags |= PIPELINE_ROUTING_ROUTE_QINQ;
-		if (p->rp.encap == PIPELINE_ROUTING_ENCAP_ETHERNET_MPLS) {
-			data1.flags |= PIPELINE_ROUTING_ROUTE_MPLS;
-			data1.l2.mpls.n_labels = 1;
-		}
-		data1.port_id = p->rp.port_local_dest;
-
-		app_pipeline_routing_add_route(app,
-			p->pipeline_id,
-			&key1,
-			&data1);
-	} else {
-		/* Local network (directly attached network) */
-		if (p->rp.n_arp_entries)
-			app_pipeline_routing_delete_route(app,
-				p->pipeline_id,
-				&key0);
-
-		/* Local termination */
-		app_pipeline_routing_delete_route(app,
-			p->pipeline_id,
-			&key1);
-	}
-}
-
-static int
-app_pipeline_routing_set_link_op(
-	struct app_params *app,
-	struct pipeline_routing *p)
-{
-	uint32_t port_id;
-
-	for (port_id = 0; port_id < p->n_ports_out; port_id++) {
-		struct app_link_params *link;
-		uint32_t link_id;
-		int status;
-
-		link = app_pipeline_track_pktq_out_to_link(app,
-			p->pipeline_id,
-			port_id);
-		if (link == NULL)
-			continue;
-
-		link_id = link - app->link_params;
-		p->link_id[port_id] = link_id;
-
-		status = app_link_set_op(app,
-			link_id,
-			p->pipeline_id,
-			app_pipeline_routing_link_op,
-			(void *) p);
-		if (status)
-			return status;
-	}
-
-	return 0;
-}
-
-static void *
-app_pipeline_routing_init(struct pipeline_params *params,
-	void *arg)
-{
-	struct app_params *app = (struct app_params *) arg;
-	struct pipeline_routing *p;
-	uint32_t pipeline_id, size;
-	int status;
-
-	/* Check input arguments */
-	if ((params == NULL) ||
-		(params->n_ports_in == 0) ||
-		(params->n_ports_out == 0))
-		return NULL;
-
-	APP_PARAM_GET_ID(params, "PIPELINE", pipeline_id);
-
-	/* 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->app = app;
-	p->pipeline_id = pipeline_id;
-	p->n_ports_in = params->n_ports_in;
-	p->n_ports_out = params->n_ports_out;
-
-	status = pipeline_routing_parse_args(&p->rp, params);
-	if (status) {
-		rte_free(p);
-		return NULL;
-	}
-	TAILQ_INIT(&p->routes);
-	p->n_routes = 0;
-
-	TAILQ_INIT(&p->arp_entries);
-	p->n_arp_entries = 0;
-
-	app_pipeline_routing_set_link_op(app, p);
-
-	return p;
-}
-
-static int
-app_pipeline_routing_post_init(void *pipeline)
-{
-	struct pipeline_routing *p = pipeline;
-
-	/* Check input arguments */
-	if (p == NULL)
-		return -1;
-
-	return app_pipeline_routing_set_macaddr(p->app, p->pipeline_id);
-}
-
-static int
-app_pipeline_routing_free(void *pipeline)
-{
-	struct pipeline_routing *p = pipeline;
-
-	/* Check input arguments */
-	if (p == NULL)
-		return -1;
-
-	/* Free resources */
-	while (!TAILQ_EMPTY(&p->routes)) {
-		struct app_pipeline_routing_route *route;
-
-		route = TAILQ_FIRST(&p->routes);
-		TAILQ_REMOVE(&p->routes, route, node);
-		rte_free(route);
-	}
-
-	while (!TAILQ_EMPTY(&p->arp_entries)) {
-		struct app_pipeline_routing_arp_entry *arp_entry;
-
-		arp_entry = TAILQ_FIRST(&p->arp_entries);
-		TAILQ_REMOVE(&p->arp_entries, arp_entry, node);
-		rte_free(arp_entry);
-	}
-
-	rte_free(p);
-	return 0;
-}
-
-static struct app_pipeline_routing_route *
-app_pipeline_routing_find_route(struct pipeline_routing *p,
-		const struct pipeline_routing_route_key *key)
-{
-	struct app_pipeline_routing_route *it, *found;
-
-	found = NULL;
-	TAILQ_FOREACH(it, &p->routes, node) {
-		if ((key->type == it->key.type) &&
-			(key->key.ipv4.ip == it->key.key.ipv4.ip) &&
-			(key->key.ipv4.depth == it->key.key.ipv4.depth)) {
-			found = it;
-			break;
-		}
-	}
-
-	return found;
-}
-
-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;
-
-	found = NULL;
-	TAILQ_FOREACH(it, &p->arp_entries, node) {
-		if ((key->type == it->key.type) &&
-			(key->key.ipv4.port_id == it->key.key.ipv4.port_id) &&
-			(key->key.ipv4.ip == it->key.key.ipv4.ip)) {
-			found = it;
-			break;
-		}
-	}
-
-	return found;
-}
-
-static void
-print_route(const struct app_pipeline_routing_route *route)
-{
-	if (route->key.type == PIPELINE_ROUTING_ROUTE_IPV4) {
-		const struct pipeline_routing_route_key_ipv4 *key =
-				&route->key.key.ipv4;
-
-		printf("IP Prefix = %" PRIu32 ".%" PRIu32
-			".%" PRIu32 ".%" PRIu32 "/%" PRIu32
-			" => (Port = %" PRIu32,
-
-			(key->ip >> 24) & 0xFF,
-			(key->ip >> 16) & 0xFF,
-			(key->ip >> 8) & 0xFF,
-			key->ip & 0xFF,
-
-			key->depth,
-			route->data.port_id);
-
-		if (route->data.flags & PIPELINE_ROUTING_ROUTE_LOCAL)
-			printf(", Local");
-		else if (route->data.flags & PIPELINE_ROUTING_ROUTE_ARP)
-			printf(
-				", Next Hop IP = %" PRIu32 ".%" PRIu32
-				".%" PRIu32 ".%" PRIu32,
-
-				(route->data.ethernet.ip >> 24) & 0xFF,
-				(route->data.ethernet.ip >> 16) & 0xFF,
-				(route->data.ethernet.ip >> 8) & 0xFF,
-				route->data.ethernet.ip & 0xFF);
-		else
-			printf(
-				", Next Hop HWaddress = %02" PRIx32
-				":%02" PRIx32 ":%02" PRIx32
-				":%02" PRIx32 ":%02" PRIx32
-				":%02" PRIx32,
-
-				route->data.ethernet.macaddr.addr_bytes[0],
-				route->data.ethernet.macaddr.addr_bytes[1],
-				route->data.ethernet.macaddr.addr_bytes[2],
-				route->data.ethernet.macaddr.addr_bytes[3],
-				route->data.ethernet.macaddr.addr_bytes[4],
-				route->data.ethernet.macaddr.addr_bytes[5]);
-
-		if (route->data.flags & PIPELINE_ROUTING_ROUTE_QINQ)
-			printf(", QinQ SVLAN = %" PRIu32 " CVLAN = %" PRIu32,
-				route->data.l2.qinq.svlan,
-				route->data.l2.qinq.cvlan);
-
-		if (route->data.flags & PIPELINE_ROUTING_ROUTE_MPLS) {
-			uint32_t i;
-
-			printf(", MPLS labels");
-			for (i = 0; i < route->data.l2.mpls.n_labels; i++)
-				printf(" %" PRIu32,
-					route->data.l2.mpls.labels[i]);
-		}
-
-		printf(")\n");
-	}
-}
-
-static void
-print_arp_entry(const struct app_pipeline_routing_arp_entry *entry)
-{
-	printf("(Port = %" PRIu32 ", IP = %" PRIu32 ".%" PRIu32
-		".%" PRIu32 ".%" PRIu32
-		") => HWaddress = %02" PRIx32 ":%02" PRIx32 ":%02" PRIx32
-		":%02" PRIx32 ":%02" PRIx32 ":%02" PRIx32 "\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->macaddr.addr_bytes[0],
-		entry->macaddr.addr_bytes[1],
-		entry->macaddr.addr_bytes[2],
-		entry->macaddr.addr_bytes[3],
-		entry->macaddr.addr_bytes[4],
-		entry->macaddr.addr_bytes[5]);
-}
-
-static int
-app_pipeline_routing_route_ls(struct app_params *app, uint32_t pipeline_id)
-{
-	struct pipeline_routing *p;
-	struct app_pipeline_routing_route *it;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_routing);
-	if (p == NULL)
-		return -EINVAL;
-
-	TAILQ_FOREACH(it, &p->routes, node)
-		print_route(it);
-
-	if (p->default_route_present)
-		printf("Default route: port %" PRIu32 " (entry ptr = %p)\n",
-				p->default_route_port_id,
-				p->default_route_entry_ptr);
-	else
-		printf("Default: DROP\n");
-
-	return 0;
-}
-
-int
-app_pipeline_routing_add_route(struct app_params *app,
-	uint32_t pipeline_id,
-	struct pipeline_routing_route_key *key,
-	struct pipeline_routing_route_data *data)
-{
-	struct pipeline_routing *p;
-
-	struct pipeline_routing_route_add_msg_req *req;
-	struct pipeline_routing_route_add_msg_rsp *rsp;
-
-	struct app_pipeline_routing_route *entry;
-
-	int new_entry;
-
-	/* Check input arguments */
-	if ((app == NULL) ||
-		(key == NULL) ||
-		(data == NULL))
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_routing);
-	if (p == NULL)
-		return -1;
-
-	switch (key->type) {
-	case PIPELINE_ROUTING_ROUTE_IPV4:
-	{
-		uint32_t depth = key->key.ipv4.depth;
-		uint32_t netmask;
-
-		/* key */
-		if ((depth == 0) || (depth > 32))
-			return -1;
-
-		netmask = (~0U) << (32 - depth);
-		key->key.ipv4.ip &= netmask;
-
-		/* data */
-		if (data->port_id >= p->n_ports_out)
-			return -1;
-
-		/* Valid range of VLAN tags 12 bits */
-		if (data->flags & PIPELINE_ROUTING_ROUTE_QINQ)
-			if ((data->l2.qinq.svlan & 0xF000) ||
-					(data->l2.qinq.cvlan & 0xF000))
-				return -1;
-
-		/* Max number of MPLS labels supported */
-		if (data->flags & PIPELINE_ROUTING_ROUTE_MPLS) {
-			uint32_t i;
-
-			if (data->l2.mpls.n_labels >
-					PIPELINE_ROUTING_MPLS_LABELS_MAX)
-				return -1;
-
-			/* Max MPLS label value 20 bits */
-			for (i = 0; i < data->l2.mpls.n_labels; i++)
-				if (data->l2.mpls.labels[i] & 0xFFF00000)
-					return -1;
-		}
-	}
-	break;
-
-	default:
-		return -1;
-	}
-
-	/* 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;
-	}
-
-	/* Allocate and write request */
-	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_ROUTE_ADD;
-	memcpy(&req->key, key, sizeof(*key));
-	memcpy(&req->data, data, sizeof(*data));
-
-	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL) {
-		if (new_entry)
-			rte_free(entry);
-		return -1;
-	}
-
-	/* Read response and write entry */
-	if (rsp->status ||
-		(rsp->entry_ptr == NULL) ||
-		((new_entry == 0) && (rsp->key_found == 0)) ||
-		((new_entry == 1) && (rsp->key_found == 1))) {
-		app_msg_free(app, rsp);
-		if (new_entry)
-			rte_free(entry);
-		return -1;
-	}
-
-	memcpy(&entry->key, key, sizeof(*key));
-	memcpy(&entry->data, data, sizeof(*data));
-	entry->entry_ptr = rsp->entry_ptr;
-
-	/* Commit entry */
-	if (new_entry) {
-		TAILQ_INSERT_TAIL(&p->routes, entry, node);
-		p->n_routes++;
-	}
-
-	/* 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_route *entry;
-
-	/* Check input arguments */
-	if ((app == NULL) ||
-		(key == NULL))
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_routing);
-	if (p == NULL)
-		return -1;
-
-	switch (key->type) {
-	case PIPELINE_ROUTING_ROUTE_IPV4:
-	{
-		uint32_t depth = key->key.ipv4.depth;
-		uint32_t netmask;
-
-		/* key */
-		if ((depth == 0) || (depth > 32))
-			return -1;
-
-		netmask = (~0U) << (32 - depth);
-		key->key.ipv4.ip &= netmask;
-	}
-	break;
-
-	default:
-		return -1;
-	}
-
-	/* 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_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	/* Read response */
-	if (rsp->status || !rsp->key_found) {
-		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;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_routing);
-	if (p == NULL)
-		return -1;
-
-	if (port_id >= p->n_ports_out)
-		return -1;
-
-	/* 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_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	/* Read response and write route */
-	if (rsp->status || (rsp->entry_ptr == NULL)) {
-		app_msg_free(app, rsp);
-		return -1;
-	}
-
-	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;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_routing);
-	if (p == NULL)
-		return -1;
-
-	/* 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_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	/* Read response and write route */
-	if (rsp->status) {
-		app_msg_free(app, rsp);
-		return -1;
-	}
-
-	/* Commit route */
-	p->default_route_present = 0;
-
-	/* Free response */
-	app_msg_free(app, rsp);
-
-	return 0;
-}
-
-static int
-app_pipeline_routing_arp_ls(struct app_params *app, uint32_t pipeline_id)
-{
-	struct pipeline_routing *p;
-	struct app_pipeline_routing_arp_entry *it;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_routing);
-	if (p == NULL)
-		return -EINVAL;
-
-	TAILQ_FOREACH(it, &p->arp_entries, node)
-		print_arp_entry(it);
-
-	if (p->default_arp_entry_present)
-		printf("Default entry: port %" PRIu32 " (entry ptr = %p)\n",
-				p->default_arp_entry_port_id,
-				p->default_arp_entry_ptr);
-	else
-		printf("Default: DROP\n");
-
-	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;
-
-	/* Check input arguments */
-	if ((app == NULL) ||
-		(key == NULL) ||
-		(macaddr == NULL))
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_routing);
-	if (p == NULL)
-		return -1;
-
-	switch (key->type) {
-	case PIPELINE_ROUTING_ARP_IPV4:
-	{
-		uint32_t port_id = key->key.ipv4.port_id;
-
-		/* key */
-		if (port_id >= p->n_ports_out)
-			return -1;
-	}
-	break;
-
-	default:
-		return -1;
-	}
-
-	/* 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_DEFAULT);
-	if (rsp == NULL) {
-		if (new_entry)
-			rte_free(entry);
-		return -1;
-	}
-
-	/* Read response and write entry */
-	if (rsp->status ||
-		(rsp->entry_ptr == NULL) ||
-		((new_entry == 0) && (rsp->key_found == 0)) ||
-		((new_entry == 1) && (rsp->key_found == 1))) {
-		app_msg_free(app, rsp);
-		if (new_entry)
-			rte_free(entry);
-		return -1;
-	}
-
-	memcpy(&entry->key, key, sizeof(*key));
-	ether_addr_copy(macaddr, &entry->macaddr);
-	entry->entry_ptr = rsp->entry_ptr;
-
-	/* Commit entry */
-	if (new_entry) {
-		TAILQ_INSERT_TAIL(&p->arp_entries, entry, node);
-		p->n_arp_entries++;
-	}
-
-	/* Message buffer free */
-	app_msg_free(app, rsp);
-	return 0;
-}
-
-int
-app_pipeline_routing_delete_arp_entry(struct app_params *app,
-	uint32_t pipeline_id,
-	struct pipeline_routing_arp_key *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;
-
-	/* Check input arguments */
-	if ((app == NULL) ||
-		(key == NULL))
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_routing);
-	if (p == NULL)
-		return -EINVAL;
-
-	switch (key->type) {
-	case PIPELINE_ROUTING_ARP_IPV4:
-	{
-		uint32_t port_id = key->key.ipv4.port_id;
-
-		/* key */
-		if (port_id >= p->n_ports_out)
-			return -1;
-	}
-	break;
-
-	default:
-		return -1;
-	}
-
-	/* 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_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	/* Read response */
-	if (rsp->status || !rsp->key_found) {
-		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;
-}
-
-int
-app_pipeline_routing_add_default_arp_entry(struct app_params *app,
-		uint32_t pipeline_id,
-		uint32_t port_id)
-{
-	struct pipeline_routing *p;
-
-	struct pipeline_routing_arp_add_default_msg_req *req;
-	struct pipeline_routing_arp_add_default_msg_rsp *rsp;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_routing);
-	if (p == NULL)
-		return -1;
-
-	if (port_id >= p->n_ports_out)
-		return -1;
-
-	/* 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_DEFAULT);
-	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;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_routing);
-	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_DEFAULT);
-	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;
-}
-
-int
-app_pipeline_routing_set_macaddr(struct app_params *app,
-	uint32_t pipeline_id)
-{
-	struct app_pipeline_params *p;
-	struct pipeline_routing_set_macaddr_msg_req *req;
-	struct pipeline_routing_set_macaddr_msg_rsp *rsp;
-	uint32_t port_id;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -EINVAL;
-
-	APP_PARAM_FIND_BY_ID(app->pipeline_params, "PIPELINE", pipeline_id, p);
-	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_SET_MACADDR;
-
-	memset(req->macaddr, 0, sizeof(req->macaddr));
-	for (port_id = 0; port_id < p->n_pktq_out; port_id++) {
-		struct app_link_params *link;
-
-		link = app_pipeline_track_pktq_out_to_link(app,
-			pipeline_id,
-			port_id);
-		if (link)
-			req->macaddr[port_id] = link->mac_addr;
-	}
-
-	/* Send request and wait for response */
-	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL)
-		return -ETIMEDOUT;
-
-	/* Read response and write entry */
-	if (rsp->status) {
-		app_msg_free(app, rsp);
-		return rsp->status;
-	}
-
-	/* Free response */
-	app_msg_free(app, rsp);
-
-	return 0;
-}
-
-/*
- * route
- *
- * route add (ARP = ON/OFF, MPLS = ON/OFF, QINQ = ON/OFF):
- *    p <pipelineid> route add <ipaddr> <depth> port <portid> ether <nhmacaddr>
- *    p <pipelineid> route add <ipaddr> <depth> port <portid> ether <nhipaddr>
- *    p <pipelineid> route add <ipaddr> <depth> port <portid> ether <nhmacaddr> qinq <svlan> <cvlan>
- *    p <pipelineid> route add <ipaddr> <depth> port <portid> ether <nhipaddr> qinq <svlan> <cvlan>
- *    p <pipelineid> route add <ipaddr> <depth> port <portid> ether <nhmacaddr> mpls <mpls labels>
- *    p <pipelineid> route add <ipaddr> <depth> port <portid> ether <nhipaddr> mpls <mpls labels>
- *
- * route add default:
- *    p <pipelineid> route add default <portid>
- *
- * route del:
- *    p <pipelineid> route del <ipaddr> <depth>
- *
- * route del default:
- *    p <pipelineid> route del default
- *
- * route ls:
- *    p <pipelineid> route ls
- */
-
-struct cmd_route_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t p;
-	cmdline_fixed_string_t route_string;
-	cmdline_multi_string_t multi_string;
-};
-
-static void
-cmd_route_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_route_result *params = parsed_result;
-	struct app_params *app = data;
-
-	char *tokens[16];
-	uint32_t n_tokens = RTE_DIM(tokens);
-	int status;
-
-	status = parse_tokenize_string(params->multi_string, tokens, &n_tokens);
-	if (status != 0) {
-		printf(CMD_MSG_TOO_MANY_ARGS, "route");
-		return;
-	}
-
-	/* route add */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "add") == 0) &&
-		strcmp(tokens[1], "default")) {
-		struct pipeline_routing_route_key key;
-		struct pipeline_routing_route_data route_data;
-		struct in_addr ipv4, nh_ipv4;
-		struct ether_addr mac_addr;
-		uint32_t depth, port_id, svlan, cvlan, i;
-		uint32_t mpls_labels[PIPELINE_ROUTING_MPLS_LABELS_MAX];
-		uint32_t n_labels = RTE_DIM(mpls_labels);
-
-		memset(&key, 0, sizeof(key));
-		memset(&route_data, 0, sizeof(route_data));
-
-		if (n_tokens < 7) {
-			printf(CMD_MSG_NOT_ENOUGH_ARGS, "route add");
-			return;
-		}
-
-		if (parse_ipv4_addr(tokens[1], &ipv4)) {
-			printf(CMD_MSG_INVALID_ARG, "ipaddr");
-			return;
-		}
-
-		if (parser_read_uint32(&depth, tokens[2])) {
-			printf(CMD_MSG_INVALID_ARG, "depth");
-			return;
-		}
-
-		if (strcmp(tokens[3], "port")) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "port");
-			return;
-		}
-
-		if (parser_read_uint32(&port_id, tokens[4])) {
-			printf(CMD_MSG_INVALID_ARG, "portid");
-			return;
-		}
-
-		if (strcmp(tokens[5], "ether")) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "ether");
-			return;
-		}
-
-		if (parse_mac_addr(tokens[6], &mac_addr)) {
-			if (parse_ipv4_addr(tokens[6], &nh_ipv4)) {
-				printf(CMD_MSG_INVALID_ARG, "nhmacaddr or nhipaddr");
-				return;
-			}
-
-			route_data.flags |= PIPELINE_ROUTING_ROUTE_ARP;
-		}
-
-		if (n_tokens > 7) {
-			if (strcmp(tokens[7], "mpls") == 0) {
-				if (n_tokens != 9) {
-					printf(CMD_MSG_MISMATCH_ARGS, "route add mpls");
-					return;
-				}
-
-				if (parse_mpls_labels(tokens[8], mpls_labels, &n_labels)) {
-					printf(CMD_MSG_INVALID_ARG, "mpls labels");
-					return;
-				}
-
-				route_data.flags |= PIPELINE_ROUTING_ROUTE_MPLS;
-			} else if (strcmp(tokens[7], "qinq") == 0) {
-				if (n_tokens != 10) {
-					printf(CMD_MSG_MISMATCH_ARGS, "route add qinq");
-					return;
-				}
-
-				if (parser_read_uint32(&svlan, tokens[8])) {
-					printf(CMD_MSG_INVALID_ARG, "svlan");
-					return;
-				}
-				if (parser_read_uint32(&cvlan, tokens[9])) {
-					printf(CMD_MSG_INVALID_ARG, "cvlan");
-					return;
-				}
-
-				route_data.flags |= PIPELINE_ROUTING_ROUTE_QINQ;
-			} else {
-				printf(CMD_MSG_ARG_NOT_FOUND, "mpls or qinq");
-				return;
-			}
-		}
-
-		switch (route_data.flags) {
-		case 0:
-			route_data.port_id = port_id;
-			route_data.ethernet.macaddr = mac_addr;
-			break;
-
-		case PIPELINE_ROUTING_ROUTE_ARP:
-			route_data.port_id = port_id;
-			route_data.ethernet.ip = rte_be_to_cpu_32(nh_ipv4.s_addr);
-			break;
-
-		case PIPELINE_ROUTING_ROUTE_MPLS:
-			route_data.port_id = port_id;
-			route_data.ethernet.macaddr = mac_addr;
-			for (i = 0; i < n_labels; i++)
-				route_data.l2.mpls.labels[i] = mpls_labels[i];
-			route_data.l2.mpls.n_labels = n_labels;
-			break;
-
-		case PIPELINE_ROUTING_ROUTE_MPLS | PIPELINE_ROUTING_ROUTE_ARP:
-			route_data.port_id = port_id;
-			route_data.ethernet.ip = rte_be_to_cpu_32(nh_ipv4.s_addr);
-			for (i = 0; i < n_labels; i++)
-				route_data.l2.mpls.labels[i] = mpls_labels[i];
-			route_data.l2.mpls.n_labels = n_labels;
-			break;
-
-		case PIPELINE_ROUTING_ROUTE_QINQ:
-			route_data.port_id = port_id;
-			route_data.ethernet.macaddr = mac_addr;
-			route_data.l2.qinq.svlan = svlan;
-			route_data.l2.qinq.cvlan = cvlan;
-			break;
-
-		case PIPELINE_ROUTING_ROUTE_QINQ | PIPELINE_ROUTING_ROUTE_ARP:
-		default:
-			route_data.port_id = port_id;
-			route_data.ethernet.ip = rte_be_to_cpu_32(nh_ipv4.s_addr);
-			route_data.l2.qinq.svlan = svlan;
-			route_data.l2.qinq.cvlan = cvlan;
-			break;
-		}
-
-		key.type = PIPELINE_ROUTING_ROUTE_IPV4;
-		key.key.ipv4.ip = rte_be_to_cpu_32(ipv4.s_addr);
-		key.key.ipv4.depth = depth;
-
-		status = app_pipeline_routing_add_route(app,
-			params->p,
-			&key,
-			&route_data);
-		if (status != 0)
-			printf(CMD_MSG_FAIL, "route add");
-
-		return;
-	} /* route add */
-
-	/* route add default */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "add") == 0) &&
-		(strcmp(tokens[1], "default") == 0)) {
-		uint32_t port_id;
-
-		if (n_tokens != 3) {
-			printf(CMD_MSG_MISMATCH_ARGS, "route add default");
-			return;
-		}
-
-		if (parser_read_uint32(&port_id, tokens[2])) {
-			printf(CMD_MSG_INVALID_ARG, "portid");
-			return;
-		}
-
-		status = app_pipeline_routing_add_default_route(app,
-			params->p,
-			port_id);
-		if (status != 0)
-			printf(CMD_MSG_FAIL, "route add default");
-
-		return;
-	} /* route add default */
-
-	/* route del*/
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "del") == 0) &&
-		strcmp(tokens[1], "default")) {
-		struct pipeline_routing_route_key key;
-		struct in_addr ipv4;
-		uint32_t depth;
-
-		memset(&key, 0, sizeof(key));
-
-		if (n_tokens != 3) {
-			printf(CMD_MSG_MISMATCH_ARGS, "route del");
-			return;
-		}
-
-		if (parse_ipv4_addr(tokens[1], &ipv4)) {
-			printf(CMD_MSG_INVALID_ARG, "ipaddr");
-			return;
-		}
-
-		if (parser_read_uint32(&depth, tokens[2])) {
-			printf(CMD_MSG_INVALID_ARG, "depth");
-			return;
-		}
-
-		key.type = PIPELINE_ROUTING_ROUTE_IPV4;
-		key.key.ipv4.ip = rte_be_to_cpu_32(ipv4.s_addr);
-		key.key.ipv4.depth = depth;
-
-		status = app_pipeline_routing_delete_route(app, params->p, &key);
-		if (status != 0)
-			printf(CMD_MSG_FAIL, "route del");
-
-		return;
-	} /* route del */
-
-	/* route del default */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "del") == 0) &&
-		(strcmp(tokens[1], "default") == 0)) {
-		if (n_tokens != 2) {
-			printf(CMD_MSG_MISMATCH_ARGS, "route del default");
-			return;
-		}
-
-		status = app_pipeline_routing_delete_default_route(app,
-			params->p);
-		if (status != 0)
-			printf(CMD_MSG_FAIL, "route del default");
-
-		return;
-	} /* route del default */
-
-	/* route ls */
-	if ((n_tokens >= 1) && (strcmp(tokens[0], "ls") == 0)) {
-		if (n_tokens != 1) {
-			printf(CMD_MSG_MISMATCH_ARGS, "route ls");
-			return;
-		}
-
-		status = app_pipeline_routing_route_ls(app, params->p);
-		if (status != 0)
-			printf(CMD_MSG_FAIL, "route ls");
-
-		return;
-	} /* route ls */
-
-	printf(CMD_MSG_MISMATCH_ARGS, "route");
-}
-
-static cmdline_parse_token_string_t cmd_route_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_result, p_string, "p");
-
-static cmdline_parse_token_num_t cmd_route_p =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_result, p, UINT32);
-
-static cmdline_parse_token_string_t cmd_route_route_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_result, route_string, "route");
-
-static cmdline_parse_token_string_t cmd_route_multi_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_result, multi_string,
-	TOKEN_STRING_MULTI);
-
-static cmdline_parse_inst_t cmd_route = {
-	.f = cmd_route_parsed,
-	.data = NULL,
-	.help_str = "route add / add default / del / del default / ls",
-	.tokens = {
-		(void *)&cmd_route_p_string,
-		(void *)&cmd_route_p,
-		(void *)&cmd_route_route_string,
-		(void *)&cmd_route_multi_string,
-		NULL,
-	},
-};
-
-/*
- * arp
- *
- * arp add:
- *    p <pipelineid> arp add <portid> <ipaddr> <macaddr>
- *
- * arp add default:
- *    p <pipelineid> arp add default <portid>
- *
- * arp del:
- *    p <pipelineid> arp del <portid> <ipaddr>
- *
- * arp del default:
- *    p <pipelineid> arp del default
- *
- * arp ls:
- *    p <pipelineid> arp ls
- */
-
-struct cmd_arp_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t p;
-	cmdline_fixed_string_t arp_string;
-	cmdline_multi_string_t multi_string;
-};
-
-static void
-cmd_arp_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_arp_result *params = parsed_result;
-	struct app_params *app = data;
-
-	char *tokens[16];
-	uint32_t n_tokens = RTE_DIM(tokens);
-	int status;
-
-	status = parse_tokenize_string(params->multi_string, tokens, &n_tokens);
-	if (status != 0) {
-		printf(CMD_MSG_TOO_MANY_ARGS, "arp");
-		return;
-	}
-
-	/* arp add */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "add") == 0) &&
-		strcmp(tokens[1], "default")) {
-		struct pipeline_routing_arp_key key;
-		struct in_addr ipv4;
-		struct ether_addr mac_addr;
-		uint32_t port_id;
-
-		memset(&key, 0, sizeof(key));
-
-		if (n_tokens != 4) {
-			printf(CMD_MSG_MISMATCH_ARGS, "arp add");
-			return;
-		}
-
-		if (parser_read_uint32(&port_id, tokens[1])) {
-			printf(CMD_MSG_INVALID_ARG, "portid");
-			return;
-		}
-
-		if (parse_ipv4_addr(tokens[2], &ipv4)) {
-			printf(CMD_MSG_INVALID_ARG, "ipaddr");
-			return;
-		}
-
-		if (parse_mac_addr(tokens[3], &mac_addr)) {
-			printf(CMD_MSG_INVALID_ARG, "macaddr");
-			return;
-		}
-
-		key.type = PIPELINE_ROUTING_ARP_IPV4;
-		key.key.ipv4.port_id = port_id;
-		key.key.ipv4.ip = rte_be_to_cpu_32(ipv4.s_addr);
-
-		status = app_pipeline_routing_add_arp_entry(app,
-			params->p,
-			&key,
-			&mac_addr);
-		if (status != 0)
-			printf(CMD_MSG_FAIL, "arp add");
-
-		return;
-	} /* arp add */
-
-	/* arp add default */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "add") == 0) &&
-		(strcmp(tokens[1], "default") == 0)) {
-		uint32_t port_id;
-
-		if (n_tokens != 3) {
-			printf(CMD_MSG_MISMATCH_ARGS, "arp add default");
-			return;
-		}
-
-		if (parser_read_uint32(&port_id, tokens[2])) {
-			printf(CMD_MSG_INVALID_ARG, "portid");
-			return;
-		}
-
-		status = app_pipeline_routing_add_default_arp_entry(app,
-			params->p,
-			port_id);
-		if (status != 0)
-			printf(CMD_MSG_FAIL, "arp add default");
-
-		return;
-	} /* arp add default */
-
-	/* arp del*/
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "del") == 0) &&
-		strcmp(tokens[1], "default")) {
-		struct pipeline_routing_arp_key key;
-		struct in_addr ipv4;
-		uint32_t port_id;
-
-		memset(&key, 0, sizeof(key));
-
-		if (n_tokens != 3) {
-			printf(CMD_MSG_MISMATCH_ARGS, "arp del");
-			return;
-		}
-
-		if (parser_read_uint32(&port_id, tokens[1])) {
-			printf(CMD_MSG_INVALID_ARG, "portid");
-			return;
-		}
-
-		if (parse_ipv4_addr(tokens[2], &ipv4)) {
-			printf(CMD_MSG_INVALID_ARG, "ipaddr");
-			return;
-		}
-
-		key.type = PIPELINE_ROUTING_ARP_IPV4;
-		key.key.ipv4.ip = rte_be_to_cpu_32(ipv4.s_addr);
-		key.key.ipv4.port_id = port_id;
-
-		status = app_pipeline_routing_delete_arp_entry(app,
-			params->p,
-			&key);
-		if (status != 0)
-			printf(CMD_MSG_FAIL, "arp del");
-
-		return;
-	} /* arp del */
-
-	/* arp del default */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "del") == 0) &&
-		(strcmp(tokens[1], "default") == 0)) {
-			if (n_tokens != 2) {
-				printf(CMD_MSG_MISMATCH_ARGS, "arp del default");
-				return;
-			}
-
-			status = app_pipeline_routing_delete_default_arp_entry(app,
-				params->p);
-			if (status != 0)
-				printf(CMD_MSG_FAIL, "arp del default");
-
-			return;
-	} /* arp del default */
-
-	/* arp ls */
-	if ((n_tokens >= 1) && (strcmp(tokens[0], "ls") == 0)) {
-		if (n_tokens != 1) {
-			printf(CMD_MSG_MISMATCH_ARGS, "arp ls");
-			return;
-		}
-
-		status = app_pipeline_routing_arp_ls(app, params->p);
-		if (status != 0)
-			printf(CMD_MSG_FAIL, "arp ls");
-
-		return;
-	} /* arp ls */
-
-	printf(CMD_MSG_FAIL, "arp");
-}
-
-static cmdline_parse_token_string_t cmd_arp_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_result, p_string, "p");
-
-static cmdline_parse_token_num_t cmd_arp_p =
-	TOKEN_NUM_INITIALIZER(struct cmd_arp_result, p, UINT32);
-
-static cmdline_parse_token_string_t cmd_arp_arp_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_result, arp_string, "arp");
-
-static cmdline_parse_token_string_t cmd_arp_multi_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_result, multi_string,
-	TOKEN_STRING_MULTI);
-
-static cmdline_parse_inst_t cmd_arp = {
-	.f = cmd_arp_parsed,
-	.data = NULL,
-	.help_str = "arp add / add default / del / del default / ls",
-	.tokens = {
-		(void *)&cmd_arp_p_string,
-		(void *)&cmd_arp_p,
-		(void *)&cmd_arp_arp_string,
-		(void *)&cmd_arp_multi_string,
-		NULL,
-	},
-};
-
-static cmdline_parse_ctx_t pipeline_cmds[] = {
-	(cmdline_parse_inst_t *)&cmd_route,
-	(cmdline_parse_inst_t *)&cmd_arp,
-	NULL,
-};
-
-static struct pipeline_fe_ops pipeline_routing_fe_ops = {
-	.f_init = app_pipeline_routing_init,
-	.f_post_init = app_pipeline_routing_post_init,
-	.f_free = app_pipeline_routing_free,
-	.f_track = app_pipeline_track_default,
-	.cmds = pipeline_cmds,
-};
-
-struct pipeline_type pipeline_routing = {
-	.name = "ROUTING",
-	.be_ops = &pipeline_routing_be_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
deleted file mode 100644
index f249295..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_routing.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#ifndef __INCLUDE_PIPELINE_ROUTING_H__
-#define __INCLUDE_PIPELINE_ROUTING_H__
-
-#include "pipeline.h"
-#include "pipeline_routing_be.h"
-
-/*
- * Route
- */
-
-int
-app_pipeline_routing_add_route(struct app_params *app,
-	uint32_t pipeline_id,
-	struct pipeline_routing_route_key *key,
-	struct pipeline_routing_route_data *data);
-
-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);
-
-/*
- * SETTINGS
- */
-int
-app_pipeline_routing_set_macaddr(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_be.c b/examples/ip_pipeline/pipeline/pipeline_routing_be.c
deleted file mode 100644
index 6258a1a..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_routing_be.c
+++ /dev/null
@@ -1,1966 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2016 Intel Corporation
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <rte_common.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_routing_be.h"
-#include "pipeline_actions_common.h"
-#include "parser.h"
-#include "hash_func.h"
-
-#define MPLS_LABEL(label, exp, s, ttl)					\
-	(((((uint64_t) (label)) & 0xFFFFFLLU) << 12) |		\
-	((((uint64_t) (exp)) & 0x7LLU) << 9) |				\
-	((((uint64_t) (s)) & 0x1LLU) << 8) |				\
-	(((uint64_t) (ttl)) & 0xFFLU))
-
-#define RTE_SCHED_PORT_HIERARCHY(subport, pipe,		\
-	traffic_class, queue, color)				\
-	((((uint64_t) (queue)) & 0x3) |                \
-	((((uint64_t) (traffic_class)) & 0x3) << 2) |  \
-	((((uint64_t) (color)) & 0x3) << 4) |          \
-	((((uint64_t) (subport)) & 0xFFFF) << 16) |    \
-	((((uint64_t) (pipe)) & 0xFFFFFFFF) << 32))
-
-
-/* Network Byte Order (NBO) */
-#define SLAB_NBO_MACADDRSRC_ETHERTYPE(macaddr, ethertype)	\
-	(((uint64_t) macaddr) | (((uint64_t) rte_cpu_to_be_16(ethertype)) << 48))
-
-#ifndef PIPELINE_ROUTING_LPM_TABLE_NUMBER_TABLE8s
-#define PIPELINE_ROUTING_LPM_TABLE_NUMBER_TABLE8s 256
-#endif
-
-struct pipeline_routing {
-	struct pipeline p;
-	struct pipeline_routing_params params;
-	pipeline_msg_req_handler custom_handlers[PIPELINE_ROUTING_MSG_REQS];
-	uint64_t macaddr[PIPELINE_MAX_PORT_OUT];
-} __rte_cache_aligned;
-
-/*
- * Message handlers
- */
-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 void *
-pipeline_routing_msg_req_set_macaddr_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,
-	[PIPELINE_ROUTING_MSG_REQ_SET_MACADDR] =
-		pipeline_routing_msg_req_set_macaddr_handler,
-};
-
-/*
- * Routing table
- */
-struct routing_table_entry {
-	struct rte_pipeline_table_entry head;
-	uint32_t flags;
-	uint32_t port_id; /* Output port ID */
-	uint32_t ip; /* Next hop IP address (only valid for remote routes) */
-
-	/* ether_l2 */
-	uint16_t data_offset;
-	uint16_t ether_l2_length;
-	uint64_t slab[4];
-	uint16_t slab_offset[4];
-};
-
-struct layout {
-	uint16_t a;
-	uint32_t b;
-	uint16_t c;
-} __attribute__((__packed__));
-
-#define MACADDR_DST_WRITE(slab_ptr, slab)			\
-{								\
-	struct layout *dst = (struct layout *) (slab_ptr);	\
-	struct layout *src = (struct layout *) &(slab);		\
-								\
-	dst->b = src->b;					\
-	dst->c = src->c;					\
-}
-
-static __rte_always_inline void
-pkt_work_routing(
-	struct rte_mbuf *pkt,
-	struct rte_pipeline_table_entry *table_entry,
-	void *arg,
-	int arp,
-	int qinq,
-	int qinq_sched,
-	int mpls,
-	int mpls_color_mark)
-{
-	struct pipeline_routing *p_rt = arg;
-
-	struct routing_table_entry *entry =
-		(struct routing_table_entry *) table_entry;
-
-	struct ipv4_hdr *ip = (struct ipv4_hdr *)
-		RTE_MBUF_METADATA_UINT8_PTR(pkt, p_rt->params.ip_hdr_offset);
-
-	enum rte_meter_color pkt_color = (enum rte_meter_color)
-		RTE_MBUF_METADATA_UINT32(pkt, p_rt->params.color_offset);
-
-	struct pipeline_routing_arp_key_ipv4 *arp_key =
-		(struct pipeline_routing_arp_key_ipv4 *)
-		RTE_MBUF_METADATA_UINT8_PTR(pkt, p_rt->params.arp_key_offset);
-
-	uint64_t *slab0_ptr, *slab1_ptr, *slab2_ptr, *slab3_ptr, sched;
-	uint32_t ip_da, nh_ip, port_id;
-	uint16_t total_length, data_offset, ether_l2_length;
-
-	/* Read */
-	total_length = rte_bswap16(ip->total_length);
-	ip_da = ip->dst_addr;
-	data_offset = entry->data_offset;
-	ether_l2_length = entry->ether_l2_length;
-	slab0_ptr = RTE_MBUF_METADATA_UINT64_PTR(pkt, entry->slab_offset[0]);
-	slab1_ptr = RTE_MBUF_METADATA_UINT64_PTR(pkt, entry->slab_offset[1]);
-	slab2_ptr = RTE_MBUF_METADATA_UINT64_PTR(pkt, entry->slab_offset[2]);
-	slab3_ptr = RTE_MBUF_METADATA_UINT64_PTR(pkt, entry->slab_offset[3]);
-
-	if (arp) {
-		port_id = entry->port_id;
-		nh_ip = entry->ip;
-		if (entry->flags & PIPELINE_ROUTING_ROUTE_LOCAL)
-			nh_ip = ip_da;
-	}
-
-	/* Compute */
-	total_length += ether_l2_length;
-
-	if (qinq && qinq_sched) {
-		uint32_t dscp = ip->type_of_service >> 2;
-		uint32_t svlan, cvlan, tc, tc_q;
-
-		if (qinq_sched == 1) {
-			uint64_t slab_qinq = rte_bswap64(entry->slab[0]);
-
-			svlan = (slab_qinq >> 48) & 0xFFF;
-			cvlan = (slab_qinq >> 16) & 0xFFF;
-			tc = (dscp >> 2) & 0x3;
-			tc_q = dscp & 0x3;
-		} else {
-			uint32_t ip_src = rte_bswap32(ip->src_addr);
-
-			svlan = 0;
-			cvlan = (ip_src >> 16) & 0xFFF;
-			tc = (ip_src >> 2) & 0x3;
-			tc_q = ip_src & 0x3;
-		}
-		sched = RTE_SCHED_PORT_HIERARCHY(svlan,
-			cvlan,
-			tc,
-			tc_q,
-			e_RTE_METER_GREEN);
-	}
-
-	/* Write */
-	pkt->data_off = data_offset;
-	pkt->data_len = total_length;
-	pkt->pkt_len = total_length;
-
-	if ((qinq == 0) && (mpls == 0)) {
-		*slab0_ptr = entry->slab[0];
-
-		if (arp == 0)
-			MACADDR_DST_WRITE(slab1_ptr, entry->slab[1]);
-	}
-
-	if (qinq) {
-		*slab0_ptr = entry->slab[0];
-		*slab1_ptr = entry->slab[1];
-
-		if (arp == 0)
-			MACADDR_DST_WRITE(slab2_ptr, entry->slab[2]);
-
-		if (qinq_sched) {
-			pkt->hash.sched.lo = sched & 0xFFFFFFFF;
-			pkt->hash.sched.hi = sched >> 32;
-		}
-	}
-
-	if (mpls) {
-		if (mpls_color_mark) {
-			uint64_t mpls_exp = rte_bswap64(
-				(MPLS_LABEL(0, pkt_color, 0, 0) << 32) |
-				MPLS_LABEL(0, pkt_color, 0, 0));
-
-			*slab0_ptr = entry->slab[0] | mpls_exp;
-			*slab1_ptr = entry->slab[1] | mpls_exp;
-			*slab2_ptr = entry->slab[2];
-		} else {
-			*slab0_ptr = entry->slab[0];
-			*slab1_ptr = entry->slab[1];
-			*slab2_ptr = entry->slab[2];
-		}
-
-		if (arp == 0)
-			MACADDR_DST_WRITE(slab3_ptr, entry->slab[3]);
-	}
-
-	if (arp) {
-		arp_key->port_id = port_id;
-		arp_key->ip = nh_ip;
-	}
-}
-
-static __rte_always_inline void
-pkt4_work_routing(
-	struct rte_mbuf **pkts,
-	struct rte_pipeline_table_entry **table_entries,
-	void *arg,
-	int arp,
-	int qinq,
-	int qinq_sched,
-	int mpls,
-	int mpls_color_mark)
-{
-	struct pipeline_routing *p_rt = arg;
-
-	struct routing_table_entry *entry0 =
-		(struct routing_table_entry *) table_entries[0];
-	struct routing_table_entry *entry1 =
-		(struct routing_table_entry *) table_entries[1];
-	struct routing_table_entry *entry2 =
-		(struct routing_table_entry *) table_entries[2];
-	struct routing_table_entry *entry3 =
-		(struct routing_table_entry *) table_entries[3];
-
-	struct ipv4_hdr *ip0 = (struct ipv4_hdr *)
-		RTE_MBUF_METADATA_UINT8_PTR(pkts[0],
-			p_rt->params.ip_hdr_offset);
-	struct ipv4_hdr *ip1 = (struct ipv4_hdr *)
-		RTE_MBUF_METADATA_UINT8_PTR(pkts[1],
-			p_rt->params.ip_hdr_offset);
-	struct ipv4_hdr *ip2 = (struct ipv4_hdr *)
-		RTE_MBUF_METADATA_UINT8_PTR(pkts[2],
-			p_rt->params.ip_hdr_offset);
-	struct ipv4_hdr *ip3 = (struct ipv4_hdr *)
-		RTE_MBUF_METADATA_UINT8_PTR(pkts[3],
-			p_rt->params.ip_hdr_offset);
-
-	enum rte_meter_color pkt0_color = (enum rte_meter_color)
-		RTE_MBUF_METADATA_UINT32(pkts[0], p_rt->params.color_offset);
-	enum rte_meter_color pkt1_color = (enum rte_meter_color)
-		RTE_MBUF_METADATA_UINT32(pkts[1], p_rt->params.color_offset);
-	enum rte_meter_color pkt2_color = (enum rte_meter_color)
-		RTE_MBUF_METADATA_UINT32(pkts[2], p_rt->params.color_offset);
-	enum rte_meter_color pkt3_color = (enum rte_meter_color)
-		RTE_MBUF_METADATA_UINT32(pkts[3], p_rt->params.color_offset);
-
-	struct pipeline_routing_arp_key_ipv4 *arp_key0 =
-		(struct pipeline_routing_arp_key_ipv4 *)
-		RTE_MBUF_METADATA_UINT8_PTR(pkts[0],
-			p_rt->params.arp_key_offset);
-	struct pipeline_routing_arp_key_ipv4 *arp_key1 =
-		(struct pipeline_routing_arp_key_ipv4 *)
-		RTE_MBUF_METADATA_UINT8_PTR(pkts[1],
-			p_rt->params.arp_key_offset);
-	struct pipeline_routing_arp_key_ipv4 *arp_key2 =
-		(struct pipeline_routing_arp_key_ipv4 *)
-		RTE_MBUF_METADATA_UINT8_PTR(pkts[2],
-			p_rt->params.arp_key_offset);
-	struct pipeline_routing_arp_key_ipv4 *arp_key3 =
-		(struct pipeline_routing_arp_key_ipv4 *)
-		RTE_MBUF_METADATA_UINT8_PTR(pkts[3],
-			p_rt->params.arp_key_offset);
-
-	uint64_t *slab0_ptr0, *slab1_ptr0, *slab2_ptr0, *slab3_ptr0;
-	uint64_t *slab0_ptr1, *slab1_ptr1, *slab2_ptr1, *slab3_ptr1;
-	uint64_t *slab0_ptr2, *slab1_ptr2, *slab2_ptr2, *slab3_ptr2;
-	uint64_t *slab0_ptr3, *slab1_ptr3, *slab2_ptr3, *slab3_ptr3;
-	uint64_t sched0, sched1, sched2, sched3;
-
-	uint32_t ip_da0, nh_ip0, port_id0;
-	uint32_t ip_da1, nh_ip1, port_id1;
-	uint32_t ip_da2, nh_ip2, port_id2;
-	uint32_t ip_da3, nh_ip3, port_id3;
-
-	uint16_t total_length0, data_offset0, ether_l2_length0;
-	uint16_t total_length1, data_offset1, ether_l2_length1;
-	uint16_t total_length2, data_offset2, ether_l2_length2;
-	uint16_t total_length3, data_offset3, ether_l2_length3;
-
-	/* Read */
-	total_length0 = rte_bswap16(ip0->total_length);
-	total_length1 = rte_bswap16(ip1->total_length);
-	total_length2 = rte_bswap16(ip2->total_length);
-	total_length3 = rte_bswap16(ip3->total_length);
-
-	ip_da0 = ip0->dst_addr;
-	ip_da1 = ip1->dst_addr;
-	ip_da2 = ip2->dst_addr;
-	ip_da3 = ip3->dst_addr;
-
-	data_offset0 = entry0->data_offset;
-	data_offset1 = entry1->data_offset;
-	data_offset2 = entry2->data_offset;
-	data_offset3 = entry3->data_offset;
-
-	ether_l2_length0 = entry0->ether_l2_length;
-	ether_l2_length1 = entry1->ether_l2_length;
-	ether_l2_length2 = entry2->ether_l2_length;
-	ether_l2_length3 = entry3->ether_l2_length;
-
-	slab0_ptr0 = RTE_MBUF_METADATA_UINT64_PTR(pkts[0],
-		entry0->slab_offset[0]);
-	slab1_ptr0 = RTE_MBUF_METADATA_UINT64_PTR(pkts[0],
-		entry0->slab_offset[1]);
-	slab2_ptr0 = RTE_MBUF_METADATA_UINT64_PTR(pkts[0],
-		entry0->slab_offset[2]);
-	slab3_ptr0 = RTE_MBUF_METADATA_UINT64_PTR(pkts[0],
-		entry0->slab_offset[3]);
-
-	slab0_ptr1 = RTE_MBUF_METADATA_UINT64_PTR(pkts[1],
-		entry1->slab_offset[0]);
-	slab1_ptr1 = RTE_MBUF_METADATA_UINT64_PTR(pkts[1],
-		entry1->slab_offset[1]);
-	slab2_ptr1 = RTE_MBUF_METADATA_UINT64_PTR(pkts[1],
-		entry1->slab_offset[2]);
-	slab3_ptr1 = RTE_MBUF_METADATA_UINT64_PTR(pkts[1],
-		entry1->slab_offset[3]);
-
-	slab0_ptr2 = RTE_MBUF_METADATA_UINT64_PTR(pkts[2],
-		entry2->slab_offset[0]);
-	slab1_ptr2 = RTE_MBUF_METADATA_UINT64_PTR(pkts[2],
-		entry2->slab_offset[1]);
-	slab2_ptr2 = RTE_MBUF_METADATA_UINT64_PTR(pkts[2],
-		entry2->slab_offset[2]);
-	slab3_ptr2 = RTE_MBUF_METADATA_UINT64_PTR(pkts[2],
-		entry2->slab_offset[3]);
-
-	slab0_ptr3 = RTE_MBUF_METADATA_UINT64_PTR(pkts[3],
-		entry3->slab_offset[0]);
-	slab1_ptr3 = RTE_MBUF_METADATA_UINT64_PTR(pkts[3],
-		entry3->slab_offset[1]);
-	slab2_ptr3 = RTE_MBUF_METADATA_UINT64_PTR(pkts[3],
-		entry3->slab_offset[2]);
-	slab3_ptr3 = RTE_MBUF_METADATA_UINT64_PTR(pkts[3],
-		entry3->slab_offset[3]);
-
-	if (arp) {
-		port_id0 = entry0->port_id;
-		nh_ip0 = entry0->ip;
-		if (entry0->flags & PIPELINE_ROUTING_ROUTE_LOCAL)
-			nh_ip0 = ip_da0;
-
-		port_id1 = entry1->port_id;
-		nh_ip1 = entry1->ip;
-		if (entry1->flags & PIPELINE_ROUTING_ROUTE_LOCAL)
-			nh_ip1 = ip_da1;
-
-		port_id2 = entry2->port_id;
-		nh_ip2 = entry2->ip;
-		if (entry2->flags & PIPELINE_ROUTING_ROUTE_LOCAL)
-			nh_ip2 = ip_da2;
-
-		port_id3 = entry3->port_id;
-		nh_ip3 = entry3->ip;
-		if (entry3->flags & PIPELINE_ROUTING_ROUTE_LOCAL)
-			nh_ip3 = ip_da3;
-	}
-
-	/* Compute */
-	total_length0 += ether_l2_length0;
-	total_length1 += ether_l2_length1;
-	total_length2 += ether_l2_length2;
-	total_length3 += ether_l2_length3;
-
-	if (qinq && qinq_sched) {
-		uint32_t dscp0 = ip0->type_of_service >> 2;
-		uint32_t dscp1 = ip1->type_of_service >> 2;
-		uint32_t dscp2 = ip2->type_of_service >> 2;
-		uint32_t dscp3 = ip3->type_of_service >> 2;
-		uint32_t svlan0, cvlan0, tc0, tc_q0;
-		uint32_t svlan1, cvlan1, tc1, tc_q1;
-		uint32_t svlan2, cvlan2, tc2, tc_q2;
-		uint32_t svlan3, cvlan3, tc3, tc_q3;
-
-		if (qinq_sched == 1) {
-			uint64_t slab_qinq0 = rte_bswap64(entry0->slab[0]);
-			uint64_t slab_qinq1 = rte_bswap64(entry1->slab[0]);
-			uint64_t slab_qinq2 = rte_bswap64(entry2->slab[0]);
-			uint64_t slab_qinq3 = rte_bswap64(entry3->slab[0]);
-
-			svlan0 = (slab_qinq0 >> 48) & 0xFFF;
-			svlan1 = (slab_qinq1 >> 48) & 0xFFF;
-			svlan2 = (slab_qinq2 >> 48) & 0xFFF;
-			svlan3 = (slab_qinq3 >> 48) & 0xFFF;
-
-			cvlan0 = (slab_qinq0 >> 16) & 0xFFF;
-			cvlan1 = (slab_qinq1 >> 16) & 0xFFF;
-			cvlan2 = (slab_qinq2 >> 16) & 0xFFF;
-			cvlan3 = (slab_qinq3 >> 16) & 0xFFF;
-
-			tc0 = (dscp0 >> 2) & 0x3;
-			tc1 = (dscp1 >> 2) & 0x3;
-			tc2 = (dscp2 >> 2) & 0x3;
-			tc3 = (dscp3 >> 2) & 0x3;
-
-			tc_q0 = dscp0 & 0x3;
-			tc_q1 = dscp1 & 0x3;
-			tc_q2 = dscp2 & 0x3;
-			tc_q3 = dscp3 & 0x3;
-		} else {
-			uint32_t ip_src0 = rte_bswap32(ip0->src_addr);
-			uint32_t ip_src1 = rte_bswap32(ip1->src_addr);
-			uint32_t ip_src2 = rte_bswap32(ip2->src_addr);
-			uint32_t ip_src3 = rte_bswap32(ip3->src_addr);
-
-			svlan0 = 0;
-			svlan1 = 0;
-			svlan2 = 0;
-			svlan3 = 0;
-
-			cvlan0 = (ip_src0 >> 16) & 0xFFF;
-			cvlan1 = (ip_src1 >> 16) & 0xFFF;
-			cvlan2 = (ip_src2 >> 16) & 0xFFF;
-			cvlan3 = (ip_src3 >> 16) & 0xFFF;
-
-			tc0 = (ip_src0 >> 2) & 0x3;
-			tc1 = (ip_src1 >> 2) & 0x3;
-			tc2 = (ip_src2 >> 2) & 0x3;
-			tc3 = (ip_src3 >> 2) & 0x3;
-
-			tc_q0 = ip_src0 & 0x3;
-			tc_q1 = ip_src1 & 0x3;
-			tc_q2 = ip_src2 & 0x3;
-			tc_q3 = ip_src3 & 0x3;
-		}
-
-		sched0 = RTE_SCHED_PORT_HIERARCHY(svlan0,
-			cvlan0,
-			tc0,
-			tc_q0,
-			e_RTE_METER_GREEN);
-		sched1 = RTE_SCHED_PORT_HIERARCHY(svlan1,
-			cvlan1,
-			tc1,
-			tc_q1,
-			e_RTE_METER_GREEN);
-		sched2 = RTE_SCHED_PORT_HIERARCHY(svlan2,
-			cvlan2,
-			tc2,
-			tc_q2,
-			e_RTE_METER_GREEN);
-		sched3 = RTE_SCHED_PORT_HIERARCHY(svlan3,
-			cvlan3,
-			tc3,
-			tc_q3,
-			e_RTE_METER_GREEN);
-
-	}
-
-	/* Write */
-	pkts[0]->data_off = data_offset0;
-	pkts[1]->data_off = data_offset1;
-	pkts[2]->data_off = data_offset2;
-	pkts[3]->data_off = data_offset3;
-
-	pkts[0]->data_len = total_length0;
-	pkts[1]->data_len = total_length1;
-	pkts[2]->data_len = total_length2;
-	pkts[3]->data_len = total_length3;
-
-	pkts[0]->pkt_len = total_length0;
-	pkts[1]->pkt_len = total_length1;
-	pkts[2]->pkt_len = total_length2;
-	pkts[3]->pkt_len = total_length3;
-
-	if ((qinq == 0) && (mpls == 0)) {
-		*slab0_ptr0 = entry0->slab[0];
-		*slab0_ptr1 = entry1->slab[0];
-		*slab0_ptr2 = entry2->slab[0];
-		*slab0_ptr3 = entry3->slab[0];
-
-		if (arp == 0) {
-			MACADDR_DST_WRITE(slab1_ptr0, entry0->slab[1]);
-			MACADDR_DST_WRITE(slab1_ptr1, entry1->slab[1]);
-			MACADDR_DST_WRITE(slab1_ptr2, entry2->slab[1]);
-			MACADDR_DST_WRITE(slab1_ptr3, entry3->slab[1]);
-		}
-	}
-
-	if (qinq) {
-		*slab0_ptr0 = entry0->slab[0];
-		*slab0_ptr1 = entry1->slab[0];
-		*slab0_ptr2 = entry2->slab[0];
-		*slab0_ptr3 = entry3->slab[0];
-
-		*slab1_ptr0 = entry0->slab[1];
-		*slab1_ptr1 = entry1->slab[1];
-		*slab1_ptr2 = entry2->slab[1];
-		*slab1_ptr3 = entry3->slab[1];
-
-		if (arp == 0) {
-			MACADDR_DST_WRITE(slab2_ptr0, entry0->slab[2]);
-			MACADDR_DST_WRITE(slab2_ptr1, entry1->slab[2]);
-			MACADDR_DST_WRITE(slab2_ptr2, entry2->slab[2]);
-			MACADDR_DST_WRITE(slab2_ptr3, entry3->slab[2]);
-		}
-
-		if (qinq_sched) {
-			pkts[0]->hash.sched.lo = sched0 & 0xFFFFFFFF;
-			pkts[0]->hash.sched.hi = sched0 >> 32;
-			pkts[1]->hash.sched.lo = sched1 & 0xFFFFFFFF;
-			pkts[1]->hash.sched.hi = sched1 >> 32;
-			pkts[2]->hash.sched.lo = sched2 & 0xFFFFFFFF;
-			pkts[2]->hash.sched.hi = sched2 >> 32;
-			pkts[3]->hash.sched.lo = sched3 & 0xFFFFFFFF;
-			pkts[3]->hash.sched.hi = sched3 >> 32;
-		}
-	}
-
-	if (mpls) {
-		if (mpls_color_mark) {
-			uint64_t mpls_exp0 = rte_bswap64(
-				(MPLS_LABEL(0, pkt0_color, 0, 0) << 32) |
-				MPLS_LABEL(0, pkt0_color, 0, 0));
-			uint64_t mpls_exp1 = rte_bswap64(
-				(MPLS_LABEL(0, pkt1_color, 0, 0) << 32) |
-				MPLS_LABEL(0, pkt1_color, 0, 0));
-			uint64_t mpls_exp2 = rte_bswap64(
-				(MPLS_LABEL(0, pkt2_color, 0, 0) << 32) |
-				MPLS_LABEL(0, pkt2_color, 0, 0));
-			uint64_t mpls_exp3 = rte_bswap64(
-				(MPLS_LABEL(0, pkt3_color, 0, 0) << 32) |
-				MPLS_LABEL(0, pkt3_color, 0, 0));
-
-			*slab0_ptr0 = entry0->slab[0] | mpls_exp0;
-			*slab0_ptr1 = entry1->slab[0] | mpls_exp1;
-			*slab0_ptr2 = entry2->slab[0] | mpls_exp2;
-			*slab0_ptr3 = entry3->slab[0] | mpls_exp3;
-
-			*slab1_ptr0 = entry0->slab[1] | mpls_exp0;
-			*slab1_ptr1 = entry1->slab[1] | mpls_exp1;
-			*slab1_ptr2 = entry2->slab[1] | mpls_exp2;
-			*slab1_ptr3 = entry3->slab[1] | mpls_exp3;
-
-			*slab2_ptr0 = entry0->slab[2];
-			*slab2_ptr1 = entry1->slab[2];
-			*slab2_ptr2 = entry2->slab[2];
-			*slab2_ptr3 = entry3->slab[2];
-		} else {
-			*slab0_ptr0 = entry0->slab[0];
-			*slab0_ptr1 = entry1->slab[0];
-			*slab0_ptr2 = entry2->slab[0];
-			*slab0_ptr3 = entry3->slab[0];
-
-			*slab1_ptr0 = entry0->slab[1];
-			*slab1_ptr1 = entry1->slab[1];
-			*slab1_ptr2 = entry2->slab[1];
-			*slab1_ptr3 = entry3->slab[1];
-
-			*slab2_ptr0 = entry0->slab[2];
-			*slab2_ptr1 = entry1->slab[2];
-			*slab2_ptr2 = entry2->slab[2];
-			*slab2_ptr3 = entry3->slab[2];
-		}
-
-		if (arp == 0) {
-			MACADDR_DST_WRITE(slab3_ptr0, entry0->slab[3]);
-			MACADDR_DST_WRITE(slab3_ptr1, entry1->slab[3]);
-			MACADDR_DST_WRITE(slab3_ptr2, entry2->slab[3]);
-			MACADDR_DST_WRITE(slab3_ptr3, entry3->slab[3]);
-		}
-	}
-
-	if (arp) {
-		arp_key0->port_id = port_id0;
-		arp_key1->port_id = port_id1;
-		arp_key2->port_id = port_id2;
-		arp_key3->port_id = port_id3;
-
-		arp_key0->ip = nh_ip0;
-		arp_key1->ip = nh_ip1;
-		arp_key2->ip = nh_ip2;
-		arp_key3->ip = nh_ip3;
-	}
-}
-
-#define PKT_WORK_ROUTING_ETHERNET(arp)				\
-static inline void						\
-pkt_work_routing_ether_arp##arp(				\
-	struct rte_mbuf *pkt,					\
-	struct rte_pipeline_table_entry *table_entry,		\
-	void *arg)						\
-{								\
-	pkt_work_routing(pkt, table_entry, arg, arp, 0, 0, 0, 0);\
-}
-
-#define PKT4_WORK_ROUTING_ETHERNET(arp)				\
-static inline void						\
-pkt4_work_routing_ether_arp##arp(				\
-	struct rte_mbuf **pkts,					\
-	struct rte_pipeline_table_entry **table_entries,	\
-	void *arg)						\
-{								\
-	pkt4_work_routing(pkts, table_entries, arg, arp, 0, 0, 0, 0);\
-}
-
-#define routing_table_ah_hit_ether(arp)				\
-PKT_WORK_ROUTING_ETHERNET(arp)					\
-PKT4_WORK_ROUTING_ETHERNET(arp)					\
-PIPELINE_TABLE_AH_HIT(routing_table_ah_hit_ether_arp##arp,	\
-	pkt_work_routing_ether_arp##arp,			\
-	pkt4_work_routing_ether_arp##arp)
-
-routing_table_ah_hit_ether(0)
-routing_table_ah_hit_ether(1)
-
-#define PKT_WORK_ROUTING_ETHERNET_QINQ(sched, arp)		\
-static inline void						\
-pkt_work_routing_ether_qinq_sched##sched##_arp##arp(		\
-	struct rte_mbuf *pkt,					\
-	struct rte_pipeline_table_entry *table_entry,		\
-	void *arg)						\
-{								\
-	pkt_work_routing(pkt, table_entry, arg, arp, 1, sched, 0, 0);\
-}
-
-#define PKT4_WORK_ROUTING_ETHERNET_QINQ(sched, arp)		\
-static inline void						\
-pkt4_work_routing_ether_qinq_sched##sched##_arp##arp(		\
-	struct rte_mbuf **pkts,					\
-	struct rte_pipeline_table_entry **table_entries,	\
-	void *arg)						\
-{								\
-	pkt4_work_routing(pkts, table_entries, arg, arp, 1, sched, 0, 0);\
-}
-
-#define routing_table_ah_hit_ether_qinq(sched, arp)		\
-PKT_WORK_ROUTING_ETHERNET_QINQ(sched, arp)			\
-PKT4_WORK_ROUTING_ETHERNET_QINQ(sched, arp)			\
-PIPELINE_TABLE_AH_HIT(routing_table_ah_hit_ether_qinq_sched##sched##_arp##arp,\
-	pkt_work_routing_ether_qinq_sched##sched##_arp##arp,	\
-	pkt4_work_routing_ether_qinq_sched##sched##_arp##arp)
-
-routing_table_ah_hit_ether_qinq(0, 0)
-routing_table_ah_hit_ether_qinq(1, 0)
-routing_table_ah_hit_ether_qinq(2, 0)
-routing_table_ah_hit_ether_qinq(0, 1)
-routing_table_ah_hit_ether_qinq(1, 1)
-routing_table_ah_hit_ether_qinq(2, 1)
-
-#define PKT_WORK_ROUTING_ETHERNET_MPLS(color, arp)		\
-static inline void						\
-pkt_work_routing_ether_mpls_color##color##_arp##arp(		\
-	struct rte_mbuf *pkt,					\
-	struct rte_pipeline_table_entry *table_entry,		\
-	void *arg)						\
-{								\
-	pkt_work_routing(pkt, table_entry, arg, arp, 0, 0, 1, color);\
-}
-
-#define PKT4_WORK_ROUTING_ETHERNET_MPLS(color, arp)		\
-static inline void						\
-pkt4_work_routing_ether_mpls_color##color##_arp##arp(		\
-	struct rte_mbuf **pkts,					\
-	struct rte_pipeline_table_entry **table_entries,	\
-	void *arg)						\
-{								\
-	pkt4_work_routing(pkts, table_entries, arg, arp, 0, 0, 1, color);\
-}
-
-#define routing_table_ah_hit_ether_mpls(color, arp)		\
-PKT_WORK_ROUTING_ETHERNET_MPLS(color, arp)			\
-PKT4_WORK_ROUTING_ETHERNET_MPLS(color, arp)			\
-PIPELINE_TABLE_AH_HIT(routing_table_ah_hit_ether_mpls_color##color##_arp##arp,\
-	pkt_work_routing_ether_mpls_color##color##_arp##arp,	\
-	pkt4_work_routing_ether_mpls_color##color##_arp##arp)
-
-routing_table_ah_hit_ether_mpls(0, 0)
-routing_table_ah_hit_ether_mpls(1, 0)
-routing_table_ah_hit_ether_mpls(0, 1)
-routing_table_ah_hit_ether_mpls(1, 1)
-
-static rte_pipeline_table_action_handler_hit
-get_routing_table_ah_hit(struct pipeline_routing *p)
-{
-	if (p->params.dbg_ah_disable)
-		return NULL;
-
-	switch (p->params.encap) {
-	case PIPELINE_ROUTING_ENCAP_ETHERNET:
-		return (p->params.n_arp_entries) ?
-			routing_table_ah_hit_ether_arp1 :
-			routing_table_ah_hit_ether_arp0;
-
-	case PIPELINE_ROUTING_ENCAP_ETHERNET_QINQ:
-		if (p->params.n_arp_entries)
-			switch (p->params.qinq_sched) {
-			case 0:
-				return routing_table_ah_hit_ether_qinq_sched0_arp1;
-			case 1:
-				return routing_table_ah_hit_ether_qinq_sched1_arp1;
-			case 2:
-				return routing_table_ah_hit_ether_qinq_sched2_arp1;
-			default:
-				return NULL;
-			}
-		 else
-			switch (p->params.qinq_sched) {
-			case 0:
-				return routing_table_ah_hit_ether_qinq_sched0_arp0;
-			case 1:
-				return routing_table_ah_hit_ether_qinq_sched1_arp0;
-			case 2:
-				return routing_table_ah_hit_ether_qinq_sched2_arp0;
-			default:
-				return NULL;
-			}
-
-	case PIPELINE_ROUTING_ENCAP_ETHERNET_MPLS:
-		if (p->params.n_arp_entries)
-			if (p->params.mpls_color_mark)
-				return routing_table_ah_hit_ether_mpls_color1_arp1;
-			else
-				return routing_table_ah_hit_ether_mpls_color0_arp1;
-		else
-			if (p->params.mpls_color_mark)
-				return routing_table_ah_hit_ether_mpls_color1_arp0;
-			else
-				return routing_table_ah_hit_ether_mpls_color0_arp0;
-
-	default:
-		return NULL;
-	}
-}
-
-/*
- * ARP table
- */
-struct arp_table_entry {
-	struct rte_pipeline_table_entry head;
-	uint64_t macaddr;
-};
-
-/**
- * ARP table AH
- */
-static inline void
-pkt_work_arp(
-	struct rte_mbuf *pkt,
-	struct rte_pipeline_table_entry *table_entry,
-	__rte_unused void *arg)
-{
-	struct arp_table_entry *entry = (struct arp_table_entry *) table_entry;
-
-	/* Read */
-	uint64_t macaddr_dst = entry->macaddr;
-	uint64_t *slab_ptr = (uint64_t *) ((char *) pkt->buf_addr +
-		(pkt->data_off - 2));
-
-	/* Compute */
-
-	/* Write */
-	MACADDR_DST_WRITE(slab_ptr, macaddr_dst);
-}
-
-static inline void
-pkt4_work_arp(
-	struct rte_mbuf **pkts,
-	struct rte_pipeline_table_entry **table_entries,
-	__rte_unused void *arg)
-{
-	struct arp_table_entry *entry0 =
-		(struct arp_table_entry *) table_entries[0];
-	struct arp_table_entry *entry1 =
-		(struct arp_table_entry *) table_entries[1];
-	struct arp_table_entry *entry2 =
-		(struct arp_table_entry *) table_entries[2];
-	struct arp_table_entry *entry3 =
-		(struct arp_table_entry *) table_entries[3];
-
-	/* Read */
-	uint64_t macaddr_dst0 = entry0->macaddr;
-	uint64_t macaddr_dst1 = entry1->macaddr;
-	uint64_t macaddr_dst2 = entry2->macaddr;
-	uint64_t macaddr_dst3 = entry3->macaddr;
-
-	uint64_t *slab_ptr0 = (uint64_t *) ((char *) pkts[0]->buf_addr +
-		(pkts[0]->data_off - 2));
-	uint64_t *slab_ptr1 = (uint64_t *) ((char *) pkts[1]->buf_addr +
-		(pkts[1]->data_off - 2));
-	uint64_t *slab_ptr2 = (uint64_t *) ((char *) pkts[2]->buf_addr +
-		(pkts[2]->data_off - 2));
-	uint64_t *slab_ptr3 = (uint64_t *) ((char *) pkts[3]->buf_addr +
-		(pkts[3]->data_off - 2));
-
-	/* Compute */
-
-	/* Write */
-	MACADDR_DST_WRITE(slab_ptr0, macaddr_dst0);
-	MACADDR_DST_WRITE(slab_ptr1, macaddr_dst1);
-	MACADDR_DST_WRITE(slab_ptr2, macaddr_dst2);
-	MACADDR_DST_WRITE(slab_ptr3, macaddr_dst3);
-}
-
-PIPELINE_TABLE_AH_HIT(arp_table_ah_hit,
-	pkt_work_arp,
-	pkt4_work_arp);
-
-static rte_pipeline_table_action_handler_hit
-get_arp_table_ah_hit(struct pipeline_routing *p)
-{
-	if (p->params.dbg_ah_disable)
-		return NULL;
-
-	return arp_table_ah_hit;
-}
-
-/*
- * Argument parsing
- */
-int
-pipeline_routing_parse_args(struct pipeline_routing_params *p,
-	struct pipeline_params *params)
-{
-	uint32_t n_routes_present = 0;
-	uint32_t port_local_dest_present = 0;
-	uint32_t encap_present = 0;
-	uint32_t qinq_sched_present = 0;
-	uint32_t mpls_color_mark_present = 0;
-	uint32_t n_arp_entries_present = 0;
-	uint32_t ip_hdr_offset_present = 0;
-	uint32_t arp_key_offset_present = 0;
-	uint32_t color_offset_present = 0;
-	uint32_t dbg_ah_disable_present = 0;
-	uint32_t i;
-
-	/* default values */
-	p->n_routes = PIPELINE_ROUTING_N_ROUTES_DEFAULT;
-	p->port_local_dest = params->n_ports_out - 1;
-	p->encap = PIPELINE_ROUTING_ENCAP_ETHERNET;
-	p->qinq_sched = 0;
-	p->mpls_color_mark = 0;
-	p->n_arp_entries = 0;
-	p->dbg_ah_disable = 0;
-
-	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) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				n_routes_present == 0, params->name,
-				arg_name);
-			n_routes_present = 1;
-
-			status = parser_read_uint32(&p->n_routes,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL(((status != -EINVAL) &&
-				(p->n_routes != 0)), params->name,
-				arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			continue;
-		}
-		/* port_local_dest */
-		if (strcmp(arg_name, "port_local_dest") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				port_local_dest_present == 0, params->name,
-				arg_name);
-			port_local_dest_present = 1;
-
-			status = parser_read_uint32(&p->port_local_dest,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL(((status == 0) &&
-				(p->port_local_dest < params->n_ports_out)),
-				params->name, arg_name, arg_value);
-
-			continue;
-		}
-
-		/* encap */
-		if (strcmp(arg_name, "encap") == 0) {
-			PIPELINE_PARSE_ERR_DUPLICATE(encap_present == 0,
-				params->name, arg_name);
-			encap_present = 1;
-
-			/* ethernet */
-			if (strcmp(arg_value, "ethernet") == 0) {
-				p->encap = PIPELINE_ROUTING_ENCAP_ETHERNET;
-				continue;
-			}
-
-			/* ethernet_qinq */
-			if (strcmp(arg_value, "ethernet_qinq") == 0) {
-				p->encap = PIPELINE_ROUTING_ENCAP_ETHERNET_QINQ;
-				continue;
-			}
-
-			/* ethernet_mpls */
-			if (strcmp(arg_value, "ethernet_mpls") == 0) {
-				p->encap = PIPELINE_ROUTING_ENCAP_ETHERNET_MPLS;
-				continue;
-			}
-
-			/* any other */
-			PIPELINE_PARSE_ERR_INV_VAL(0, params->name,
-				arg_name, arg_value);
-		}
-
-		/* qinq_sched */
-		if (strcmp(arg_name, "qinq_sched") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				qinq_sched_present == 0, params->name,
-				arg_name);
-			qinq_sched_present = 1;
-
-			status = parser_read_arg_bool(arg_value);
-			if (status == -EINVAL) {
-				if (strcmp(arg_value, "test") == 0) {
-					p->qinq_sched = 2;
-					continue;
-				}
-			} else {
-				p->qinq_sched = status;
-				continue;
-			}
-
-			PIPELINE_PARSE_ERR_INV_VAL(0, params->name,
-				arg_name, arg_value);
-		}
-
-		/* mpls_color_mark */
-		if (strcmp(arg_name, "mpls_color_mark") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				mpls_color_mark_present == 0,
-				params->name, arg_name);
-			mpls_color_mark_present = 1;
-
-
-			status = parser_read_arg_bool(arg_value);
-			if (status >= 0) {
-				p->mpls_color_mark = status;
-				continue;
-			}
-
-			PIPELINE_PARSE_ERR_INV_VAL(0, params->name,
-				arg_name, arg_value);
-		}
-
-		/* n_arp_entries */
-		if (strcmp(arg_name, "n_arp_entries") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				n_arp_entries_present == 0, params->name,
-				arg_name);
-			n_arp_entries_present = 1;
-
-			status = parser_read_uint32(&p->n_arp_entries,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			continue;
-		}
-
-		/* ip_hdr_offset */
-		if (strcmp(arg_name, "ip_hdr_offset") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				ip_hdr_offset_present == 0, params->name,
-				arg_name);
-			ip_hdr_offset_present = 1;
-
-			status = parser_read_uint32(&p->ip_hdr_offset,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			continue;
-		}
-
-		/* arp_key_offset */
-		if (strcmp(arg_name, "arp_key_offset") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				arp_key_offset_present == 0, params->name,
-				arg_name);
-			arp_key_offset_present = 1;
-
-			status = parser_read_uint32(&p->arp_key_offset,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			continue;
-		}
-
-		/* color_offset */
-		if (strcmp(arg_name, "color_offset") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				color_offset_present == 0, params->name,
-				arg_name);
-			color_offset_present = 1;
-
-			status = parser_read_uint32(&p->color_offset,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			continue;
-		}
-
-		/* debug */
-		if (strcmp(arg_name, "dbg_ah_disable") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				dbg_ah_disable_present == 0, params->name,
-				arg_name);
-			dbg_ah_disable_present = 1;
-
-			status = parser_read_arg_bool(arg_value);
-			if (status >= 0) {
-				p->dbg_ah_disable = status;
-				continue;
-			}
-
-			PIPELINE_PARSE_ERR_INV_VAL(0, params->name,
-				arg_name, arg_value);
-
-			continue;
-		}
-
-		/* any other */
-		PIPELINE_PARSE_ERR_INV_ENT(0, params->name, arg_name);
-	}
-
-	/* Check that mandatory arguments are present */
-	PIPELINE_PARSE_ERR_MANDATORY(ip_hdr_offset_present, params->name,
-		"ip_hdr_offset");
-
-	/* Check relations between arguments */
-	switch (p->encap) {
-	case PIPELINE_ROUTING_ENCAP_ETHERNET:
-		PIPELINE_ARG_CHECK((!p->qinq_sched), "Parse error in "
-			"section \"%s\": encap = ethernet, therefore "
-			"qinq_sched = yes/test is not allowed",
-			params->name);
-		PIPELINE_ARG_CHECK((!p->mpls_color_mark), "Parse error "
-			"in section \"%s\": encap = ethernet, therefore "
-			"mpls_color_mark = yes is not allowed",
-			params->name);
-		PIPELINE_ARG_CHECK((!color_offset_present), "Parse error "
-			"in section \"%s\": encap = ethernet, therefore "
-			"color_offset is not allowed",
-			params->name);
-		break;
-
-	case PIPELINE_ROUTING_ENCAP_ETHERNET_QINQ:
-		PIPELINE_ARG_CHECK((!p->mpls_color_mark), "Parse error "
-			"in section \"%s\": encap = ethernet_qinq, "
-			"therefore mpls_color_mark = yes is not allowed",
-			params->name);
-		PIPELINE_ARG_CHECK((!color_offset_present), "Parse error "
-			"in section \"%s\": encap = ethernet_qinq, "
-			"therefore color_offset is not allowed",
-			params->name);
-		break;
-
-	case PIPELINE_ROUTING_ENCAP_ETHERNET_MPLS:
-		PIPELINE_ARG_CHECK((!p->qinq_sched), "Parse error in "
-			"section \"%s\": encap = ethernet_mpls, therefore "
-			"qinq_sched  = yes/test is not allowed",
-			params->name);
-		break;
-	}
-
-	PIPELINE_ARG_CHECK((!(p->n_arp_entries &&
-		(!arp_key_offset_present))), "Parse error in section "
-			"\"%s\": n_arp_entries is set while "
-			"arp_key_offset is not set", params->name);
-
-	PIPELINE_ARG_CHECK((!((p->n_arp_entries == 0) &&
-		arp_key_offset_present)), "Parse error in section "
-			"\"%s\": arp_key_offset present while "
-			"n_arp_entries is not set", params->name);
-
-	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);
-	p->log_level = params->log_level;
-
-	PLOG(p, HIGH, "Routing");
-
-	/* Parse arguments */
-	if (pipeline_routing_parse_args(&p_rt->params, 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,
-			.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 = {
-			.name = p->name,
-			.n_rules = p_rt->params.n_routes,
-			.number_tbl8s = PIPELINE_ROUTING_LPM_TABLE_NUMBER_TABLE8s,
-			.flags = 0,
-			.entry_unique_size = sizeof(struct routing_table_entry),
-			.offset = p_rt->params.ip_hdr_offset +
-				__builtin_offsetof(struct ipv4_hdr, dst_addr),
-		};
-
-		struct rte_pipeline_table_params table_params = {
-				.ops = &rte_table_lpm_ops,
-				.arg_create = &table_lpm_params,
-				.f_action_hit = get_routing_table_ah_hit(p_rt),
-				.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->params.n_arp_entries) {
-		struct rte_table_hash_params table_arp_params = {
-			.name = p->name,
-			.key_size = 8,
-			.key_offset = p_rt->params.arp_key_offset,
-			.key_mask = NULL,
-			.n_keys = p_rt->params.n_arp_entries,
-			.n_buckets =
-				rte_align32pow2(p_rt->params.n_arp_entries / 4),
-			.f_hash = hash_default_key8,
-			.seed = 0,
-		};
-
-		struct rte_pipeline_table_params table_params = {
-			.ops = &rte_table_hash_key8_ext_ops,
-			.arg_create = &table_arp_params,
-			.f_action_hit = get_arp_table_ah_hit(p_rt),
-			.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_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 *p_rt = (struct pipeline_routing *) p;
-	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_arp0 = {
-		.head = {
-			.action = RTE_PIPELINE_ACTION_PORT,
-			{.port_id = p->port_out_id[req->data.port_id]},
-		},
-
-		.flags = req->data.flags,
-		.port_id = req->data.port_id,
-		.ip = 0,
-		.data_offset = 0,
-		.ether_l2_length = 0,
-		.slab = {0},
-		.slab_offset = {0},
-	};
-
-	struct routing_table_entry entry_arp1 = {
-		.head = {
-			.action = RTE_PIPELINE_ACTION_TABLE,
-			{.table_id = p->table_id[1]},
-		},
-
-		.flags = req->data.flags,
-		.port_id = req->data.port_id,
-		.ip = rte_bswap32(req->data.ethernet.ip),
-		.data_offset = 0,
-		.ether_l2_length = 0,
-		.slab = {0},
-		.slab_offset = {0},
-	};
-
-	struct rte_pipeline_table_entry *entry = (p_rt->params.n_arp_entries) ?
-		(struct rte_pipeline_table_entry *) &entry_arp1 :
-		(struct rte_pipeline_table_entry *) &entry_arp0;
-
-	if ((req->key.type != PIPELINE_ROUTING_ROUTE_IPV4) ||
-		((p_rt->params.n_arp_entries == 0) &&
-			(req->data.flags & PIPELINE_ROUTING_ROUTE_ARP)) ||
-		(p_rt->params.n_arp_entries &&
-			((req->data.flags & PIPELINE_ROUTING_ROUTE_ARP) == 0)) ||
-		((p_rt->params.encap != PIPELINE_ROUTING_ENCAP_ETHERNET_QINQ) &&
-			(req->data.flags & PIPELINE_ROUTING_ROUTE_QINQ)) ||
-		((p_rt->params.encap == PIPELINE_ROUTING_ENCAP_ETHERNET_QINQ) &&
-			((req->data.flags & PIPELINE_ROUTING_ROUTE_QINQ) == 0)) ||
-		((p_rt->params.encap != PIPELINE_ROUTING_ENCAP_ETHERNET_MPLS) &&
-			(req->data.flags & PIPELINE_ROUTING_ROUTE_MPLS)) ||
-		((p_rt->params.encap == PIPELINE_ROUTING_ENCAP_ETHERNET_MPLS) &&
-			((req->data.flags & PIPELINE_ROUTING_ROUTE_MPLS) == 0))) {
-		rsp->status = -1;
-		return rsp;
-	}
-
-	/* Ether - ARP off */
-	if ((p_rt->params.encap == PIPELINE_ROUTING_ENCAP_ETHERNET) &&
-		(p_rt->params.n_arp_entries == 0)) {
-		uint64_t macaddr_src = p_rt->macaddr[req->data.port_id];
-		uint64_t macaddr_dst;
-		uint64_t ethertype = ETHER_TYPE_IPv4;
-
-		macaddr_dst = *((uint64_t *)&(req->data.ethernet.macaddr));
-		macaddr_dst = rte_bswap64(macaddr_dst << 16);
-
-		entry_arp0.slab[0] =
-			SLAB_NBO_MACADDRSRC_ETHERTYPE(macaddr_src, ethertype);
-		entry_arp0.slab_offset[0] = p_rt->params.ip_hdr_offset - 8;
-
-		entry_arp0.slab[1] = rte_bswap64(macaddr_dst);
-		entry_arp0.slab_offset[1] = p_rt->params.ip_hdr_offset - 2 * 8;
-
-		entry_arp0.data_offset = entry_arp0.slab_offset[1] + 2
-			- sizeof(struct rte_mbuf);
-		entry_arp0.ether_l2_length = 14;
-	}
-
-	/* Ether - ARP on */
-	if ((p_rt->params.encap == PIPELINE_ROUTING_ENCAP_ETHERNET) &&
-		p_rt->params.n_arp_entries) {
-		uint64_t macaddr_src = p_rt->macaddr[req->data.port_id];
-		uint64_t ethertype = ETHER_TYPE_IPv4;
-
-		entry_arp1.slab[0] =
-			SLAB_NBO_MACADDRSRC_ETHERTYPE(macaddr_src, ethertype);
-		entry_arp1.slab_offset[0] = p_rt->params.ip_hdr_offset - 8;
-
-		entry_arp1.data_offset = entry_arp1.slab_offset[0] - 6
-			- sizeof(struct rte_mbuf);
-		entry_arp1.ether_l2_length = 14;
-	}
-
-	/* Ether QinQ - ARP off */
-	if ((p_rt->params.encap == PIPELINE_ROUTING_ENCAP_ETHERNET_QINQ) &&
-		(p_rt->params.n_arp_entries == 0)) {
-		uint64_t macaddr_src = p_rt->macaddr[req->data.port_id];
-		uint64_t macaddr_dst;
-		uint64_t ethertype_ipv4 = ETHER_TYPE_IPv4;
-		uint64_t ethertype_vlan = 0x8100;
-		uint64_t ethertype_qinq = 0x9100;
-		uint64_t svlan = req->data.l2.qinq.svlan;
-		uint64_t cvlan = req->data.l2.qinq.cvlan;
-
-		macaddr_dst = *((uint64_t *)&(req->data.ethernet.macaddr));
-		macaddr_dst = rte_bswap64(macaddr_dst << 16);
-
-		entry_arp0.slab[0] = rte_bswap64((svlan << 48) |
-			(ethertype_vlan << 32) |
-			(cvlan << 16) |
-			ethertype_ipv4);
-		entry_arp0.slab_offset[0] = p_rt->params.ip_hdr_offset - 8;
-
-		entry_arp0.slab[1] =
-			SLAB_NBO_MACADDRSRC_ETHERTYPE(macaddr_src, ethertype_qinq);
-		entry_arp0.slab_offset[1] = p_rt->params.ip_hdr_offset - 2 * 8;
-
-		entry_arp0.slab[2] = rte_bswap64(macaddr_dst);
-		entry_arp0.slab_offset[2] = p_rt->params.ip_hdr_offset - 3 * 8;
-
-		entry_arp0.data_offset = entry_arp0.slab_offset[2] + 2
-			- sizeof(struct rte_mbuf);
-		entry_arp0.ether_l2_length = 22;
-	}
-
-	/* Ether QinQ - ARP on */
-	if ((p_rt->params.encap == PIPELINE_ROUTING_ENCAP_ETHERNET_QINQ) &&
-		p_rt->params.n_arp_entries) {
-		uint64_t macaddr_src = p_rt->macaddr[req->data.port_id];
-		uint64_t ethertype_ipv4 = ETHER_TYPE_IPv4;
-		uint64_t ethertype_vlan = 0x8100;
-		uint64_t ethertype_qinq = 0x9100;
-		uint64_t svlan = req->data.l2.qinq.svlan;
-		uint64_t cvlan = req->data.l2.qinq.cvlan;
-
-		entry_arp1.slab[0] = rte_bswap64((svlan << 48) |
-			(ethertype_vlan << 32) |
-			(cvlan << 16) |
-			ethertype_ipv4);
-		entry_arp1.slab_offset[0] = p_rt->params.ip_hdr_offset - 8;
-
-		entry_arp1.slab[1] =
-			SLAB_NBO_MACADDRSRC_ETHERTYPE(macaddr_src, ethertype_qinq);
-		entry_arp1.slab_offset[1] = p_rt->params.ip_hdr_offset - 2 * 8;
-
-		entry_arp1.data_offset = entry_arp1.slab_offset[1] - 6
-			- sizeof(struct rte_mbuf);
-		entry_arp1.ether_l2_length = 22;
-	}
-
-	/* Ether MPLS - ARP off */
-	if ((p_rt->params.encap == PIPELINE_ROUTING_ENCAP_ETHERNET_MPLS) &&
-		(p_rt->params.n_arp_entries == 0)) {
-		uint64_t macaddr_src = p_rt->macaddr[req->data.port_id];
-		uint64_t macaddr_dst;
-		uint64_t ethertype_mpls = 0x8847;
-
-		uint64_t label0 = req->data.l2.mpls.labels[0];
-		uint64_t label1 = req->data.l2.mpls.labels[1];
-		uint64_t label2 = req->data.l2.mpls.labels[2];
-		uint64_t label3 = req->data.l2.mpls.labels[3];
-		uint32_t n_labels = req->data.l2.mpls.n_labels;
-
-		macaddr_dst = *((uint64_t *)&(req->data.ethernet.macaddr));
-		macaddr_dst = rte_bswap64(macaddr_dst << 16);
-
-		switch (n_labels) {
-		case 1:
-			entry_arp0.slab[0] = 0;
-			entry_arp0.slab_offset[0] =
-				p_rt->params.ip_hdr_offset - 8;
-
-			entry_arp0.slab[1] = rte_bswap64(
-				MPLS_LABEL(label0, 0, 1, 0));
-			entry_arp0.slab_offset[1] =
-				p_rt->params.ip_hdr_offset - 8;
-			break;
-
-		case 2:
-			entry_arp0.slab[0] = 0;
-			entry_arp0.slab_offset[0] =
-				p_rt->params.ip_hdr_offset - 8;
-
-			entry_arp0.slab[1] = rte_bswap64(
-				(MPLS_LABEL(label0, 0, 0, 0) << 32) |
-				MPLS_LABEL(label1, 0, 1, 0));
-			entry_arp0.slab_offset[1] =
-				p_rt->params.ip_hdr_offset - 8;
-			break;
-
-		case 3:
-			entry_arp0.slab[0] = rte_bswap64(
-				(MPLS_LABEL(label1, 0, 0, 0) << 32) |
-				MPLS_LABEL(label2, 0, 1, 0));
-			entry_arp0.slab_offset[0] =
-				p_rt->params.ip_hdr_offset - 8;
-
-			entry_arp0.slab[1] = rte_bswap64(
-				MPLS_LABEL(label0, 0, 0, 0));
-			entry_arp0.slab_offset[1] =
-				p_rt->params.ip_hdr_offset - 2 * 8;
-			break;
-
-		case 4:
-			entry_arp0.slab[0] = rte_bswap64(
-				(MPLS_LABEL(label2, 0, 0, 0) << 32) |
-				MPLS_LABEL(label3, 0, 1, 0));
-			entry_arp0.slab_offset[0] =
-				p_rt->params.ip_hdr_offset - 8;
-
-			entry_arp0.slab[1] = rte_bswap64(
-				(MPLS_LABEL(label0, 0, 0, 0) << 32) |
-				MPLS_LABEL(label1, 0, 0, 0));
-			entry_arp0.slab_offset[1] =
-				p_rt->params.ip_hdr_offset - 2 * 8;
-			break;
-
-		default:
-			rsp->status = -1;
-			return rsp;
-		}
-
-		entry_arp0.slab[2] =
-			SLAB_NBO_MACADDRSRC_ETHERTYPE(macaddr_src, ethertype_mpls);
-		entry_arp0.slab_offset[2] = p_rt->params.ip_hdr_offset -
-			(n_labels * 4 + 8);
-
-		entry_arp0.slab[3] = rte_bswap64(macaddr_dst);
-		entry_arp0.slab_offset[3] = p_rt->params.ip_hdr_offset -
-			(n_labels * 4 + 2 * 8);
-
-		entry_arp0.data_offset = entry_arp0.slab_offset[3] + 2
-			- sizeof(struct rte_mbuf);
-		entry_arp0.ether_l2_length = n_labels * 4 + 14;
-	}
-
-	/* Ether MPLS - ARP on */
-	if ((p_rt->params.encap == PIPELINE_ROUTING_ENCAP_ETHERNET_MPLS) &&
-		p_rt->params.n_arp_entries) {
-		uint64_t macaddr_src = p_rt->macaddr[req->data.port_id];
-		uint64_t ethertype_mpls = 0x8847;
-
-		uint64_t label0 = req->data.l2.mpls.labels[0];
-		uint64_t label1 = req->data.l2.mpls.labels[1];
-		uint64_t label2 = req->data.l2.mpls.labels[2];
-		uint64_t label3 = req->data.l2.mpls.labels[3];
-		uint32_t n_labels = req->data.l2.mpls.n_labels;
-
-		switch (n_labels) {
-		case 1:
-			entry_arp1.slab[0] = 0;
-			entry_arp1.slab_offset[0] =
-				p_rt->params.ip_hdr_offset - 8;
-
-			entry_arp1.slab[1] = rte_bswap64(
-				MPLS_LABEL(label0, 0, 1, 0));
-			entry_arp1.slab_offset[1] =
-				p_rt->params.ip_hdr_offset - 8;
-			break;
-
-		case 2:
-			entry_arp1.slab[0] = 0;
-			entry_arp1.slab_offset[0] =
-				p_rt->params.ip_hdr_offset - 8;
-
-			entry_arp1.slab[1] = rte_bswap64(
-				(MPLS_LABEL(label0, 0, 0, 0) << 32) |
-				MPLS_LABEL(label1, 0, 1, 0));
-			entry_arp1.slab_offset[1] =
-				p_rt->params.ip_hdr_offset - 8;
-			break;
-
-		case 3:
-			entry_arp1.slab[0] = rte_bswap64(
-				(MPLS_LABEL(label1, 0, 0, 0) << 32) |
-				MPLS_LABEL(label2, 0, 1, 0));
-			entry_arp1.slab_offset[0] =
-				p_rt->params.ip_hdr_offset - 8;
-
-			entry_arp1.slab[1] = rte_bswap64(
-				MPLS_LABEL(label0, 0, 0, 0));
-			entry_arp1.slab_offset[1] =
-				p_rt->params.ip_hdr_offset - 2 * 8;
-			break;
-
-		case 4:
-			entry_arp1.slab[0] = rte_bswap64(
-				(MPLS_LABEL(label2, 0, 0, 0) << 32) |
-				MPLS_LABEL(label3, 0, 1, 0));
-			entry_arp1.slab_offset[0] =
-				p_rt->params.ip_hdr_offset - 8;
-
-			entry_arp1.slab[1] = rte_bswap64(
-				(MPLS_LABEL(label0, 0, 0, 0) << 32) |
-				MPLS_LABEL(label1, 0, 0, 0));
-			entry_arp1.slab_offset[1] =
-				p_rt->params.ip_hdr_offset - 2 * 8;
-			break;
-
-		default:
-			rsp->status = -1;
-			return rsp;
-		}
-
-		entry_arp1.slab[2] =
-			SLAB_NBO_MACADDRSRC_ETHERTYPE(macaddr_src, ethertype_mpls);
-		entry_arp1.slab_offset[2] = p_rt->params.ip_hdr_offset -
-			(n_labels * 4 + 8);
-
-		entry_arp1.data_offset = entry_arp1.slab_offset[2] - 6
-			- sizeof(struct rte_mbuf);
-		entry_arp1.ether_l2_length = n_labels * 4 + 14;
-	}
-
-	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);
-
-	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);
-
-	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_ipv4 key = {
-		.port_id = req->key.key.ipv4.port_id,
-		.ip = rte_bswap32(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, /* set below */
-	};
-
-	if (req->key.type != PIPELINE_ROUTING_ARP_IPV4) {
-		rsp->status = -1;
-		return rsp;
-	}
-
-	entry.macaddr = *((uint64_t *)&(req->macaddr));
-	entry.macaddr = entry.macaddr << 16;
-
-	rsp->status = rte_pipeline_table_entry_add(p->p,
-		p->table_id[1],
-		&key,
-		(struct rte_pipeline_table_entry *) &entry,
-		&rsp->key_found,
-		(struct rte_pipeline_table_entry **) &rsp->entry_ptr);
-
-	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_ipv4 key = {
-		.port_id = req->key.key.ipv4.port_id,
-		.ip = rte_bswap32(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);
-
-	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;
-}
-
-void *
-pipeline_routing_msg_req_set_macaddr_handler(struct pipeline *p, void *msg)
-{
-	struct pipeline_routing *p_rt = (struct pipeline_routing *) p;
-	struct pipeline_routing_set_macaddr_msg_req *req = msg;
-	struct pipeline_routing_set_macaddr_msg_rsp *rsp = msg;
-	uint32_t port_id;
-
-	for (port_id = 0; port_id < p->n_ports_out; port_id++)
-		p_rt->macaddr[port_id] = req->macaddr[port_id];
-
-	rsp->status = 0;
-
-	return rsp;
-}
-
-struct pipeline_be_ops pipeline_routing_be_ops = {
-	.f_init = pipeline_routing_init,
-	.f_free = pipeline_routing_free,
-	.f_run = NULL,
-	.f_timer = pipeline_routing_timer,
-};
diff --git a/examples/ip_pipeline/pipeline/pipeline_routing_be.h b/examples/ip_pipeline/pipeline/pipeline_routing_be.h
deleted file mode 100644
index 7140ee4..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_routing_be.h
+++ /dev/null
@@ -1,283 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#ifndef __INCLUDE_PIPELINE_ROUTING_BE_H__
-#define __INCLUDE_PIPELINE_ROUTING_BE_H__
-
-#include <rte_ether.h>
-
-#include "pipeline_common_be.h"
-
-/*
- * Pipeline argument parsing
- */
-#ifndef PIPELINE_ROUTING_N_ROUTES_DEFAULT
-#define PIPELINE_ROUTING_N_ROUTES_DEFAULT                  4096
-#endif
-
-enum pipeline_routing_encap {
-	PIPELINE_ROUTING_ENCAP_ETHERNET = 0,
-	PIPELINE_ROUTING_ENCAP_ETHERNET_QINQ,
-	PIPELINE_ROUTING_ENCAP_ETHERNET_MPLS,
-};
-
-struct pipeline_routing_params {
-	/* routing */
-	uint32_t n_routes;
-	uint32_t port_local_dest;
-
-	/* routing packet encapsulation */
-	enum pipeline_routing_encap encap;
-	uint32_t qinq_sched;
-	uint32_t mpls_color_mark;
-
-	/* arp */
-	uint32_t n_arp_entries;
-
-	/* packet buffer offsets */
-	uint32_t ip_hdr_offset;
-	uint32_t arp_key_offset;
-	uint32_t color_offset;
-
-	/* debug */
-	uint32_t dbg_ah_disable;
-};
-
-int
-pipeline_routing_parse_args(struct pipeline_routing_params *p,
-	struct pipeline_params *params);
-
-/*
- * Route
- */
-enum pipeline_routing_route_key_type {
-	PIPELINE_ROUTING_ROUTE_IPV4,
-};
-
-struct pipeline_routing_route_key_ipv4 {
-	uint32_t ip;
-	uint32_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 */
-	PIPELINE_ROUTING_ROUTE_ARP = 1 << 1, /* 0 = ARP OFF; 1 = ARP ON */
-	PIPELINE_ROUTING_ROUTE_QINQ = 1 << 2, /* 0 = QINQ OFF; 1 = QINQ ON */
-	PIPELINE_ROUTING_ROUTE_MPLS = 1 << 3, /* 0 = MPLS OFF; 1 = MPLS ON */
-};
-
-#define PIPELINE_ROUTING_MPLS_LABELS_MAX         4
-
-struct pipeline_routing_route_data {
-	uint32_t flags;
-	uint32_t port_id; /* Output port ID */
-
-	union {
-		/* Next hop IP (valid only when ARP is enabled) */
-		uint32_t ip;
-
-		/* Next hop MAC address (valid only when ARP disabled */
-		struct ether_addr macaddr;
-	} ethernet;
-
-	union {
-		struct {
-			uint16_t svlan;
-			uint16_t cvlan;
-		} qinq;
-
-		struct {
-			uint32_t labels[PIPELINE_ROUTING_MPLS_LABELS_MAX];
-			uint32_t n_labels;
-		} mpls;
-	} l2;
-};
-
-/*
- * 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_REQ_SET_MACADDR,
-	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 */
-	struct pipeline_routing_route_data data;
-};
-
-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;
-};
-
-/*
- * MSG SET MACADDR
- */
-struct pipeline_routing_set_macaddr_msg_req {
-	enum pipeline_msg_req_type type;
-	enum pipeline_routing_msg_req_type subtype;
-
-	uint64_t macaddr[PIPELINE_MAX_PORT_OUT];
-};
-
-struct pipeline_routing_set_macaddr_msg_rsp {
-	int status;
-};
-
-extern struct pipeline_be_ops pipeline_routing_be_ops;
-
-#endif
-- 
2.9.3

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

* [dpdk-dev] [PATCH v2 12/44] ip_pipeline: remove flow classification pipeline
  2018-03-12 17:25   ` [dpdk-dev] [PATCH v2 00/44] ip_pipeline: refactoring Jasvinder Singh
                       ` (10 preceding siblings ...)
  2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 11/44] ip_pipeline: remove routing pipeline Jasvinder Singh
@ 2018-03-12 17:25     ` Jasvinder Singh
  2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 13/44] ip_pipeline: remove flow actions pipeline Jasvinder Singh
                       ` (31 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-12 17:25 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Remove flow classification pipeline.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/Makefile                      |    2 -
 examples/ip_pipeline/init.c                        |    2 -
 examples/ip_pipeline/meson.build                   |    2 -
 .../pipeline/pipeline_flow_classification.c        | 1878 --------------------
 .../pipeline/pipeline_flow_classification.h        |  106 --
 .../pipeline/pipeline_flow_classification_be.c     |  723 --------
 .../pipeline/pipeline_flow_classification_be.h     |  113 --
 7 files changed, 2826 deletions(-)
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_classification.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_classification.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_classification_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_classification_be.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index f67cfe6..e43001f 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -21,8 +21,6 @@ SRCS-y += pipeline_master_be.c
 SRCS-y += pipeline_master.c
 SRCS-y += pipeline_firewall_be.c
 SRCS-y += pipeline_firewall.c
-SRCS-y += pipeline_flow_classification_be.c
-SRCS-y += pipeline_flow_classification.c
 SRCS-y += pipeline_flow_actions_be.c
 SRCS-y += pipeline_flow_actions.c
 
diff --git a/examples/ip_pipeline/init.c b/examples/ip_pipeline/init.c
index 241d80a..4780bb1 100644
--- a/examples/ip_pipeline/init.c
+++ b/examples/ip_pipeline/init.c
@@ -27,7 +27,6 @@
 #include "pipeline_common_fe.h"
 #include "pipeline_master.h"
 #include "pipeline_firewall.h"
-#include "pipeline_flow_classification.h"
 #include "pipeline_flow_actions.h"
 #include "thread_fe.h"
 
@@ -1820,7 +1819,6 @@ int app_init(struct app_params *app)
 	app_pipeline_common_cmd_push(app);
 	app_pipeline_thread_cmd_push(app);
 	app_pipeline_type_register(app, &pipeline_master);
-	app_pipeline_type_register(app, &pipeline_flow_classification);
 	app_pipeline_type_register(app, &pipeline_flow_actions);
 	app_pipeline_type_register(app, &pipeline_firewall);
 
diff --git a/examples/ip_pipeline/meson.build b/examples/ip_pipeline/meson.build
index 53d36df..a04e418 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -24,8 +24,6 @@ sources = files(
 	'pipeline/pipeline_firewall.c',
 	'pipeline/pipeline_flow_actions_be.c',
 	'pipeline/pipeline_flow_actions.c',
-	'pipeline/pipeline_flow_classification_be.c',
-	'pipeline/pipeline_flow_classification.c',
 	'pipeline/pipeline_master_be.c',
 	'pipeline/pipeline_master.c',
 )
diff --git a/examples/ip_pipeline/pipeline/pipeline_flow_classification.c b/examples/ip_pipeline/pipeline/pipeline_flow_classification.c
deleted file mode 100644
index d39e0fb..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_flow_classification.c
+++ /dev/null
@@ -1,1878 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2016 Intel Corporation
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <sys/queue.h>
-#include <netinet/in.h>
-#include <unistd.h>
-
-#include <rte_common.h>
-#include <rte_hexdump.h>
-#include <rte_malloc.h>
-#include <cmdline_rdline.h>
-#include <cmdline_parse.h>
-#include <cmdline_parse_num.h>
-#include <cmdline_parse_string.h>
-
-#include "app.h"
-#include "pipeline_common_fe.h"
-#include "pipeline_flow_classification.h"
-#include "hash_func.h"
-#include "parser.h"
-
-/*
- * Key conversion
- */
-
-struct pkt_key_qinq {
-	uint16_t ethertype_svlan;
-	uint16_t svlan;
-	uint16_t ethertype_cvlan;
-	uint16_t cvlan;
-} __attribute__((__packed__));
-
-struct pkt_key_ipv4_5tuple {
-	uint8_t ttl;
-	uint8_t proto;
-	uint16_t checksum;
-	uint32_t ip_src;
-	uint32_t ip_dst;
-	uint16_t port_src;
-	uint16_t port_dst;
-} __attribute__((__packed__));
-
-struct pkt_key_ipv6_5tuple {
-	uint16_t payload_length;
-	uint8_t proto;
-	uint8_t hop_limit;
-	uint8_t ip_src[16];
-	uint8_t ip_dst[16];
-	uint16_t port_src;
-	uint16_t port_dst;
-} __attribute__((__packed__));
-
-static int
-app_pipeline_fc_key_convert(struct pipeline_fc_key *key_in,
-	uint8_t *key_out,
-	uint32_t *signature)
-{
-	uint8_t buffer[PIPELINE_FC_FLOW_KEY_MAX_SIZE];
-	uint8_t m[PIPELINE_FC_FLOW_KEY_MAX_SIZE]; /* key mask */
-	void *key_buffer = (key_out) ? key_out : buffer;
-
-	memset(m, 0xFF, sizeof(m));
-	switch (key_in->type) {
-	case FLOW_KEY_QINQ:
-	{
-		struct pkt_key_qinq *qinq = key_buffer;
-
-		qinq->ethertype_svlan = 0;
-		qinq->svlan = rte_cpu_to_be_16(key_in->key.qinq.svlan);
-		qinq->ethertype_cvlan = 0;
-		qinq->cvlan = rte_cpu_to_be_16(key_in->key.qinq.cvlan);
-
-		if (signature)
-			*signature = (uint32_t) hash_default_key8(qinq, m, 8, 0);
-		return 0;
-	}
-
-	case FLOW_KEY_IPV4_5TUPLE:
-	{
-		struct pkt_key_ipv4_5tuple *ipv4 = key_buffer;
-
-		ipv4->ttl = 0;
-		ipv4->proto = key_in->key.ipv4_5tuple.proto;
-		ipv4->checksum = 0;
-		ipv4->ip_src = rte_cpu_to_be_32(key_in->key.ipv4_5tuple.ip_src);
-		ipv4->ip_dst = rte_cpu_to_be_32(key_in->key.ipv4_5tuple.ip_dst);
-		ipv4->port_src = rte_cpu_to_be_16(key_in->key.ipv4_5tuple.port_src);
-		ipv4->port_dst = rte_cpu_to_be_16(key_in->key.ipv4_5tuple.port_dst);
-
-		if (signature)
-			*signature = (uint32_t) hash_default_key16(ipv4, m, 16, 0);
-		return 0;
-	}
-
-	case FLOW_KEY_IPV6_5TUPLE:
-	{
-		struct pkt_key_ipv6_5tuple *ipv6 = key_buffer;
-
-		memset(ipv6, 0, 64);
-		ipv6->payload_length = 0;
-		ipv6->proto = key_in->key.ipv6_5tuple.proto;
-		ipv6->hop_limit = 0;
-		memcpy(&ipv6->ip_src, &key_in->key.ipv6_5tuple.ip_src, 16);
-		memcpy(&ipv6->ip_dst, &key_in->key.ipv6_5tuple.ip_dst, 16);
-		ipv6->port_src = rte_cpu_to_be_16(key_in->key.ipv6_5tuple.port_src);
-		ipv6->port_dst = rte_cpu_to_be_16(key_in->key.ipv6_5tuple.port_dst);
-
-		if (signature)
-			*signature = (uint32_t) hash_default_key64(ipv6, m, 64, 0);
-		return 0;
-	}
-
-	default:
-		return -1;
-	}
-}
-
-/*
- * Flow classification pipeline
- */
-
-struct app_pipeline_fc_flow {
-	struct pipeline_fc_key key;
-	uint32_t port_id;
-	uint32_t flow_id;
-	uint32_t signature;
-	void *entry_ptr;
-
-	TAILQ_ENTRY(app_pipeline_fc_flow) node;
-};
-
-#define N_BUCKETS                                65536
-
-struct app_pipeline_fc {
-	/* Parameters */
-	uint32_t n_ports_in;
-	uint32_t n_ports_out;
-
-	/* Flows */
-	TAILQ_HEAD(, app_pipeline_fc_flow) flows[N_BUCKETS];
-	uint32_t n_flows;
-
-	/* Default flow */
-	uint32_t default_flow_present;
-	uint32_t default_flow_port_id;
-	void *default_flow_entry_ptr;
-};
-
-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;
-	uint32_t signature, bucket_id;
-
-	app_pipeline_fc_key_convert(key, NULL, &signature);
-	bucket_id = signature & (N_BUCKETS - 1);
-
-	TAILQ_FOREACH(f, &p->flows[bucket_id], node)
-		if ((signature == f->signature) &&
-			(memcmp(key,
-				&f->key,
-				sizeof(struct pipeline_fc_key)) == 0))
-			return f;
-
-	return NULL;
-}
-
-static void*
-app_pipeline_fc_init(struct pipeline_params *params,
-	__rte_unused void *arg)
-{
-	struct app_pipeline_fc *p;
-	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 app_pipeline_fc));
-	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;
-
-	for (i = 0; i < N_BUCKETS; i++)
-		TAILQ_INIT(&p->flows[i]);
-	p->n_flows = 0;
-
-	return (void *) p;
-}
-
-static int
-app_pipeline_fc_free(void *pipeline)
-{
-	struct app_pipeline_fc *p = pipeline;
-	uint32_t i;
-
-	/* Check input arguments */
-	if (p == NULL)
-		return -1;
-
-	/* Free resources */
-	for (i = 0; i < N_BUCKETS; i++)
-		while (!TAILQ_EMPTY(&p->flows[i])) {
-			struct app_pipeline_fc_flow *flow;
-
-			flow = TAILQ_FIRST(&p->flows[i]);
-			TAILQ_REMOVE(&p->flows[i], flow, node);
-			rte_free(flow);
-		}
-
-	rte_free(p);
-	return 0;
-}
-
-static int
-app_pipeline_fc_key_check(struct pipeline_fc_key *key)
-{
-	switch (key->type) {
-	case FLOW_KEY_QINQ:
-	{
-		uint16_t svlan = key->key.qinq.svlan;
-		uint16_t cvlan = key->key.qinq.cvlan;
-
-		if ((svlan & 0xF000) ||
-			(cvlan & 0xF000))
-			return -1;
-
-		return 0;
-	}
-
-	case FLOW_KEY_IPV4_5TUPLE:
-		return 0;
-
-	case FLOW_KEY_IPV6_5TUPLE:
-		return 0;
-
-	default:
-		return -1;
-	}
-}
-
-int
-app_pipeline_fc_load_file_qinq(char *filename,
-	struct pipeline_fc_key *keys,
-	uint32_t *port_ids,
-	uint32_t *flow_ids,
-	uint32_t *n_keys,
-	uint32_t *line)
-{
-	FILE *f = NULL;
-	char file_buf[1024];
-	uint32_t i, l;
-
-	/* Check input arguments */
-	if ((filename == NULL) ||
-		(keys == NULL) ||
-		(port_ids == NULL) ||
-		(flow_ids == NULL) ||
-		(n_keys == NULL) ||
-		(*n_keys == 0) ||
-		(line == NULL)) {
-		if (line)
-			*line = 0;
-		return -1;
-		}
-
-	/* Open input file */
-	f = fopen(filename, "r");
-	if (f == NULL) {
-		*line = 0;
-		return -1;
-	}
-
-	/* Read file */
-	for (i = 0, l = 1; i < *n_keys; l++) {
-		char *tokens[32];
-		uint32_t n_tokens = RTE_DIM(tokens);
-
-		uint16_t svlan, cvlan;
-		uint32_t portid, flowid;
-		int status;
-
-		if (fgets(file_buf, sizeof(file_buf), f) == NULL)
-			break;
-
-		status = parse_tokenize_string(file_buf, tokens, &n_tokens);
-		if (status)
-			goto error1;
-
-		if ((n_tokens == 0) || (tokens[0][0] == '#'))
-			continue;
-
-		if ((n_tokens != 7) ||
-			strcmp(tokens[0], "qinq") ||
-			parser_read_uint16(&svlan, tokens[1]) ||
-			parser_read_uint16(&cvlan, tokens[2]) ||
-			strcmp(tokens[3], "port") ||
-			parser_read_uint32(&portid, tokens[4]) ||
-			strcmp(tokens[5], "id") ||
-			parser_read_uint32(&flowid, tokens[6]))
-			goto error1;
-
-		keys[i].type = FLOW_KEY_QINQ;
-		keys[i].key.qinq.svlan = svlan;
-		keys[i].key.qinq.cvlan = cvlan;
-
-		port_ids[i] = portid;
-		flow_ids[i] = flowid;
-
-		if (app_pipeline_fc_key_check(&keys[i]))
-			goto error1;
-
-		i++;
-	}
-
-	/* Close file */
-	*n_keys = i;
-	fclose(f);
-	return 0;
-
-error1:
-	*line = l;
-	fclose(f);
-	return -1;
-}
-
-int
-app_pipeline_fc_load_file_ipv4(char *filename,
-	struct pipeline_fc_key *keys,
-	uint32_t *port_ids,
-	uint32_t *flow_ids,
-	uint32_t *n_keys,
-	uint32_t *line)
-{
-	FILE *f = NULL;
-	char file_buf[1024];
-	uint32_t i, l;
-
-	/* Check input arguments */
-	if ((filename == NULL) ||
-		(keys == NULL) ||
-		(port_ids == NULL) ||
-		(flow_ids == NULL) ||
-		(n_keys == NULL) ||
-		(*n_keys == 0) ||
-		(line == NULL)) {
-		if (line)
-			*line = 0;
-		return -1;
-		}
-
-	/* Open input file */
-	f = fopen(filename, "r");
-	if (f == NULL) {
-		*line = 0;
-		return -1;
-	}
-
-	/* Read file */
-	for (i = 0, l = 1; i < *n_keys; l++) {
-		char *tokens[32];
-		uint32_t n_tokens = RTE_DIM(tokens);
-
-		struct in_addr sipaddr, dipaddr;
-		uint16_t sport, dport;
-		uint8_t proto;
-		uint32_t portid, flowid;
-		int status;
-
-		if (fgets(file_buf, sizeof(file_buf), f) == NULL)
-			break;
-
-		status = parse_tokenize_string(file_buf, tokens, &n_tokens);
-		if (status)
-			goto error2;
-
-		if ((n_tokens == 0) || (tokens[0][0] == '#'))
-			continue;
-
-		if ((n_tokens != 10) ||
-			strcmp(tokens[0], "ipv4") ||
-			parse_ipv4_addr(tokens[1], &sipaddr) ||
-			parse_ipv4_addr(tokens[2], &dipaddr) ||
-			parser_read_uint16(&sport, tokens[3]) ||
-			parser_read_uint16(&dport, tokens[4]) ||
-			parser_read_uint8(&proto, tokens[5]) ||
-			strcmp(tokens[6], "port") ||
-			parser_read_uint32(&portid, tokens[7]) ||
-			strcmp(tokens[8], "id") ||
-			parser_read_uint32(&flowid, tokens[9]))
-			goto error2;
-
-		keys[i].type = FLOW_KEY_IPV4_5TUPLE;
-		keys[i].key.ipv4_5tuple.ip_src = rte_be_to_cpu_32(sipaddr.s_addr);
-		keys[i].key.ipv4_5tuple.ip_dst = rte_be_to_cpu_32(dipaddr.s_addr);
-		keys[i].key.ipv4_5tuple.port_src = sport;
-		keys[i].key.ipv4_5tuple.port_dst = dport;
-		keys[i].key.ipv4_5tuple.proto = proto;
-
-		port_ids[i] = portid;
-		flow_ids[i] = flowid;
-
-		if (app_pipeline_fc_key_check(&keys[i]))
-			goto error2;
-
-		i++;
-	}
-
-	/* Close file */
-	*n_keys = i;
-	fclose(f);
-	return 0;
-
-error2:
-	*line = l;
-	fclose(f);
-	return -1;
-}
-
-int
-app_pipeline_fc_load_file_ipv6(char *filename,
-	struct pipeline_fc_key *keys,
-	uint32_t *port_ids,
-	uint32_t *flow_ids,
-	uint32_t *n_keys,
-	uint32_t *line)
-{
-	FILE *f = NULL;
-	char file_buf[1024];
-	uint32_t i, l;
-
-	/* Check input arguments */
-	if ((filename == NULL) ||
-		(keys == NULL) ||
-		(port_ids == NULL) ||
-		(flow_ids == NULL) ||
-		(n_keys == NULL) ||
-		(*n_keys == 0) ||
-		(line == NULL)) {
-		if (line)
-			*line = 0;
-		return -1;
-		}
-
-	/* Open input file */
-	f = fopen(filename, "r");
-	if (f == NULL) {
-		*line = 0;
-		return -1;
-	}
-
-	/* Read file */
-	for (i = 0, l = 1; i < *n_keys; l++) {
-		char *tokens[32];
-		uint32_t n_tokens = RTE_DIM(tokens);
-
-		struct in6_addr sipaddr, dipaddr;
-		uint16_t sport, dport;
-		uint8_t proto;
-		uint32_t portid, flowid;
-		int status;
-
-		if (fgets(file_buf, sizeof(file_buf), f) == NULL)
-			break;
-
-		status = parse_tokenize_string(file_buf, tokens, &n_tokens);
-		if (status)
-			goto error3;
-
-		if ((n_tokens == 0) || (tokens[0][0] == '#'))
-			continue;
-
-		if ((n_tokens != 10) ||
-			strcmp(tokens[0], "ipv6") ||
-			parse_ipv6_addr(tokens[1], &sipaddr) ||
-			parse_ipv6_addr(tokens[2], &dipaddr) ||
-			parser_read_uint16(&sport, tokens[3]) ||
-			parser_read_uint16(&dport, tokens[4]) ||
-			parser_read_uint8(&proto, tokens[5]) ||
-			strcmp(tokens[6], "port") ||
-			parser_read_uint32(&portid, tokens[7]) ||
-			strcmp(tokens[8], "id") ||
-			parser_read_uint32(&flowid, tokens[9]))
-			goto error3;
-
-		keys[i].type = FLOW_KEY_IPV6_5TUPLE;
-		memcpy(keys[i].key.ipv6_5tuple.ip_src,
-			sipaddr.s6_addr,
-			sizeof(sipaddr.s6_addr));
-		memcpy(keys[i].key.ipv6_5tuple.ip_dst,
-			dipaddr.s6_addr,
-			sizeof(dipaddr.s6_addr));
-		keys[i].key.ipv6_5tuple.port_src = sport;
-		keys[i].key.ipv6_5tuple.port_dst = dport;
-		keys[i].key.ipv6_5tuple.proto = proto;
-
-		port_ids[i] = portid;
-		flow_ids[i] = flowid;
-
-		if (app_pipeline_fc_key_check(&keys[i]))
-			goto error3;
-
-		i++;
-	}
-
-	/* Close file */
-	*n_keys = i;
-	fclose(f);
-	return 0;
-
-error3:
-	*line = l;
-	fclose(f);
-	return -1;
-}
-
-
-
-int
-app_pipeline_fc_add(struct app_params *app,
-	uint32_t pipeline_id,
-	struct pipeline_fc_key *key,
-	uint32_t port_id,
-	uint32_t flow_id)
-{
-	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;
-
-	uint32_t signature;
-	int new_flow;
-
-	/* Check input arguments */
-	if ((app == NULL) ||
-		(key == NULL))
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_flow_classification);
-	if (p == NULL)
-		return -1;
-
-	if (port_id >= p->n_ports_out)
-		return -1;
-
-	if (app_pipeline_fc_key_check(key) != 0)
-		return -1;
-
-	/* 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;
-	}
-
-	/* 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;
-	app_pipeline_fc_key_convert(key, req->key, &signature);
-	req->port_id = port_id;
-	req->flow_id = flow_id;
-
-	/* Send request and wait for response */
-	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL) {
-		if (new_flow)
-			rte_free(flow);
-		return -1;
-	}
-
-	/* Read response and write flow */
-	if (rsp->status ||
-		(rsp->entry_ptr == NULL) ||
-		((new_flow == 0) && (rsp->key_found == 0)) ||
-		((new_flow == 1) && (rsp->key_found == 1))) {
-		app_msg_free(app, rsp);
-		if (new_flow)
-			rte_free(flow);
-		return -1;
-	}
-
-	memset(&flow->key, 0, sizeof(flow->key));
-	memcpy(&flow->key, key, sizeof(flow->key));
-	flow->port_id = port_id;
-	flow->flow_id = flow_id;
-	flow->signature = signature;
-	flow->entry_ptr = rsp->entry_ptr;
-
-	/* Commit rule */
-	if (new_flow) {
-		uint32_t bucket_id = signature & (N_BUCKETS - 1);
-
-		TAILQ_INSERT_TAIL(&p->flows[bucket_id], flow, node);
-		p->n_flows++;
-	}
-
-	/* Free response */
-	app_msg_free(app, rsp);
-
-	return 0;
-}
-
-int
-app_pipeline_fc_add_bulk(struct app_params *app,
-	uint32_t pipeline_id,
-	struct pipeline_fc_key *key,
-	uint32_t *port_id,
-	uint32_t *flow_id,
-	uint32_t n_keys)
-{
-	struct app_pipeline_fc *p;
-	struct pipeline_fc_add_bulk_msg_req *req;
-	struct pipeline_fc_add_bulk_msg_rsp *rsp;
-
-	struct app_pipeline_fc_flow **flow;
-	uint32_t *signature;
-	int *new_flow;
-	struct pipeline_fc_add_bulk_flow_req *flow_req;
-	struct pipeline_fc_add_bulk_flow_rsp *flow_rsp;
-
-	uint32_t i;
-	int status;
-
-	/* Check input arguments */
-	if ((app == NULL) ||
-		(key == NULL) ||
-		(port_id == NULL) ||
-		(flow_id == NULL) ||
-		(n_keys == 0))
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_flow_classification);
-	if (p == NULL)
-		return -1;
-
-	for (i = 0; i < n_keys; i++)
-		if (port_id[i] >= p->n_ports_out)
-			return -1;
-
-	for (i = 0; i < n_keys; i++)
-		if (app_pipeline_fc_key_check(&key[i]) != 0)
-			return -1;
-
-	/* Memory allocation */
-	flow = rte_malloc(NULL,
-		n_keys * sizeof(struct app_pipeline_fc_flow *),
-		RTE_CACHE_LINE_SIZE);
-	if (flow == NULL)
-		return -1;
-
-	signature = rte_malloc(NULL,
-		n_keys * sizeof(uint32_t),
-		RTE_CACHE_LINE_SIZE);
-	if (signature == NULL) {
-		rte_free(flow);
-		return -1;
-	}
-
-	new_flow = rte_malloc(
-		NULL,
-		n_keys * sizeof(int),
-		RTE_CACHE_LINE_SIZE);
-	if (new_flow == NULL) {
-		rte_free(signature);
-		rte_free(flow);
-		return -1;
-	}
-
-	flow_req = rte_malloc(NULL,
-		n_keys * sizeof(struct pipeline_fc_add_bulk_flow_req),
-		RTE_CACHE_LINE_SIZE);
-	if (flow_req == NULL) {
-		rte_free(new_flow);
-		rte_free(signature);
-		rte_free(flow);
-		return -1;
-	}
-
-	flow_rsp = rte_malloc(NULL,
-		n_keys * sizeof(struct pipeline_fc_add_bulk_flow_rsp),
-		RTE_CACHE_LINE_SIZE);
-	if (flow_rsp == NULL) {
-		rte_free(flow_req);
-		rte_free(new_flow);
-		rte_free(signature);
-		rte_free(flow);
-		return -1;
-	}
-
-	/* Find existing flow or allocate new flow */
-	for (i = 0; i < n_keys; i++) {
-		flow[i] = app_pipeline_fc_flow_find(p, &key[i]);
-		new_flow[i] = (flow[i] == NULL);
-		if (flow[i] == NULL) {
-			flow[i] = rte_zmalloc(NULL,
-				sizeof(struct app_pipeline_fc_flow),
-				RTE_CACHE_LINE_SIZE);
-
-			if (flow[i] == NULL) {
-				uint32_t j;
-
-				for (j = 0; j < i; j++)
-					if (new_flow[j])
-						rte_free(flow[j]);
-
-				rte_free(flow_rsp);
-				rte_free(flow_req);
-				rte_free(new_flow);
-				rte_free(signature);
-				rte_free(flow);
-				return -1;
-			}
-		}
-	}
-
-	/* Allocate and write request */
-	req = app_msg_alloc(app);
-	if (req == NULL) {
-		for (i = 0; i < n_keys; i++)
-			if (new_flow[i])
-				rte_free(flow[i]);
-
-		rte_free(flow_rsp);
-		rte_free(flow_req);
-		rte_free(new_flow);
-		rte_free(signature);
-		rte_free(flow);
-		return -1;
-	}
-
-	for (i = 0; i < n_keys; i++) {
-		app_pipeline_fc_key_convert(&key[i],
-			flow_req[i].key,
-			&signature[i]);
-		flow_req[i].port_id = port_id[i];
-		flow_req[i].flow_id = flow_id[i];
-	}
-
-	req->type = PIPELINE_MSG_REQ_CUSTOM;
-	req->subtype = PIPELINE_FC_MSG_REQ_FLOW_ADD_BULK;
-	req->req = flow_req;
-	req->rsp = flow_rsp;
-	req->n_keys = n_keys;
-
-	/* Send request and wait for response */
-	rsp = app_msg_send_recv(app, pipeline_id, req, 10000);
-	if (rsp == NULL) {
-		for (i = 0; i < n_keys; i++)
-			if (new_flow[i])
-				rte_free(flow[i]);
-
-		rte_free(flow_rsp);
-		rte_free(flow_req);
-		rte_free(new_flow);
-		rte_free(signature);
-		rte_free(flow);
-		return -1;
-	}
-
-	/* Read response */
-	status = 0;
-
-	for (i = 0; i < rsp->n_keys; i++)
-		if ((flow_rsp[i].entry_ptr == NULL) ||
-			((new_flow[i] == 0) && (flow_rsp[i].key_found == 0)) ||
-			((new_flow[i] == 1) && (flow_rsp[i].key_found == 1)))
-			status = -1;
-
-	if (rsp->n_keys < n_keys)
-		status = -1;
-
-	/* Commit flows */
-	for (i = 0; i < rsp->n_keys; i++) {
-		memcpy(&flow[i]->key, &key[i], sizeof(flow[i]->key));
-		flow[i]->port_id = port_id[i];
-		flow[i]->flow_id = flow_id[i];
-		flow[i]->signature = signature[i];
-		flow[i]->entry_ptr = flow_rsp[i].entry_ptr;
-
-		if (new_flow[i]) {
-			uint32_t bucket_id = signature[i] & (N_BUCKETS - 1);
-
-			TAILQ_INSERT_TAIL(&p->flows[bucket_id], flow[i], node);
-			p->n_flows++;
-		}
-	}
-
-	/* Free resources */
-
-	for (i = rsp->n_keys; i < n_keys; i++)
-		if (new_flow[i])
-			rte_free(flow[i]);
-
-	app_msg_free(app, rsp);
-	rte_free(flow_rsp);
-	rte_free(flow_req);
-	rte_free(new_flow);
-	rte_free(signature);
-	rte_free(flow);
-
-	return status;
-}
-
-int
-app_pipeline_fc_del(struct app_params *app,
-	uint32_t pipeline_id,
-	struct pipeline_fc_key *key)
-{
-	struct app_pipeline_fc *p;
-	struct app_pipeline_fc_flow *flow;
-
-	struct pipeline_fc_del_msg_req *req;
-	struct pipeline_fc_del_msg_rsp *rsp;
-
-	uint32_t signature, bucket_id;
-
-	/* Check input arguments */
-	if ((app == NULL) ||
-		(key == NULL))
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_flow_classification);
-	if (p == NULL)
-		return -1;
-
-	if (app_pipeline_fc_key_check(key) != 0)
-		return -1;
-
-	/* 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;
-	app_pipeline_fc_key_convert(key, req->key, &signature);
-
-	/* Send request and wait for response */
-	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	/* Read response */
-	if (rsp->status || !rsp->key_found) {
-		app_msg_free(app, rsp);
-		return -1;
-	}
-
-	/* Remove rule */
-	bucket_id = signature & (N_BUCKETS - 1);
-	TAILQ_REMOVE(&p->flows[bucket_id], flow, node);
-	p->n_flows--;
-	rte_free(flow);
-
-	/* Free response */
-	app_msg_free(app, rsp);
-
-	return 0;
-}
-
-int
-app_pipeline_fc_add_default(struct app_params *app,
-	uint32_t pipeline_id,
-	uint32_t port_id)
-{
-	struct app_pipeline_fc *p;
-
-	struct pipeline_fc_add_default_msg_req *req;
-	struct pipeline_fc_add_default_msg_rsp *rsp;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_flow_classification);
-	if (p == NULL)
-		return -1;
-
-	if (port_id >= p->n_ports_out)
-		return -1;
-
-	/* 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_DEFAULT;
-	req->port_id = port_id;
-
-	/* Send request and wait for response */
-	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	/* Read response and write flow */
-	if (rsp->status || (rsp->entry_ptr == NULL)) {
-		app_msg_free(app, rsp);
-		return -1;
-	}
-
-	p->default_flow_port_id = port_id;
-	p->default_flow_entry_ptr = rsp->entry_ptr;
-
-	/* Commit route */
-	p->default_flow_present = 1;
-
-	/* Free response */
-	app_msg_free(app, rsp);
-
-	return 0;
-}
-
-int
-app_pipeline_fc_del_default(struct app_params *app,
-	uint32_t pipeline_id)
-{
-	struct app_pipeline_fc *p;
-
-	struct pipeline_fc_del_default_msg_req *req;
-	struct pipeline_fc_del_default_msg_rsp *rsp;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_flow_classification);
-	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_FC_MSG_REQ_FLOW_DEL_DEFAULT;
-
-	/* Send request and wait for response */
-	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	/* Read response */
-	if (rsp->status) {
-		app_msg_free(app, rsp);
-		return -1;
-	}
-
-	/* Commit route */
-	p->default_flow_present = 0;
-
-	/* Free response */
-	app_msg_free(app, rsp);
-
-	return 0;
-}
-
-/*
- * Flow ls
- */
-
-static void
-print_fc_qinq_flow(struct app_pipeline_fc_flow *flow)
-{
-	printf("(SVLAN = %" PRIu32 ", "
-		"CVLAN = %" PRIu32 ") => "
-		"Port = %" PRIu32 ", "
-		"Flow ID = %" PRIu32 ", "
-		"(signature = 0x%08" PRIx32 ", "
-		"entry_ptr = %p)\n",
-
-		flow->key.key.qinq.svlan,
-		flow->key.key.qinq.cvlan,
-		flow->port_id,
-		flow->flow_id,
-		flow->signature,
-		flow->entry_ptr);
-}
-
-static void
-print_fc_ipv4_5tuple_flow(struct app_pipeline_fc_flow *flow)
-{
-	printf("(SA = %" PRIu32 ".%" PRIu32 ".%" PRIu32 ".%" PRIu32 ", "
-		   "DA = %" PRIu32 ".%" PRIu32 ".%" PRIu32 ".%" PRIu32 ", "
-		   "SP = %" PRIu32 ", "
-		   "DP = %" PRIu32 ", "
-		   "Proto = %" PRIu32 ") => "
-		   "Port = %" PRIu32 ", "
-		   "Flow ID = %" PRIu32 " "
-		   "(signature = 0x%08" PRIx32 ", "
-		   "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->flow_id,
-		   flow->signature,
-		   flow->entry_ptr);
-}
-
-static void
-print_fc_ipv6_5tuple_flow(struct app_pipeline_fc_flow *flow) {
-	printf("(SA = %02" PRIx32 "%02" PRIx32 ":%02" PRIx32 "%02" PRIx32
-		":%02" PRIx32 "%02" PRIx32 ":%02" PRIx32 "%02" PRIx32
-		":%02" PRIx32 "%02" PRIx32 ":%02" PRIx32 "%02" PRIx32
-		":%02" PRIx32 "%02" PRIx32 ":%02" PRIx32 "%02" PRIx32 ", "
-		"DA = %02" PRIx32 "%02" PRIx32 ":%02" PRIx32 "%02" PRIx32
-		":%02" PRIx32 "%02" PRIx32 ":%02" PRIx32 "%02" PRIx32
-		":%02" PRIx32 "%02" PRIx32 ":%02" PRIx32 "%02" PRIx32
-		":%02" PRIx32 "%02" PRIx32 ":%02" PRIx32 "%02" PRIx32 ", "
-		"SP = %" PRIu32 ", "
-		"DP = %" PRIu32 " "
-		"Proto = %" PRIu32 " "
-		"=> Port = %" PRIu32 ", "
-		"Flow ID = %" PRIu32 " "
-		"(signature = 0x%08" PRIx32 ", "
-		"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],
-
-		flow->key.key.ipv6_5tuple.port_src,
-		flow->key.key.ipv6_5tuple.port_dst,
-
-		flow->key.key.ipv6_5tuple.proto,
-
-		flow->port_id,
-		flow->flow_id,
-		flow->signature,
-		flow->entry_ptr);
-}
-
-static void
-print_fc_flow(struct app_pipeline_fc_flow *flow)
-{
-	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;
-	}
-}
-
-static int
-app_pipeline_fc_ls(struct app_params *app,
-		uint32_t pipeline_id)
-{
-	struct app_pipeline_fc *p;
-	struct app_pipeline_fc_flow *flow;
-	uint32_t i;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_flow_classification);
-	if (p == NULL)
-		return -1;
-
-	for (i = 0; i < N_BUCKETS; i++)
-		TAILQ_FOREACH(flow, &p->flows[i], node)
-			print_fc_flow(flow);
-
-	if (p->default_flow_present)
-		printf("Default flow: port %" PRIu32 " (entry ptr = %p)\n",
-			p->default_flow_port_id,
-			p->default_flow_entry_ptr);
-	else
-		printf("Default: DROP\n");
-
-	return 0;
-}
-/*
- * flow
- *
- * flow add:
- *    p <pipelineid> flow add qinq <svlan> <cvlan> port <portid> id <flowid>
- *    p <pipelineid> flow add qinq bulk <file>
- *    p <pipelineid> flow add ipv4 <sipaddr> <dipaddr> <sport> <dport> <proto> port <port ID> id <flowid>
- *    p <pipelineid> flow add ipv4 bulk <file>
- *    p <pipelineid> flow add ipv6 <sipaddr> <dipaddr> <sport> <dport> <proto> port <port ID> id <flowid>
- *    p <pipelineid> flow add ipv6 bulk <file>
- *
- * flow add default:
- *    p <pipelineid> flow add default <portid>
- *
- * flow del:
- *    p <pipelineid> flow del qinq <svlan> <cvlan>
- *    p <pipelineid> flow del ipv4 <sipaddr> <dipaddr> <sport> <dport> <proto>
- *    p <pipelineid> flow del ipv6 <sipaddr> <dipaddr> <sport> <dport> <proto>
- *
- * flow del default:
- *    p <pipelineid> flow del default
- *
- * flow ls:
- *    p <pipelineid> flow ls
- */
-
-struct cmd_flow_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t flow_string;
-	cmdline_multi_string_t multi_string;
-};
-
-static void
-cmd_flow_parsed(void *parsed_result,
-	__attribute__((unused)) struct cmdline *cl,
-	void *data)
-{
-	struct cmd_flow_result *results = parsed_result;
-	struct app_params *app = data;
-
-	char *tokens[16];
-	uint32_t n_tokens = RTE_DIM(tokens);
-	int status;
-
-	status = parse_tokenize_string(results->multi_string, tokens, &n_tokens);
-	if (status) {
-		printf(CMD_MSG_TOO_MANY_ARGS, "flow");
-		return;
-	}
-
-	/* flow add qinq */
-	if ((n_tokens >= 3) &&
-		(strcmp(tokens[0], "add") == 0) &&
-		(strcmp(tokens[1], "qinq") == 0) &&
-		strcmp(tokens[2], "bulk")) {
-		struct pipeline_fc_key key;
-		uint32_t svlan;
-		uint32_t cvlan;
-		uint32_t port_id;
-		uint32_t flow_id;
-
-		memset(&key, 0, sizeof(key));
-
-		if (n_tokens != 8) {
-			printf(CMD_MSG_MISMATCH_ARGS, "flow add qinq");
-			return;
-		}
-
-		if (parser_read_uint32(&svlan, tokens[2]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "svlan");
-			return;
-		}
-
-		if (parser_read_uint32(&cvlan, tokens[3]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "cvlan");
-			return;
-		}
-
-		if (strcmp(tokens[4], "port") != 0) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "port");
-			return;
-		}
-
-		if (parser_read_uint32(&port_id, tokens[5]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "portid");
-			return;
-		}
-
-		if (strcmp(tokens[6], "id") != 0) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "id");
-			return;
-		}
-
-		if (parser_read_uint32(&flow_id, tokens[7]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "flowid");
-			return;
-		}
-
-		key.type = FLOW_KEY_QINQ;
-		key.key.qinq.svlan = svlan;
-		key.key.qinq.cvlan = cvlan;
-
-		status = app_pipeline_fc_add(app,
-			results->pipeline_id,
-			&key,
-			port_id,
-			flow_id);
-		if (status)
-			printf(CMD_MSG_FAIL, "flow add qinq");
-
-		return;
-	} /* flow add qinq */
-
-	/* flow add ipv4 */
-	if ((n_tokens >= 3) &&
-		(strcmp(tokens[0], "add") == 0) &&
-		(strcmp(tokens[1], "ipv4") == 0) &&
-		strcmp(tokens[2], "bulk")) {
-		struct pipeline_fc_key key;
-		struct in_addr sipaddr;
-		struct in_addr dipaddr;
-		uint32_t sport;
-		uint32_t dport;
-		uint32_t proto;
-		uint32_t port_id;
-		uint32_t flow_id;
-
-		memset(&key, 0, sizeof(key));
-
-		if (n_tokens != 11) {
-			printf(CMD_MSG_MISMATCH_ARGS, "flow add ipv4");
-			return;
-		}
-
-		if (parse_ipv4_addr(tokens[2], &sipaddr) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "sipv4addr");
-			return;
-		}
-		if (parse_ipv4_addr(tokens[3], &dipaddr) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "dipv4addr");
-			return;
-		}
-
-		if (parser_read_uint32(&sport, tokens[4]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "sport");
-			return;
-		}
-
-		if (parser_read_uint32(&dport, tokens[5]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "dport");
-			return;
-		}
-
-		if (parser_read_uint32(&proto, tokens[6]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "proto");
-			return;
-		}
-
-		if (strcmp(tokens[7], "port") != 0) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "port");
-			return;
-		}
-
-		if (parser_read_uint32(&port_id, tokens[8]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "portid");
-			return;
-		}
-
-		if (strcmp(tokens[9], "id") != 0) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "id");
-			return;
-		}
-
-		if (parser_read_uint32(&flow_id, tokens[10]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "flowid");
-			return;
-		}
-
-		key.type = FLOW_KEY_IPV4_5TUPLE;
-		key.key.ipv4_5tuple.ip_src = rte_be_to_cpu_32(sipaddr.s_addr);
-		key.key.ipv4_5tuple.ip_dst = rte_be_to_cpu_32(dipaddr.s_addr);
-		key.key.ipv4_5tuple.port_src = sport;
-		key.key.ipv4_5tuple.port_dst = dport;
-		key.key.ipv4_5tuple.proto = proto;
-
-		status = app_pipeline_fc_add(app,
-			results->pipeline_id,
-			&key,
-			port_id,
-			flow_id);
-		if (status)
-			printf(CMD_MSG_FAIL, "flow add ipv4");
-
-		return;
-	} /* flow add ipv4 */
-
-	/* flow add ipv6 */
-	if ((n_tokens >= 3) &&
-		(strcmp(tokens[0], "add") == 0) &&
-		(strcmp(tokens[1], "ipv6") == 0) &&
-		strcmp(tokens[2], "bulk")) {
-		struct pipeline_fc_key key;
-		struct in6_addr sipaddr;
-		struct in6_addr dipaddr;
-		uint32_t sport;
-		uint32_t dport;
-		uint32_t proto;
-		uint32_t port_id;
-		uint32_t flow_id;
-
-		memset(&key, 0, sizeof(key));
-
-		if (n_tokens != 11) {
-			printf(CMD_MSG_MISMATCH_ARGS, "flow add ipv6");
-			return;
-		}
-
-		if (parse_ipv6_addr(tokens[2], &sipaddr) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "sipv6addr");
-			return;
-		}
-		if (parse_ipv6_addr(tokens[3], &dipaddr) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "dipv6addr");
-			return;
-		}
-
-		if (parser_read_uint32(&sport, tokens[4]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "sport");
-			return;
-		}
-
-		if (parser_read_uint32(&dport, tokens[5]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "dport");
-			return;
-		}
-
-		if (parser_read_uint32(&proto, tokens[6]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "proto");
-			return;
-		}
-
-		if (strcmp(tokens[7], "port") != 0) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "port");
-			return;
-		}
-
-		if (parser_read_uint32(&port_id, tokens[8]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "portid");
-			return;
-		}
-
-		if (strcmp(tokens[9], "id") != 0) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "id");
-			return;
-		}
-
-		if (parser_read_uint32(&flow_id, tokens[10]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "flowid");
-			return;
-		}
-
-		key.type = FLOW_KEY_IPV6_5TUPLE;
-		memcpy(key.key.ipv6_5tuple.ip_src, (void *)&sipaddr, 16);
-		memcpy(key.key.ipv6_5tuple.ip_dst, (void *)&dipaddr, 16);
-		key.key.ipv6_5tuple.port_src = sport;
-		key.key.ipv6_5tuple.port_dst = dport;
-		key.key.ipv6_5tuple.proto = proto;
-
-		status = app_pipeline_fc_add(app,
-			results->pipeline_id,
-			&key,
-			port_id,
-			flow_id);
-		if (status)
-			printf(CMD_MSG_FAIL, "flow add ipv6");
-
-		return;
-	} /* flow add ipv6 */
-
-	/* flow add qinq bulk */
-	if ((n_tokens >= 3) &&
-		(strcmp(tokens[0], "add") == 0) &&
-		(strcmp(tokens[1], "qinq") == 0) &&
-		(strcmp(tokens[2], "bulk") == 0)) {
-		struct pipeline_fc_key *keys;
-		uint32_t *port_ids, *flow_ids, n_keys, line;
-		char *filename;
-
-		if (n_tokens != 4) {
-			printf(CMD_MSG_MISMATCH_ARGS, "flow add qinq bulk");
-			return;
-		}
-
-		filename = tokens[3];
-
-		n_keys = APP_PIPELINE_FC_MAX_FLOWS_IN_FILE;
-		keys = malloc(n_keys * sizeof(struct pipeline_fc_key));
-		if (keys == NULL)
-			return;
-		memset(keys, 0, n_keys * sizeof(struct pipeline_fc_key));
-
-		port_ids = malloc(n_keys * sizeof(uint32_t));
-		if (port_ids == NULL) {
-			free(keys);
-			return;
-		}
-
-		flow_ids = malloc(n_keys * sizeof(uint32_t));
-		if (flow_ids == NULL) {
-			free(port_ids);
-			free(keys);
-			return;
-		}
-
-		status = app_pipeline_fc_load_file_qinq(filename,
-			keys,
-			port_ids,
-			flow_ids,
-			&n_keys,
-			&line);
-		if (status != 0) {
-			printf(CMD_MSG_FILE_ERR, filename, line);
-			free(flow_ids);
-			free(port_ids);
-			free(keys);
-			return;
-		}
-
-		status = app_pipeline_fc_add_bulk(app,
-			results->pipeline_id,
-			keys,
-			port_ids,
-			flow_ids,
-			n_keys);
-		if (status)
-			printf(CMD_MSG_FAIL, "flow add qinq bulk");
-
-		free(flow_ids);
-		free(port_ids);
-		free(keys);
-		return;
-	} /* flow add qinq bulk */
-
-	/* flow add ipv4 bulk */
-	if ((n_tokens >= 3) &&
-		(strcmp(tokens[0], "add") == 0) &&
-		(strcmp(tokens[1], "ipv4") == 0) &&
-		(strcmp(tokens[2], "bulk") == 0)) {
-		struct pipeline_fc_key *keys;
-		uint32_t *port_ids, *flow_ids, n_keys, line;
-		char *filename;
-
-		if (n_tokens != 4) {
-			printf(CMD_MSG_MISMATCH_ARGS, "flow add ipv4 bulk");
-			return;
-		}
-
-		filename = tokens[3];
-
-		n_keys = APP_PIPELINE_FC_MAX_FLOWS_IN_FILE;
-		keys = malloc(n_keys * sizeof(struct pipeline_fc_key));
-		if (keys == NULL)
-			return;
-		memset(keys, 0, n_keys * sizeof(struct pipeline_fc_key));
-
-		port_ids = malloc(n_keys * sizeof(uint32_t));
-		if (port_ids == NULL) {
-			free(keys);
-			return;
-		}
-
-		flow_ids = malloc(n_keys * sizeof(uint32_t));
-		if (flow_ids == NULL) {
-			free(port_ids);
-			free(keys);
-			return;
-		}
-
-		status = app_pipeline_fc_load_file_ipv4(filename,
-			keys,
-			port_ids,
-			flow_ids,
-			&n_keys,
-			&line);
-		if (status != 0) {
-			printf(CMD_MSG_FILE_ERR, filename, line);
-			free(flow_ids);
-			free(port_ids);
-			free(keys);
-			return;
-		}
-
-		status = app_pipeline_fc_add_bulk(app,
-			results->pipeline_id,
-			keys,
-			port_ids,
-			flow_ids,
-			n_keys);
-		if (status)
-			printf(CMD_MSG_FAIL, "flow add ipv4 bulk");
-
-		free(flow_ids);
-		free(port_ids);
-		free(keys);
-		return;
-	} /* flow add ipv4 bulk */
-
-	/* flow add ipv6 bulk */
-	if ((n_tokens >= 3) &&
-		(strcmp(tokens[0], "add") == 0) &&
-		(strcmp(tokens[1], "ipv6") == 0) &&
-		(strcmp(tokens[2], "bulk") == 0)) {
-		struct pipeline_fc_key *keys;
-		uint32_t *port_ids, *flow_ids, n_keys, line;
-		char *filename;
-
-		if (n_tokens != 4) {
-			printf(CMD_MSG_MISMATCH_ARGS, "flow add ipv6 bulk");
-			return;
-		}
-
-		filename = tokens[3];
-
-		n_keys = APP_PIPELINE_FC_MAX_FLOWS_IN_FILE;
-		keys = malloc(n_keys * sizeof(struct pipeline_fc_key));
-		if (keys == NULL)
-			return;
-		memset(keys, 0, n_keys * sizeof(struct pipeline_fc_key));
-
-		port_ids = malloc(n_keys * sizeof(uint32_t));
-		if (port_ids == NULL) {
-			free(keys);
-			return;
-		}
-
-		flow_ids = malloc(n_keys * sizeof(uint32_t));
-		if (flow_ids == NULL) {
-			free(port_ids);
-			free(keys);
-			return;
-		}
-
-		status = app_pipeline_fc_load_file_ipv6(filename,
-			keys,
-			port_ids,
-			flow_ids,
-			&n_keys,
-			&line);
-		if (status != 0) {
-			printf(CMD_MSG_FILE_ERR, filename, line);
-			free(flow_ids);
-			free(port_ids);
-			free(keys);
-			return;
-		}
-
-		status = app_pipeline_fc_add_bulk(app,
-			results->pipeline_id,
-			keys,
-			port_ids,
-			flow_ids,
-			n_keys);
-		if (status)
-			printf(CMD_MSG_FAIL, "flow add ipv6 bulk");
-
-		free(flow_ids);
-		free(port_ids);
-		free(keys);
-		return;
-	} /* flow add ipv6 bulk */
-
-	/* flow add default*/
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "add") == 0) &&
-		(strcmp(tokens[1], "default") == 0)) {
-		uint32_t port_id;
-
-		if (n_tokens != 3) {
-			printf(CMD_MSG_MISMATCH_ARGS, "flow add default");
-			return;
-		}
-
-		if (parser_read_uint32(&port_id, tokens[2]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "portid");
-			return;
-		}
-
-		status = app_pipeline_fc_add_default(app,
-			results->pipeline_id,
-			port_id);
-		if (status)
-			printf(CMD_MSG_FAIL, "flow add default");
-
-		return;
-	} /* flow add default */
-
-	/* flow del qinq */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "del") == 0) &&
-		(strcmp(tokens[1], "qinq") == 0)) {
-		struct pipeline_fc_key key;
-		uint32_t svlan;
-		uint32_t cvlan;
-
-		memset(&key, 0, sizeof(key));
-
-		if (n_tokens != 4) {
-			printf(CMD_MSG_MISMATCH_ARGS, "flow del qinq");
-			return;
-		}
-
-		if (parser_read_uint32(&svlan, tokens[2]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "svlan");
-			return;
-		}
-
-		if (parser_read_uint32(&cvlan, tokens[3]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "cvlan");
-			return;
-		}
-
-		key.type = FLOW_KEY_QINQ;
-		key.key.qinq.svlan = svlan;
-		key.key.qinq.cvlan = cvlan;
-
-		status = app_pipeline_fc_del(app,
-			results->pipeline_id,
-			&key);
-		if (status)
-			printf(CMD_MSG_FAIL, "flow del qinq");
-
-		return;
-	} /* flow del qinq */
-
-	/* flow del ipv4 */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "del") == 0) &&
-		(strcmp(tokens[1], "ipv4") == 0)) {
-		struct pipeline_fc_key key;
-		struct in_addr sipaddr;
-		struct in_addr dipaddr;
-		uint32_t sport;
-		uint32_t dport;
-		uint32_t proto;
-
-		memset(&key, 0, sizeof(key));
-
-		if (n_tokens != 7) {
-			printf(CMD_MSG_MISMATCH_ARGS, "flow del ipv4");
-			return;
-		}
-
-		if (parse_ipv4_addr(tokens[2], &sipaddr) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "sipv4addr");
-			return;
-		}
-		if (parse_ipv4_addr(tokens[3], &dipaddr) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "dipv4addr");
-			return;
-		}
-
-		if (parser_read_uint32(&sport, tokens[4]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "sport");
-			return;
-		}
-
-		if (parser_read_uint32(&dport, tokens[5]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "dport");
-			return;
-		}
-
-		if (parser_read_uint32(&proto, tokens[6]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "proto");
-			return;
-		}
-
-		key.type = FLOW_KEY_IPV4_5TUPLE;
-		key.key.ipv4_5tuple.ip_src = rte_be_to_cpu_32(sipaddr.s_addr);
-		key.key.ipv4_5tuple.ip_dst = rte_be_to_cpu_32(dipaddr.s_addr);
-		key.key.ipv4_5tuple.port_src = sport;
-		key.key.ipv4_5tuple.port_dst = dport;
-		key.key.ipv4_5tuple.proto = proto;
-
-		status = app_pipeline_fc_del(app,
-			results->pipeline_id,
-			&key);
-		if (status)
-			printf(CMD_MSG_FAIL, "flow del ipv4");
-
-		return;
-	} /* flow del ipv4 */
-
-	/* flow del ipv6 */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "del") == 0) &&
-		(strcmp(tokens[1], "ipv6") == 0)) {
-		struct pipeline_fc_key key;
-		struct in6_addr sipaddr;
-		struct in6_addr dipaddr;
-		uint32_t sport;
-		uint32_t dport;
-		uint32_t proto;
-
-		memset(&key, 0, sizeof(key));
-
-		if (n_tokens != 7) {
-			printf(CMD_MSG_MISMATCH_ARGS, "flow del ipv6");
-			return;
-		}
-
-		if (parse_ipv6_addr(tokens[2], &sipaddr) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "sipv6addr");
-			return;
-		}
-
-		if (parse_ipv6_addr(tokens[3], &dipaddr) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "dipv6addr");
-			return;
-		}
-
-		if (parser_read_uint32(&sport, tokens[4]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "sport");
-			return;
-		}
-
-		if (parser_read_uint32(&dport, tokens[5]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "dport");
-			return;
-		}
-
-		if (parser_read_uint32(&proto, tokens[6]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "proto");
-			return;
-		}
-
-		key.type = FLOW_KEY_IPV6_5TUPLE;
-		memcpy(key.key.ipv6_5tuple.ip_src, &sipaddr, 16);
-		memcpy(key.key.ipv6_5tuple.ip_dst, &dipaddr, 16);
-		key.key.ipv6_5tuple.port_src = sport;
-		key.key.ipv6_5tuple.port_dst = dport;
-		key.key.ipv6_5tuple.proto = proto;
-
-		status = app_pipeline_fc_del(app,
-			results->pipeline_id,
-			&key);
-		if (status)
-			printf(CMD_MSG_FAIL, "flow del ipv6");
-
-		return;
-	} /* flow del ipv6 */
-
-	/* flow del default*/
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "del") == 0) &&
-		(strcmp(tokens[1], "default") == 0)) {
-		if (n_tokens != 2) {
-			printf(CMD_MSG_MISMATCH_ARGS, "flow del default");
-			return;
-		}
-
-		status = app_pipeline_fc_del_default(app,
-			results->pipeline_id);
-		if (status)
-			printf(CMD_MSG_FAIL, "flow del default");
-
-		return;
-	} /* flow del default */
-
-	/* flow ls */
-	if ((n_tokens >= 1) && (strcmp(tokens[0], "ls") == 0)) {
-		if (n_tokens != 1) {
-			printf(CMD_MSG_MISMATCH_ARGS, "flow ls");
-			return;
-		}
-
-		status = app_pipeline_fc_ls(app, results->pipeline_id);
-		if (status)
-			printf(CMD_MSG_FAIL, "flow ls");
-
-		return;
-	} /* flow ls */
-
-	printf(CMD_MSG_MISMATCH_ARGS, "flow");
-}
-
-static cmdline_parse_token_string_t cmd_flow_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_flow_result, p_string, "p");
-
-static cmdline_parse_token_num_t cmd_flow_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_flow_result, pipeline_id, UINT32);
-
-static cmdline_parse_token_string_t cmd_flow_flow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_flow_result, flow_string, "flow");
-
-static cmdline_parse_token_string_t cmd_flow_multi_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_flow_result, multi_string,
-		TOKEN_STRING_MULTI);
-
-static cmdline_parse_inst_t cmd_flow = {
-	.f = cmd_flow_parsed,
-	.data = NULL,
-	.help_str = "flow add / add bulk / add default / del / del default / ls",
-	.tokens = {
-		(void *) &cmd_flow_p_string,
-		(void *) &cmd_flow_pipeline_id,
-		(void *) &cmd_flow_flow_string,
-		(void *) &cmd_flow_multi_string,
-		NULL,
-	},
-};
-
-static cmdline_parse_ctx_t pipeline_cmds[] = {
-	(cmdline_parse_inst_t *) &cmd_flow,
-	NULL,
-};
-
-static struct pipeline_fe_ops pipeline_flow_classification_fe_ops = {
-	.f_init = app_pipeline_fc_init,
-	.f_post_init = NULL,
-	.f_free = app_pipeline_fc_free,
-	.f_track = app_pipeline_track_default,
-	.cmds = pipeline_cmds,
-};
-
-struct pipeline_type pipeline_flow_classification = {
-	.name = "FLOW_CLASSIFICATION",
-	.be_ops = &pipeline_flow_classification_be_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
deleted file mode 100644
index 8c35498..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_flow_classification.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#ifndef __INCLUDE_PIPELINE_FLOW_CLASSIFICATION_H__
-#define __INCLUDE_PIPELINE_FLOW_CLASSIFICATION_H__
-
-#include "pipeline.h"
-#include "pipeline_flow_classification_be.h"
-
-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;
-	} key;
-};
-
-int
-app_pipeline_fc_add(struct app_params *app,
-	uint32_t pipeline_id,
-	struct pipeline_fc_key *key,
-	uint32_t port_id,
-	uint32_t flow_id);
-
-int
-app_pipeline_fc_add_bulk(struct app_params *app,
-	uint32_t pipeline_id,
-	struct pipeline_fc_key *key,
-	uint32_t *port_id,
-	uint32_t *flow_id,
-	uint32_t n_keys);
-
-int
-app_pipeline_fc_del(struct app_params *app,
-	uint32_t pipeline_id,
-	struct pipeline_fc_key *key);
-
-int
-app_pipeline_fc_add_default(struct app_params *app,
-	uint32_t pipeline_id,
-	uint32_t port_id);
-
-int
-app_pipeline_fc_del_default(struct app_params *app,
-	uint32_t pipeline_id);
-
-#ifndef APP_PIPELINE_FC_MAX_FLOWS_IN_FILE
-#define APP_PIPELINE_FC_MAX_FLOWS_IN_FILE	(16 * 1024 * 1024)
-#endif
-
-int
-app_pipeline_fc_load_file_qinq(char *filename,
-	struct pipeline_fc_key *keys,
-	uint32_t *port_ids,
-	uint32_t *flow_ids,
-	uint32_t *n_keys,
-	uint32_t *line);
-
-int
-app_pipeline_fc_load_file_ipv4(char *filename,
-	struct pipeline_fc_key *keys,
-	uint32_t *port_ids,
-	uint32_t *flow_ids,
-	uint32_t *n_keys,
-	uint32_t *line);
-
-int
-app_pipeline_fc_load_file_ipv6(char *filename,
-	struct pipeline_fc_key *keys,
-	uint32_t *port_ids,
-	uint32_t *flow_ids,
-	uint32_t *n_keys,
-	uint32_t *line);
-
-extern struct pipeline_type pipeline_flow_classification;
-
-#endif
diff --git a/examples/ip_pipeline/pipeline/pipeline_flow_classification_be.c b/examples/ip_pipeline/pipeline/pipeline_flow_classification_be.c
deleted file mode 100644
index 097ec34..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_flow_classification_be.c
+++ /dev/null
@@ -1,723 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2016 Intel Corporation
- */
-
-#include <string.h>
-
-#include <rte_common.h>
-#include <rte_malloc.h>
-#include <rte_table_hash.h>
-#include <rte_byteorder.h>
-#include <pipeline.h>
-
-#include "pipeline_flow_classification_be.h"
-#include "pipeline_actions_common.h"
-#include "parser.h"
-#include "hash_func.h"
-
-struct pipeline_flow_classification {
-	struct pipeline p;
-	pipeline_msg_req_handler custom_handlers[PIPELINE_FC_MSG_REQS];
-
-	uint32_t n_flows;
-	uint32_t key_size;
-	uint32_t flow_id;
-
-	uint32_t key_offset;
-	uint32_t hash_offset;
-	uint8_t key_mask[PIPELINE_FC_FLOW_KEY_MAX_SIZE];
-	uint32_t key_mask_present;
-	uint32_t flow_id_offset;
-
-} __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_add_bulk_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 pipeline_msg_req_handler custom_handlers[] = {
-	[PIPELINE_FC_MSG_REQ_FLOW_ADD] =
-		pipeline_fc_msg_req_add_handler,
-	[PIPELINE_FC_MSG_REQ_FLOW_ADD_BULK] =
-		pipeline_fc_msg_req_add_bulk_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,
-};
-
-/*
- * Flow table
- */
-struct flow_table_entry {
-	struct rte_pipeline_table_entry head;
-
-	uint32_t flow_id;
-	uint32_t pad;
-};
-
-rte_table_hash_op_hash hash_func[] = {
-	hash_default_key8,
-	hash_default_key16,
-	hash_default_key24,
-	hash_default_key32,
-	hash_default_key40,
-	hash_default_key48,
-	hash_default_key56,
-	hash_default_key64
-};
-
-/*
- * Flow table AH - Write flow_id to packet meta-data
- */
-static inline void
-pkt_work_flow_id(
-	struct rte_mbuf *pkt,
-	struct rte_pipeline_table_entry *table_entry,
-	void *arg)
-{
-	struct pipeline_flow_classification *p_fc = arg;
-	uint32_t *flow_id_ptr =
-		RTE_MBUF_METADATA_UINT32_PTR(pkt, p_fc->flow_id_offset);
-	struct flow_table_entry *entry =
-		(struct flow_table_entry *) table_entry;
-
-	/* Read */
-	uint32_t flow_id = entry->flow_id;
-
-	/* Compute */
-
-	/* Write */
-	*flow_id_ptr = flow_id;
-}
-
-static inline void
-pkt4_work_flow_id(
-	struct rte_mbuf **pkts,
-	struct rte_pipeline_table_entry **table_entries,
-	void *arg)
-{
-	struct pipeline_flow_classification *p_fc = arg;
-
-	uint32_t *flow_id_ptr0 =
-		RTE_MBUF_METADATA_UINT32_PTR(pkts[0], p_fc->flow_id_offset);
-	uint32_t *flow_id_ptr1 =
-		RTE_MBUF_METADATA_UINT32_PTR(pkts[1], p_fc->flow_id_offset);
-	uint32_t *flow_id_ptr2 =
-		RTE_MBUF_METADATA_UINT32_PTR(pkts[2], p_fc->flow_id_offset);
-	uint32_t *flow_id_ptr3 =
-		RTE_MBUF_METADATA_UINT32_PTR(pkts[3], p_fc->flow_id_offset);
-
-	struct flow_table_entry *entry0 =
-		(struct flow_table_entry *) table_entries[0];
-	struct flow_table_entry *entry1 =
-		(struct flow_table_entry *) table_entries[1];
-	struct flow_table_entry *entry2 =
-		(struct flow_table_entry *) table_entries[2];
-	struct flow_table_entry *entry3 =
-		(struct flow_table_entry *) table_entries[3];
-
-	/* Read */
-	uint32_t flow_id0 = entry0->flow_id;
-	uint32_t flow_id1 = entry1->flow_id;
-	uint32_t flow_id2 = entry2->flow_id;
-	uint32_t flow_id3 = entry3->flow_id;
-
-	/* Compute */
-
-	/* Write */
-	*flow_id_ptr0 = flow_id0;
-	*flow_id_ptr1 = flow_id1;
-	*flow_id_ptr2 = flow_id2;
-	*flow_id_ptr3 = flow_id3;
-}
-
-PIPELINE_TABLE_AH_HIT(fc_table_ah_hit,
-		pkt_work_flow_id, pkt4_work_flow_id);
-
-static rte_pipeline_table_action_handler_hit
-get_fc_table_ah_hit(struct pipeline_flow_classification *p)
-{
-	if (p->flow_id)
-		return fc_table_ah_hit;
-
-	return NULL;
-}
-
-/*
- * Argument parsing
- */
-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 key_mask_present = 0;
-	uint32_t flow_id_offset_present = 0;
-
-	uint32_t i;
-	char key_mask_str[PIPELINE_FC_FLOW_KEY_MAX_SIZE * 2 + 1];
-
-	p->hash_offset = 0;
-
-	/* default values */
-	p->flow_id = 0;
-
-	for (i = 0; i < params->n_args; i++) {
-		char *arg_name = params->args_name[i];
-		char *arg_value = params->args_value[i];
-
-		/* n_flows */
-		if (strcmp(arg_name, "n_flows") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				n_flows_present == 0, params->name,
-				arg_name);
-			n_flows_present = 1;
-
-			status = parser_read_uint32(&p->n_flows,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL(((status != -EINVAL) &&
-				(p->n_flows != 0)), params->name,
-				arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			continue;
-		}
-
-		/* key_offset */
-		if (strcmp(arg_name, "key_offset") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				key_offset_present == 0, params->name,
-				arg_name);
-			key_offset_present = 1;
-
-			status = parser_read_uint32(&p->key_offset,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			continue;
-		}
-
-		/* key_size */
-		if (strcmp(arg_name, "key_size") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				key_size_present == 0, params->name,
-				arg_name);
-			key_size_present = 1;
-
-			status = parser_read_uint32(&p->key_size,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL(((status != -EINVAL) &&
-				(p->key_size != 0) &&
-				(p->key_size % 8 == 0)),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG(((status != -ERANGE) &&
-				(p->key_size <=
-				PIPELINE_FC_FLOW_KEY_MAX_SIZE)),
-				params->name, arg_name, arg_value);
-
-			continue;
-		}
-
-		/* key_mask */
-		if (strcmp(arg_name, "key_mask") == 0) {
-			int mask_str_len = strlen(arg_value);
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				key_mask_present == 0,
-				params->name, arg_name);
-			key_mask_present = 1;
-
-			PIPELINE_ARG_CHECK((mask_str_len <=
-				(PIPELINE_FC_FLOW_KEY_MAX_SIZE * 2)),
-				"Parse error in section \"%s\": entry "
-				"\"%s\" is too long", params->name,
-				arg_name);
-
-			snprintf(key_mask_str, mask_str_len + 1, "%s",
-				arg_value);
-
-			continue;
-		}
-
-		/* hash_offset */
-		if (strcmp(arg_name, "hash_offset") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				hash_offset_present == 0, params->name,
-				arg_name);
-			hash_offset_present = 1;
-
-			status = parser_read_uint32(&p->hash_offset,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			continue;
-		}
-
-		/* flow_id_offset */
-		if (strcmp(arg_name, "flowid_offset") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				flow_id_offset_present == 0, params->name,
-				arg_name);
-			flow_id_offset_present = 1;
-
-			status = parser_read_uint32(&p->flow_id_offset,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			p->flow_id = 1;
-
-			continue;
-		}
-
-		/* Unknown argument */
-		PIPELINE_PARSE_ERR_INV_ENT(0, params->name, arg_name);
-	}
-
-	/* Check that mandatory arguments are present */
-	PIPELINE_PARSE_ERR_MANDATORY((n_flows_present), params->name,
-		"n_flows");
-	PIPELINE_PARSE_ERR_MANDATORY((key_offset_present), params->name,
-		"key_offset");
-	PIPELINE_PARSE_ERR_MANDATORY((key_size_present), params->name,
-		"key_size");
-
-	if (key_mask_present) {
-		uint32_t key_size = p->key_size;
-		int status;
-
-		PIPELINE_ARG_CHECK(((key_size == 8) || (key_size == 16)),
-			"Parse error in section \"%s\": entry key_mask "
-			"only allowed for key_size of 8 or 16 bytes",
-			params->name);
-
-		PIPELINE_ARG_CHECK((strlen(key_mask_str) ==
-			(key_size * 2)), "Parse error in section "
-			"\"%s\": key_mask should have exactly %u hex "
-			"digits", params->name, (key_size * 2));
-
-		PIPELINE_ARG_CHECK((hash_offset_present == 0), "Parse "
-			"error in section \"%s\": entry hash_offset only "
-			"allowed when key_mask is not present",
-			params->name);
-
-		status = parse_hex_string(key_mask_str, p->key_mask,
-			&p->key_size);
-
-		PIPELINE_PARSE_ERR_INV_VAL(((status == 0) &&
-			(key_size == p->key_size)), params->name,
-			"key_mask", key_mask_str);
-	}
-
-	p->key_mask_present = key_mask_present;
-
-	return 0;
-}
-
-static void *pipeline_fc_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 = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
-	if (p == NULL)
-		return NULL;
-	p_fc = (struct pipeline_flow_classification *) p;
-
-	strcpy(p->name, params->name);
-	p->log_level = params->log_level;
-
-	PLOG(p, HIGH, "Flow classification");
-
-	/* Parse arguments */
-	if (pipeline_fc_parse_args(p_fc, 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,
-			.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_params table_hash_params = {
-			.name = p->name,
-			.key_size = p_fc->key_size,
-			.key_offset = p_fc->key_offset,
-			.key_mask = (p_fc->key_mask_present) ?
-				p_fc->key_mask : NULL,
-			.n_keys = p_fc->n_flows,
-			.n_buckets = rte_align32pow2(p_fc->n_flows / 4),
-			.f_hash = hash_func[(p_fc->key_size / 8) - 1],
-			.seed = 0,
-		};
-
-		struct rte_pipeline_table_params table_params = {
-			.ops = NULL, /* set below */
-			.arg_create = NULL, /* set below */
-			.f_action_hit = get_fc_table_ah_hit(p_fc),
-			.f_action_miss = NULL,
-			.arg_ah = p_fc,
-			.action_data_size = sizeof(struct flow_table_entry) -
-				sizeof(struct rte_pipeline_table_entry),
-		};
-
-		int status;
-
-		switch (p_fc->key_size) {
-		case 8:
-			table_params.ops = &rte_table_hash_key8_ext_ops;
-			break;
-
-		case 16:
-			table_params.ops = &rte_table_hash_key16_ext_ops;
-			break;
-
-		default:
-			table_params.ops = &rte_table_hash_ext_ops;
-		}
-
-		table_params.arg_create = &table_hash_params;
-
-		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_fc_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_fc_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 flow_table_entry entry = {
-		.head = {
-			.action = RTE_PIPELINE_ACTION_PORT,
-			{.port_id = p->port_out_id[req->port_id]},
-		},
-		.flow_id = req->flow_id,
-	};
-
-	rsp->status = rte_pipeline_table_entry_add(p->p,
-		p->table_id[0],
-		&req->key,
-		(struct rte_pipeline_table_entry *) &entry,
-		&rsp->key_found,
-		(struct rte_pipeline_table_entry **) &rsp->entry_ptr);
-
-	return rsp;
-}
-
-static void *
-pipeline_fc_msg_req_add_bulk_handler(struct pipeline *p, void *msg)
-{
-	struct pipeline_fc_add_bulk_msg_req *req = msg;
-	struct pipeline_fc_add_bulk_msg_rsp *rsp = msg;
-	uint32_t i;
-
-	for (i = 0; i < req->n_keys; i++) {
-		struct pipeline_fc_add_bulk_flow_req *flow_req = &req->req[i];
-		struct pipeline_fc_add_bulk_flow_rsp *flow_rsp = &req->rsp[i];
-
-		struct flow_table_entry entry = {
-			.head = {
-				.action = RTE_PIPELINE_ACTION_PORT,
-				{.port_id = p->port_out_id[flow_req->port_id]},
-			},
-			.flow_id = flow_req->flow_id,
-		};
-
-		int status = rte_pipeline_table_entry_add(p->p,
-			p->table_id[0],
-			&flow_req->key,
-			(struct rte_pipeline_table_entry *) &entry,
-			&flow_rsp->key_found,
-			(struct rte_pipeline_table_entry **)
-				&flow_rsp->entry_ptr);
-
-		if (status)
-			break;
-	}
-
-	rsp->n_keys = i;
-
-	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;
-
-	rsp->status = rte_pipeline_table_entry_delete(p->p,
-		p->table_id[0],
-		&req->key,
-		&rsp->key_found,
-		NULL);
-
-	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 flow_table_entry default_entry = {
-		.head = {
-			.action = RTE_PIPELINE_ACTION_PORT,
-			{.port_id = p->port_out_id[req->port_id]},
-		},
-
-		.flow_id = 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;
-}
-
-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;
-}
-
-struct pipeline_be_ops pipeline_flow_classification_be_ops = {
-	.f_init = pipeline_fc_init,
-	.f_free = pipeline_fc_free,
-	.f_run = NULL,
-	.f_timer = pipeline_fc_timer,
-};
diff --git a/examples/ip_pipeline/pipeline/pipeline_flow_classification_be.h b/examples/ip_pipeline/pipeline/pipeline_flow_classification_be.h
deleted file mode 100644
index 18f5bb4..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_flow_classification_be.h
+++ /dev/null
@@ -1,113 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#ifndef __INCLUDE_PIPELINE_FLOW_CLASSIFICATION_BE_H__
-#define __INCLUDE_PIPELINE_FLOW_CLASSIFICATION_BE_H__
-
-#include "pipeline_common_be.h"
-
-enum pipeline_fc_msg_req_type {
-	PIPELINE_FC_MSG_REQ_FLOW_ADD = 0,
-	PIPELINE_FC_MSG_REQ_FLOW_ADD_BULK,
-	PIPELINE_FC_MSG_REQ_FLOW_DEL,
-	PIPELINE_FC_MSG_REQ_FLOW_ADD_DEFAULT,
-	PIPELINE_FC_MSG_REQ_FLOW_DEL_DEFAULT,
-	PIPELINE_FC_MSG_REQS,
-};
-
-#ifndef PIPELINE_FC_FLOW_KEY_MAX_SIZE
-#define PIPELINE_FC_FLOW_KEY_MAX_SIZE            64
-#endif
-
-/*
- * MSG ADD
- */
-struct pipeline_fc_add_msg_req {
-	enum pipeline_msg_req_type type;
-	enum pipeline_fc_msg_req_type subtype;
-
-	uint8_t key[PIPELINE_FC_FLOW_KEY_MAX_SIZE];
-
-	uint32_t port_id;
-	uint32_t flow_id;
-};
-
-struct pipeline_fc_add_msg_rsp {
-	int status;
-	int key_found;
-	void *entry_ptr;
-};
-
-/*
- * MSG ADD BULK
- */
-struct pipeline_fc_add_bulk_flow_req {
-	uint8_t key[PIPELINE_FC_FLOW_KEY_MAX_SIZE];
-	uint32_t port_id;
-	uint32_t flow_id;
-};
-
-struct pipeline_fc_add_bulk_flow_rsp {
-	int key_found;
-	void *entry_ptr;
-};
-
-struct pipeline_fc_add_bulk_msg_req {
-	enum pipeline_msg_req_type type;
-	enum pipeline_fc_msg_req_type subtype;
-
-	struct pipeline_fc_add_bulk_flow_req *req;
-	struct pipeline_fc_add_bulk_flow_rsp *rsp;
-	uint32_t n_keys;
-};
-
-struct pipeline_fc_add_bulk_msg_rsp {
-	uint32_t n_keys;
-};
-
-/*
- * MSG DEL
- */
-struct pipeline_fc_del_msg_req {
-	enum pipeline_msg_req_type type;
-	enum pipeline_fc_msg_req_type subtype;
-
-	uint8_t key[PIPELINE_FC_FLOW_KEY_MAX_SIZE];
-};
-
-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 *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_be_ops pipeline_flow_classification_be_ops;
-
-#endif
-- 
2.9.3

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

* [dpdk-dev] [PATCH v2 13/44] ip_pipeline: remove flow actions pipeline
  2018-03-12 17:25   ` [dpdk-dev] [PATCH v2 00/44] ip_pipeline: refactoring Jasvinder Singh
                       ` (11 preceding siblings ...)
  2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 12/44] ip_pipeline: remove flow classification pipeline Jasvinder Singh
@ 2018-03-12 17:25     ` Jasvinder Singh
  2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 14/44] ip_pipeline: remove firewall pipeline Jasvinder Singh
                       ` (30 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-12 17:25 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Remove flow actions pipeline.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/Makefile                      |    2 -
 examples/ip_pipeline/init.c                        |    2 -
 examples/ip_pipeline/meson.build                   |    2 -
 .../ip_pipeline/pipeline/pipeline_flow_actions.c   | 1286 --------------------
 .../ip_pipeline/pipeline/pipeline_flow_actions.h   |   60 -
 .../pipeline/pipeline_flow_actions_be.c            |  983 ---------------
 .../pipeline/pipeline_flow_actions_be.h            |  139 ---
 7 files changed, 2474 deletions(-)
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_actions.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_actions.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_actions_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_actions_be.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index e43001f..0782308 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -21,8 +21,6 @@ SRCS-y += pipeline_master_be.c
 SRCS-y += pipeline_master.c
 SRCS-y += pipeline_firewall_be.c
 SRCS-y += pipeline_firewall.c
-SRCS-y += pipeline_flow_actions_be.c
-SRCS-y += pipeline_flow_actions.c
 
 # Build using pkg-config variables if possible
 $(shell pkg-config --exists libdpdk)
diff --git a/examples/ip_pipeline/init.c b/examples/ip_pipeline/init.c
index 4780bb1..6599b0d 100644
--- a/examples/ip_pipeline/init.c
+++ b/examples/ip_pipeline/init.c
@@ -27,7 +27,6 @@
 #include "pipeline_common_fe.h"
 #include "pipeline_master.h"
 #include "pipeline_firewall.h"
-#include "pipeline_flow_actions.h"
 #include "thread_fe.h"
 
 #define APP_NAME_SIZE	32
@@ -1819,7 +1818,6 @@ int app_init(struct app_params *app)
 	app_pipeline_common_cmd_push(app);
 	app_pipeline_thread_cmd_push(app);
 	app_pipeline_type_register(app, &pipeline_master);
-	app_pipeline_type_register(app, &pipeline_flow_actions);
 	app_pipeline_type_register(app, &pipeline_firewall);
 
 	app_init_pipelines(app);
diff --git a/examples/ip_pipeline/meson.build b/examples/ip_pipeline/meson.build
index a04e418..802c82c 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -22,8 +22,6 @@ sources = files(
 	'pipeline/pipeline_common_fe.c',
 	'pipeline/pipeline_firewall_be.c',
 	'pipeline/pipeline_firewall.c',
-	'pipeline/pipeline_flow_actions_be.c',
-	'pipeline/pipeline_flow_actions.c',
 	'pipeline/pipeline_master_be.c',
 	'pipeline/pipeline_master.c',
 )
diff --git a/examples/ip_pipeline/pipeline/pipeline_flow_actions.c b/examples/ip_pipeline/pipeline/pipeline_flow_actions.c
deleted file mode 100644
index 021aee1..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_flow_actions.c
+++ /dev/null
@@ -1,1286 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <sys/queue.h>
-#include <netinet/in.h>
-#include <unistd.h>
-
-#include <rte_common.h>
-#include <rte_hexdump.h>
-#include <rte_malloc.h>
-#include <cmdline_rdline.h>
-#include <cmdline_parse.h>
-#include <cmdline_parse_num.h>
-#include <cmdline_parse_string.h>
-
-#include "app.h"
-#include "pipeline_common_fe.h"
-#include "pipeline_flow_actions.h"
-#include "hash_func.h"
-#include "parser.h"
-
-/*
- * Flow actions pipeline
- */
-#ifndef N_FLOWS_BULK
-#define N_FLOWS_BULK					4096
-#endif
-
-struct app_pipeline_fa_flow {
-	struct pipeline_fa_flow_params params;
-	void *entry_ptr;
-};
-
-struct app_pipeline_fa_dscp {
-	uint32_t traffic_class;
-	enum rte_meter_color color;
-};
-
-struct app_pipeline_fa {
-	/* Parameters */
-	uint32_t n_ports_in;
-	uint32_t n_ports_out;
-	struct pipeline_fa_params params;
-
-	/* Flows */
-	struct app_pipeline_fa_dscp dscp[PIPELINE_FA_N_DSCP];
-	struct app_pipeline_fa_flow *flows;
-} __rte_cache_aligned;
-
-static void*
-app_pipeline_fa_init(struct pipeline_params *params,
-	__rte_unused void *arg)
-{
-	struct app_pipeline_fa *p;
-	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 app_pipeline_fa));
-	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;
-	if (pipeline_fa_parse_args(&p->params, params)) {
-		rte_free(p);
-		return NULL;
-	}
-
-	/* Memory allocation */
-	size = RTE_CACHE_LINE_ROUNDUP(
-		p->params.n_flows * sizeof(struct app_pipeline_fa_flow));
-	p->flows = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
-	if (p->flows == NULL) {
-		rte_free(p);
-		return NULL;
-	}
-
-	/* Initialization of flow table */
-	for (i = 0; i < p->params.n_flows; i++)
-		pipeline_fa_flow_params_set_default(&p->flows[i].params);
-
-	/* Initialization of DSCP table */
-	for (i = 0; i < RTE_DIM(p->dscp); i++) {
-		p->dscp[i].traffic_class = 0;
-		p->dscp[i].color = e_RTE_METER_GREEN;
-	}
-
-	return (void *) p;
-}
-
-static int
-app_pipeline_fa_free(void *pipeline)
-{
-	struct app_pipeline_fa *p = pipeline;
-
-	/* Check input arguments */
-	if (p == NULL)
-		return -1;
-
-	/* Free resources */
-	rte_free(p->flows);
-	rte_free(p);
-
-	return 0;
-}
-
-static int
-flow_params_check(struct app_pipeline_fa *p,
-	__rte_unused uint32_t meter_update_mask,
-	uint32_t policer_update_mask,
-	uint32_t port_update,
-	struct pipeline_fa_flow_params *params)
-{
-	uint32_t mask, i;
-
-	/* Meter */
-
-	/* Policer */
-	for (i = 0, mask = 1; i < PIPELINE_FA_N_TC_MAX; i++, mask <<= 1) {
-		struct pipeline_fa_policer_params *p = &params->p[i];
-		uint32_t j;
-
-		if ((mask & policer_update_mask) == 0)
-			continue;
-
-		for (j = 0; j < e_RTE_METER_COLORS; j++) {
-			struct pipeline_fa_policer_action *action =
-				&p->action[j];
-
-			if ((action->drop == 0) &&
-				(action->color >= e_RTE_METER_COLORS))
-				return -1;
-		}
-	}
-
-	/* Port */
-	if (port_update && (params->port_id >= p->n_ports_out))
-		return -1;
-
-	return 0;
-}
-
-int
-app_pipeline_fa_flow_config(struct app_params *app,
-	uint32_t pipeline_id,
-	uint32_t flow_id,
-	uint32_t meter_update_mask,
-	uint32_t policer_update_mask,
-	uint32_t port_update,
-	struct pipeline_fa_flow_params *params)
-{
-	struct app_pipeline_fa *p;
-	struct app_pipeline_fa_flow *flow;
-
-	struct pipeline_fa_flow_config_msg_req *req;
-	struct pipeline_fa_flow_config_msg_rsp *rsp;
-
-	uint32_t i, mask;
-
-	/* Check input arguments */
-	if ((app == NULL) ||
-		((meter_update_mask == 0) &&
-		(policer_update_mask == 0) &&
-		(port_update == 0)) ||
-		(meter_update_mask >= (1 << PIPELINE_FA_N_TC_MAX)) ||
-		(policer_update_mask >= (1 << PIPELINE_FA_N_TC_MAX)) ||
-		(params == NULL))
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id,
-		&pipeline_flow_actions);
-	if (p == NULL)
-		return -1;
-
-	if (flow_params_check(p,
-		meter_update_mask,
-		policer_update_mask,
-		port_update,
-		params) != 0)
-		return -1;
-
-	flow_id %= p->params.n_flows;
-	flow = &p->flows[flow_id];
-
-	/* Allocate and write request */
-	req = app_msg_alloc(app);
-	if (req == NULL)
-		return -1;
-
-	req->type = PIPELINE_MSG_REQ_CUSTOM;
-	req->subtype = PIPELINE_FA_MSG_REQ_FLOW_CONFIG;
-	req->entry_ptr = flow->entry_ptr;
-	req->flow_id = flow_id;
-	req->meter_update_mask = meter_update_mask;
-	req->policer_update_mask = policer_update_mask;
-	req->port_update = port_update;
-	memcpy(&req->params, params, sizeof(*params));
-
-	/* Send request and wait for response */
-	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	/* Read response */
-	if (rsp->status ||
-		(rsp->entry_ptr == NULL)) {
-		app_msg_free(app, rsp);
-		return -1;
-	}
-
-	/* Commit flow */
-	for (i = 0, mask = 1; i < PIPELINE_FA_N_TC_MAX; i++, mask <<= 1) {
-		if ((mask & meter_update_mask) == 0)
-			continue;
-
-		memcpy(&flow->params.m[i], &params->m[i], sizeof(params->m[i]));
-	}
-
-	for (i = 0, mask = 1; i < PIPELINE_FA_N_TC_MAX; i++, mask <<= 1) {
-		if ((mask & policer_update_mask) == 0)
-			continue;
-
-		memcpy(&flow->params.p[i], &params->p[i], sizeof(params->p[i]));
-	}
-
-	if (port_update)
-		flow->params.port_id = params->port_id;
-
-	flow->entry_ptr = rsp->entry_ptr;
-
-	/* Free response */
-	app_msg_free(app, rsp);
-
-	return 0;
-}
-
-int
-app_pipeline_fa_flow_config_bulk(struct app_params *app,
-	uint32_t pipeline_id,
-	uint32_t *flow_id,
-	uint32_t n_flows,
-	uint32_t meter_update_mask,
-	uint32_t policer_update_mask,
-	uint32_t port_update,
-	struct pipeline_fa_flow_params *params)
-{
-	struct app_pipeline_fa *p;
-	struct pipeline_fa_flow_config_bulk_msg_req *req;
-	struct pipeline_fa_flow_config_bulk_msg_rsp *rsp;
-	void **req_entry_ptr;
-	uint32_t *req_flow_id;
-	uint32_t i;
-	int status;
-
-	/* Check input arguments */
-	if ((app == NULL) ||
-		(flow_id == NULL) ||
-		(n_flows == 0) ||
-		((meter_update_mask == 0) &&
-		(policer_update_mask == 0) &&
-		(port_update == 0)) ||
-		(meter_update_mask >= (1 << PIPELINE_FA_N_TC_MAX)) ||
-		(policer_update_mask >= (1 << PIPELINE_FA_N_TC_MAX)) ||
-		(params == NULL))
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id,
-		&pipeline_flow_actions);
-	if (p == NULL)
-		return -1;
-
-	for (i = 0; i < n_flows; i++) {
-		struct pipeline_fa_flow_params *flow_params = &params[i];
-
-		if (flow_params_check(p,
-			meter_update_mask,
-			policer_update_mask,
-			port_update,
-			flow_params) != 0)
-			return -1;
-	}
-
-	/* Allocate and write request */
-	req_entry_ptr = (void **) rte_malloc(NULL,
-		n_flows * sizeof(void *),
-		RTE_CACHE_LINE_SIZE);
-	if (req_entry_ptr == NULL)
-		return -1;
-
-	req_flow_id = (uint32_t *) rte_malloc(NULL,
-		n_flows * sizeof(uint32_t),
-		RTE_CACHE_LINE_SIZE);
-	if (req_flow_id == NULL) {
-		rte_free(req_entry_ptr);
-		return -1;
-	}
-
-	for (i = 0; i < n_flows; i++) {
-		uint32_t fid = flow_id[i] % p->params.n_flows;
-		struct app_pipeline_fa_flow *flow = &p->flows[fid];
-
-		req_flow_id[i] = fid;
-		req_entry_ptr[i] = flow->entry_ptr;
-	}
-
-	req = app_msg_alloc(app);
-	if (req == NULL) {
-		rte_free(req_flow_id);
-		rte_free(req_entry_ptr);
-		return -1;
-	}
-
-	req->type = PIPELINE_MSG_REQ_CUSTOM;
-	req->subtype = PIPELINE_FA_MSG_REQ_FLOW_CONFIG_BULK;
-	req->entry_ptr = req_entry_ptr;
-	req->flow_id = req_flow_id;
-	req->n_flows = n_flows;
-	req->meter_update_mask = meter_update_mask;
-	req->policer_update_mask = policer_update_mask;
-	req->port_update = port_update;
-	req->params = params;
-
-	/* Send request and wait for response */
-	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL) {
-		rte_free(req_flow_id);
-		rte_free(req_entry_ptr);
-		return -1;
-	}
-
-	/* Read response */
-	status = (rsp->n_flows == n_flows) ? 0 : -1;
-
-	/* Commit flows */
-	for (i = 0; i < rsp->n_flows; i++) {
-		uint32_t fid = flow_id[i] % p->params.n_flows;
-		struct app_pipeline_fa_flow *flow = &p->flows[fid];
-		struct pipeline_fa_flow_params *flow_params = &params[i];
-		void *entry_ptr = req_entry_ptr[i];
-		uint32_t j, mask;
-
-		for (j = 0, mask = 1; j < PIPELINE_FA_N_TC_MAX;
-			j++, mask <<= 1) {
-			if ((mask & meter_update_mask) == 0)
-				continue;
-
-			memcpy(&flow->params.m[j],
-				&flow_params->m[j],
-				sizeof(flow_params->m[j]));
-		}
-
-		for (j = 0, mask = 1; j < PIPELINE_FA_N_TC_MAX;
-			j++, mask <<= 1) {
-			if ((mask & policer_update_mask) == 0)
-				continue;
-
-			memcpy(&flow->params.p[j],
-				&flow_params->p[j],
-				sizeof(flow_params->p[j]));
-		}
-
-		if (port_update)
-			flow->params.port_id = flow_params->port_id;
-
-		flow->entry_ptr = entry_ptr;
-	}
-
-	/* Free response */
-	app_msg_free(app, rsp);
-	rte_free(req_flow_id);
-	rte_free(req_entry_ptr);
-
-	return status;
-}
-
-int
-app_pipeline_fa_dscp_config(struct app_params *app,
-	uint32_t pipeline_id,
-	uint32_t dscp,
-	uint32_t traffic_class,
-	enum rte_meter_color color)
-{
-	struct app_pipeline_fa *p;
-
-	struct pipeline_fa_dscp_config_msg_req *req;
-	struct pipeline_fa_dscp_config_msg_rsp *rsp;
-
-	/* Check input arguments */
-	if ((app == NULL) ||
-		(dscp >= PIPELINE_FA_N_DSCP) ||
-		(traffic_class >= PIPELINE_FA_N_TC_MAX) ||
-		(color >= e_RTE_METER_COLORS))
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id,
-		&pipeline_flow_actions);
-	if (p == NULL)
-		return -1;
-
-	if (p->params.dscp_enabled == 0)
-		return -1;
-
-	/* Allocate and write request */
-	req = app_msg_alloc(app);
-	if (req == NULL)
-		return -1;
-
-	req->type = PIPELINE_MSG_REQ_CUSTOM;
-	req->subtype = PIPELINE_FA_MSG_REQ_DSCP_CONFIG;
-	req->dscp = dscp;
-	req->traffic_class = traffic_class;
-	req->color = color;
-
-	/* Send request and wait for response */
-	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	/* Read response */
-	if (rsp->status) {
-		app_msg_free(app, rsp);
-		return -1;
-	}
-
-	/* Commit DSCP */
-	p->dscp[dscp].traffic_class = traffic_class;
-	p->dscp[dscp].color = color;
-
-	/* Free response */
-	app_msg_free(app, rsp);
-
-	return 0;
-}
-
-int
-app_pipeline_fa_flow_policer_stats_read(struct app_params *app,
-	uint32_t pipeline_id,
-	uint32_t flow_id,
-	uint32_t policer_id,
-	int clear,
-	struct pipeline_fa_policer_stats *stats)
-{
-	struct app_pipeline_fa *p;
-	struct app_pipeline_fa_flow *flow;
-
-	struct pipeline_fa_policer_stats_msg_req *req;
-	struct pipeline_fa_policer_stats_msg_rsp *rsp;
-
-	/* Check input arguments */
-	if ((app == NULL) || (stats == NULL))
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id,
-		&pipeline_flow_actions);
-	if (p == NULL)
-		return -1;
-
-	flow_id %= p->params.n_flows;
-	flow = &p->flows[flow_id];
-
-	if ((policer_id >= p->params.n_meters_per_flow) ||
-		(flow->entry_ptr == NULL))
-		return -1;
-
-	/* Allocate and write request */
-	req = app_msg_alloc(app);
-	if (req == NULL)
-		return -1;
-
-	req->type = PIPELINE_MSG_REQ_CUSTOM;
-	req->subtype = PIPELINE_FA_MSG_REQ_POLICER_STATS_READ;
-	req->entry_ptr = flow->entry_ptr;
-	req->policer_id = policer_id;
-	req->clear = clear;
-
-	/* Send request and wait for response */
-	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	/* Read response */
-	if (rsp->status) {
-		app_msg_free(app, rsp);
-		return -1;
-	}
-
-	memcpy(stats, &rsp->stats, sizeof(*stats));
-
-	/* Free response */
-	app_msg_free(app, rsp);
-
-	return 0;
-}
-
-static const char *
-color_to_string(enum rte_meter_color color)
-{
-	switch (color) {
-	case e_RTE_METER_GREEN: return "G";
-	case e_RTE_METER_YELLOW: return "Y";
-	case e_RTE_METER_RED: return "R";
-	default: return "?";
-	}
-}
-
-static int
-string_to_color(char *s, enum rte_meter_color *c)
-{
-	if (strcmp(s, "G") == 0) {
-		*c = e_RTE_METER_GREEN;
-		return 0;
-	}
-
-	if (strcmp(s, "Y") == 0) {
-		*c = e_RTE_METER_YELLOW;
-		return 0;
-	}
-
-	if (strcmp(s, "R") == 0) {
-		*c = e_RTE_METER_RED;
-		return 0;
-	}
-
-	return -1;
-}
-
-static const char *
-policer_action_to_string(struct pipeline_fa_policer_action *a)
-{
-	if (a->drop)
-		return "D";
-
-	return color_to_string(a->color);
-}
-
-static int
-string_to_policer_action(char *s, struct pipeline_fa_policer_action *a)
-{
-	if (strcmp(s, "G") == 0) {
-		a->drop = 0;
-		a->color = e_RTE_METER_GREEN;
-		return 0;
-	}
-
-	if (strcmp(s, "Y") == 0) {
-		a->drop = 0;
-		a->color = e_RTE_METER_YELLOW;
-		return 0;
-	}
-
-	if (strcmp(s, "R") == 0) {
-		a->drop = 0;
-		a->color = e_RTE_METER_RED;
-		return 0;
-	}
-
-	if (strcmp(s, "D") == 0) {
-		a->drop = 1;
-		a->color = e_RTE_METER_GREEN;
-		return 0;
-	}
-
-	return -1;
-}
-
-static void
-print_flow(struct app_pipeline_fa *p,
-	uint32_t flow_id,
-	struct app_pipeline_fa_flow *flow)
-{
-	uint32_t i;
-
-	printf("Flow ID = %" PRIu32 "\n", flow_id);
-
-	for (i = 0; i < p->params.n_meters_per_flow; i++) {
-		struct rte_meter_trtcm_params *meter = &flow->params.m[i];
-		struct pipeline_fa_policer_params *policer = &flow->params.p[i];
-
-	printf("\ttrTCM [CIR = %" PRIu64
-		", CBS = %" PRIu64 ", PIR = %" PRIu64
-		", PBS = %" PRIu64	"] Policer [G : %s, Y : %s, R : %s]\n",
-		meter->cir,
-		meter->cbs,
-		meter->pir,
-		meter->pbs,
-		policer_action_to_string(&policer->action[e_RTE_METER_GREEN]),
-		policer_action_to_string(&policer->action[e_RTE_METER_YELLOW]),
-		policer_action_to_string(&policer->action[e_RTE_METER_RED]));
-	}
-
-	printf("\tPort %u (entry_ptr = %p)\n",
-		flow->params.port_id,
-		flow->entry_ptr);
-}
-
-
-static int
-app_pipeline_fa_flow_ls(struct app_params *app,
-		uint32_t pipeline_id)
-{
-	struct app_pipeline_fa *p;
-	uint32_t i;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id,
-		&pipeline_flow_actions);
-	if (p == NULL)
-		return -1;
-
-	for (i = 0; i < p->params.n_flows; i++) {
-		struct app_pipeline_fa_flow *flow = &p->flows[i];
-
-		print_flow(p, i, flow);
-	}
-
-	return 0;
-}
-
-static int
-app_pipeline_fa_dscp_ls(struct app_params *app,
-		uint32_t pipeline_id)
-{
-	struct app_pipeline_fa *p;
-	uint32_t i;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id,
-		&pipeline_flow_actions);
-	if (p == NULL)
-		return -1;
-
-	if (p->params.dscp_enabled == 0)
-		return -1;
-
-	for (i = 0; i < RTE_DIM(p->dscp); i++) {
-		struct app_pipeline_fa_dscp *dscp =	&p->dscp[i];
-
-		printf("DSCP = %2" PRIu32 ": Traffic class = %" PRIu32
-			", Color = %s\n",
-			i,
-			dscp->traffic_class,
-			color_to_string(dscp->color));
-	}
-
-	return 0;
-}
-
-int
-app_pipeline_fa_load_file(char *filename,
-	uint32_t *flow_ids,
-	struct pipeline_fa_flow_params *p,
-	uint32_t *n_flows,
-	uint32_t *line)
-{
-	FILE *f = NULL;
-	char file_buf[1024];
-	uint32_t i, l;
-
-	/* Check input arguments */
-	if ((filename == NULL) ||
-		(flow_ids == NULL) ||
-		(p == NULL) ||
-		(n_flows == NULL) ||
-		(*n_flows == 0) ||
-		(line == NULL)) {
-		if (line)
-			*line = 0;
-		return -1;
-		}
-
-	/* Open input file */
-	f = fopen(filename, "r");
-	if (f == NULL) {
-		*line = 0;
-		return -1;
-	}
-
-	/* Read file */
-	for (i = 0, l = 1; i < *n_flows; l++) {
-		char *tokens[64];
-		uint32_t n_tokens = RTE_DIM(tokens);
-
-		int status;
-
-		if (fgets(file_buf, sizeof(file_buf), f) == NULL)
-			break;
-
-		status = parse_tokenize_string(file_buf, tokens, &n_tokens);
-		if (status)
-			goto error1;
-
-		if ((n_tokens == 0) || (tokens[0][0] == '#'))
-			continue;
-
-
-		if ((n_tokens != 64) ||
-			/* flow */
-			strcmp(tokens[0], "flow") ||
-			parser_read_uint32(&flow_ids[i], tokens[1]) ||
-
-			/* meter & policer 0 */
-			strcmp(tokens[2], "meter") ||
-			strcmp(tokens[3], "0") ||
-			strcmp(tokens[4], "trtcm") ||
-			parser_read_uint64(&p[i].m[0].cir, tokens[5]) ||
-			parser_read_uint64(&p[i].m[0].pir, tokens[6]) ||
-			parser_read_uint64(&p[i].m[0].cbs, tokens[7]) ||
-			parser_read_uint64(&p[i].m[0].pbs, tokens[8]) ||
-			strcmp(tokens[9], "policer") ||
-			strcmp(tokens[10], "0") ||
-			strcmp(tokens[11], "g") ||
-			string_to_policer_action(tokens[12],
-				&p[i].p[0].action[e_RTE_METER_GREEN]) ||
-			strcmp(tokens[13], "y") ||
-			string_to_policer_action(tokens[14],
-				&p[i].p[0].action[e_RTE_METER_YELLOW]) ||
-			strcmp(tokens[15], "r") ||
-			string_to_policer_action(tokens[16],
-				&p[i].p[0].action[e_RTE_METER_RED]) ||
-
-			/* meter & policer 1 */
-			strcmp(tokens[17], "meter") ||
-			strcmp(tokens[18], "1") ||
-			strcmp(tokens[19], "trtcm") ||
-			parser_read_uint64(&p[i].m[1].cir, tokens[20]) ||
-			parser_read_uint64(&p[i].m[1].pir, tokens[21]) ||
-			parser_read_uint64(&p[i].m[1].cbs, tokens[22]) ||
-			parser_read_uint64(&p[i].m[1].pbs, tokens[23]) ||
-			strcmp(tokens[24], "policer") ||
-			strcmp(tokens[25], "1") ||
-			strcmp(tokens[26], "g") ||
-			string_to_policer_action(tokens[27],
-				&p[i].p[1].action[e_RTE_METER_GREEN]) ||
-			strcmp(tokens[28], "y") ||
-			string_to_policer_action(tokens[29],
-				&p[i].p[1].action[e_RTE_METER_YELLOW]) ||
-			strcmp(tokens[30], "r") ||
-			string_to_policer_action(tokens[31],
-				&p[i].p[1].action[e_RTE_METER_RED]) ||
-
-			/* meter & policer 2 */
-			strcmp(tokens[32], "meter") ||
-			strcmp(tokens[33], "2") ||
-			strcmp(tokens[34], "trtcm") ||
-			parser_read_uint64(&p[i].m[2].cir, tokens[35]) ||
-			parser_read_uint64(&p[i].m[2].pir, tokens[36]) ||
-			parser_read_uint64(&p[i].m[2].cbs, tokens[37]) ||
-			parser_read_uint64(&p[i].m[2].pbs, tokens[38]) ||
-			strcmp(tokens[39], "policer") ||
-			strcmp(tokens[40], "2") ||
-			strcmp(tokens[41], "g") ||
-			string_to_policer_action(tokens[42],
-				&p[i].p[2].action[e_RTE_METER_GREEN]) ||
-			strcmp(tokens[43], "y") ||
-			string_to_policer_action(tokens[44],
-				&p[i].p[2].action[e_RTE_METER_YELLOW]) ||
-			strcmp(tokens[45], "r") ||
-			string_to_policer_action(tokens[46],
-				&p[i].p[2].action[e_RTE_METER_RED]) ||
-
-			/* meter & policer 3 */
-			strcmp(tokens[47], "meter") ||
-			strcmp(tokens[48], "3") ||
-			strcmp(tokens[49], "trtcm") ||
-			parser_read_uint64(&p[i].m[3].cir, tokens[50]) ||
-			parser_read_uint64(&p[i].m[3].pir, tokens[51]) ||
-			parser_read_uint64(&p[i].m[3].cbs, tokens[52]) ||
-			parser_read_uint64(&p[i].m[3].pbs, tokens[53]) ||
-			strcmp(tokens[54], "policer") ||
-			strcmp(tokens[55], "3") ||
-			strcmp(tokens[56], "g") ||
-			string_to_policer_action(tokens[57],
-				&p[i].p[3].action[e_RTE_METER_GREEN]) ||
-			strcmp(tokens[58], "y") ||
-			string_to_policer_action(tokens[59],
-				&p[i].p[3].action[e_RTE_METER_YELLOW]) ||
-			strcmp(tokens[60], "r") ||
-			string_to_policer_action(tokens[61],
-				&p[i].p[3].action[e_RTE_METER_RED]) ||
-
-			/* port */
-			strcmp(tokens[62], "port") ||
-			parser_read_uint32(&p[i].port_id, tokens[63]))
-			goto error1;
-
-		i++;
-	}
-
-	/* Close file */
-	*n_flows = i;
-	fclose(f);
-	return 0;
-
-error1:
-	*line = l;
-	fclose(f);
-	return -1;
-}
-
-/*
- * action
- *
- * flow meter, policer and output port configuration:
- *    p <pipelineid> action flow <flowid> meter <meterid> trtcm <cir> <pir> <cbs> <pbs>
- *
- *    p <pipelineid> action flow <flowid> policer <policerid> g <gaction> y <yaction> r <raction>
- *  <action> is one of the following:
- *      G = recolor to green
- *      Y = recolor as yellow
- *      R = recolor as red
- *      D = drop
- *
- *    p <pipelineid> action flow <flowid> port <port ID>
- *
- *    p <pipelineid> action flow bulk <file>
- *
- * flow policer stats read:
- *    p <pipelineid> action flow <flowid> stats
- *
- * flow ls:
- *    p <pipelineid> action flow ls
- *
- * dscp table configuration:
- *    p <pipelineid> action dscp <dscpid> class <class ID> color <color>
- *
- * dscp table ls:
- *    p <pipelineid> action dscp ls
-**/
-
-struct cmd_action_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t action_string;
-	cmdline_multi_string_t multi_string;
-};
-
-static void
-cmd_action_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_action_result *params = parsed_result;
-	struct app_params *app = data;
-
-	char *tokens[16];
-	uint32_t n_tokens = RTE_DIM(tokens);
-	int status;
-
-	status = parse_tokenize_string(params->multi_string, tokens, &n_tokens);
-	if (status != 0) {
-		printf(CMD_MSG_TOO_MANY_ARGS, "action");
-		return;
-	}
-
-	/* action flow meter */
-	if ((n_tokens >= 3) &&
-		(strcmp(tokens[0], "flow") == 0) &&
-		strcmp(tokens[1], "bulk") &&
-		strcmp(tokens[1], "ls") &&
-		(strcmp(tokens[2], "meter") == 0)) {
-		struct pipeline_fa_flow_params flow_params;
-		uint32_t flow_id, meter_id;
-
-		if (n_tokens != 9) {
-			printf(CMD_MSG_MISMATCH_ARGS, "action flow meter");
-			return;
-		}
-
-		memset(&flow_params, 0, sizeof(flow_params));
-
-		if (parser_read_uint32(&flow_id, tokens[1])) {
-			printf(CMD_MSG_INVALID_ARG, "flowid");
-			return;
-		}
-
-		if (parser_read_uint32(&meter_id, tokens[3]) ||
-			(meter_id >= PIPELINE_FA_N_TC_MAX)) {
-			printf(CMD_MSG_INVALID_ARG, "meterid");
-			return;
-		}
-
-		if (strcmp(tokens[4], "trtcm")) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "trtcm");
-			return;
-		}
-
-		if (parser_read_uint64(&flow_params.m[meter_id].cir, tokens[5])) {
-			printf(CMD_MSG_INVALID_ARG, "cir");
-			return;
-		}
-
-		if (parser_read_uint64(&flow_params.m[meter_id].pir, tokens[6])) {
-			printf(CMD_MSG_INVALID_ARG, "pir");
-			return;
-		}
-
-		if (parser_read_uint64(&flow_params.m[meter_id].cbs, tokens[7])) {
-			printf(CMD_MSG_INVALID_ARG, "cbs");
-			return;
-		}
-
-		if (parser_read_uint64(&flow_params.m[meter_id].pbs, tokens[8])) {
-			printf(CMD_MSG_INVALID_ARG, "pbs");
-			return;
-		}
-
-		status = app_pipeline_fa_flow_config(app,
-			params->pipeline_id,
-			flow_id,
-			1 << meter_id,
-			0,
-			0,
-			&flow_params);
-		if (status)
-			printf(CMD_MSG_FAIL, "action flow meter");
-
-		return;
-	} /* action flow meter */
-
-	/* action flow policer */
-	if ((n_tokens >= 3) &&
-		(strcmp(tokens[0], "flow") == 0) &&
-		strcmp(tokens[1], "bulk") &&
-		strcmp(tokens[1], "ls") &&
-		(strcmp(tokens[2], "policer") == 0)) {
-		struct pipeline_fa_flow_params flow_params;
-		uint32_t flow_id, policer_id;
-
-		if (n_tokens != 10) {
-			printf(CMD_MSG_MISMATCH_ARGS, "action flow policer");
-			return;
-		}
-
-		memset(&flow_params, 0, sizeof(flow_params));
-
-		if (parser_read_uint32(&flow_id, tokens[1])) {
-			printf(CMD_MSG_INVALID_ARG, "flowid");
-			return;
-		}
-
-		if (parser_read_uint32(&policer_id, tokens[3]) ||
-			(policer_id >= PIPELINE_FA_N_TC_MAX)) {
-			printf(CMD_MSG_INVALID_ARG, "policerid");
-			return;
-		}
-
-		if (strcmp(tokens[4], "g")) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "g");
-			return;
-		}
-
-		if (string_to_policer_action(tokens[5],
-			&flow_params.p[policer_id].action[e_RTE_METER_GREEN])) {
-			printf(CMD_MSG_INVALID_ARG, "gaction");
-			return;
-		}
-
-		if (strcmp(tokens[6], "y")) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "y");
-			return;
-		}
-
-		if (string_to_policer_action(tokens[7],
-			&flow_params.p[policer_id].action[e_RTE_METER_YELLOW])) {
-			printf(CMD_MSG_INVALID_ARG, "yaction");
-			return;
-		}
-
-		if (strcmp(tokens[8], "r")) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "r");
-			return;
-		}
-
-		if (string_to_policer_action(tokens[9],
-			&flow_params.p[policer_id].action[e_RTE_METER_RED])) {
-			printf(CMD_MSG_INVALID_ARG, "raction");
-			return;
-		}
-
-		status = app_pipeline_fa_flow_config(app,
-			params->pipeline_id,
-			flow_id,
-			0,
-			1 << policer_id,
-			0,
-			&flow_params);
-		if (status != 0)
-			printf(CMD_MSG_FAIL, "action flow policer");
-
-		return;
-	} /* action flow policer */
-
-	/* action flow port */
-	if ((n_tokens >= 3) &&
-		(strcmp(tokens[0], "flow") == 0) &&
-		strcmp(tokens[1], "bulk") &&
-		strcmp(tokens[1], "ls") &&
-		(strcmp(tokens[2], "port") == 0)) {
-		struct pipeline_fa_flow_params flow_params;
-		uint32_t flow_id, port_id;
-
-		if (n_tokens != 4) {
-			printf(CMD_MSG_MISMATCH_ARGS, "action flow port");
-			return;
-		}
-
-		memset(&flow_params, 0, sizeof(flow_params));
-
-		if (parser_read_uint32(&flow_id, tokens[1])) {
-			printf(CMD_MSG_INVALID_ARG, "flowid");
-			return;
-		}
-
-		if (parser_read_uint32(&port_id, tokens[3])) {
-			printf(CMD_MSG_INVALID_ARG, "portid");
-			return;
-		}
-
-		flow_params.port_id = port_id;
-
-		status = app_pipeline_fa_flow_config(app,
-			params->pipeline_id,
-			flow_id,
-			0,
-			0,
-			1,
-			&flow_params);
-		if (status)
-			printf(CMD_MSG_FAIL, "action flow port");
-
-		return;
-	} /* action flow port */
-
-	/* action flow stats */
-	if ((n_tokens >= 3) &&
-		(strcmp(tokens[0], "flow") == 0) &&
-		strcmp(tokens[1], "bulk") &&
-		strcmp(tokens[1], "ls") &&
-		(strcmp(tokens[2], "stats") == 0)) {
-		struct pipeline_fa_policer_stats stats;
-		uint32_t flow_id, policer_id;
-
-		if (n_tokens != 3) {
-			printf(CMD_MSG_MISMATCH_ARGS, "action flow stats");
-			return;
-		}
-
-		if (parser_read_uint32(&flow_id, tokens[1])) {
-			printf(CMD_MSG_INVALID_ARG, "flowid");
-			return;
-		}
-
-		for (policer_id = 0;
-			policer_id < PIPELINE_FA_N_TC_MAX;
-			policer_id++) {
-			status = app_pipeline_fa_flow_policer_stats_read(app,
-				params->pipeline_id,
-				flow_id,
-				policer_id,
-				1,
-				&stats);
-			if (status != 0) {
-				printf(CMD_MSG_FAIL, "action flow stats");
-				return;
-			}
-
-			/* Display stats */
-			printf("\tPolicer: %" PRIu32
-				"\tPkts G: %" PRIu64
-				"\tPkts Y: %" PRIu64
-				"\tPkts R: %" PRIu64
-				"\tPkts D: %" PRIu64 "\n",
-				policer_id,
-				stats.n_pkts[e_RTE_METER_GREEN],
-				stats.n_pkts[e_RTE_METER_YELLOW],
-				stats.n_pkts[e_RTE_METER_RED],
-				stats.n_pkts_drop);
-		}
-
-		return;
-	} /* action flow stats */
-
-	/* action flow bulk */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "flow") == 0) &&
-		(strcmp(tokens[1], "bulk") == 0)) {
-		struct pipeline_fa_flow_params *flow_params;
-		uint32_t *flow_ids, n_flows, line;
-		char *filename;
-
-		if (n_tokens != 3) {
-			printf(CMD_MSG_MISMATCH_ARGS, "action flow bulk");
-			return;
-		}
-
-		filename = tokens[2];
-
-		n_flows = APP_PIPELINE_FA_MAX_RECORDS_IN_FILE;
-		flow_ids = malloc(n_flows * sizeof(uint32_t));
-		if (flow_ids == NULL) {
-			printf(CMD_MSG_OUT_OF_MEMORY);
-			return;
-		}
-
-		flow_params = malloc(n_flows * sizeof(struct pipeline_fa_flow_params));
-		if (flow_params == NULL) {
-			printf(CMD_MSG_OUT_OF_MEMORY);
-			free(flow_ids);
-			return;
-		}
-
-		status = app_pipeline_fa_load_file(filename,
-			flow_ids,
-			flow_params,
-			&n_flows,
-			&line);
-		if (status) {
-			printf(CMD_MSG_FILE_ERR, filename, line);
-			free(flow_params);
-			free(flow_ids);
-			return;
-		}
-
-		status = app_pipeline_fa_flow_config_bulk(app,
-			params->pipeline_id,
-			flow_ids,
-			n_flows,
-			0xF,
-			0xF,
-			1,
-			flow_params);
-		if (status)
-			printf(CMD_MSG_FAIL, "action flow bulk");
-
-		free(flow_params);
-		free(flow_ids);
-		return;
-	} /* action flow bulk */
-
-	/* action flow ls */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "flow") == 0) &&
-		(strcmp(tokens[1], "ls") == 0)) {
-		if (n_tokens != 2) {
-			printf(CMD_MSG_MISMATCH_ARGS, "action flow ls");
-			return;
-		}
-
-		status = app_pipeline_fa_flow_ls(app,
-			params->pipeline_id);
-		if (status)
-			printf(CMD_MSG_FAIL, "action flow ls");
-
-		return;
-	} /* action flow ls */
-
-	/* action dscp */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "dscp") == 0) &&
-		strcmp(tokens[1], "ls")) {
-		uint32_t dscp_id, tc_id;
-		enum rte_meter_color color;
-
-		if (n_tokens != 6) {
-			printf(CMD_MSG_MISMATCH_ARGS, "action dscp");
-			return;
-		}
-
-		if (parser_read_uint32(&dscp_id, tokens[1])) {
-			printf(CMD_MSG_INVALID_ARG, "dscpid");
-			return;
-		}
-
-		if (strcmp(tokens[2], "class")) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "class");
-			return;
-		}
-
-		if (parser_read_uint32(&tc_id, tokens[3])) {
-			printf(CMD_MSG_INVALID_ARG, "classid");
-			return;
-		}
-
-		if (strcmp(tokens[4], "color")) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "color");
-			return;
-		}
-
-		if (string_to_color(tokens[5], &color)) {
-			printf(CMD_MSG_INVALID_ARG, "colorid");
-			return;
-		}
-
-		status = app_pipeline_fa_dscp_config(app,
-			params->pipeline_id,
-			dscp_id,
-			tc_id,
-			color);
-		if (status != 0)
-			printf(CMD_MSG_FAIL, "action dscp");
-
-		return;
-	} /* action dscp */
-
-	/* action dscp ls */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "dscp") == 0) &&
-		(strcmp(tokens[1], "ls") == 0)) {
-		if (n_tokens != 2) {
-			printf(CMD_MSG_MISMATCH_ARGS, "action dscp ls");
-			return;
-		}
-
-		status = app_pipeline_fa_dscp_ls(app,
-			params->pipeline_id);
-		if (status)
-			printf(CMD_MSG_FAIL, "action dscp ls");
-
-		return;
-	} /* action dscp ls */
-
-	printf(CMD_MSG_FAIL, "action");
-}
-
-static cmdline_parse_token_string_t cmd_action_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_action_result, p_string, "p");
-
-static cmdline_parse_token_num_t cmd_action_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_action_result, pipeline_id, UINT32);
-
-static cmdline_parse_token_string_t cmd_action_action_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_action_result, action_string, "action");
-
-static cmdline_parse_token_string_t cmd_action_multi_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_action_result, multi_string,
-	TOKEN_STRING_MULTI);
-
-cmdline_parse_inst_t cmd_action = {
-	.f = cmd_action_parsed,
-	.data = NULL,
-	.help_str = "flow actions (meter, policer, policer stats, dscp table)",
-	.tokens = {
-		(void *) &cmd_action_p_string,
-		(void *) &cmd_action_pipeline_id,
-		(void *) &cmd_action_action_string,
-		(void *) &cmd_action_multi_string,
-		NULL,
-	},
-};
-
-static cmdline_parse_ctx_t pipeline_cmds[] = {
-	(cmdline_parse_inst_t *) &cmd_action,
-	NULL,
-};
-
-static struct pipeline_fe_ops pipeline_flow_actions_fe_ops = {
-	.f_init = app_pipeline_fa_init,
-	.f_post_init = NULL,
-	.f_free = app_pipeline_fa_free,
-	.f_track = app_pipeline_track_default,
-	.cmds = pipeline_cmds,
-};
-
-struct pipeline_type pipeline_flow_actions = {
-	.name = "FLOW_ACTIONS",
-	.be_ops = &pipeline_flow_actions_be_ops,
-	.fe_ops = &pipeline_flow_actions_fe_ops,
-};
diff --git a/examples/ip_pipeline/pipeline/pipeline_flow_actions.h b/examples/ip_pipeline/pipeline/pipeline_flow_actions.h
deleted file mode 100644
index 885923e..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_flow_actions.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#ifndef __INCLUDE_PIPELINE_FLOW_ACTIONS_H__
-#define __INCLUDE_PIPELINE_FLOW_ACTIONS_H__
-
-#include <rte_meter.h>
-
-#include "pipeline.h"
-#include "pipeline_flow_actions_be.h"
-
-int
-app_pipeline_fa_flow_config(struct app_params *app,
-	uint32_t pipeline_id,
-	uint32_t flow_id,
-	uint32_t meter_update_mask,
-	uint32_t policer_update_mask,
-	uint32_t port_update,
-	struct pipeline_fa_flow_params *params);
-
-int
-app_pipeline_fa_flow_config_bulk(struct app_params *app,
-	uint32_t pipeline_id,
-	uint32_t *flow_id,
-	uint32_t n_flows,
-	uint32_t meter_update_mask,
-	uint32_t policer_update_mask,
-	uint32_t port_update,
-	struct pipeline_fa_flow_params *params);
-
-int
-app_pipeline_fa_dscp_config(struct app_params *app,
-	uint32_t pipeline_id,
-	uint32_t dscp,
-	uint32_t traffic_class,
-	enum rte_meter_color color);
-
-int
-app_pipeline_fa_flow_policer_stats_read(struct app_params *app,
-	uint32_t pipeline_id,
-	uint32_t flow_id,
-	uint32_t policer_id,
-	int clear,
-	struct pipeline_fa_policer_stats *stats);
-
-#ifndef APP_PIPELINE_FA_MAX_RECORDS_IN_FILE
-#define APP_PIPELINE_FA_MAX_RECORDS_IN_FILE		65536
-#endif
-
-int
-app_pipeline_fa_load_file(char *filename,
-	uint32_t *flow_ids,
-	struct pipeline_fa_flow_params *p,
-	uint32_t *n_flows,
-	uint32_t *line);
-
-extern struct pipeline_type pipeline_flow_actions;
-
-#endif
diff --git a/examples/ip_pipeline/pipeline/pipeline_flow_actions_be.c b/examples/ip_pipeline/pipeline/pipeline_flow_actions_be.c
deleted file mode 100644
index 33f1c41..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_flow_actions_be.c
+++ /dev/null
@@ -1,983 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2016 Intel Corporation
- */
-
-#include <string.h>
-
-#include <rte_common.h>
-#include <rte_malloc.h>
-#include <rte_cycles.h>
-#include <rte_table_array.h>
-#include <rte_byteorder.h>
-#include <rte_ip.h>
-
-#include "pipeline_actions_common.h"
-#include "pipeline_flow_actions_be.h"
-#include "parser.h"
-#include "hash_func.h"
-
-int
-pipeline_fa_flow_params_set_default(struct pipeline_fa_flow_params *params)
-{
-	uint32_t i;
-
-	if (params == NULL)
-		return -1;
-
-	for (i = 0; i < PIPELINE_FA_N_TC_MAX; i++) {
-		struct rte_meter_trtcm_params *m = &params->m[i];
-
-		m->cir = 1;
-		m->cbs = 1;
-		m->pir = 1;
-		m->pbs = 2;
-	}
-
-	for (i = 0; i < PIPELINE_FA_N_TC_MAX; i++) {
-		struct pipeline_fa_policer_params *p = &params->p[i];
-		uint32_t j;
-
-		for (j = 0; j < e_RTE_METER_COLORS; j++) {
-			struct pipeline_fa_policer_action *a = &p->action[j];
-
-			a->drop = 0;
-			a->color = (enum rte_meter_color) j;
-		}
-	}
-
-	params->port_id = 0;
-
-	return 0;
-}
-
-struct dscp_entry {
-	uint32_t traffic_class;
-	enum rte_meter_color color;
-};
-
-struct pipeline_flow_actions {
-	struct pipeline p;
-	struct pipeline_fa_params params;
-	pipeline_msg_req_handler custom_handlers[PIPELINE_FA_MSG_REQS];
-
-	struct dscp_entry dscp[PIPELINE_FA_N_DSCP];
-} __rte_cache_aligned;
-
-static void *
-pipeline_fa_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_fa_msg_req_custom_handler,
-};
-
-static void *
-pipeline_fa_msg_req_flow_config_handler(struct pipeline *p, void *msg);
-
-static void *
-pipeline_fa_msg_req_flow_config_bulk_handler(struct pipeline *p, void *msg);
-
-static void *
-pipeline_fa_msg_req_dscp_config_handler(struct pipeline *p, void *msg);
-
-static void *
-pipeline_fa_msg_req_policer_stats_read_handler(struct pipeline *p, void *msg);
-
-static pipeline_msg_req_handler custom_handlers[] = {
-	[PIPELINE_FA_MSG_REQ_FLOW_CONFIG] =
-		pipeline_fa_msg_req_flow_config_handler,
-	[PIPELINE_FA_MSG_REQ_FLOW_CONFIG_BULK] =
-		pipeline_fa_msg_req_flow_config_bulk_handler,
-	[PIPELINE_FA_MSG_REQ_DSCP_CONFIG] =
-		pipeline_fa_msg_req_dscp_config_handler,
-	[PIPELINE_FA_MSG_REQ_POLICER_STATS_READ] =
-		pipeline_fa_msg_req_policer_stats_read_handler,
-};
-
-/*
- * Flow table
- */
-struct meter_policer {
-	struct rte_meter_trtcm meter;
-	struct rte_meter_trtcm_profile meter_profile;
-	struct pipeline_fa_policer_params policer;
-	struct pipeline_fa_policer_stats stats;
-};
-
-struct flow_table_entry {
-	struct rte_pipeline_table_entry head;
-	struct meter_policer mp[PIPELINE_FA_N_TC_MAX];
-};
-
-static int
-flow_table_entry_set_meter(struct flow_table_entry *entry,
-	uint32_t meter_id,
-	struct pipeline_fa_flow_params *params)
-{
-	struct rte_meter_trtcm *meter = &entry->mp[meter_id].meter;
-	struct rte_meter_trtcm_params *meter_params = &params->m[meter_id];
-	struct rte_meter_trtcm_profile *meter_profile =
-					&entry->mp[meter_id].meter_profile;
-	int status;
-
-	status = rte_meter_trtcm_profile_config(meter_profile, meter_params);
-	if (status)
-		return status;
-
-	return rte_meter_trtcm_config(meter, meter_profile);
-}
-
-static void
-flow_table_entry_set_policer(struct flow_table_entry *entry,
-	uint32_t policer_id,
-	struct pipeline_fa_flow_params *params)
-{
-	struct pipeline_fa_policer_params *p0 = &entry->mp[policer_id].policer;
-	struct pipeline_fa_policer_params *p1 = &params->p[policer_id];
-
-	memcpy(p0, p1, sizeof(*p0));
-}
-
-static void
-flow_table_entry_set_port_id(struct pipeline_flow_actions *p,
-	struct flow_table_entry *entry,
-	struct pipeline_fa_flow_params *params)
-{
-	entry->head.action = RTE_PIPELINE_ACTION_PORT;
-	entry->head.port_id = p->p.port_out_id[params->port_id];
-}
-
-static int
-flow_table_entry_set_default(struct pipeline_flow_actions *p,
-	struct flow_table_entry *entry)
-{
-	struct pipeline_fa_flow_params params;
-	uint32_t i;
-
-	pipeline_fa_flow_params_set_default(&params);
-
-	memset(entry, 0, sizeof(*entry));
-
-	flow_table_entry_set_port_id(p, entry, &params);
-
-	for (i = 0; i < PIPELINE_FA_N_TC_MAX; i++) {
-		int status;
-
-		status = flow_table_entry_set_meter(entry, i, &params);
-		if (status)
-			return status;
-	}
-
-	for (i = 0; i < PIPELINE_FA_N_TC_MAX; i++)
-		flow_table_entry_set_policer(entry, i, &params);
-
-	return 0;
-}
-
-static inline uint64_t
-pkt_work(
-	struct rte_mbuf *pkt,
-	struct rte_pipeline_table_entry *table_entry,
-	void *arg,
-	uint64_t time)
-{
-	struct pipeline_flow_actions *p = arg;
-	struct flow_table_entry *entry =
-		(struct flow_table_entry *) table_entry;
-
-	struct ipv4_hdr *pkt_ip = (struct ipv4_hdr *)
-		RTE_MBUF_METADATA_UINT32_PTR(pkt, p->params.ip_hdr_offset);
-	enum rte_meter_color *pkt_color = (enum rte_meter_color *)
-		RTE_MBUF_METADATA_UINT32_PTR(pkt, p->params.color_offset);
-
-	/* Read (IP header) */
-	uint32_t total_length = rte_bswap16(pkt_ip->total_length);
-	uint32_t dscp = pkt_ip->type_of_service >> 2;
-
-	uint32_t tc = p->dscp[dscp].traffic_class;
-	enum rte_meter_color color = p->dscp[dscp].color;
-
-	struct rte_meter_trtcm *meter = &entry->mp[tc].meter;
-	struct rte_meter_trtcm_profile *meter_profile =
-					&entry->mp[tc].meter_profile;
-	struct pipeline_fa_policer_params *policer = &entry->mp[tc].policer;
-	struct pipeline_fa_policer_stats *stats = &entry->mp[tc].stats;
-
-	/* Read (entry), compute */
-	enum rte_meter_color color2 = rte_meter_trtcm_color_aware_check(meter,
-		meter_profile,
-		time,
-		total_length,
-		color);
-
-	enum rte_meter_color color3 = policer->action[color2].color;
-	uint64_t drop = policer->action[color2].drop;
-
-	/* Read (entry), write (entry, color) */
-	stats->n_pkts[color3] += drop ^ 1LLU;
-	stats->n_pkts_drop += drop;
-	*pkt_color = color3;
-
-	return drop;
-}
-
-static inline uint64_t
-pkt4_work(
-	struct rte_mbuf **pkts,
-	struct rte_pipeline_table_entry **table_entries,
-	void *arg,
-	uint64_t time)
-{
-	struct pipeline_flow_actions *p = arg;
-
-	struct flow_table_entry *entry0 =
-		(struct flow_table_entry *) table_entries[0];
-	struct flow_table_entry *entry1 =
-		(struct flow_table_entry *) table_entries[1];
-	struct flow_table_entry *entry2 =
-		(struct flow_table_entry *) table_entries[2];
-	struct flow_table_entry *entry3 =
-		(struct flow_table_entry *) table_entries[3];
-
-	struct ipv4_hdr *pkt0_ip = (struct ipv4_hdr *)
-		RTE_MBUF_METADATA_UINT32_PTR(pkts[0], p->params.ip_hdr_offset);
-	struct ipv4_hdr *pkt1_ip = (struct ipv4_hdr *)
-		RTE_MBUF_METADATA_UINT32_PTR(pkts[1], p->params.ip_hdr_offset);
-	struct ipv4_hdr *pkt2_ip = (struct ipv4_hdr *)
-		RTE_MBUF_METADATA_UINT32_PTR(pkts[2], p->params.ip_hdr_offset);
-	struct ipv4_hdr *pkt3_ip = (struct ipv4_hdr *)
-		RTE_MBUF_METADATA_UINT32_PTR(pkts[3], p->params.ip_hdr_offset);
-
-	enum rte_meter_color *pkt0_color = (enum rte_meter_color *)
-		RTE_MBUF_METADATA_UINT32_PTR(pkts[0], p->params.color_offset);
-	enum rte_meter_color *pkt1_color = (enum rte_meter_color *)
-		RTE_MBUF_METADATA_UINT32_PTR(pkts[1], p->params.color_offset);
-	enum rte_meter_color *pkt2_color = (enum rte_meter_color *)
-		RTE_MBUF_METADATA_UINT32_PTR(pkts[2], p->params.color_offset);
-	enum rte_meter_color *pkt3_color = (enum rte_meter_color *)
-		RTE_MBUF_METADATA_UINT32_PTR(pkts[3], p->params.color_offset);
-
-	/* Read (IP header) */
-	uint32_t total_length0 = rte_bswap16(pkt0_ip->total_length);
-	uint32_t dscp0 = pkt0_ip->type_of_service >> 2;
-
-	uint32_t total_length1 = rte_bswap16(pkt1_ip->total_length);
-	uint32_t dscp1 = pkt1_ip->type_of_service >> 2;
-
-	uint32_t total_length2 = rte_bswap16(pkt2_ip->total_length);
-	uint32_t dscp2 = pkt2_ip->type_of_service >> 2;
-
-	uint32_t total_length3 = rte_bswap16(pkt3_ip->total_length);
-	uint32_t dscp3 = pkt3_ip->type_of_service >> 2;
-
-	uint32_t tc0 = p->dscp[dscp0].traffic_class;
-	enum rte_meter_color color0 = p->dscp[dscp0].color;
-
-	uint32_t tc1 = p->dscp[dscp1].traffic_class;
-	enum rte_meter_color color1 = p->dscp[dscp1].color;
-
-	uint32_t tc2 = p->dscp[dscp2].traffic_class;
-	enum rte_meter_color color2 = p->dscp[dscp2].color;
-
-	uint32_t tc3 = p->dscp[dscp3].traffic_class;
-	enum rte_meter_color color3 = p->dscp[dscp3].color;
-
-	struct rte_meter_trtcm *meter0 = &entry0->mp[tc0].meter;
-	struct rte_meter_trtcm_profile *meter0_profile =
-				&entry0->mp[tc0].meter_profile;
-	struct pipeline_fa_policer_params *policer0 = &entry0->mp[tc0].policer;
-	struct pipeline_fa_policer_stats *stats0 = &entry0->mp[tc0].stats;
-
-	struct rte_meter_trtcm *meter1 = &entry1->mp[tc1].meter;
-	struct rte_meter_trtcm_profile *meter1_profile =
-				&entry1->mp[tc1].meter_profile;
-	struct pipeline_fa_policer_params *policer1 = &entry1->mp[tc1].policer;
-	struct pipeline_fa_policer_stats *stats1 = &entry1->mp[tc1].stats;
-
-	struct rte_meter_trtcm *meter2 = &entry2->mp[tc2].meter;
-	struct rte_meter_trtcm_profile *meter2_profile =
-				&entry2->mp[tc2].meter_profile;
-	struct pipeline_fa_policer_params *policer2 = &entry2->mp[tc2].policer;
-	struct pipeline_fa_policer_stats *stats2 = &entry2->mp[tc2].stats;
-
-	struct rte_meter_trtcm *meter3 = &entry3->mp[tc3].meter;
-	struct rte_meter_trtcm_profile *meter3_profile =
-				&entry3->mp[tc3].meter_profile;
-	struct pipeline_fa_policer_params *policer3 = &entry3->mp[tc3].policer;
-	struct pipeline_fa_policer_stats *stats3 = &entry3->mp[tc3].stats;
-
-	/* Read (entry), compute, write (entry) */
-	enum rte_meter_color color2_0 = rte_meter_trtcm_color_aware_check(
-		meter0,
-		meter0_profile,
-		time,
-		total_length0,
-		color0);
-
-	enum rte_meter_color color2_1 = rte_meter_trtcm_color_aware_check(
-		meter1,
-		meter1_profile,
-		time,
-		total_length1,
-		color1);
-
-	enum rte_meter_color color2_2 = rte_meter_trtcm_color_aware_check(
-		meter2,
-		meter2_profile,
-		time,
-		total_length2,
-		color2);
-
-	enum rte_meter_color color2_3 = rte_meter_trtcm_color_aware_check(
-		meter3,
-		meter3_profile,
-		time,
-		total_length3,
-		color3);
-
-	enum rte_meter_color color3_0 = policer0->action[color2_0].color;
-	enum rte_meter_color color3_1 = policer1->action[color2_1].color;
-	enum rte_meter_color color3_2 = policer2->action[color2_2].color;
-	enum rte_meter_color color3_3 = policer3->action[color2_3].color;
-
-	uint64_t drop0 = policer0->action[color2_0].drop;
-	uint64_t drop1 = policer1->action[color2_1].drop;
-	uint64_t drop2 = policer2->action[color2_2].drop;
-	uint64_t drop3 = policer3->action[color2_3].drop;
-
-	/* Read (entry), write (entry, color) */
-	stats0->n_pkts[color3_0] += drop0 ^ 1LLU;
-	stats0->n_pkts_drop += drop0;
-
-	stats1->n_pkts[color3_1] += drop1 ^ 1LLU;
-	stats1->n_pkts_drop += drop1;
-
-	stats2->n_pkts[color3_2] += drop2 ^ 1LLU;
-	stats2->n_pkts_drop += drop2;
-
-	stats3->n_pkts[color3_3] += drop3 ^ 1LLU;
-	stats3->n_pkts_drop += drop3;
-
-	*pkt0_color = color3_0;
-	*pkt1_color = color3_1;
-	*pkt2_color = color3_2;
-	*pkt3_color = color3_3;
-
-	return drop0 | (drop1 << 1) | (drop2 << 2) | (drop3 << 3);
-}
-
-PIPELINE_TABLE_AH_HIT_DROP_TIME(fa_table_ah_hit, pkt_work, pkt4_work);
-
-static rte_pipeline_table_action_handler_hit
-get_fa_table_ah_hit(__rte_unused struct pipeline_flow_actions *p)
-{
-	return fa_table_ah_hit;
-}
-
-/*
- * Argument parsing
- */
-int
-pipeline_fa_parse_args(struct pipeline_fa_params *p,
-	struct pipeline_params *params)
-{
-	uint32_t n_flows_present = 0;
-	uint32_t n_meters_per_flow_present = 0;
-	uint32_t flow_id_offset_present = 0;
-	uint32_t ip_hdr_offset_present = 0;
-	uint32_t color_offset_present = 0;
-	uint32_t i;
-
-	/* Default values */
-	p->n_meters_per_flow = 1;
-	p->dscp_enabled = 0;
-
-	for (i = 0; i < params->n_args; i++) {
-		char *arg_name = params->args_name[i];
-		char *arg_value = params->args_value[i];
-
-		/* n_flows */
-		if (strcmp(arg_name, "n_flows") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				n_flows_present == 0, params->name,
-				arg_name);
-			n_flows_present = 1;
-
-			status = parser_read_uint32(&p->n_flows,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL(((status != -EINVAL) &&
-				(p->n_flows != 0)), params->name,
-				arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			continue;
-		}
-
-		/* n_meters_per_flow */
-		if (strcmp(arg_name, "n_meters_per_flow") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				n_meters_per_flow_present == 0,
-				params->name, arg_name);
-			n_meters_per_flow_present = 1;
-
-			status = parser_read_uint32(&p->n_meters_per_flow,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL(((status != -EINVAL) &&
-				(p->n_meters_per_flow != 0)),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG(((status != -ERANGE) &&
-				(p->n_meters_per_flow <=
-				PIPELINE_FA_N_TC_MAX)), params->name,
-				arg_name, arg_value);
-
-			continue;
-		}
-
-		/* flow_id_offset */
-		if (strcmp(arg_name, "flow_id_offset") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				flow_id_offset_present == 0,
-				params->name, arg_name);
-			flow_id_offset_present = 1;
-
-			status = parser_read_uint32(&p->flow_id_offset,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			continue;
-		}
-
-		/* ip_hdr_offset */
-		if (strcmp(arg_name, "ip_hdr_offset") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				ip_hdr_offset_present == 0,
-				params->name, arg_name);
-			ip_hdr_offset_present = 1;
-
-			status = parser_read_uint32(&p->ip_hdr_offset,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			continue;
-		}
-
-		/* color_offset */
-		if (strcmp(arg_name, "color_offset") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				color_offset_present == 0, params->name,
-				arg_name);
-			color_offset_present = 1;
-
-			status = parser_read_uint32(&p->color_offset,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			p->dscp_enabled = 1;
-
-			continue;
-		}
-
-		/* Unknown argument */
-		PIPELINE_PARSE_ERR_INV_ENT(0, params->name, arg_name);
-	}
-
-	/* Check that mandatory arguments are present */
-	PIPELINE_PARSE_ERR_MANDATORY((n_flows_present), params->name,
-		"n_flows");
-	PIPELINE_PARSE_ERR_MANDATORY((flow_id_offset_present),
-		params->name, "flow_id_offset");
-	PIPELINE_PARSE_ERR_MANDATORY((ip_hdr_offset_present),
-		params->name, "ip_hdr_offset");
-	PIPELINE_PARSE_ERR_MANDATORY((color_offset_present), params->name,
-		"color_offset");
-
-	return 0;
-}
-
-static void
-dscp_init(struct pipeline_flow_actions *p)
-{
-	uint32_t i;
-
-	for (i = 0; i < PIPELINE_FA_N_DSCP; i++) {
-		p->dscp[i].traffic_class = 0;
-		p->dscp[i].color = e_RTE_METER_GREEN;
-	}
-}
-
-static void *pipeline_fa_init(struct pipeline_params *params,
-	__rte_unused void *arg)
-{
-	struct pipeline *p;
-	struct pipeline_flow_actions *p_fa;
-	uint32_t size, i;
-
-	/* Check input arguments */
-	if (params == NULL)
-		return NULL;
-
-	if (params->n_ports_in != params->n_ports_out)
-		return NULL;
-
-	/* Memory allocation */
-	size = RTE_CACHE_LINE_ROUNDUP(
-		sizeof(struct pipeline_flow_actions));
-	p = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
-	if (p == NULL)
-		return NULL;
-	p_fa = (struct pipeline_flow_actions *) p;
-
-	strcpy(p->name, params->name);
-	p->log_level = params->log_level;
-
-	PLOG(p, HIGH, "Flow actions");
-
-	/* Parse arguments */
-	if (pipeline_fa_parse_args(&p_fa->params, params))
-		return NULL;
-
-	dscp_init(p_fa);
-
-	/* 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,
-			.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_array_params table_array_params = {
-			.n_entries = p_fa->params.n_flows,
-			.offset = p_fa->params.flow_id_offset,
-		};
-
-		struct rte_pipeline_table_params table_params = {
-			.ops = &rte_table_array_ops,
-			.arg_create = &table_array_params,
-			.f_action_hit = get_fa_table_ah_hit(p_fa),
-			.f_action_miss = NULL,
-			.arg_ah = p_fa,
-			.action_data_size =
-				sizeof(struct flow_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;
-		}
-	}
-
-	/* 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;
-		}
-	}
-
-	/* Initialize table entries */
-	for (i = 0; i < p_fa->params.n_flows; i++) {
-		struct rte_table_array_key key = {
-			.pos = i,
-		};
-
-		struct flow_table_entry entry;
-		struct rte_pipeline_table_entry *entry_ptr;
-		int key_found, status;
-
-		flow_table_entry_set_default(p_fa, &entry);
-
-		status = rte_pipeline_table_entry_add(p->p,
-			p->table_id[0],
-			&key,
-			(struct rte_pipeline_table_entry *) &entry,
-			&key_found,
-			&entry_ptr);
-
-		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_fa->custom_handlers,
-		custom_handlers,
-		sizeof(p_fa->custom_handlers));
-
-	return p;
-}
-
-static int
-pipeline_fa_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_fa_timer(void *pipeline)
-{
-	struct pipeline *p = (struct pipeline *) pipeline;
-
-	pipeline_msg_req_handle(p);
-	rte_pipeline_flush(p->p);
-
-	return 0;
-}
-
-void *
-pipeline_fa_msg_req_custom_handler(struct pipeline *p, void *msg)
-{
-	struct pipeline_flow_actions *p_fa =
-			(struct pipeline_flow_actions *) p;
-	struct pipeline_custom_msg_req *req = msg;
-	pipeline_msg_req_handler f_handle;
-
-	f_handle = (req->subtype < PIPELINE_FA_MSG_REQS) ?
-		p_fa->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_fa_msg_req_flow_config_handler(struct pipeline *p, void *msg)
-{
-	struct pipeline_flow_actions *p_fa = (struct pipeline_flow_actions *) p;
-	struct pipeline_fa_flow_config_msg_req *req = msg;
-	struct pipeline_fa_flow_config_msg_rsp *rsp = msg;
-	struct flow_table_entry *entry;
-	uint32_t mask, i;
-
-	/* Set flow table entry to default if not configured before */
-	if (req->entry_ptr == NULL) {
-		struct rte_table_array_key key = {
-			.pos = req->flow_id % p_fa->params.n_flows,
-		};
-
-		struct flow_table_entry default_entry;
-
-		int key_found, status;
-
-		flow_table_entry_set_default(p_fa, &default_entry);
-
-		status = rte_pipeline_table_entry_add(p->p,
-			p->table_id[0],
-			&key,
-			(struct rte_pipeline_table_entry *) &default_entry,
-			&key_found,
-			(struct rte_pipeline_table_entry **) &entry);
-		if (status) {
-			rsp->status = -1;
-			return rsp;
-		}
-	} else
-		entry = (struct flow_table_entry *) req->entry_ptr;
-
-	/* Meter */
-	for (i = 0, mask = 1; i < PIPELINE_FA_N_TC_MAX; i++, mask <<= 1) {
-		int status;
-
-		if ((mask & req->meter_update_mask) == 0)
-			continue;
-
-		status = flow_table_entry_set_meter(entry, i, &req->params);
-		if (status) {
-			rsp->status = -1;
-			return rsp;
-		}
-	}
-
-	/* Policer */
-	for (i = 0, mask = 1; i < PIPELINE_FA_N_TC_MAX; i++, mask <<= 1) {
-		if ((mask & req->policer_update_mask) == 0)
-			continue;
-
-		flow_table_entry_set_policer(entry, i, &req->params);
-	}
-
-	/* Port */
-	if (req->port_update)
-		flow_table_entry_set_port_id(p_fa, entry, &req->params);
-
-	/* Response */
-	rsp->status = 0;
-	rsp->entry_ptr = (void *) entry;
-	return rsp;
-}
-
-void *
-pipeline_fa_msg_req_flow_config_bulk_handler(struct pipeline *p, void *msg)
-{
-	struct pipeline_flow_actions *p_fa = (struct pipeline_flow_actions *) p;
-	struct pipeline_fa_flow_config_bulk_msg_req *req = msg;
-	struct pipeline_fa_flow_config_bulk_msg_rsp *rsp = msg;
-	uint32_t i;
-
-	for (i = 0; i < req->n_flows; i++) {
-		struct flow_table_entry *entry;
-		uint32_t j, mask;
-
-		/* Set flow table entry to default if not configured before */
-		if (req->entry_ptr[i] == NULL) {
-			struct rte_table_array_key key = {
-				.pos = req->flow_id[i] % p_fa->params.n_flows,
-			};
-
-			struct flow_table_entry entry_to_add;
-
-			int key_found, status;
-
-			flow_table_entry_set_default(p_fa, &entry_to_add);
-
-			status = rte_pipeline_table_entry_add(p->p,
-			 p->table_id[0],
-			 &key,
-			 (struct rte_pipeline_table_entry *) &entry_to_add,
-			 &key_found,
-			 (struct rte_pipeline_table_entry **) &entry);
-			if (status) {
-				rsp->n_flows = i;
-				return rsp;
-			}
-
-			req->entry_ptr[i] = (void *) entry;
-		} else
-			entry = (struct flow_table_entry *) req->entry_ptr[i];
-
-		/* Meter */
-		for (j = 0, mask = 1;
-			j < PIPELINE_FA_N_TC_MAX;
-			j++, mask <<= 1) {
-			int status;
-
-			if ((mask & req->meter_update_mask) == 0)
-				continue;
-
-			status = flow_table_entry_set_meter(entry,
-				j, &req->params[i]);
-			if (status) {
-				rsp->n_flows = i;
-				return rsp;
-			}
-		}
-
-		/* Policer */
-		for (j = 0, mask = 1;
-			j < PIPELINE_FA_N_TC_MAX;
-			j++, mask <<= 1) {
-			if ((mask & req->policer_update_mask) == 0)
-				continue;
-
-			flow_table_entry_set_policer(entry,
-			 j, &req->params[i]);
-		}
-
-		/* Port */
-		if (req->port_update)
-			flow_table_entry_set_port_id(p_fa,
-			 entry, &req->params[i]);
-	}
-
-	/* Response */
-	rsp->n_flows = i;
-	return rsp;
-}
-
-void *
-pipeline_fa_msg_req_dscp_config_handler(struct pipeline *p, void *msg)
-{
-	struct pipeline_flow_actions *p_fa = (struct pipeline_flow_actions *) p;
-	struct pipeline_fa_dscp_config_msg_req *req = msg;
-	struct pipeline_fa_dscp_config_msg_rsp *rsp = msg;
-
-	/* Check request */
-	if ((req->dscp >= PIPELINE_FA_N_DSCP) ||
-		(req->traffic_class >= PIPELINE_FA_N_TC_MAX) ||
-		(req->color >= e_RTE_METER_COLORS)) {
-		rsp->status = -1;
-		return rsp;
-	}
-
-	p_fa->dscp[req->dscp].traffic_class = req->traffic_class;
-	p_fa->dscp[req->dscp].color = req->color;
-	rsp->status = 0;
-	return rsp;
-}
-
-void *
-pipeline_fa_msg_req_policer_stats_read_handler(__rte_unused struct pipeline *p,
-	void *msg)
-{
-	struct pipeline_fa_policer_stats_msg_req *req = msg;
-	struct pipeline_fa_policer_stats_msg_rsp *rsp = msg;
-
-	struct flow_table_entry *entry = req->entry_ptr;
-	uint32_t policer_id = req->policer_id;
-	int clear = req->clear;
-
-	/* Check request */
-	if ((req->entry_ptr == NULL) ||
-		(req->policer_id >= PIPELINE_FA_N_TC_MAX)) {
-		rsp->status = -1;
-		return rsp;
-	}
-
-	memcpy(&rsp->stats,
-		&entry->mp[policer_id].stats,
-		sizeof(rsp->stats));
-	if (clear)
-		memset(&entry->mp[policer_id].stats,
-			0, sizeof(entry->mp[policer_id].stats));
-	rsp->status = 0;
-	return rsp;
-}
-
-struct pipeline_be_ops pipeline_flow_actions_be_ops = {
-	.f_init = pipeline_fa_init,
-	.f_free = pipeline_fa_free,
-	.f_run = NULL,
-	.f_timer = pipeline_fa_timer,
-};
diff --git a/examples/ip_pipeline/pipeline/pipeline_flow_actions_be.h b/examples/ip_pipeline/pipeline/pipeline_flow_actions_be.h
deleted file mode 100644
index ef6cb26..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_flow_actions_be.h
+++ /dev/null
@@ -1,139 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#ifndef __INCLUDE_PIPELINE_FLOW_ACTIONS_BE_H__
-#define __INCLUDE_PIPELINE_FLOW_ACTIONS_BE_H__
-
-#include <rte_meter.h>
-
-#include "pipeline_common_be.h"
-
-#ifndef PIPELINE_FA_N_TC_MAX
-#define PIPELINE_FA_N_TC_MAX                               4
-#endif
-
-#define PIPELINE_FA_N_DSCP                                 64
-
-struct pipeline_fa_params {
-	uint32_t n_flows;
-	uint32_t n_meters_per_flow;
-	uint32_t flow_id_offset;
-	uint32_t ip_hdr_offset;
-	uint32_t color_offset;
-	uint32_t dscp_enabled;
-};
-
-int
-pipeline_fa_parse_args(struct pipeline_fa_params *p,
-	struct pipeline_params *params);
-
-struct pipeline_fa_policer_action {
-	uint32_t drop;
-	enum rte_meter_color color;
-};
-
-struct pipeline_fa_policer_params {
-	struct pipeline_fa_policer_action action[e_RTE_METER_COLORS];
-};
-
-struct pipeline_fa_flow_params {
-	struct rte_meter_trtcm_params m[PIPELINE_FA_N_TC_MAX];
-	struct pipeline_fa_policer_params p[PIPELINE_FA_N_TC_MAX];
-	uint32_t port_id;
-};
-
-int
-pipeline_fa_flow_params_set_default(struct pipeline_fa_flow_params *params);
-
-struct pipeline_fa_policer_stats {
-	uint64_t n_pkts[e_RTE_METER_COLORS];
-	uint64_t n_pkts_drop;
-};
-
-enum pipeline_fa_msg_req_type {
-	PIPELINE_FA_MSG_REQ_FLOW_CONFIG = 0,
-	PIPELINE_FA_MSG_REQ_FLOW_CONFIG_BULK,
-	PIPELINE_FA_MSG_REQ_DSCP_CONFIG,
-	PIPELINE_FA_MSG_REQ_POLICER_STATS_READ,
-	PIPELINE_FA_MSG_REQS,
-};
-
-/*
- * MSG FLOW CONFIG
- */
-struct pipeline_fa_flow_config_msg_req {
-	enum pipeline_msg_req_type type;
-	enum pipeline_fa_msg_req_type subtype;
-
-	void *entry_ptr;
-	uint32_t flow_id;
-
-	uint32_t meter_update_mask;
-	uint32_t policer_update_mask;
-	uint32_t port_update;
-	struct pipeline_fa_flow_params params;
-};
-
-struct pipeline_fa_flow_config_msg_rsp {
-	int status;
-	void *entry_ptr;
-};
-
-/*
- * MSG FLOW CONFIG BULK
- */
-struct pipeline_fa_flow_config_bulk_msg_req {
-	enum pipeline_msg_req_type type;
-	enum pipeline_fa_msg_req_type subtype;
-
-	void **entry_ptr;
-	uint32_t *flow_id;
-	uint32_t n_flows;
-
-	uint32_t meter_update_mask;
-	uint32_t policer_update_mask;
-	uint32_t port_update;
-	struct pipeline_fa_flow_params *params;
-};
-
-struct pipeline_fa_flow_config_bulk_msg_rsp {
-	uint32_t n_flows;
-};
-
-/*
- * MSG DSCP CONFIG
- */
-struct pipeline_fa_dscp_config_msg_req {
-	enum pipeline_msg_req_type type;
-	enum pipeline_fa_msg_req_type subtype;
-
-	uint32_t dscp;
-	uint32_t traffic_class;
-	enum rte_meter_color color;
-};
-
-struct pipeline_fa_dscp_config_msg_rsp {
-	int status;
-};
-
-/*
- * MSG POLICER STATS READ
- */
-struct pipeline_fa_policer_stats_msg_req {
-	enum pipeline_msg_req_type type;
-	enum pipeline_fa_msg_req_type subtype;
-
-	void *entry_ptr;
-	uint32_t policer_id;
-	int clear;
-};
-
-struct pipeline_fa_policer_stats_msg_rsp {
-	int status;
-	struct pipeline_fa_policer_stats stats;
-};
-
-extern struct pipeline_be_ops pipeline_flow_actions_be_ops;
-
-#endif
-- 
2.9.3

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

* [dpdk-dev] [PATCH v2 14/44] ip_pipeline: remove firewall pipeline
  2018-03-12 17:25   ` [dpdk-dev] [PATCH v2 00/44] ip_pipeline: refactoring Jasvinder Singh
                       ` (12 preceding siblings ...)
  2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 13/44] ip_pipeline: remove flow actions pipeline Jasvinder Singh
@ 2018-03-12 17:25     ` Jasvinder Singh
  2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 15/44] ip_pipeline: remove master pipeline Jasvinder Singh
                       ` (29 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-12 17:25 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Remove firewall pipeline.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/Makefile                      |    2 -
 examples/ip_pipeline/init.c                        |    2 -
 examples/ip_pipeline/meson.build                   |    2 -
 examples/ip_pipeline/pipeline/pipeline_firewall.c  | 1421 --------------------
 examples/ip_pipeline/pipeline/pipeline_firewall.h  |   60 -
 .../ip_pipeline/pipeline/pipeline_firewall_be.c    |  856 ------------
 .../ip_pipeline/pipeline/pipeline_firewall_be.h    |  147 --
 7 files changed, 2490 deletions(-)
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_firewall.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_firewall.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_firewall_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_firewall_be.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index 0782308..ae76edc 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -19,8 +19,6 @@ SRCS-y += pipeline_common_be.c
 SRCS-y += pipeline_common_fe.c
 SRCS-y += pipeline_master_be.c
 SRCS-y += pipeline_master.c
-SRCS-y += pipeline_firewall_be.c
-SRCS-y += pipeline_firewall.c
 
 # Build using pkg-config variables if possible
 $(shell pkg-config --exists libdpdk)
diff --git a/examples/ip_pipeline/init.c b/examples/ip_pipeline/init.c
index 6599b0d..f848310 100644
--- a/examples/ip_pipeline/init.c
+++ b/examples/ip_pipeline/init.c
@@ -26,7 +26,6 @@
 #include "pipeline.h"
 #include "pipeline_common_fe.h"
 #include "pipeline_master.h"
-#include "pipeline_firewall.h"
 #include "thread_fe.h"
 
 #define APP_NAME_SIZE	32
@@ -1818,7 +1817,6 @@ int app_init(struct app_params *app)
 	app_pipeline_common_cmd_push(app);
 	app_pipeline_thread_cmd_push(app);
 	app_pipeline_type_register(app, &pipeline_master);
-	app_pipeline_type_register(app, &pipeline_firewall);
 
 	app_init_pipelines(app);
 	app_init_threads(app);
diff --git a/examples/ip_pipeline/meson.build b/examples/ip_pipeline/meson.build
index 802c82c..7563b39 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -20,8 +20,6 @@ sources = files(
 	'thread_fe.c',
 	'pipeline/pipeline_common_be.c',
 	'pipeline/pipeline_common_fe.c',
-	'pipeline/pipeline_firewall_be.c',
-	'pipeline/pipeline_firewall.c',
 	'pipeline/pipeline_master_be.c',
 	'pipeline/pipeline_master.c',
 )
diff --git a/examples/ip_pipeline/pipeline/pipeline_firewall.c b/examples/ip_pipeline/pipeline/pipeline_firewall.c
deleted file mode 100644
index 0cae9d7..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_firewall.c
+++ /dev/null
@@ -1,1421 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-#include <errno.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/queue.h>
-#include <netinet/in.h>
-
-#include <rte_common.h>
-#include <rte_hexdump.h>
-#include <rte_malloc.h>
-#include <cmdline_rdline.h>
-#include <cmdline_parse.h>
-#include <cmdline_parse_num.h>
-#include <cmdline_parse_string.h>
-
-#include "app.h"
-#include "pipeline_common_fe.h"
-#include "pipeline_firewall.h"
-#include "parser.h"
-
-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;
-};
-
-static void
-print_firewall_ipv4_rule(struct app_pipeline_firewall_rule *rule)
-{
-	printf("Prio = %" PRId32 " (SA = %" PRIu32 ".%" PRIu32
-		".%" PRIu32 ".%" PRIu32 "/%" PRIu32 ", "
-		"DA = %" PRIu32 ".%" PRIu32
-		".%"PRIu32 ".%" PRIu32 "/%" PRIu32 ", "
-		"SP = %" PRIu32 "-%" PRIu32 ", "
-		"DP = %" PRIu32 "-%" PRIu32 ", "
-		"Proto = %" PRIu32 " / 0x%" PRIx32 ") => "
-		"Port = %" PRIu32 " (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);
-}
-
-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;
-
-	TAILQ_FOREACH(r, &p->rules, node)
-		if (memcmp(key,
-			&r->key,
-			sizeof(struct pipeline_firewall_key)) == 0)
-			return r;
-
-	return NULL;
-}
-
-static int
-app_pipeline_firewall_ls(
-	struct app_params *app,
-	uint32_t pipeline_id)
-{
-	struct app_pipeline_firewall *p;
-	struct app_pipeline_firewall_rule *rule;
-	uint32_t n_rules;
-	int priority;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_firewall);
-	if (p == NULL)
-		return -1;
-
-	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 %" PRIu32 " (entry ptr = %p)\n",
-			p->default_rule_port_id,
-			p->default_rule_entry_ptr);
-	else
-		printf("Default rule: DROP\n");
-
-	printf("\n");
-
-	return 0;
-}
-
-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;
-
-	/* Initialization */
-	p->n_ports_in = params->n_ports_in;
-	p->n_ports_out = params->n_ports_out;
-
-	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;
-
-	return (void *) p;
-}
-
-static int
-app_pipeline_firewall_free(void *pipeline)
-{
-	struct app_pipeline_firewall *p = pipeline;
-
-	/* Check input arguments */
-	if (p == NULL)
-		return -1;
-
-	/* Free resources */
-	while (!TAILQ_EMPTY(&p->rules)) {
-		struct app_pipeline_firewall_rule *rule;
-
-		rule = TAILQ_FIRST(&p->rules);
-		TAILQ_REMOVE(&p->rules, rule, node);
-		rte_free(rule);
-	}
-
-	rte_free(p);
-	return 0;
-}
-
-static int
-app_pipeline_firewall_key_check_and_normalize(struct pipeline_firewall_key *key)
-{
-	switch (key->type) {
-	case PIPELINE_FIREWALL_IPV4_5TUPLE:
-	{
-		uint32_t src_ip_depth = key->key.ipv4_5tuple.src_ip_mask;
-		uint32_t dst_ip_depth = key->key.ipv4_5tuple.dst_ip_mask;
-		uint16_t src_port_from = key->key.ipv4_5tuple.src_port_from;
-		uint16_t src_port_to = key->key.ipv4_5tuple.src_port_to;
-		uint16_t dst_port_from = key->key.ipv4_5tuple.dst_port_from;
-		uint16_t dst_port_to = key->key.ipv4_5tuple.dst_port_to;
-
-		uint32_t src_ip_netmask = 0;
-		uint32_t dst_ip_netmask = 0;
-
-		if ((src_ip_depth > 32) ||
-			(dst_ip_depth > 32) ||
-			(src_port_from > src_port_to) ||
-			(dst_port_from > dst_port_to))
-			return -1;
-
-		if (src_ip_depth)
-			src_ip_netmask = (~0U) << (32 - src_ip_depth);
-
-		if (dst_ip_depth)
-			dst_ip_netmask = ((~0U) << (32 - dst_ip_depth));
-
-		key->key.ipv4_5tuple.src_ip &= src_ip_netmask;
-		key->key.ipv4_5tuple.dst_ip &= dst_ip_netmask;
-
-		return 0;
-	}
-
-	default:
-		return -1;
-	}
-}
-
-int
-app_pipeline_firewall_load_file(char *filename,
-	struct pipeline_firewall_key *keys,
-	uint32_t *priorities,
-	uint32_t *port_ids,
-	uint32_t *n_keys,
-	uint32_t *line)
-{
-	FILE *f = NULL;
-	char file_buf[1024];
-	uint32_t i, l;
-
-	/* Check input arguments */
-	if ((filename == NULL) ||
-		(keys == NULL) ||
-		(priorities == NULL) ||
-		(port_ids == NULL) ||
-		(n_keys == NULL) ||
-		(*n_keys == 0) ||
-		(line == NULL)) {
-		if (line)
-			*line = 0;
-		return -1;
-		}
-
-	/* Open input file */
-	f = fopen(filename, "r");
-	if (f == NULL) {
-		*line = 0;
-		return -1;
-	}
-
-	/* Read file */
-	for (i = 0, l = 1; i < *n_keys; l++) {
-		char *tokens[32];
-		uint32_t n_tokens = RTE_DIM(tokens);
-
-		uint32_t priority = 0;
-		struct in_addr sipaddr;
-		uint32_t sipdepth = 0;
-		struct in_addr dipaddr;
-		uint32_t dipdepth = 0;
-		uint16_t sport0 = 0;
-		uint16_t sport1 = 0;
-		uint16_t dport0 = 0;
-		uint16_t dport1 = 0;
-		uint8_t proto = 0;
-		uint8_t protomask = 0;
-		uint32_t port_id = 0;
-
-		int status;
-
-		if (fgets(file_buf, sizeof(file_buf), f) == NULL)
-			break;
-
-		status = parse_tokenize_string(file_buf, tokens, &n_tokens);
-		if (status)
-			goto error1;
-
-		if ((n_tokens == 0) || (tokens[0][0] == '#'))
-			continue;
-
-		if ((n_tokens != 15) ||
-			strcmp(tokens[0], "priority") ||
-			parser_read_uint32(&priority, tokens[1]) ||
-			strcmp(tokens[2], "ipv4") ||
-			parse_ipv4_addr(tokens[3], &sipaddr) ||
-			parser_read_uint32(&sipdepth, tokens[4]) ||
-			parse_ipv4_addr(tokens[5], &dipaddr) ||
-			parser_read_uint32(&dipdepth, tokens[6]) ||
-			parser_read_uint16(&sport0, tokens[7]) ||
-			parser_read_uint16(&sport1, tokens[8]) ||
-			parser_read_uint16(&dport0, tokens[9]) ||
-			parser_read_uint16(&dport1, tokens[10]) ||
-			parser_read_uint8(&proto, tokens[11]) ||
-			parser_read_uint8_hex(&protomask, tokens[12]) ||
-			strcmp(tokens[13], "port") ||
-			parser_read_uint32(&port_id, tokens[14]))
-			goto error1;
-
-		keys[i].type = PIPELINE_FIREWALL_IPV4_5TUPLE;
-		keys[i].key.ipv4_5tuple.src_ip =
-			rte_be_to_cpu_32(sipaddr.s_addr);
-		keys[i].key.ipv4_5tuple.src_ip_mask = sipdepth;
-		keys[i].key.ipv4_5tuple.dst_ip =
-			rte_be_to_cpu_32(dipaddr.s_addr);
-		keys[i].key.ipv4_5tuple.dst_ip_mask = dipdepth;
-		keys[i].key.ipv4_5tuple.src_port_from = sport0;
-		keys[i].key.ipv4_5tuple.src_port_to = sport1;
-		keys[i].key.ipv4_5tuple.dst_port_from = dport0;
-		keys[i].key.ipv4_5tuple.dst_port_to = dport1;
-		keys[i].key.ipv4_5tuple.proto = proto;
-		keys[i].key.ipv4_5tuple.proto_mask = protomask;
-
-		port_ids[i] = port_id;
-		priorities[i] = priority;
-
-		if (app_pipeline_firewall_key_check_and_normalize(&keys[i]))
-			goto error1;
-
-		i++;
-	}
-
-	/* Close file */
-	*n_keys = i;
-	fclose(f);
-	return 0;
-
-error1:
-	*line = l;
-	fclose(f);
-	return -1;
-}
-
-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_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;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_firewall);
-	if (p == NULL)
-		return -1;
-
-	if (port_id >= p->n_ports_out)
-		return -1;
-
-	if (app_pipeline_firewall_key_check_and_normalize(key) != 0)
-		return -1;
-
-	/* 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;
-	}
-
-	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_DEFAULT);
-	if (rsp == NULL) {
-		if (new_rule)
-			rte_free(rule);
-		return -1;
-	}
-
-	/* Read response and write rule */
-	if (rsp->status ||
-		(rsp->entry_ptr == NULL) ||
-		((new_rule == 0) && (rsp->key_found == 0)) ||
-		((new_rule == 1) && (rsp->key_found == 1))) {
-		app_msg_free(app, rsp);
-		if (new_rule)
-			rte_free(rule);
-		return -1;
-	}
-
-	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;
-}
-
-int
-app_pipeline_firewall_delete_rule(struct app_params *app,
-	uint32_t pipeline_id,
-	struct pipeline_firewall_key *key)
-{
-	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;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_firewall);
-	if (p == NULL)
-		return -1;
-
-	if (app_pipeline_firewall_key_check_and_normalize(key) != 0)
-		return -1;
-
-	/* 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_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	/* Read response */
-	if (rsp->status || !rsp->key_found) {
-		app_msg_free(app, rsp);
-		return -1;
-	}
-
-	/* Remove rule */
-	TAILQ_REMOVE(&p->rules, rule, node);
-	p->n_rules--;
-	rte_free(rule);
-
-	/* Free response */
-	app_msg_free(app, rsp);
-
-	return 0;
-}
-
-int
-app_pipeline_firewall_add_bulk(struct app_params *app,
-		uint32_t pipeline_id,
-		struct pipeline_firewall_key *keys,
-		uint32_t n_keys,
-		uint32_t *priorities,
-		uint32_t *port_ids)
-{
-	struct app_pipeline_firewall *p;
-	struct pipeline_firewall_add_bulk_msg_req *req;
-	struct pipeline_firewall_add_bulk_msg_rsp *rsp;
-
-	struct app_pipeline_firewall_rule **rules;
-	int *new_rules;
-
-	int *keys_found;
-	void **entries_ptr;
-
-	uint32_t i;
-	int status = 0;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_firewall);
-	if (p == NULL)
-		return -1;
-
-	rules = rte_malloc(NULL,
-		n_keys * sizeof(struct app_pipeline_firewall_rule *),
-		RTE_CACHE_LINE_SIZE);
-	if (rules == NULL)
-		return -1;
-
-	new_rules = rte_malloc(NULL,
-		n_keys * sizeof(int),
-		RTE_CACHE_LINE_SIZE);
-	if (new_rules == NULL) {
-		rte_free(rules);
-		return -1;
-	}
-
-	/* check data integrity and add to rule list */
-	for (i = 0; i < n_keys; i++) {
-		if (port_ids[i]  >= p->n_ports_out) {
-			rte_free(rules);
-			rte_free(new_rules);
-			return -1;
-		}
-
-		if (app_pipeline_firewall_key_check_and_normalize(&keys[i]) != 0) {
-			rte_free(rules);
-			rte_free(new_rules);
-			return -1;
-		}
-
-		rules[i] = app_pipeline_firewall_rule_find(p, &keys[i]);
-		new_rules[i] = (rules[i] == NULL);
-		if (rules[i] == NULL) {
-			rules[i] = rte_malloc(NULL,
-				sizeof(*rules[i]),
-				RTE_CACHE_LINE_SIZE);
-
-			if (rules[i] == NULL) {
-				uint32_t j;
-
-				for (j = 0; j <= i; j++)
-					if (new_rules[j])
-						rte_free(rules[j]);
-
-				rte_free(rules);
-				rte_free(new_rules);
-				return -1;
-			}
-		}
-	}
-
-	keys_found = rte_malloc(NULL,
-		n_keys * sizeof(int),
-		RTE_CACHE_LINE_SIZE);
-	if (keys_found == NULL) {
-		uint32_t j;
-
-		for (j = 0; j < n_keys; j++)
-			if (new_rules[j])
-				rte_free(rules[j]);
-
-		rte_free(rules);
-		rte_free(new_rules);
-		return -1;
-	}
-
-	entries_ptr = rte_malloc(NULL,
-		n_keys * sizeof(struct rte_pipeline_table_entry *),
-		RTE_CACHE_LINE_SIZE);
-	if (entries_ptr == NULL) {
-		uint32_t j;
-
-		for (j = 0; j < n_keys; j++)
-			if (new_rules[j])
-				rte_free(rules[j]);
-
-		rte_free(rules);
-		rte_free(new_rules);
-		rte_free(keys_found);
-		return -1;
-	}
-	for (i = 0; i < n_keys; i++) {
-		entries_ptr[i] = rte_malloc(NULL,
-			sizeof(struct rte_pipeline_table_entry),
-			RTE_CACHE_LINE_SIZE);
-
-		if (entries_ptr[i] == NULL) {
-			uint32_t j;
-
-			for (j = 0; j < n_keys; j++)
-				if (new_rules[j])
-					rte_free(rules[j]);
-
-			for (j = 0; j <= i; j++)
-				rte_free(entries_ptr[j]);
-
-			rte_free(rules);
-			rte_free(new_rules);
-			rte_free(keys_found);
-			rte_free(entries_ptr);
-			return -1;
-		}
-	}
-
-	/* Allocate and write request */
-	req = app_msg_alloc(app);
-	if (req == NULL) {
-		uint32_t j;
-
-		for (j = 0; j < n_keys; j++)
-			if (new_rules[j])
-				rte_free(rules[j]);
-
-		for (j = 0; j < n_keys; j++)
-			rte_free(entries_ptr[j]);
-
-		rte_free(rules);
-		rte_free(new_rules);
-		rte_free(keys_found);
-		rte_free(entries_ptr);
-		return -1;
-	}
-
-	req->type = PIPELINE_MSG_REQ_CUSTOM;
-	req->subtype = PIPELINE_FIREWALL_MSG_REQ_ADD_BULK;
-
-	req->keys = keys;
-	req->n_keys = n_keys;
-	req->port_ids = port_ids;
-	req->priorities = priorities;
-	req->keys_found = keys_found;
-	req->entries_ptr = entries_ptr;
-
-	/* Send request and wait for response */
-	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL) {
-		uint32_t j;
-
-		for (j = 0; j < n_keys; j++)
-			if (new_rules[j])
-				rte_free(rules[j]);
-
-		for (j = 0; j < n_keys; j++)
-			rte_free(entries_ptr[j]);
-
-		rte_free(rules);
-		rte_free(new_rules);
-		rte_free(keys_found);
-		rte_free(entries_ptr);
-		return -1;
-	}
-
-	if (rsp->status) {
-		for (i = 0; i < n_keys; i++)
-			if (new_rules[i])
-				rte_free(rules[i]);
-
-		for (i = 0; i < n_keys; i++)
-			rte_free(entries_ptr[i]);
-
-		status = -1;
-		goto cleanup;
-	}
-
-	for (i = 0; i < n_keys; i++) {
-		if (entries_ptr[i] == NULL ||
-			((new_rules[i] == 0) && (keys_found[i] == 0)) ||
-			((new_rules[i] == 1) && (keys_found[i] == 1))) {
-			for (i = 0; i < n_keys; i++)
-				if (new_rules[i])
-					rte_free(rules[i]);
-
-			for (i = 0; i < n_keys; i++)
-				rte_free(entries_ptr[i]);
-
-			status = -1;
-			goto cleanup;
-		}
-	}
-
-	for (i = 0; i < n_keys; i++) {
-		memcpy(&rules[i]->key, &keys[i], sizeof(keys[i]));
-		rules[i]->priority = priorities[i];
-		rules[i]->port_id = port_ids[i];
-		rules[i]->entry_ptr = entries_ptr[i];
-
-		/* Commit rule */
-		if (new_rules[i]) {
-			TAILQ_INSERT_TAIL(&p->rules, rules[i], node);
-			p->n_rules++;
-		}
-
-		print_firewall_ipv4_rule(rules[i]);
-	}
-
-cleanup:
-	app_msg_free(app, rsp);
-	rte_free(rules);
-	rte_free(new_rules);
-	rte_free(keys_found);
-	rte_free(entries_ptr);
-
-	return status;
-}
-
-int
-app_pipeline_firewall_delete_bulk(struct app_params *app,
-	uint32_t pipeline_id,
-	struct pipeline_firewall_key *keys,
-	uint32_t n_keys)
-{
-	struct app_pipeline_firewall *p;
-	struct pipeline_firewall_del_bulk_msg_req *req;
-	struct pipeline_firewall_del_bulk_msg_rsp *rsp;
-
-	struct app_pipeline_firewall_rule **rules;
-	int *keys_found;
-
-	uint32_t i;
-	int status = 0;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_firewall);
-	if (p == NULL)
-		return -1;
-
-	rules = rte_malloc(NULL,
-		n_keys * sizeof(struct app_pipeline_firewall_rule *),
-		RTE_CACHE_LINE_SIZE);
-	if (rules == NULL)
-		return -1;
-
-	for (i = 0; i < n_keys; i++) {
-		if (app_pipeline_firewall_key_check_and_normalize(&keys[i]) != 0) {
-			return -1;
-		}
-
-		rules[i] = app_pipeline_firewall_rule_find(p, &keys[i]);
-	}
-
-	keys_found = rte_malloc(NULL,
-		n_keys * sizeof(int),
-		RTE_CACHE_LINE_SIZE);
-	if (keys_found == NULL) {
-		rte_free(rules);
-		return -1;
-	}
-
-	/* Allocate and write request */
-	req = app_msg_alloc(app);
-	if (req == NULL) {
-		rte_free(rules);
-		rte_free(keys_found);
-		return -1;
-	}
-
-	req->type = PIPELINE_MSG_REQ_CUSTOM;
-	req->subtype = PIPELINE_FIREWALL_MSG_REQ_DEL_BULK;
-
-	req->keys = keys;
-	req->n_keys = n_keys;
-	req->keys_found = keys_found;
-
-	/* Send request and wait for response */
-	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL) {
-		rte_free(rules);
-		rte_free(keys_found);
-		return -1;
-	}
-
-	if (rsp->status) {
-		status = -1;
-		goto cleanup;
-	}
-
-	for (i = 0; i < n_keys; i++) {
-		if (keys_found[i] == 0) {
-			status = -1;
-			goto cleanup;
-		}
-	}
-
-	for (i = 0; i < n_keys; i++) {
-		TAILQ_REMOVE(&p->rules, rules[i], node);
-		p->n_rules--;
-		rte_free(rules[i]);
-	}
-
-cleanup:
-	app_msg_free(app, rsp);
-	rte_free(rules);
-	rte_free(keys_found);
-
-	return status;
-}
-
-int
-app_pipeline_firewall_add_default_rule(struct app_params *app,
-	uint32_t pipeline_id,
-	uint32_t port_id)
-{
-	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;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_firewall);
-	if (p == NULL)
-		return -1;
-
-	if (port_id >= p->n_ports_out)
-		return -1;
-
-	/* 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_DEFAULT);
-	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_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;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_firewall);
-	if (p == NULL)
-		return -1;
-
-	/* 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_DEFAULT);
-	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);
-
-	return 0;
-}
-
-/*
- * firewall
- *
- * firewall add:
- *    p <pipelineid> firewall add priority <priority>
- *       ipv4 <sipaddr> <sipdepth> <dipaddr> <dipdepth>
- *       <sport0> <sport1> <dport0> <dport1> <proto> <protomask>
- *       port <portid>
- *       Note: <protomask> is a hex value
- *
- *    p <pipelineid> firewall add bulk <file>
- *
- * firewall add default:
- *    p <pipelineid> firewall add default <port ID>
- *
- * firewall del:
- *    p <pipelineid> firewall del
- *       ipv4 <sipaddr> <sipdepth> <dipaddr> <dipdepth>
- *       <sport0> <sport1> <dport0> <dport1> <proto> <protomask>
- *
- *    p <pipelineid> firewall del bulk <file>
- *
- * firewall del default:
- *    p <pipelineid> firewall del default
- *
- * firewall ls:
- *    p <pipelineid> firewall ls
- */
-
-struct cmd_firewall_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t firewall_string;
-	cmdline_multi_string_t multi_string;
-};
-
-static void cmd_firewall_parsed(void *parsed_result,
-	__attribute__((unused))  struct cmdline *cl,
-	void *data)
-{
-	struct cmd_firewall_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
-
-	char *tokens[17];
-	uint32_t n_tokens = RTE_DIM(tokens);
-
-	status = parse_tokenize_string(params->multi_string, tokens, &n_tokens);
-	if (status) {
-		printf(CMD_MSG_TOO_MANY_ARGS, "firewall");
-		return;
-	}
-
-	/* firewall add */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "add") == 0) &&
-		(strcmp(tokens[1], "priority") == 0)) {
-		struct pipeline_firewall_key key;
-		uint32_t priority;
-		struct in_addr sipaddr;
-		uint32_t sipdepth;
-		struct in_addr dipaddr;
-		uint32_t dipdepth;
-		uint16_t sport0;
-		uint16_t sport1;
-		uint16_t dport0;
-		uint16_t dport1;
-		uint8_t proto;
-		uint8_t protomask;
-		uint32_t port_id;
-
-		memset(&key, 0, sizeof(key));
-
-		if (n_tokens != 16) {
-			printf(CMD_MSG_MISMATCH_ARGS, "firewall add");
-			return;
-		}
-
-		if (parser_read_uint32(&priority, tokens[2])) {
-			printf(CMD_MSG_INVALID_ARG, "priority");
-			return;
-		}
-
-		if (strcmp(tokens[3], "ipv4")) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "ipv4");
-			return;
-		}
-
-		if (parse_ipv4_addr(tokens[4], &sipaddr)) {
-			printf(CMD_MSG_INVALID_ARG, "sipaddr");
-			return;
-		}
-
-		if (parser_read_uint32(&sipdepth, tokens[5])) {
-			printf(CMD_MSG_INVALID_ARG, "sipdepth");
-			return;
-		}
-
-		if (parse_ipv4_addr(tokens[6], &dipaddr)) {
-			printf(CMD_MSG_INVALID_ARG, "dipaddr");
-			return;
-		}
-
-		if (parser_read_uint32(&dipdepth, tokens[7])) {
-			printf(CMD_MSG_INVALID_ARG, "dipdepth");
-			return;
-		}
-
-		if (parser_read_uint16(&sport0, tokens[8])) {
-			printf(CMD_MSG_INVALID_ARG, "sport0");
-			return;
-		}
-
-		if (parser_read_uint16(&sport1, tokens[9])) {
-			printf(CMD_MSG_INVALID_ARG, "sport1");
-			return;
-		}
-
-		if (parser_read_uint16(&dport0, tokens[10])) {
-			printf(CMD_MSG_INVALID_ARG, "dport0");
-			return;
-		}
-
-		if (parser_read_uint16(&dport1, tokens[11])) {
-			printf(CMD_MSG_INVALID_ARG, "dport1");
-			return;
-		}
-
-		if (parser_read_uint8(&proto, tokens[12])) {
-			printf(CMD_MSG_INVALID_ARG, "proto");
-			return;
-		}
-
-		if (parser_read_uint8_hex(&protomask, tokens[13])) {
-			printf(CMD_MSG_INVALID_ARG, "protomask");
-			return;
-		}
-
-		if (strcmp(tokens[14], "port")) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "port");
-			return;
-		}
-
-		if (parser_read_uint32(&port_id, tokens[15])) {
-			printf(CMD_MSG_INVALID_ARG, "portid");
-			return;
-		}
-
-		key.type = PIPELINE_FIREWALL_IPV4_5TUPLE;
-		key.key.ipv4_5tuple.src_ip = rte_be_to_cpu_32(sipaddr.s_addr);
-		key.key.ipv4_5tuple.src_ip_mask = sipdepth;
-		key.key.ipv4_5tuple.dst_ip = rte_be_to_cpu_32(dipaddr.s_addr);
-		key.key.ipv4_5tuple.dst_ip_mask = dipdepth;
-		key.key.ipv4_5tuple.src_port_from = sport0;
-		key.key.ipv4_5tuple.src_port_to = sport1;
-		key.key.ipv4_5tuple.dst_port_from = dport0;
-		key.key.ipv4_5tuple.dst_port_to = dport1;
-		key.key.ipv4_5tuple.proto = proto;
-		key.key.ipv4_5tuple.proto_mask = protomask;
-
-		status = app_pipeline_firewall_add_rule(app,
-			params->pipeline_id,
-			&key,
-			priority,
-			port_id);
-		if (status)
-			printf(CMD_MSG_FAIL, "firewall add");
-
-		return;
-	} /* firewall add */
-
-	/* firewall add bulk */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "add") == 0) &&
-		(strcmp(tokens[1], "bulk") == 0)) {
-		struct pipeline_firewall_key *keys;
-		uint32_t *priorities, *port_ids, n_keys, line;
-		char *filename;
-
-		if (n_tokens != 3) {
-			printf(CMD_MSG_MISMATCH_ARGS, "firewall add bulk");
-			return;
-		}
-
-		filename = tokens[2];
-
-		n_keys = APP_PIPELINE_FIREWALL_MAX_RULES_IN_FILE;
-		keys = malloc(n_keys * sizeof(struct pipeline_firewall_key));
-		if (keys == NULL) {
-			printf(CMD_MSG_OUT_OF_MEMORY);
-			return;
-		}
-		memset(keys, 0, n_keys * sizeof(struct pipeline_firewall_key));
-
-		priorities = malloc(n_keys * sizeof(uint32_t));
-		if (priorities == NULL) {
-			printf(CMD_MSG_OUT_OF_MEMORY);
-			free(keys);
-			return;
-		}
-
-		port_ids = malloc(n_keys * sizeof(uint32_t));
-		if (port_ids == NULL) {
-			printf(CMD_MSG_OUT_OF_MEMORY);
-			free(priorities);
-			free(keys);
-			return;
-		}
-
-		status = app_pipeline_firewall_load_file(filename,
-			keys,
-			priorities,
-			port_ids,
-			&n_keys,
-			&line);
-		if (status != 0) {
-			printf(CMD_MSG_FILE_ERR, filename, line);
-			free(port_ids);
-			free(priorities);
-			free(keys);
-			return;
-		}
-
-		status = app_pipeline_firewall_add_bulk(app,
-			params->pipeline_id,
-			keys,
-			n_keys,
-			priorities,
-			port_ids);
-		if (status)
-			printf(CMD_MSG_FAIL, "firewall add bulk");
-
-		free(keys);
-		free(priorities);
-		free(port_ids);
-		return;
-	} /* firewall add bulk */
-
-	/* firewall add default */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "add") == 0) &&
-		(strcmp(tokens[1], "default") == 0)) {
-		uint32_t port_id;
-
-		if (n_tokens != 3) {
-			printf(CMD_MSG_MISMATCH_ARGS, "firewall add default");
-			return;
-		}
-
-		if (parser_read_uint32(&port_id, tokens[2])) {
-			printf(CMD_MSG_INVALID_ARG, "portid");
-			return;
-		}
-
-		status = app_pipeline_firewall_add_default_rule(app,
-			params->pipeline_id,
-			port_id);
-		if (status)
-			printf(CMD_MSG_FAIL, "firewall add default");
-
-		return;
-	} /* firewall add default */
-
-	/* firewall del */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "del") == 0) &&
-		(strcmp(tokens[1], "ipv4") == 0)) {
-		struct pipeline_firewall_key key;
-		struct in_addr sipaddr;
-		uint32_t sipdepth;
-		struct in_addr dipaddr;
-		uint32_t dipdepth;
-		uint16_t sport0;
-		uint16_t sport1;
-		uint16_t dport0;
-		uint16_t dport1;
-		uint8_t proto;
-		uint8_t protomask;
-
-		memset(&key, 0, sizeof(key));
-
-		if (n_tokens != 12) {
-			printf(CMD_MSG_MISMATCH_ARGS, "firewall del");
-			return;
-		}
-
-		if (parse_ipv4_addr(tokens[2], &sipaddr)) {
-			printf(CMD_MSG_INVALID_ARG, "sipaddr");
-			return;
-		}
-
-		if (parser_read_uint32(&sipdepth, tokens[3])) {
-			printf(CMD_MSG_INVALID_ARG, "sipdepth");
-			return;
-		}
-
-		if (parse_ipv4_addr(tokens[4], &dipaddr)) {
-			printf(CMD_MSG_INVALID_ARG, "dipaddr");
-			return;
-		}
-
-		if (parser_read_uint32(&dipdepth, tokens[5])) {
-			printf(CMD_MSG_INVALID_ARG, "dipdepth");
-			return;
-		}
-
-		if (parser_read_uint16(&sport0, tokens[6])) {
-			printf(CMD_MSG_INVALID_ARG, "sport0");
-			return;
-		}
-
-		if (parser_read_uint16(&sport1, tokens[7])) {
-			printf(CMD_MSG_INVALID_ARG, "sport1");
-			return;
-		}
-
-		if (parser_read_uint16(&dport0, tokens[8])) {
-			printf(CMD_MSG_INVALID_ARG, "dport0");
-			return;
-		}
-
-		if (parser_read_uint16(&dport1, tokens[9])) {
-			printf(CMD_MSG_INVALID_ARG, "dport1");
-			return;
-		}
-
-		if (parser_read_uint8(&proto, tokens[10])) {
-			printf(CMD_MSG_INVALID_ARG, "proto");
-			return;
-		}
-
-		if (parser_read_uint8_hex(&protomask, tokens[11])) {
-			printf(CMD_MSG_INVALID_ARG, "protomask");
-			return;
-		}
-
-		key.type = PIPELINE_FIREWALL_IPV4_5TUPLE;
-		key.key.ipv4_5tuple.src_ip = rte_be_to_cpu_32(sipaddr.s_addr);
-		key.key.ipv4_5tuple.src_ip_mask = sipdepth;
-		key.key.ipv4_5tuple.dst_ip = rte_be_to_cpu_32(dipaddr.s_addr);
-		key.key.ipv4_5tuple.dst_ip_mask = dipdepth;
-		key.key.ipv4_5tuple.src_port_from = sport0;
-		key.key.ipv4_5tuple.src_port_to = sport1;
-		key.key.ipv4_5tuple.dst_port_from = dport0;
-		key.key.ipv4_5tuple.dst_port_to = dport1;
-		key.key.ipv4_5tuple.proto = proto;
-		key.key.ipv4_5tuple.proto_mask = protomask;
-
-		status = app_pipeline_firewall_delete_rule(app,
-			params->pipeline_id,
-			&key);
-		if (status)
-			printf(CMD_MSG_FAIL, "firewall del");
-
-		return;
-	} /* firewall del */
-
-	/* firewall del bulk */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "del") == 0) &&
-		(strcmp(tokens[1], "bulk") == 0)) {
-		struct pipeline_firewall_key *keys;
-		uint32_t *priorities, *port_ids, n_keys, line;
-		char *filename;
-
-		if (n_tokens != 3) {
-			printf(CMD_MSG_MISMATCH_ARGS, "firewall del bulk");
-			return;
-		}
-
-		filename = tokens[2];
-
-		n_keys = APP_PIPELINE_FIREWALL_MAX_RULES_IN_FILE;
-		keys = malloc(n_keys * sizeof(struct pipeline_firewall_key));
-		if (keys == NULL) {
-			printf(CMD_MSG_OUT_OF_MEMORY);
-			return;
-		}
-		memset(keys, 0, n_keys * sizeof(struct pipeline_firewall_key));
-
-		priorities = malloc(n_keys * sizeof(uint32_t));
-		if (priorities == NULL) {
-			printf(CMD_MSG_OUT_OF_MEMORY);
-			free(keys);
-			return;
-		}
-
-		port_ids = malloc(n_keys * sizeof(uint32_t));
-		if (port_ids == NULL) {
-			printf(CMD_MSG_OUT_OF_MEMORY);
-			free(priorities);
-			free(keys);
-			return;
-		}
-
-		status = app_pipeline_firewall_load_file(filename,
-			keys,
-			priorities,
-			port_ids,
-			&n_keys,
-			&line);
-		if (status != 0) {
-			printf(CMD_MSG_FILE_ERR, filename, line);
-			free(port_ids);
-			free(priorities);
-			free(keys);
-			return;
-		}
-
-		status = app_pipeline_firewall_delete_bulk(app,
-			params->pipeline_id,
-			keys,
-			n_keys);
-		if (status)
-			printf(CMD_MSG_FAIL, "firewall del bulk");
-
-		free(port_ids);
-		free(priorities);
-		free(keys);
-		return;
-	} /* firewall del bulk */
-
-	/* firewall del default */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "del") == 0) &&
-		(strcmp(tokens[1], "default") == 0)) {
-		if (n_tokens != 2) {
-			printf(CMD_MSG_MISMATCH_ARGS, "firewall del default");
-			return;
-		}
-
-		status = app_pipeline_firewall_delete_default_rule(app,
-			params->pipeline_id);
-		if (status)
-			printf(CMD_MSG_FAIL, "firewall del default");
-
-		return;
-
-	} /* firewall del default */
-
-	/* firewall ls */
-	if ((n_tokens >= 1) && (strcmp(tokens[0], "ls") == 0)) {
-		if (n_tokens != 1) {
-			printf(CMD_MSG_MISMATCH_ARGS, "firewall ls");
-			return;
-		}
-
-		status = app_pipeline_firewall_ls(app, params->pipeline_id);
-		if (status)
-			printf(CMD_MSG_FAIL, "firewall ls");
-
-		return;
-	} /* firewall ls */
-
-	printf(CMD_MSG_MISMATCH_ARGS, "firewall");
-}
-
-static cmdline_parse_token_string_t cmd_firewall_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_result, p_string, "p");
-
-static cmdline_parse_token_num_t cmd_firewall_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_result, pipeline_id, UINT32);
-
-static cmdline_parse_token_string_t cmd_firewall_firewall_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_result, firewall_string,
-	"firewall");
-
-static cmdline_parse_token_string_t cmd_firewall_multi_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_result, multi_string,
-	TOKEN_STRING_MULTI);
-
-static cmdline_parse_inst_t cmd_firewall = {
-	.f = cmd_firewall_parsed,
-	.data = NULL,
-	.help_str =	"firewall add / add bulk / add default / del / del bulk"
-		" / del default / ls",
-	.tokens = {
-		(void *) &cmd_firewall_p_string,
-		(void *) &cmd_firewall_pipeline_id,
-		(void *) &cmd_firewall_firewall_string,
-		(void *) &cmd_firewall_multi_string,
-		NULL,
-	},
-};
-
-static cmdline_parse_ctx_t pipeline_cmds[] = {
-	(cmdline_parse_inst_t *) &cmd_firewall,
-	NULL,
-};
-
-static struct pipeline_fe_ops pipeline_firewall_fe_ops = {
-	.f_init = app_pipeline_firewall_init,
-	.f_post_init = NULL,
-	.f_free = app_pipeline_firewall_free,
-	.f_track = app_pipeline_track_default,
-	.cmds = pipeline_cmds,
-};
-
-struct pipeline_type pipeline_firewall = {
-	.name = "FIREWALL",
-	.be_ops = &pipeline_firewall_be_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
deleted file mode 100644
index 27304b0..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_firewall.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#ifndef __INCLUDE_PIPELINE_FIREWALL_H__
-#define __INCLUDE_PIPELINE_FIREWALL_H__
-
-#include "pipeline.h"
-#include "pipeline_firewall_be.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_bulk(struct app_params *app,
-		uint32_t pipeline_id,
-		struct pipeline_firewall_key *keys,
-		uint32_t n_keys,
-		uint32_t *priorities,
-		uint32_t *port_ids);
-
-int
-app_pipeline_firewall_delete_bulk(struct app_params *app,
-	uint32_t pipeline_id,
-	struct pipeline_firewall_key *keys,
-	uint32_t n_keys);
-
-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);
-
-#ifndef APP_PIPELINE_FIREWALL_MAX_RULES_IN_FILE
-#define APP_PIPELINE_FIREWALL_MAX_RULES_IN_FILE		65536
-#endif
-
-int
-app_pipeline_firewall_load_file(char *filename,
-	struct pipeline_firewall_key *keys,
-	uint32_t *priorities,
-	uint32_t *port_ids,
-	uint32_t *n_keys,
-	uint32_t *line);
-
-extern struct pipeline_type pipeline_firewall;
-
-#endif
diff --git a/examples/ip_pipeline/pipeline/pipeline_firewall_be.c b/examples/ip_pipeline/pipeline/pipeline_firewall_be.c
deleted file mode 100644
index bd5e1b2..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_firewall_be.c
+++ /dev/null
@@ -1,856 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2016 Intel Corporation
- */
-
-#include <string.h>
-
-#include <rte_common.h>
-#include <rte_malloc.h>
-#include <rte_ether.h>
-#include <rte_ip.h>
-#include <rte_tcp.h>
-#include <rte_byteorder.h>
-#include <rte_table_acl.h>
-
-#include "pipeline_firewall_be.h"
-#include "parser.h"
-
-struct pipeline_firewall {
-	struct pipeline p;
-	pipeline_msg_req_handler custom_handlers[PIPELINE_FIREWALL_MSG_REQS];
-
-	uint32_t n_rules;
-	uint32_t n_rule_fields;
-	struct rte_acl_field_def *field_format;
-	uint32_t field_format_size;
-} __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_bulk_handler(struct pipeline *p, void *msg);
-
-static void *
-pipeline_firewall_msg_req_del_bulk_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_BULK] =
-		pipeline_firewall_msg_req_add_bulk_handler,
-	[PIPELINE_FIREWALL_MSG_REQ_DEL_BULK] =
-		pipeline_firewall_msg_req_del_bulk_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,
-};
-
-/*
- * Firewall table
- */
-struct firewall_table_entry {
-	struct rte_pipeline_table_entry head;
-};
-
-static struct rte_acl_field_def field_format_ipv4[] = {
-	/* Protocol */
-	[0] = {
-		.type = RTE_ACL_FIELD_TYPE_BITMASK,
-		.size = sizeof(uint8_t),
-		.field_index = 0,
-		.input_index = 0,
-		.offset = sizeof(struct ether_hdr) +
-			offsetof(struct ipv4_hdr, next_proto_id),
-	},
-
-	/* Source IP address (IPv4) */
-	[1] = {
-		.type = RTE_ACL_FIELD_TYPE_MASK,
-		.size = sizeof(uint32_t),
-		.field_index = 1,
-		.input_index = 1,
-		.offset = sizeof(struct ether_hdr) +
-			offsetof(struct ipv4_hdr, src_addr),
-	},
-
-	/* Destination IP address (IPv4) */
-	[2] = {
-		.type = RTE_ACL_FIELD_TYPE_MASK,
-		.size = sizeof(uint32_t),
-		.field_index = 2,
-		.input_index = 2,
-		.offset = sizeof(struct ether_hdr) +
-			offsetof(struct ipv4_hdr, dst_addr),
-	},
-
-	/* Source Port */
-	[3] = {
-		.type = RTE_ACL_FIELD_TYPE_RANGE,
-		.size = sizeof(uint16_t),
-		.field_index = 3,
-		.input_index = 3,
-		.offset = sizeof(struct ether_hdr) +
-			sizeof(struct ipv4_hdr) +
-			offsetof(struct tcp_hdr, src_port),
-	},
-
-	/* Destination Port */
-	[4] = {
-		.type = RTE_ACL_FIELD_TYPE_RANGE,
-		.size = sizeof(uint16_t),
-		.field_index = 4,
-		.input_index = 3,
-		.offset = sizeof(struct ether_hdr) +
-			sizeof(struct ipv4_hdr) +
-			offsetof(struct tcp_hdr, dst_port),
-	},
-};
-
-#define SIZEOF_VLAN_HDR                          4
-
-static struct rte_acl_field_def field_format_vlan_ipv4[] = {
-	/* Protocol */
-	[0] = {
-		.type = RTE_ACL_FIELD_TYPE_BITMASK,
-		.size = sizeof(uint8_t),
-		.field_index = 0,
-		.input_index = 0,
-		.offset = sizeof(struct ether_hdr) +
-			SIZEOF_VLAN_HDR +
-			offsetof(struct ipv4_hdr, next_proto_id),
-	},
-
-	/* Source IP address (IPv4) */
-	[1] = {
-		.type = RTE_ACL_FIELD_TYPE_MASK,
-		.size = sizeof(uint32_t),
-		.field_index = 1,
-		.input_index = 1,
-		.offset = sizeof(struct ether_hdr) +
-			SIZEOF_VLAN_HDR +
-			offsetof(struct ipv4_hdr, src_addr),
-	},
-
-	/* Destination IP address (IPv4) */
-	[2] = {
-		.type = RTE_ACL_FIELD_TYPE_MASK,
-		.size = sizeof(uint32_t),
-		.field_index = 2,
-		.input_index = 2,
-		.offset = sizeof(struct ether_hdr) +
-			SIZEOF_VLAN_HDR +
-			offsetof(struct ipv4_hdr, dst_addr),
-	},
-
-	/* Source Port */
-	[3] = {
-		.type = RTE_ACL_FIELD_TYPE_RANGE,
-		.size = sizeof(uint16_t),
-		.field_index = 3,
-		.input_index = 3,
-		.offset = sizeof(struct ether_hdr) +
-			SIZEOF_VLAN_HDR +
-			sizeof(struct ipv4_hdr) +
-			offsetof(struct tcp_hdr, src_port),
-	},
-
-	/* Destination Port */
-	[4] = {
-		.type = RTE_ACL_FIELD_TYPE_RANGE,
-		.size = sizeof(uint16_t),
-		.field_index = 4,
-		.input_index = 3,
-		.offset = sizeof(struct ether_hdr) +
-			SIZEOF_VLAN_HDR +
-			sizeof(struct ipv4_hdr) +
-			offsetof(struct tcp_hdr, dst_port),
-	},
-};
-
-#define SIZEOF_QINQ_HEADER                       8
-
-static struct rte_acl_field_def field_format_qinq_ipv4[] = {
-	/* Protocol */
-	[0] = {
-		.type = RTE_ACL_FIELD_TYPE_BITMASK,
-		.size = sizeof(uint8_t),
-		.field_index = 0,
-		.input_index = 0,
-		.offset = sizeof(struct ether_hdr) +
-			SIZEOF_QINQ_HEADER +
-			offsetof(struct ipv4_hdr, next_proto_id),
-	},
-
-	/* Source IP address (IPv4) */
-	[1] = {
-		.type = RTE_ACL_FIELD_TYPE_MASK,
-		.size = sizeof(uint32_t),
-		.field_index = 1,
-		.input_index = 1,
-		.offset = sizeof(struct ether_hdr) +
-			SIZEOF_QINQ_HEADER +
-			offsetof(struct ipv4_hdr, src_addr),
-	},
-
-	/* Destination IP address (IPv4) */
-	[2] = {
-		.type = RTE_ACL_FIELD_TYPE_MASK,
-		.size = sizeof(uint32_t),
-		.field_index = 2,
-		.input_index = 2,
-		.offset = sizeof(struct ether_hdr) +
-			SIZEOF_QINQ_HEADER +
-			offsetof(struct ipv4_hdr, dst_addr),
-	},
-
-	/* Source Port */
-	[3] = {
-		.type = RTE_ACL_FIELD_TYPE_RANGE,
-		.size = sizeof(uint16_t),
-		.field_index = 3,
-		.input_index = 3,
-		.offset = sizeof(struct ether_hdr) +
-			SIZEOF_QINQ_HEADER +
-			sizeof(struct ipv4_hdr) +
-			offsetof(struct tcp_hdr, src_port),
-	},
-
-	/* Destination Port */
-	[4] = {
-		.type = RTE_ACL_FIELD_TYPE_RANGE,
-		.size = sizeof(uint16_t),
-		.field_index = 4,
-		.input_index = 3,
-		.offset = sizeof(struct ether_hdr) +
-			SIZEOF_QINQ_HEADER +
-			sizeof(struct ipv4_hdr) +
-			offsetof(struct tcp_hdr, dst_port),
-	},
-};
-
-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;
-
-	/* defaults */
-	p->n_rules = 4 * 1024;
-	p->n_rule_fields = RTE_DIM(field_format_ipv4);
-	p->field_format = field_format_ipv4;
-	p->field_format_size = sizeof(field_format_ipv4);
-
-	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) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				n_rules_present == 0, params->name,
-				arg_name);
-			n_rules_present = 1;
-
-			status = parser_read_uint32(&p->n_rules,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-			continue;
-		}
-
-		if (strcmp(arg_name, "pkt_type") == 0) {
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				pkt_type_present == 0, params->name,
-				arg_name);
-			pkt_type_present = 1;
-
-			/* ipv4 */
-			if (strcmp(arg_value, "ipv4") == 0) {
-				p->n_rule_fields = RTE_DIM(field_format_ipv4);
-				p->field_format = field_format_ipv4;
-				p->field_format_size =
-					sizeof(field_format_ipv4);
-				continue;
-			}
-
-			/* vlan_ipv4 */
-			if (strcmp(arg_value, "vlan_ipv4") == 0) {
-				p->n_rule_fields =
-					RTE_DIM(field_format_vlan_ipv4);
-				p->field_format = field_format_vlan_ipv4;
-				p->field_format_size =
-					sizeof(field_format_vlan_ipv4);
-				continue;
-			}
-
-			/* qinq_ipv4 */
-			if (strcmp(arg_value, "qinq_ipv4") == 0) {
-				p->n_rule_fields =
-					RTE_DIM(field_format_qinq_ipv4);
-				p->field_format = field_format_qinq_ipv4;
-				p->field_format_size =
-					sizeof(field_format_qinq_ipv4);
-				continue;
-			}
-
-			/* other */
-			PIPELINE_PARSE_ERR_INV_VAL(0, params->name,
-				arg_name, arg_value);
-		}
-
-		/* other */
-		PIPELINE_PARSE_ERR_INV_ENT(0, params->name, arg_name);
-	}
-
-	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);
-	p->log_level = params->log_level;
-
-	PLOG(p, HIGH, "Firewall");
-
-	/* 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,
-			.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 = params->name,
-			.n_rules = p_fw->n_rules,
-			.n_rule_fields = p_fw->n_rule_fields,
-		};
-
-		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 =
-					sizeof(struct firewall_table_entry) -
-					sizeof(struct rte_pipeline_table_entry),
-			};
-
-		int status;
-
-		memcpy(table_acl_params.field_format,
-			p_fw->field_format,
-			p_fw->field_format_size);
-
-		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_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 firewall_table_entry entry = {
-		.head = {
-			.action = RTE_PIPELINE_ACTION_PORT,
-			{.port_id = p->port_out_id[req->port_id]},
-		},
-	};
-
-	memset(&params, 0, sizeof(params));
-
-	switch (req->key.type) {
-	case PIPELINE_FIREWALL_IPV4_5TUPLE:
-		params.priority = req->priority;
-		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,
-		(struct rte_pipeline_table_entry *) &entry,
-		&rsp->key_found,
-		(struct rte_pipeline_table_entry **) &rsp->entry_ptr);
-
-	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;
-
-	memset(&params, 0, sizeof(params));
-
-	switch (req->key.type) {
-	case PIPELINE_FIREWALL_IPV4_5TUPLE:
-		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);
-
-	return rsp;
-}
-
-static void *
-pipeline_firewall_msg_req_add_bulk_handler(struct pipeline *p, void *msg)
-{
-	struct pipeline_firewall_add_bulk_msg_req *req = msg;
-	struct pipeline_firewall_add_bulk_msg_rsp *rsp = msg;
-
-	struct rte_table_acl_rule_add_params *params[req->n_keys];
-	struct firewall_table_entry *entries[req->n_keys];
-
-	uint32_t i, n_keys;
-
-	n_keys = req->n_keys;
-
-	for (i = 0; i < n_keys; i++) {
-		entries[i] = rte_zmalloc(NULL,
-				sizeof(struct firewall_table_entry),
-				RTE_CACHE_LINE_SIZE);
-		if (entries[i] == NULL) {
-			rsp->status = -1;
-			return rsp;
-		}
-
-		params[i] = rte_zmalloc(NULL,
-				sizeof(struct rte_table_acl_rule_add_params),
-				RTE_CACHE_LINE_SIZE);
-		if (params[i] == NULL) {
-			rsp->status = -1;
-			return rsp;
-		}
-
-		entries[i]->head.action = RTE_PIPELINE_ACTION_PORT;
-		entries[i]->head.port_id = p->port_out_id[req->port_ids[i]];
-
-		switch (req->keys[i].type) {
-		case PIPELINE_FIREWALL_IPV4_5TUPLE:
-			params[i]->priority = req->priorities[i];
-			params[i]->field_value[0].value.u8 =
-				req->keys[i].key.ipv4_5tuple.proto;
-			params[i]->field_value[0].mask_range.u8 =
-				req->keys[i].key.ipv4_5tuple.proto_mask;
-			params[i]->field_value[1].value.u32 =
-				req->keys[i].key.ipv4_5tuple.src_ip;
-			params[i]->field_value[1].mask_range.u32 =
-				req->keys[i].key.ipv4_5tuple.src_ip_mask;
-			params[i]->field_value[2].value.u32 =
-				req->keys[i].key.ipv4_5tuple.dst_ip;
-			params[i]->field_value[2].mask_range.u32 =
-				req->keys[i].key.ipv4_5tuple.dst_ip_mask;
-			params[i]->field_value[3].value.u16 =
-				req->keys[i].key.ipv4_5tuple.src_port_from;
-			params[i]->field_value[3].mask_range.u16 =
-				req->keys[i].key.ipv4_5tuple.src_port_to;
-			params[i]->field_value[4].value.u16 =
-				req->keys[i].key.ipv4_5tuple.dst_port_from;
-			params[i]->field_value[4].mask_range.u16 =
-				req->keys[i].key.ipv4_5tuple.dst_port_to;
-			break;
-
-		default:
-			rsp->status = -1; /* Error */
-
-			for (i = 0; i < n_keys; i++) {
-				rte_free(entries[i]);
-				rte_free(params[i]);
-			}
-
-			return rsp;
-		}
-	}
-
-	rsp->status = rte_pipeline_table_entry_add_bulk(p->p, p->table_id[0],
-			(void *)params, (struct rte_pipeline_table_entry **)entries,
-			n_keys, req->keys_found,
-			(struct rte_pipeline_table_entry **)req->entries_ptr);
-
-	for (i = 0; i < n_keys; i++) {
-		rte_free(entries[i]);
-		rte_free(params[i]);
-	}
-
-	return rsp;
-}
-
-static void *
-pipeline_firewall_msg_req_del_bulk_handler(struct pipeline *p, void *msg)
-{
-	struct pipeline_firewall_del_bulk_msg_req *req = msg;
-	struct pipeline_firewall_del_bulk_msg_rsp *rsp = msg;
-
-	struct rte_table_acl_rule_delete_params *params[req->n_keys];
-
-	uint32_t i, n_keys;
-
-	n_keys = req->n_keys;
-
-	for (i = 0; i < n_keys; i++) {
-		params[i] = rte_zmalloc(NULL,
-				sizeof(struct rte_table_acl_rule_delete_params),
-				RTE_CACHE_LINE_SIZE);
-		if (params[i] == NULL) {
-			rsp->status = -1;
-			return rsp;
-		}
-
-		switch (req->keys[i].type) {
-		case PIPELINE_FIREWALL_IPV4_5TUPLE:
-			params[i]->field_value[0].value.u8 =
-				req->keys[i].key.ipv4_5tuple.proto;
-			params[i]->field_value[0].mask_range.u8 =
-				req->keys[i].key.ipv4_5tuple.proto_mask;
-			params[i]->field_value[1].value.u32 =
-				req->keys[i].key.ipv4_5tuple.src_ip;
-			params[i]->field_value[1].mask_range.u32 =
-				req->keys[i].key.ipv4_5tuple.src_ip_mask;
-			params[i]->field_value[2].value.u32 =
-				req->keys[i].key.ipv4_5tuple.dst_ip;
-			params[i]->field_value[2].mask_range.u32 =
-				req->keys[i].key.ipv4_5tuple.dst_ip_mask;
-			params[i]->field_value[3].value.u16 =
-				req->keys[i].key.ipv4_5tuple.src_port_from;
-			params[i]->field_value[3].mask_range.u16 =
-				req->keys[i].key.ipv4_5tuple.src_port_to;
-			params[i]->field_value[4].value.u16 =
-				req->keys[i].key.ipv4_5tuple.dst_port_from;
-			params[i]->field_value[4].mask_range.u16 =
-				req->keys[i].key.ipv4_5tuple.dst_port_to;
-			break;
-
-		default:
-			rsp->status = -1; /* Error */
-
-			for (i = 0; i < n_keys; i++)
-				rte_free(params[i]);
-
-			return rsp;
-		}
-	}
-
-	rsp->status = rte_pipeline_table_entry_delete_bulk(p->p, p->table_id[0],
-			(void **)&params, n_keys, req->keys_found, NULL);
-
-	for (i = 0; i < n_keys; i++)
-		rte_free(params[i]);
-
-	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 firewall_table_entry default_entry = {
-		.head = {
-			.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],
-		(struct rte_pipeline_table_entry *) &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_be_ops pipeline_firewall_be_ops = {
-	.f_init = pipeline_firewall_init,
-	.f_free = pipeline_firewall_free,
-	.f_run = NULL,
-	.f_timer = pipeline_firewall_timer,
-};
diff --git a/examples/ip_pipeline/pipeline/pipeline_firewall_be.h b/examples/ip_pipeline/pipeline/pipeline_firewall_be.h
deleted file mode 100644
index 246f0a6..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_firewall_be.h
+++ /dev/null
@@ -1,147 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#ifndef __INCLUDE_PIPELINE_FIREWALL_BE_H__
-#define __INCLUDE_PIPELINE_FIREWALL_BE_H__
-
-#include "pipeline_common_be.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_BULK,
-	PIPELINE_FIREWALL_MSG_REQ_DEL_BULK,
-	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 BULK
- */
-struct pipeline_firewall_add_bulk_msg_req {
-	enum pipeline_msg_req_type type;
-	enum pipeline_firewall_msg_req_type subtype;
-
-	struct pipeline_firewall_key *keys;
-	uint32_t n_keys;
-
-	uint32_t *priorities;
-	uint32_t *port_ids;
-	int *keys_found;
-	void **entries_ptr;
-};
-struct pipeline_firewall_add_bulk_msg_rsp {
-	int status;
-};
-
-/*
- * MSG DEL BULK
- */
-struct pipeline_firewall_del_bulk_msg_req {
-	enum pipeline_msg_req_type type;
-	enum pipeline_firewall_msg_req_type subtype;
-
-	/* key */
-	struct pipeline_firewall_key *keys;
-	uint32_t n_keys;
-	int *keys_found;
-};
-
-struct pipeline_firewall_del_bulk_msg_rsp {
-	int status;
-};
-
-/*
- * 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_be_ops pipeline_firewall_be_ops;
-
-#endif
-- 
2.9.3

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

* [dpdk-dev] [PATCH v2 15/44] ip_pipeline: remove master pipeline
  2018-03-12 17:25   ` [dpdk-dev] [PATCH v2 00/44] ip_pipeline: refactoring Jasvinder Singh
                       ` (13 preceding siblings ...)
  2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 14/44] ip_pipeline: remove firewall pipeline Jasvinder Singh
@ 2018-03-12 17:25     ` Jasvinder Singh
  2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 16/44] ip_pipeline: remove config Jasvinder Singh
                       ` (28 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-12 17:25 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

remove master pipeline.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/Makefile                      |    6 -
 examples/ip_pipeline/app.h                         |   12 -
 examples/ip_pipeline/{pipeline => }/hash_func.h    |    3 +-
 .../ip_pipeline/{pipeline => }/hash_func_arm64.h   |    0
 examples/ip_pipeline/init.c                        |  574 --------
 examples/ip_pipeline/meson.build                   |    8 +-
 .../ip_pipeline/pipeline/pipeline_actions_common.h |  202 ---
 examples/ip_pipeline/pipeline/pipeline_common_be.c |  176 ---
 examples/ip_pipeline/pipeline/pipeline_common_be.h |  134 --
 examples/ip_pipeline/pipeline/pipeline_common_fe.c | 1455 --------------------
 examples/ip_pipeline/pipeline/pipeline_common_fe.h |  231 ----
 examples/ip_pipeline/pipeline/pipeline_master.c    |   20 -
 examples/ip_pipeline/pipeline/pipeline_master.h    |   12 -
 examples/ip_pipeline/pipeline/pipeline_master_be.c |  141 --
 examples/ip_pipeline/pipeline/pipeline_master_be.h |   12 -
 examples/ip_pipeline/thread.c                      |   53 -
 examples/ip_pipeline/thread_fe.c                   |  457 ------
 examples/ip_pipeline/thread_fe.h                   |   72 -
 18 files changed, 3 insertions(+), 3565 deletions(-)
 rename examples/ip_pipeline/{pipeline => }/hash_func.h (99%)
 rename examples/ip_pipeline/{pipeline => }/hash_func_arm64.h (100%)
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_actions_common.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_common_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_common_be.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_common_fe.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_common_fe.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_master.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_master.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_master_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_master_be.h
 delete mode 100644 examples/ip_pipeline/thread_fe.c
 delete mode 100644 examples/ip_pipeline/thread_fe.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index ae76edc..8ba7887 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -12,14 +12,8 @@ SRCS-y += config_parse_tm.c
 SRCS-y += config_check.c
 SRCS-y += init.c
 SRCS-y += thread.c
-SRCS-y += thread_fe.c
 SRCS-y += cpu_core_map.c
 
-SRCS-y += pipeline_common_be.c
-SRCS-y += pipeline_common_fe.c
-SRCS-y += pipeline_master_be.c
-SRCS-y += pipeline_master.c
-
 # Build using pkg-config variables if possible
 $(shell pkg-config --exists libdpdk)
 ifeq ($(.SHELLSTATUS),0)
diff --git a/examples/ip_pipeline/app.h b/examples/ip_pipeline/app.h
index 907d4e7..dadaf2b 100644
--- a/examples/ip_pipeline/app.h
+++ b/examples/ip_pipeline/app.h
@@ -1359,10 +1359,6 @@ app_core_build_core_mask_string(struct app_params *app, char *mask_buffer)
 	}
 }
 
-void app_pipeline_params_get(struct app_params *app,
-	struct app_pipeline_params *p_in,
-	struct pipeline_params *p_out);
-
 int app_config_init(struct app_params *app);
 
 int app_config_args(struct app_params *app,
@@ -1382,16 +1378,8 @@ int app_config_check(struct app_params *app);
 
 int app_init(struct app_params *app);
 
-int app_post_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);
 
diff --git a/examples/ip_pipeline/pipeline/hash_func.h b/examples/ip_pipeline/hash_func.h
similarity index 99%
rename from examples/ip_pipeline/pipeline/hash_func.h
rename to examples/ip_pipeline/hash_func.h
index 806ac22..f1b9d94 100644
--- a/examples/ip_pipeline/pipeline/hash_func.h
+++ b/examples/ip_pipeline/hash_func.h
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
+ * Copyright(c) 2010-2018 Intel Corporation
  */
+
 #ifndef __INCLUDE_HASH_FUNC_H__
 #define __INCLUDE_HASH_FUNC_H__
 
diff --git a/examples/ip_pipeline/pipeline/hash_func_arm64.h b/examples/ip_pipeline/hash_func_arm64.h
similarity index 100%
rename from examples/ip_pipeline/pipeline/hash_func_arm64.h
rename to examples/ip_pipeline/hash_func_arm64.h
diff --git a/examples/ip_pipeline/init.c b/examples/ip_pipeline/init.c
index f848310..9430809 100644
--- a/examples/ip_pipeline/init.c
+++ b/examples/ip_pipeline/init.c
@@ -24,9 +24,6 @@
 
 #include "app.h"
 #include "pipeline.h"
-#include "pipeline_common_fe.h"
-#include "pipeline_master.h"
-#include "thread_fe.h"
 
 #define APP_NAME_SIZE	32
 
@@ -1328,478 +1325,6 @@ app_init_msgq(struct app_params *app)
 	}
 }
 
-void app_pipeline_params_get(struct app_params *app,
-	struct app_pipeline_params *p_in,
-	struct pipeline_params *p_out)
-{
-	uint32_t i;
-
-	snprintf(p_out->name, PIPELINE_NAME_SIZE, "%s", p_in->name);
-
-	snprintf(p_out->type, PIPELINE_TYPE_SIZE, "%s", p_in->type);
-
-	p_out->socket_id = (int) p_in->socket_id;
-
-	p_out->log_level = app->log_level;
-
-	/* 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];
-
-		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%" SCNu32 ".%" SCNu32,
-				&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:
-		{
-			struct app_pktq_swq_params *swq_params = &app->swq_params[in->id];
-
-			if ((swq_params->ipv4_frag == 0) && (swq_params->ipv6_frag == 0)) {
-				if (app_swq_get_readers(app, swq_params) == 1) {
-					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;
-				} else {
-					out->type = PIPELINE_PORT_IN_RING_MULTI_READER;
-					out->params.ring_multi.ring = app->swq[in->id];
-					out->burst_size = swq_params->burst_read;
-				}
-			} else {
-				if (swq_params->ipv4_frag == 1) {
-					struct rte_port_ring_reader_ipv4_frag_params *params =
-						&out->params.ring_ipv4_frag;
-
-					out->type = PIPELINE_PORT_IN_RING_READER_IPV4_FRAG;
-					params->ring = app->swq[in->id];
-					params->mtu = swq_params->mtu;
-					params->metadata_size = swq_params->metadata_size;
-					params->pool_direct =
-						app->mempool[swq_params->mempool_direct_id];
-					params->pool_indirect =
-						app->mempool[swq_params->mempool_indirect_id];
-					out->burst_size = swq_params->burst_read;
-				} else {
-					struct rte_port_ring_reader_ipv6_frag_params *params =
-						&out->params.ring_ipv6_frag;
-
-					out->type = PIPELINE_PORT_IN_RING_READER_IPV6_FRAG;
-					params->ring = app->swq[in->id];
-					params->mtu = swq_params->mtu;
-					params->metadata_size = swq_params->metadata_size;
-					params->pool_direct =
-						app->mempool[swq_params->mempool_direct_id];
-					params->pool_indirect =
-						app->mempool[swq_params->mempool_indirect_id];
-					out->burst_size = swq_params->burst_read;
-				}
-			}
-			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;
-		}
-#ifdef RTE_EXEC_ENV_LINUXAPP
-		case APP_PKTQ_IN_TAP:
-		{
-			struct app_pktq_tap_params *tap_params =
-				&app->tap_params[in->id];
-			struct app_mempool_params *mempool_params =
-				&app->mempool_params[tap_params->mempool_id];
-			struct rte_mempool *mempool =
-				app->mempool[tap_params->mempool_id];
-
-			out->type = PIPELINE_PORT_IN_FD_READER;
-			out->params.fd.fd = app->tap[in->id];
-			out->params.fd.mtu = mempool_params->buffer_size;
-			out->params.fd.mempool = mempool;
-			out->burst_size = app->tap_params[in->id].burst_read;
-			break;
-		}
-#endif
-#ifdef RTE_LIBRTE_KNI
-		case APP_PKTQ_IN_KNI:
-		{
-			out->type = PIPELINE_PORT_IN_KNI_READER;
-			out->params.kni.kni = app->kni[in->id];
-			out->burst_size = app->kni_params[in->id].burst_read;
-			break;
-		}
-#endif /* RTE_LIBRTE_KNI */
-		case APP_PKTQ_IN_SOURCE:
-		{
-			uint32_t mempool_id =
-				app->source_params[in->id].mempool_id;
-
-			out->type = PIPELINE_PORT_IN_SOURCE;
-			out->params.source.mempool = app->mempool[mempool_id];
-			out->burst_size = app->source_params[in->id].burst;
-			out->params.source.file_name =
-				app->source_params[in->id].file_name;
-			out->params.source.n_bytes_per_pkt =
-				app->source_params[in->id].n_bytes_per_pkt;
-			break;
-		}
-		default:
-			break;
-		}
-	}
-
-	/* 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%" SCNu32 ".%" SCNu32,
-				&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:
-		{
-			struct app_pktq_swq_params *swq_params = &app->swq_params[in->id];
-
-			if ((swq_params->ipv4_ras == 0) && (swq_params->ipv6_ras == 0)) {
-				if (app_swq_get_writers(app, swq_params) == 1) {
-					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;
-					}
-				} else {
-					if (swq_params->dropless == 0) {
-						struct rte_port_ring_multi_writer_params *params =
-							&out->params.ring_multi;
-
-						out->type = PIPELINE_PORT_OUT_RING_MULTI_WRITER;
-						params->ring = app->swq[in->id];
-						params->tx_burst_sz = swq_params->burst_write;
-					} else {
-						struct rte_port_ring_multi_writer_nodrop_params
-							*params = &out->params.ring_multi_nodrop;
-
-						out->type = PIPELINE_PORT_OUT_RING_MULTI_WRITER_NODROP;
-						params->ring = app->swq[in->id];
-						params->tx_burst_sz = swq_params->burst_write;
-						params->n_retries = swq_params->n_retries;
-					}
-				}
-			} else {
-				if (swq_params->ipv4_ras == 1) {
-					struct rte_port_ring_writer_ipv4_ras_params *params =
-						&out->params.ring_ipv4_ras;
-
-					out->type = PIPELINE_PORT_OUT_RING_WRITER_IPV4_RAS;
-					params->ring = app->swq[in->id];
-					params->tx_burst_sz = swq_params->burst_write;
-				} else {
-					struct rte_port_ring_writer_ipv6_ras_params *params =
-						&out->params.ring_ipv6_ras;
-
-					out->type = PIPELINE_PORT_OUT_RING_WRITER_IPV6_RAS;
-					params->ring = app->swq[in->id];
-					params->tx_burst_sz = swq_params->burst_write;
-				}
-			}
-			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;
-		}
-#ifdef RTE_EXEC_ENV_LINUXAPP
-		case APP_PKTQ_OUT_TAP:
-		{
-			struct rte_port_fd_writer_params *params =
-				&out->params.fd;
-
-			out->type = PIPELINE_PORT_OUT_FD_WRITER;
-			params->fd = app->tap[in->id];
-			params->tx_burst_sz =
-				app->tap_params[in->id].burst_write;
-			break;
-		}
-#endif
-#ifdef RTE_LIBRTE_KNI
-		case APP_PKTQ_OUT_KNI:
-		{
-			struct app_pktq_kni_params *p_kni =
-				&app->kni_params[in->id];
-
-			if (p_kni->dropless == 0) {
-				struct rte_port_kni_writer_params *params =
-					&out->params.kni;
-
-				out->type = PIPELINE_PORT_OUT_KNI_WRITER;
-				params->kni = app->kni[in->id];
-				params->tx_burst_sz =
-					app->kni_params[in->id].burst_write;
-			} else {
-				struct rte_port_kni_writer_nodrop_params
-					*params = &out->params.kni_nodrop;
-
-				out->type = PIPELINE_PORT_OUT_KNI_WRITER_NODROP;
-				params->kni = app->kni[in->id];
-				params->tx_burst_sz =
-					app->kni_params[in->id].burst_write;
-				params->n_retries =
-					app->kni_params[in->id].n_retries;
-			}
-			break;
-		}
-#endif /* RTE_LIBRTE_KNI */
-		case APP_PKTQ_OUT_SINK:
-		{
-			out->type = PIPELINE_PORT_OUT_SINK;
-			out->params.sink.file_name =
-				app->sink_params[in->id].file_name;
-			out->params.sink.max_n_pkts =
-				app->sink_params[in->id].
-				n_pkts_to_dump;
-
-			break;
-		}
-		default:
-			break;
-		}
-	}
-
-	/* msgq */
-	p_out->n_msgq = p_in->n_msgq_in;
-
-	for (i = 0; i < p_in->n_msgq_in; i++)
-		p_out->msgq_in[i] = app->msgq[p_in->msgq_in[i]];
-
-	for (i = 0; i < p_in->n_msgq_out; i++)
-		p_out->msgq_out[i] = app->msgq[p_in->msgq_out[i]];
-
-	/* 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];
-	}
-}
-
-static void
-app_init_pipelines(struct app_params *app)
-{
-	uint32_t p_id;
-
-	for (p_id = 0; p_id < app->n_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;
-
-		APP_LOG(app, HIGH, "Initializing %s ...", 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->be_ops->f_init) {
-			data->be = ptype->be_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->ptype = ptype;
-
-		data->timer_period = (rte_get_tsc_hz() *
-			params->timer_period) / 1000;
-	}
-}
-
-static void
-app_post_init_pipelines(struct app_params *app)
-{
-	uint32_t p_id;
-
-	for (p_id = 0; p_id < app->n_pipelines; p_id++) {
-		struct app_pipeline_params *params =
-			&app->pipeline_params[p_id];
-		struct app_pipeline_data *data = &app->pipeline_data[p_id];
-		int status;
-
-		if (data->ptype->fe_ops->f_post_init == NULL)
-			continue;
-
-		status = data->ptype->fe_ops->f_post_init(data->fe);
-		if (status)
-			rte_panic("Pipeline instance \"%s\" front-end "
-				"post-init error\n", params->name);
-	}
-}
-
-static void
-app_init_threads(struct app_params *app)
-{
-	uint64_t time = rte_get_tsc_cycles();
-	uint32_t p_id;
-
-	for (p_id = 0; p_id < app->n_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;
-
-		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%" PRIu32 "c%" PRIu32 "%s\n",
-				params->socket_id,
-				params->core_id,
-				(params->hyper_th_id) ? "h" : "");
-
-		t = &app->thread_data[lcore_id];
-
-		t->timer_period = (rte_get_tsc_hz() * APP_THREAD_TIMER_PERIOD) / 1000;
-		t->thread_req_deadline = time + t->timer_period;
-
-		t->headroom_cycles = 0;
-		t->headroom_time = rte_get_tsc_cycles();
-		t->headroom_ratio = 0.0;
-
-		t->msgq_in = app_thread_msgq_in_get(app,
-				params->socket_id,
-				params->core_id,
-				params->hyper_th_id);
-		if (t->msgq_in == NULL)
-			rte_panic("Init error: Cannot find MSGQ_IN for thread %" PRId32,
-				lcore_id);
-
-		t->msgq_out = app_thread_msgq_out_get(app,
-				params->socket_id,
-				params->core_id,
-				params->hyper_th_id);
-		if (t->msgq_out == NULL)
-			rte_panic("Init error: Cannot find MSGQ_OUT for thread %" PRId32,
-				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->be_ops->f_run == NULL) ?
-			&t->regular[t->n_regular] :
-			&t->custom[t->n_custom];
-
-		p->pipeline_id = p_id;
-		p->be = data->be;
-		p->f_run = ptype->be_ops->f_run;
-		p->f_timer = ptype->be_ops->f_timer;
-		p->timer_period = data->timer_period;
-		p->deadline = time + data->timer_period;
-
-		data->enabled = 1;
-
-		if (ptype->be_ops->f_run == NULL)
-			t->n_regular++;
-		else
-			t->n_custom++;
-	}
-}
-
 int app_init(struct app_params *app)
 {
 	app_init_core_map(app);
@@ -1814,104 +1339,5 @@ int app_init(struct app_params *app)
 	app_init_kni(app);
 	app_init_msgq(app);
 
-	app_pipeline_common_cmd_push(app);
-	app_pipeline_thread_cmd_push(app);
-	app_pipeline_type_register(app, &pipeline_master);
-
-	app_init_pipelines(app);
-	app_init_threads(app);
-
 	return 0;
 }
-
-int app_post_init(struct app_params *app)
-{
-	app_post_init_pipelines(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)
-{
-	uint32_t n_cmds, i;
-
-	/* Check input arguments */
-	if ((app == NULL) ||
-		(ptype == NULL) ||
-		(ptype->name == NULL) ||
-		(strlen(ptype->name) == 0) ||
-		(ptype->be_ops->f_init == NULL) ||
-		(ptype->be_ops->f_timer == 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;
-}
-
-struct
-pipeline_type *app_pipeline_type_find(struct app_params *app, char *name)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_pipeline_types; i++)
-		if (strcmp(app->pipeline_type[i].name, name) == 0)
-			return &app->pipeline_type[i];
-
-	return NULL;
-}
diff --git a/examples/ip_pipeline/meson.build b/examples/ip_pipeline/meson.build
index 7563b39..be3f3e5 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -6,8 +6,7 @@
 # To build this example as a standalone application with an already-installed
 # DPDK instance, use 'make'
 
-deps += ['cfgfile', 'pipeline', 'bus_pci']
-includes += include_directories('pipeline')
+deps += ['cfgfile', 'bus_pci']
 sources = files(
 	'config_check.c',
 	'config_parse.c',
@@ -17,9 +16,4 @@ sources = files(
 	'main.c',
 	'parser.c',
 	'thread.c',
-	'thread_fe.c',
-	'pipeline/pipeline_common_be.c',
-	'pipeline/pipeline_common_fe.c',
-	'pipeline/pipeline_master_be.c',
-	'pipeline/pipeline_master.c',
 )
diff --git a/examples/ip_pipeline/pipeline/pipeline_actions_common.h b/examples/ip_pipeline/pipeline/pipeline_actions_common.h
deleted file mode 100644
index 23f8836..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_actions_common.h
+++ /dev/null
@@ -1,202 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2016 Intel Corporation
- */
-#ifndef __INCLUDE_PIPELINE_ACTIONS_COMMON_H__
-#define __INCLUDE_PIPELINE_ACTIONS_COMMON_H__
-
-#include <stdint.h>
-
-#include <rte_common.h>
-#include <rte_cycles.h>
-#include <rte_mbuf.h>
-#include <rte_pipeline.h>
-
-#define PIPELINE_PORT_IN_AH(f_ah, f_pkt_work, f_pkt4_work)		\
-static int								\
-f_ah(									\
-	__rte_unused struct rte_pipeline *p,				\
-	struct rte_mbuf **pkts,						\
-	uint32_t n_pkts,						\
-	void *arg)							\
-{									\
-	uint32_t i;							\
-									\
-	for (i = 0; i < (n_pkts & (~0x3LLU)); i += 4)			\
-		f_pkt4_work(&pkts[i], arg);				\
-									\
-	for ( ; i < n_pkts; i++)					\
-		f_pkt_work(pkts[i], arg);				\
-									\
-	return 0;							\
-}
-
-#define PIPELINE_PORT_IN_AH_HIJACK_ALL(f_ah, f_pkt_work, f_pkt4_work) \
-static int								\
-f_ah(									\
-	struct rte_pipeline *p,				\
-	struct rte_mbuf **pkts,					\
-	uint32_t n_pkts,						\
-	void *arg)						\
-{									\
-	uint64_t pkt_mask = RTE_LEN2MASK(n_pkts, uint64_t);	\
-	uint32_t i;							\
-									\
-	rte_pipeline_ah_packet_hijack(p, pkt_mask);	\
-									\
-	for (i = 0; i < (n_pkts & (~0x3LLU)); i += 4)	\
-		f_pkt4_work(&pkts[i], arg);				\
-									\
-	for ( ; i < n_pkts; i++)				\
-		f_pkt_work(pkts[i], arg);			\
-									\
-	return 0;							\
-}
-
-#define PIPELINE_TABLE_AH_HIT(f_ah, f_pkt_work, f_pkt4_work)		\
-static int								\
-f_ah(									\
-	__rte_unused struct rte_pipeline *p,				\
-	struct rte_mbuf **pkts,						\
-	uint64_t pkts_in_mask,						\
-	struct rte_pipeline_table_entry **entries,			\
-	void *arg)							\
-{									\
-	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 & (~0x3LLU)); i += 4)		\
-			f_pkt4_work(&pkts[i], &entries[i], arg);	\
-									\
-		for ( ; i < n_pkts; i++)				\
-			f_pkt_work(pkts[i], entries[i], arg);		\
-	} else								\
-		for ( ; pkts_in_mask; ) {				\
-			uint32_t pos = __builtin_ctzll(pkts_in_mask);	\
-			uint64_t pkt_mask = 1LLU << pos;		\
-									\
-			pkts_in_mask &= ~pkt_mask;			\
-			f_pkt_work(pkts[pos], entries[pos], arg);	\
-		}							\
-									\
-	return 0;							\
-}
-
-#define PIPELINE_TABLE_AH_MISS(f_ah, f_pkt_work, f_pkt4_work)		\
-static int								\
-f_ah(									\
-	__rte_unused struct rte_pipeline *p,				\
-	struct rte_mbuf **pkts,						\
-	uint64_t pkts_in_mask,						\
-	struct rte_pipeline_table_entry *entry,				\
-	void *arg)							\
-{									\
-	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 & (~0x3LLU)); i += 4)		\
-			f_pkt4_work(&pkts[i], entry, arg);		\
-									\
-		for ( ; i < n_pkts; i++)				\
-			f_pkt_work(pkts[i], entry, arg);		\
-	} else								\
-		for ( ; pkts_in_mask; ) {				\
-			uint32_t pos = __builtin_ctzll(pkts_in_mask);	\
-			uint64_t pkt_mask = 1LLU << pos;		\
-									\
-			pkts_in_mask &= ~pkt_mask;			\
-			f_pkt_work(pkts[pos], entry, arg);		\
-		}							\
-									\
-	return 0;							\
-}
-
-#define PIPELINE_TABLE_AH_HIT_DROP_TIME(f_ah, f_pkt_work, f_pkt4_work)	\
-static int								\
-f_ah(									\
-	struct rte_pipeline *p,						\
-	struct rte_mbuf **pkts,						\
-	uint64_t pkts_mask,						\
-	struct rte_pipeline_table_entry **entries,			\
-	void *arg)							\
-{									\
-	uint64_t pkts_in_mask = pkts_mask;				\
-	uint64_t pkts_out_mask = pkts_mask;				\
-	uint64_t time = rte_rdtsc();					\
-									\
-	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 & (~0x3LLU)); i += 4) {		\
-			uint64_t mask = f_pkt4_work(&pkts[i],		\
-				&entries[i], arg, time);		\
-			pkts_out_mask ^= mask << i;			\
-		}							\
-									\
-		for ( ; i < n_pkts; i++) {				\
-			uint64_t mask = f_pkt_work(pkts[i],		\
-				entries[i], arg, time);			\
-			pkts_out_mask ^= mask << i;			\
-		}							\
-	} else								\
-		for ( ; pkts_in_mask; ) {				\
-			uint32_t pos = __builtin_ctzll(pkts_in_mask);	\
-			uint64_t pkt_mask = 1LLU << pos;		\
-			uint64_t mask = f_pkt_work(pkts[pos],		\
-				entries[pos], arg, time);		\
-									\
-			pkts_in_mask &= ~pkt_mask;			\
-			pkts_out_mask ^= mask << pos;			\
-		}							\
-									\
-	rte_pipeline_ah_packet_drop(p, pkts_out_mask ^ pkts_mask);	\
-									\
-	return 0;							\
-}
-
-#define PIPELINE_TABLE_AH_MISS_DROP_TIME(f_ah, f_pkt_work, f_pkt4_work)	\
-static int								\
-f_ah(									\
-	struct rte_pipeline *p,						\
-	struct rte_mbuf **pkts,						\
-	uint64_t pkts_mask,						\
-	struct rte_pipeline_table_entry *entry,				\
-	void *arg)							\
-{									\
-	uint64_t pkts_in_mask = pkts_mask;				\
-	uint64_t pkts_out_mask = pkts_mask;				\
-	uint64_t time = rte_rdtsc();					\
-									\
-	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 & (~0x3LLU)); i += 4) {		\
-			uint64_t mask = f_pkt4_work(&pkts[i],		\
-				entry, arg, time);			\
-			pkts_out_mask ^= mask << i;			\
-		}							\
-									\
-		for ( ; i < n_pkts; i++) {				\
-			uint64_t mask = f_pkt_work(pkts[i], entry, arg, time);\
-			pkts_out_mask ^= mask << i;			\
-		}							\
-	} else								\
-		for ( ; pkts_in_mask; ) {				\
-			uint32_t pos = __builtin_ctzll(pkts_in_mask);	\
-			uint64_t pkt_mask = 1LLU << pos;		\
-			uint64_t mask = f_pkt_work(pkts[pos],		\
-				entry, arg, time);		\
-									\
-			pkts_in_mask &= ~pkt_mask;			\
-			pkts_out_mask ^= mask << pos;			\
-		}							\
-									\
-	rte_pipeline_ah_packet_drop(p, pkts_out_mask ^ pkts_mask);	\
-									\
-	return 0;							\
-}
-
-#endif
diff --git a/examples/ip_pipeline/pipeline/pipeline_common_be.c b/examples/ip_pipeline/pipeline/pipeline_common_be.c
deleted file mode 100644
index 5d84989..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_common_be.c
+++ /dev/null
@@ -1,176 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#include <rte_common.h>
-#include <rte_malloc.h>
-
-#include "pipeline_common_be.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(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(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(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(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(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_be.h b/examples/ip_pipeline/pipeline/pipeline_common_be.h
deleted file mode 100644
index 83bd04e..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_common_be.h
+++ /dev/null
@@ -1,134 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#ifndef __INCLUDE_PIPELINE_COMMON_BE_H__
-#define __INCLUDE_PIPELINE_COMMON_BE_H__
-
-#include <rte_common.h>
-#include <rte_ring.h>
-#include <rte_pipeline.h>
-
-#include "pipeline_be.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];
-	uint32_t log_level;
-};
-
-enum pipeline_log_level {
-	PIPELINE_LOG_LEVEL_HIGH = 1,
-	PIPELINE_LOG_LEVEL_LOW,
-	PIPELINE_LOG_LEVELS
-};
-
-#define PLOG(p, level, fmt, ...)					\
-do {									\
-	if (p->log_level >= PIPELINE_LOG_LEVEL_ ## level)		\
-		fprintf(stdout, "[%s] " fmt "\n", p->name, ## __VA_ARGS__);\
-} while (0)
-
-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_common_fe.c b/examples/ip_pipeline/pipeline/pipeline_common_fe.c
deleted file mode 100644
index cc5214c..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_common_fe.c
+++ /dev/null
@@ -1,1455 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2016 Intel Corporation
- */
-
-#include <stdio.h>
-#include <fcntl.h>
-#include <unistd.h>
-
-#include <rte_common.h>
-#include <rte_malloc.h>
-#include <cmdline_rdline.h>
-#include <cmdline_parse.h>
-#include <cmdline_parse_num.h>
-#include <cmdline_parse_string.h>
-#include <cmdline.h>
-
-#include "pipeline_common_fe.h"
-#include "parser.h"
-
-struct app_link_params *
-app_pipeline_track_pktq_out_to_link(struct app_params *app,
-	uint32_t pipeline_id,
-	uint32_t pktq_out_id)
-{
-	struct app_pipeline_params *p;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return NULL;
-
-	APP_PARAM_FIND_BY_ID(app->pipeline_params, "PIPELINE", pipeline_id, p);
-	if (p == NULL)
-		return NULL;
-
-	for ( ; ; ) {
-		struct app_pktq_out_params *pktq_out =
-			&p->pktq_out[pktq_out_id];
-
-		switch (pktq_out->type) {
-		case APP_PKTQ_OUT_HWQ:
-		{
-			struct app_pktq_hwq_out_params *hwq_out;
-
-			hwq_out = &app->hwq_out_params[pktq_out->id];
-
-			return app_get_link_for_txq(app, hwq_out);
-		}
-
-		case APP_PKTQ_OUT_SWQ:
-		{
-			struct pipeline_params pp;
-			struct pipeline_type *ptype;
-			struct app_pktq_swq_params *swq;
-			uint32_t pktq_in_id;
-			int status;
-
-			swq = &app->swq_params[pktq_out->id];
-			p = app_swq_get_reader(app, swq, &pktq_in_id);
-			if (p == NULL)
-				return NULL;
-
-			ptype = app_pipeline_type_find(app, p->type);
-			if ((ptype == NULL) || (ptype->fe_ops->f_track == NULL))
-				return NULL;
-
-			app_pipeline_params_get(app, p, &pp);
-			status = ptype->fe_ops->f_track(&pp,
-				pktq_in_id,
-				&pktq_out_id);
-			if (status)
-				return NULL;
-
-			break;
-		}
-
-		case APP_PKTQ_OUT_TM:
-		{
-			struct pipeline_params pp;
-			struct pipeline_type *ptype;
-			struct app_pktq_tm_params *tm;
-			uint32_t pktq_in_id;
-			int status;
-
-			tm = &app->tm_params[pktq_out->id];
-			p = app_tm_get_reader(app, tm, &pktq_in_id);
-			if (p == NULL)
-				return NULL;
-
-			ptype = app_pipeline_type_find(app, p->type);
-			if ((ptype == NULL) || (ptype->fe_ops->f_track == NULL))
-				return NULL;
-
-			app_pipeline_params_get(app, p, &pp);
-			status = ptype->fe_ops->f_track(&pp,
-				pktq_in_id,
-				&pktq_out_id);
-			if (status)
-				return NULL;
-
-			break;
-		}
-
-		case APP_PKTQ_OUT_KNI:
-		{
-			struct pipeline_params pp;
-			struct pipeline_type *ptype;
-			struct app_pktq_kni_params *kni;
-			uint32_t pktq_in_id;
-			int status;
-
-			kni = &app->kni_params[pktq_out->id];
-			p = app_kni_get_reader(app, kni, &pktq_in_id);
-			if (p == NULL)
-				return NULL;
-
-			ptype = app_pipeline_type_find(app, p->type);
-			if ((ptype == NULL) || (ptype->fe_ops->f_track == NULL))
-				return NULL;
-
-			app_pipeline_params_get(app, p, &pp);
-			status = ptype->fe_ops->f_track(&pp,
-				pktq_in_id,
-				&pktq_out_id);
-			if (status)
-				return NULL;
-
-			break;
-		}
-
-		case APP_PKTQ_OUT_TAP:
-		case APP_PKTQ_OUT_SINK:
-		default:
-			return NULL;
-		}
-	}
-}
-
-int
-app_pipeline_track_default(struct pipeline_params *p,
-	uint32_t port_in,
-	uint32_t *port_out)
-{
-	/* Check input arguments */
-	if ((p == NULL) ||
-		(port_in >= p->n_ports_in) ||
-		(port_out == NULL))
-		return -1;
-
-	if (p->n_ports_out == 1) {
-		*port_out = 0;
-		return 0;
-	}
-
-	return -1;
-}
-
-int
-app_pipeline_ping(struct app_params *app,
-	uint32_t pipeline_id)
-{
-	struct app_pipeline_params *p;
-	struct pipeline_msg_req *req;
-	struct pipeline_msg_rsp *rsp;
-	int status = 0;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	APP_PARAM_FIND_BY_ID(app->pipeline_params, "PIPELINE", pipeline_id, p);
-	if (p == NULL)
-		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, MSG_TIMEOUT_DEFAULT);
-	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 app_pipeline_params *p;
-	struct pipeline_stats_msg_req *req;
-	struct pipeline_stats_port_in_msg_rsp *rsp;
-	int status = 0;
-
-	/* Check input arguments */
-	if ((app == NULL) ||
-		(stats == NULL))
-		return -1;
-
-	APP_PARAM_FIND_BY_ID(app->pipeline_params, "PIPELINE", pipeline_id, p);
-	if ((p == NULL) ||
-		(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, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	/* Check response */
-	status = rsp->status;
-	if (status == 0)
-		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 app_pipeline_params *p;
-	struct pipeline_stats_msg_req *req;
-	struct pipeline_stats_port_out_msg_rsp *rsp;
-	int status = 0;
-
-	/* Check input arguments */
-	if ((app == NULL) ||
-		(pipeline_id >= app->n_pipelines) ||
-		(stats == NULL))
-		return -1;
-
-	APP_PARAM_FIND_BY_ID(app->pipeline_params, "PIPELINE", pipeline_id, p);
-	if ((p == NULL) ||
-		(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, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	/* Check response */
-	status = rsp->status;
-	if (status == 0)
-		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 app_pipeline_params *p;
-	struct pipeline_stats_msg_req *req;
-	struct pipeline_stats_table_msg_rsp *rsp;
-	int status = 0;
-
-	/* Check input arguments */
-	if ((app == NULL) ||
-		(stats == NULL))
-		return -1;
-
-	APP_PARAM_FIND_BY_ID(app->pipeline_params, "PIPELINE", pipeline_id, p);
-	if (p == 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, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	/* Check response */
-	status = rsp->status;
-	if (status == 0)
-		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 app_pipeline_params *p;
-	struct pipeline_port_in_msg_req *req;
-	struct pipeline_msg_rsp *rsp;
-	int status = 0;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	APP_PARAM_FIND_BY_ID(app->pipeline_params, "PIPELINE", pipeline_id, p);
-	if ((p == NULL) ||
-		(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, MSG_TIMEOUT_DEFAULT);
-	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 app_pipeline_params *p;
-	struct pipeline_port_in_msg_req *req;
-	struct pipeline_msg_rsp *rsp;
-	int status = 0;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	APP_PARAM_FIND_BY_ID(app->pipeline_params, "PIPELINE", pipeline_id, p);
-	if ((p == NULL) ||
-		(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, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	/* Check response */
-	status = rsp->status;
-
-	/* Message buffer free */
-	app_msg_free(app, rsp);
-
-	return status;
-}
-
-int
-app_link_set_op(struct app_params *app,
-	uint32_t link_id,
-	uint32_t pipeline_id,
-	app_link_op op,
-	void *arg)
-{
-	struct app_pipeline_params *pp;
-	struct app_link_params *lp;
-	struct app_link_data *ld;
-	uint32_t ppos, lpos;
-
-	/* Check input arguments */
-	if ((app == NULL) ||
-		(op == NULL))
-		return -1;
-
-	APP_PARAM_FIND_BY_ID(app->link_params, "LINK", link_id, lp);
-	if (lp == NULL)
-		return -1;
-	lpos = lp - app->link_params;
-	ld = &app->link_data[lpos];
-
-	APP_PARAM_FIND_BY_ID(app->pipeline_params, "PIPELINE", pipeline_id, pp);
-	if (pp == NULL)
-		return -1;
-	ppos = pp - app->pipeline_params;
-
-	ld->f_link[ppos] = op;
-	ld->arg[ppos] = arg;
-
-	return 0;
-}
-
-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;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	APP_PARAM_FIND_BY_ID(app->link_params, "LINK", link_id, p);
-	if (p == NULL) {
-		APP_LOG(app, HIGH, "LINK%" PRIu32 " is not a valid link",
-			link_id);
-		return -1;
-	}
-
-	if (p->state) {
-		APP_LOG(app, HIGH, "%s is UP, please bring it DOWN first",
-			p->name);
-		return -1;
-	}
-
-	netmask = (~0U) << (32 - depth);
-	host = ip & netmask;
-	bcast = host | (~netmask);
-
-	if ((ip == 0) ||
-		(ip == UINT32_MAX) ||
-		(ip == host) ||
-		(ip == bcast)) {
-		APP_LOG(app, HIGH, "Illegal IP address");
-		return -1;
-	}
-
-	for (i = 0; i < app->n_links; i++) {
-		struct app_link_params *link = &app->link_params[i];
-
-		if (strcmp(p->name, link->name) == 0)
-			continue;
-
-		if (link->ip == ip) {
-			APP_LOG(app, HIGH,
-				"%s is already assigned this IP address",
-				link->name);
-			return -1;
-		}
-	}
-
-	if ((depth == 0) || (depth > 32)) {
-		APP_LOG(app, HIGH, "Illegal value for depth parameter "
-			"(%" PRIu32 ")",
-			depth);
-		return -1;
-	}
-
-	/* Save link parameters */
-	p->ip = ip;
-	p->depth = depth;
-
-	return 0;
-}
-
-int
-app_link_up(struct app_params *app,
-	uint32_t link_id)
-{
-	struct app_link_params *p;
-	struct app_link_data *d;
-	int i;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	APP_PARAM_FIND_BY_ID(app->link_params, "LINK", link_id, p);
-	if (p == NULL) {
-		APP_LOG(app, HIGH, "LINK%" PRIu32 " is not a valid link",
-			link_id);
-		return -1;
-	}
-
-	d = &app->link_data[p - app->link_params];
-
-	/* Check link state */
-	if (p->state) {
-		APP_LOG(app, HIGH, "%s is already UP", p->name);
-		return 0;
-	}
-
-	/* Check that IP address is valid */
-	if (p->ip == 0) {
-		APP_LOG(app, HIGH, "%s IP address is not set", p->name);
-		return 0;
-	}
-
-	app_link_up_internal(app, p);
-
-	/* Callbacks */
-	for (i = 0; i < APP_MAX_PIPELINES; i++)
-		if (d->f_link[i])
-			d->f_link[i](app, link_id, 1, d->arg[i]);
-
-	return 0;
-}
-
-int
-app_link_down(struct app_params *app,
-	uint32_t link_id)
-{
-	struct app_link_params *p;
-	struct app_link_data *d;
-	uint32_t i;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	APP_PARAM_FIND_BY_ID(app->link_params, "LINK", link_id, p);
-	if (p == NULL) {
-		APP_LOG(app, HIGH, "LINK%" PRIu32 " is not a valid link",
-			link_id);
-		return -1;
-	}
-
-	d = &app->link_data[p - app->link_params];
-
-	/* Check link state */
-	if (p->state == 0) {
-		APP_LOG(app, HIGH, "%s is already DOWN", p->name);
-		return 0;
-	}
-
-	app_link_down_internal(app, p);
-
-	/* Callbacks */
-	for (i = 0; i < APP_MAX_PIPELINES; i++)
-		if (d->f_link[i])
-			d->f_link[i](app, link_id, 0, d->arg[i]);
-
-	return 0;
-}
-
-/*
- * 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("Command failed\n");
-}
-
-static cmdline_parse_token_string_t cmd_ping_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_ping_result, p_string, "p");
-
-static cmdline_parse_token_num_t cmd_ping_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_ping_result, pipeline_id, UINT32);
-
-static cmdline_parse_token_string_t cmd_ping_ping_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_ping_result, ping_string, "ping");
-
-static cmdline_parse_inst_t cmd_ping = {
-	.f = cmd_ping_parsed,
-	.data = NULL,
-	.help_str = "Pipeline ping",
-	.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("Command failed\n");
-		return;
-	}
-
-	/* Display stats */
-	printf("Pipeline %" PRIu32 " - stats for input port %" PRIu32 ":\n"
-		"\tPkts in: %" PRIu64 "\n"
-		"\tPkts dropped by AH: %" PRIu64 "\n"
-		"\tPkts dropped by other: %" PRIu64 "\n",
-		params->pipeline_id,
-		params->port_in_id,
-		stats.stats.n_pkts_in,
-		stats.n_pkts_dropped_by_ah,
-		stats.stats.n_pkts_drop);
-}
-
-static cmdline_parse_token_string_t cmd_stats_port_in_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_stats_port_in_result, p_string,
-		"p");
-
-static cmdline_parse_token_num_t cmd_stats_port_in_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_stats_port_in_result, pipeline_id,
-		UINT32);
-
-static cmdline_parse_token_string_t cmd_stats_port_in_stats_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_stats_port_in_result, stats_string,
-		"stats");
-
-static cmdline_parse_token_string_t cmd_stats_port_in_port_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_stats_port_in_result, port_string,
-		"port");
-
-static 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);
-
-static cmdline_parse_inst_t cmd_stats_port_in = {
-	.f = cmd_stats_port_in_parsed,
-	.data = NULL,
-	.help_str = "Pipeline input port stats",
-	.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("Command failed\n");
-		return;
-	}
-
-	/* Display stats */
-	printf("Pipeline %" PRIu32 " - stats for output port %" PRIu32 ":\n"
-		"\tPkts in: %" PRIu64 "\n"
-		"\tPkts dropped by AH: %" PRIu64 "\n"
-		"\tPkts dropped by other: %" PRIu64 "\n",
-		params->pipeline_id,
-		params->port_out_id,
-		stats.stats.n_pkts_in,
-		stats.n_pkts_dropped_by_ah,
-		stats.stats.n_pkts_drop);
-}
-
-static cmdline_parse_token_string_t cmd_stats_port_out_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_stats_port_out_result, p_string,
-	"p");
-
-static cmdline_parse_token_num_t cmd_stats_port_out_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_stats_port_out_result, pipeline_id,
-		UINT32);
-
-static cmdline_parse_token_string_t cmd_stats_port_out_stats_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_stats_port_out_result, stats_string,
-		"stats");
-
-static cmdline_parse_token_string_t cmd_stats_port_out_port_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_stats_port_out_result, port_string,
-		"port");
-
-static cmdline_parse_token_string_t cmd_stats_port_out_out_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_stats_port_out_result, out_string,
-		"out");
-
-static 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);
-
-static cmdline_parse_inst_t cmd_stats_port_out = {
-	.f = cmd_stats_port_out_parsed,
-	.data = NULL,
-	.help_str = "Pipeline output port stats",
-	.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("Command failed\n");
-		return;
-	}
-
-	/* Display stats */
-	printf("Pipeline %" PRIu32 " - stats for table %" PRIu32 ":\n"
-		"\tPkts in: %" PRIu64 "\n"
-		"\tPkts in with lookup miss: %" PRIu64 "\n"
-		"\tPkts in with lookup hit dropped by AH: %" PRIu64 "\n"
-		"\tPkts in with lookup hit dropped by others: %" PRIu64 "\n"
-		"\tPkts in with lookup miss dropped by AH: %" PRIu64 "\n"
-		"\tPkts in with lookup miss dropped by others: %" PRIu64 "\n",
-		params->pipeline_id,
-		params->table_id,
-		stats.stats.n_pkts_in,
-		stats.stats.n_pkts_lookup_miss,
-		stats.n_pkts_dropped_by_lkp_hit_ah,
-		stats.n_pkts_dropped_lkp_hit,
-		stats.n_pkts_dropped_by_lkp_miss_ah,
-		stats.n_pkts_dropped_lkp_miss);
-}
-
-static cmdline_parse_token_string_t cmd_stats_table_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_stats_table_result, p_string,
-		"p");
-
-static cmdline_parse_token_num_t cmd_stats_table_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_stats_table_result, pipeline_id,
-		UINT32);
-
-static cmdline_parse_token_string_t cmd_stats_table_stats_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_stats_table_result, stats_string,
-		"stats");
-
-static cmdline_parse_token_string_t cmd_stats_table_table_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_stats_table_result, table_string,
-		"table");
-
-static cmdline_parse_token_num_t cmd_stats_table_table_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_stats_table_result, table_id, UINT32);
-
-static cmdline_parse_inst_t cmd_stats_table = {
-	.f = cmd_stats_table_parsed,
-	.data = NULL,
-	.help_str = "Pipeline table stats",
-	.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("Command failed\n");
-}
-
-static cmdline_parse_token_string_t cmd_port_in_enable_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_port_in_enable_result, p_string,
-		"p");
-
-static cmdline_parse_token_num_t cmd_port_in_enable_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_port_in_enable_result, pipeline_id,
-		UINT32);
-
-static cmdline_parse_token_string_t cmd_port_in_enable_port_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_port_in_enable_result, port_string,
-	"port");
-
-static cmdline_parse_token_string_t cmd_port_in_enable_in_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_port_in_enable_result, in_string,
-		"in");
-
-static 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);
-
-static cmdline_parse_token_string_t cmd_port_in_enable_enable_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_port_in_enable_result,
-		enable_string, "enable");
-
-static 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("Command failed\n");
-}
-
-static cmdline_parse_token_string_t cmd_port_in_disable_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_port_in_disable_result, p_string,
-		"p");
-
-static cmdline_parse_token_num_t cmd_port_in_disable_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_port_in_disable_result, pipeline_id,
-		UINT32);
-
-static cmdline_parse_token_string_t cmd_port_in_disable_port_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_port_in_disable_result, port_string,
-		"port");
-
-static cmdline_parse_token_string_t cmd_port_in_disable_in_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_port_in_disable_result, in_string,
-		"in");
-
-static 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);
-
-static cmdline_parse_token_string_t cmd_port_in_disable_disable_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_port_in_disable_result,
-		disable_string, "disable");
-
-static 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,
-	},
-};
-
-/*
- * 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 = (~0U) << (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;
-
-	if (strlen(p->pci_bdf))
-		printf("%s(%s): flags=<%s>\n",
-			p->name,
-			p->pci_bdf,
-			(p->state) ? "UP" : "DOWN");
-	else
-		printf("%s: flags=<%s>\n",
-			p->name,
-			(p->state) ? "UP" : "DOWN");
-
-	if (p->ip)
-		printf("\tinet %" PRIu32 ".%" PRIu32
-			".%" PRIu32 ".%" PRIu32
-			" netmask %" PRIu32 ".%" PRIu32
-			".%" PRIu32 ".%" PRIu32 " "
-			"broadcast %" PRIu32 ".%" PRIu32
-			".%" PRIu32 ".%" PRIu32 "\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 %02" PRIx32 ":%02" PRIx32 ":%02" PRIx32
-		":%02" PRIx32 ":%02" PRIx32 ":%02" PRIx32 "\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 errors %" PRIu64
-		"  missed %" PRIu64
-		"  no-mbuf %" PRIu64
-		"\n",
-		stats.ierrors,
-		stats.imissed,
-		stats.rx_nombuf);
-
-	printf("\tTX packets %" PRIu64
-		"  bytes %" PRIu64 "\n",
-		stats.opackets,
-		stats.obytes);
-
-	printf("\tTX errors %" PRIu64
-		"\n",
-		stats.oerrors);
-
-	printf("\n");
-}
-
-/*
- * link
- *
- * link config:
- *    link <linkid> config <ipaddr> <depth>
- *
- * link up:
- *    link <linkid> up
- *
- * link down:
- *    link <linkid> down
- *
- * link ls:
- *    link ls
- */
-
-struct cmd_link_result {
-	cmdline_fixed_string_t link_string;
-	cmdline_multi_string_t multi_string;
-};
-
-static void
-cmd_link_parsed(
-	void *parsed_result,
-	__attribute__((unused)) struct cmdline *cl,
-	 void *data)
-{
-	struct cmd_link_result *params = parsed_result;
-	struct app_params *app = data;
-
-	char *tokens[16];
-	uint32_t n_tokens = RTE_DIM(tokens);
-	int status;
-
-	uint32_t link_id;
-
-	status = parse_tokenize_string(params->multi_string, tokens, &n_tokens);
-	if (status != 0) {
-		printf(CMD_MSG_TOO_MANY_ARGS, "link");
-		return;
-	}
-
-	/* link ls */
-	if ((n_tokens == 1) && (strcmp(tokens[0], "ls") == 0)) {
-		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);
-		}
-		return;
-	} /* link ls */
-
-	if (n_tokens < 2) {
-		printf(CMD_MSG_MISMATCH_ARGS, "link");
-		return;
-	}
-
-	if (parser_read_uint32(&link_id, tokens[0])) {
-		printf(CMD_MSG_INVALID_ARG, "linkid");
-		return;
-	}
-
-	/* link config */
-	if (strcmp(tokens[1], "config") == 0) {
-		struct in_addr ipaddr_ipv4;
-		uint32_t depth;
-
-		if (n_tokens != 4) {
-			printf(CMD_MSG_MISMATCH_ARGS, "link config");
-			return;
-		}
-
-		if (parse_ipv4_addr(tokens[2], &ipaddr_ipv4)) {
-			printf(CMD_MSG_INVALID_ARG, "ipaddr");
-			return;
-		}
-
-		if (parser_read_uint32(&depth, tokens[3])) {
-			printf(CMD_MSG_INVALID_ARG, "depth");
-			return;
-		}
-
-		status = app_link_config(app,
-			link_id,
-			rte_be_to_cpu_32(ipaddr_ipv4.s_addr),
-			depth);
-		if (status)
-			printf(CMD_MSG_FAIL, "link config");
-
-		return;
-	} /* link config */
-
-	/* link up */
-	if (strcmp(tokens[1], "up") == 0) {
-		if (n_tokens != 2) {
-			printf(CMD_MSG_MISMATCH_ARGS, "link up");
-			return;
-		}
-
-		status = app_link_up(app, link_id);
-		if (status)
-			printf(CMD_MSG_FAIL, "link up");
-
-		return;
-	} /* link up */
-
-	/* link down */
-	if (strcmp(tokens[1], "down") == 0) {
-		if (n_tokens != 2) {
-			printf(CMD_MSG_MISMATCH_ARGS, "link down");
-			return;
-		}
-
-		status = app_link_down(app, link_id);
-		if (status)
-			printf(CMD_MSG_FAIL, "link down");
-
-		return;
-	} /* link down */
-
-	printf(CMD_MSG_MISMATCH_ARGS, "link");
-}
-
-static cmdline_parse_token_string_t cmd_link_link_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_link_result, link_string, "link");
-
-static cmdline_parse_token_string_t cmd_link_multi_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_link_result, multi_string,
-	TOKEN_STRING_MULTI);
-
-static cmdline_parse_inst_t cmd_link = {
-	.f = cmd_link_parsed,
-	.data = NULL,
-	.help_str = "link config / up / down / ls",
-	.tokens = {
-		(void *) &cmd_link_link_string,
-		(void *) &cmd_link_multi_string,
-		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,
-	},
-};
-
-/*
- * run
- *
- *    run <file>
- *    run <file> [<count> [<interval>]]
-	 <count> default is 1
- *       <interval> is measured in milliseconds, default is 1 second
- */
-
-static void
-app_run_file(
-	cmdline_parse_ctx_t *ctx,
-	const char *file_name)
-{
-	struct cmdline *file_cl;
-	int fd;
-
-	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_result {
-	cmdline_fixed_string_t run_string;
-	cmdline_multi_string_t multi_string;
-};
-
-static void
-cmd_run_parsed(
-	void *parsed_result,
-	struct cmdline *cl,
-	__attribute__((unused)) void *data)
-{
-	struct cmd_run_result *params = parsed_result;
-
-	char *tokens[16];
-	uint32_t n_tokens = RTE_DIM(tokens);
-	int status;
-
-	char *file_name;
-	uint32_t count, interval, i;
-
-	status = parse_tokenize_string(params->multi_string, tokens, &n_tokens);
-	if (status) {
-		printf(CMD_MSG_TOO_MANY_ARGS, "run");
-		return;
-	}
-
-	switch (n_tokens) {
-	case 0:
-		printf(CMD_MSG_NOT_ENOUGH_ARGS, "run");
-		return;
-
-	case 1:
-		file_name = tokens[0];
-		count = 1;
-		interval = 1000;
-		break;
-
-	case 2:
-		file_name = tokens[0];
-
-		if (parser_read_uint32(&count, tokens[1]) ||
-			(count == 0)) {
-			printf(CMD_MSG_INVALID_ARG, "count");
-			return;
-		}
-
-		interval = 1000;
-		break;
-
-	case 3:
-		file_name = tokens[0];
-
-		if (parser_read_uint32(&count, tokens[1]) ||
-			(count == 0)) {
-			printf(CMD_MSG_INVALID_ARG, "count");
-			return;
-		}
-
-		if (parser_read_uint32(&interval, tokens[2]) ||
-			(interval == 0)) {
-			printf(CMD_MSG_INVALID_ARG, "interval");
-			return;
-		}
-		break;
-
-	default:
-		printf(CMD_MSG_MISMATCH_ARGS, "run");
-		return;
-	}
-
-	for (i = 0; i < count; i++) {
-		app_run_file(cl->ctx, file_name);
-		if (interval)
-			usleep(interval * 1000);
-	}
-}
-
-static cmdline_parse_token_string_t cmd_run_run_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_run_result, run_string, "run");
-
-static cmdline_parse_token_string_t cmd_run_multi_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_run_result, multi_string,
-	TOKEN_STRING_MULTI);
-
-
-static 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_multi_string,
-		NULL,
-	},
-};
-
-static cmdline_parse_ctx_t pipeline_common_cmds[] = {
-	(cmdline_parse_inst_t *) &cmd_quit,
-	(cmdline_parse_inst_t *) &cmd_run,
-	(cmdline_parse_inst_t *) &cmd_link,
-	(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,
-	NULL,
-};
-
-int
-app_pipeline_common_cmd_push(struct app_params *app)
-{
-	uint32_t n_cmds, i;
-
-	/* Check for available slots in the application commands array */
-	n_cmds = RTE_DIM(pipeline_common_cmds) - 1;
-	if (n_cmds > APP_MAX_CMDS - app->n_cmds)
-		return -ENOMEM;
-
-	/* Push pipeline commands into the application */
-	memcpy(&app->cmds[app->n_cmds],
-		pipeline_common_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;
-}
diff --git a/examples/ip_pipeline/pipeline/pipeline_common_fe.h b/examples/ip_pipeline/pipeline/pipeline_common_fe.h
deleted file mode 100644
index 7227544..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_common_fe.h
+++ /dev/null
@@ -1,231 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#ifndef __INCLUDE_PIPELINE_COMMON_FE_H__
-#define __INCLUDE_PIPELINE_COMMON_FE_H__
-
-#include <rte_common.h>
-#include <rte_cycles.h>
-#include <rte_malloc.h>
-#include <cmdline_parse.h>
-
-#include "pipeline_common_be.h"
-#include "pipeline.h"
-#include "app.h"
-
-#ifndef MSG_TIMEOUT_DEFAULT
-#define MSG_TIMEOUT_DEFAULT                      1000
-#endif
-
-static inline struct app_pipeline_data *
-app_pipeline_data(struct app_params *app, uint32_t id)
-{
-	struct app_pipeline_params *params;
-
-	APP_PARAM_FIND_BY_ID(app->pipeline_params, "PIPELINE", id, params);
-	if (params == NULL)
-		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 pipeline_type *ptype)
-{
-	struct app_pipeline_data *pipeline_data;
-
-	pipeline_data = app_pipeline_data(app, id);
-	if (pipeline_data == NULL)
-		return NULL;
-
-	if (strcmp(pipeline_data->ptype->name, ptype->name) != 0)
-		return NULL;
-
-	if (pipeline_data->enabled == 0)
-		return NULL;
-
-	return pipeline_data->fe;
-}
-
-static inline struct rte_ring *
-app_pipeline_msgq_in_get(struct app_params *app,
-	uint32_t pipeline_id)
-{
-	struct app_msgq_params *p;
-
-	APP_PARAM_FIND_BY_ID(app->msgq_params,
-		"MSGQ-REQ-PIPELINE",
-		pipeline_id,
-		p);
-	if (p == NULL)
-		return NULL;
-
-	return app->msgq[p - app->msgq_params];
-}
-
-static inline struct rte_ring *
-app_pipeline_msgq_out_get(struct app_params *app,
-	uint32_t pipeline_id)
-{
-	struct app_msgq_params *p;
-
-	APP_PARAM_FIND_BY_ID(app->msgq_params,
-		"MSGQ-RSP-PIPELINE",
-		pipeline_id,
-		p);
-	if (p == NULL)
-		return NULL;
-
-	return app->msgq[p - app->msgq_params];
-}
-
-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;
-}
-
-struct app_link_params *
-app_pipeline_track_pktq_out_to_link(struct app_params *app,
-	uint32_t pipeline_id,
-	uint32_t pktq_out_id);
-
-int
-app_pipeline_track_default(struct pipeline_params *params,
-	uint32_t port_in,
-	uint32_t *port_out);
-
-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_set_op(struct app_params *app,
-	uint32_t link_id,
-	uint32_t pipeline_id,
-	app_link_op op,
-	void *arg);
-
-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);
-
-int
-app_pipeline_common_cmd_push(struct app_params *app);
-
-#define CMD_MSG_OUT_OF_MEMORY	"Not enough memory\n"
-#define CMD_MSG_NOT_ENOUGH_ARGS	"Not enough arguments for command \"%s\"\n"
-#define CMD_MSG_TOO_MANY_ARGS	"Too many arguments for command \"%s\"\n"
-#define CMD_MSG_MISMATCH_ARGS	"Incorrect set of arguments for command \"%s\"\n"
-#define CMD_MSG_INVALID_ARG	"Invalid value for argument \"%s\"\n"
-#define CMD_MSG_ARG_NOT_FOUND	"Syntax error: \"%s\" not found\n"
-#define CMD_MSG_FILE_ERR	"Error in file \"%s\" at line %u\n"
-#define CMD_MSG_FAIL		"Command \"%s\" failed\n"
-
-#endif
diff --git a/examples/ip_pipeline/pipeline/pipeline_master.c b/examples/ip_pipeline/pipeline/pipeline_master.c
deleted file mode 100644
index b0d730a..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_master.c
+++ /dev/null
@@ -1,20 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#include "pipeline_master.h"
-#include "pipeline_master_be.h"
-
-static struct pipeline_fe_ops pipeline_master_fe_ops = {
-	.f_init = NULL,
-	.f_post_init = NULL,
-	.f_free = NULL,
-	.f_track = NULL,
-	.cmds = NULL,
-};
-
-struct pipeline_type pipeline_master = {
-	.name = "MASTER",
-	.be_ops = &pipeline_master_be_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
deleted file mode 100644
index a5183e3..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_master.h
+++ /dev/null
@@ -1,12 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#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_be.c b/examples/ip_pipeline/pipeline/pipeline_master_be.c
deleted file mode 100644
index c72038e..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_master_be.c
+++ /dev/null
@@ -1,141 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#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_be.h"
-
-struct pipeline_master {
-	struct app_params *app;
-	struct cmdline *cl;
-	int post_init_done;
-	int script_file_done;
-} __rte_cache_aligned;
-
-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 (app == NULL)
-		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;
-
-	/* Initialization */
-	p->app = app;
-
-	p->cl = cmdline_stdin_new(app->cmds, "pipeline> ");
-	if (p->cl == NULL) {
-		rte_free(p);
-		return NULL;
-	}
-
-	p->post_init_done = 0;
-	p->script_file_done = 0;
-	if (app->script_file == NULL)
-		p->script_file_done = 1;
-
-	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;
-	struct app_params *app = p->app;
-	int status;
-#ifdef RTE_LIBRTE_KNI
-	uint32_t i;
-#endif /* RTE_LIBRTE_KNI */
-
-	/* Application post-init phase */
-	if (p->post_init_done == 0) {
-		app_post_init(app);
-
-		p->post_init_done = 1;
-	}
-
-	/* Run startup script file */
-	if (p->script_file_done == 0) {
-		struct app_params *app = p->app;
-		int fd = open(app->script_file, O_RDONLY);
-
-		if (fd < 0)
-			printf("Cannot open CLI script file \"%s\"\n",
-				app->script_file);
-		else {
-			struct cmdline *file_cl;
-
-			printf("Running CLI script file \"%s\" ...\n",
-				app->script_file);
-			file_cl = cmdline_new(p->cl->ctx, "", fd, 1);
-			cmdline_interact(file_cl);
-			close(fd);
-		}
-
-		p->script_file_done = 1;
-	}
-
-	/* Command Line Interface (CLI) */
-	status = cmdline_poll(p->cl);
-	if (status < 0)
-		rte_panic("CLI poll error (%" PRId32 ")\n", status);
-	else if (status == RDLINE_EXITED) {
-		cmdline_stdin_exit(p->cl);
-		rte_exit(0, "Bye!\n");
-	}
-
-#ifdef RTE_LIBRTE_KNI
-	/* Handle KNI requests from Linux kernel */
-	for (i = 0; i < app->n_pktq_kni; i++)
-		rte_kni_handle_request(app->kni[i]);
-#endif /* RTE_LIBRTE_KNI */
-
-	return 0;
-}
-
-static int
-pipeline_timer(__rte_unused void *pipeline)
-{
-	return 0;
-}
-
-struct pipeline_be_ops pipeline_master_be_ops = {
-		.f_init = pipeline_init,
-		.f_free = pipeline_free,
-		.f_run = pipeline_run,
-		.f_timer = pipeline_timer,
-};
diff --git a/examples/ip_pipeline/pipeline/pipeline_master_be.h b/examples/ip_pipeline/pipeline/pipeline_master_be.h
deleted file mode 100644
index 847c564..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_master_be.h
+++ /dev/null
@@ -1,12 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#ifndef __INCLUDE_PIPELINE_MASTER_BE_H__
-#define __INCLUDE_PIPELINE_MASTER_BE_H__
-
-#include "pipeline_common_be.h"
-
-extern struct pipeline_be_ops pipeline_master_be_ops;
-
-#endif
diff --git a/examples/ip_pipeline/thread.c b/examples/ip_pipeline/thread.c
index 9013afd..a36bf92 100644
--- a/examples/ip_pipeline/thread.c
+++ b/examples/ip_pipeline/thread.c
@@ -6,47 +6,9 @@
 #include <rte_cycles.h>
 #include <rte_pipeline.h>
 
-#include "pipeline_common_be.h"
 #include "app.h"
 #include "thread.h"
 
-#if APP_THREAD_HEADROOM_STATS_COLLECT
-
-#define PIPELINE_RUN_REGULAR(thread, pipeline)		\
-do {							\
-	uint64_t t0 = rte_rdtsc_precise();		\
-	int n_pkts = rte_pipeline_run(pipeline->p);	\
-							\
-	if (n_pkts == 0) {				\
-		uint64_t t1 = rte_rdtsc_precise();	\
-							\
-		thread->headroom_cycles += t1 - t0;	\
-	}						\
-} while (0)
-
-
-#define PIPELINE_RUN_CUSTOM(thread, data)		\
-do {							\
-	uint64_t t0 = rte_rdtsc_precise();		\
-	int n_pkts = data->f_run(data->be);		\
-							\
-	if (n_pkts == 0) {				\
-		uint64_t t1 = rte_rdtsc_precise();	\
-							\
-		thread->headroom_cycles += t1 - t0;	\
-	}						\
-} while (0)
-
-#else
-
-#define PIPELINE_RUN_REGULAR(thread, pipeline)		\
-	rte_pipeline_run(pipeline->p)
-
-#define PIPELINE_RUN_CUSTOM(thread, data)		\
-	data->f_run(data->be)
-
-#endif
-
 static inline void *
 thread_msg_recv(struct rte_ring *r)
 {
@@ -214,21 +176,6 @@ app_thread(void *arg)
 		uint32_t n_regular = RTE_MIN(t->n_regular, RTE_DIM(t->regular));
 		uint32_t n_custom = RTE_MIN(t->n_custom, RTE_DIM(t->custom));
 
-		/* Run regular pipelines */
-		for (j = 0; j < n_regular; j++) {
-			struct app_thread_pipeline_data *data = &t->regular[j];
-			struct pipeline *p = data->be;
-
-			PIPELINE_RUN_REGULAR(t, p);
-		}
-
-		/* Run custom pipelines */
-		for (j = 0; j < n_custom; j++) {
-			struct app_thread_pipeline_data *data = &t->custom[j];
-
-			PIPELINE_RUN_CUSTOM(t, data);
-		}
-
 		/* Timer */
 		if ((i & 0xF) == 0) {
 			uint64_t time = rte_get_tsc_cycles();
diff --git a/examples/ip_pipeline/thread_fe.c b/examples/ip_pipeline/thread_fe.c
deleted file mode 100644
index 4590c2b..0000000
--- a/examples/ip_pipeline/thread_fe.c
+++ /dev/null
@@ -1,457 +0,0 @@
-#include <rte_common.h>
-#include <rte_ring.h>
-#include <rte_malloc.h>
-#include <cmdline_rdline.h>
-#include <cmdline_parse.h>
-#include <cmdline_parse_num.h>
-#include <cmdline_parse_string.h>
-
-#include "thread.h"
-#include "thread_fe.h"
-#include "pipeline.h"
-#include "pipeline_common_fe.h"
-#include "app.h"
-
-static inline void *
-thread_msg_send_recv(struct app_params *app,
-	uint32_t socket_id, uint32_t core_id, uint32_t ht_id,
-	void *msg,
-	uint32_t timeout_ms)
-{
-	struct rte_ring *r_req = app_thread_msgq_in_get(app,
-		socket_id, core_id, ht_id);
-	struct rte_ring *r_rsp = app_thread_msgq_out_get(app,
-		socket_id, core_id, ht_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_enable(struct app_params *app,
-		uint32_t socket_id,
-		uint32_t core_id,
-		uint32_t hyper_th_id,
-		uint32_t pipeline_id)
-{
-	struct thread_pipeline_enable_msg_req *req;
-	struct thread_pipeline_enable_msg_rsp *rsp;
-	int thread_id;
-	struct app_pipeline_data *p;
-	struct app_pipeline_params *p_params;
-	struct pipeline_type *p_type;
-	int status;
-
-	if (app == NULL)
-		return -1;
-
-	thread_id = cpu_core_map_get_lcore_id(app->core_map,
-			socket_id,
-			core_id,
-			hyper_th_id);
-
-	if ((thread_id < 0) || !app_core_is_enabled(app, thread_id))
-		return -1;
-
-	if (app_pipeline_data(app, pipeline_id) == NULL)
-		return -1;
-
-	p = &app->pipeline_data[pipeline_id];
-	p_params = &app->pipeline_params[pipeline_id];
-	p_type = app_pipeline_type_find(app, p_params->type);
-
-	if (p_type == NULL)
-		return -1;
-
-	if (p->enabled == 1)
-		return -1;
-
-	req = app_msg_alloc(app);
-	if (req == NULL)
-		return -1;
-
-	req->type = THREAD_MSG_REQ_PIPELINE_ENABLE;
-	req->pipeline_id = pipeline_id;
-	req->be = p->be;
-	req->f_run = p_type->be_ops->f_run;
-	req->f_timer = p_type->be_ops->f_timer;
-	req->timer_period = p->timer_period;
-
-	rsp = thread_msg_send_recv(app,
-		socket_id, core_id, hyper_th_id, req, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	status = rsp->status;
-	app_msg_free(app, rsp);
-
-	if (status != 0)
-		return -1;
-
-	p->enabled = 1;
-	return 0;
-}
-
-int
-app_pipeline_disable(struct app_params *app,
-		uint32_t socket_id,
-		uint32_t core_id,
-		uint32_t hyper_th_id,
-		uint32_t pipeline_id)
-{
-	struct thread_pipeline_disable_msg_req *req;
-	struct thread_pipeline_disable_msg_rsp *rsp;
-	int thread_id;
-	struct app_pipeline_data *p;
-	int status;
-
-	if (app == NULL)
-		return -1;
-
-	thread_id = cpu_core_map_get_lcore_id(app->core_map,
-			socket_id,
-			core_id,
-			hyper_th_id);
-
-	if ((thread_id < 0) || !app_core_is_enabled(app, thread_id))
-		return -1;
-
-	if (app_pipeline_data(app, pipeline_id) == NULL)
-		return -1;
-
-	p = &app->pipeline_data[pipeline_id];
-
-	if (p->enabled == 0)
-		return -1;
-
-	req = app_msg_alloc(app);
-	if (req == NULL)
-		return -1;
-
-	req->type = THREAD_MSG_REQ_PIPELINE_DISABLE;
-	req->pipeline_id = pipeline_id;
-
-	rsp = thread_msg_send_recv(app,
-		socket_id, core_id, hyper_th_id, req, MSG_TIMEOUT_DEFAULT);
-
-	if (rsp == NULL)
-		return -1;
-
-	status = rsp->status;
-	app_msg_free(app, rsp);
-
-	if (status != 0)
-		return -1;
-
-	p->enabled = 0;
-	return 0;
-}
-
-int
-app_thread_headroom(struct app_params *app,
-		uint32_t socket_id,
-		uint32_t core_id,
-		uint32_t hyper_th_id)
-{
-	struct thread_headroom_read_msg_req *req;
-	struct thread_headroom_read_msg_rsp *rsp;
-	int thread_id;
-	int status;
-
-	if (app == NULL)
-		return -1;
-
-	thread_id = cpu_core_map_get_lcore_id(app->core_map,
-			socket_id,
-			core_id,
-			hyper_th_id);
-
-	if ((thread_id < 0) || !app_core_is_enabled(app, thread_id))
-		return -1;
-
-	req = app_msg_alloc(app);
-	if (req == NULL)
-		return -1;
-
-	req->type = THREAD_MSG_REQ_HEADROOM_READ;
-
-	rsp = thread_msg_send_recv(app,
-		socket_id, core_id, hyper_th_id, req, MSG_TIMEOUT_DEFAULT);
-
-	if (rsp == NULL)
-		return -1;
-
-	status = rsp->status;
-
-	if (status != 0)
-		return -1;
-
-	printf("%.3f%%\n", rsp->headroom_ratio * 100);
-
-
-	app_msg_free(app, rsp);
-
-	return 0;
-}
-
-/*
- * pipeline enable
- */
-
-struct cmd_pipeline_enable_result {
-	cmdline_fixed_string_t t_string;
-	cmdline_fixed_string_t t_id_string;
-	cmdline_fixed_string_t pipeline_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t enable_string;
-};
-
-static void
-cmd_pipeline_enable_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	 void *data)
-{
-	struct cmd_pipeline_enable_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
-	uint32_t core_id, socket_id, hyper_th_id;
-
-	if (parse_pipeline_core(&socket_id,
-			&core_id,
-			&hyper_th_id,
-			params->t_id_string) != 0) {
-		printf("Command failed\n");
-		return;
-	}
-
-	status = app_pipeline_enable(app,
-			socket_id,
-			core_id,
-			hyper_th_id,
-			params->pipeline_id);
-
-	if (status != 0)
-		printf("Command failed\n");
-}
-
-static cmdline_parse_token_string_t cmd_pipeline_enable_t_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_pipeline_enable_result, t_string, "t");
-
-static cmdline_parse_token_string_t cmd_pipeline_enable_t_id_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_pipeline_enable_result, t_id_string,
-		NULL);
-
-static cmdline_parse_token_string_t cmd_pipeline_enable_pipeline_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_pipeline_enable_result, pipeline_string,
-		"pipeline");
-
-static cmdline_parse_token_num_t cmd_pipeline_enable_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_pipeline_enable_result, pipeline_id,
-		UINT32);
-
-static cmdline_parse_token_string_t cmd_pipeline_enable_enable_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_pipeline_enable_result, enable_string,
-		"enable");
-
-static cmdline_parse_inst_t cmd_pipeline_enable = {
-	.f = cmd_pipeline_enable_parsed,
-	.data = NULL,
-	.help_str = "Enable pipeline on specified core",
-	.tokens = {
-		(void *)&cmd_pipeline_enable_t_string,
-		(void *)&cmd_pipeline_enable_t_id_string,
-		(void *)&cmd_pipeline_enable_pipeline_string,
-		(void *)&cmd_pipeline_enable_pipeline_id,
-		(void *)&cmd_pipeline_enable_enable_string,
-		NULL,
-	},
-};
-
-/*
- * pipeline disable
- */
-
-struct cmd_pipeline_disable_result {
-	cmdline_fixed_string_t t_string;
-	cmdline_fixed_string_t t_id_string;
-	cmdline_fixed_string_t pipeline_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t disable_string;
-};
-
-static void
-cmd_pipeline_disable_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	 void *data)
-{
-	struct cmd_pipeline_disable_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
-	uint32_t core_id, socket_id, hyper_th_id;
-
-	if (parse_pipeline_core(&socket_id,
-			&core_id,
-			&hyper_th_id,
-			params->t_id_string) != 0) {
-		printf("Command failed\n");
-		return;
-	}
-
-	status = app_pipeline_disable(app,
-			socket_id,
-			core_id,
-			hyper_th_id,
-			params->pipeline_id);
-
-	if (status != 0)
-		printf("Command failed\n");
-}
-
-static cmdline_parse_token_string_t cmd_pipeline_disable_t_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_pipeline_disable_result, t_string, "t");
-
-static cmdline_parse_token_string_t cmd_pipeline_disable_t_id_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_pipeline_disable_result, t_id_string,
-		NULL);
-
-static cmdline_parse_token_string_t cmd_pipeline_disable_pipeline_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_pipeline_disable_result,
-		pipeline_string, "pipeline");
-
-static cmdline_parse_token_num_t cmd_pipeline_disable_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_pipeline_disable_result, pipeline_id,
-		UINT32);
-
-static cmdline_parse_token_string_t cmd_pipeline_disable_disable_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_pipeline_disable_result, disable_string,
-		"disable");
-
-static cmdline_parse_inst_t cmd_pipeline_disable = {
-	.f = cmd_pipeline_disable_parsed,
-	.data = NULL,
-	.help_str = "Disable pipeline on specified core",
-	.tokens = {
-		(void *)&cmd_pipeline_disable_t_string,
-		(void *)&cmd_pipeline_disable_t_id_string,
-		(void *)&cmd_pipeline_disable_pipeline_string,
-		(void *)&cmd_pipeline_disable_pipeline_id,
-		(void *)&cmd_pipeline_disable_disable_string,
-		NULL,
-	},
-};
-
-
-/*
- * thread headroom
- */
-
-struct cmd_thread_headroom_result {
-	cmdline_fixed_string_t t_string;
-	cmdline_fixed_string_t t_id_string;
-	cmdline_fixed_string_t headroom_string;
-};
-
-static void
-cmd_thread_headroom_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	 void *data)
-{
-	struct cmd_thread_headroom_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
-	uint32_t core_id, socket_id, hyper_th_id;
-
-	if (parse_pipeline_core(&socket_id,
-			&core_id,
-			&hyper_th_id,
-			params->t_id_string) != 0) {
-		printf("Command failed\n");
-		return;
-	}
-
-	status = app_thread_headroom(app,
-			socket_id,
-			core_id,
-			hyper_th_id);
-
-	if (status != 0)
-		printf("Command failed\n");
-}
-
-static cmdline_parse_token_string_t cmd_thread_headroom_t_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_thread_headroom_result,
-	t_string, "t");
-
-static cmdline_parse_token_string_t cmd_thread_headroom_t_id_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_thread_headroom_result,
-	t_id_string, NULL);
-
-static cmdline_parse_token_string_t cmd_thread_headroom_headroom_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_thread_headroom_result,
-		headroom_string, "headroom");
-
-static cmdline_parse_inst_t cmd_thread_headroom = {
-	.f = cmd_thread_headroom_parsed,
-	.data = NULL,
-	.help_str = "Display thread headroom",
-	.tokens = {
-		(void *)&cmd_thread_headroom_t_string,
-		(void *)&cmd_thread_headroom_t_id_string,
-		(void *)&cmd_thread_headroom_headroom_string,
-		NULL,
-	},
-};
-
-
-static cmdline_parse_ctx_t thread_cmds[] = {
-	(cmdline_parse_inst_t *) &cmd_pipeline_enable,
-	(cmdline_parse_inst_t *) &cmd_pipeline_disable,
-	(cmdline_parse_inst_t *) &cmd_thread_headroom,
-	NULL,
-};
-
-int
-app_pipeline_thread_cmd_push(struct app_params *app)
-{
-	uint32_t n_cmds, i;
-
-	/* Check for available slots in the application commands array */
-	n_cmds = RTE_DIM(thread_cmds) - 1;
-	if (n_cmds > APP_MAX_CMDS - app->n_cmds)
-		return -ENOMEM;
-
-	/* Push thread commands into the application */
-	memcpy(&app->cmds[app->n_cmds], thread_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;
-}
diff --git a/examples/ip_pipeline/thread_fe.h b/examples/ip_pipeline/thread_fe.h
deleted file mode 100644
index 056a5e8..0000000
--- a/examples/ip_pipeline/thread_fe.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#ifndef THREAD_FE_H_
-#define THREAD_FE_H_
-
-static inline struct rte_ring *
-app_thread_msgq_in_get(struct app_params *app,
-		uint32_t socket_id, uint32_t core_id, uint32_t ht_id)
-{
-	char msgq_name[32];
-	ssize_t param_idx;
-
-	snprintf(msgq_name, sizeof(msgq_name),
-		"MSGQ-REQ-CORE-s%" PRIu32 "c%" PRIu32 "%s",
-		socket_id,
-		core_id,
-		(ht_id) ? "h" : "");
-	param_idx = APP_PARAM_FIND(app->msgq_params, msgq_name);
-
-	if (param_idx < 0)
-		return NULL;
-
-	return app->msgq[param_idx];
-}
-
-static inline struct rte_ring *
-app_thread_msgq_out_get(struct app_params *app,
-		uint32_t socket_id, uint32_t core_id, uint32_t ht_id)
-{
-	char msgq_name[32];
-	ssize_t param_idx;
-
-	snprintf(msgq_name, sizeof(msgq_name),
-		"MSGQ-RSP-CORE-s%" PRIu32 "c%" PRIu32 "%s",
-		socket_id,
-		core_id,
-		(ht_id) ? "h" : "");
-	param_idx = APP_PARAM_FIND(app->msgq_params, msgq_name);
-
-	if (param_idx < 0)
-		return NULL;
-
-	return app->msgq[param_idx];
-
-}
-
-int
-app_pipeline_thread_cmd_push(struct app_params *app);
-
-int
-app_pipeline_enable(struct app_params *app,
-		uint32_t core_id,
-		uint32_t socket_id,
-		uint32_t hyper_th_id,
-		uint32_t pipeline_id);
-
-int
-app_pipeline_disable(struct app_params *app,
-		uint32_t core_id,
-		uint32_t socket_id,
-		uint32_t hyper_th_id,
-		uint32_t pipeline_id);
-
-int
-app_thread_headroom(struct app_params *app,
-		uint32_t core_id,
-		uint32_t socket_id,
-		uint32_t hyper_th_id);
-
-#endif /* THREAD_FE_H_ */
-- 
2.9.3

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

* [dpdk-dev] [PATCH v2 16/44] ip_pipeline: remove config
  2018-03-12 17:25   ` [dpdk-dev] [PATCH v2 00/44] ip_pipeline: refactoring Jasvinder Singh
                       ` (14 preceding siblings ...)
  2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 15/44] ip_pipeline: remove master pipeline Jasvinder Singh
@ 2018-03-12 17:25     ` Jasvinder Singh
  2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 17/44] ip_pipeline: rework and improvements Jasvinder Singh
                       ` (27 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-12 17:25 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Remove application configuration and script files.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/config/action.cfg             |  68 --
 examples/ip_pipeline/config/action.sh              | 119 ---
 examples/ip_pipeline/config/action.txt             |   8 -
 examples/ip_pipeline/config/diagram-generator.py   | 317 -------
 .../ip_pipeline/config/edge_router_downstream.cfg  |  97 ---
 .../ip_pipeline/config/edge_router_downstream.sh   |  13 -
 .../ip_pipeline/config/edge_router_upstream.cfg    | 124 ---
 .../ip_pipeline/config/edge_router_upstream.sh     |  33 -
 examples/ip_pipeline/config/firewall.cfg           |  68 --
 examples/ip_pipeline/config/firewall.sh            |  13 -
 examples/ip_pipeline/config/firewall.txt           |   9 -
 examples/ip_pipeline/config/flow.cfg               |  72 --
 examples/ip_pipeline/config/flow.sh                |  25 -
 examples/ip_pipeline/config/flow.txt               |  17 -
 examples/ip_pipeline/config/ip_pipeline.cfg        |   9 -
 examples/ip_pipeline/config/ip_pipeline.sh         |   5 -
 examples/ip_pipeline/config/kni.cfg                |  67 --
 examples/ip_pipeline/config/l2fwd.cfg              |  58 --
 examples/ip_pipeline/config/l3fwd.cfg              |  68 --
 examples/ip_pipeline/config/l3fwd.sh               |  33 -
 examples/ip_pipeline/config/l3fwd_arp.cfg          |  70 --
 examples/ip_pipeline/config/l3fwd_arp.sh           |  43 -
 examples/ip_pipeline/config/network_layers.cfg     | 227 ------
 examples/ip_pipeline/config/network_layers.sh      |  79 --
 .../ip_pipeline/config/pipeline-to-core-mapping.py | 906 ---------------------
 examples/ip_pipeline/config/tap.cfg                |  64 --
 examples/ip_pipeline/config/tm_profile.cfg         | 105 ---
 27 files changed, 2717 deletions(-)
 delete mode 100644 examples/ip_pipeline/config/action.cfg
 delete mode 100644 examples/ip_pipeline/config/action.sh
 delete mode 100644 examples/ip_pipeline/config/action.txt
 delete mode 100755 examples/ip_pipeline/config/diagram-generator.py
 delete mode 100644 examples/ip_pipeline/config/edge_router_downstream.cfg
 delete mode 100644 examples/ip_pipeline/config/edge_router_downstream.sh
 delete mode 100644 examples/ip_pipeline/config/edge_router_upstream.cfg
 delete mode 100644 examples/ip_pipeline/config/edge_router_upstream.sh
 delete mode 100644 examples/ip_pipeline/config/firewall.cfg
 delete mode 100644 examples/ip_pipeline/config/firewall.sh
 delete mode 100644 examples/ip_pipeline/config/firewall.txt
 delete mode 100644 examples/ip_pipeline/config/flow.cfg
 delete mode 100644 examples/ip_pipeline/config/flow.sh
 delete mode 100644 examples/ip_pipeline/config/flow.txt
 delete mode 100644 examples/ip_pipeline/config/ip_pipeline.cfg
 delete mode 100644 examples/ip_pipeline/config/ip_pipeline.sh
 delete mode 100644 examples/ip_pipeline/config/kni.cfg
 delete mode 100644 examples/ip_pipeline/config/l2fwd.cfg
 delete mode 100644 examples/ip_pipeline/config/l3fwd.cfg
 delete mode 100644 examples/ip_pipeline/config/l3fwd.sh
 delete mode 100644 examples/ip_pipeline/config/l3fwd_arp.cfg
 delete mode 100644 examples/ip_pipeline/config/l3fwd_arp.sh
 delete mode 100644 examples/ip_pipeline/config/network_layers.cfg
 delete mode 100644 examples/ip_pipeline/config/network_layers.sh
 delete mode 100755 examples/ip_pipeline/config/pipeline-to-core-mapping.py
 delete mode 100644 examples/ip_pipeline/config/tap.cfg
 delete mode 100644 examples/ip_pipeline/config/tm_profile.cfg

diff --git a/examples/ip_pipeline/config/action.cfg b/examples/ip_pipeline/config/action.cfg
deleted file mode 100644
index 994ae94..0000000
--- a/examples/ip_pipeline/config/action.cfg
+++ /dev/null
@@ -1,68 +0,0 @@
-;   BSD LICENSE
-;
-;   Copyright(c) 2016 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.
-
-;             ________________
-; RXQ0.0 --->|                |---> TXQ0.0
-;            |                |
-; RXQ1.0 --->|                |---> TXQ1.0
-;            |      Flow      |
-; RXQ2.0 --->|     Actions    |---> TXQ2.0
-;            |                |
-; RXQ3.0 --->|                |---> TXQ3.0
-;            |________________|
-;
-;
-; Input packet: Ethernet/IPv4
-;
-; Packet buffer layout:
-; #	Field Name		Offset (Bytes)	Size (Bytes)
-; 0	Mbuf			0 		128
-; 1	Headroom		128 		128
-; 2	Ethernet header		256 		14
-; 3	IPv4 header		270 		20
-
-[EAL]
-log_level = 0
-
-[PIPELINE0]
-type = MASTER
-core = 0
-
-[PIPELINE1]
-type = FLOW_ACTIONS
-core = 1
-pktq_in = RXQ0.0 RXQ1.0 RXQ2.0 RXQ3.0
-pktq_out = TXQ0.0 TXQ1.0 TXQ2.0 TXQ3.0
-n_flows = 65536
-n_meters_per_flow = 4
-flow_id_offset = 286; ipdaddr
-ip_hdr_offset = 270
-color_offset = 128
diff --git a/examples/ip_pipeline/config/action.sh b/examples/ip_pipeline/config/action.sh
deleted file mode 100644
index 2986ae6..0000000
--- a/examples/ip_pipeline/config/action.sh
+++ /dev/null
@@ -1,119 +0,0 @@
-#
-# run ./config/action.sh
-#
-
-p 1 action flow 0 meter 0 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 0 policer 0 g G y Y r R
-p 1 action flow 0 meter 1 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 0 policer 1 g G y Y r R
-p 1 action flow 0 meter 2 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 0 policer 2 g G y Y r R
-p 1 action flow 0 meter 3 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 0 policer 3 g G y Y r R
-p 1 action flow 0 port 0
-
-p 1 action flow 1 meter 0 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 1 policer 0 g G y Y r R
-p 1 action flow 1 meter 1 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 1 policer 1 g G y Y r R
-p 1 action flow 1 meter 2 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 1 policer 2 g G y Y r R
-p 1 action flow 1 meter 3 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 1 policer 3 g G y Y r R
-p 1 action flow 1 port 1
-
-p 1 action flow 2 meter 0 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 2 policer 0 g G y Y r R
-p 1 action flow 2 meter 1 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 2 policer 1 g G y Y r R
-p 1 action flow 2 meter 2 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 2 policer 2 g G y Y r R
-p 1 action flow 2 meter 3 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 2 policer 3 g G y Y r R
-p 1 action flow 2 port 2
-
-p 1 action flow 3 meter 0 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 3 policer 0 g G y Y r R
-p 1 action flow 3 meter 1 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 3 policer 1 g G y Y r R
-p 1 action flow 3 meter 2 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 3 policer 2 g G y Y r R
-p 1 action flow 3 meter 3 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 3 policer 3 g G y Y r R
-p 1 action flow 3 port 3
-
-#p 1 action flow bulk ./config/action.txt
-
-#p 1 action flow ls
-
-p 1 action flow 0 stats
-p 1 action flow 1 stats
-p 1 action flow 2 stats
-p 1 action flow 3 stats
-
-p 1 action dscp 0 class 0 color G
-p 1 action dscp 1 class 1 color G
-p 1 action dscp 2 class 2 color G
-p 1 action dscp 3 class 3 color G
-p 1 action dscp 4 class 0 color G
-p 1 action dscp 5 class 1 color G
-p 1 action dscp 6 class 2 color G
-p 1 action dscp 7 class 3 color G
-p 1 action dscp 8 class 0 color G
-p 1 action dscp 9 class 1 color G
-p 1 action dscp 10 class 2 color G
-p 1 action dscp 11 class 3 color G
-p 1 action dscp 12 class 0 color G
-p 1 action dscp 13 class 1 color G
-p 1 action dscp 14 class 2 color G
-p 1 action dscp 15 class 3 color G
-p 1 action dscp 16 class 0 color G
-p 1 action dscp 17 class 1 color G
-p 1 action dscp 18 class 2 color G
-p 1 action dscp 19 class 3 color G
-p 1 action dscp 20 class 0 color G
-p 1 action dscp 21 class 1 color G
-p 1 action dscp 22 class 2 color G
-p 1 action dscp 23 class 3 color G
-p 1 action dscp 24 class 0 color G
-p 1 action dscp 25 class 1 color G
-p 1 action dscp 26 class 2 color G
-p 1 action dscp 27 class 3 color G
-p 1 action dscp 27 class 0 color G
-p 1 action dscp 29 class 1 color G
-p 1 action dscp 30 class 2 color G
-p 1 action dscp 31 class 3 color G
-p 1 action dscp 32 class 0 color G
-p 1 action dscp 33 class 1 color G
-p 1 action dscp 34 class 2 color G
-p 1 action dscp 35 class 3 color G
-p 1 action dscp 36 class 0 color G
-p 1 action dscp 37 class 1 color G
-p 1 action dscp 38 class 2 color G
-p 1 action dscp 39 class 3 color G
-p 1 action dscp 40 class 0 color G
-p 1 action dscp 41 class 1 color G
-p 1 action dscp 42 class 2 color G
-p 1 action dscp 43 class 3 color G
-p 1 action dscp 44 class 0 color G
-p 1 action dscp 45 class 1 color G
-p 1 action dscp 46 class 2 color G
-p 1 action dscp 47 class 3 color G
-p 1 action dscp 48 class 0 color G
-p 1 action dscp 49 class 1 color G
-p 1 action dscp 50 class 2 color G
-p 1 action dscp 51 class 3 color G
-p 1 action dscp 52 class 0 color G
-p 1 action dscp 53 class 1 color G
-p 1 action dscp 54 class 2 color G
-p 1 action dscp 55 class 3 color G
-p 1 action dscp 56 class 0 color G
-p 1 action dscp 57 class 1 color G
-p 1 action dscp 58 class 2 color G
-p 1 action dscp 59 class 3 color G
-p 1 action dscp 60 class 0 color G
-p 1 action dscp 61 class 1 color G
-p 1 action dscp 62 class 2 color G
-p 1 action dscp 63 class 3 color G
-
-p 1 action dscp ls
diff --git a/examples/ip_pipeline/config/action.txt b/examples/ip_pipeline/config/action.txt
deleted file mode 100644
index f14207b..0000000
--- a/examples/ip_pipeline/config/action.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-# p <pipelineid> action flow bulk ./config/action.txt
-#
-
-flow 0 meter 0 trtcm 1250000000 1250000000 1000000 1000000 policer 0 g G y Y r R meter 1 trtcm 1250000000 1250000000 1000000 1000000 policer 1 g G y Y r R meter 2 trtcm 1250000000 1250000000 1000000 1000000 policer 2 g G y Y r R meter 3 trtcm 1250000000 1250000000 1000000 1000000 policer 3 g G y Y r R port 0
-flow 1 meter 0 trtcm 1250000000 1250000000 1000000 1000000 policer 0 g G y Y r R meter 1 trtcm 1250000000 1250000000 1000000 1000000 policer 1 g G y Y r R meter 2 trtcm 1250000000 1250000000 1000000 1000000 policer 2 g G y Y r R meter 3 trtcm 1250000000 1250000000 1000000 1000000 policer 3 g G y Y r R port 1
-flow 2 meter 0 trtcm 1250000000 1250000000 1000000 1000000 policer 0 g G y Y r R meter 1 trtcm 1250000000 1250000000 1000000 1000000 policer 1 g G y Y r R meter 2 trtcm 1250000000 1250000000 1000000 1000000 policer 2 g G y Y r R meter 3 trtcm 1250000000 1250000000 1000000 1000000 policer 3 g G y Y r R port 2
-flow 3 meter 0 trtcm 1250000000 1250000000 1000000 1000000 policer 0 g G y Y r R meter 1 trtcm 1250000000 1250000000 1000000 1000000 policer 1 g G y Y r R meter 2 trtcm 1250000000 1250000000 1000000 1000000 policer 2 g G y Y r R meter 3 trtcm 1250000000 1250000000 1000000 1000000 policer 3 g G y Y r R port 3
diff --git a/examples/ip_pipeline/config/diagram-generator.py b/examples/ip_pipeline/config/diagram-generator.py
deleted file mode 100755
index d9efc75..0000000
--- a/examples/ip_pipeline/config/diagram-generator.py
+++ /dev/null
@@ -1,317 +0,0 @@
-#!/usr/bin/env python
-# SPDX-License-Identifier: BSD-3-Clause
-# Copyright(c) 2016 Intel Corporation
-
-#
-# This script creates a visual representation for a configuration file used by
-# the DPDK ip_pipeline application.
-#
-# The input configuration file is translated to an output file in DOT syntax,
-# which is then used to create the image file using graphviz
-# (www.graphviz.org).
-#
-
-from __future__ import print_function
-import argparse
-import re
-import os
-
-#
-# Command to generate the image file
-#
-DOT_COMMAND = 'dot -Gsize=20,30 -Tpng %s > %s'
-
-#
-# Layout of generated DOT file
-#
-DOT_INTRO = \
-    '#\n# Command to generate image file:\n# \t%s\n#\n\n'
-DOT_GRAPH_BEGIN = \
-    'digraph g {\n  graph [ splines = true rankdir = "LR" ]\n'
-DOT_NODE_LINK_RX = \
-    '  "%s RX" [ shape = box style = filled fillcolor = yellowgreen ]\n'
-DOT_NODE_LINK_TX = \
-    '  "%s TX" [ shape = box style = filled fillcolor = yellowgreen ]\n'
-DOT_NODE_KNI_RX = \
-    '  "%s RX" [ shape = box style = filled fillcolor = orange ]\n'
-DOT_NODE_KNI_TX = \
-    '  "%s TX" [ shape = box style = filled fillcolor = orange ]\n'
-DOT_NODE_TAP_RX = \
-    '  "%s RX" [ shape = box style = filled fillcolor = gold ]\n'
-DOT_NODE_TAP_TX = \
-    '  "%s TX" [ shape = box style = filled fillcolor = gold ]\n'
-DOT_NODE_SOURCE = \
-    '  "%s" [ shape = box style = filled fillcolor = darkgreen ]\n'
-DOT_NODE_SINK = \
-    '  "%s" [ shape = box style = filled fillcolor = peachpuff ]\n'
-DOT_NODE_PIPELINE = \
-    '  "%s" [ shape = box style = filled fillcolor = royalblue ]\n'
-DOT_EDGE_PKTQ = \
-    '  "%s" -> "%s" [ label = "%s" color = gray ]\n'
-DOT_GRAPH_END = \
-    '}\n'
-
-# Relationships between the graph nodes and the graph edges:
-#
-# Edge ID | Edge Label | Writer Node | Reader Node   | Dependencies
-# --------+------------+-------------+---------------+--------------
-# RXQx.y  | RXQx.y     | LINKx       | PIPELINEz     | LINKx
-# TXQx.y  | TXQx.y     | PIPELINEz   | LINKx         | LINKx
-# SWQx    | SWQx       | PIPELINEy   | PIPELINEz     | -
-# TMx     | TMx        | PIPELINEy   | PIPELINEz     | LINKx
-# KNIx RX | KNIx       | KNIx RX     | PIPELINEy     | KNIx, LINKx
-# KNIx TX | KNIx       | PIPELINEy   | KNIx TX       | KNIx, LINKx
-# TAPx RX | TAPx       | TAPx RX     | PIPELINEy     | TAPx
-# TAPx TX | TAPx       | PIPELINEy   | TAPx TX       | TAPx
-# SOURCEx | SOURCEx    | SOURCEx     | PIPELINEy     | SOURCEx
-# SINKx   | SINKx      | PIPELINEy   | SINKx         | SINKx
-
-
-#
-# Parse the input configuration file to detect the graph nodes and edges
-#
-def process_config_file(cfgfile):
-    edges = {}
-    links = set()
-    knis = set()
-    taps = set()
-    sources = set()
-    sinks = set()
-    pipelines = set()
-    pipeline = ''
-
-    dotfile = cfgfile + '.txt'
-    imgfile = cfgfile + '.png'
-
-    #
-    # Read configuration file
-    #
-    lines = open(cfgfile, 'r')
-    for line in lines:
-        # Remove any leading and trailing white space characters
-        line = line.strip()
-
-        # Remove any comment at end of line
-        line, sep, tail = line.partition(';')
-
-        # Look for next "PIPELINE" section
-        match = re.search(r'\[(PIPELINE\d+)\]', line)
-        if match:
-            pipeline = match.group(1)
-            continue
-
-        # Look for next "pktq_in" section entry
-        match = re.search(r'pktq_in\s*=\s*(.+)', line)
-        if match:
-            pipelines.add(pipeline)
-            for q in re.findall('\S+', match.group(1)):
-                match_rxq = re.search(r'^RXQ(\d+)\.\d+$', q)
-                match_swq = re.search(r'^SWQ\d+$', q)
-                match_tm = re.search(r'^TM(\d+)$', q)
-                match_kni = re.search(r'^KNI(\d+)$', q)
-                match_tap = re.search(r'^TAP\d+$', q)
-                match_source = re.search(r'^SOURCE\d+$', q)
-
-                # Set ID for the current packet queue (graph edge)
-                q_id = ''
-                if match_rxq or match_swq or match_tm or match_source:
-                    q_id = q
-                elif match_kni or match_tap:
-                    q_id = q + ' RX'
-                else:
-                    print('Error: Unrecognized pktq_in element "%s"' % q)
-                    return
-
-                # Add current packet queue to the set of graph edges
-                if q_id not in edges:
-                    edges[q_id] = {}
-                if 'label' not in edges[q_id]:
-                    edges[q_id]['label'] = q
-                if 'readers' not in edges[q_id]:
-                    edges[q_id]['readers'] = []
-                if 'writers' not in edges[q_id]:
-                    edges[q_id]['writers'] = []
-
-                # Add reader for the new edge
-                edges[q_id]['readers'].append(pipeline)
-
-                # Check for RXQ
-                if match_rxq:
-                    link = 'LINK' + str(match_rxq.group(1))
-                    edges[q_id]['writers'].append(link + ' RX')
-                    links.add(link)
-                    continue
-
-                # Check for SWQ
-                if match_swq:
-                    continue
-
-                # Check for TM
-                if match_tm:
-                    link = 'LINK' + str(match_tm.group(1))
-                    links.add(link)
-                    continue
-
-                # Check for KNI
-                if match_kni:
-                    link = 'LINK' + str(match_kni.group(1))
-                    edges[q_id]['writers'].append(q_id)
-                    knis.add(q)
-                    links.add(link)
-                    continue
-
-                # Check for TAP
-                if match_tap:
-                    edges[q_id]['writers'].append(q_id)
-                    taps.add(q)
-                    continue
-
-                # Check for SOURCE
-                if match_source:
-                    edges[q_id]['writers'].append(q)
-                    sources.add(q)
-                    continue
-
-                continue
-
-        # Look for next "pktq_out" section entry
-        match = re.search(r'pktq_out\s*=\s*(.+)', line)
-        if match:
-            for q in re.findall('\S+', match.group(1)):
-                match_txq = re.search(r'^TXQ(\d+)\.\d+$', q)
-                match_swq = re.search(r'^SWQ\d+$', q)
-                match_tm = re.search(r'^TM(\d+)$', q)
-                match_kni = re.search(r'^KNI(\d+)$', q)
-                match_tap = re.search(r'^TAP(\d+)$', q)
-                match_sink = re.search(r'^SINK(\d+)$', q)
-
-                # Set ID for the current packet queue (graph edge)
-                q_id = ''
-                if match_txq or match_swq or match_tm or match_sink:
-                    q_id = q
-                elif match_kni or match_tap:
-                    q_id = q + ' TX'
-                else:
-                    print('Error: Unrecognized pktq_out element "%s"' % q)
-                    return
-
-                # Add current packet queue to the set of graph edges
-                if q_id not in edges:
-                    edges[q_id] = {}
-                if 'label' not in edges[q_id]:
-                    edges[q_id]['label'] = q
-                if 'readers' not in edges[q_id]:
-                    edges[q_id]['readers'] = []
-                if 'writers' not in edges[q_id]:
-                    edges[q_id]['writers'] = []
-
-                # Add writer for the new edge
-                edges[q_id]['writers'].append(pipeline)
-
-                # Check for TXQ
-                if match_txq:
-                    link = 'LINK' + str(match_txq.group(1))
-                    edges[q_id]['readers'].append(link + ' TX')
-                    links.add(link)
-                    continue
-
-                # Check for SWQ
-                if match_swq:
-                    continue
-
-                # Check for TM
-                if match_tm:
-                    link = 'LINK' + str(match_tm.group(1))
-                    links.add(link)
-                    continue
-
-                # Check for KNI
-                if match_kni:
-                    link = 'LINK' + str(match_kni.group(1))
-                    edges[q_id]['readers'].append(q_id)
-                    knis.add(q)
-                    links.add(link)
-                    continue
-
-                # Check for TAP
-                if match_tap:
-                    edges[q_id]['readers'].append(q_id)
-                    taps.add(q)
-                    continue
-
-                # Check for SINK
-                if match_sink:
-                    edges[q_id]['readers'].append(q)
-                    sinks.add(q)
-                    continue
-
-                continue
-
-    #
-    # Write DOT file
-    #
-    print('Creating DOT file "%s" ...' % dotfile)
-    dot_cmd = DOT_COMMAND % (dotfile, imgfile)
-    file = open(dotfile, 'w')
-    file.write(DOT_INTRO % dot_cmd)
-    file.write(DOT_GRAPH_BEGIN)
-
-    # Write the graph nodes to the DOT file
-    for l in sorted(links):
-        file.write(DOT_NODE_LINK_RX % l)
-        file.write(DOT_NODE_LINK_TX % l)
-    for k in sorted(knis):
-        file.write(DOT_NODE_KNI_RX % k)
-        file.write(DOT_NODE_KNI_TX % k)
-    for t in sorted(taps):
-        file.write(DOT_NODE_TAP_RX % t)
-        file.write(DOT_NODE_TAP_TX % t)
-    for s in sorted(sources):
-        file.write(DOT_NODE_SOURCE % s)
-    for s in sorted(sinks):
-        file.write(DOT_NODE_SINK % s)
-    for p in sorted(pipelines):
-        file.write(DOT_NODE_PIPELINE % p)
-
-    # Write the graph edges to the DOT file
-    for q in sorted(edges.keys()):
-        rw = edges[q]
-        if 'writers' not in rw:
-            print('Error: "%s" has no writer' % q)
-            return
-        if 'readers' not in rw:
-            print('Error: "%s" has no reader' % q)
-            return
-        for w in rw['writers']:
-            for r in rw['readers']:
-                file.write(DOT_EDGE_PKTQ % (w, r, rw['label']))
-
-    file.write(DOT_GRAPH_END)
-    file.close()
-
-    #
-    # Execute the DOT command to create the image file
-    #
-    print('Creating image file "%s" ...' % imgfile)
-    if os.system('which dot > /dev/null'):
-        print('Error: Unable to locate "dot" executable.'
-              'Please install the "graphviz" package (www.graphviz.org).')
-        return
-
-    os.system(dot_cmd)
-
-
-if __name__ == '__main__':
-    parser = argparse.ArgumentParser(description='Create diagram for IP '
-                                                 'pipeline configuration '
-                                                 'file.')
-
-    parser.add_argument(
-        '-f',
-        '--file',
-        help='input configuration file (e.g. "ip_pipeline.cfg")',
-        required=True)
-
-    args = parser.parse_args()
-
-    process_config_file(args.file)
diff --git a/examples/ip_pipeline/config/edge_router_downstream.cfg b/examples/ip_pipeline/config/edge_router_downstream.cfg
deleted file mode 100644
index c6b4e1f..0000000
--- a/examples/ip_pipeline/config/edge_router_downstream.cfg
+++ /dev/null
@@ -1,97 +0,0 @@
-;   BSD LICENSE
-;
-;   Copyright(c) 2015-2016 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.
-
-
-;   An edge router typically sits between two networks such as the provider
-;   core network and the provider access network. A typical packet processing
-;   pipeline for the downstream traffic (i.e. traffic from core to access
-;   network) contains the following functional blocks: Packet RX & Routing,
-;   Traffic management and Packet TX. The input packets are assumed to be
-;   IPv4, while the output packets are Q-in-Q IPv4.
-;
-;  A simple implementation for this functional pipeline is presented below.
-;
-;                  Packet Rx &                Traffic Management               Packet Tx
-;                   Routing                    (Pass-Through)                (Pass-Through)
-;             _____________________  SWQ0  ______________________  SWQ4  _____________________
-; RXQ0.0 --->|                     |----->|                      |----->|                     |---> TXQ0.0
-;            |                     | SWQ1 |                      | SWQ5 |                     |
-; RXQ1.0 --->|                     |----->|                      |----->|                     |---> TXQ1.0
-;            |        (P1)         | SWQ2 |         (P2)         | SWQ6 |        (P3)         |
-; RXQ2.0 --->|                     |----->|                      |----->|                     |---> TXQ2.0
-;            |                     | SWQ3 |                      | SWQ7 |                     |
-; RXQ3.0 --->|                     |----->|                      |----->|                     |---> TXQ3.0
-;            |_____________________|      |______________________|      |_____________________|
-;                       |                  |  ^  |  ^  |  ^  |  ^
-;                       |                  |__|  |__|  |__|  |__|
-;                       +--> SINK0          TM0   TM1   TM2   TM3
-;                      (Default)
-;
-; Input packet: Ethernet/IPv4
-; Output packet: Ethernet/QinQ/IPv4
-;
-; Packet buffer layout:
-; #	Field Name		Offset (Bytes)	Size (Bytes)
-; 0	Mbuf			0 		128
-; 1	Headroom		128 		128
-; 2	Ethernet header		256 		14
-; 3	IPv4 header		270 		20
-
-[EAL]
-log_level = 0
-
-[PIPELINE0]
-type = MASTER
-core = 0
-
-[PIPELINE1]
-type = ROUTING
-core = 1
-pktq_in = RXQ0.0 RXQ1.0 RXQ2.0 RXQ3.0
-pktq_out = SWQ0 SWQ1 SWQ2 SWQ3 SINK0
-encap = ethernet_qinq
-qinq_sched = test
-ip_hdr_offset = 270
-
-[PIPELINE2]
-type = PASS-THROUGH
-core = 2
-pktq_in = SWQ0 SWQ1 SWQ2 SWQ3 TM0 TM1 TM2 TM3
-pktq_out = TM0 TM1 TM2 TM3 SWQ4 SWQ5 SWQ6 SWQ7
-
-[PIPELINE3]
-type = PASS-THROUGH
-core = 3
-pktq_in = SWQ4 SWQ5 SWQ6 SWQ7
-pktq_out = TXQ0.0 TXQ1.0 TXQ2.0 TXQ3.0
-
-[MEMPOOL0]
-pool_size = 2M
diff --git a/examples/ip_pipeline/config/edge_router_downstream.sh b/examples/ip_pipeline/config/edge_router_downstream.sh
deleted file mode 100644
index 67c3a0d..0000000
--- a/examples/ip_pipeline/config/edge_router_downstream.sh
+++ /dev/null
@@ -1,13 +0,0 @@
-#
-# run ./config/edge_router_downstream.sh
-#
-
-################################################################################
-# Routing: Ether QinQ, ARP off
-################################################################################
-p 1 route add default 4 #SINK0
-p 1 route add 0.0.0.0 10 port 0 ether a0:b0:c0:d0:e0:f0 qinq 256 257
-p 1 route add 0.64.0.0 10 port 1 ether a1:b1:c1:d1:e1:f1 qinq 258 259
-p 1 route add 0.128.0.0 10 port 2 ether a2:b2:c2:d2:e2:f2 qinq 260 261
-p 1 route add 0.192.0.0 10 port 3 ether a3:b3:c3:d3:e3:f3 qinq 262 263
-#p 1 route ls
diff --git a/examples/ip_pipeline/config/edge_router_upstream.cfg b/examples/ip_pipeline/config/edge_router_upstream.cfg
deleted file mode 100644
index dea42b9..0000000
--- a/examples/ip_pipeline/config/edge_router_upstream.cfg
+++ /dev/null
@@ -1,124 +0,0 @@
-;   BSD LICENSE
-;
-;   Copyright(c) 2015-2016 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.
-
-
-;   An edge router typically sits between two networks such as the provider
-;   core network and the provider access network. A typical packet processing
-;   pipeline for the upstream traffic (i.e. traffic from access to core
-;   network) contains the following functional blocks: Packet RX & Firewall,
-;   Flow classification, Metering, Routing and Packet TX. The input packets
-;   are assumed to be Q-in-Q IPv4, while the output packets are MPLS IPv4
-;  (with variable number of labels per route).
-;
-;   A simple implementation for this functional pipeline is presented below.
-;
-;             Packet RX &       Pass-Through    Flow Classification   Flow Actions         Routing
-:              Firewall
-;             __________  SWQ0   __________  SWQ4   __________  SWQ8   __________  SWQ12  __________
-; RXQ0.0 --->|          |------>|          |------>|          |------>|          |------>|          |------> TXQ0.0
-;            |          | SWQ1  |          | SWQ5  |          | SWQ9  |          | SWQ13 |          |
-; RXQ1.0 --->|          |------>|          |------>|          |------>|          |------>|          |------> TXQ1.0
-;            |   (P1)   | SWQ2  |  (P2)    | SWQ6  |   (P3)   | SWQ10 |   (P4)   | SWQ14 |   (P5)   |
-; RXQ2.0 --->|          |------>|          |------>|          |------>|          |------>|          |------> TXQ2.0
-;            |          | SWQ3  |          | SWQ7  |          | SWQ11 |          | SWQ15 |          |
-; RXQ3.0 --->|          |------>|          |------>|          |------>|          |------>|          |------> TXQ3.0
-;            |__________|       |__________|       |__________|       |__________|       |__________|
-;                 |                                     |                                     |
-;                 +--> SINK0 (Default)                  +--> SINK1 (Default)                  +--> SINK2 (Default)
-;
-; Input packet: Ethernet/QinQ/IPv4
-; Output packet: Ethernet/MPLS/IPv4
-;
-; Packet buffer layout:
-; #	Field Name		Offset (Bytes)	Size (Bytes)
-; 0	Mbuf			0 		128
-; 1	Headroom		128 		128
-; 2	Ethernet header		256 		14
-; 3     QinQ header             270             8
-; 4	IPv4 header		278 		20
-
-[EAL]
-log_level = 0
-
-[PIPELINE0]
-type = MASTER
-core = 0
-
-[PIPELINE1]
-type = FIREWALL
-core = 1
-pktq_in = RXQ0.0 RXQ1.0 RXQ2.0 RXQ3.0
-pktq_out = SWQ0 SWQ1 SWQ2 SWQ3 SINK0
-n_rules = 4096
-pkt_type = qinq_ipv4
-
-[PIPELINE2]
-type = PASS-THROUGH
-core = 2
-pktq_in = SWQ0 SWQ1 SWQ2 SWQ3
-pktq_out = SWQ4 SWQ5 SWQ6 SWQ7
-dma_size = 8
-dma_dst_offset = 128
-dma_src_offset = 268; 1st Ethertype offset
-dma_src_mask = 00000FFF00000FFF; qinq
-dma_hash_offset = 136; dma_dst_offset + dma_size
-
-[PIPELINE3]
-type = FLOW_CLASSIFICATION
-core = 2
-pktq_in = SWQ4 SWQ5 SWQ6 SWQ7
-pktq_out = SWQ8 SWQ9 SWQ10 SWQ11 SINK1
-n_flows = 65536
-key_size = 8; dma_size
-key_offset = 128; dma_dst_offset
-hash_offset = 136; dma_hash_offset
-flowid_offset = 192
-
-[PIPELINE4]
-type = FLOW_ACTIONS
-core = 3
-pktq_in = SWQ8 SWQ9 SWQ10 SWQ11
-pktq_out = SWQ12 SWQ13 SWQ14 SWQ15
-n_flows = 65536
-n_meters_per_flow = 1
-flow_id_offset = 192; flowid_offset
-ip_hdr_offset = 278
-color_offset = 196; flowid_offset + sizeof(flow_id)
-
-[PIPELINE5]
-type = ROUTING
-core = 4
-pktq_in = SWQ12 SWQ13 SWQ14 SWQ15
-pktq_out = TXQ0.0 TXQ1.0 TXQ2.0 TXQ3.0 SINK2
-encap = ethernet_mpls
-mpls_color_mark = yes
-ip_hdr_offset = 278
-color_offset = 196; flowid_offset + sizeof(flow_id)
diff --git a/examples/ip_pipeline/config/edge_router_upstream.sh b/examples/ip_pipeline/config/edge_router_upstream.sh
deleted file mode 100644
index 5d574c1..0000000
--- a/examples/ip_pipeline/config/edge_router_upstream.sh
+++ /dev/null
@@ -1,33 +0,0 @@
-#
-# run ./config/edge_router_upstream.sh
-#
-
-################################################################################
-# Firewall
-################################################################################
-p 1 firewall add default 4 #SINK0
-p 1 firewall add bulk ./config/edge_router_upstream_firewall.txt
-#p 1 firewall ls
-
-################################################################################
-# Flow Classification
-################################################################################
-p 3 flow add default 4 #SINK1
-p 3 flow add qinq bulk ./config/edge_router_upstream_flow.txt
-#p 3 flow ls
-
-################################################################################
-# Flow Actions - Metering and Policing
-################################################################################
-p 4 action flow bulk ./config/edge_router_upstream_action.txt
-#p 4 action flow ls
-
-################################################################################
-# Routing: Ether MPLS, ARP off
-################################################################################
-p 5 route add default 4 #SINK2
-p 5 route add 0.0.0.0 10 port 0 ether a0:b0:c0:d0:e0:f0 mpls 0:1
-p 5 route add 0.64.0.0 10 port 1 ether a1:b1:c1:d1:e1:f1 mpls 10:11
-p 5 route add 0.128.0.0 10 port 2 ether a2:b2:c2:d2:e2:f2 mpls 20:21
-p 5 route add 0.192.0.0 10 port 3 ether a3:b3:c3:d3:e3:f3 mpls 30:31
-#p 5 route ls
diff --git a/examples/ip_pipeline/config/firewall.cfg b/examples/ip_pipeline/config/firewall.cfg
deleted file mode 100644
index 2f5dd9f..0000000
--- a/examples/ip_pipeline/config/firewall.cfg
+++ /dev/null
@@ -1,68 +0,0 @@
-;   BSD LICENSE
-;
-;   Copyright(c) 2015-2016 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.
-
-;             _______________
-; RXQ0.0 --->|               |---> TXQ0.0
-;            |               |
-; RXQ1.0 --->|               |---> TXQ1.0
-;            |   Firewall    |
-; RXQ2.0 --->|               |---> TXQ2.0
-;            |               |
-; RXQ3.0 --->|               |---> TXQ3.0
-;            |_______________|
-;                    |
-;                    +-----------> SINK0 (default rule)
-;
-; Input packet: Ethernet/IPv4
-;
-; Packet buffer layout:
-; #	Field Name		Offset (Bytes)	Size (Bytes)
-; 0	Mbuf			0 		128
-; 1	Headroom		128 		128
-; 2	Ethernet header		256 		14
-; 3	IPv4 header		270 		20
-
-[EAL]
-log_level = 0
-
-[PIPELINE0]
-type = MASTER
-core = 0
-
-[PIPELINE1]
-type = FIREWALL
-core = 1
-pktq_in = RXQ0.0 RXQ1.0 RXQ2.0 RXQ3.0
-pktq_out = TXQ0.0 TXQ1.0 TXQ2.0 TXQ3.0 SINK0
-n_rules = 4096
-pkt_type = ipv4
-;pkt_type = vlan_ipv4
-;pkt_type = qinq_ipv4
diff --git a/examples/ip_pipeline/config/firewall.sh b/examples/ip_pipeline/config/firewall.sh
deleted file mode 100644
index c83857e..0000000
--- a/examples/ip_pipeline/config/firewall.sh
+++ /dev/null
@@ -1,13 +0,0 @@
-#
-# run ./config/firewall.sh
-#
-
-p 1 firewall add default 4 #SINK0
-p 1 firewall add priority 1 ipv4 0.0.0.0 0 100.0.0.0 10 0 65535 0 65535 6 0xF port 0
-p 1 firewall add priority 1 ipv4 0.0.0.0 0 100.64.0.0 10 0 65535 0 65535 6 0xF port 1
-p 1 firewall add priority 1 ipv4 0.0.0.0 0 100.128.0.0 10 0 65535 0 65535 6 0xF port 2
-p 1 firewall add priority 1 ipv4 0.0.0.0 0 100.192.0.0 10 0 65535 0 65535 6 0xF port 3
-
-#p 1 firewall add bulk ./config/firewall.txt
-
-p 1 firewall ls
diff --git a/examples/ip_pipeline/config/firewall.txt b/examples/ip_pipeline/config/firewall.txt
deleted file mode 100644
index 54cfffd..0000000
--- a/examples/ip_pipeline/config/firewall.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# p <pipelineid> firewall add bulk ./config/firewall.txt
-# p <pipelineid> firewall del bulk ./config/firewall.txt
-#
-
-priority 1 ipv4 0.0.0.0 0 100.0.0.0 10 0 65535 0 65535 6 0xF port 0
-priority 1 ipv4 0.0.0.0 0 100.64.0.0 10 0 65535 0 65535 6 0xF port 1
-priority 1 ipv4 0.0.0.0 0 100.128.0.0 10 0 65535 0 65535 6 0xF port 2
-priority 1 ipv4 0.0.0.0 0 100.192.0.0 10 0 65535 0 65535 6 0xF port 3
diff --git a/examples/ip_pipeline/config/flow.cfg b/examples/ip_pipeline/config/flow.cfg
deleted file mode 100644
index cec990a..0000000
--- a/examples/ip_pipeline/config/flow.cfg
+++ /dev/null
@@ -1,72 +0,0 @@
-;   BSD LICENSE
-;
-;   Copyright(c) 2015-2016 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.
-
-;             ________________
-; RXQ0.0 --->|                |---> TXQ0.0
-;            |                |
-; RXQ1.0 --->|                |---> TXQ1.0
-;            |      Flow      |
-; RXQ2.0 --->| Classification |---> TXQ2.0
-;            |                |
-; RXQ3.0 --->|                |---> TXQ3.0
-;            |________________|
-;                    |
-;                    +-----------> SINK0 (flow lookup miss)
-;
-; Input packet: Ethernet/IPv4
-;
-; Packet buffer layout:
-; #	Field Name		Offset (Bytes)	Size (Bytes)
-; 0	Mbuf			0		128
-; 1	Headroom		128 		128
-; 2	Ethernet header		256 		14
-; 3	QinQ/IPv4/IPv6 header	270 		8/20/40
-
-[EAL]
-log_level = 0
-
-[PIPELINE0]
-type = MASTER
-core = 0
-
-[PIPELINE1]
-type = FLOW_CLASSIFICATION
-core = 1
-pktq_in = RXQ0.0 RXQ1.0 RXQ2.0 RXQ3.0
-pktq_out = TXQ0.0 TXQ1.0 TXQ2.0 TXQ3.0 SINK0
-n_flows = 65536
-;key_size = 8                ; QinQ key size
-;key_offset = 268            ; QinQ key offset
-;key_mask = 00000FFF00000FFF ; QinQ key mask
-key_size = 16                               ; IPv4 5-tuple key size
-key_offset = 278                            ; IPv4 5-tuple key offset
-key_mask = 00FF0000FFFFFFFFFFFFFFFFFFFFFFFF ; IPv4 5-tuple key mask
-flowid_offset = 128
diff --git a/examples/ip_pipeline/config/flow.sh b/examples/ip_pipeline/config/flow.sh
deleted file mode 100644
index 489c707..0000000
--- a/examples/ip_pipeline/config/flow.sh
+++ /dev/null
@@ -1,25 +0,0 @@
-#
-# run ./config/flow.sh
-#
-
-################################################################################
-# Flow classification (QinQ)
-################################################################################
-#p 1 flow add default 4 #SINK0
-#p 1 flow add qinq 100 200 port 0 id 0
-#p 1 flow add qinq 101 201 port 1 id 1
-#p 1 flow add qinq 102 202 port 2 id 2
-#p 1 flow add qinq 103 203 port 3 id 3
-
-#p 1 flow add qinq bulk ./config/flow.txt
-
-################################################################################
-# Flow classification (IPv4 5-tuple)
-################################################################################
-p 1 flow add default 4 #SINK0
-p 1 flow add ipv4 100.0.0.10 200.0.0.10 100 200 6 port 0 id 0
-p 1 flow add ipv4 100.0.0.11 200.0.0.11 101 201 6 port 1 id 1
-p 1 flow add ipv4 100.0.0.12 200.0.0.12 102 202 6 port 2 id 2
-p 1 flow add ipv4 100.0.0.13 200.0.0.13 103 203 6 port 3 id 3
-
-#p 1 flow add ipv4 bulk ./config/flow.txt
diff --git a/examples/ip_pipeline/config/flow.txt b/examples/ip_pipeline/config/flow.txt
deleted file mode 100644
index c1a141d..0000000
--- a/examples/ip_pipeline/config/flow.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-#
-# p <pipelineid> flow add qinq bulk ./config/flow.txt
-#
-
-#qinq 100 200 port 0 id 0
-#qinq 101 201 port 1 id 1
-#qinq 102 202 port 2 id 2
-#qinq 103 203 port 3 id 3
-
-#
-# p <pipelineid> flow add ipv4 bulk ./config/flow.txt
-#
-
-ipv4 100.0.0.10 200.0.0.10 100 200 6 port 0 id 0
-ipv4 100.0.0.11 200.0.0.11 101 201 6 port 1 id 1
-ipv4 100.0.0.12 200.0.0.12 102 202 6 port 2 id 2
-ipv4 100.0.0.13 200.0.0.13 103 203 6 port 3 id 3
diff --git a/examples/ip_pipeline/config/ip_pipeline.cfg b/examples/ip_pipeline/config/ip_pipeline.cfg
deleted file mode 100644
index 095ed25..0000000
--- a/examples/ip_pipeline/config/ip_pipeline.cfg
+++ /dev/null
@@ -1,9 +0,0 @@
-[PIPELINE0]
-type = MASTER
-core = 0
-
-[PIPELINE1]
-type = PASS-THROUGH
-core = 1
-pktq_in = RXQ0.0 RXQ1.0 RXQ2.0 RXQ3.0
-pktq_out = TXQ0.0 TXQ1.0 TXQ2.0 TXQ3.0
diff --git a/examples/ip_pipeline/config/ip_pipeline.sh b/examples/ip_pipeline/config/ip_pipeline.sh
deleted file mode 100644
index 4fca259..0000000
--- a/examples/ip_pipeline/config/ip_pipeline.sh
+++ /dev/null
@@ -1,5 +0,0 @@
-#
-#run config/ip_pipeline.sh
-#
-
-p 1 ping
diff --git a/examples/ip_pipeline/config/kni.cfg b/examples/ip_pipeline/config/kni.cfg
deleted file mode 100644
index cea208b..0000000
--- a/examples/ip_pipeline/config/kni.cfg
+++ /dev/null
@@ -1,67 +0,0 @@
-;   BSD LICENSE
-;
-;   Copyright(c) 2016 Intel Corporation.
-;   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.
-;
-;             ______________          ______________________
-;            |              |  KNI0  |                      |
-; RXQ0.0 --->|              |------->|--+                   |
-;            |              |  KNI1  |  | br0               |
-; TXQ1.0 <---|              |<-------|<-+                   |
-;            | Pass-through |        |     Linux Kernel     |
-;            |     (P1)     |        |     Network Stack    |
-;            |              |  KNI1  |                      |
-; RXQ1.0 --->|              |------->|--+                   |
-;            |              |  KNI0  |  | br0               |
-; TXQ0.0 <---|              |<-------|<-+                   |
-;            |______________|        |______________________|
-;
-; Insert Linux kernel KNI module:
-;    [Linux]$ insmod rte_kni.ko
-;
-; Configure Linux kernel bridge between KNI0 and KNI1 interfaces:
-;    [Linux]$ ifconfig KNI0 up
-;    [Linux]$ ifconfig KNI1 up
-;    [Linux]$ brctl addbr "br0"
-;    [Linux]$ brctl addif br0 KNI0
-;    [Linux]$ brctl addif br0 KNI1
-;    [Linux]$ ifconfig br0 up
-
-[EAL]
-log_level = 0
-
-[PIPELINE0]
-type = MASTER
-core = 0
-
-[PIPELINE1]
-type = PASS-THROUGH
-core = 1
-pktq_in = RXQ0.0 KNI1 RXQ1.0 KNI0
-pktq_out = KNI0 TXQ1.0 KNI1 TXQ0.0
diff --git a/examples/ip_pipeline/config/l2fwd.cfg b/examples/ip_pipeline/config/l2fwd.cfg
deleted file mode 100644
index a1df9e6..0000000
--- a/examples/ip_pipeline/config/l2fwd.cfg
+++ /dev/null
@@ -1,58 +0,0 @@
-;   BSD LICENSE
-;
-;   Copyright(c) 2015-2016 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.
-
-;
-; The pass-through pipeline below connects the input ports to the output ports
-; as follows: RXQ0.0 -> TXQ1.0, RXQ1.0 -> TXQ0.0, RXQ2.0 -> TXQ3.0 and
-; RXQ3.0 -> TXQ2.0.
-;             ________________
-; RXQ0.0 --->|................|---> TXQ1.0
-;            |                |
-; RXQ1.0 --->|................|---> TXQ0.0
-;            |  Pass-through  |
-; RXQ2.0 --->|................|---> TXQ3.0
-;            |                |
-; RXQ3.0 --->|................|---> TXQ2.0
-;            |________________|
-;
-
-[EAL]
-log_level = 0
-
-[PIPELINE0]
-type = MASTER
-core = 0
-
-[PIPELINE1]
-type = PASS-THROUGH
-core = 1
-pktq_in = RXQ0.0 RXQ1.0 RXQ2.0 RXQ3.0
-pktq_out = TXQ1.0 TXQ0.0 TXQ3.0 TXQ2.0
diff --git a/examples/ip_pipeline/config/l3fwd.cfg b/examples/ip_pipeline/config/l3fwd.cfg
deleted file mode 100644
index 02c8f36..0000000
--- a/examples/ip_pipeline/config/l3fwd.cfg
+++ /dev/null
@@ -1,68 +0,0 @@
-;   BSD LICENSE
-;
-;   Copyright(c) 2015-2016 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.
-
-;             _______________
-; RXQ0.0 --->|               |---> TXQ0.0
-;            |               |
-; RXQ1.0 --->|               |---> TXQ1.0
-;            |    Routing    |
-; RXQ2.0 --->|               |---> TXQ2.0
-;            |               |
-; RXQ3.0 --->|               |---> TXQ3.0
-;            |_______________|
-;                    |
-;                    +-----------> SINK0 (route miss)
-;
-; Input packet: Ethernet/IPv4
-;
-; Packet buffer layout:
-; #	Field Name		Offset (Bytes)	Size (Bytes)
-; 0	Mbuf			0 		128
-; 1	Headroom		128 		128
-; 2	Ethernet header		256 		14
-; 3	IPv4 header		270 		20
-
-[EAL]
-log_level = 0
-
-[PIPELINE0]
-type = MASTER
-core = 0
-
-[PIPELINE1]
-type = ROUTING
-core = 1
-pktq_in = RXQ0.0 RXQ1.0 RXQ2.0 RXQ3.0
-pktq_out = TXQ0.0 TXQ1.0 TXQ2.0 TXQ3.0 SINK0
-encap = ethernet
-;encap = ethernet_qinq
-;encap = ethernet_mpls
-ip_hdr_offset = 270
diff --git a/examples/ip_pipeline/config/l3fwd.sh b/examples/ip_pipeline/config/l3fwd.sh
deleted file mode 100644
index 47406aa..0000000
--- a/examples/ip_pipeline/config/l3fwd.sh
+++ /dev/null
@@ -1,33 +0,0 @@
-#
-# run ./config/l3fwd.sh
-#
-
-################################################################################
-# Routing: encap = ethernet, arp = off
-################################################################################
-p 1 route add default 4 #SINK0
-p 1 route add 100.0.0.0 10 port 0 ether a0:b0:c0:d0:e0:f0
-p 1 route add 100.64.0.0 10 port 1 ether a1:b1:c1:d1:e1:f1
-p 1 route add 100.128.0.0 10 port 2 ether a2:b2:c2:d2:e2:f2
-p 1 route add 100.192.0.0 10 port 3 ether a3:b3:c3:d3:e3:f3
-p 1 route ls
-
-################################################################################
-# Routing: encap = ethernet_qinq, arp = off
-################################################################################
-#p 1 route add default 4 #SINK0
-#p 1 route add 100.0.0.0 10 port 0 ether a0:b0:c0:d0:e0:f0 qinq 1000 2000
-#p 1 route add 100.64.0.0 10 port 1 ether a1:b1:c1:d1:e1:f1 qinq 1001 2001
-#p 1 route add 100.128.0.0 10 port 2 ether a2:b2:c2:d2:e2:f2 qinq 1002 2002
-#p 1 route add 100.192.0.0 10 port 3 ether a3:b3:c3:d3:e3:f3 qinq 1003 2003
-#p 1 route ls
-
-################################################################################
-# Routing: encap = ethernet_mpls, arp = off
-################################################################################
-#p 1 route add default 4 #SINK0
-#p 1 route add 100.0.0.0 10 port 0 ether a0:b0:c0:d0:e0:f0 mpls 1000:2000
-#p 1 route add 100.64.0.0 10 port 1 ether a1:b1:c1:d1:e1:f1 mpls 1001:2001
-#p 1 route add 100.128.0.0 10 port 2 ether a2:b2:c2:d2:e2:f2 mpls 1002:2002
-#p 1 route add 100.192.0.0 10 port 3 ether a3:b3:c3:d3:e3:f3 mpls 1003:2003
-#p 1 route ls
diff --git a/examples/ip_pipeline/config/l3fwd_arp.cfg b/examples/ip_pipeline/config/l3fwd_arp.cfg
deleted file mode 100644
index 2c63c8f..0000000
--- a/examples/ip_pipeline/config/l3fwd_arp.cfg
+++ /dev/null
@@ -1,70 +0,0 @@
-;   BSD LICENSE
-;
-;   Copyright(c) 2015-2016 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.
-
-;             _______________
-; RXQ0.0 --->|               |---> TXQ0.0
-;            |               |
-; RXQ1.0 --->|               |---> TXQ1.0
-;            |    Routing    |
-; RXQ2.0 --->|               |---> TXQ2.0
-;            |               |
-; RXQ3.0 --->|               |---> TXQ3.0
-;            |_______________|
-;                    |
-;                    +-----------> SINK0 (route miss)
-;
-; Input packet: Ethernet/IPv4
-;
-; Packet buffer layout:
-; #	Field Name		Offset (Bytes)	Size (Bytes)
-; 0	Mbuf			0 		128
-; 1	Headroom		128 		128
-; 2	Ethernet header		256 		14
-; 3	IPv4 header		270 		20
-
-[EAL]
-log_level = 0
-
-[PIPELINE0]
-type = MASTER
-core = 0
-
-[PIPELINE1]
-type = ROUTING
-core = 1
-pktq_in = RXQ0.0 RXQ1.0 RXQ2.0 RXQ3.0
-pktq_out = TXQ0.0 TXQ1.0 TXQ2.0 TXQ3.0 SINK0
-encap = ethernet
-;encap = ethernet_qinq
-;encap = ethernet_mpls
-n_arp_entries = 1024
-ip_hdr_offset = 270
-arp_key_offset = 128
diff --git a/examples/ip_pipeline/config/l3fwd_arp.sh b/examples/ip_pipeline/config/l3fwd_arp.sh
deleted file mode 100644
index 20bea58..0000000
--- a/examples/ip_pipeline/config/l3fwd_arp.sh
+++ /dev/null
@@ -1,43 +0,0 @@
-#
-# run ./config/l3fwd_arp.sh
-#
-
-################################################################################
-# ARP
-################################################################################
-p 1 arp add default 4 #SINK0
-p 1 arp add 0 10.0.0.1 a0:b0:c0:d0:e0:f0
-p 1 arp add 1 11.0.0.1 a1:b1:c1:d1:e1:f1
-p 1 arp add 2 12.0.0.1 a2:b2:c2:d2:e2:f2
-p 1 arp add 3 13.0.0.1 a3:b3:c3:d3:e3:f3
-p 1 arp ls
-
-################################################################################
-# Routing: encap = ethernet, arp = on
-################################################################################
-p 1 route add default 4 #SINK0
-p 1 route add 100.0.0.0 10 port 0 ether 10.0.0.1
-p 1 route add 100.64.0.0 10 port 1 ether 11.0.0.1
-p 1 route add 100.128.0.0 10 port 2 ether 12.0.0.1
-p 1 route add 100.192.0.0 10 port 3 ether 13.0.0.1
-p 1 route ls
-
-################################################################################
-# Routing: encap = ethernet_qinq, arp = on
-################################################################################
-#p 1 route add default 4 #SINK0
-#p 1 route add 100.0.0.0 10 port 0 ether 10.0.0.1 qinq 1000 2000
-#p 1 route add 100.64.0.0 10 port 1 ether 11.0.0.1 qinq 1001 2001
-#p 1 route add 100.128.0.0 10 port 2 ether 12.0.0.1 qinq 1002 2002
-#p 1 route add 100.192.0.0 10 port 3 ether 13.0.0.1 qinq 1003 2003
-#p 1 route ls
-
-################################################################################
-# Routing: encap = ethernet_mpls, arp = on
-################################################################################
-#p 1 route add default 4 #SINK0
-#p 1 route add 100.0.0.0 10 port 0 ether 10.0.0.1 mpls 1000:2000
-#p 1 route add 100.64.0.0 10 port 1 ether 11.0.0.1 mpls 1001:2001
-#p 1 route add 100.128.0.0 10 port 2 ether 12.0.0.1 mpls 1002:2002
-#p 1 route add 100.192.0.0 10 port 3 ether 13.0.0.1 mpls 1003:2003
-#p 1 route ls
diff --git a/examples/ip_pipeline/config/network_layers.cfg b/examples/ip_pipeline/config/network_layers.cfg
deleted file mode 100644
index 397b5d7..0000000
--- a/examples/ip_pipeline/config/network_layers.cfg
+++ /dev/null
@@ -1,227 +0,0 @@
-;   BSD LICENSE
-;
-;   Copyright(c) 2016 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.
-
-; The diagram below shows how additional protocol components can be plugged into
-; the IP layer implemented by the ip_pipeline application. Pick your favorite
-; open source components for dynamic ARP, ICMP, UDP or TCP termination, etc and
-; connect them through SWQs to the IP infrastructure.
-;
-; The input packets with local destination are sent to the UDP/TCP applications
-; while the input packets with remote destination are routed back to the
-; network. Additional features can easily be added to this setup:
-;  * IP Reassembly: add SWQs with IP reassembly enabled (typically required for
-;    the input traffic with local destination);
-;  * IP Fragmentation: add SWQs with IP fragmentation enabled (typically
-;    required to enforce the MTU for the routed output traffic);
-;  * Traffic Metering: add Flow Action pipeline instances (e.g. for metering the
-;    TCP connections or ICMP input traffic);
-;  * Traffic Management: add TMs for the required output LINKs;
-;  * Protocol encapsulations (QinQ, MPLS) for the output packets: part of the
-;    routing pipeline configuration.
-;
-;                     _________                       _________
-;                    |         |                     |         |
-;                    |   UDP   |                     |   TCP   |
-;                    |   App   |                     |   App   |
-;                    |_________|                     |_________|
-;                       ^   |                           ^   |
-;                     __|___V__                       __|___V__
-;                    |         |  SWQ0 (UDP TX)      |         |  SWQ1 (TCP TX)
-;                    |   UDP   |-------+             |   TCP   |------------+
-;                    |         |       |             |         |            |
-;                    |_________|       |             |_________|            |
-;                         ^            |                  ^                 |
-;                         | SWQ2       |                  | SWQ3            |
-;                         | (UDP RX)   |                  | (TCP RX)        |
-;                     ____|____        |              ____|____             |
-;                    |         |       |             |         |            |
-; RXQ<0..3>.1 ------>|Firewall +--->|  |     +------>|  Flow   +--->|       |
-; (UDP local dest)   |  (P2)   | SINK0 |     |       |  (P3)   |  SINK1     |
-;                    |_________| (Deny)|     |       |_________|  (RST)     |
-; RXQ<0..3>.2 -------------------------|-----+                              |
-; (TCP local dest)                     |                                    |
-;                                      |     +------------------------------+
-;                                      |     |
-;                                     _V_____V_
-;                                    |         |
-;                                    | Routing |                   TXQ<0..3>.0
-; RXQ<0..3>.0 ---------------------->|  & ARP  +----------------------------->
-; (IP remote dest)                   |  (P1)   |
-;                                    |_________|
-;                                      |  ^  |
-;                   SWQ4 +-------------+  |  |  SWQ5 (ARP miss)
-;           (Route miss) |                |  +------------+
-;                        |  +-------------+               |
-;                     ___V__|__   SWQ6                ____V____
-;                    |         |  (ICMP TX)          |         |   TXQ<0..3>.1
-; RXQ<0..3>.3 ------>|  ICMP   |             +------>| Dyn ARP +------------->
-; (IP local dest)    |         |             |       |         |
-;                    |_________|             |       |_________|
-; RXQ<0..3>.4 -------------------------------+
-; (ARP)
-;
-; This configuration file implements the diagram presented below, where the
-; dynamic ARP, ICMP, UDP and TCP components have been stubbed out and replaced
-; with loop-back and packet drop devices.
-;
-;                     _________                       _________
-;                    |         |  SWQ0 (UDP TX)      |         |  SWQ1 (TCP TX)
-;                    |Loobpack |-------+             |Loopback |------------+
-;                    |  (P4)   |       |             |  (P5)   |            |
-;                    |_________|       |             |_________|            |
-;                         ^            |                  ^                 |
-;                         | SWQ2       |                  | SWQ3            |
-;                         | (UDP RX)   |                  | (TCP RX)        |
-;                     ____|____        |              ____|____             |
-;                    |         |       |             |         |            |
-; RXQ<0..3>.1 ------>|Firewall +--->|  |     +------>|  Flow   +--->|       |
-; (UDP local dest)   |  (P2)   | SINK0 |     |       |  (P3)   |  SINK1     |
-;                    |_________| (Deny)|     |       |_________|  (RST)     |
-; RXQ<0..3>.2 -------------------------|-----+                              |
-; (TCP local dest)                     |                                    |
-;                                      |     +------------------------------+
-;                                      |     |
-;                                     _V_____V_
-;                                    |         |
-;                                    | Routing |                   TXQ<0..3>.0
-; RXQ<0..3>.0 ---------------------->|  & ARP  +----------------------------->
-; (IP remote dest)                   |  (P1)   |
-;                                    |_________|
-;                                      |     |
-;                           SINK2 |<---+     +--->| SINK3
-;                           (Route miss)            (ARP miss)
-;
-;                     _________                            _________
-;                    |         |                          |         |
-; RXQ<0..3>.3 ------>|  Drop   +--->| SINK<4..7>  +------>|  Drop   +--->| SINK<8..11>
-; (IP local dest)    |  (P6)   | (IP local dest)  |       |  (P7)   |     (ARP)
-;                    |_________|                  |       |_________|
-; RXQ<0..3>.4 ------------------------------------+
-; (ARP)
-;
-;
-; Input packet: Ethernet/IPv4 or Ethernet/ARP
-; Output packet: Ethernet/IPv4 or Ethernet/ARP
-;
-; Packet buffer layout (for input IPv4 packets):
-; #	Field Name			Offset (Bytes)	Size (Bytes)
-; 0	Mbuf				0				128
-; 1	Headroom			128				128
-; 2	Ethernet header		256				14
-; 3	IPv4 header			270				20
-; 4	ICMP/UDP/TCP header	290				8/8/20
-
-[EAL]
-log_level = 0
-
-[LINK0]
-udp_local_q = 1
-tcp_local_q = 2
-ip_local_q = 3
-arp_q = 4
-
-[LINK1]
-udp_local_q = 1
-tcp_local_q = 2
-ip_local_q = 3
-arp_q = 4
-
-[LINK2]
-udp_local_q = 1
-tcp_local_q = 2
-ip_local_q = 3
-arp_q = 4
-
-[LINK3]
-udp_local_q = 1
-tcp_local_q = 2
-ip_local_q = 3
-arp_q = 4
-
-[PIPELINE0]
-type = MASTER
-core = 0
-
-[PIPELINE1]
-type = ROUTING
-core = 1
-pktq_in = RXQ0.0 RXQ1.0 RXQ2.0 RXQ3.0 SWQ0 SWQ1
-pktq_out = TXQ0.0 TXQ1.0 TXQ2.0 TXQ3.0 SINK2 SINK3
-port_local_dest = 4 ; SINK2 (Drop)
-n_arp_entries = 1000
-ip_hdr_offset = 270
-arp_key_offset = 128
-
-[PIPELINE2]
-type = FIREWALL
-core = 1
-pktq_in = RXQ0.1 RXQ1.1 RXQ2.1 RXQ3.1
-pktq_out = SWQ2 SINK0
-n_rules = 4096
-
-[PIPELINE3]
-type = FLOW_CLASSIFICATION
-core = 1
-pktq_in = RXQ0.2 RXQ1.2 RXQ2.2 RXQ3.2
-pktq_out = SWQ3 SINK1
-n_flows = 65536
-key_size = 16                               ; IPv4 5-tuple key size
-key_offset = 278                            ; IPv4 5-tuple key offset
-key_mask = 00FF0000FFFFFFFFFFFFFFFFFFFFFFFF ; IPv4 5-tuple key mask
-flowid_offset = 128 ; Flow ID effectively acts as TCP socket ID
-
-[PIPELINE4]
-type = PASS-THROUGH ; Loop-back (UDP place-holder)
-core = 1
-pktq_in = SWQ2
-pktq_out = SWQ0
-swap = 282 286 ; IPSRC <-> IPDST
-swap = 290 292 ; PORTSRC <-> PORTDST
-
-[PIPELINE5]
-type = PASS-THROUGH ; Loop-back (TCP place-holder)
-core = 1
-pktq_in = SWQ3
-pktq_out = SWQ1
-swap = 282 286 ; IPSRC <-> IPDST
-swap = 290 292 ; PORTSRC <-> PORTDST
-
-[PIPELINE6]
-type = PASS-THROUGH ; Drop (ICMP place-holder)
-core = 1
-pktq_in = RXQ0.3 RXQ1.3 RXQ2.3 RXQ3.3
-pktq_out = SINK4 SINK5 SINK6 SINK7
-
-[PIPELINE7]
-type = PASS-THROUGH ; Drop (Dynamic ARP place-holder)
-core = 1
-pktq_in = RXQ0.4 RXQ1.4 RXQ2.4 RXQ3.4
-pktq_out = SINK8 SINK9 SINK10 SINK11
diff --git a/examples/ip_pipeline/config/network_layers.sh b/examples/ip_pipeline/config/network_layers.sh
deleted file mode 100644
index 449b006..0000000
--- a/examples/ip_pipeline/config/network_layers.sh
+++ /dev/null
@@ -1,79 +0,0 @@
-#
-# run ./config/network_layers.sh
-#
-
-################################################################################
-# Link configuration
-################################################################################
-# Routes added implicitly when links are brought UP:
-# IP Prefix = 10.0.0.1/16 => (Port 0, Local)
-# IP Prefix = 10.0.0.1/32 => (Port 4, Local)
-# IP Prefix = 10.1.0.1/16 => (Port 1, Local)
-# IP Prefix = 10.1.0.1/32 => (Port 4, Local)
-# IP Prefix = 10.2.0.1/16 => (Port 2, Local)
-# IP Prefix = 10.2.0.1/32 => (Port 4, Local)
-# IP Prefix = 10.3.0.1/16 => (Port 3, Local)
-# IP Prefix = 10.3.0.1/32 => (Port 4, Local)
-link 0 down
-link 1 down
-link 2 down
-link 3 down
-link 0 config 10.0.0.1 16
-link 1 config 10.1.0.1 16
-link 2 config 10.2.0.1 16
-link 3 config 10.3.0.1 16
-link 0 up
-link 1 up
-link 2 up
-link 3 up
-#link ls
-
-################################################################################
-# Static ARP
-################################################################################
-p 1 arp add default 5 #SINK3
-p 1 arp add 0 10.0.0.2 a0:b0:c0:d0:e0:f0
-p 1 arp add 1 10.1.0.2 a1:b1:c1:d1:e1:f1
-p 1 arp add 2 10.2.0.2 a2:b2:c2:d2:e2:f2
-p 1 arp add 3 10.3.0.2 a3:b3:c3:d3:e3:f3
-#p 1 arp ls
-
-################################################################################
-# Routes
-################################################################################
-p 1 route add default 4 #SINK2
-p 1 route add 100.0.0.0 16 port 0 ether 10.0.0.2
-p 1 route add 100.1.0.0 16 port 1 ether 10.1.0.2
-p 1 route add 100.2.0.0 16 port 2 ether 10.2.0.2
-p 1 route add 100.3.0.0 16 port 3 ether 10.3.0.2
-#p 1 route ls
-
-################################################################################
-# Local destination UDP traffic
-################################################################################
-# Prio = Lowest: [SA = ANY, DA = ANY, SP = ANY, DP = ANY, PROTO = ANY] => Drop
-# Prio = 1 (High): [SA = ANY, DA = 10.0.0.1, SP = ANY, DP = 1000, PROTO = UDP] => Allow
-# Prio = 1 (High): [SA = ANY, DA = 10.1.0.1, SP = ANY, DP = 1001, PROTO = UDP] => Allow
-# Prio = 1 (High): [SA = ANY, DA = 10.2.0.1, SP = ANY, DP = 1002, PROTO = UDP] => Allow
-# Prio = 1 (High): [SA = ANY, DA = 10.3.0.1, SP = ANY, DP = 1003, PROTO = UDP] => Allow
-p 2 firewall add default 1 #SINK0
-p 2 firewall add priority 1 ipv4 0.0.0.0 0 10.0.0.1 32 0 65535 1000 1000 17 0xF port 0
-p 2 firewall add priority 1 ipv4 0.0.0.0 0 10.1.0.1 32 0 65535 1001 1001 17 0xF port 0
-p 2 firewall add priority 1 ipv4 0.0.0.0 0 10.2.0.1 32 0 65535 1002 1002 17 0xF port 0
-p 2 firewall add priority 1 ipv4 0.0.0.0 0 10.3.0.1 32 0 65535 1003 1003 17 0xF port 0
-#p 2 firewall ls
-
-################################################################################
-# Local destination TCP traffic
-################################################################################
-# Unknown connection => Drop
-# TCP [SA = 100.0.0.10, DA = 10.0.0.1, SP = 1000, DP = 80] => socket ID = 0
-# TCP [SA = 100.1.0.10, DA = 10.1.0.1, SP = 1001, DP = 80] => socket ID = 1
-# TCP [SA = 100.2.0.10, DA = 10.2.0.1, SP = 1002, DP = 80] => socket ID = 2
-# TCP [SA = 100.3.0.10, DA = 10.3.0.1, SP = 1003, DP = 80] => socket ID = 3
-p 3 flow add default 1 #SINK1
-p 3 flow add ipv4 100.0.0.10 10.0.0.1 1000 80 6 port 0 id 0
-p 3 flow add ipv4 100.1.0.10 10.1.0.1 1001 80 6 port 0 id 1
-p 3 flow add ipv4 100.2.0.10 10.2.0.1 1002 80 6 port 0 id 2
-p 3 flow add ipv4 100.3.0.10 10.3.0.1 1003 80 6 port 0 id 3
-#p 3 flow ls
diff --git a/examples/ip_pipeline/config/pipeline-to-core-mapping.py b/examples/ip_pipeline/config/pipeline-to-core-mapping.py
deleted file mode 100755
index fc52b2b..0000000
--- a/examples/ip_pipeline/config/pipeline-to-core-mapping.py
+++ /dev/null
@@ -1,906 +0,0 @@
-#!/usr/bin/env python
-# SPDX-License-Identifier: BSD-3-Clause
-# Copyright(c) 2016 Intel Corporation
-
-#
-# This script maps the set of pipelines identified (MASTER pipelines are
-# ignored) from the input configuration file to the set of cores
-# provided as input argument and creates configuration files for each of
-# the mapping combinations.
-#
-
-from __future__ import print_function
-from collections import namedtuple
-import argparse
-import array
-import errno
-import itertools
-import os
-import re
-import sys
-
-# default values
-enable_stage0_traceout = 1
-enable_stage1_traceout = 1
-enable_stage2_traceout = 1
-
-enable_stage1_fileout = 1
-enable_stage2_fileout = 1
-
-Constants = namedtuple('Constants', ['MAX_CORES', 'MAX_PIPELINES'])
-constants = Constants(16, 64)
-
-# pattern for physical core
-pattern_phycore = '^(s|S)\d(c|C)[1-9][0-9]*$'
-reg_phycore = re.compile(pattern_phycore)
-
-
-def popcount(mask):
-    return bin(mask).count("1")
-
-
-def len2mask(length):
-    if (length == 0):
-        return 0
-
-    if (length > 64):
-        sys.exit('error: len2mask - length %i > 64. exiting' % length)
-
-    return int('1' * length, 2)
-
-
-def bitstring_write(n, n_bits):
-    tmpstr = ""
-    if (n_bits > 64):
-        return
-
-    i = n_bits - 1
-    while (i >= 0):
-        cond = (n & (1 << i))
-        if (cond):
-            print('1', end='')
-            tmpstr += '1'
-        else:
-            print('0', end='')
-            tmpstr += '0'
-        i -= 1
-    return tmpstr
-
-
-class Cores0:
-
-    def __init__(self):
-        self.n_pipelines = 0
-
-
-class Cores1:
-
-    def __init__(self):
-        self.pipelines = 0
-        self.n_pipelines = 0
-
-
-class Cores2:
-
-    def __init__(self):
-        self.pipelines = 0
-        self.n_pipelines = 0
-        self.counter = 0
-        self.counter_max = 0
-        self.bitpos = array.array(
-            "L", itertools.repeat(0, constants.MAX_PIPELINES))
-
-
-class Context0:
-
-    def __init__(self):
-        self.cores = [Cores0() for i in range(0, constants.MAX_CORES)]
-        self.n_cores = 0
-        self.n_pipelines = 0
-        self.n_pipelines0 = 0
-        self.pos = 0
-        self.file_comment = ""
-        self.ctx1 = None
-        self.ctx2 = None
-
-    def stage0_print(self):
-        print('printing Context0 obj')
-        print('c0.cores(n_pipelines) = [ ', end='')
-        for cores_count in range(0, constants.MAX_CORES):
-            print(self.cores[cores_count].n_pipelines, end=' ')
-        print(']')
-        print('c0.n_cores = %d' % self.n_cores)
-        print('c0.n_pipelines = %d' % self.n_pipelines)
-        print('c0.n_pipelines0 = %d' % self.n_pipelines0)
-        print('c0.pos = %d' % self.pos)
-        print('c0.file_comment = %s' % self.file_comment)
-        if (self.ctx1 is not None):
-            print('c0.ctx1 = ', end='')
-            print(repr(self.ctx1))
-        else:
-            print('c0.ctx1 = None')
-
-        if (self.ctx2 is not None):
-            print('c0.ctx2 = ', end='')
-            print(repr(self.ctx2))
-        else:
-            print('c0.ctx2 = None')
-
-    def stage0_init(self, num_cores, num_pipelines, ctx1, ctx2):
-        self.n_cores = num_cores
-        self.n_pipelines = num_pipelines
-        self.ctx1 = ctx1
-        self.ctx2 = ctx2
-
-    def stage0_process(self):
-        # stage0 init
-        self.cores[0].n_pipelines = self.n_pipelines
-        self.n_pipelines0 = 0
-        self.pos = 1
-
-        while True:
-            # go forward
-            while True:
-                if ((self.pos < self.n_cores) and (self.n_pipelines0 > 0)):
-                    self.cores[self.pos].n_pipelines = min(
-                        self.cores[self.pos - 1].n_pipelines,
-                        self.n_pipelines0)
-                    self.n_pipelines0 -= self.cores[self.pos].n_pipelines
-                    self.pos += 1
-                else:
-                    break
-
-            # check solution
-            if (self.n_pipelines0 == 0):
-                self.stage0_log()
-                self.ctx1.stage1_init(self, self.ctx2)  # self is object c0
-                self.ctx1.stage1_process()
-
-            # go backward
-            while True:
-                if (self.pos == 0):
-                    return
-
-                self.pos -= 1
-                if ((self.cores[self.pos].n_pipelines > 1) and
-                        (self.pos != (self.n_cores - 1))):
-                    break
-
-                self.n_pipelines0 += self.cores[self.pos].n_pipelines
-                self.cores[self.pos].n_pipelines = 0
-
-            # rearm
-            self.cores[self.pos].n_pipelines -= 1
-            self.n_pipelines0 += 1
-            self.pos += 1
-
-    def stage0_log(self):
-        tmp_file_comment = ""
-        if(enable_stage0_traceout != 1):
-            return
-
-        print('STAGE0: ', end='')
-        tmp_file_comment += 'STAGE0: '
-        for cores_count in range(0, self.n_cores):
-            print('C%d = %d\t'
-                  % (cores_count,
-                      self.cores[cores_count].n_pipelines), end='')
-            tmp_file_comment += "C{} = {}\t".format(
-                cores_count, self.cores[cores_count].n_pipelines)
-        # end for
-        print('')
-        self.ctx1.stage0_file_comment = tmp_file_comment
-        self.ctx2.stage0_file_comment = tmp_file_comment
-
-
-class Context1:
-    _fileTrace = None
-
-    def __init__(self):
-        self.cores = [Cores1() for i in range(constants.MAX_CORES)]
-        self.n_cores = 0
-        self.n_pipelines = 0
-        self.pos = 0
-        self.stage0_file_comment = ""
-        self.stage1_file_comment = ""
-
-        self.ctx2 = None
-        self.arr_pipelines2cores = []
-
-    def stage1_reset(self):
-        for i in range(constants.MAX_CORES):
-            self.cores[i].pipelines = 0
-            self.cores[i].n_pipelines = 0
-
-        self.n_cores = 0
-        self.n_pipelines = 0
-        self.pos = 0
-        self.ctx2 = None
-        # clear list
-        del self.arr_pipelines2cores[:]
-
-    def stage1_print(self):
-        print('printing Context1 obj')
-        print('ctx1.cores(pipelines,n_pipelines) = [ ', end='')
-        for cores_count in range(0, constants.MAX_CORES):
-            print('(%d,%d)' % (self.cores[cores_count].pipelines,
-                               self.cores[cores_count].n_pipelines), end=' ')
-        print(']')
-        print('ctx1.n_cores = %d' % self.n_cores)
-        print('ctx1.n_pipelines = %d' % self.n_pipelines)
-        print('ctx1.pos = %d' % self.pos)
-        print('ctx1.stage0_file_comment = %s' % self.stage0_file_comment)
-        print('ctx1.stage1_file_comment = %s' % self.stage1_file_comment)
-        if (self.ctx2 is not None):
-            print('ctx1.ctx2 = ', end='')
-            print(self.ctx2)
-        else:
-            print('ctx1.ctx2 = None')
-
-    def stage1_init(self, c0, ctx2):
-        self.stage1_reset()
-        self.n_cores = 0
-        while (c0.cores[self.n_cores].n_pipelines > 0):
-            self.n_cores += 1
-
-        self.n_pipelines = c0.n_pipelines
-        self.ctx2 = ctx2
-
-        self.arr_pipelines2cores = [0] * self.n_pipelines
-
-        i = 0
-        while (i < self.n_cores):
-            self.cores[i].n_pipelines = c0.cores[i].n_pipelines
-            i += 1
-
-    def stage1_process(self):
-        pipelines_max = len2mask(self.n_pipelines)
-        while True:
-            pos = 0
-            overlap = 0
-
-            if (self.cores[self.pos].pipelines == pipelines_max):
-                if (self.pos == 0):
-                    return
-
-                self.cores[self.pos].pipelines = 0
-                self.pos -= 1
-                continue
-
-            self.cores[self.pos].pipelines += 1
-            if (popcount(self.cores[self.pos].pipelines) !=
-                    self.cores[self.pos].n_pipelines):
-                continue
-
-            overlap = 0
-            pos = 0
-            while (pos < self.pos):
-                if ((self.cores[self.pos].pipelines) &
-                        (self.cores[pos].pipelines)):
-                    overlap = 1
-                    break
-                pos += 1
-
-            if (overlap):
-                continue
-
-            if ((self.pos > 0) and
-                ((self.cores[self.pos].n_pipelines) ==
-                    (self.cores[self.pos - 1].n_pipelines)) and
-                    ((self.cores[self.pos].pipelines) <
-                        (self.cores[self.pos - 1].pipelines))):
-                continue
-
-            if (self.pos == self.n_cores - 1):
-                self.stage1_log()
-                self.ctx2.stage2_init(self)
-                self.ctx2.stage2_process()
-
-                if (self.pos == 0):
-                    return
-
-                self.cores[self.pos].pipelines = 0
-                self.pos -= 1
-                continue
-
-            self.pos += 1
-
-    def stage1_log(self):
-        tmp_file_comment = ""
-        if(enable_stage1_traceout == 1):
-            print('STAGE1: ', end='')
-            tmp_file_comment += 'STAGE1: '
-            i = 0
-            while (i < self.n_cores):
-                print('C%d = [' % i, end='')
-                tmp_file_comment += "C{} = [".format(i)
-
-                j = self.n_pipelines - 1
-                while (j >= 0):
-                    cond = ((self.cores[i].pipelines) & (1 << j))
-                    if (cond):
-                        print('1', end='')
-                        tmp_file_comment += '1'
-                    else:
-                        print('0', end='')
-                        tmp_file_comment += '0'
-                    j -= 1
-
-                print(']\t', end='')
-                tmp_file_comment += ']\t'
-                i += 1
-
-            print('\n', end='')
-            self.stage1_file_comment = tmp_file_comment
-            self.ctx2.stage1_file_comment = tmp_file_comment
-
-        # check if file traceing is enabled
-        if(enable_stage1_fileout != 1):
-            return
-
-        # spit out the combination to file
-        self.stage1_process_file()
-
-    def stage1_updateCoresInBuf(self, nPipeline, sCore):
-        rePipeline = self._fileTrace.arr_pipelines[nPipeline]
-        rePipeline = rePipeline.replace("[", "\[").replace("]", "\]")
-        reCore = 'core\s*=\s*((\d*)|(((s|S)\d)?(c|C)[1-9][0-9]*)).*\n'
-        sSubs = 'core = ' + sCore + '\n'
-
-        reg_pipeline = re.compile(rePipeline)
-        search_match = reg_pipeline.search(self._fileTrace.in_buf)
-
-        if(search_match):
-            pos = search_match.start()
-            substr1 = self._fileTrace.in_buf[:pos]
-            substr2 = self._fileTrace.in_buf[pos:]
-            substr2 = re.sub(reCore, sSubs, substr2, 1)
-            self._fileTrace.in_buf = substr1 + substr2
-
-    def stage1_process_file(self):
-        outFileName = os.path.join(self._fileTrace.out_path,
-                                   self._fileTrace.prefix_outfile)
-        outFileName += "_{}CoReS".format(self.n_cores)
-
-        i = 0  # represents core number
-        while (i < self.n_cores):
-            j = self.n_pipelines - 1
-            pipeline_idx = 0
-            while(j >= 0):
-                cond = ((self.cores[i].pipelines) & (1 << j))
-                if (cond):
-                    # update the pipelines array to match the core
-                    # only in case of cond match
-                    self.arr_pipelines2cores[
-                        pipeline_idx] = fileTrace.in_physical_cores[i]
-
-                j -= 1
-                pipeline_idx += 1
-
-            i += 1
-
-        # update the in_buf as per the arr_pipelines2cores
-        for pipeline_idx in range(len(self.arr_pipelines2cores)):
-            outFileName += "_{}".format(self.arr_pipelines2cores[pipeline_idx])
-            self.stage1_updateCoresInBuf(
-                pipeline_idx, self.arr_pipelines2cores[pipeline_idx])
-
-        # by now the in_buf is all set to be written to file
-        outFileName += self._fileTrace.suffix_outfile
-        outputFile = open(outFileName, "w")
-
-        # write out the comments
-        strTruncated = ("", "(Truncated)")[self._fileTrace.ncores_truncated]
-        outputFile.write(
-            "; =============== Pipeline-to-Core Mapping ================\n"
-            "; Generated from file {}\n"
-            "; Input pipelines = {}\n"
-            "; Input cores = {}\n"
-            "; N_PIPELINES = {} N_CORES = {} {} hyper_thread = {}\n"
-            .format(
-                self._fileTrace.in_file_namepath,
-                fileTrace.arr_pipelines,
-                fileTrace.in_physical_cores,
-                self._fileTrace.n_pipelines,
-                self._fileTrace.n_cores,
-                strTruncated,
-                self._fileTrace.hyper_thread))
-
-        outputFile.write(
-            "; {stg0cmt}\n"
-            "; {stg1cmt}\n"
-            "; ========================================================\n"
-            "; \n"
-            .format(
-                stg0cmt=self.stage0_file_comment,
-                stg1cmt=self.stage1_file_comment))
-
-        # write buffer contents
-        outputFile.write(self._fileTrace.in_buf)
-        outputFile.flush()
-        outputFile.close()
-
-
-class Context2:
-    _fileTrace = None
-
-    def __init__(self):
-        self.cores = [Cores2() for i in range(constants.MAX_CORES)]
-        self.n_cores = 0
-        self.n_pipelines = 0
-        self.pos = 0
-        self.stage0_file_comment = ""
-        self.stage1_file_comment = ""
-        self.stage2_file_comment = ""
-
-        # each array entry is a pipeline mapped to core stored as string
-        # pipeline ranging from 1 to n, however stored in zero based array
-        self.arr2_pipelines2cores = []
-
-    def stage2_print(self):
-        print('printing Context2 obj')
-        print('ctx2.cores(pipelines, n_pipelines, counter, counter_max) =')
-        for cores_count in range(0, constants.MAX_CORES):
-            print('core[%d] = (%d,%d,%d,%d)' % (
-                cores_count,
-                self.cores[cores_count].pipelines,
-                self.cores[cores_count].n_pipelines,
-                self.cores[cores_count].counter,
-                self.cores[cores_count].counter_max))
-
-            print('ctx2.n_cores = %d' % self.n_cores, end='')
-            print('ctx2.n_pipelines = %d' % self.n_pipelines, end='')
-            print('ctx2.pos = %d' % self.pos)
-            print('ctx2.stage0_file_comment = %s' %
-                  self.self.stage0_file_comment)
-            print('ctx2.stage1_file_comment = %s' %
-                  self.self.stage1_file_comment)
-            print('ctx2.stage2_file_comment = %s' %
-                  self.self.stage2_file_comment)
-
-    def stage2_reset(self):
-        for i in range(0, constants.MAX_CORES):
-            self.cores[i].pipelines = 0
-            self.cores[i].n_pipelines = 0
-            self.cores[i].counter = 0
-            self.cores[i].counter_max = 0
-
-            for idx in range(0, constants.MAX_PIPELINES):
-                self.cores[i].bitpos[idx] = 0
-
-        self.n_cores = 0
-        self.n_pipelines = 0
-        self.pos = 0
-        # clear list
-        del self.arr2_pipelines2cores[:]
-
-    def bitpos_load(self, coreidx):
-        i = j = 0
-        while (i < self.n_pipelines):
-            if ((self.cores[coreidx].pipelines) &
-                    (1 << i)):
-                self.cores[coreidx].bitpos[j] = i
-                j += 1
-            i += 1
-        self.cores[coreidx].n_pipelines = j
-
-    def bitpos_apply(self, in_buf, pos, n_pos):
-        out = 0
-        for i in range(0, n_pos):
-            out |= (in_buf & (1 << i)) << (pos[i] - i)
-
-        return out
-
-    def stage2_init(self, ctx1):
-        self.stage2_reset()
-        self.n_cores = ctx1.n_cores
-        self.n_pipelines = ctx1.n_pipelines
-
-        self.arr2_pipelines2cores = [''] * self.n_pipelines
-
-        core_idx = 0
-        while (core_idx < self.n_cores):
-            self.cores[core_idx].pipelines = ctx1.cores[core_idx].pipelines
-
-            self.bitpos_load(core_idx)
-            core_idx += 1
-
-    def stage2_log(self):
-        tmp_file_comment = ""
-        if(enable_stage2_traceout == 1):
-            print('STAGE2: ', end='')
-            tmp_file_comment += 'STAGE2: '
-
-            for i in range(0, self.n_cores):
-                mask = len2mask(self.cores[i].n_pipelines)
-                pipelines_ht0 = self.bitpos_apply(
-                    (~self.cores[i].counter) & mask,
-                    self.cores[i].bitpos,
-                    self.cores[i].n_pipelines)
-
-                pipelines_ht1 = self.bitpos_apply(
-                    self.cores[i].counter,
-                    self.cores[i].bitpos,
-                    self.cores[i].n_pipelines)
-
-                print('C%dHT0 = [' % i, end='')
-                tmp_file_comment += "C{}HT0 = [".format(i)
-                tmp_file_comment += bitstring_write(
-                    pipelines_ht0, self.n_pipelines)
-
-                print(']\tC%dHT1 = [' % i, end='')
-                tmp_file_comment += "]\tC{}HT1 = [".format(i)
-                tmp_file_comment += bitstring_write(
-                    pipelines_ht1, self.n_pipelines)
-                print(']\t', end='')
-                tmp_file_comment += ']\t'
-
-            print('')
-            self.stage2_file_comment = tmp_file_comment
-
-        # check if file traceing is enabled
-        if(enable_stage2_fileout != 1):
-            return
-        # spit out the combination to file
-        self.stage2_process_file()
-
-    def stage2_updateCoresInBuf(self, nPipeline, sCore):
-        rePipeline = self._fileTrace.arr_pipelines[nPipeline]
-        rePipeline = rePipeline.replace("[", "\[").replace("]", "\]")
-        reCore = 'core\s*=\s*((\d*)|(((s|S)\d)?(c|C)[1-9][0-9]*)).*\n'
-        sSubs = 'core = ' + sCore + '\n'
-
-        reg_pipeline = re.compile(rePipeline)
-        search_match = reg_pipeline.search(self._fileTrace.in_buf)
-
-        if(search_match):
-            pos = search_match.start()
-            substr1 = self._fileTrace.in_buf[:pos]
-            substr2 = self._fileTrace.in_buf[pos:]
-            substr2 = re.sub(reCore, sSubs, substr2, 1)
-            self._fileTrace.in_buf = substr1 + substr2
-
-    def pipelines2cores(self, n, n_bits, nCore, bHT):
-        if (n_bits > 64):
-            return
-
-        i = n_bits - 1
-        pipeline_idx = 0
-        while (i >= 0):
-            cond = (n & (1 << i))
-            if (cond):
-                # update the pipelines array to match the core
-                # only in case of cond match
-                # PIPELINE0 and core 0 are reserved
-                if(bHT):
-                    tmpCore = fileTrace.in_physical_cores[nCore] + 'h'
-                    self.arr2_pipelines2cores[pipeline_idx] = tmpCore
-                else:
-                    self.arr2_pipelines2cores[pipeline_idx] = \
-                        fileTrace.in_physical_cores[nCore]
-
-            i -= 1
-            pipeline_idx += 1
-
-    def stage2_process_file(self):
-        outFileName = os.path.join(self._fileTrace.out_path,
-                                   self._fileTrace.prefix_outfile)
-        outFileName += "_{}CoReS".format(self.n_cores)
-
-        for i in range(0, self.n_cores):
-            mask = len2mask(self.cores[i].n_pipelines)
-            pipelines_ht0 = self.bitpos_apply((~self.cores[i].counter) & mask,
-                                              self.cores[i].bitpos,
-                                              self.cores[i].n_pipelines)
-
-            pipelines_ht1 = self.bitpos_apply(self.cores[i].counter,
-                                              self.cores[i].bitpos,
-                                              self.cores[i].n_pipelines)
-
-            # update pipelines to core mapping
-            self.pipelines2cores(pipelines_ht0, self.n_pipelines, i, False)
-            self.pipelines2cores(pipelines_ht1, self.n_pipelines, i, True)
-
-        # update the in_buf as per the arr_pipelines2cores
-        for pipeline_idx in range(len(self.arr2_pipelines2cores)):
-            outFileName += "_{}".format(
-                self.arr2_pipelines2cores[pipeline_idx])
-            self.stage2_updateCoresInBuf(
-                pipeline_idx, self.arr2_pipelines2cores[pipeline_idx])
-
-        # by now the in_buf is all set to be written to file
-        outFileName += self._fileTrace.suffix_outfile
-        outputFile = open(outFileName, "w")
-
-        # write the file comments
-        strTruncated = ("", "(Truncated)")[self._fileTrace.ncores_truncated]
-        outputFile.write(
-            "; =============== Pipeline-to-Core Mapping ================\n"
-            "; Generated from file {}\n"
-            "; Input pipelines = {}\n"
-            "; Input cores = {}\n"
-            "; N_PIPELINES = {}  N_CORES = {} {} hyper_thread = {} \n"
-            .format(
-                self._fileTrace.in_file_namepath,
-                fileTrace.arr_pipelines,
-                fileTrace.in_physical_cores,
-                self._fileTrace.n_pipelines,
-                self._fileTrace.n_cores,
-                strTruncated,
-                self._fileTrace.hyper_thread))
-
-        outputFile.write(
-            "; {stg0cmt}\n"
-            "; {stg1cmt}\n"
-            "; {stg2cmt}\n"
-            "; ========================================================\n"
-            "; \n"
-            .format(
-                stg0cmt=self.stage0_file_comment,
-                stg1cmt=self.stage1_file_comment,
-                stg2cmt=self.stage2_file_comment))
-
-        # write the buffer contents
-        outputFile.write(self._fileTrace.in_buf)
-        outputFile.flush()
-        outputFile.close()
-
-    def stage2_process(self):
-        i = 0
-        while(i < self.n_cores):
-            self.cores[i].counter_max = len2mask(
-                self.cores[i].n_pipelines - 1)
-            i += 1
-
-        self.pos = self.n_cores - 1
-        while True:
-            if (self.pos == self.n_cores - 1):
-                self.stage2_log()
-
-            if (self.cores[self.pos].counter ==
-                    self.cores[self.pos].counter_max):
-                if (self.pos == 0):
-                    return
-
-                self.cores[self.pos].counter = 0
-                self.pos -= 1
-                continue
-
-            self.cores[self.pos].counter += 1
-            if(self.pos < self.n_cores - 1):
-                self.pos += 1
-
-
-class FileTrace:
-
-    def __init__(self, filenamepath):
-        self.in_file_namepath = os.path.abspath(filenamepath)
-        self.in_filename = os.path.basename(self.in_file_namepath)
-        self.in_path = os.path.dirname(self.in_file_namepath)
-
-        filenamesplit = self.in_filename.split('.')
-        self.prefix_outfile = filenamesplit[0]
-        self.suffix_outfile = ".cfg"
-
-        # output folder:  in the same folder as input file
-        # create new folder in the name of input file
-        self.out_path = os.path.join(
-            os.path.abspath(os.path.dirname(__file__)),
-            self.prefix_outfile)
-
-        try:
-            os.makedirs(self.out_path)
-        except OSError as excep:
-            if excep.errno == errno.EEXIST and os.path.isdir(self.out_path):
-                pass
-            else:
-                raise
-
-        self.in_buf = None
-        self.arr_pipelines = []  # holds the positions of search
-
-        self.max_cores = 15
-        self.max_pipelines = 15
-
-        self.in_physical_cores = None
-        self.hyper_thread = None
-
-        # save the num of pipelines determined from input file
-        self.n_pipelines = 0
-        # save the num of cores input (or the truncated value)
-        self.n_cores = 0
-        self.ncores_truncated = False
-
-    def print_TraceFile(self):
-        print("self.in_file_namepath = ", self.in_file_namepath)
-        print("self.in_filename = ", self.in_filename)
-        print("self.in_path = ", self.in_path)
-        print("self.out_path = ", self.out_path)
-        print("self.prefix_outfile = ", self.prefix_outfile)
-        print("self.suffix_outfile = ", self.suffix_outfile)
-        print("self.in_buf = ", self.in_buf)
-        print("self.arr_pipelines =", self.arr_pipelines)
-        print("self.in_physical_cores", self.in_physical_cores)
-        print("self.hyper_thread", self.hyper_thread)
-
-
-def process(n_cores, n_pipelines, fileTrace):
-    '''process and map pipelines, cores.'''
-    if (n_cores == 0):
-        sys.exit('N_CORES is 0, exiting')
-
-    if (n_pipelines == 0):
-        sys.exit('N_PIPELINES is 0, exiting')
-
-    if (n_cores > n_pipelines):
-        print('\nToo many cores, truncating N_CORES to N_PIPELINES')
-        n_cores = n_pipelines
-        fileTrace.ncores_truncated = True
-
-    fileTrace.n_pipelines = n_pipelines
-    fileTrace.n_cores = n_cores
-
-    strTruncated = ("", "(Truncated)")[fileTrace.ncores_truncated]
-    print("N_PIPELINES = {}, N_CORES = {} {}"
-          .format(n_pipelines, n_cores, strTruncated))
-    print("---------------------------------------------------------------")
-
-    ctx0_inst = Context0()
-    ctx1_inst = Context1()
-    ctx2_inst = Context2()
-
-    # initialize the class variables
-    ctx1_inst._fileTrace = fileTrace
-    ctx2_inst._fileTrace = fileTrace
-
-    ctx0_inst.stage0_init(n_cores, n_pipelines, ctx1_inst, ctx2_inst)
-    ctx0_inst.stage0_process()
-
-
-def validate_core(core):
-    match = reg_phycore.match(core)
-    if(match):
-        return True
-    else:
-        return False
-
-
-def validate_phycores(phy_cores):
-    '''validate physical cores, check if unique.'''
-    # eat up whitespaces
-    phy_cores = phy_cores.strip().split(',')
-
-    # check if the core list is unique
-    if(len(phy_cores) != len(set(phy_cores))):
-        print('list of physical cores has duplicates')
-        return None
-
-    for core in phy_cores:
-        if not validate_core(core):
-            print('invalid physical core specified.')
-            return None
-    return phy_cores
-
-
-def scanconfigfile(fileTrace):
-    '''scan input file for pipelines, validate then process.'''
-    # open file
-    filetoscan = open(fileTrace.in_file_namepath, 'r')
-    fileTrace.in_buf = filetoscan.read()
-
-    # reset iterator on open file
-    filetoscan.seek(0)
-
-    # scan input file for pipelines
-    # master pipelines to be ignored
-    pattern_pipeline = r'\[PIPELINE\d*\]'
-    pattern_mastertype = r'type\s*=\s*MASTER'
-
-    pending_pipeline = False
-    for line in filetoscan:
-        match_pipeline = re.search(pattern_pipeline, line)
-        match_type = re.search('type\s*=', line)
-        match_mastertype = re.search(pattern_mastertype, line)
-
-        if(match_pipeline):
-            sPipeline = line[match_pipeline.start():match_pipeline.end()]
-            pending_pipeline = True
-        elif(match_type):
-            # found a type definition...
-            if(match_mastertype is None):
-                # and this is not a master pipeline...
-                if(pending_pipeline):
-                    # add it to the list of pipelines to be mapped
-                    fileTrace.arr_pipelines.append(sPipeline)
-                    pending_pipeline = False
-            else:
-                # and this is a master pipeline...
-                # ignore the current and move on to next
-                sPipeline = ""
-                pending_pipeline = False
-    filetoscan.close()
-
-    # validate if pipelines are unique
-    if(len(fileTrace.arr_pipelines) != len(set(fileTrace.arr_pipelines))):
-        sys.exit('Error: duplicate pipelines in input file')
-
-    num_pipelines = len(fileTrace.arr_pipelines)
-    num_cores = len(fileTrace.in_physical_cores)
-
-    print("-------------------Pipeline-to-core mapping--------------------")
-    print("Input pipelines = {}\nInput cores = {}"
-          .format(fileTrace.arr_pipelines, fileTrace.in_physical_cores))
-
-    # input configuration file validations goes here
-    if (num_cores > fileTrace.max_cores):
-        sys.exit('Error: number of cores specified > max_cores (%d)' %
-                 fileTrace.max_cores)
-
-    if (num_pipelines > fileTrace.max_pipelines):
-        sys.exit('Error: number of pipelines in input \
-                cfg file > max_pipelines (%d)' % fileTrace.max_pipelines)
-
-    # call process to generate pipeline-to-core mapping, trace and log
-    process(num_cores, num_pipelines, fileTrace)
-
-
-if __name__ == "__main__":
-    parser = argparse.ArgumentParser(description='mappipelines')
-
-    reqNamedGrp = parser.add_argument_group('required named args')
-    reqNamedGrp.add_argument(
-        '-i',
-        '--input-file',
-        type=argparse.FileType('r'),
-        help='Input config file',
-        required=True)
-
-    reqNamedGrp.add_argument(
-        '-pc',
-        '--physical-cores',
-        type=validate_phycores,
-        help='''Enter available CPU cores in
-                format:\"<core>,<core>,...\"
-                where each core format: \"s<SOCKETID>c<COREID>\"
-                where SOCKETID={0..9}, COREID={1-99}''',
-        required=True)
-
-    # add optional arguments
-    parser.add_argument(
-        '-ht',
-        '--hyper-thread',
-        help='enable/disable hyper threading. default is ON',
-        default='ON',
-        choices=['ON', 'OFF'])
-
-    parser.add_argument(
-        '-nO',
-        '--no-output-file',
-        help='''disable output config file generation.
-                Output file generation is enabled by default''',
-        action="store_true")
-
-    args = parser.parse_args()
-
-    if(args.physical_cores is None):
-        parser.error("invalid physical_cores specified")
-
-    # create object of FileTrace and initialise
-    fileTrace = FileTrace(args.input_file.name)
-    fileTrace.in_physical_cores = args.physical_cores
-    fileTrace.hyper_thread = args.hyper_thread
-
-    if(fileTrace.hyper_thread == 'OFF'):
-        print("!!!!disabling stage2 HT!!!!")
-        enable_stage2_traceout = 0
-        enable_stage2_fileout = 0
-    elif(fileTrace.hyper_thread == 'ON'):
-        print("!!!!HT enabled. disabling stage1 file generation.!!!!")
-        enable_stage1_fileout = 0
-
-    if(args.no_output_file is True):
-        print("!!!!disabling stage1 and stage2 fileout!!!!")
-        enable_stage1_fileout = 0
-        enable_stage2_fileout = 0
-
-    scanconfigfile(fileTrace)
diff --git a/examples/ip_pipeline/config/tap.cfg b/examples/ip_pipeline/config/tap.cfg
deleted file mode 100644
index 10d35eb..0000000
--- a/examples/ip_pipeline/config/tap.cfg
+++ /dev/null
@@ -1,64 +0,0 @@
-;   BSD LICENSE
-;
-;   Copyright(c) 2016 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.
-
-;             ______________          ______________________
-;            |              |  TAP0  |                      |
-; RXQ0.0 --->|              |------->|--+                   |
-;            |              |  TAP1  |  | br0               |
-; TXQ1.0 <---|              |<-------|<-+                   |
-;            | Pass-through |        |     Linux Kernel     |
-;            |     (P1)     |        |     Network Stack    |
-;            |              |  TAP1  |                      |
-; RXQ1.0 --->|              |------->|--+                   |
-;            |              |  TAP0  |  | br0               |
-; TXQ0.0 <---|              |<-------|<-+                   |
-;            |______________|        |______________________|
-;
-; Configure Linux kernel bridge between TAP0 and TAP1 interfaces:
-;    [Linux]$ ifconfig TAP0 up
-;    [Linux]$ ifconfig TAP1 up
-;    [Linux]$ brctl addbr "br0"
-;    [Linux]$ brctl addif br0 TAP0
-;    [Linux]$ brctl addif br0 TAP1
-;    [Linux]$ ifconfig br0 up
-
-[EAL]
-log_level = 0
-
-[PIPELINE0]
-type = MASTER
-core = 0
-
-[PIPELINE1]
-type = PASS-THROUGH
-core = 1
-pktq_in = RXQ0.0 TAP1 RXQ1.0 TAP0
-pktq_out = TAP0 TXQ1.0 TAP1 TXQ0.0
diff --git a/examples/ip_pipeline/config/tm_profile.cfg b/examples/ip_pipeline/config/tm_profile.cfg
deleted file mode 100644
index 2dfb215..0000000
--- a/examples/ip_pipeline/config/tm_profile.cfg
+++ /dev/null
@@ -1,105 +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.
-
-; This file enables the following hierarchical scheduler configuration for each
-; 10GbE output port:
-;	* Single subport (subport 0):
-;		- Subport rate set to 100% of port rate
-;		- Each of the 4 traffic classes has rate set to 100% of port rate
-;	* 4K pipes per subport 0 (pipes 0 .. 4095) with identical configuration:
-;		- Pipe rate set to 1/4K of port rate
-;		- Each of the 4 traffic classes has rate set to 100% of pipe rate
-;		- Within each traffic class, the byte-level WRR weights for the 4 queues
-;         are set to 1:1:1:1
-;
-; For more details, please refer to chapter "Quality of Service (QoS) Framework"
-; of Data Plane Development Kit (DPDK) Programmer's Guide.
-
-; Port configuration
-[port]
-frame overhead = 24 ; frame overhead = Preamble (7) + SFD (1) + FCS (4) + IFG (12)
-mtu = 1522; mtu = Q-in-Q MTU (FCS not included)
-number of subports per port = 1
-number of pipes per subport = 4096
-queue sizes = 64 64 64 64
-
-; Subport configuration
-[subport 0]
-tb rate = 1250000000           ; Bytes per second
-tb size = 1000000              ; Bytes
-
-tc 0 rate = 1250000000         ; Bytes per second
-tc 1 rate = 1250000000         ; Bytes per second
-tc 2 rate = 1250000000         ; Bytes per second
-tc 3 rate = 1250000000         ; Bytes per second
-tc period = 10                 ; Milliseconds
-
-pipe 0-4095 = 0                ; These pipes are configured with pipe profile 0
-
-; Pipe configuration
-[pipe profile 0]
-tb rate = 305175               ; Bytes per second
-tb size = 1000000              ; Bytes
-
-tc 0 rate = 305175             ; Bytes per second
-tc 1 rate = 305175             ; Bytes per second
-tc 2 rate = 305175             ; Bytes per second
-tc 3 rate = 305175             ; Bytes per second
-tc period = 40                 ; Milliseconds
-
-tc 3 oversubscription weight = 1
-
-tc 0 wrr weights = 1 1 1 1
-tc 1 wrr weights = 1 1 1 1
-tc 2 wrr weights = 1 1 1 1
-tc 3 wrr weights = 1 1 1 1
-
-; RED params per traffic class and color (Green / Yellow / Red)
-[red]
-tc 0 wred min = 48 40 32
-tc 0 wred max = 64 64 64
-tc 0 wred inv prob = 10 10 10
-tc 0 wred weight = 9 9 9
-
-tc 1 wred min = 48 40 32
-tc 1 wred max = 64 64 64
-tc 1 wred inv prob = 10 10 10
-tc 1 wred weight = 9 9 9
-
-tc 2 wred min = 48 40 32
-tc 2 wred max = 64 64 64
-tc 2 wred inv prob = 10 10 10
-tc 2 wred weight = 9 9 9
-
-tc 3 wred min = 48 40 32
-tc 3 wred max = 64 64 64
-tc 3 wred inv prob = 10 10 10
-tc 3 wred weight = 9 9 9
-- 
2.9.3

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

* [dpdk-dev] [PATCH v2 17/44] ip_pipeline: rework and improvements
  2018-03-12 17:25   ` [dpdk-dev] [PATCH v2 00/44] ip_pipeline: refactoring Jasvinder Singh
                       ` (15 preceding siblings ...)
  2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 16/44] ip_pipeline: remove config Jasvinder Singh
@ 2018-03-12 17:25     ` Jasvinder Singh
  2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 18/44] ip_pipeline: add cli interface Jasvinder Singh
                       ` (26 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-12 17:25 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

All the actions associated with application pipelines
tables and ports are now implemented using the new action
APIs. Therefore, thousands of lines of code are eliminated
from the application. The reduced code size is easier to
maintain and extend.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/Makefile          |   22 +-
 examples/ip_pipeline/app.h             | 1389 -------------
 examples/ip_pipeline/config_check.c    |  488 -----
 examples/ip_pipeline/config_parse.c    | 3395 --------------------------------
 examples/ip_pipeline/config_parse_tm.c |  419 ----
 examples/ip_pipeline/cpu_core_map.c    |  471 -----
 examples/ip_pipeline/cpu_core_map.h    |   40 -
 examples/ip_pipeline/init.c            | 1343 -------------
 examples/ip_pipeline/main.c            |   36 +-
 examples/ip_pipeline/meson.build       |   10 +-
 examples/ip_pipeline/parser.c          |   16 +-
 examples/ip_pipeline/parser.h          |    8 +
 examples/ip_pipeline/pipeline.h        |   73 -
 examples/ip_pipeline/pipeline_be.h     |  322 ---
 examples/ip_pipeline/thread.c          |  240 ---
 examples/ip_pipeline/thread.h          |   69 -
 16 files changed, 37 insertions(+), 8304 deletions(-)
 delete mode 100644 examples/ip_pipeline/app.h
 delete mode 100644 examples/ip_pipeline/config_check.c
 delete mode 100644 examples/ip_pipeline/config_parse.c
 delete mode 100644 examples/ip_pipeline/config_parse_tm.c
 delete mode 100644 examples/ip_pipeline/cpu_core_map.c
 delete mode 100644 examples/ip_pipeline/cpu_core_map.h
 delete mode 100644 examples/ip_pipeline/init.c
 delete mode 100644 examples/ip_pipeline/pipeline.h
 delete mode 100644 examples/ip_pipeline/pipeline_be.h
 delete mode 100644 examples/ip_pipeline/thread.c
 delete mode 100644 examples/ip_pipeline/thread.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index 8ba7887..981c4f7 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -1,18 +1,13 @@
 # SPDX-License-Identifier: BSD-3-Clause
-# Copyright(c) 2010-2014 Intel Corporation
+# Copyright(c) 2010-2018 Intel Corporation
 
 # binary name
 APP = ip_pipeline
 
 # all source are stored in SRCS-y
 SRCS-y := main.c
-SRCS-y += config_parse.c
 SRCS-y += parser.c
-SRCS-y += config_parse_tm.c
-SRCS-y += config_check.c
-SRCS-y += init.c
-SRCS-y += thread.c
-SRCS-y += cpu_core_map.c
+#SRCS-y += thread.c
 
 # Build using pkg-config variables if possible
 $(shell pkg-config --exists libdpdk)
@@ -30,9 +25,7 @@ CFLAGS += -O3 $(shell pkg-config --cflags libdpdk)
 LDFLAGS_SHARED = $(shell pkg-config --libs libdpdk)
 LDFLAGS_STATIC = -Wl,-Bstatic $(shell pkg-config --static --libs libdpdk)
 
-VPATH += pipeline
-CFLAGS += -I. -I./pipeline/
-CFLAGS += -DALLOW_EXPERIMENTAL_API
+CFLAGS += -I.
 
 OBJS := $(patsubst %.c,build/%.o,$(SRCS-y))
 
@@ -59,21 +52,18 @@ ifeq ($(RTE_SDK),)
 $(error "Please define RTE_SDK environment variable")
 endif
 
-VPATH += $(SRCDIR)/pipeline
-
 # Default target, can be overridden by command line or environment
 RTE_TARGET ?= x86_64-native-linuxapp-gcc
 
 include $(RTE_SDK)/mk/rte.vars.mk
 
-INC += $(sort $(wildcard *.h)) $(sort $(wildcard pipeline/*.h))
+INC += $(sort $(wildcard *.h))
 
 SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) := $(SRCS-y)
 
-CFLAGS += -I$(SRCDIR) -I$(SRCDIR)/pipeline
+CFLAGS += -I$(SRCDIR)
 CFLAGS += -O3
-CFLAGS += $(WERROR_FLAGS) -Wno-error=unused-function -Wno-error=unused-variable
-CFLAGS += -DALLOW_EXPERIMENTAL_API
+CFLAGS += $(WERROR_FLAGS)
 
 include $(RTE_SDK)/mk/rte.extapp.mk
 
diff --git a/examples/ip_pipeline/app.h b/examples/ip_pipeline/app.h
deleted file mode 100644
index dadaf2b..0000000
--- a/examples/ip_pipeline/app.h
+++ /dev/null
@@ -1,1389 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2016 Intel Corporation
- */
-
-#ifndef __INCLUDE_APP_H__
-#define __INCLUDE_APP_H__
-
-#include <stdint.h>
-#include <string.h>
-
-#include <rte_common.h>
-#include <rte_mempool.h>
-#include <rte_ring.h>
-#include <rte_sched.h>
-#include <cmdline_parse.h>
-
-#include <rte_ethdev.h>
-#ifdef RTE_LIBRTE_KNI
-#include <rte_kni.h>
-#endif
-
-#include "cpu_core_map.h"
-#include "pipeline.h"
-
-#define APP_PARAM_NAME_SIZE                      PIPELINE_NAME_SIZE
-#define APP_LINK_PCI_BDF_SIZE                    16
-
-#ifndef APP_LINK_MAX_HWQ_IN
-#define APP_LINK_MAX_HWQ_IN                      128
-#endif
-
-#ifndef APP_LINK_MAX_HWQ_OUT
-#define APP_LINK_MAX_HWQ_OUT                     128
-#endif
-
-struct app_mempool_params {
-	char *name;
-	uint32_t parsed;
-	uint32_t buffer_size;
-	uint32_t pool_size;
-	uint32_t cache_size;
-	uint32_t cpu_socket_id;
-};
-
-struct app_link_params {
-	char *name;
-	uint32_t parsed;
-	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_q; /* 0 = Disabled (pkts go to default queue) */
-	uint32_t ip_local_q; /* 0 = Disabled (pkts go to default queue 0) */
-	uint32_t tcp_local_q; /* 0 = Disabled (pkts go to default queue 0) */
-	uint32_t udp_local_q; /* 0 = Disabled (pkts go to default queue 0) */
-	uint32_t sctp_local_q; /* 0 = Disabled (pkts go to default queue 0) */
-	uint32_t rss_qs[APP_LINK_MAX_HWQ_IN];
-	uint32_t n_rss_qs;
-	uint64_t rss_proto_ipv4;
-	uint64_t rss_proto_ipv6;
-	uint64_t rss_proto_l2;
-	uint32_t promisc;
-	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 */
-	char pci_bdf[APP_LINK_PCI_BDF_SIZE];
-
-	struct rte_eth_conf conf;
-};
-
-struct app_pktq_hwq_in_params {
-	char *name;
-	uint32_t parsed;
-	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;
-	uint32_t parsed;
-	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;
-	uint32_t parsed;
-	uint32_t size;
-	uint32_t burst_read;
-	uint32_t burst_write;
-	uint32_t dropless;
-	uint64_t n_retries;
-	uint32_t cpu_socket_id;
-	uint32_t ipv4_frag;
-	uint32_t ipv6_frag;
-	uint32_t ipv4_ras;
-	uint32_t ipv6_ras;
-	uint32_t mtu;
-	uint32_t metadata_size;
-	uint32_t mempool_direct_id;
-	uint32_t mempool_indirect_id;
-};
-
-struct app_pktq_kni_params {
-	char *name;
-	uint32_t parsed;
-
-	uint32_t socket_id;
-	uint32_t core_id;
-	uint32_t hyper_th_id;
-	uint32_t force_bind;
-
-	uint32_t mempool_id; /* Position in the app->mempool_params */
-	uint32_t burst_read;
-	uint32_t burst_write;
-	uint32_t dropless;
-	uint64_t n_retries;
-};
-
-#ifndef APP_FILE_NAME_SIZE
-#define APP_FILE_NAME_SIZE                       256
-#endif
-
-#ifndef APP_MAX_SCHED_SUBPORTS
-#define APP_MAX_SCHED_SUBPORTS                   8
-#endif
-
-#ifndef APP_MAX_SCHED_PIPES
-#define APP_MAX_SCHED_PIPES                      4096
-#endif
-
-struct app_pktq_tm_params {
-	char *name;
-	uint32_t parsed;
-	const char *file_name;
-	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_tap_params {
-	char *name;
-	uint32_t parsed;
-	uint32_t burst_read;
-	uint32_t burst_write;
-	uint32_t dropless;
-	uint64_t n_retries;
-	uint32_t mempool_id; /* Position in the app->mempool_params */
-};
-
-struct app_pktq_source_params {
-	char *name;
-	uint32_t parsed;
-	uint32_t mempool_id; /* Position in the app->mempool_params array */
-	uint32_t burst;
-	const char *file_name; /* Full path of PCAP file to be copied to mbufs */
-	uint32_t n_bytes_per_pkt;
-};
-
-struct app_pktq_sink_params {
-	char *name;
-	uint8_t parsed;
-	const char *file_name; /* Full path of PCAP file to be copied to mbufs */
-	uint32_t n_pkts_to_dump;
-};
-
-struct app_msgq_params {
-	char *name;
-	uint32_t parsed;
-	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_TAP,
-	APP_PKTQ_IN_KNI,
-	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_TAP,
-	APP_PKTQ_OUT_KNI,
-	APP_PKTQ_OUT_SINK,
-};
-
-struct app_pktq_out_params {
-	enum app_pktq_out_type type;
-	uint32_t id; /* Position in the appropriate app array */
-};
-
-#define APP_PIPELINE_TYPE_SIZE                   PIPELINE_TYPE_SIZE
-
-#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
-
-#define APP_MAX_PIPELINE_ARGS                    PIPELINE_MAX_ARGS
-
-struct app_pipeline_params {
-	char *name;
-	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_params;
-
-typedef void (*app_link_op)(struct app_params *app,
-	uint32_t link_id,
-	uint32_t up,
-	void *arg);
-
-#ifndef APP_MAX_PIPELINES
-#define APP_MAX_PIPELINES                        64
-#endif
-
-struct app_link_data {
-	app_link_op f_link[APP_MAX_PIPELINES];
-	void *arg[APP_MAX_PIPELINES];
-};
-
-struct app_pipeline_data {
-	void *be;
-	void *fe;
-	struct pipeline_type *ptype;
-	uint64_t timer_period;
-	uint32_t enabled;
-};
-
-struct app_thread_pipeline_data {
-	uint32_t pipeline_id;
-	void *be;
-	pipeline_be_op_run f_run;
-	pipeline_be_op_timer f_timer;
-	uint64_t timer_period;
-	uint64_t deadline;
-};
-
-#ifndef APP_MAX_THREAD_PIPELINES
-#define APP_MAX_THREAD_PIPELINES                 64
-#endif
-
-#ifndef APP_THREAD_TIMER_PERIOD
-#define APP_THREAD_TIMER_PERIOD                  1
-#endif
-
-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 timer_period;
-	uint64_t thread_req_deadline;
-
-	uint64_t deadline;
-
-	struct rte_ring *msgq_in;
-	struct rte_ring *msgq_out;
-
-	uint64_t headroom_time;
-	uint64_t headroom_cycles;
-	double headroom_ratio;
-} __rte_cache_aligned;
-
-#ifndef APP_MAX_LINKS
-#define APP_MAX_LINKS                            16
-#endif
-
-struct app_eal_params {
-	/* Map lcore set to physical cpu set */
-	char *coremap;
-
-	/* Core ID that is used as master */
-	uint32_t master_lcore_present;
-	uint32_t master_lcore;
-
-	/* Number of memory channels */
-	uint32_t channels_present;
-	uint32_t channels;
-
-	/* Memory to allocate (see also --socket-mem) */
-	uint32_t memory_present;
-	uint32_t memory;
-
-	/* Force number of memory ranks (don't detect) */
-	uint32_t ranks_present;
-	uint32_t ranks;
-
-	/* Add a PCI device in black list. */
-	char *pci_blacklist[APP_MAX_LINKS];
-
-	/* Add a PCI device in white list. */
-	char *pci_whitelist[APP_MAX_LINKS];
-
-	/* Add a virtual device. */
-	char *vdev[APP_MAX_LINKS];
-
-	 /* Use VMware TSC map instead of native RDTSC */
-	uint32_t vmware_tsc_map_present;
-	int vmware_tsc_map;
-
-	 /* Type of this process (primary|secondary|auto) */
-	char *proc_type;
-
-	 /* Set syslog facility */
-	char *syslog;
-
-	/* Set default log level */
-	uint32_t log_level_present;
-	uint32_t log_level;
-
-	/* Display version information on startup */
-	uint32_t version_present;
-	int version;
-
-	/* This help */
-	uint32_t help_present;
-	int help;
-
-	 /* Use malloc instead of hugetlbfs */
-	uint32_t no_huge_present;
-	int no_huge;
-
-	/* Disable PCI */
-	uint32_t no_pci_present;
-	int no_pci;
-
-	/* Disable HPET */
-	uint32_t no_hpet_present;
-	int no_hpet;
-
-	/* No shared config (mmap'd files) */
-	uint32_t no_shconf_present;
-	int no_shconf;
-
-	/* Add driver */
-	char *add_driver;
-
-	/*  Memory to allocate on sockets (comma separated values)*/
-	char *socket_mem;
-
-	/* Directory where hugetlbfs is mounted */
-	char *huge_dir;
-
-	/* Prefix for hugepage filenames */
-	char *file_prefix;
-
-	/* Base virtual address */
-	char *base_virtaddr;
-
-	/* Create /dev/uioX (usually done by hotplug) */
-	uint32_t create_uio_dev_present;
-	int create_uio_dev;
-
-	/* Interrupt mode for VFIO (legacy|msi|msix) */
-	char *vfio_intr;
-
-	uint32_t parsed;
-};
-
-#ifndef APP_APPNAME_SIZE
-#define APP_APPNAME_SIZE                         256
-#endif
-
-#ifndef APP_MAX_MEMPOOLS
-#define APP_MAX_MEMPOOLS                         8
-#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_TAP
-#define APP_MAX_PKTQ_TAP                         APP_MAX_LINKS
-#endif
-
-#define APP_MAX_PKTQ_KNI                         APP_MAX_LINKS
-
-#ifndef APP_MAX_PKTQ_SOURCE
-#define APP_MAX_PKTQ_SOURCE                      64
-#endif
-
-#ifndef APP_MAX_PKTQ_SINK
-#define APP_MAX_PKTQ_SINK                        64
-#endif
-
-#ifndef APP_MAX_MSGQ
-#define APP_MAX_MSGQ                             256
-#endif
-
-#ifndef APP_EAL_ARGC
-#define APP_EAL_ARGC                             64
-#endif
-
-#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
-
-#ifndef APP_THREAD_HEADROOM_STATS_COLLECT
-#define APP_THREAD_HEADROOM_STATS_COLLECT        1
-#endif
-
-#define APP_CORE_MASK_SIZE					\
-	(RTE_MAX_LCORE / 64 + ((RTE_MAX_LCORE % 64) ? 1 : 0))
-
-struct app_params {
-	/* Config */
-	char app_name[APP_APPNAME_SIZE];
-	const char *config_file;
-	const char *script_file;
-	const char *parser_file;
-	const char *output_file;
-	const char *preproc;
-	const char *preproc_args;
-	uint64_t port_mask;
-	uint32_t log_level;
-
-	struct app_eal_params eal_params;
-	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_tap_params tap_params[APP_MAX_PKTQ_TAP];
-	struct app_pktq_kni_params kni_params[APP_MAX_PKTQ_KNI];
-	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_tap;
-	uint32_t n_pktq_kni;
-	uint32_t n_pktq_source;
-	uint32_t n_pktq_sink;
-	uint32_t n_msgq;
-	uint32_t n_pipelines;
-
-	/* Init */
-	char *eal_argv[1 + APP_EAL_ARGC];
-	struct cpu_core_map *core_map;
-	uint64_t core_mask[APP_CORE_MASK_SIZE];
-	struct rte_mempool *mempool[APP_MAX_MEMPOOLS];
-	struct app_link_data link_data[APP_MAX_LINKS];
-	struct rte_ring *swq[APP_MAX_PKTQ_SWQ];
-	struct rte_sched_port *tm[APP_MAX_PKTQ_TM];
-	int tap[APP_MAX_PKTQ_TAP];
-#ifdef RTE_LIBRTE_KNI
-	struct rte_kni *kni[APP_MAX_PKTQ_KNI];
-#endif /* RTE_LIBRTE_KNI */
-	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];
-
-	int eal_argc;
-	uint32_t n_pipeline_types;
-	uint32_t n_cmds;
-};
-
-#define APP_PARAM_VALID(obj) ((obj)->name != NULL)
-
-#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++;					\
-}
-
-#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 "%" PRIu32, 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 "%" SCNu32, &id);				\
-while (0)								\
-
-#define	APP_CHECK(exp, fmt, ...)					\
-do {									\
-	if (!(exp)) {							\
-		fprintf(stderr, fmt "\n", ## __VA_ARGS__);		\
-		abort();						\
-	}								\
-} while (0)
-
-enum app_log_level {
-	APP_LOG_LEVEL_HIGH = 1,
-	APP_LOG_LEVEL_LOW,
-	APP_LOG_LEVELS
-};
-
-#define APP_LOG(app, level, fmt, ...)					\
-do {									\
-	if (app->log_level >= APP_LOG_LEVEL_ ## level)			\
-		fprintf(stdout, "[APP] " fmt "\n", ## __VA_ARGS__);	\
-} while (0)
-
-static inline uint32_t
-app_link_get_n_rxq(struct app_params *app, struct app_link_params *link)
-{
-	uint32_t n_rxq = 0, link_id, i;
-	uint32_t n_pktq_hwq_in = RTE_MIN(app->n_pktq_hwq_in,
-		RTE_DIM(app->hwq_in_params));
-
-	APP_PARAM_GET_ID(link, "LINK", link_id);
-
-	for (i = 0; i < n_pktq_hwq_in; i++) {
-		struct app_pktq_hwq_in_params *p = &app->hwq_in_params[i];
-		uint32_t rxq_link_id, rxq_queue_id;
-
-		sscanf(p->name, "RXQ%" SCNu32 ".%" SCNu32,
-			&rxq_link_id, &rxq_queue_id);
-		if (rxq_link_id == link_id)
-			n_rxq++;
-	}
-
-	return n_rxq;
-}
-
-static inline uint32_t
-app_link_get_n_txq(struct app_params *app, struct app_link_params *link)
-{
-	uint32_t n_txq = 0, link_id, i;
-	uint32_t n_pktq_hwq_out = RTE_MIN(app->n_pktq_hwq_out,
-		RTE_DIM(app->hwq_out_params));
-
-	APP_PARAM_GET_ID(link, "LINK", link_id);
-
-	for (i = 0; i < n_pktq_hwq_out; i++) {
-		struct app_pktq_hwq_out_params *p = &app->hwq_out_params[i];
-		uint32_t txq_link_id, txq_queue_id;
-
-		sscanf(p->name, "TXQ%" SCNu32 ".%" SCNu32,
-			&txq_link_id, &txq_queue_id);
-		if (txq_link_id == link_id)
-			n_txq++;
-	}
-
-	return n_txq;
-}
-
-static inline uint32_t
-app_rxq_get_readers(struct app_params *app, struct app_pktq_hwq_in_params *rxq)
-{
-	uint32_t pos = rxq - app->hwq_in_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_readers = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_in = RTE_MIN(p->n_pktq_in, RTE_DIM(p->pktq_in));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_in; j++) {
-			struct app_pktq_in_params *pktq = &p->pktq_in[j];
-
-			if ((pktq->type == APP_PKTQ_IN_HWQ) &&
-				(pktq->id == pos))
-				n_readers++;
-		}
-	}
-
-	return n_readers;
-}
-
-static inline uint32_t
-app_swq_get_readers(struct app_params *app, struct app_pktq_swq_params *swq)
-{
-	uint32_t pos = swq - app->swq_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_readers = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_in = RTE_MIN(p->n_pktq_in, RTE_DIM(p->pktq_in));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_in; j++) {
-			struct app_pktq_in_params *pktq = &p->pktq_in[j];
-
-			if ((pktq->type == APP_PKTQ_IN_SWQ) &&
-				(pktq->id == pos))
-				n_readers++;
-		}
-	}
-
-	return n_readers;
-}
-
-static inline struct app_pipeline_params *
-app_swq_get_reader(struct app_params *app,
-	struct app_pktq_swq_params *swq,
-	uint32_t *pktq_in_id)
-{
-	struct app_pipeline_params *reader = NULL;
-	uint32_t pos = swq - app->swq_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_readers = 0, id = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_in = RTE_MIN(p->n_pktq_in, RTE_DIM(p->pktq_in));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_in; j++) {
-			struct app_pktq_in_params *pktq = &p->pktq_in[j];
-
-			if ((pktq->type == APP_PKTQ_IN_SWQ) &&
-				(pktq->id == pos)) {
-				n_readers++;
-				reader = p;
-				id = j;
-			}
-		}
-	}
-
-	if (n_readers != 1)
-		return NULL;
-
-	*pktq_in_id = id;
-	return reader;
-}
-
-static inline uint32_t
-app_tm_get_readers(struct app_params *app, struct app_pktq_tm_params *tm)
-{
-	uint32_t pos = tm - app->tm_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_readers = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_in = RTE_MIN(p->n_pktq_in, RTE_DIM(p->pktq_in));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_in; j++) {
-			struct app_pktq_in_params *pktq = &p->pktq_in[j];
-
-			if ((pktq->type == APP_PKTQ_IN_TM) &&
-				(pktq->id == pos))
-				n_readers++;
-		}
-	}
-
-	return n_readers;
-}
-
-static inline struct app_pipeline_params *
-app_tm_get_reader(struct app_params *app,
-	struct app_pktq_tm_params *tm,
-	uint32_t *pktq_in_id)
-{
-	struct app_pipeline_params *reader = NULL;
-	uint32_t pos = tm - app->tm_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_readers = 0, id = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_in = RTE_MIN(p->n_pktq_in, RTE_DIM(p->pktq_in));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_in; j++) {
-			struct app_pktq_in_params *pktq = &p->pktq_in[j];
-
-			if ((pktq->type == APP_PKTQ_IN_TM) &&
-				(pktq->id == pos)) {
-				n_readers++;
-				reader = p;
-				id = j;
-			}
-		}
-	}
-
-	if (n_readers != 1)
-		return NULL;
-
-	*pktq_in_id = id;
-	return reader;
-}
-
-static inline uint32_t
-app_tap_get_readers(struct app_params *app, struct app_pktq_tap_params *tap)
-{
-	uint32_t pos = tap - app->tap_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_readers = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_in = RTE_MIN(p->n_pktq_in, RTE_DIM(p->pktq_in));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_in; j++) {
-			struct app_pktq_in_params *pktq = &p->pktq_in[j];
-
-			if ((pktq->type == APP_PKTQ_IN_TAP) &&
-				(pktq->id == pos))
-				n_readers++;
-		}
-	}
-
-	return n_readers;
-}
-
-static inline struct app_pipeline_params *
-app_tap_get_reader(struct app_params *app,
-	struct app_pktq_tap_params *tap,
-	uint32_t *pktq_in_id)
-{
-	struct app_pipeline_params *reader = NULL;
-	uint32_t pos = tap - app->tap_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_readers = 0, id = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_in = RTE_MIN(p->n_pktq_in, RTE_DIM(p->pktq_in));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_in; j++) {
-			struct app_pktq_in_params *pktq = &p->pktq_in[j];
-
-			if ((pktq->type == APP_PKTQ_IN_TAP) &&
-				(pktq->id == pos)) {
-				n_readers++;
-				reader = p;
-				id = j;
-			}
-		}
-	}
-
-	if (n_readers != 1)
-		return NULL;
-
-	*pktq_in_id = id;
-	return reader;
-}
-
-static inline uint32_t
-app_kni_get_readers(struct app_params *app, struct app_pktq_kni_params *kni)
-{
-	uint32_t pos = kni - app->kni_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_readers = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_in = RTE_MIN(p->n_pktq_in, RTE_DIM(p->pktq_in));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_in; j++) {
-			struct app_pktq_in_params *pktq = &p->pktq_in[j];
-
-			if ((pktq->type == APP_PKTQ_IN_KNI) &&
-				(pktq->id == pos))
-				n_readers++;
-		}
-	}
-
-	return n_readers;
-}
-
-static inline struct app_pipeline_params *
-app_kni_get_reader(struct app_params *app,
-				  struct app_pktq_kni_params *kni,
-				  uint32_t *pktq_in_id)
-{
-	struct app_pipeline_params *reader = NULL;
-	uint32_t pos = kni - app->kni_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_readers = 0, id = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_in = RTE_MIN(p->n_pktq_in, RTE_DIM(p->pktq_in));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_in; j++) {
-			struct app_pktq_in_params *pktq = &p->pktq_in[j];
-
-			if ((pktq->type == APP_PKTQ_IN_KNI) &&
-				(pktq->id == pos)) {
-				n_readers++;
-				reader = p;
-				id = j;
-			}
-		}
-	}
-
-	if (n_readers != 1)
-		return NULL;
-
-	*pktq_in_id = id;
-	return reader;
-}
-
-static inline uint32_t
-app_source_get_readers(struct app_params *app,
-struct app_pktq_source_params *source)
-{
-	uint32_t pos = source - app->source_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_readers = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_in = RTE_MIN(p->n_pktq_in, RTE_DIM(p->pktq_in));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_in; j++) {
-			struct app_pktq_in_params *pktq = &p->pktq_in[j];
-
-			if ((pktq->type == APP_PKTQ_IN_SOURCE) &&
-				(pktq->id == pos))
-				n_readers++;
-		}
-	}
-
-	return n_readers;
-}
-
-static inline uint32_t
-app_msgq_get_readers(struct app_params *app, struct app_msgq_params *msgq)
-{
-	uint32_t pos = msgq - app->msgq_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_readers = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_msgq_in = RTE_MIN(p->n_msgq_in, RTE_DIM(p->msgq_in));
-		uint32_t j;
-
-		for (j = 0; j < n_msgq_in; j++)
-			if (p->msgq_in[j] == pos)
-				n_readers++;
-	}
-
-	return n_readers;
-}
-
-static inline uint32_t
-app_txq_get_writers(struct app_params *app, struct app_pktq_hwq_out_params *txq)
-{
-	uint32_t pos = txq - app->hwq_out_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_writers = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_out = RTE_MIN(p->n_pktq_out,
-			RTE_DIM(p->pktq_out));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_out; j++) {
-			struct app_pktq_out_params *pktq = &p->pktq_out[j];
-
-			if ((pktq->type == APP_PKTQ_OUT_HWQ) &&
-				(pktq->id == pos))
-				n_writers++;
-		}
-	}
-
-	return n_writers;
-}
-
-static inline uint32_t
-app_swq_get_writers(struct app_params *app, struct app_pktq_swq_params *swq)
-{
-	uint32_t pos = swq - app->swq_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_writers = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_out = RTE_MIN(p->n_pktq_out,
-			RTE_DIM(p->pktq_out));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_out; j++) {
-			struct app_pktq_out_params *pktq = &p->pktq_out[j];
-
-			if ((pktq->type == APP_PKTQ_OUT_SWQ) &&
-				(pktq->id == pos))
-				n_writers++;
-		}
-	}
-
-	return n_writers;
-}
-
-static inline struct app_pipeline_params *
-app_swq_get_writer(struct app_params *app,
-	struct app_pktq_swq_params *swq,
-	uint32_t *pktq_out_id)
-{
-	struct app_pipeline_params *writer = NULL;
-	uint32_t pos = swq - app->swq_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_writers = 0, id = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_out = RTE_MIN(p->n_pktq_out,
-			RTE_DIM(p->pktq_out));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_out; j++) {
-			struct app_pktq_out_params *pktq = &p->pktq_out[j];
-
-			if ((pktq->type == APP_PKTQ_OUT_SWQ) &&
-				(pktq->id == pos)) {
-				n_writers++;
-				writer = p;
-				id = j;
-			}
-		}
-	}
-
-	if (n_writers != 1)
-		return NULL;
-
-	*pktq_out_id = id;
-	return writer;
-}
-
-static inline uint32_t
-app_tm_get_writers(struct app_params *app, struct app_pktq_tm_params *tm)
-{
-	uint32_t pos = tm - app->tm_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_writers = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_out = RTE_MIN(p->n_pktq_out,
-			RTE_DIM(p->pktq_out));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_out; j++) {
-			struct app_pktq_out_params *pktq = &p->pktq_out[j];
-
-			if ((pktq->type == APP_PKTQ_OUT_TM) &&
-				(pktq->id == pos))
-				n_writers++;
-		}
-	}
-
-	return n_writers;
-}
-
-static inline struct app_pipeline_params *
-app_tm_get_writer(struct app_params *app,
-	struct app_pktq_tm_params *tm,
-	uint32_t *pktq_out_id)
-{
-	struct app_pipeline_params *writer = NULL;
-	uint32_t pos = tm - app->tm_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_writers = 0, id = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_out = RTE_MIN(p->n_pktq_out,
-			RTE_DIM(p->pktq_out));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_out; j++) {
-			struct app_pktq_out_params *pktq = &p->pktq_out[j];
-
-			if ((pktq->type == APP_PKTQ_OUT_TM) &&
-				(pktq->id == pos)) {
-				n_writers++;
-				writer = p;
-				id = j;
-			}
-		}
-	}
-
-	if (n_writers != 1)
-		return NULL;
-
-	*pktq_out_id = id;
-	return writer;
-}
-
-static inline uint32_t
-app_tap_get_writers(struct app_params *app, struct app_pktq_tap_params *tap)
-{
-	uint32_t pos = tap - app->tap_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_writers = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_out = RTE_MIN(p->n_pktq_out,
-			RTE_DIM(p->pktq_out));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_out; j++) {
-			struct app_pktq_out_params *pktq = &p->pktq_out[j];
-
-		if ((pktq->type == APP_PKTQ_OUT_TAP) &&
-			(pktq->id == pos))
-			n_writers++;
-		}
-	}
-
-	return n_writers;
-}
-
-static inline struct app_pipeline_params *
-app_tap_get_writer(struct app_params *app,
-	struct app_pktq_tap_params *tap,
-	uint32_t *pktq_out_id)
-{
-	struct app_pipeline_params *writer = NULL;
-	uint32_t pos = tap - app->tap_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_writers = 0, id = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_out = RTE_MIN(p->n_pktq_out,
-			RTE_DIM(p->pktq_out));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_out; j++) {
-			struct app_pktq_out_params *pktq = &p->pktq_out[j];
-
-			if ((pktq->type == APP_PKTQ_OUT_TAP) &&
-				(pktq->id == pos)) {
-				n_writers++;
-				writer = p;
-				id = j;
-			}
-		}
-	}
-
-	if (n_writers != 1)
-		return NULL;
-
-	*pktq_out_id = id;
-	return writer;
-}
-
-static inline uint32_t
-app_kni_get_writers(struct app_params *app, struct app_pktq_kni_params *kni)
-{
-	uint32_t pos = kni - app->kni_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_writers = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_out = RTE_MIN(p->n_pktq_out,
-			RTE_DIM(p->pktq_out));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_out; j++) {
-			struct app_pktq_out_params *pktq = &p->pktq_out[j];
-
-			if ((pktq->type == APP_PKTQ_OUT_KNI) &&
-				(pktq->id == pos))
-				n_writers++;
-		}
-	}
-
-	return n_writers;
-}
-
-static inline struct app_pipeline_params *
-app_kni_get_writer(struct app_params *app,
-				  struct app_pktq_kni_params *kni,
-				  uint32_t *pktq_out_id)
-{
-	struct app_pipeline_params *writer = NULL;
-	uint32_t pos = kni - app->kni_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_writers = 0, id = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_out = RTE_MIN(p->n_pktq_out,
-			RTE_DIM(p->pktq_out));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_out; j++) {
-			struct app_pktq_out_params *pktq = &p->pktq_out[j];
-
-			if ((pktq->type == APP_PKTQ_OUT_KNI) &&
-				(pktq->id == pos)) {
-				n_writers++;
-				writer = p;
-				id = j;
-			}
-		}
-	}
-
-	if (n_writers != 1)
-		return NULL;
-
-	*pktq_out_id = id;
-	return writer;
-}
-
-static inline uint32_t
-app_sink_get_writers(struct app_params *app, struct app_pktq_sink_params *sink)
-{
-	uint32_t pos = sink - app->sink_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_writers = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_out = RTE_MIN(p->n_pktq_out,
-			RTE_DIM(p->pktq_out));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_out; j++) {
-			struct app_pktq_out_params *pktq = &p->pktq_out[j];
-
-			if ((pktq->type == APP_PKTQ_OUT_SINK) &&
-				(pktq->id == pos))
-				n_writers++;
-		}
-	}
-
-	return n_writers;
-}
-
-static inline uint32_t
-app_msgq_get_writers(struct app_params *app, struct app_msgq_params *msgq)
-{
-	uint32_t pos = msgq - app->msgq_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_writers = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_msgq_out = RTE_MIN(p->n_msgq_out,
-			RTE_DIM(p->msgq_out));
-		uint32_t j;
-
-		for (j = 0; j < n_msgq_out; j++)
-			if (p->msgq_out[j] == pos)
-				n_writers++;
-	}
-
-	return n_writers;
-}
-
-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%" SCNu32 ".%" SCNu32,
-		&rxq_link_id, &rxq_queue_id);
-	sprintf(link_name, "LINK%" PRIu32, 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%" SCNu32 ".%" SCNu32,
-		&txq_link_id, &txq_queue_id);
-	sprintf(link_name, "LINK%" PRIu32, 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%" PRIu32, &link_id);
-	sprintf(link_name, "LINK%" PRIu32, 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];
-}
-
-static inline struct app_link_params *
-app_get_link_for_kni(struct app_params *app, struct app_pktq_kni_params *p_kni)
-{
-	char link_name[APP_PARAM_NAME_SIZE];
-	uint32_t link_id;
-	ssize_t link_param_idx;
-
-	sscanf(p_kni->name, "KNI%" PRIu32, &link_id);
-	sprintf(link_name, "LINK%" PRIu32, 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_kni->name);
-
-	return &app->link_params[link_param_idx];
-}
-
-static inline uint32_t
-app_core_is_enabled(struct app_params *app, uint32_t lcore_id)
-{
-	return(app->core_mask[lcore_id / 64] &
-		(1LLU << (lcore_id % 64)));
-}
-
-static inline void
-app_core_enable_in_core_mask(struct app_params *app, int lcore_id)
-{
-	app->core_mask[lcore_id / 64] |= 1LLU << (lcore_id % 64);
-
-}
-
-static inline void
-app_core_build_core_mask_string(struct app_params *app, char *mask_buffer)
-{
-	int i;
-
-	mask_buffer[0] = '\0';
-	for (i = (int)RTE_DIM(app->core_mask); i > 0; i--) {
-		/* For Hex representation of bits in uint64_t */
-		char buffer[(64 / 8) * 2 + 1];
-		memset(buffer, 0, sizeof(buffer));
-		snprintf(buffer, sizeof(buffer), "%016" PRIx64,
-			 app->core_mask[i-1]);
-		strcat(mask_buffer, buffer);
-	}
-}
-
-int app_config_init(struct app_params *app);
-
-int app_config_args(struct app_params *app,
-	int argc, char **argv);
-
-int app_config_preproc(struct app_params *app);
-
-int app_config_parse(struct app_params *app,
-	const char *file_name);
-
-int app_config_parse_tm(struct app_params *app);
-
-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);
-
-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_check.c b/examples/ip_pipeline/config_check.c
deleted file mode 100644
index 86d1191..0000000
--- a/examples/ip_pipeline/config_check.c
+++ /dev/null
@@ -1,488 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2016 Intel Corporation
- */
-
-#include <stdio.h>
-
-#include <rte_ip.h>
-
-#include "app.h"
-
-static void
-check_mempools(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_mempools; i++) {
-		struct app_mempool_params *p = &app->mempool_params[i];
-
-		APP_CHECK((p->pool_size > 0),
-			"Mempool %s size is 0\n", p->name);
-
-		APP_CHECK((p->cache_size > 0),
-			"Mempool %s cache size is 0\n", p->name);
-
-		APP_CHECK(rte_is_power_of_2(p->cache_size),
-			"Mempool %s cache size not a power of 2\n", p->name);
-	}
-}
-
-static inline uint32_t
-link_rxq_used(struct app_link_params *link, uint32_t q_id)
-{
-	uint32_t i;
-
-	if ((link->arp_q == q_id) ||
-		(link->tcp_syn_q == q_id) ||
-		(link->ip_local_q == q_id) ||
-		(link->tcp_local_q == q_id) ||
-		(link->udp_local_q == q_id) ||
-		(link->sctp_local_q == q_id))
-		return 1;
-
-	for (i = 0; i < link->n_rss_qs; i++)
-		if (link->rss_qs[i] == q_id)
-			return 1;
-
-	return 0;
-}
-
-static void
-check_links(struct app_params *app)
-{
-	uint32_t i;
-
-	/* Check that number of links matches the port mask */
-	if (app->port_mask) {
-		uint32_t n_links_port_mask =
-			__builtin_popcountll(app->port_mask);
-
-		APP_CHECK((app->n_links == n_links_port_mask),
-			"Not enough links provided in the PORT_MASK\n");
-	}
-
-	for (i = 0; i < app->n_links; i++) {
-		struct app_link_params *link = &app->link_params[i];
-		uint32_t rxq_max, n_rxq, n_txq, link_id, i;
-
-		APP_PARAM_GET_ID(link, "LINK", link_id);
-
-		/* Check that link RXQs are contiguous */
-		rxq_max = 0;
-		if (link->arp_q > rxq_max)
-			rxq_max = link->arp_q;
-		if (link->tcp_syn_q > rxq_max)
-			rxq_max = link->tcp_syn_q;
-		if (link->ip_local_q > rxq_max)
-			rxq_max = link->ip_local_q;
-		if (link->tcp_local_q > rxq_max)
-			rxq_max = link->tcp_local_q;
-		if (link->udp_local_q > rxq_max)
-			rxq_max = link->udp_local_q;
-		if (link->sctp_local_q > rxq_max)
-			rxq_max = link->sctp_local_q;
-		for (i = 0; i < link->n_rss_qs; i++)
-			if (link->rss_qs[i] > rxq_max)
-				rxq_max = link->rss_qs[i];
-
-		for (i = 1; i <= rxq_max; i++)
-			APP_CHECK((link_rxq_used(link, i)),
-				"%s RXQs are not contiguous (A)\n", link->name);
-
-		n_rxq = app_link_get_n_rxq(app, link);
-
-		APP_CHECK((n_rxq), "%s does not have any RXQ\n", link->name);
-
-		APP_CHECK((n_rxq == rxq_max + 1),
-			"%s RXQs are not contiguous (B)\n", link->name);
-
-		for (i = 0; i < n_rxq; i++) {
-			char name[APP_PARAM_NAME_SIZE];
-			int pos;
-
-			sprintf(name, "RXQ%" PRIu32 ".%" PRIu32,
-				link_id, i);
-			pos = APP_PARAM_FIND(app->hwq_in_params, name);
-			APP_CHECK((pos >= 0),
-				"%s RXQs are not contiguous (C)\n", link->name);
-		}
-
-		/* Check that link TXQs are contiguous */
-		n_txq = app_link_get_n_txq(app, link);
-
-		APP_CHECK((n_txq),  "%s does not have any TXQ\n", link->name);
-
-		for (i = 0; i < n_txq; i++) {
-			char name[APP_PARAM_NAME_SIZE];
-			int pos;
-
-			sprintf(name, "TXQ%" PRIu32 ".%" PRIu32,
-				link_id, i);
-			pos = APP_PARAM_FIND(app->hwq_out_params, name);
-			APP_CHECK((pos >= 0),
-				"%s TXQs are not contiguous\n", link->name);
-		}
-	}
-}
-
-static void
-check_rxqs(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_pktq_hwq_in; i++) {
-		struct app_pktq_hwq_in_params *p = &app->hwq_in_params[i];
-		uint32_t n_readers = app_rxq_get_readers(app, p);
-
-		APP_CHECK((p->size > 0),
-			"%s size is 0\n", p->name);
-
-		APP_CHECK((rte_is_power_of_2(p->size)),
-			"%s size is not a power of 2\n", p->name);
-
-		APP_CHECK((p->burst > 0),
-			"%s burst size is 0\n", p->name);
-
-		APP_CHECK((p->burst <= p->size),
-			"%s burst size is bigger than its size\n", p->name);
-
-		APP_CHECK((n_readers != 0),
-			"%s has no reader\n", p->name);
-
-		APP_CHECK((n_readers == 1),
-			"%s has more than one reader\n", p->name);
-	}
-}
-
-static void
-check_txqs(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_pktq_hwq_out; i++) {
-		struct app_pktq_hwq_out_params *p = &app->hwq_out_params[i];
-		uint32_t n_writers = app_txq_get_writers(app, p);
-
-		APP_CHECK((p->size > 0),
-			"%s size is 0\n", p->name);
-
-		APP_CHECK((rte_is_power_of_2(p->size)),
-			"%s size is not a power of 2\n", p->name);
-
-		APP_CHECK((p->burst > 0),
-			"%s burst size is 0\n", p->name);
-
-		APP_CHECK((p->burst <= p->size),
-			"%s burst size is bigger than its size\n", p->name);
-
-		APP_CHECK((n_writers != 0),
-			"%s has no writer\n", p->name);
-
-		APP_CHECK((n_writers == 1),
-			"%s has more than one writer\n", p->name);
-	}
-}
-
-static void
-check_swqs(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_pktq_swq; i++) {
-		struct app_pktq_swq_params *p = &app->swq_params[i];
-		uint32_t n_readers = app_swq_get_readers(app, p);
-		uint32_t n_writers = app_swq_get_writers(app, p);
-		uint32_t n_flags;
-
-		APP_CHECK((p->size > 0),
-			"%s size is 0\n", p->name);
-
-		APP_CHECK((rte_is_power_of_2(p->size)),
-			"%s size is not a power of 2\n", p->name);
-
-		APP_CHECK((p->burst_read > 0),
-			"%s read burst size is 0\n", p->name);
-
-		APP_CHECK((p->burst_read <= p->size),
-			"%s read burst size is bigger than its size\n",
-			p->name);
-
-		APP_CHECK((p->burst_write > 0),
-			"%s write burst size is 0\n", p->name);
-
-		APP_CHECK((p->burst_write <= p->size),
-			"%s write burst size is bigger than its size\n",
-			p->name);
-
-		APP_CHECK((n_readers != 0),
-			"%s has no reader\n", p->name);
-
-		if (n_readers > 1)
-			APP_LOG(app, LOW, "%s has more than one reader", p->name);
-
-		APP_CHECK((n_writers != 0),
-			"%s has no writer\n", p->name);
-
-		if (n_writers > 1)
-			APP_LOG(app, LOW, "%s has more than one writer", p->name);
-
-		n_flags = p->ipv4_frag + p->ipv6_frag + p->ipv4_ras + p->ipv6_ras;
-
-		APP_CHECK((n_flags < 2),
-			"%s has more than one fragmentation or reassembly mode enabled\n",
-			p->name);
-
-		APP_CHECK((!((n_readers > 1) && (n_flags == 1))),
-			"%s has more than one reader when fragmentation or reassembly"
-			" mode enabled\n",
-			p->name);
-
-		APP_CHECK((!((n_writers > 1) && (n_flags == 1))),
-			"%s has more than one writer when fragmentation or reassembly"
-			" mode enabled\n",
-			p->name);
-
-		n_flags = p->ipv4_ras + p->ipv6_ras;
-
-		APP_CHECK((!((p->dropless == 1) && (n_flags == 1))),
-			"%s has dropless when reassembly mode enabled\n", p->name);
-
-		n_flags = p->ipv4_frag + p->ipv6_frag;
-
-		if (n_flags == 1) {
-			uint16_t ip_hdr_size = (p->ipv4_frag) ? sizeof(struct ipv4_hdr) :
-				sizeof(struct ipv6_hdr);
-
-			APP_CHECK((p->mtu > ip_hdr_size),
-				"%s mtu size is smaller than ip header\n", p->name);
-
-			APP_CHECK((!((p->mtu - ip_hdr_size) % 8)),
-				"%s mtu size is incorrect\n", p->name);
-		}
-	}
-}
-
-static void
-check_tms(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_pktq_tm; i++) {
-		struct app_pktq_tm_params *p = &app->tm_params[i];
-		uint32_t n_readers = app_tm_get_readers(app, p);
-		uint32_t n_writers = app_tm_get_writers(app, p);
-
-		APP_CHECK((n_readers != 0),
-			"%s has no reader\n", p->name);
-
-		APP_CHECK((n_readers == 1),
-			"%s has more than one reader\n", p->name);
-
-		APP_CHECK((n_writers != 0),
-			"%s has no writer\n", p->name);
-
-		APP_CHECK((n_writers == 1),
-			"%s has more than one writer\n", p->name);
-	}
-}
-
-static void
-check_taps(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_pktq_tap; i++) {
-		struct app_pktq_tap_params *p = &app->tap_params[i];
-		uint32_t n_readers = app_tap_get_readers(app, p);
-		uint32_t n_writers = app_tap_get_writers(app, p);
-
-		APP_CHECK((n_readers != 0),
-			"%s has no reader\n", p->name);
-
-		APP_CHECK((n_readers == 1),
-			"%s has more than one reader\n", p->name);
-
-		APP_CHECK((n_writers != 0),
-			"%s has no writer\n", p->name);
-
-		APP_CHECK((n_writers == 1),
-			"%s has more than one writer\n", p->name);
-
-		APP_CHECK((p->burst_read > 0),
-			"%s read burst size is 0\n", p->name);
-
-		APP_CHECK((p->burst_write > 0),
-			"%s write burst size is 0\n", p->name);
-	}
-}
-
-static void
-check_knis(struct app_params *app) {
-	uint32_t i;
-
-	for (i = 0; i < app->n_pktq_kni; i++) {
-		struct app_pktq_kni_params *p = &app->kni_params[i];
-		uint32_t n_readers = app_kni_get_readers(app, p);
-		uint32_t n_writers = app_kni_get_writers(app, p);
-
-		APP_CHECK((n_readers != 0),
-			"%s has no reader\n", p->name);
-
-		APP_CHECK((n_readers == 1),
-			"%s has more than one reader\n", p->name);
-
-		APP_CHECK((n_writers != 0),
-			"%s has no writer\n", p->name);
-
-		APP_CHECK((n_writers == 1),
-			"%s has more than one writer\n", p->name);
-	}
-}
-
-static void
-check_sources(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_pktq_source; i++) {
-		struct app_pktq_source_params *p = &app->source_params[i];
-		uint32_t n_readers = app_source_get_readers(app, p);
-
-		APP_CHECK((n_readers != 0),
-			"%s has no reader\n", p->name);
-
-		APP_CHECK((n_readers == 1),
-			"%s has more than one reader\n", p->name);
-	}
-}
-
-static void
-check_sinks(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_pktq_sink; i++) {
-		struct app_pktq_sink_params *p = &app->sink_params[i];
-		uint32_t n_writers = app_sink_get_writers(app, p);
-
-		APP_CHECK((n_writers != 0),
-			"%s has no writer\n", p->name);
-
-		APP_CHECK((n_writers == 1),
-			"%s has more than one writer\n", p->name);
-	}
-}
-
-static void
-check_msgqs(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_msgq; i++) {
-		struct app_msgq_params *p = &app->msgq_params[i];
-		uint32_t n_readers = app_msgq_get_readers(app, p);
-		uint32_t n_writers = app_msgq_get_writers(app, p);
-		uint32_t msgq_req_pipeline, msgq_rsp_pipeline;
-		uint32_t msgq_req_core, msgq_rsp_core;
-
-		APP_CHECK((p->size > 0),
-			"%s size is 0\n", p->name);
-
-		APP_CHECK((rte_is_power_of_2(p->size)),
-			"%s size is not a power of 2\n", p->name);
-
-		msgq_req_pipeline = (strncmp(p->name, "MSGQ-REQ-PIPELINE",
-			strlen("MSGQ-REQ-PIPELINE")) == 0);
-
-		msgq_rsp_pipeline = (strncmp(p->name, "MSGQ-RSP-PIPELINE",
-			strlen("MSGQ-RSP-PIPELINE")) == 0);
-
-		msgq_req_core = (strncmp(p->name, "MSGQ-REQ-CORE",
-			strlen("MSGQ-REQ-CORE")) == 0);
-
-		msgq_rsp_core = (strncmp(p->name, "MSGQ-RSP-CORE",
-			strlen("MSGQ-RSP-CORE")) == 0);
-
-		if ((msgq_req_pipeline == 0) &&
-			(msgq_rsp_pipeline == 0) &&
-			(msgq_req_core == 0) &&
-			(msgq_rsp_core == 0)) {
-			APP_CHECK((n_readers != 0),
-				"%s has no reader\n", p->name);
-
-			APP_CHECK((n_readers == 1),
-				"%s has more than one reader\n", p->name);
-
-			APP_CHECK((n_writers != 0),
-				"%s has no writer\n", p->name);
-
-			APP_CHECK((n_writers == 1),
-				"%s has more than one writer\n", p->name);
-		}
-
-		if (msgq_req_pipeline) {
-			struct app_pipeline_params *pipeline;
-			uint32_t pipeline_id;
-
-			APP_PARAM_GET_ID(p, "MSGQ-REQ-PIPELINE", pipeline_id);
-
-			APP_PARAM_FIND_BY_ID(app->pipeline_params,
-				"PIPELINE",
-				pipeline_id,
-				pipeline);
-
-			APP_CHECK((pipeline != NULL),
-				"%s is not associated with a valid pipeline\n",
-				p->name);
-		}
-
-		if (msgq_rsp_pipeline) {
-			struct app_pipeline_params *pipeline;
-			uint32_t pipeline_id;
-
-			APP_PARAM_GET_ID(p, "MSGQ-RSP-PIPELINE", pipeline_id);
-
-			APP_PARAM_FIND_BY_ID(app->pipeline_params,
-				"PIPELINE",
-				pipeline_id,
-				pipeline);
-
-			APP_CHECK((pipeline != NULL),
-				"%s is not associated with a valid pipeline\n",
-				p->name);
-		}
-	}
-}
-
-static void
-check_pipelines(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-
-		APP_CHECK((p->n_msgq_in == p->n_msgq_out),
-			"%s number of input MSGQs does not match "
-			"the number of output MSGQs\n", p->name);
-	}
-}
-
-int
-app_config_check(struct app_params *app)
-{
-	check_mempools(app);
-	check_links(app);
-	check_rxqs(app);
-	check_txqs(app);
-	check_swqs(app);
-	check_tms(app);
-	check_taps(app);
-	check_knis(app);
-	check_sources(app);
-	check_sinks(app);
-	check_msgqs(app);
-	check_pipelines(app);
-
-	return 0;
-}
diff --git a/examples/ip_pipeline/config_parse.c b/examples/ip_pipeline/config_parse.c
deleted file mode 100644
index e90499e..0000000
--- a/examples/ip_pipeline/config_parse.c
+++ /dev/null
@@ -1,3395 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2016 Intel Corporation
- */
-
-#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 <libgen.h>
-#include <unistd.h>
-#include <sys/wait.h>
-
-#include <rte_errno.h>
-#include <rte_cfgfile.h>
-#include <rte_string_fns.h>
-
-#include "app.h"
-#include "parser.h"
-
-/**
- * Default config values
- **/
-
-static struct app_params app_params_default = {
-	.config_file = "./config/ip_pipeline.cfg",
-	.log_level = APP_LOG_LEVEL_HIGH,
-	.port_mask = 0,
-
-	.eal_params = {
-		.channels = 4,
-	},
-};
-
-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_q = 0,
-	.ip_local_q = 0,
-	.tcp_local_q = 0,
-	.udp_local_q = 0,
-	.sctp_local_q = 0,
-	.rss_qs = {0},
-	.n_rss_qs = 0,
-	.rss_proto_ipv4 = ETH_RSS_IPV4,
-	.rss_proto_ipv6 = ETH_RSS_IPV6,
-	.rss_proto_l2 = 0,
-	.state = 0,
-	.ip = 0,
-	.depth = 0,
-	.mac_addr = 0,
-	.pci_bdf = {0},
-
-	.conf = {
-		.link_speeds = 0,
-		.rxmode = {
-			.mq_mode = ETH_MQ_RX_NONE,
-
-			.ignore_offload_bitfield = 1,
-			.offloads = DEV_RX_OFFLOAD_CRC_STRIP,
-
-			.max_rx_pkt_len = 9000, /* Jumbo frame max packet len */
-			.split_hdr_size = 0, /* Header split buffer size */
-		},
-		.rx_adv_conf = {
-			.rss_conf = {
-				.rss_key = NULL,
-				.rss_key_len = 40,
-				.rss_hf = 0,
-			},
-		},
-		.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_IGNORE,
-		.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,
-	.ipv4_frag = 0,
-	.ipv6_frag = 0,
-	.ipv4_ras = 0,
-	.ipv6_ras = 0,
-	.mtu = 0,
-	.metadata_size = 0,
-	.mempool_direct_id = 0,
-	.mempool_indirect_id = 0,
-};
-
-struct app_pktq_tm_params default_tm_params = {
-	.parsed = 0,
-	.file_name = "./config/tm_profile.cfg",
-	.burst_read = 24,
-	.burst_write = 32,
-};
-
-struct app_pktq_tap_params default_tap_params = {
-	.parsed = 0,
-	.burst_read = 32,
-	.burst_write = 32,
-	.dropless = 0,
-	.n_retries = 0,
-	.mempool_id = 0,
-};
-
-struct app_pktq_kni_params default_kni_params = {
-	.parsed = 0,
-	.socket_id = 0,
-	.core_id = 0,
-	.hyper_th_id = 0,
-	.force_bind = 0,
-
-	.mempool_id = 0,
-	.burst_read = 32,
-	.burst_write = 32,
-	.dropless = 0,
-	.n_retries = 0,
-};
-
-struct app_pktq_source_params default_source_params = {
-	.parsed = 0,
-	.mempool_id = 0,
-	.burst = 32,
-	.file_name = "./config/packets.pcap",
-	.n_bytes_per_pkt = 0,
-};
-
-struct app_pktq_sink_params default_sink_params = {
-	.parsed = 0,
-	.file_name = NULL,
-	.n_pkts_to_dump = 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] "
-	"[-l LOG_LEVEL] [--preproc PREPROCESSOR] [--preproc-args ARGS]\n"
-	"\n"
-	"Arguments:\n"
-	"\t-f CONFIG_FILE: Default config file is %s\n"
-	"\t-p PORT_MASK: Mask of NIC port IDs in hex format (generated from "
-		"config file when not provided)\n"
-	"\t-s SCRIPT_FILE: No CLI script file is run when not specified\n"
-	"\t-l LOG_LEVEL: 0 = NONE, 1 = HIGH PRIO (default), 2 = LOW PRIO\n"
-	"\t--preproc PREPROCESSOR: Configuration file pre-processor\n"
-	"\t--preproc-args ARGS: Arguments to be passed to pre-processor\n"
-	"\n";
-
-static void
-app_print_usage(char *prgname)
-{
-	rte_exit(0, app_usage, prgname, app_params_default.config_file);
-}
-
-#define APP_PARAM_ADD(set, key)						\
-({									\
-	ssize_t pos = APP_PARAM_FIND(set, key);				\
-	ssize_t size = RTE_DIM(set);					\
-									\
-	if (pos < 0) {							\
-		for (pos = 0; pos < size; pos++) {			\
-			if (!APP_PARAM_VALID(&((set)[pos])))		\
-				break;					\
-		}							\
-									\
-		APP_CHECK((pos < size),					\
-			"Parse error: size of %s is limited to %u elements",\
-			#set, (uint32_t) size);				\
-									\
-		(set)[pos].name = strdup(key);				\
-		APP_CHECK(((set)[pos].name),				\
-			"Parse error: no free memory");			\
-	}								\
-	pos;								\
-})
-
-#define APP_PARAM_ADD_LINK_FOR_RXQ(app, rxq_name)			\
-({									\
-	char link_name[APP_PARAM_NAME_SIZE];				\
-	ssize_t link_param_pos;						\
-	uint32_t link_id, queue_id;				\
-									\
-	sscanf((rxq_name), "RXQ%" SCNu32 ".%" SCNu32, &link_id, &queue_id);\
-	sprintf(link_name, "LINK%" PRIu32, link_id);			\
-	link_param_pos = APP_PARAM_ADD((app)->link_params, link_name);	\
-	link_param_pos;							\
-})
-
-#define APP_PARAM_ADD_LINK_FOR_TXQ(app, txq_name)			\
-({									\
-	char link_name[APP_PARAM_NAME_SIZE];				\
-	ssize_t link_param_pos;						\
-	uint32_t link_id, queue_id;					\
-									\
-	sscanf((txq_name), "TXQ%" SCNu32 ".%" SCNu32, &link_id, &queue_id);\
-	sprintf(link_name, "LINK%" PRIu32, link_id);			\
-	link_param_pos = APP_PARAM_ADD((app)->link_params, link_name);	\
-	link_param_pos;							\
-})
-
-#define APP_PARAM_ADD_LINK_FOR_TM(app, tm_name)				\
-({									\
-	char link_name[APP_PARAM_NAME_SIZE];				\
-	ssize_t link_param_pos;						\
-	uint32_t link_id;						\
-									\
-	sscanf((tm_name), "TM%" SCNu32, &link_id);			\
-	sprintf(link_name, "LINK%" PRIu32, link_id);			\
-	link_param_pos = APP_PARAM_ADD((app)->link_params, link_name);	\
-	link_param_pos;							\
-})
-
-#define APP_PARAM_ADD_LINK_FOR_KNI(app, kni_name)			\
-({									\
-	char link_name[APP_PARAM_NAME_SIZE];				\
-	ssize_t link_param_pos;						\
-	uint32_t link_id;						\
-									\
-	sscanf((kni_name), "KNI%" SCNu32, &link_id);		\
-	sprintf(link_name, "LINK%" PRIu32, link_id);			\
-	link_param_pos = APP_PARAM_ADD((app)->link_params, link_name);	\
-	link_param_pos;							\
-})
-
-#define PARSE_CHECK_DUPLICATE_SECTION(obj)				\
-do {									\
-	APP_CHECK(((obj)->parsed == 0),					\
-		"Parse error: duplicate \"%s\" section", (obj)->name);	\
-	(obj)->parsed++;					\
-} while (0)
-
-#define PARSE_CHECK_DUPLICATE_SECTION_EAL(obj)				\
-do {									\
-	APP_CHECK(((obj)->parsed == 0),					\
-		"Parse error: duplicate \"%s\" section", "EAL");	\
-	(obj)->parsed++;					\
-} while (0)
-
-#define PARSE_ERROR(exp, section, entry)				\
-APP_CHECK(exp, "Parse error in section \"%s\": entry \"%s\"", section, entry)
-
-#define PARSE_ERROR_MESSAGE(exp, section, entry, message)		\
-APP_CHECK(exp, "Parse error in section \"%s\", entry \"%s\": %s",	\
-	section, entry, message)
-
-#define PARSE_ERROR_NO_ELEMENTS(exp, section, entry)			\
-APP_CHECK(exp, "Parse error in section \"%s\", entry \"%s\": "		\
-	"no elements detected",						\
-	section, entry)
-
-#define PARSE_ERROR_TOO_MANY_ELEMENTS(exp, section, entry, max)		\
-APP_CHECK(exp, "Parse error in section \"%s\", entry \"%s\": "		\
-	"maximum number of elements allowed is %u",			\
-	section, entry, max)
-
-#define PARSE_ERROR_INVALID_ELEMENT(exp, section, entry, value)		\
-APP_CHECK(exp, "Parse error in section \"%s\", entry \"%s\": "		\
-	"Invalid element value \"%s\"",					\
-	section, entry, value)
-
-#define PARSE_ERROR_MALLOC(exp)						\
-APP_CHECK(exp, "Parse error: no free memory")
-
-#define PARSE_ERROR_SECTION(exp, section)				\
-APP_CHECK(exp, "Parse error in section \"%s\"", section)
-
-#define PARSE_ERROR_SECTION_NO_ENTRIES(exp, section)			\
-APP_CHECK(exp, "Parse error in section \"%s\": no entries", section)
-
-#define PARSE_WARNING_IGNORED(exp, section, entry)			\
-do									\
-if (!(exp))								\
-	fprintf(stderr, "Parse warning in section \"%s\": "		\
-		"entry \"%s\" is ignored", section, entry);		\
-while (0)
-
-#define PARSE_ERROR_INVALID(exp, section, entry)			\
-APP_CHECK(exp, "Parse error in section \"%s\": unrecognized entry \"%s\"",\
-	section, entry)
-
-#define PARSE_ERROR_DUPLICATE(exp, section, entry)			\
-APP_CHECK(exp, "Parse error in section \"%s\": duplicate entry \"%s\"",	\
-	section, entry)
-
-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 void
-parse_eal(struct app_params *app,
-	const char *section_name,
-	struct rte_cfgfile *cfg)
-{
-	struct app_eal_params *p = &app->eal_params;
-	struct rte_cfgfile_entry *entries;
-	int n_entries, i;
-
-	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
-	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
-
-	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
-	PARSE_ERROR_MALLOC(entries != NULL);
-
-	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
-
-	PARSE_CHECK_DUPLICATE_SECTION_EAL(p);
-
-	for (i = 0; i < n_entries; i++) {
-		struct rte_cfgfile_entry *entry = &entries[i];
-
-		/* coremask */
-		if (strcmp(entry->name, "c") == 0) {
-			PARSE_WARNING_IGNORED(0, section_name, entry->name);
-			continue;
-		}
-
-		/* corelist */
-		if (strcmp(entry->name, "l") == 0) {
-			PARSE_WARNING_IGNORED(0, section_name, entry->name);
-			continue;
-		}
-
-		/* coremap */
-		if (strcmp(entry->name, "lcores") == 0) {
-			PARSE_ERROR_DUPLICATE((p->coremap == NULL),
-				section_name,
-				entry->name);
-			p->coremap = strdup(entry->value);
-			continue;
-		}
-
-		/* master_lcore */
-		if (strcmp(entry->name, "master_lcore") == 0) {
-			int status;
-
-			PARSE_ERROR_DUPLICATE((p->master_lcore_present == 0),
-				section_name,
-				entry->name);
-			p->master_lcore_present = 1;
-
-			status = parser_read_uint32(&p->master_lcore,
-				entry->value);
-			PARSE_ERROR((status == 0), section_name, entry->name);
-			continue;
-		}
-
-		/* channels */
-		if (strcmp(entry->name, "n") == 0) {
-			int status;
-
-			PARSE_ERROR_DUPLICATE((p->channels_present == 0),
-				section_name,
-				entry->name);
-			p->channels_present = 1;
-
-			status = parser_read_uint32(&p->channels, entry->value);
-			PARSE_ERROR((status == 0), section_name, entry->name);
-			continue;
-		}
-
-		/* memory */
-		if (strcmp(entry->name, "m") == 0) {
-			int status;
-
-			PARSE_ERROR_DUPLICATE((p->memory_present == 0),
-				section_name,
-				entry->name);
-			p->memory_present = 1;
-
-			status = parser_read_uint32(&p->memory, entry->value);
-			PARSE_ERROR((status == 0), section_name, entry->name);
-			continue;
-		}
-
-		/* ranks */
-		if (strcmp(entry->name, "r") == 0) {
-			int status;
-
-			PARSE_ERROR_DUPLICATE((p->ranks_present == 0),
-				section_name,
-				entry->name);
-			p->ranks_present = 1;
-
-			status = parser_read_uint32(&p->ranks, entry->value);
-			PARSE_ERROR((status == 0), section_name, entry->name);
-			continue;
-		}
-
-		/* pci_blacklist */
-		if ((strcmp(entry->name, "pci_blacklist") == 0) ||
-			(strcmp(entry->name, "b") == 0)) {
-			uint32_t i;
-
-			for (i = 0; i < APP_MAX_LINKS; i++) {
-				if (p->pci_blacklist[i])
-					continue;
-
-				p->pci_blacklist[i] =
-					strdup(entry->value);
-				PARSE_ERROR_MALLOC(p->pci_blacklist[i]);
-
-				break;
-			}
-
-			PARSE_ERROR_MESSAGE((i < APP_MAX_LINKS),
-				section_name, entry->name,
-				"too many elements");
-			continue;
-		}
-
-		/* pci_whitelist */
-		if ((strcmp(entry->name, "pci_whitelist") == 0) ||
-			(strcmp(entry->name, "w") == 0)) {
-			uint32_t i;
-
-			PARSE_ERROR_MESSAGE((app->port_mask != 0),
-				section_name, entry->name, "entry to be "
-				"generated by the application (port_mask "
-				"not provided)");
-
-			for (i = 0; i < APP_MAX_LINKS; i++) {
-				if (p->pci_whitelist[i])
-					continue;
-
-				p->pci_whitelist[i] = strdup(entry->value);
-				PARSE_ERROR_MALLOC(p->pci_whitelist[i]);
-
-				break;
-			}
-
-			PARSE_ERROR_MESSAGE((i < APP_MAX_LINKS),
-				section_name, entry->name,
-				"too many elements");
-			continue;
-		}
-
-		/* vdev */
-		if (strcmp(entry->name, "vdev") == 0) {
-			uint32_t i;
-
-			for (i = 0; i < APP_MAX_LINKS; i++) {
-				if (p->vdev[i])
-					continue;
-
-				p->vdev[i] = strdup(entry->value);
-				PARSE_ERROR_MALLOC(p->vdev[i]);
-
-				break;
-			}
-
-			PARSE_ERROR_MESSAGE((i < APP_MAX_LINKS),
-				section_name, entry->name,
-				"too many elements");
-			continue;
-		}
-
-		/* vmware_tsc_map */
-		if (strcmp(entry->name, "vmware_tsc_map") == 0) {
-			int val;
-
-			PARSE_ERROR_DUPLICATE((p->vmware_tsc_map_present == 0),
-				section_name,
-				entry->name);
-			p->vmware_tsc_map_present = 1;
-
-			val = parser_read_arg_bool(entry->value);
-			PARSE_ERROR((val >= 0), section_name, entry->name);
-			p->vmware_tsc_map = val;
-			continue;
-		}
-
-		/* proc_type */
-		if (strcmp(entry->name, "proc_type") == 0) {
-			PARSE_ERROR_DUPLICATE((p->proc_type == NULL),
-				section_name,
-				entry->name);
-			p->proc_type = strdup(entry->value);
-			continue;
-		}
-
-		/* syslog */
-		if (strcmp(entry->name, "syslog") == 0) {
-			PARSE_ERROR_DUPLICATE((p->syslog == NULL),
-				section_name,
-				entry->name);
-			p->syslog = strdup(entry->value);
-			continue;
-		}
-
-		/* log_level */
-		if (strcmp(entry->name, "log_level") == 0) {
-			int status;
-
-			PARSE_ERROR_DUPLICATE((p->log_level_present == 0),
-				section_name,
-				entry->name);
-			p->log_level_present = 1;
-
-			status = parser_read_uint32(&p->log_level,
-				entry->value);
-			PARSE_ERROR((status == 0), section_name, entry->name);
-			continue;
-		}
-
-		/* version */
-		if (strcmp(entry->name, "v") == 0) {
-			int val;
-
-			PARSE_ERROR_DUPLICATE((p->version_present == 0),
-				section_name,
-				entry->name);
-			p->version_present = 1;
-
-			val = parser_read_arg_bool(entry->value);
-			PARSE_ERROR((val >= 0), section_name, entry->name);
-			p->version = val;
-			continue;
-		}
-
-		/* help */
-		if ((strcmp(entry->name, "help") == 0) ||
-			(strcmp(entry->name, "h") == 0)) {
-			int val;
-
-			PARSE_ERROR_DUPLICATE((p->help_present == 0),
-				section_name,
-				entry->name);
-			p->help_present = 1;
-
-			val = parser_read_arg_bool(entry->value);
-			PARSE_ERROR((val >= 0), section_name, entry->name);
-			p->help = val;
-			continue;
-		}
-
-		/* no_huge */
-		if (strcmp(entry->name, "no_huge") == 0) {
-			int val;
-
-			PARSE_ERROR_DUPLICATE((p->no_huge_present == 0),
-				section_name,
-				entry->name);
-			p->no_huge_present = 1;
-
-			val = parser_read_arg_bool(entry->value);
-			PARSE_ERROR((val >= 0), section_name, entry->name);
-			p->no_huge = val;
-			continue;
-		}
-
-		/* no_pci */
-		if (strcmp(entry->name, "no_pci") == 0) {
-			int val;
-
-			PARSE_ERROR_DUPLICATE((p->no_pci_present == 0),
-				section_name,
-				entry->name);
-			p->no_pci_present = 1;
-
-			val = parser_read_arg_bool(entry->value);
-			PARSE_ERROR((val >= 0), section_name, entry->name);
-			p->no_pci = val;
-			continue;
-		}
-
-		/* no_hpet */
-		if (strcmp(entry->name, "no_hpet") == 0) {
-			int val;
-
-			PARSE_ERROR_DUPLICATE((p->no_hpet_present == 0),
-				section_name,
-				entry->name);
-			p->no_hpet_present = 1;
-
-			val = parser_read_arg_bool(entry->value);
-			PARSE_ERROR((val >= 0), section_name, entry->name);
-			p->no_hpet = val;
-			continue;
-		}
-
-		/* no_shconf */
-		if (strcmp(entry->name, "no_shconf") == 0) {
-			int val;
-
-			PARSE_ERROR_DUPLICATE((p->no_shconf_present == 0),
-				section_name,
-				entry->name);
-			p->no_shconf_present = 1;
-
-			val = parser_read_arg_bool(entry->value);
-			PARSE_ERROR((val >= 0), section_name, entry->name);
-			p->no_shconf = val;
-			continue;
-		}
-
-		/* add_driver */
-		if (strcmp(entry->name, "d") == 0) {
-			PARSE_ERROR_DUPLICATE((p->add_driver == NULL),
-				section_name,
-				entry->name);
-			p->add_driver = strdup(entry->value);
-			continue;
-		}
-
-		/* socket_mem */
-		if (strcmp(entry->name, "socket_mem") == 0) {
-			PARSE_ERROR_DUPLICATE((p->socket_mem == NULL),
-				section_name,
-				entry->name);
-			p->socket_mem = strdup(entry->value);
-			continue;
-		}
-
-		/* huge_dir */
-		if (strcmp(entry->name, "huge_dir") == 0) {
-			PARSE_ERROR_DUPLICATE((p->huge_dir == NULL),
-				section_name,
-				entry->name);
-			p->huge_dir = strdup(entry->value);
-			continue;
-		}
-
-		/* file_prefix */
-		if (strcmp(entry->name, "file_prefix") == 0) {
-			PARSE_ERROR_DUPLICATE((p->file_prefix == NULL),
-				section_name,
-				entry->name);
-			p->file_prefix = strdup(entry->value);
-			continue;
-		}
-
-		/* base_virtaddr */
-		if (strcmp(entry->name, "base_virtaddr") == 0) {
-			PARSE_ERROR_DUPLICATE((p->base_virtaddr == NULL),
-				section_name,
-				entry->name);
-			p->base_virtaddr = strdup(entry->value);
-			continue;
-		}
-
-		/* create_uio_dev */
-		if (strcmp(entry->name, "create_uio_dev") == 0) {
-			int val;
-
-			PARSE_ERROR_DUPLICATE((p->create_uio_dev_present == 0),
-				section_name,
-				entry->name);
-			p->create_uio_dev_present = 1;
-
-			val = parser_read_arg_bool(entry->value);
-			PARSE_ERROR((val >= 0), section_name, entry->name);
-			p->create_uio_dev = val;
-			continue;
-		}
-
-		/* vfio_intr */
-		if (strcmp(entry->name, "vfio_intr") == 0) {
-			PARSE_ERROR_DUPLICATE((p->vfio_intr == NULL),
-				section_name,
-				entry->name);
-			p->vfio_intr = strdup(entry->value);
-			continue;
-		}
-
-		/* unrecognized */
-		PARSE_ERROR_INVALID(0, section_name, entry->name);
-	}
-
-	free(entries);
-}
-
-static void
-parse_pipeline_pktq_in(struct app_params *app,
-	struct app_pipeline_params *p,
-	char *value)
-{
-	p->n_pktq_in = 0;
-
-	while (1) {
-		enum app_pktq_in_type type;
-		int id;
-		char *name = strtok_r(value, PARSE_DELIMITER, &value);
-
-		if (name == NULL)
-			break;
-
-		PARSE_ERROR_TOO_MANY_ELEMENTS(
-			(p->n_pktq_in < RTE_DIM(p->pktq_in)),
-			p->name, "pktq_in", (uint32_t)RTE_DIM(p->pktq_in));
-
-		if (validate_name(name, "RXQ", 2) == 0) {
-			type = APP_PKTQ_IN_HWQ;
-			id = APP_PARAM_ADD(app->hwq_in_params, name);
-			APP_PARAM_ADD_LINK_FOR_RXQ(app, 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);
-			APP_PARAM_ADD_LINK_FOR_TM(app, name);
-		} else if (validate_name(name, "TAP", 1) == 0) {
-			type = APP_PKTQ_IN_TAP;
-			id = APP_PARAM_ADD(app->tap_params, name);
-		} else if (validate_name(name, "KNI", 1) == 0) {
-			type = APP_PKTQ_IN_KNI;
-			id = APP_PARAM_ADD(app->kni_params, name);
-			APP_PARAM_ADD_LINK_FOR_KNI(app, name);
-		} else if (validate_name(name, "SOURCE", 1) == 0) {
-			type = APP_PKTQ_IN_SOURCE;
-			id = APP_PARAM_ADD(app->source_params, name);
-		} else
-			PARSE_ERROR_INVALID_ELEMENT(0,
-				p->name, "pktq_in", name);
-
-		p->pktq_in[p->n_pktq_in].type = type;
-		p->pktq_in[p->n_pktq_in].id = (uint32_t) id;
-		p->n_pktq_in++;
-	}
-
-	PARSE_ERROR_NO_ELEMENTS((p->n_pktq_in > 0), p->name, "pktq_in");
-}
-
-static void
-parse_pipeline_pktq_out(struct app_params *app,
-	struct app_pipeline_params *p,
-	char *value)
-{
-	p->n_pktq_out = 0;
-
-	while (1) {
-		enum app_pktq_out_type type;
-		int id;
-		char *name = strtok_r(value, PARSE_DELIMITER, &value);
-
-		if (name == NULL)
-			break;
-
-		PARSE_ERROR_TOO_MANY_ELEMENTS(
-			(p->n_pktq_out < RTE_DIM(p->pktq_out)),
-			p->name, "pktq_out", (uint32_t)RTE_DIM(p->pktq_out));
-
-		if (validate_name(name, "TXQ", 2) == 0) {
-			type = APP_PKTQ_OUT_HWQ;
-			id = APP_PARAM_ADD(app->hwq_out_params, name);
-			APP_PARAM_ADD_LINK_FOR_TXQ(app, 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);
-			APP_PARAM_ADD_LINK_FOR_TM(app, name);
-		} else if (validate_name(name, "TAP", 1) == 0) {
-			type = APP_PKTQ_OUT_TAP;
-			id = APP_PARAM_ADD(app->tap_params, name);
-		} else if (validate_name(name, "KNI", 1) == 0) {
-			type = APP_PKTQ_OUT_KNI;
-			id = APP_PARAM_ADD(app->kni_params, name);
-			APP_PARAM_ADD_LINK_FOR_KNI(app, name);
-		} else if (validate_name(name, "SINK", 1) == 0) {
-			type = APP_PKTQ_OUT_SINK;
-			id = APP_PARAM_ADD(app->sink_params, name);
-		} else
-			PARSE_ERROR_INVALID_ELEMENT(0,
-				p->name, "pktq_out", name);
-
-		p->pktq_out[p->n_pktq_out].type = type;
-		p->pktq_out[p->n_pktq_out].id = id;
-		p->n_pktq_out++;
-	}
-
-	PARSE_ERROR_NO_ELEMENTS((p->n_pktq_out > 0), p->name, "pktq_out");
-}
-
-static void
-parse_pipeline_msgq_in(struct app_params *app,
-	struct app_pipeline_params *p,
-	char *value)
-{
-	p->n_msgq_in = 0;
-
-	while (1) {
-		int idx;
-		char *name = strtok_r(value, PARSE_DELIMITER, &value);
-
-		if (name == NULL)
-			break;
-
-		PARSE_ERROR_TOO_MANY_ELEMENTS(
-			(p->n_msgq_in < RTE_DIM(p->msgq_in)),
-			p->name, "msgq_in", (uint32_t)(RTE_DIM(p->msgq_in)));
-
-		PARSE_ERROR_INVALID_ELEMENT(
-			(validate_name(name, "MSGQ", 1) == 0),
-			p->name, "msgq_in", name);
-
-		idx = APP_PARAM_ADD(app->msgq_params, name);
-		p->msgq_in[p->n_msgq_in] = idx;
-		p->n_msgq_in++;
-	}
-
-	PARSE_ERROR_NO_ELEMENTS((p->n_msgq_in > 0), p->name, "msgq_in");
-}
-
-static void
-parse_pipeline_msgq_out(struct app_params *app,
-	struct app_pipeline_params *p,
-	char *value)
-{
-	p->n_msgq_out = 0;
-
-	while (1) {
-		int idx;
-		char *name = strtok_r(value, PARSE_DELIMITER, &value);
-
-		if (name == NULL)
-			break;
-
-		PARSE_ERROR_TOO_MANY_ELEMENTS(
-			(p->n_msgq_out < RTE_DIM(p->msgq_out)),
-			p->name, "msgq_out", (uint32_t)RTE_DIM(p->msgq_out));
-
-		PARSE_ERROR_INVALID_ELEMENT(
-			(validate_name(name, "MSGQ", 1) == 0),
-			p->name, "msgq_out", name);
-
-		idx = APP_PARAM_ADD(app->msgq_params, name);
-		p->msgq_out[p->n_msgq_out] = idx;
-		p->n_msgq_out++;
-	}
-
-	PARSE_ERROR_NO_ELEMENTS((p->n_msgq_out > 0), p->name, "msgq_out");
-}
-
-static void
-parse_pipeline(struct app_params *app,
-	const char *section_name,
-	struct rte_cfgfile *cfg)
-{
-	char name[CFG_NAME_LEN];
-	struct app_pipeline_params *param;
-	struct rte_cfgfile_entry *entries;
-	ssize_t param_idx;
-	int n_entries, i;
-
-	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
-	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
-
-	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
-	PARSE_ERROR_MALLOC(entries != NULL);
-
-	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
-
-	param_idx = APP_PARAM_ADD(app->pipeline_params, section_name);
-	param = &app->pipeline_params[param_idx];
-	PARSE_CHECK_DUPLICATE_SECTION(param);
-
-	for (i = 0; i < n_entries; i++) {
-		struct rte_cfgfile_entry *ent = &entries[i];
-
-		if (strcmp(ent->name, "type") == 0) {
-			int w_size = snprintf(param->type, RTE_DIM(param->type),
-					"%s", ent->value);
-
-			PARSE_ERROR(((w_size > 0) &&
-				(w_size < (int)RTE_DIM(param->type))),
-				section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "core") == 0) {
-			int status = parse_pipeline_core(
-				&param->socket_id, &param->core_id,
-				&param->hyper_th_id, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "pktq_in") == 0) {
-			parse_pipeline_pktq_in(app, param, ent->value);
-
-			continue;
-		}
-
-		if (strcmp(ent->name, "pktq_out") == 0) {
-			parse_pipeline_pktq_out(app, param, ent->value);
-
-			continue;
-		}
-
-		if (strcmp(ent->name, "msgq_in") == 0) {
-			parse_pipeline_msgq_in(app, param, ent->value);
-
-			continue;
-		}
-
-		if (strcmp(ent->name, "msgq_out") == 0) {
-			parse_pipeline_msgq_out(app, param, ent->value);
-
-			continue;
-		}
-
-		if (strcmp(ent->name, "timer_period") == 0) {
-			int status = parser_read_uint32(
-				&param->timer_period,
-				ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		/* pipeline type specific items */
-		APP_CHECK((param->n_args < APP_MAX_PIPELINE_ARGS),
-			"Parse error in section \"%s\": too many "
-			"pipeline specified parameters", section_name);
-
-		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),
-			"Parse error: no free memory");
-
-		param->n_args++;
-	}
-
-	snprintf(name, sizeof(name), "MSGQ-REQ-%s", section_name);
-	param_idx = APP_PARAM_ADD(app->msgq_params, 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", section_name);
-	param_idx = APP_PARAM_ADD(app->msgq_params, 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);
-	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);
-	app->msgq_params[param_idx].cpu_socket_id = param->socket_id;
-
-	free(entries);
-}
-
-static void
-parse_mempool(struct app_params *app,
-	const char *section_name,
-	struct rte_cfgfile *cfg)
-{
-	struct app_mempool_params *param;
-	struct rte_cfgfile_entry *entries;
-	ssize_t param_idx;
-	int n_entries, i;
-
-	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
-	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
-
-	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
-	PARSE_ERROR_MALLOC(entries != NULL);
-
-	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
-
-	param_idx = APP_PARAM_ADD(app->mempool_params, section_name);
-	param = &app->mempool_params[param_idx];
-	PARSE_CHECK_DUPLICATE_SECTION(param);
-
-	for (i = 0; i < n_entries; i++) {
-		struct rte_cfgfile_entry *ent = &entries[i];
-
-		if (strcmp(ent->name, "buffer_size") == 0) {
-			int status = parser_read_uint32(
-				&param->buffer_size, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "pool_size") == 0) {
-			int status = parser_read_uint32(
-				&param->pool_size, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "cache_size") == 0) {
-			int status = parser_read_uint32(
-				&param->cache_size, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "cpu") == 0) {
-			int status = parser_read_uint32(
-				&param->cpu_socket_id, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		/* unrecognized */
-		PARSE_ERROR_INVALID(0, section_name, ent->name);
-	}
-
-	free(entries);
-}
-
-static int
-parse_link_rss_qs(struct app_link_params *p,
-	char *value)
-{
-	p->n_rss_qs = 0;
-
-	while (1) {
-		char *token = strtok_r(value, PARSE_DELIMITER, &value);
-
-		if (token == NULL)
-			break;
-
-		if (p->n_rss_qs == RTE_DIM(p->rss_qs))
-			return -ENOMEM;
-
-		if (parser_read_uint32(&p->rss_qs[p->n_rss_qs++], token))
-			return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int
-parse_link_rss_proto_ipv4(struct app_link_params *p,
-	char *value)
-{
-	uint64_t mask = 0;
-
-	while (1) {
-		char *token = strtok_r(value, PARSE_DELIMITER, &value);
-
-		if (token == NULL)
-			break;
-
-		if (strcmp(token, "IP") == 0) {
-			mask |= ETH_RSS_IPV4;
-			continue;
-		}
-		if (strcmp(token, "FRAG") == 0) {
-			mask |= ETH_RSS_FRAG_IPV4;
-			continue;
-		}
-		if (strcmp(token, "TCP") == 0) {
-			mask |= ETH_RSS_NONFRAG_IPV4_TCP;
-			continue;
-		}
-		if (strcmp(token, "UDP") == 0) {
-			mask |= ETH_RSS_NONFRAG_IPV4_UDP;
-			continue;
-		}
-		if (strcmp(token, "SCTP") == 0) {
-			mask |= ETH_RSS_NONFRAG_IPV4_SCTP;
-			continue;
-		}
-		if (strcmp(token, "OTHER") == 0) {
-			mask |= ETH_RSS_NONFRAG_IPV4_OTHER;
-			continue;
-		}
-		return -EINVAL;
-	}
-
-	p->rss_proto_ipv4 = mask;
-	return 0;
-}
-
-static int
-parse_link_rss_proto_ipv6(struct app_link_params *p,
-	char *value)
-{
-	uint64_t mask = 0;
-
-	while (1) {
-		char *token = strtok_r(value, PARSE_DELIMITER, &value);
-
-		if (token == NULL)
-			break;
-
-		if (strcmp(token, "IP") == 0) {
-			mask |= ETH_RSS_IPV6;
-			continue;
-		}
-		if (strcmp(token, "FRAG") == 0) {
-			mask |= ETH_RSS_FRAG_IPV6;
-			continue;
-		}
-		if (strcmp(token, "TCP") == 0) {
-			mask |= ETH_RSS_NONFRAG_IPV6_TCP;
-			continue;
-		}
-		if (strcmp(token, "UDP") == 0) {
-			mask |= ETH_RSS_NONFRAG_IPV6_UDP;
-			continue;
-		}
-		if (strcmp(token, "SCTP") == 0) {
-			mask |= ETH_RSS_NONFRAG_IPV6_SCTP;
-			continue;
-		}
-		if (strcmp(token, "OTHER") == 0) {
-			mask |= ETH_RSS_NONFRAG_IPV6_OTHER;
-			continue;
-		}
-		if (strcmp(token, "IP_EX") == 0) {
-			mask |= ETH_RSS_IPV6_EX;
-			continue;
-		}
-		if (strcmp(token, "TCP_EX") == 0) {
-			mask |= ETH_RSS_IPV6_TCP_EX;
-			continue;
-		}
-		if (strcmp(token, "UDP_EX") == 0) {
-			mask |= ETH_RSS_IPV6_UDP_EX;
-			continue;
-		}
-		return -EINVAL;
-	}
-
-	p->rss_proto_ipv6 = mask;
-	return 0;
-}
-
-static int
-parse_link_rss_proto_l2(struct app_link_params *p,
-	char *value)
-{
-	uint64_t mask = 0;
-
-	while (1) {
-		char *token = strtok_r(value, PARSE_DELIMITER, &value);
-
-		if (token == NULL)
-			break;
-
-		if (strcmp(token, "L2") == 0) {
-			mask |= ETH_RSS_L2_PAYLOAD;
-			continue;
-		}
-		return -EINVAL;
-	}
-
-	p->rss_proto_l2 = mask;
-	return 0;
-}
-
-static void
-parse_link(struct app_params *app,
-	const char *section_name,
-	struct rte_cfgfile *cfg)
-{
-	struct app_link_params *param;
-	struct rte_cfgfile_entry *entries;
-	int n_entries, i;
-	int rss_qs_present = 0;
-	int rss_proto_ipv4_present = 0;
-	int rss_proto_ipv6_present = 0;
-	int rss_proto_l2_present = 0;
-	int pci_bdf_present = 0;
-	ssize_t param_idx;
-
-	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
-	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
-
-	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
-	PARSE_ERROR_MALLOC(entries != NULL);
-
-	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
-
-	param_idx = APP_PARAM_ADD(app->link_params, section_name);
-	param = &app->link_params[param_idx];
-	PARSE_CHECK_DUPLICATE_SECTION(param);
-
-	for (i = 0; i < n_entries; i++) {
-		struct rte_cfgfile_entry *ent = &entries[i];
-
-		if (strcmp(ent->name, "promisc") == 0) {
-			int status = parser_read_arg_bool(ent->value);
-
-			PARSE_ERROR((status != -EINVAL), section_name,
-				ent->name);
-			param->promisc = status;
-			continue;
-		}
-
-		if (strcmp(ent->name, "arp_q") == 0) {
-			int status = parser_read_uint32(&param->arp_q,
-				ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "tcp_syn_q") == 0) {
-			int status = parser_read_uint32(
-				&param->tcp_syn_q, ent->value);
-
-			PARSE_ERROR((status == 0), section_name, ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "ip_local_q") == 0) {
-			int status = parser_read_uint32(
-				&param->ip_local_q, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "tcp_local_q") == 0) {
-			int status = parser_read_uint32(
-				&param->tcp_local_q, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "udp_local_q") == 0) {
-			int status = parser_read_uint32(
-				&param->udp_local_q, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "sctp_local_q") == 0) {
-			int status = parser_read_uint32(
-				&param->sctp_local_q, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "rss_qs") == 0) {
-			int status = parse_link_rss_qs(param, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			rss_qs_present = 1;
-			continue;
-		}
-
-		if (strcmp(ent->name, "rss_proto_ipv4") == 0) {
-			int status =
-				parse_link_rss_proto_ipv4(param, ent->value);
-
-			PARSE_ERROR((status != -EINVAL), section_name,
-				ent->name);
-			rss_proto_ipv4_present = 1;
-			continue;
-		}
-
-		if (strcmp(ent->name, "rss_proto_ipv6") == 0) {
-			int status =
-				parse_link_rss_proto_ipv6(param, ent->value);
-
-			PARSE_ERROR((status != -EINVAL), section_name,
-				ent->name);
-			rss_proto_ipv6_present = 1;
-			continue;
-		}
-
-		if (strcmp(ent->name, "rss_proto_l2") == 0) {
-			int status = parse_link_rss_proto_l2(param, ent->value);
-
-			PARSE_ERROR((status != -EINVAL), section_name,
-				ent->name);
-			rss_proto_l2_present = 1;
-			continue;
-		}
-
-		if (strcmp(ent->name, "pci_bdf") == 0) {
-			PARSE_ERROR_DUPLICATE((pci_bdf_present == 0),
-				section_name, ent->name);
-
-			snprintf(param->pci_bdf, APP_LINK_PCI_BDF_SIZE,
-				"%s", ent->value);
-			pci_bdf_present = 1;
-			continue;
-		}
-
-		/* unrecognized */
-		PARSE_ERROR_INVALID(0, section_name, ent->name);
-	}
-
-	/* Check for mandatory fields */
-	if (app->port_mask)
-		PARSE_ERROR_MESSAGE((pci_bdf_present == 0),
-			section_name, "pci_bdf",
-			"entry not allowed (port_mask is provided)");
-	else
-		PARSE_ERROR_MESSAGE((pci_bdf_present),
-			section_name, "pci_bdf",
-			"this entry is mandatory (port_mask is not "
-			"provided)");
-
-	if (rss_proto_ipv4_present)
-		PARSE_ERROR_MESSAGE((rss_qs_present),
-			section_name, "rss_proto_ipv4",
-			"entry not allowed (rss_qs entry is not provided)");
-	if (rss_proto_ipv6_present)
-		PARSE_ERROR_MESSAGE((rss_qs_present),
-			section_name, "rss_proto_ipv6",
-			"entry not allowed (rss_qs entry is not provided)");
-	if (rss_proto_l2_present)
-		PARSE_ERROR_MESSAGE((rss_qs_present),
-			section_name, "rss_proto_l2",
-			"entry not allowed (rss_qs entry is not provided)");
-	if (rss_proto_ipv4_present |
-		rss_proto_ipv6_present |
-		rss_proto_l2_present){
-		if (rss_proto_ipv4_present == 0)
-			param->rss_proto_ipv4 = 0;
-		if (rss_proto_ipv6_present == 0)
-			param->rss_proto_ipv6 = 0;
-		if (rss_proto_l2_present == 0)
-			param->rss_proto_l2 = 0;
-	}
-
-	free(entries);
-}
-
-static void
-parse_rxq(struct app_params *app,
-	const char *section_name,
-	struct rte_cfgfile *cfg)
-{
-	struct app_pktq_hwq_in_params *param;
-	struct rte_cfgfile_entry *entries;
-	int n_entries, i;
-	ssize_t param_idx;
-
-	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
-	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
-
-	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
-	PARSE_ERROR_MALLOC(entries != NULL);
-
-	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
-
-	param_idx = APP_PARAM_ADD(app->hwq_in_params, section_name);
-	param = &app->hwq_in_params[param_idx];
-	PARSE_CHECK_DUPLICATE_SECTION(param);
-
-	APP_PARAM_ADD_LINK_FOR_RXQ(app, section_name);
-
-	for (i = 0; i < n_entries; i++) {
-		struct rte_cfgfile_entry *ent = &entries[i];
-
-		if (strcmp(ent->name, "mempool") == 0) {
-			int status = validate_name(ent->value,
-				"MEMPOOL", 1);
-			ssize_t idx;
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-
-			idx = APP_PARAM_ADD(app->mempool_params, ent->value);
-			param->mempool_id = idx;
-			continue;
-		}
-
-		if (strcmp(ent->name, "size") == 0) {
-			int status = parser_read_uint32(&param->size,
-				ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "burst") == 0) {
-			int status = parser_read_uint32(&param->burst,
-				ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		/* unrecognized */
-		PARSE_ERROR_INVALID(0, section_name, ent->name);
-	}
-
-	free(entries);
-}
-
-static void
-parse_txq(struct app_params *app,
-	const char *section_name,
-	struct rte_cfgfile *cfg)
-{
-	struct app_pktq_hwq_out_params *param;
-	struct rte_cfgfile_entry *entries;
-	int n_entries, i;
-	ssize_t param_idx;
-
-	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
-	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
-
-	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
-	PARSE_ERROR_MALLOC(entries != NULL);
-
-	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
-
-	param_idx = APP_PARAM_ADD(app->hwq_out_params, section_name);
-	param = &app->hwq_out_params[param_idx];
-	PARSE_CHECK_DUPLICATE_SECTION(param);
-
-	APP_PARAM_ADD_LINK_FOR_TXQ(app, section_name);
-
-	for (i = 0; i < n_entries; i++) {
-		struct rte_cfgfile_entry *ent = &entries[i];
-
-		if (strcmp(ent->name, "size") == 0) {
-			int status = parser_read_uint32(&param->size,
-				ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "burst") == 0) {
-			int status = parser_read_uint32(&param->burst,
-				ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "dropless") == 0) {
-			int status = parser_read_arg_bool(ent->value);
-
-
-			PARSE_ERROR((status != -EINVAL), section_name,
-				ent->name);
-			param->dropless = status;
-			continue;
-		}
-
-		if (strcmp(ent->name, "n_retries") == 0) {
-			int status = parser_read_uint64(&param->n_retries,
-				ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		/* unrecognized */
-		PARSE_ERROR_INVALID(0, section_name, ent->name);
-	}
-
-	free(entries);
-}
-
-static void
-parse_swq(struct app_params *app,
-	const char *section_name,
-	struct rte_cfgfile *cfg)
-{
-	struct app_pktq_swq_params *param;
-	struct rte_cfgfile_entry *entries;
-	int n_entries, i;
-	uint32_t mtu_present = 0;
-	uint32_t metadata_size_present = 0;
-	uint32_t mempool_direct_present = 0;
-	uint32_t mempool_indirect_present = 0;
-
-	ssize_t param_idx;
-
-	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
-	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
-
-	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
-	PARSE_ERROR_MALLOC(entries != NULL);
-
-	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
-
-	param_idx = APP_PARAM_ADD(app->swq_params, section_name);
-	param = &app->swq_params[param_idx];
-	PARSE_CHECK_DUPLICATE_SECTION(param);
-
-	for (i = 0; i < n_entries; i++) {
-		struct rte_cfgfile_entry *ent = &entries[i];
-
-		if (strcmp(ent->name, "size") == 0) {
-			int status = parser_read_uint32(&param->size,
-				ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "burst_read") == 0) {
-			int status = parser_read_uint32(&
-				param->burst_read, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "burst_write") == 0) {
-			int status = parser_read_uint32(
-				&param->burst_write, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "dropless") == 0) {
-			int status = parser_read_arg_bool(ent->value);
-
-			PARSE_ERROR((status != -EINVAL), section_name,
-				ent->name);
-			param->dropless = status;
-			continue;
-		}
-
-		if (strcmp(ent->name, "n_retries") == 0) {
-			int status = parser_read_uint64(&param->n_retries,
-				ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "cpu") == 0) {
-			int status = parser_read_uint32(
-				&param->cpu_socket_id, ent->value);
-
-			PARSE_ERROR((status == 0), section_name, ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "ipv4_frag") == 0) {
-			int status = parser_read_arg_bool(ent->value);
-
-			PARSE_ERROR((status != -EINVAL), section_name,
-				ent->name);
-
-			param->ipv4_frag = status;
-			if (param->mtu == 0)
-				param->mtu = 1500;
-
-			continue;
-		}
-
-		if (strcmp(ent->name, "ipv6_frag") == 0) {
-			int status = parser_read_arg_bool(ent->value);
-
-			PARSE_ERROR((status != -EINVAL), section_name,
-				ent->name);
-			param->ipv6_frag = status;
-			if (param->mtu == 0)
-				param->mtu = 1320;
-			continue;
-		}
-
-		if (strcmp(ent->name, "ipv4_ras") == 0) {
-			int status = parser_read_arg_bool(ent->value);
-
-			PARSE_ERROR((status != -EINVAL), section_name,
-				ent->name);
-			param->ipv4_ras = status;
-			continue;
-		}
-
-		if (strcmp(ent->name, "ipv6_ras") == 0) {
-			int status = parser_read_arg_bool(ent->value);
-
-			PARSE_ERROR((status != -EINVAL), section_name,
-				ent->name);
-			param->ipv6_ras = status;
-			continue;
-		}
-
-		if (strcmp(ent->name, "mtu") == 0) {
-			int status = parser_read_uint32(&param->mtu,
-					ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			mtu_present = 1;
-			continue;
-		}
-
-		if (strcmp(ent->name, "metadata_size") == 0) {
-			int status = parser_read_uint32(
-				&param->metadata_size, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			metadata_size_present = 1;
-			continue;
-		}
-
-		if (strcmp(ent->name, "mempool_direct") == 0) {
-			int status = validate_name(ent->value,
-				"MEMPOOL", 1);
-			ssize_t idx;
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-
-			idx = APP_PARAM_ADD(app->mempool_params, ent->value);
-			param->mempool_direct_id = idx;
-
-			mempool_direct_present = 1;
-			continue;
-		}
-
-		if (strcmp(ent->name, "mempool_indirect") == 0) {
-			int status = validate_name(ent->value,
-				"MEMPOOL", 1);
-			ssize_t idx;
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-
-			idx = APP_PARAM_ADD(app->mempool_params, ent->value);
-			param->mempool_indirect_id = idx;
-
-			mempool_indirect_present = 1;
-			continue;
-		}
-
-		/* unrecognized */
-		PARSE_ERROR_INVALID(0, section_name, ent->name);
-	}
-
-	APP_CHECK(((mtu_present == 0) ||
-		((param->ipv4_frag == 1) || (param->ipv6_frag == 1))),
-		"Parse error in section \"%s\": IPv4/IPv6 fragmentation "
-		"is off, therefore entry \"mtu\" is not allowed",
-		section_name);
-
-	APP_CHECK(((metadata_size_present == 0) ||
-		((param->ipv4_frag == 1) || (param->ipv6_frag == 1))),
-		"Parse error in section \"%s\": IPv4/IPv6 fragmentation "
-		"is off, therefore entry \"metadata_size\" is "
-		"not allowed", section_name);
-
-	APP_CHECK(((mempool_direct_present == 0) ||
-		((param->ipv4_frag == 1) || (param->ipv6_frag == 1))),
-		"Parse error in section \"%s\": IPv4/IPv6 fragmentation "
-		"is off, therefore entry \"mempool_direct\" is "
-		"not allowed", section_name);
-
-	APP_CHECK(((mempool_indirect_present == 0) ||
-		((param->ipv4_frag == 1) || (param->ipv6_frag == 1))),
-		"Parse error in section \"%s\": IPv4/IPv6 fragmentation "
-		"is off, therefore entry \"mempool_indirect\" is "
-		"not allowed", section_name);
-
-	free(entries);
-}
-
-static void
-parse_tm(struct app_params *app,
-	const char *section_name,
-	struct rte_cfgfile *cfg)
-{
-	struct app_pktq_tm_params *param;
-	struct rte_cfgfile_entry *entries;
-	int n_entries, i;
-	ssize_t param_idx;
-
-	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
-	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
-
-	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
-	PARSE_ERROR_MALLOC(entries != NULL);
-
-	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
-
-	param_idx = APP_PARAM_ADD(app->tm_params, section_name);
-	param = &app->tm_params[param_idx];
-	PARSE_CHECK_DUPLICATE_SECTION(param);
-
-	APP_PARAM_ADD_LINK_FOR_TM(app, section_name);
-
-	for (i = 0; i < n_entries; i++) {
-		struct rte_cfgfile_entry *ent = &entries[i];
-
-		if (strcmp(ent->name, "cfg") == 0) {
-			param->file_name = strdup(ent->value);
-			PARSE_ERROR_MALLOC(param->file_name != NULL);
-			continue;
-		}
-
-		if (strcmp(ent->name, "burst_read") == 0) {
-			int status = parser_read_uint32(
-				&param->burst_read, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "burst_write") == 0) {
-			int status = parser_read_uint32(
-				&param->burst_write, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		/* unrecognized */
-		PARSE_ERROR_INVALID(0, section_name, ent->name);
-	}
-
-	free(entries);
-}
-
-static void
-parse_tap(struct app_params *app,
-	const char *section_name,
-	struct rte_cfgfile *cfg)
-{
-	struct app_pktq_tap_params *param;
-	struct rte_cfgfile_entry *entries;
-	int n_entries, i;
-	ssize_t param_idx;
-
-	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
-	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
-
-	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
-	PARSE_ERROR_MALLOC(entries != NULL);
-
-	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
-
-	param_idx = APP_PARAM_ADD(app->tap_params, section_name);
-	param = &app->tap_params[param_idx];
-	PARSE_CHECK_DUPLICATE_SECTION(param);
-
-	for (i = 0; i < n_entries; i++) {
-		struct rte_cfgfile_entry *ent = &entries[i];
-
-		if (strcmp(ent->name, "burst_read") == 0) {
-			int status = parser_read_uint32(
-				&param->burst_read, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "burst_write") == 0) {
-			int status = parser_read_uint32(
-				&param->burst_write, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "dropless") == 0) {
-			int status = parser_read_arg_bool(ent->value);
-
-			PARSE_ERROR((status != -EINVAL), section_name,
-				ent->name);
-			param->dropless = status;
-			continue;
-		}
-
-		if (strcmp(ent->name, "n_retries") == 0) {
-			int status = parser_read_uint64(&param->n_retries,
-				ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "mempool") == 0) {
-			int status = validate_name(ent->value,
-				"MEMPOOL", 1);
-			ssize_t idx;
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-
-			idx = APP_PARAM_ADD(app->mempool_params, ent->value);
-			param->mempool_id = idx;
-
-			continue;
-		}
-
-		/* unrecognized */
-		PARSE_ERROR_INVALID(0, section_name, ent->name);
-	}
-
-	free(entries);
-}
-
-static void
-parse_kni(struct app_params *app,
-		  const char *section_name,
-		  struct rte_cfgfile *cfg)
-{
-	struct app_pktq_kni_params *param;
-	struct rte_cfgfile_entry *entries;
-	int n_entries, i;
-	ssize_t param_idx;
-
-	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
-	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
-
-	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
-	PARSE_ERROR_MALLOC(entries != NULL);
-
-	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
-
-	param_idx = APP_PARAM_ADD(app->kni_params, section_name);
-	param = &app->kni_params[param_idx];
-	PARSE_CHECK_DUPLICATE_SECTION(param);
-
-	APP_PARAM_ADD_LINK_FOR_KNI(app, section_name);
-
-	for (i = 0; i < n_entries; i++) {
-		struct rte_cfgfile_entry *ent = &entries[i];
-
-		if (strcmp(ent->name, "core") == 0) {
-			int status = parse_pipeline_core(
-					&param->socket_id,
-					&param->core_id,
-					&param->hyper_th_id,
-					ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-						ent->name);
-			param->force_bind = 1;
-			continue;
-		}
-
-		if (strcmp(ent->name, "mempool") == 0) {
-			int status = validate_name(ent->value,
-				"MEMPOOL", 1);
-			ssize_t idx;
-
-			PARSE_ERROR((status == 0), section_name,
-						ent->name);
-
-			idx = APP_PARAM_ADD(app->mempool_params, ent->value);
-			param->mempool_id = idx;
-			continue;
-		}
-
-		if (strcmp(ent->name, "burst_read") == 0) {
-			int status = parser_read_uint32(&param->burst_read,
-						ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-						ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "burst_write") == 0) {
-			int status = parser_read_uint32(&param->burst_write,
-						ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-						ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "dropless") == 0) {
-			int status = parser_read_arg_bool(ent->value);
-
-			PARSE_ERROR((status != -EINVAL), section_name,
-						ent->name);
-			param->dropless = status;
-			continue;
-		}
-
-		if (strcmp(ent->name, "n_retries") == 0) {
-			int status = parser_read_uint64(&param->n_retries,
-						ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-						ent->name);
-			continue;
-		}
-
-		/* unrecognized */
-		PARSE_ERROR_INVALID(0, section_name, ent->name);
-	}
-
-	free(entries);
-}
-
-static void
-parse_source(struct app_params *app,
-	const char *section_name,
-	struct rte_cfgfile *cfg)
-{
-	struct app_pktq_source_params *param;
-	struct rte_cfgfile_entry *entries;
-	int n_entries, i;
-	ssize_t param_idx;
-	uint32_t pcap_file_present = 0;
-	uint32_t pcap_size_present = 0;
-
-	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
-	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
-
-	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
-	PARSE_ERROR_MALLOC(entries != NULL);
-
-	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
-
-	param_idx = APP_PARAM_ADD(app->source_params, section_name);
-	param = &app->source_params[param_idx];
-	PARSE_CHECK_DUPLICATE_SECTION(param);
-
-	for (i = 0; i < n_entries; i++) {
-		struct rte_cfgfile_entry *ent = &entries[i];
-
-		if (strcmp(ent->name, "mempool") == 0) {
-			int status = validate_name(ent->value,
-				"MEMPOOL", 1);
-			ssize_t idx;
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-
-			idx = APP_PARAM_ADD(app->mempool_params, ent->value);
-			param->mempool_id = idx;
-			continue;
-		}
-
-		if (strcmp(ent->name, "burst") == 0) {
-			int status = parser_read_uint32(&param->burst,
-				ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "pcap_file_rd") == 0) {
-			PARSE_ERROR_DUPLICATE((pcap_file_present == 0),
-				section_name, ent->name);
-
-			param->file_name = strdup(ent->value);
-
-			PARSE_ERROR_MALLOC(param->file_name != NULL);
-			pcap_file_present = 1;
-
-			continue;
-		}
-
-		if (strcmp(ent->name, "pcap_bytes_rd_per_pkt") == 0) {
-			int status;
-
-			PARSE_ERROR_DUPLICATE((pcap_size_present == 0),
-				section_name, ent->name);
-
-			status = parser_read_uint32(
-				&param->n_bytes_per_pkt, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			pcap_size_present = 1;
-
-			continue;
-		}
-
-		/* unrecognized */
-		PARSE_ERROR_INVALID(0, section_name, ent->name);
-	}
-
-	free(entries);
-}
-
-static void
-parse_sink(struct app_params *app,
-	const char *section_name,
-	struct rte_cfgfile *cfg)
-{
-	struct app_pktq_sink_params *param;
-	struct rte_cfgfile_entry *entries;
-	int n_entries, i;
-	ssize_t param_idx;
-	uint32_t pcap_file_present = 0;
-	uint32_t pcap_n_pkt_present = 0;
-
-	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
-	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
-
-	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
-	PARSE_ERROR_MALLOC(entries != NULL);
-
-	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
-
-	param_idx = APP_PARAM_ADD(app->sink_params, section_name);
-	param = &app->sink_params[param_idx];
-	PARSE_CHECK_DUPLICATE_SECTION(param);
-
-	for (i = 0; i < n_entries; i++) {
-		struct rte_cfgfile_entry *ent = &entries[i];
-
-		if (strcmp(ent->name, "pcap_file_wr") == 0) {
-			PARSE_ERROR_DUPLICATE((pcap_file_present == 0),
-				section_name, ent->name);
-
-			param->file_name = strdup(ent->value);
-
-			PARSE_ERROR_MALLOC((param->file_name != NULL));
-
-			continue;
-		}
-
-		if (strcmp(ent->name, "pcap_n_pkt_wr") == 0) {
-			int status;
-
-			PARSE_ERROR_DUPLICATE((pcap_n_pkt_present == 0),
-				section_name, ent->name);
-
-			status = parser_read_uint32(
-				&param->n_pkts_to_dump, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-
-			continue;
-		}
-
-		/* unrecognized */
-		PARSE_ERROR_INVALID(0, section_name, ent->name);
-	}
-
-	free(entries);
-}
-
-static void
-parse_msgq_req_pipeline(struct app_params *app,
-	const char *section_name,
-	struct rte_cfgfile *cfg)
-{
-	struct app_msgq_params *param;
-	struct rte_cfgfile_entry *entries;
-	int n_entries, i;
-	ssize_t param_idx;
-
-	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
-	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
-
-	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
-	PARSE_ERROR_MALLOC(entries != NULL);
-
-	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
-
-	param_idx = APP_PARAM_ADD(app->msgq_params, section_name);
-	param = &app->msgq_params[param_idx];
-	PARSE_CHECK_DUPLICATE_SECTION(param);
-
-	for (i = 0; i < n_entries; i++) {
-		struct rte_cfgfile_entry *ent = &entries[i];
-
-		if (strcmp(ent->name, "size") == 0) {
-			int status = parser_read_uint32(&param->size,
-				ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		/* unrecognized */
-		PARSE_ERROR_INVALID(0, section_name, ent->name);
-	}
-
-	free(entries);
-}
-
-static void
-parse_msgq_rsp_pipeline(struct app_params *app,
-	const char *section_name,
-	struct rte_cfgfile *cfg)
-{
-	struct app_msgq_params *param;
-	struct rte_cfgfile_entry *entries;
-	int n_entries, i;
-	ssize_t param_idx;
-
-	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
-	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
-
-	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
-	PARSE_ERROR_MALLOC(entries != NULL);
-
-	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
-
-	param_idx = APP_PARAM_ADD(app->msgq_params, section_name);
-	param = &app->msgq_params[param_idx];
-	PARSE_CHECK_DUPLICATE_SECTION(param);
-
-	for (i = 0; i < n_entries; i++) {
-		struct rte_cfgfile_entry *ent = &entries[i];
-
-		if (strcmp(ent->name, "size") == 0) {
-			int status = parser_read_uint32(&param->size,
-				ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		/* unrecognized */
-		PARSE_ERROR_INVALID(0, section_name, ent->name);
-	}
-
-	free(entries);
-}
-
-static void
-parse_msgq(struct app_params *app,
-	const char *section_name,
-	struct rte_cfgfile *cfg)
-{
-	struct app_msgq_params *param;
-	struct rte_cfgfile_entry *entries;
-	int n_entries, i;
-	ssize_t param_idx;
-
-	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
-	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
-
-	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
-	PARSE_ERROR_MALLOC(entries != NULL);
-
-	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
-
-	param_idx = APP_PARAM_ADD(app->msgq_params, section_name);
-	param = &app->msgq_params[param_idx];
-	PARSE_CHECK_DUPLICATE_SECTION(param);
-
-	for (i = 0; i < n_entries; i++) {
-		struct rte_cfgfile_entry *ent = &entries[i];
-
-		if (strcmp(ent->name, "size") == 0) {
-			int status = parser_read_uint32(&param->size,
-				ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "cpu") == 0) {
-			int status = parser_read_uint32(
-				&param->cpu_socket_id, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		/* unrecognized */
-		PARSE_ERROR_INVALID(0, section_name, ent->name);
-	}
-
-	free(entries);
-}
-
-typedef void (*config_section_load)(struct app_params *p,
-	const char *section_name,
-	struct rte_cfgfile *cfg);
-
-struct config_section {
-	const char prefix[CFG_NAME_LEN];
-	int numbers;
-	config_section_load load;
-};
-
-static const struct config_section cfg_file_scheme[] = {
-	{"EAL", 0, parse_eal},
-	{"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},
-	{"TAP", 1, parse_tap},
-	{"KNI", 1, parse_kni},
-	{"SOURCE", 1, parse_source},
-	{"SINK", 1, parse_sink},
-	{"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)
-{
-	APP_PARAM_ADD(app->mempool_params, "MEMPOOL0");
-}
-
-static void
-create_implicit_links_from_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%" PRIu32, link_id);
-		idx = APP_PARAM_ADD(app->link_params, name);
-
-		app->link_params[idx].pmd_id = pmd_id;
-		link_id++;
-	}
-}
-
-static void
-assign_link_pmd_id_from_pci_bdf(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_links; i++) {
-		struct app_link_params *link = &app->link_params[i];
-
-		APP_CHECK((strlen(link->pci_bdf)),
-			"Parse error: %s pci_bdf is not configured "
-			"(port_mask is not provided)",
-			link->name);
-
-		link->pmd_id = i;
-	}
-}
-
-int
-app_config_parse(struct app_params *app, const char *file_name)
-{
-	struct rte_cfgfile *cfg;
-	char **section_names;
-	int i, j, sect_count;
-
-	/* Implicit mempools */
-	create_implicit_mempools(app);
-
-	/* Port mask */
-	if (app->port_mask)
-		create_implicit_links_from_port_mask(app, app->port_mask);
-
-	/* Load application configuration file */
-	cfg = rte_cfgfile_load(file_name, 0);
-	APP_CHECK((cfg != NULL), "Parse error: Unable to load config "
-		"file %s", file_name);
-
-	sect_count = rte_cfgfile_num_sections(cfg, NULL, 0);
-	APP_CHECK((sect_count > 0), "Parse error: number of sections "
-		"in file \"%s\" return %d", file_name,
-		sect_count);
-
-	section_names = malloc(sect_count * sizeof(char *));
-	PARSE_ERROR_MALLOC(section_names != NULL);
-
-	for (i = 0; i < sect_count; i++)
-		section_names[i] = malloc(CFG_NAME_LEN);
-
-	rte_cfgfile_sections(cfg, section_names, sect_count);
-
-	for (i = 0; i < sect_count; i++) {
-		const struct config_section *sch_s;
-		int len, cfg_name_len;
-
-		cfg_name_len = strlen(section_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,
-			 * for example: "ABC" should match section name
-			 * "ABC0.0", but it should not match section_name
-			 * "ABCDEF".
-			 */
-			if ((section_names[i][len] != '\0') &&
-				!isdigit(section_names[i][len]))
-				continue;
-
-			if (strncmp(sch_s->prefix, section_names[i], len) == 0)
-				break;
-		}
-
-		APP_CHECK(j < (int)RTE_DIM(cfg_file_scheme),
-			"Parse error: unknown section %s",
-			section_names[i]);
-
-		APP_CHECK(validate_name(section_names[i],
-			sch_s->prefix,
-			sch_s->numbers) == 0,
-			"Parse error: invalid section name \"%s\"",
-			section_names[i]);
-
-		sch_s->load(app, section_names[i], cfg);
-	}
-
-	for (i = 0; i < sect_count; i++)
-		free(section_names[i]);
-
-	free(section_names);
-
-	rte_cfgfile_close(cfg);
-
-	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->tap_params, app->n_pktq_tap);
-	APP_PARAM_COUNT(app->kni_params, app->n_pktq_kni);
-	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);
-
-	if (app->port_mask == 0)
-		assign_link_pmd_id_from_pci_bdf(app);
-
-	/* Save configuration to output file */
-	app_config_save(app, app->output_file);
-
-	/* Load TM configuration files */
-	app_config_parse_tm(app);
-
-	return 0;
-}
-
-static void
-save_eal_params(struct app_params *app, FILE *f)
-{
-	struct app_eal_params *p = &app->eal_params;
-	uint32_t i;
-
-	fprintf(f, "[EAL]\n");
-
-	if (p->coremap)
-		fprintf(f, "%s = %s\n", "lcores", p->coremap);
-
-	if (p->master_lcore_present)
-		fprintf(f, "%s = %" PRIu32 "\n",
-			"master_lcore", p->master_lcore);
-
-	fprintf(f, "%s = %" PRIu32 "\n", "n", p->channels);
-
-	if (p->memory_present)
-		fprintf(f, "%s = %" PRIu32 "\n", "m", p->memory);
-
-	if (p->ranks_present)
-		fprintf(f, "%s = %" PRIu32 "\n", "r", p->ranks);
-
-	for (i = 0; i < APP_MAX_LINKS; i++) {
-		if (p->pci_blacklist[i] == NULL)
-			break;
-
-		fprintf(f, "%s = %s\n", "pci_blacklist",
-			p->pci_blacklist[i]);
-	}
-
-	for (i = 0; i < APP_MAX_LINKS; i++) {
-		if (p->pci_whitelist[i] == NULL)
-			break;
-
-		fprintf(f, "%s = %s\n", "pci_whitelist",
-			p->pci_whitelist[i]);
-	}
-
-	for (i = 0; i < APP_MAX_LINKS; i++) {
-		if (p->vdev[i] == NULL)
-			break;
-
-		fprintf(f, "%s = %s\n", "vdev",
-			p->vdev[i]);
-	}
-
-	if (p->vmware_tsc_map_present)
-		fprintf(f, "%s = %s\n", "vmware_tsc_map",
-			(p->vmware_tsc_map) ? "yes" : "no");
-
-	if (p->proc_type)
-		fprintf(f, "%s = %s\n", "proc_type", p->proc_type);
-
-	if (p->syslog)
-		fprintf(f, "%s = %s\n", "syslog", p->syslog);
-
-	if (p->log_level_present)
-		fprintf(f, "%s = %" PRIu32 "\n", "log_level", p->log_level);
-
-	if (p->version_present)
-		fprintf(f, "%s = %s\n",	"v", (p->version) ? "yes" : "no");
-
-	if (p->help_present)
-		fprintf(f, "%s = %s\n",	"help", (p->help) ? "yes" : "no");
-
-	if (p->no_huge_present)
-		fprintf(f, "%s = %s\n",	"no_huge", (p->no_huge) ? "yes" : "no");
-
-	if (p->no_pci_present)
-		fprintf(f, "%s = %s\n",	"no_pci", (p->no_pci) ? "yes" : "no");
-
-	if (p->no_hpet_present)
-		fprintf(f, "%s = %s\n",	"no_hpet", (p->no_hpet) ? "yes" : "no");
-
-	if (p->no_shconf_present)
-		fprintf(f, "%s = %s\n", "no_shconf",
-			(p->no_shconf) ? "yes" : "no");
-
-	if (p->add_driver)
-		fprintf(f, "%s = %s\n",	"d", p->add_driver);
-
-	if (p->socket_mem)
-		fprintf(f, "%s = %s\n",	"socket_mem", p->socket_mem);
-
-	if (p->huge_dir)
-		fprintf(f, "%s = %s\n", "huge_dir", p->huge_dir);
-
-	if (p->file_prefix)
-		fprintf(f, "%s = %s\n", "file_prefix", p->file_prefix);
-
-	if (p->base_virtaddr)
-		fprintf(f, "%s = %s\n",	"base_virtaddr", p->base_virtaddr);
-
-	if (p->create_uio_dev_present)
-		fprintf(f, "%s = %s\n", "create_uio_dev",
-			(p->create_uio_dev) ? "yes" : "no");
-
-	if (p->vfio_intr)
-		fprintf(f, "%s = %s\n", "vfio_intr", p->vfio_intr);
-
-	fputc('\n', f);
-}
-
-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 = %s\n", "promisc", p->promisc ? "yes" : "no");
-		fprintf(f, "%s = %" PRIu32 "\n", "arp_q", p->arp_q);
-		fprintf(f, "%s = %" PRIu32 "\n", "tcp_syn_q",
-			p->tcp_syn_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);
-
-		if (p->n_rss_qs) {
-			uint32_t j;
-
-			/* rss_qs */
-			fprintf(f, "rss_qs = ");
-			for (j = 0; j < p->n_rss_qs; j++)
-				fprintf(f, "%" PRIu32 " ",	p->rss_qs[j]);
-			fputc('\n', f);
-
-			/* rss_proto_ipv4 */
-			if (p->rss_proto_ipv4) {
-				fprintf(f, "rss_proto_ipv4 = ");
-				if (p->rss_proto_ipv4 & ETH_RSS_IPV4)
-					fprintf(f, "IP ");
-				if (p->rss_proto_ipv4 & ETH_RSS_FRAG_IPV4)
-					fprintf(f, "FRAG ");
-				if (p->rss_proto_ipv4 &
-					ETH_RSS_NONFRAG_IPV4_TCP)
-					fprintf(f, "TCP ");
-				if (p->rss_proto_ipv4 &
-					ETH_RSS_NONFRAG_IPV4_UDP)
-					fprintf(f, "UDP ");
-				if (p->rss_proto_ipv4 &
-					ETH_RSS_NONFRAG_IPV4_SCTP)
-					fprintf(f, "SCTP ");
-				if (p->rss_proto_ipv4 &
-					ETH_RSS_NONFRAG_IPV4_OTHER)
-					fprintf(f, "OTHER ");
-				fprintf(f, "\n");
-			} else
-				fprintf(f, "; rss_proto_ipv4 = <NONE>\n");
-
-			/* rss_proto_ipv6 */
-			if (p->rss_proto_ipv6) {
-				fprintf(f, "rss_proto_ipv6 = ");
-				if (p->rss_proto_ipv6 & ETH_RSS_IPV6)
-					fprintf(f, "IP ");
-				if (p->rss_proto_ipv6 & ETH_RSS_FRAG_IPV6)
-					fprintf(f, "FRAG ");
-				if (p->rss_proto_ipv6 &
-					ETH_RSS_NONFRAG_IPV6_TCP)
-					fprintf(f, "TCP ");
-				if (p->rss_proto_ipv6 &
-					ETH_RSS_NONFRAG_IPV6_UDP)
-					fprintf(f, "UDP ");
-				if (p->rss_proto_ipv6 &
-					ETH_RSS_NONFRAG_IPV6_SCTP)
-					fprintf(f, "SCTP ");
-				if (p->rss_proto_ipv6 &
-					ETH_RSS_NONFRAG_IPV6_OTHER)
-					fprintf(f, "OTHER ");
-				if (p->rss_proto_ipv6 & ETH_RSS_IPV6_EX)
-					fprintf(f, "IP_EX ");
-				if (p->rss_proto_ipv6 &
-					ETH_RSS_IPV6_TCP_EX)
-					fprintf(f, "TCP_EX ");
-				if (p->rss_proto_ipv6 &
-					ETH_RSS_IPV6_UDP_EX)
-					fprintf(f, "UDP_EX ");
-				fprintf(f, "\n");
-			} else
-				fprintf(f, "; rss_proto_ipv6 = <NONE>\n");
-
-			/* rss_proto_l2 */
-			if (p->rss_proto_l2) {
-				fprintf(f, "rss_proto_l2 = ");
-				if (p->rss_proto_l2 & ETH_RSS_L2_PAYLOAD)
-					fprintf(f, "L2 ");
-				fprintf(f, "\n");
-			} else
-				fprintf(f, "; rss_proto_l2 = <NONE>\n");
-		} else {
-			fprintf(f, "; rss_qs = <NONE>\n");
-			fprintf(f, "; rss_proto_ipv4 = <NONE>\n");
-			fprintf(f, "; rss_proto_ipv6 = <NONE>\n");
-			fprintf(f, "; rss_proto_l2 = <NONE>\n");
-		}
-
-		if (strlen(p->pci_bdf))
-			fprintf(f, "%s = %s\n", "pci_bdf", p->pci_bdf);
-
-		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");
-		fprintf(f, "%s = %" PRIu64 "\n", "n_retries", p->n_retries);
-
-		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);
-		fprintf(f, "%s = %s\n", "ipv4_frag", p->ipv4_frag ? "yes" : "no");
-		fprintf(f, "%s = %s\n", "ipv6_frag", p->ipv6_frag ? "yes" : "no");
-		fprintf(f, "%s = %s\n", "ipv4_ras", p->ipv4_ras ? "yes" : "no");
-		fprintf(f, "%s = %s\n", "ipv6_ras", p->ipv6_ras ? "yes" : "no");
-		if ((p->ipv4_frag == 1) || (p->ipv6_frag == 1)) {
-			fprintf(f, "%s = %" PRIu32 "\n", "mtu", p->mtu);
-			fprintf(f, "%s = %" PRIu32 "\n", "metadata_size", p->metadata_size);
-			fprintf(f, "%s = %s\n",
-				"mempool_direct",
-				app->mempool_params[p->mempool_direct_id].name);
-			fprintf(f, "%s = %s\n",
-				"mempool_indirect",
-				app->mempool_params[p->mempool_indirect_id].name);
-		}
-
-		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 = %" PRIu32 "\n", "burst_read", p->burst_read);
-		fprintf(f, "%s = %" PRIu32 "\n", "burst_write", p->burst_write);
-
-		fputc('\n', f);
-	}
-}
-
-static void
-save_tap_params(struct app_params *app, FILE *f)
-{
-	struct app_pktq_tap_params *p;
-	size_t i, count;
-
-	count = RTE_DIM(app->tap_params);
-	for (i = 0; i < count; i++) {
-		p = &app->tap_params[i];
-		if (!APP_PARAM_VALID(p))
-			continue;
-
-		fprintf(f, "[%s]\n", p->name);
-		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 = %s\n", "mempool",
-			app->mempool_params[p->mempool_id].name);
-
-		fputc('\n', f);
-	}
-}
-
-static void
-save_kni_params(struct app_params *app, FILE *f)
-{
-	struct app_pktq_kni_params *p;
-	size_t i, count;
-
-	count = RTE_DIM(app->kni_params);
-	for (i = 0; i < count; i++) {
-		p = &app->kni_params[i];
-		if (!APP_PARAM_VALID(p))
-			continue;
-
-		/* section name */
-		fprintf(f, "[%s]\n", p->name);
-
-		/* core */
-		if (p->force_bind) {
-			fprintf(f, "; force_bind = 1\n");
-			fprintf(f, "core = s%" PRIu32 "c%" PRIu32 "%s\n",
-					p->socket_id,
-					p->core_id,
-					(p->hyper_th_id) ? "h" : "");
-		} else
-			fprintf(f, "; force_bind = 0\n");
-
-		/* mempool */
-		fprintf(f, "%s = %s\n", "mempool",
-				app->mempool_params[p->mempool_id].name);
-
-		/* burst_read */
-		fprintf(f, "%s = %" PRIu32 "\n", "burst_read", p->burst_read);
-
-		/* burst_write */
-		fprintf(f, "%s = %" PRIu32 "\n", "burst_write", p->burst_write);
-
-		/* dropless */
-		fprintf(f, "%s = %s\n",
-				"dropless",
-				p->dropless ? "yes" : "no");
-
-		/* n_retries */
-		fprintf(f, "%s = %" PRIu64 "\n", "n_retries", p->n_retries);
-
-		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 = %" PRIu32 "\n", "burst", p->burst);
-		fprintf(f, "%s = %s\n", "pcap_file_rd", p->file_name);
-		fprintf(f, "%s = %" PRIu32 "\n", "pcap_bytes_rd_per_pkt",
-			p->n_bytes_per_pkt);
-		fputc('\n', f);
-	}
-}
-
-static void
-save_sink_params(struct app_params *app, FILE *f)
-{
-	struct app_pktq_sink_params *p;
-	size_t i, count;
-
-	count = RTE_DIM(app->sink_params);
-	for (i = 0; i < count; i++) {
-		p = &app->sink_params[i];
-		if (!APP_PARAM_VALID(p))
-			continue;
-
-		fprintf(f, "[%s]\n", p->name);
-		fprintf(f, "%s = %s\n", "pcap_file_wr", p->file_name);
-		fprintf(f, "%s = %" PRIu32 "\n",
-				"pcap_n_pkt_wr", p->n_pkts_to_dump);
-		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%" PRIu32 "c%" PRIu32 "%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_TAP:
-					name = app->tap_params[pp->id].name;
-					break;
-				case APP_PKTQ_IN_KNI:
-					name = app->kni_params[pp->id].name;
-					break;
-				case APP_PKTQ_IN_SOURCE:
-					name = app->source_params[pp->id].name;
-					break;
-				default:
-					APP_CHECK(0, "System error "
-						"occurred while saving "
-						"parameter to file");
-				}
-
-				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_TAP:
-					name = app->tap_params[pp->id].name;
-					break;
-				case APP_PKTQ_OUT_KNI:
-					name = app->kni_params[pp->id].name;
-					break;
-				case APP_PKTQ_OUT_SINK:
-					name = app->sink_params[pp->id].name;
-					break;
-				default:
-					APP_CHECK(0, "System error "
-						"occurred while saving "
-						"parameter to file");
-				}
-
-				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_out) {
-			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 = %" PRIu32 "\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;
-	char *name, *dir_name;
-	int status;
-
-	name = strdup(file_name);
-	dir_name = dirname(name);
-	status = access(dir_name, W_OK);
-	APP_CHECK((status == 0),
-		"Error: need write access privilege to directory "
-		"\"%s\" to save configuration\n", dir_name);
-
-	file = fopen(file_name, "w");
-	APP_CHECK((file != NULL),
-		"Error: failed to save configuration to file \"%s\"",
-		file_name);
-
-	save_eal_params(app, file);
-	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_tap_params(app, file);
-	save_kni_params(app, file);
-	save_source_params(app, file);
-	save_sink_params(app, file);
-	save_msgq_params(app, file);
-
-	fclose(file);
-	free(name);
-}
-
-int
-app_config_init(struct app_params *app)
-{
-	size_t i;
-
-	memcpy(app, &app_params_default, sizeof(struct app_params));
-
-	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->tap_params); i++)
-		memcpy(&app->tap_params[i],
-			&default_tap_params,
-			sizeof(default_tap_params));
-
-	for (i = 0; i < RTE_DIM(app->kni_params); i++)
-		memcpy(&app->kni_params[i],
-			   &default_kni_params,
-			   sizeof(default_kni_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;
-}
-
-static char *
-filenamedup(const char *filename, const char *suffix)
-{
-	char *s = malloc(strlen(filename) + strlen(suffix) + 1);
-
-	if (!s)
-		return NULL;
-
-	sprintf(s, "%s%s", filename, suffix);
-	return s;
-}
-
-int
-app_config_args(struct app_params *app, int argc, char **argv)
-{
-	const char *optname;
-	int opt, option_index;
-	int f_present, s_present, p_present, l_present;
-	int preproc_present, preproc_params_present;
-	int scaned = 0;
-
-	static struct option lgopts[] = {
-		{ "preproc", 1, 0, 0 },
-		{ "preproc-args", 1, 0, 0 },
-		{ NULL,  0, 0, 0 }
-	};
-
-	/* Copy application name */
-	strncpy(app->app_name, argv[0], APP_APPNAME_SIZE - 1);
-
-	f_present = 0;
-	s_present = 0;
-	p_present = 0;
-	l_present = 0;
-	preproc_present = 0;
-	preproc_params_present = 0;
-
-	while ((opt = getopt_long(argc, argv, "f:s:p:l:", lgopts,
-			&option_index)) != EOF)
-		switch (opt) {
-		case 'f':
-			if (f_present)
-				rte_panic("Error: Config file is provided "
-					"more than once\n");
-			f_present = 1;
-
-			if (!strlen(optarg))
-				rte_panic("Error: Config file name is null\n");
-
-			app->config_file = strdup(optarg);
-			if (app->config_file == NULL)
-				rte_panic("Error: Memory allocation failure\n");
-
-			break;
-
-		case 's':
-			if (s_present)
-				rte_panic("Error: Script file is provided "
-					"more than once\n");
-			s_present = 1;
-
-			if (!strlen(optarg))
-				rte_panic("Error: Script file name is null\n");
-
-			app->script_file = strdup(optarg);
-			if (app->script_file == NULL)
-				rte_panic("Error: Memory allocation failure\n");
-
-			break;
-
-		case 'p':
-			if (p_present)
-				rte_panic("Error: PORT_MASK is provided "
-					"more than once\n");
-			p_present = 1;
-
-			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");
-
-			break;
-
-		case 'l':
-			if (l_present)
-				rte_panic("Error: LOG_LEVEL is provided "
-					"more than once\n");
-			l_present = 1;
-
-			if ((sscanf(optarg, "%" SCNu32 "%n", &app->log_level,
-				&scaned) != 1) ||
-				((size_t) scaned != strlen(optarg)) ||
-				(app->log_level >= APP_LOG_LEVELS))
-				rte_panic("Error: LOG_LEVEL invalid value\n");
-
-			break;
-
-		case 0:
-			optname = lgopts[option_index].name;
-
-			if (strcmp(optname, "preproc") == 0) {
-				if (preproc_present)
-					rte_panic("Error: Preprocessor argument "
-						"is provided more than once\n");
-				preproc_present = 1;
-
-				app->preproc = strdup(optarg);
-				break;
-			}
-
-			if (strcmp(optname, "preproc-args") == 0) {
-				if (preproc_params_present)
-					rte_panic("Error: Preprocessor args "
-						"are provided more than once\n");
-				preproc_params_present = 1;
-
-				app->preproc_args = strdup(optarg);
-				break;
-			}
-
-			app_print_usage(argv[0]);
-			break;
-
-		default:
-			app_print_usage(argv[0]);
-		}
-
-	optind = 1; /* reset getopt lib */
-
-	/* Check dependencies between args */
-	if (preproc_params_present && (preproc_present == 0))
-		rte_panic("Error: Preprocessor args specified while "
-			"preprocessor is not defined\n");
-
-	app->parser_file = preproc_present ?
-		filenamedup(app->config_file, ".preproc") :
-		strdup(app->config_file);
-	app->output_file = filenamedup(app->config_file, ".out");
-
-	return 0;
-}
-
-int
-app_config_preproc(struct app_params *app)
-{
-	char buffer[256];
-	int status;
-
-	if (app->preproc == NULL)
-		return 0;
-
-	status = access(app->config_file, F_OK | R_OK);
-	APP_CHECK((status == 0), "Error: Unable to open file %s",
-		app->config_file);
-
-	snprintf(buffer, sizeof(buffer), "%s %s %s > %s",
-		app->preproc,
-		app->preproc_args ? app->preproc_args : "",
-		app->config_file,
-		app->parser_file);
-
-	status = system(buffer);
-	APP_CHECK((WIFEXITED(status) && (WEXITSTATUS(status) == 0)),
-		"Error occurred while pre-processing file \"%s\"\n",
-		app->config_file);
-
-	return status;
-}
diff --git a/examples/ip_pipeline/config_parse_tm.c b/examples/ip_pipeline/config_parse_tm.c
deleted file mode 100644
index 6edd2ca..0000000
--- a/examples/ip_pipeline/config_parse_tm.c
+++ /dev/null
@@ -1,419 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-#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 <libgen.h>
-#include <unistd.h>
-
-#include <rte_errno.h>
-#include <rte_cfgfile.h>
-#include <rte_string_fns.h>
-
-#include "app.h"
-
-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", "mtu");
-	if (entry)
-		port_params->mtu = (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 %" PRId32 " 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 %" PRId32 " 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 %" PRId32 " 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 %" PRId32 " 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 %" PRId32, 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 %" PRId32, 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);
-			struct rte_cfgfile_entry entries[n_entries];
-
-			rte_cfgfile_section_entries(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 + 1];
-
-					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 %" PRId32,
-							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 i;
-
-	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_port_params));
-	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];
-
-	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;
-}
-
-int
-app_config_parse_tm(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < RTE_DIM(app->tm_params); i++) {
-		struct app_pktq_tm_params *p = &app->tm_params[i];
-		int status;
-
-		if (!APP_PARAM_VALID(p))
-			break;
-
-		status = tm_cfgfile_load(p);
-		APP_CHECK(status == 0,
-			"Parse error for %s configuration file \"%s\"\n",
-			p->name,
-			p->file_name);
-	}
-
-	return 0;
-}
diff --git a/examples/ip_pipeline/cpu_core_map.c b/examples/ip_pipeline/cpu_core_map.c
deleted file mode 100644
index 231f38e..0000000
--- a/examples/ip_pipeline/cpu_core_map.c
+++ /dev/null
@@ -1,471 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#include <inttypes.h>
-#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%" PRIu32 "/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%" PRIu32 "/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 !defined(RTE_ARCH_PPC_64)
-			if (lcore_socket_id < 0)
-				return -1;
-#endif
-
-			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 !defined(RTE_ARCH_PPC_64)
-				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;
-#endif
-
-#if !defined(RTE_ARCH_PPC_64)
-				if (((uint32_t) lcore_socket_id == socket_id) &&
-					((uint32_t) lcore_core_id == core_id)) {
-#else
-				if (((uint32_t) lcore_socket_id == socket_id)) {
-#endif
-					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)
-{
-	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 %" PRIu32 ":\n", socket_id);
-
-		for (core_id = 0;
-			core_id < map->n_cores_per_socket;
-			core_id++) {
-			printf("[%" PRIu32 "] = [", 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 =
-					cpu_core_map_get_core_id_linux(
-						lcore_id);
-
-				printf(" %" PRId32 " (%" PRIu32 ") ",
-					lcore_id,
-					core_id_noncontig);
-			}
-
-			printf("]\n");
-		}
-	}
-}
-
-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)
-{
-	free(map);
-}
diff --git a/examples/ip_pipeline/cpu_core_map.h b/examples/ip_pipeline/cpu_core_map.h
deleted file mode 100644
index 5e50f6e..0000000
--- a/examples/ip_pipeline/cpu_core_map.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#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/init.c b/examples/ip_pipeline/init.c
deleted file mode 100644
index 9430809..0000000
--- a/examples/ip_pipeline/init.c
+++ /dev/null
@@ -1,1343 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2016 Intel Corporation
- */
-
-#include <inttypes.h>
-#include <stdio.h>
-#include <string.h>
-#include <netinet/in.h>
-#ifdef RTE_EXEC_ENV_LINUXAPP
-#include <linux/if.h>
-#include <linux/if_tun.h>
-#endif
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <unistd.h>
-
-#include <rte_cycles.h>
-#include <rte_ethdev.h>
-#include <rte_ether.h>
-#include <rte_ip.h>
-#include <rte_eal.h>
-#include <rte_malloc.h>
-#include <rte_bus_pci.h>
-
-#include "app.h"
-#include "pipeline.h"
-
-#define APP_NAME_SIZE	32
-
-#define APP_RETA_SIZE_MAX     (ETH_RSS_RETA_SIZE_512 / RTE_RETA_GROUP_SIZE)
-
-static void
-app_init_core_map(struct app_params *app)
-{
-	APP_LOG(app, HIGH, "Initializing CPU core map ...");
-	app->core_map = cpu_core_map_init(RTE_MAX_NUMA_NODES, RTE_MAX_LCORE,
-				4, 0);
-
-	if (app->core_map == NULL)
-		rte_panic("Cannot create CPU core map\n");
-
-	if (app->log_level >= APP_LOG_LEVEL_LOW)
-		cpu_core_map_print(app->core_map);
-}
-
-/* Core Mask String in Hex Representation */
-#define APP_CORE_MASK_STRING_SIZE ((64 * APP_CORE_MASK_SIZE) / 8 * 2 + 1)
-
-static void
-app_init_core_mask(struct app_params *app)
-{
-	uint32_t i;
-	char core_mask_str[APP_CORE_MASK_STRING_SIZE];
-
-	for (i = 0; i < app->n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		int lcore_id;
-
-		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");
-
-		app_core_enable_in_core_mask(app, lcore_id);
-	}
-
-	app_core_build_core_mask_string(app, core_mask_str);
-	APP_LOG(app, HIGH, "CPU core mask = 0x%s", core_mask_str);
-}
-
-static void
-app_init_eal(struct app_params *app)
-{
-	char buffer[256];
-	char core_mask_str[APP_CORE_MASK_STRING_SIZE];
-	struct app_eal_params *p = &app->eal_params;
-	uint32_t n_args = 0;
-	uint32_t i;
-	int status;
-
-	app->eal_argv[n_args++] = strdup(app->app_name);
-
-	app_core_build_core_mask_string(app, core_mask_str);
-	snprintf(buffer, sizeof(buffer), "-c%s", core_mask_str);
-	app->eal_argv[n_args++] = strdup(buffer);
-
-	if (p->coremap) {
-		snprintf(buffer, sizeof(buffer), "--lcores=%s", p->coremap);
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if (p->master_lcore_present) {
-		snprintf(buffer,
-			sizeof(buffer),
-			"--master-lcore=%" PRIu32,
-			p->master_lcore);
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	snprintf(buffer, sizeof(buffer), "-n%" PRIu32, p->channels);
-	app->eal_argv[n_args++] = strdup(buffer);
-
-	if (p->memory_present) {
-		snprintf(buffer, sizeof(buffer), "-m%" PRIu32, p->memory);
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if (p->ranks_present) {
-		snprintf(buffer, sizeof(buffer), "-r%" PRIu32, p->ranks);
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	for (i = 0; i < APP_MAX_LINKS; i++) {
-		if (p->pci_blacklist[i] == NULL)
-			break;
-
-		snprintf(buffer,
-			sizeof(buffer),
-			"--pci-blacklist=%s",
-			p->pci_blacklist[i]);
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if (app->port_mask != 0)
-		for (i = 0; i < APP_MAX_LINKS; i++) {
-			if (p->pci_whitelist[i] == NULL)
-				break;
-
-			snprintf(buffer,
-				sizeof(buffer),
-				"--pci-whitelist=%s",
-				p->pci_whitelist[i]);
-			app->eal_argv[n_args++] = strdup(buffer);
-		}
-	else
-		for (i = 0; i < app->n_links; i++) {
-			char *pci_bdf = app->link_params[i].pci_bdf;
-
-			snprintf(buffer,
-				sizeof(buffer),
-				"--pci-whitelist=%s",
-				pci_bdf);
-			app->eal_argv[n_args++] = strdup(buffer);
-		}
-
-	for (i = 0; i < APP_MAX_LINKS; i++) {
-		if (p->vdev[i] == NULL)
-			break;
-
-		snprintf(buffer,
-			sizeof(buffer),
-			"--vdev=%s",
-			p->vdev[i]);
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if ((p->vmware_tsc_map_present) && p->vmware_tsc_map) {
-		snprintf(buffer, sizeof(buffer), "--vmware-tsc-map");
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if (p->proc_type) {
-		snprintf(buffer,
-			sizeof(buffer),
-			"--proc-type=%s",
-			p->proc_type);
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if (p->syslog) {
-		snprintf(buffer, sizeof(buffer), "--syslog=%s", p->syslog);
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if (p->log_level_present) {
-		snprintf(buffer,
-			sizeof(buffer),
-			"--log-level=%" PRIu32,
-			p->log_level);
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if ((p->version_present) && p->version) {
-		snprintf(buffer, sizeof(buffer), "-v");
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if ((p->help_present) && p->help) {
-		snprintf(buffer, sizeof(buffer), "--help");
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if ((p->no_huge_present) && p->no_huge) {
-		snprintf(buffer, sizeof(buffer), "--no-huge");
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if ((p->no_pci_present) && p->no_pci) {
-		snprintf(buffer, sizeof(buffer), "--no-pci");
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if ((p->no_hpet_present) && p->no_hpet) {
-		snprintf(buffer, sizeof(buffer), "--no-hpet");
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if ((p->no_shconf_present) && p->no_shconf) {
-		snprintf(buffer, sizeof(buffer), "--no-shconf");
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if (p->add_driver) {
-		snprintf(buffer, sizeof(buffer), "-d%s", p->add_driver);
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if (p->socket_mem) {
-		snprintf(buffer,
-			sizeof(buffer),
-			"--socket-mem=%s",
-			p->socket_mem);
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if (p->huge_dir) {
-		snprintf(buffer, sizeof(buffer), "--huge-dir=%s", p->huge_dir);
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if (p->file_prefix) {
-		snprintf(buffer,
-			sizeof(buffer),
-			"--file-prefix=%s",
-			p->file_prefix);
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if (p->base_virtaddr) {
-		snprintf(buffer,
-			sizeof(buffer),
-			"--base-virtaddr=%s",
-			p->base_virtaddr);
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if ((p->create_uio_dev_present) && p->create_uio_dev) {
-		snprintf(buffer, sizeof(buffer), "--create-uio-dev");
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if (p->vfio_intr) {
-		snprintf(buffer,
-			sizeof(buffer),
-			"--vfio-intr=%s",
-			p->vfio_intr);
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	snprintf(buffer, sizeof(buffer), "--");
-	app->eal_argv[n_args++] = strdup(buffer);
-
-	app->eal_argc = n_args;
-
-	APP_LOG(app, HIGH, "Initializing EAL ...");
-	if (app->log_level >= APP_LOG_LEVEL_LOW) {
-		int i;
-
-		fprintf(stdout, "[APP] EAL arguments: \"");
-		for (i = 1; i < app->eal_argc; i++)
-			fprintf(stdout, "%s ", app->eal_argv[i]);
-		fprintf(stdout, "\"\n");
-	}
-
-	status = rte_eal_init(app->eal_argc, app->eal_argv);
-	if (status < 0)
-		rte_panic("EAL init error\n");
-}
-
-static void
-app_init_mempool(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_mempools; i++) {
-		struct app_mempool_params *p = &app->mempool_params[i];
-
-		APP_LOG(app, HIGH, "Initializing %s ...", p->name);
-		app->mempool[i] = rte_pktmbuf_pool_create(
-			p->name,
-			p->pool_size,
-			p->cache_size,
-			0, /* priv_size */
-			p->buffer_size -
-				sizeof(struct rte_mbuf), /* mbuf data size */
-			p->cpu_socket_id);
-
-		if (app->mempool[i] == NULL)
-			rte_panic("%s init error\n", p->name);
-	}
-}
-
-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 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_q,
-	};
-
-	return rte_eth_dev_filter_ctrl(link->pmd_id,
-		RTE_ETH_FILTER_SYN,
-		RTE_ETH_FILTER_ADD,
-		&filter);
-}
-
-static inline int
-app_link_filter_ip_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 = UINT32_MAX, /* Enable */
-		.src_ip = 0,
-		.src_ip_mask = 0, /* Disable */
-		.dst_port = 0,
-		.dst_port_mask = 0, /* Disable */
-		.src_port = 0,
-		.src_port_mask = 0, /* Disable */
-		.proto = 0,
-		.proto_mask = 0, /* 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);
-}
-
-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 = UINT32_MAX, /* Enable */
-		.src_ip = 0,
-		.src_ip_mask = 0, /* Disable */
-		.dst_port = 0,
-		.dst_port_mask = 0, /* Disable */
-		.src_port = 0,
-		.src_port_mask = 0, /* Disable */
-		.proto = 0,
-		.proto_mask = 0, /* 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);
-}
-
-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 = UINT32_MAX, /* Enable */
-		.src_ip = 0,
-		.src_ip_mask = 0, /* Disable */
-		.dst_port = 0,
-		.dst_port_mask = 0, /* Disable */
-		.src_port = 0,
-		.src_port_mask = 0, /* Disable */
-		.proto = IPPROTO_TCP,
-		.proto_mask = UINT8_MAX, /* 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);
-}
-
-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 = UINT32_MAX, /* Enable */
-		.src_ip = 0,
-		.src_ip_mask = 0, /* Disable */
-		.dst_port = 0,
-		.dst_port_mask = 0, /* Disable */
-		.src_port = 0,
-		.src_port_mask = 0, /* Disable */
-		.proto = IPPROTO_TCP,
-		.proto_mask = UINT8_MAX, /* 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);
-}
-
-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 = UINT32_MAX, /* Enable */
-		.src_ip = 0,
-		.src_ip_mask = 0, /* Disable */
-		.dst_port = 0,
-		.dst_port_mask = 0, /* Disable */
-		.src_port = 0,
-		.src_port_mask = 0, /* Disable */
-		.proto = IPPROTO_UDP,
-		.proto_mask = UINT8_MAX, /* 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 = UINT32_MAX, /* Enable */
-		.src_ip = 0,
-		.src_ip_mask = 0, /* Disable */
-		.dst_port = 0,
-		.dst_port_mask = 0, /* Disable */
-		.src_port = 0,
-		.src_port_mask = 0, /* Disable */
-		.proto = IPPROTO_UDP,
-		.proto_mask = UINT8_MAX, /* 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 = UINT32_MAX, /* Enable */
-		.src_ip = 0,
-		.src_ip_mask = 0, /* Disable */
-		.dst_port = 0,
-		.dst_port_mask = 0, /* Disable */
-		.src_port = 0,
-		.src_port_mask = 0, /* Disable */
-		.proto = IPPROTO_SCTP,
-		.proto_mask = UINT8_MAX, /* 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 = UINT32_MAX, /* Enable */
-		.src_ip = 0,
-		.src_ip_mask = 0, /* Disable */
-		.dst_port = 0,
-		.dst_port_mask = 0, /* Disable */
-		.src_port = 0,
-		.src_port_mask = 0, /* Disable */
-		.proto = IPPROTO_SCTP,
-		.proto_mask = UINT8_MAX, /* 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);
-}
-
-static void
-app_link_set_arp_filter(struct app_params *app, struct app_link_params *cp)
-{
-	if (cp->arp_q != 0) {
-		int status = app_link_filter_arp_add(cp);
-
-		APP_LOG(app, LOW, "%s (%" PRIu32 "): "
-			"Adding ARP filter (queue = %" PRIu32 ")",
-			cp->name, cp->pmd_id, cp->arp_q);
-
-		if (status)
-			rte_panic("%s (%" PRIu32 "): "
-				"Error adding ARP filter "
-				"(queue = %" PRIu32 ") (%" PRId32 ")\n",
-				cp->name, cp->pmd_id, cp->arp_q, status);
-	}
-}
-
-static void
-app_link_set_tcp_syn_filter(struct app_params *app, struct app_link_params *cp)
-{
-	if (cp->tcp_syn_q != 0) {
-		int status = app_link_filter_tcp_syn_add(cp);
-
-		APP_LOG(app, LOW, "%s (%" PRIu32 "): "
-			"Adding TCP SYN filter (queue = %" PRIu32 ")",
-			cp->name, cp->pmd_id, cp->tcp_syn_q);
-
-		if (status)
-			rte_panic("%s (%" PRIu32 "): "
-				"Error adding TCP SYN filter "
-				"(queue = %" PRIu32 ") (%" PRId32 ")\n",
-				cp->name, cp->pmd_id, cp->tcp_syn_q,
-				status);
-	}
-}
-
-void
-app_link_up_internal(struct app_params *app, struct app_link_params *cp)
-{
-	uint32_t i;
-	int status;
-
-	/* For each link, add filters for IP of current link */
-	if (cp->ip != 0) {
-		for (i = 0; i < app->n_links; i++) {
-			struct app_link_params *p = &app->link_params[i];
-
-			/* IP */
-			if (p->ip_local_q != 0) {
-				int status = app_link_filter_ip_add(p, cp);
-
-				APP_LOG(app, LOW, "%s (%" PRIu32 "): "
-					"Adding IP filter (queue= %" PRIu32
-					", IP = 0x%08" PRIx32 ")",
-					p->name, p->pmd_id, p->ip_local_q,
-					cp->ip);
-
-				if (status)
-					rte_panic("%s (%" PRIu32 "): "
-						"Error adding IP "
-						"filter (queue= %" PRIu32 ", "
-						"IP = 0x%08" PRIx32
-						") (%" PRId32 ")\n",
-						p->name, p->pmd_id,
-						p->ip_local_q, cp->ip, status);
-			}
-
-			/* TCP */
-			if (p->tcp_local_q != 0) {
-				int status = app_link_filter_tcp_add(p, cp);
-
-				APP_LOG(app, LOW, "%s (%" PRIu32 "): "
-					"Adding TCP filter "
-					"(queue = %" PRIu32
-					", IP = 0x%08" PRIx32 ")",
-					p->name, p->pmd_id, p->tcp_local_q,
-					cp->ip);
-
-				if (status)
-					rte_panic("%s (%" PRIu32 "): "
-						"Error adding TCP "
-						"filter (queue = %" PRIu32 ", "
-						"IP = 0x%08" PRIx32
-						") (%" PRId32 ")\n",
-						p->name, p->pmd_id,
-						p->tcp_local_q, cp->ip, status);
-			}
-
-			/* UDP */
-			if (p->udp_local_q != 0) {
-				int status = app_link_filter_udp_add(p, cp);
-
-				APP_LOG(app, LOW, "%s (%" PRIu32 "): "
-					"Adding UDP filter "
-					"(queue = %" PRIu32
-					", IP = 0x%08" PRIx32 ")",
-					p->name, p->pmd_id, p->udp_local_q,
-					cp->ip);
-
-				if (status)
-					rte_panic("%s (%" PRIu32 "): "
-						"Error adding UDP "
-						"filter (queue = %" PRIu32 ", "
-						"IP = 0x%08" PRIx32
-						") (%" PRId32 ")\n",
-						p->name, p->pmd_id,
-						p->udp_local_q, cp->ip, status);
-			}
-
-			/* SCTP */
-			if (p->sctp_local_q != 0) {
-				int status = app_link_filter_sctp_add(p, cp);
-
-				APP_LOG(app, LOW, "%s (%" PRIu32
-					"): Adding SCTP filter "
-					"(queue = %" PRIu32
-					", IP = 0x%08" PRIx32 ")",
-					p->name, p->pmd_id, p->sctp_local_q,
-					cp->ip);
-
-				if (status)
-					rte_panic("%s (%" PRIu32 "): "
-						"Error adding SCTP "
-						"filter (queue = %" PRIu32 ", "
-						"IP = 0x%08" PRIx32
-						") (%" PRId32 ")\n",
-						p->name, p->pmd_id,
-						p->sctp_local_q, cp->ip,
-						status);
-			}
-		}
-	}
-
-	/* PMD link up */
-	status = rte_eth_dev_set_link_up(cp->pmd_id);
-	/* Do not panic if PMD does not provide link up functionality */
-	if (status < 0 && status != -ENOTSUP)
-		rte_panic("%s (%" PRIu32 "): PMD set link up error %"
-			PRId32 "\n", cp->name, cp->pmd_id, status);
-
-	/* Mark link as UP */
-	cp->state = 1;
-}
-
-void
-app_link_down_internal(struct app_params *app, struct app_link_params *cp)
-{
-	uint32_t i;
-	int status;
-
-	/* PMD link down */
-	status = rte_eth_dev_set_link_down(cp->pmd_id);
-	/* Do not panic if PMD does not provide link down functionality */
-	if (status < 0 && status != -ENOTSUP)
-		rte_panic("%s (%" PRIu32 "): PMD set link down error %"
-			PRId32 "\n", cp->name, cp->pmd_id, status);
-
-	/* Mark link as DOWN */
-	cp->state = 0;
-
-	/* Return if current link IP is not valid */
-	if (cp->ip == 0)
-		return;
-
-	/* For each link, remove filters for IP of current link */
-	for (i = 0; i < app->n_links; i++) {
-		struct app_link_params *p = &app->link_params[i];
-
-		/* IP */
-		if (p->ip_local_q != 0) {
-			int status = app_link_filter_ip_del(p, cp);
-
-			APP_LOG(app, LOW, "%s (%" PRIu32
-				"): Deleting IP filter "
-				"(queue = %" PRIu32 ", IP = 0x%" PRIx32 ")",
-				p->name, p->pmd_id, p->ip_local_q, cp->ip);
-
-			if (status)
-				rte_panic("%s (%" PRIu32
-					"): Error deleting IP filter "
-					"(queue = %" PRIu32
-					", IP = 0x%" PRIx32
-					") (%" PRId32 ")\n",
-					p->name, p->pmd_id, p->ip_local_q,
-					cp->ip, status);
-		}
-
-		/* TCP */
-		if (p->tcp_local_q != 0) {
-			int status = app_link_filter_tcp_del(p, cp);
-
-			APP_LOG(app, LOW, "%s (%" PRIu32
-				"): Deleting TCP filter "
-				"(queue = %" PRIu32
-				", IP = 0x%" PRIx32 ")",
-				p->name, p->pmd_id, p->tcp_local_q, cp->ip);
-
-			if (status)
-				rte_panic("%s (%" PRIu32
-					"): Error deleting TCP filter "
-					"(queue = %" PRIu32
-					", IP = 0x%" PRIx32
-					") (%" PRId32 ")\n",
-					p->name, p->pmd_id, p->tcp_local_q,
-					cp->ip, status);
-		}
-
-		/* UDP */
-		if (p->udp_local_q != 0) {
-			int status = app_link_filter_udp_del(p, cp);
-
-			APP_LOG(app, LOW, "%s (%" PRIu32
-				"): Deleting UDP filter "
-				"(queue = %" PRIu32 ", IP = 0x%" PRIx32 ")",
-				p->name, p->pmd_id, p->udp_local_q, cp->ip);
-
-			if (status)
-				rte_panic("%s (%" PRIu32
-					"): Error deleting UDP filter "
-					"(queue = %" PRIu32
-					", IP = 0x%" PRIx32
-					") (%" PRId32 ")\n",
-					p->name, p->pmd_id, p->udp_local_q,
-					cp->ip, status);
-		}
-
-		/* SCTP */
-		if (p->sctp_local_q != 0) {
-			int status = app_link_filter_sctp_del(p, cp);
-
-			APP_LOG(app, LOW, "%s (%" PRIu32
-				"): Deleting SCTP filter "
-				"(queue = %" PRIu32
-				", IP = 0x%" PRIx32 ")",
-				p->name, p->pmd_id, p->sctp_local_q, cp->ip);
-
-			if (status)
-				rte_panic("%s (%" PRIu32
-					"): Error deleting SCTP filter "
-					"(queue = %" PRIu32
-					", IP = 0x%" PRIx32
-					") (%" PRId32 ")\n",
-					p->name, p->pmd_id, p->sctp_local_q,
-					cp->ip, status);
-		}
-	}
-}
-
-static void
-app_check_link(struct app_params *app)
-{
-	uint32_t all_links_up, i;
-
-	all_links_up = 1;
-
-	for (i = 0; i < app->n_links; i++) {
-		struct app_link_params *p = &app->link_params[i];
-		struct rte_eth_link link_params;
-
-		memset(&link_params, 0, sizeof(link_params));
-		rte_eth_link_get(p->pmd_id, &link_params);
-
-		APP_LOG(app, HIGH, "%s (%" PRIu32 ") (%" PRIu32 " Gbps) %s",
-			p->name,
-			p->pmd_id,
-			link_params.link_speed / 1000,
-			link_params.link_status ? "UP" : "DOWN");
-
-		if (link_params.link_status == ETH_LINK_DOWN)
-			all_links_up = 0;
-	}
-
-	if (all_links_up == 0)
-		rte_panic("Some links are DOWN\n");
-}
-
-static uint32_t
-is_any_swq_frag_or_ras(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_pktq_swq; i++) {
-		struct app_pktq_swq_params *p = &app->swq_params[i];
-
-		if ((p->ipv4_frag == 1) || (p->ipv6_frag == 1) ||
-			(p->ipv4_ras == 1) || (p->ipv6_ras == 1))
-			return 1;
-	}
-
-	return 0;
-}
-
-static void
-app_init_link_frag_ras(struct app_params *app)
-{
-	uint32_t i;
-
-	if (is_any_swq_frag_or_ras(app)) {
-		for (i = 0; i < app->n_links; i++) {
-			struct app_link_params *p_link = &app->link_params[i];
-				p_link->conf.txmode.offloads |=
-						DEV_TX_OFFLOAD_MULTI_SEGS;
-		}
-	}
-}
-
-static inline int
-app_get_cpu_socket_id(uint32_t pmd_id)
-{
-	int status = rte_eth_dev_socket_id(pmd_id);
-
-	return (status != SOCKET_ID_ANY) ? status : 0;
-}
-
-static inline int
-app_link_rss_enabled(struct app_link_params *cp)
-{
-	return (cp->n_rss_qs) ? 1 : 0;
-}
-
-static void
-app_link_rss_setup(struct app_link_params *cp)
-{
-	struct rte_eth_dev_info dev_info;
-	struct rte_eth_rss_reta_entry64 reta_conf[APP_RETA_SIZE_MAX];
-	uint32_t i;
-	int status;
-
-    /* Get RETA size */
-	memset(&dev_info, 0, sizeof(dev_info));
-	rte_eth_dev_info_get(cp->pmd_id, &dev_info);
-
-	if (dev_info.reta_size == 0)
-		rte_panic("%s (%u): RSS setup error (null RETA size)\n",
-			cp->name, cp->pmd_id);
-
-	if (dev_info.reta_size > ETH_RSS_RETA_SIZE_512)
-		rte_panic("%s (%u): RSS setup error (RETA size too big)\n",
-			cp->name, cp->pmd_id);
-
-	/* Setup RETA contents */
-	memset(reta_conf, 0, sizeof(reta_conf));
-
-	for (i = 0; i < dev_info.reta_size; i++)
-		reta_conf[i / RTE_RETA_GROUP_SIZE].mask = UINT64_MAX;
-
-	for (i = 0; i < dev_info.reta_size; i++) {
-		uint32_t reta_id = i / RTE_RETA_GROUP_SIZE;
-		uint32_t reta_pos = i % RTE_RETA_GROUP_SIZE;
-		uint32_t rss_qs_pos = i % cp->n_rss_qs;
-
-		reta_conf[reta_id].reta[reta_pos] =
-			(uint16_t) cp->rss_qs[rss_qs_pos];
-	}
-
-	/* RETA update */
-	status = rte_eth_dev_rss_reta_update(cp->pmd_id,
-		reta_conf,
-		dev_info.reta_size);
-	if (status != 0)
-		rte_panic("%s (%u): RSS setup error (RETA update failed)\n",
-			cp->name, cp->pmd_id);
-}
-
-static void
-app_init_link_set_config(struct app_link_params *p)
-{
-	if (p->n_rss_qs) {
-		p->conf.rxmode.mq_mode = ETH_MQ_RX_RSS;
-		p->conf.rx_adv_conf.rss_conf.rss_hf = p->rss_proto_ipv4 |
-			p->rss_proto_ipv6 |
-			p->rss_proto_l2;
-	}
-}
-
-static void
-app_init_link(struct app_params *app)
-{
-	uint32_t i;
-
-	app_init_link_frag_ras(app);
-
-	for (i = 0; i < app->n_links; i++) {
-		struct app_link_params *p_link = &app->link_params[i];
-		struct rte_eth_dev_info dev_info;
-		uint32_t link_id, n_hwq_in, n_hwq_out, j;
-		int status;
-
-		sscanf(p_link->name, "LINK%" PRIu32, &link_id);
-		n_hwq_in = app_link_get_n_rxq(app, p_link);
-		n_hwq_out = app_link_get_n_txq(app, p_link);
-		app_init_link_set_config(p_link);
-
-		APP_LOG(app, HIGH, "Initializing %s (%" PRIu32") "
-			"(%" PRIu32 " RXQ, %" PRIu32 " TXQ) ...",
-			p_link->name,
-			p_link->pmd_id,
-			n_hwq_in,
-			n_hwq_out);
-
-		/* LINK */
-		rte_eth_dev_info_get(p_link->pmd_id, &dev_info);
-		if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE)
-			p_link->conf.txmode.offloads |=
-				DEV_TX_OFFLOAD_MBUF_FAST_FREE;
-		status = rte_eth_dev_configure(
-			p_link->pmd_id,
-			n_hwq_in,
-			n_hwq_out,
-			&p_link->conf);
-		if (status < 0)
-			rte_panic("%s (%" PRId32 "): "
-				"init error (%" PRId32 ")\n",
-				p_link->name, p_link->pmd_id, status);
-
-		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->n_pktq_hwq_in; j++) {
-			struct app_pktq_hwq_in_params *p_rxq =
-				&app->hwq_in_params[j];
-			uint32_t rxq_link_id, rxq_queue_id;
-			uint16_t nb_rxd = p_rxq->size;
-
-			sscanf(p_rxq->name, "RXQ%" PRIu32 ".%" PRIu32,
-				&rxq_link_id, &rxq_queue_id);
-			if (rxq_link_id != link_id)
-				continue;
-
-			status = rte_eth_dev_adjust_nb_rx_tx_desc(
-				p_link->pmd_id,
-				&nb_rxd,
-				NULL);
-			if (status < 0)
-				rte_panic("%s (%" PRIu32 "): "
-					"%s adjust number of Rx descriptors "
-					"error (%" PRId32 ")\n",
-					p_link->name,
-					p_link->pmd_id,
-					p_rxq->name,
-					status);
-
-			p_rxq->conf.offloads = p_link->conf.rxmode.offloads;
-			status = rte_eth_rx_queue_setup(
-				p_link->pmd_id,
-				rxq_queue_id,
-				nb_rxd,
-				app_get_cpu_socket_id(p_link->pmd_id),
-				&p_rxq->conf,
-				app->mempool[p_rxq->mempool_id]);
-			if (status < 0)
-				rte_panic("%s (%" PRIu32 "): "
-					"%s init error (%" PRId32 ")\n",
-					p_link->name,
-					p_link->pmd_id,
-					p_rxq->name,
-					status);
-		}
-
-		/* TXQ */
-		for (j = 0; j < app->n_pktq_hwq_out; j++) {
-			struct app_pktq_hwq_out_params *p_txq =
-				&app->hwq_out_params[j];
-			uint32_t txq_link_id, txq_queue_id;
-			uint16_t nb_txd = p_txq->size;
-
-			sscanf(p_txq->name, "TXQ%" PRIu32 ".%" PRIu32,
-				&txq_link_id, &txq_queue_id);
-			if (txq_link_id != link_id)
-				continue;
-
-			status = rte_eth_dev_adjust_nb_rx_tx_desc(
-				p_link->pmd_id,
-				NULL,
-				&nb_txd);
-			if (status < 0)
-				rte_panic("%s (%" PRIu32 "): "
-					"%s adjust number of Tx descriptors "
-					"error (%" PRId32 ")\n",
-					p_link->name,
-					p_link->pmd_id,
-					p_txq->name,
-					status);
-
-			p_txq->conf.offloads = p_link->conf.txmode.offloads;
-			status = rte_eth_tx_queue_setup(
-				p_link->pmd_id,
-				txq_queue_id,
-				nb_txd,
-				app_get_cpu_socket_id(p_link->pmd_id),
-				&p_txq->conf);
-			if (status < 0)
-				rte_panic("%s (%" PRIu32 "): "
-					"%s init error (%" PRId32 ")\n",
-					p_link->name,
-					p_link->pmd_id,
-					p_txq->name,
-					status);
-		}
-
-		/* LINK START */
-		status = rte_eth_dev_start(p_link->pmd_id);
-		if (status < 0)
-			rte_panic("Cannot start %s (error %" PRId32 ")\n",
-				p_link->name, status);
-
-		/* LINK FILTERS */
-		app_link_set_arp_filter(app, p_link);
-		app_link_set_tcp_syn_filter(app, p_link);
-		if (app_link_rss_enabled(p_link))
-			app_link_rss_setup(p_link);
-
-		/* LINK UP */
-		app_link_up_internal(app, p_link);
-	}
-
-	app_check_link(app);
-}
-
-static void
-app_init_swq(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_pktq_swq; i++) {
-		struct app_pktq_swq_params *p = &app->swq_params[i];
-		unsigned flags = 0;
-
-		if (app_swq_get_readers(app, p) == 1)
-			flags |= RING_F_SC_DEQ;
-		if (app_swq_get_writers(app, p) == 1)
-			flags |= RING_F_SP_ENQ;
-
-		APP_LOG(app, HIGH, "Initializing %s...", p->name);
-		app->swq[i] = rte_ring_create(
-				p->name,
-				p->size,
-				p->cpu_socket_id,
-				flags);
-
-		if (app->swq[i] == NULL)
-			rte_panic("%s init error\n", p->name);
-	}
-}
-
-static void
-app_init_tm(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_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;
-
-		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 =
-			app_get_cpu_socket_id(p_link->pmd_id);
-		p_tm->sched_port_params.rate =
-			(uint64_t) link_eth_params.link_speed * 1000 * 1000 / 8;
-
-		APP_LOG(app, HIGH, "Initializing %s ...", p_tm->name);
-		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 %" PRIu32
-					" init error (%" PRId32 ")\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 %" PRIu32
-						" pipe %" PRIu32
-						" (profile %" PRId32 ") "
-						"init error (% " PRId32 ")\n",
-						p_tm->name, subport_id, pipe_id,
-						profile_id, status);
-			}
-		}
-	}
-}
-
-#ifndef RTE_EXEC_ENV_LINUXAPP
-static void
-app_init_tap(struct app_params *app) {
-	if (app->n_pktq_tap == 0)
-		return;
-
-	rte_panic("TAP device not supported.\n");
-}
-#else
-static void
-app_init_tap(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_pktq_tap; i++) {
-		struct app_pktq_tap_params *p_tap = &app->tap_params[i];
-		struct ifreq ifr;
-		int fd, status;
-
-		APP_LOG(app, HIGH, "Initializing %s ...", p_tap->name);
-
-		fd = open("/dev/net/tun", O_RDWR | O_NONBLOCK);
-		if (fd < 0)
-			rte_panic("Cannot open file /dev/net/tun\n");
-
-		memset(&ifr, 0, sizeof(ifr));
-		ifr.ifr_flags = IFF_TAP | IFF_NO_PI; /* No packet information */
-		snprintf(ifr.ifr_name, IFNAMSIZ, "%s", p_tap->name);
-
-		status = ioctl(fd, TUNSETIFF, (void *) &ifr);
-		if (status < 0)
-			rte_panic("TAP setup error\n");
-
-		app->tap[i] = fd;
-	}
-}
-#endif
-
-#ifdef RTE_LIBRTE_KNI
-static int
-kni_config_network_interface(uint16_t port_id, uint8_t if_up) {
-	int ret = 0;
-
-	if (port_id >= rte_eth_dev_count())
-		return -EINVAL;
-
-	ret = (if_up) ?
-		rte_eth_dev_set_link_up(port_id) :
-		rte_eth_dev_set_link_down(port_id);
-
-	return ret;
-}
-
-static int
-kni_change_mtu(uint16_t port_id, unsigned int new_mtu) {
-	int ret;
-
-	if (port_id >= rte_eth_dev_count())
-		return -EINVAL;
-
-	if (new_mtu > ETHER_MAX_LEN)
-		return -EINVAL;
-
-	/* Set new MTU */
-	ret = rte_eth_dev_set_mtu(port_id, new_mtu);
-	if (ret < 0)
-		return ret;
-
-	return 0;
-}
-#endif /* RTE_LIBRTE_KNI */
-
-#ifndef RTE_LIBRTE_KNI
-static void
-app_init_kni(struct app_params *app) {
-	if (app->n_pktq_kni == 0)
-		return;
-
-	rte_panic("Can not init KNI without librte_kni support.\n");
-}
-#else
-static void
-app_init_kni(struct app_params *app) {
-	uint32_t i;
-
-	if (app->n_pktq_kni == 0)
-		return;
-
-	rte_kni_init(app->n_pktq_kni);
-
-	for (i = 0; i < app->n_pktq_kni; i++) {
-		struct app_pktq_kni_params *p_kni = &app->kni_params[i];
-		struct app_link_params *p_link;
-		struct rte_eth_dev_info dev_info;
-		struct app_mempool_params *mempool_params;
-		struct rte_mempool *mempool;
-		struct rte_kni_conf conf;
-		struct rte_kni_ops ops;
-
-		/* LINK */
-		p_link = app_get_link_for_kni(app, p_kni);
-		memset(&dev_info, 0, sizeof(dev_info));
-		rte_eth_dev_info_get(p_link->pmd_id, &dev_info);
-
-		/* MEMPOOL */
-		mempool_params = &app->mempool_params[p_kni->mempool_id];
-		mempool = app->mempool[p_kni->mempool_id];
-
-		/* KNI */
-		memset(&conf, 0, sizeof(conf));
-		snprintf(conf.name, RTE_KNI_NAMESIZE, "%s", p_kni->name);
-		conf.force_bind = p_kni->force_bind;
-		if (conf.force_bind) {
-			int lcore_id;
-
-			lcore_id = cpu_core_map_get_lcore_id(app->core_map,
-				p_kni->socket_id,
-				p_kni->core_id,
-				p_kni->hyper_th_id);
-
-			if (lcore_id < 0)
-				rte_panic("%s invalid CPU core\n", p_kni->name);
-
-			conf.core_id = (uint32_t) lcore_id;
-		}
-		conf.group_id = p_link->pmd_id;
-		conf.mbuf_size = mempool_params->buffer_size;
-		conf.addr = dev_info.pci_dev->addr;
-		conf.id = dev_info.pci_dev->id;
-
-		memset(&ops, 0, sizeof(ops));
-		ops.port_id = (uint8_t) p_link->pmd_id;
-		ops.change_mtu = kni_change_mtu;
-		ops.config_network_if = kni_config_network_interface;
-
-		APP_LOG(app, HIGH, "Initializing %s ...", p_kni->name);
-		app->kni[i] = rte_kni_alloc(mempool, &conf, &ops);
-		if (!app->kni[i])
-			rte_panic("%s init error\n", p_kni->name);
-	}
-}
-#endif /* RTE_LIBRTE_KNI */
-
-static void
-app_init_msgq(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_msgq; i++) {
-		struct app_msgq_params *p = &app->msgq_params[i];
-
-		APP_LOG(app, HIGH, "Initializing %s ...", 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);
-	}
-}
-
-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_tap(app);
-	app_init_kni(app);
-	app_init_msgq(app);
-
-	return 0;
-}
diff --git a/examples/ip_pipeline/main.c b/examples/ip_pipeline/main.c
index a44cf9a..1696e36 100644
--- a/examples/ip_pipeline/main.c
+++ b/examples/ip_pipeline/main.c
@@ -2,34 +2,24 @@
  * Copyright(c) 2010-2015 Intel Corporation
  */
 
-#include "app.h"
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <getopt.h>
 
-static struct app_params app;
+#include <rte_eal.h>
 
 int
 main(int argc, char **argv)
 {
-	rte_openlog_stream(stderr);
+	int status;
 
-	/* Config */
-	app_config_init(&app);
+	/* EAL */
+	status = rte_eal_init(argc, argv);
+	if (status < 0) {
+		printf("Error: EAL initialization failed (%d)\n", status);
+		return status;
+	};
 
-	app_config_args(&app, argc, argv);
-
-	app_config_preproc(&app);
-
-	app_config_parse(&app, app.parser_file);
-
-	app_config_check(&app);
-
-	/* 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/meson.build b/examples/ip_pipeline/meson.build
index be3f3e5..063865c 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -1,19 +1,13 @@
 # SPDX-License-Identifier: BSD-3-Clause
-# Copyright(c) 2017 Intel Corporation
+# Copyright(c) 2017-2018 Intel Corporation
 
 # meson file, for building this example as part of a main DPDK build.
 #
 # To build this example as a standalone application with an already-installed
 # DPDK instance, use 'make'
 
-deps += ['cfgfile', 'bus_pci']
+deps += ['pipeline', 'bus_pci']
 sources = files(
-	'config_check.c',
-	'config_parse.c',
-	'config_parse_tm.c',
-	'cpu_core_map.c',
-	'init.c',
 	'main.c',
 	'parser.c',
-	'thread.c',
 )
diff --git a/examples/ip_pipeline/parser.c b/examples/ip_pipeline/parser.c
index 0901e9c..0ae3d1d 100644
--- a/examples/ip_pipeline/parser.c
+++ b/examples/ip_pipeline/parser.c
@@ -39,7 +39,6 @@
 #include <rte_cfgfile.h>
 #include <rte_string_fns.h>
 
-#include "app.h"
 #include "parser.h"
 
 static uint32_t
@@ -596,10 +595,8 @@ parse_mac_addr(const char *token, struct ether_addr *addr)
 }
 
 int
-parse_pipeline_core(uint32_t *socket,
-	uint32_t *core,
-	uint32_t *ht,
-	const char *entry)
+parse_cpu_core(const char *entry,
+	struct cpu_core_params *p)
 {
 	size_t num_len;
 	char num[8];
@@ -609,6 +606,9 @@ parse_pipeline_core(uint32_t *socket,
 	const char *next = skip_white_spaces(entry);
 	char type;
 
+	if (p == NULL)
+		return -EINVAL;
+
 	/* Expect <CORE> or [sX][cY][h]. At least one parameter is required. */
 	while (*next != '\0') {
 		/* If everything parsed nothing should left */
@@ -682,8 +682,8 @@ parse_pipeline_core(uint32_t *socket,
 		}
 	}
 
-	*socket = s;
-	*core = c;
-	*ht = h;
+	p->socket_id = s;
+	p->core_id = c;
+	p->thread_id = h;
 	return 0;
 }
diff --git a/examples/ip_pipeline/parser.h b/examples/ip_pipeline/parser.h
index 5c421d2..261a8c8 100644
--- a/examples/ip_pipeline/parser.h
+++ b/examples/ip_pipeline/parser.h
@@ -50,6 +50,14 @@ int parse_ipv6_addr(const char *token, struct in6_addr *ipv6);
 int parse_mac_addr(const char *token, struct ether_addr *addr);
 int parse_mpls_labels(char *string, uint32_t *labels, uint32_t *n_labels);
 
+struct cpu_core_params {
+	uint32_t socket_id;
+	uint32_t core_id;
+	uint32_t thread_id;
+};
+
+int parse_cpu_core(const char *entry, struct cpu_core_params *p);
+
 int parse_tokenize_string(char *string, char *tokens[], uint32_t *n_tokens);
 
 #endif
diff --git a/examples/ip_pipeline/pipeline.h b/examples/ip_pipeline/pipeline.h
deleted file mode 100644
index 7ca9cad..0000000
--- a/examples/ip_pipeline/pipeline.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#ifndef __INCLUDE_PIPELINE_H__
-#define __INCLUDE_PIPELINE_H__
-
-#include <cmdline_parse.h>
-
-#include "pipeline_be.h"
-
-/*
- * Pipeline type front-end operations
- */
-
-typedef void* (*pipeline_fe_op_init)(struct pipeline_params *params,
-	void *arg);
-
-typedef int (*pipeline_fe_op_post_init)(void *pipeline);
-
-typedef int (*pipeline_fe_op_free)(void *pipeline);
-
-typedef int (*pipeline_fe_op_track)(struct pipeline_params *params,
-	uint32_t port_in,
-	uint32_t *port_out);
-
-struct pipeline_fe_ops {
-	pipeline_fe_op_init f_init;
-	pipeline_fe_op_post_init f_post_init;
-	pipeline_fe_op_free f_free;
-	pipeline_fe_op_track f_track;
-	cmdline_parse_ctx_t *cmds;
-};
-
-/*
- * Pipeline type
- */
-
-struct pipeline_type {
-	const char *name;
-
-	/* pipeline back-end */
-	struct pipeline_be_ops *be_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;
-}
-
-int
-parse_pipeline_core(uint32_t *socket,
-	uint32_t *core,
-	uint32_t *ht,
-	const char *entry);
-
-#endif
diff --git a/examples/ip_pipeline/pipeline_be.h b/examples/ip_pipeline/pipeline_be.h
deleted file mode 100644
index 6c0c97a..0000000
--- a/examples/ip_pipeline/pipeline_be.h
+++ /dev/null
@@ -1,322 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2016 Intel Corporation
- */
-
-#ifndef __INCLUDE_PIPELINE_BE_H__
-#define __INCLUDE_PIPELINE_BE_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_fd.h>
-#include <rte_port_source_sink.h>
-#ifdef RTE_LIBRTE_KNI
-#include <rte_port_kni.h>
-#endif
-#include <rte_pipeline.h>
-
-enum pipeline_port_in_type {
-	PIPELINE_PORT_IN_ETHDEV_READER,
-	PIPELINE_PORT_IN_RING_READER,
-	PIPELINE_PORT_IN_RING_MULTI_READER,
-	PIPELINE_PORT_IN_RING_READER_IPV4_FRAG,
-	PIPELINE_PORT_IN_RING_READER_IPV6_FRAG,
-	PIPELINE_PORT_IN_SCHED_READER,
-	PIPELINE_PORT_IN_FD_READER,
-	PIPELINE_PORT_IN_KNI_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_multi_reader_params ring_multi;
-		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_fd_reader_params fd;
-#ifdef RTE_LIBRTE_KNI
-		struct rte_port_kni_reader_params kni;
-#endif
-		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_MULTI_READER:
-		return (void *) &p->params.ring_multi;
-	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_FD_READER:
-		return (void *) &p->params.fd;
-#ifdef RTE_LIBRTE_KNI
-	case PIPELINE_PORT_IN_KNI_READER:
-		return (void *) &p->params.kni;
-#endif
-	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_MULTI_READER:
-		return &rte_port_ring_multi_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_FD_READER:
-		return &rte_port_fd_reader_ops;
-#ifdef RTE_LIBRTE_KNI
-	case PIPELINE_PORT_IN_KNI_READER:
-		return &rte_port_kni_reader_ops;
-#endif
-	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_MULTI_WRITER,
-	PIPELINE_PORT_OUT_RING_WRITER_NODROP,
-	PIPELINE_PORT_OUT_RING_MULTI_WRITER_NODROP,
-	PIPELINE_PORT_OUT_RING_WRITER_IPV4_RAS,
-	PIPELINE_PORT_OUT_RING_WRITER_IPV6_RAS,
-	PIPELINE_PORT_OUT_SCHED_WRITER,
-	PIPELINE_PORT_OUT_FD_WRITER,
-	PIPELINE_PORT_OUT_KNI_WRITER,
-	PIPELINE_PORT_OUT_KNI_WRITER_NODROP,
-	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_multi_writer_params ring_multi;
-		struct rte_port_ring_writer_nodrop_params ring_nodrop;
-		struct rte_port_ring_multi_writer_nodrop_params ring_multi_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;
-		struct rte_port_fd_writer_params fd;
-#ifdef RTE_LIBRTE_KNI
-		struct rte_port_kni_writer_params kni;
-		struct rte_port_kni_writer_nodrop_params kni_nodrop;
-#endif
-		struct rte_port_sink_params sink;
-	} 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_MULTI_WRITER:
-		return (void *) &p->params.ring_multi;
-	case PIPELINE_PORT_OUT_RING_WRITER_NODROP:
-		return (void *) &p->params.ring_nodrop;
-	case PIPELINE_PORT_OUT_RING_MULTI_WRITER_NODROP:
-		return (void *) &p->params.ring_multi_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_FD_WRITER:
-		return (void *) &p->params.fd;
-#ifdef RTE_LIBRTE_KNI
-	case PIPELINE_PORT_OUT_KNI_WRITER:
-		return (void *) &p->params.kni;
-	case PIPELINE_PORT_OUT_KNI_WRITER_NODROP:
-		return (void *) &p->params.kni_nodrop;
-#endif
-	case PIPELINE_PORT_OUT_SINK:
-		return (void *) &p->params.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_MULTI_WRITER:
-		return &rte_port_ring_multi_writer_ops;
-	case PIPELINE_PORT_OUT_RING_WRITER_NODROP:
-		return &rte_port_ring_writer_nodrop_ops;
-	case PIPELINE_PORT_OUT_RING_MULTI_WRITER_NODROP:
-		return &rte_port_ring_multi_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_FD_WRITER:
-		return &rte_port_fd_writer_ops;
-#ifdef RTE_LIBRTE_KNI
-	case PIPELINE_PORT_OUT_KNI_WRITER:
-		return &rte_port_kni_writer_ops;
-	case PIPELINE_PORT_OUT_KNI_WRITER_NODROP:
-		return &rte_port_kni_writer_nodrop_ops;
-#endif
-	case PIPELINE_PORT_OUT_SINK:
-		return &rte_port_sink_ops;
-	default:
-		return NULL;
-	}
-}
-
-#ifndef PIPELINE_NAME_SIZE
-#define PIPELINE_NAME_SIZE                       64
-#endif
-
-#ifndef PIPELINE_TYPE_SIZE
-#define PIPELINE_TYPE_SIZE                       64
-#endif
-
-#ifndef PIPELINE_MAX_PORT_IN
-#define PIPELINE_MAX_PORT_IN                     64
-#endif
-
-#ifndef PIPELINE_MAX_PORT_OUT
-#define PIPELINE_MAX_PORT_OUT                    64
-#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                        64
-#endif
-
-struct pipeline_params {
-	char name[PIPELINE_NAME_SIZE];
-	char type[PIPELINE_TYPE_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;
-
-	uint32_t log_level;
-};
-
-/*
- * Pipeline type back-end operations
- */
-
-typedef void* (*pipeline_be_op_init)(struct pipeline_params *params,
-	void *arg);
-
-typedef int (*pipeline_be_op_free)(void *pipeline);
-
-typedef int (*pipeline_be_op_run)(void *pipeline);
-
-typedef int (*pipeline_be_op_timer)(void *pipeline);
-
-struct pipeline_be_ops {
-	pipeline_be_op_init f_init;
-	pipeline_be_op_free f_free;
-	pipeline_be_op_run f_run;
-	pipeline_be_op_timer f_timer;
-};
-
-/* Pipeline specific config parse error messages */
-#define PIPELINE_ARG_CHECK(exp, fmt, ...)				\
-do {									\
-	if (!(exp)) {							\
-		fprintf(stderr, fmt "\n", ## __VA_ARGS__);		\
-		return -1;						\
-	}								\
-} while (0)
-
-#define PIPELINE_PARSE_ERR_INV_VAL(exp, section, entry, val)		\
-PIPELINE_ARG_CHECK(exp, "Parse error in section \"%s\": entry \"%s\" "	\
-	"has invalid value (\"%s\")", section, entry, val)
-
-#define PIPELINE_PARSE_ERR_OUT_RNG(exp, section, entry, val)		\
-PIPELINE_ARG_CHECK(exp, "Parse error in section \"%s\": entry \"%s\" "	\
-	"value is out of range (\"%s\")", section, entry, val)
-
-#define PIPELINE_PARSE_ERR_DUPLICATE(exp, section, entry)		\
-PIPELINE_ARG_CHECK(exp, "Parse error in section \"%s\": duplicated "	\
-	"entry \"%s\"", section, entry)
-
-#define PIPELINE_PARSE_ERR_INV_ENT(exp, section, entry)			\
-PIPELINE_ARG_CHECK(exp, "Parse error in section \"%s\": invalid entry "	\
-	"\"%s\"", section, entry)
-
-#define PIPELINE_PARSE_ERR_MANDATORY(exp, section, entry)		\
-PIPELINE_ARG_CHECK(exp, "Parse error in section \"%s\": mandatory "	\
-	"entry \"%s\" is missing", section, entry)
-
-#endif
diff --git a/examples/ip_pipeline/thread.c b/examples/ip_pipeline/thread.c
deleted file mode 100644
index a36bf92..0000000
--- a/examples/ip_pipeline/thread.c
+++ /dev/null
@@ -1,240 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#include <rte_common.h>
-#include <rte_cycles.h>
-#include <rte_pipeline.h>
-
-#include "app.h"
-#include "thread.h"
-
-static inline void *
-thread_msg_recv(struct rte_ring *r)
-{
-	void *msg;
-	int status = rte_ring_sc_dequeue(r, &msg);
-
-	if (status != 0)
-		return NULL;
-
-	return msg;
-}
-
-static inline void
-thread_msg_send(struct rte_ring *r,
-	void *msg)
-{
-	int status;
-
-	do {
-		status = rte_ring_sp_enqueue(r, msg);
-	} while (status == -ENOBUFS);
-}
-
-static int
-thread_pipeline_enable(struct app_thread_data *t,
-		struct thread_pipeline_enable_msg_req *req)
-{
-	struct app_thread_pipeline_data *p;
-
-	if (req->f_run == NULL) {
-		if (t->n_regular >= APP_MAX_THREAD_PIPELINES)
-			return -1;
-	} else {
-		if (t->n_custom >= APP_MAX_THREAD_PIPELINES)
-			return -1;
-	}
-
-	p = (req->f_run == NULL) ?
-		&t->regular[t->n_regular] :
-		&t->custom[t->n_custom];
-
-	p->pipeline_id = req->pipeline_id;
-	p->be = req->be;
-	p->f_run = req->f_run;
-	p->f_timer = req->f_timer;
-	p->timer_period = req->timer_period;
-	p->deadline = 0;
-
-	if (req->f_run == NULL)
-		t->n_regular++;
-	else
-		t->n_custom++;
-
-	return 0;
-}
-
-static int
-thread_pipeline_disable(struct app_thread_data *t,
-		struct thread_pipeline_disable_msg_req *req)
-{
-	uint32_t n_regular = RTE_MIN(t->n_regular, RTE_DIM(t->regular));
-	uint32_t n_custom = RTE_MIN(t->n_custom, RTE_DIM(t->custom));
-	uint32_t i;
-
-	/* search regular pipelines of current thread */
-	for (i = 0; i < n_regular; i++) {
-		if (t->regular[i].pipeline_id != req->pipeline_id)
-			continue;
-
-		if (i < n_regular - 1)
-			memcpy(&t->regular[i],
-			  &t->regular[i+1],
-			  (n_regular - 1 - i) * sizeof(struct app_thread_pipeline_data));
-
-		n_regular--;
-		t->n_regular = n_regular;
-
-		return 0;
-	}
-
-	/* search custom pipelines of current thread */
-	for (i = 0; i < n_custom; i++) {
-		if (t->custom[i].pipeline_id != req->pipeline_id)
-			continue;
-
-		if (i < n_custom - 1)
-			memcpy(&t->custom[i],
-			  &t->custom[i+1],
-			  (n_custom - 1 - i) * sizeof(struct app_thread_pipeline_data));
-
-		n_custom--;
-		t->n_custom = n_custom;
-
-		return 0;
-	}
-
-	/* return if pipeline not found */
-	return -1;
-}
-
-static int
-thread_msg_req_handle(struct app_thread_data *t)
-{
-	void *msg_ptr;
-	struct thread_msg_req *req;
-	struct thread_msg_rsp *rsp;
-
-	msg_ptr = thread_msg_recv(t->msgq_in);
-	req = msg_ptr;
-	rsp = msg_ptr;
-
-	if (req != NULL)
-		switch (req->type) {
-		case THREAD_MSG_REQ_PIPELINE_ENABLE: {
-			rsp->status = thread_pipeline_enable(t,
-					(struct thread_pipeline_enable_msg_req *) req);
-			thread_msg_send(t->msgq_out, rsp);
-			break;
-		}
-
-		case THREAD_MSG_REQ_PIPELINE_DISABLE: {
-			rsp->status = thread_pipeline_disable(t,
-					(struct thread_pipeline_disable_msg_req *) req);
-			thread_msg_send(t->msgq_out, rsp);
-			break;
-		}
-
-		case THREAD_MSG_REQ_HEADROOM_READ: {
-			struct thread_headroom_read_msg_rsp *rsp =
-				(struct thread_headroom_read_msg_rsp *)
-				req;
-
-			rsp->headroom_ratio = t->headroom_ratio;
-			rsp->status = 0;
-			thread_msg_send(t->msgq_out, rsp);
-			break;
-		}
-		default:
-			break;
-		}
-
-	return 0;
-}
-
-static void
-thread_headroom_update(struct app_thread_data *t, uint64_t time)
-{
-	uint64_t time_diff = time - t->headroom_time;
-
-	t->headroom_ratio =
-		((double) t->headroom_cycles) / ((double) time_diff);
-
-	t->headroom_cycles = 0;
-	t->headroom_time = rte_rdtsc_precise();
-}
-
-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++) {
-		uint32_t n_regular = RTE_MIN(t->n_regular, RTE_DIM(t->regular));
-		uint32_t n_custom = RTE_MIN(t->n_custom, RTE_DIM(t->custom));
-
-		/* 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 < 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 < 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;
-			}
-
-			/* Timer for thread message request */
-			{
-				uint64_t deadline = t->thread_req_deadline;
-
-				if (deadline <= time) {
-					thread_msg_req_handle(t);
-					thread_headroom_update(t, time);
-					deadline = time + t->timer_period;
-					t->thread_req_deadline = deadline;
-				}
-
-				if (deadline < t_deadline)
-					t_deadline = deadline;
-			}
-
-
-			t->deadline = t_deadline;
-		}
-	}
-
-	return 0;
-}
diff --git a/examples/ip_pipeline/thread.h b/examples/ip_pipeline/thread.h
deleted file mode 100644
index 2c4fb6a..0000000
--- a/examples/ip_pipeline/thread.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#ifndef THREAD_H_
-#define THREAD_H_
-
-#include "app.h"
-#include "pipeline_be.h"
-
-enum thread_msg_req_type {
-	THREAD_MSG_REQ_PIPELINE_ENABLE = 0,
-	THREAD_MSG_REQ_PIPELINE_DISABLE,
-	THREAD_MSG_REQ_HEADROOM_READ,
-	THREAD_MSG_REQS
-};
-
-struct thread_msg_req {
-	enum thread_msg_req_type type;
-};
-
-struct thread_msg_rsp {
-	int status;
-};
-
-/*
- * PIPELINE ENABLE
- */
-struct thread_pipeline_enable_msg_req {
-	enum thread_msg_req_type type;
-
-	uint32_t pipeline_id;
-	void *be;
-	pipeline_be_op_run f_run;
-	pipeline_be_op_timer f_timer;
-	uint64_t timer_period;
-};
-
-struct thread_pipeline_enable_msg_rsp {
-	int status;
-};
-
-/*
- * PIPELINE DISABLE
- */
-struct thread_pipeline_disable_msg_req {
-	enum thread_msg_req_type type;
-
-	uint32_t pipeline_id;
-};
-
-struct thread_pipeline_disable_msg_rsp {
-	int status;
-};
-
-/*
- * THREAD HEADROOM
- */
-struct thread_headroom_read_msg_req {
-	enum thread_msg_req_type type;
-};
-
-struct thread_headroom_read_msg_rsp {
-	int status;
-
-	double headroom_ratio;
-};
-
-#endif /* THREAD_H_ */
-- 
2.9.3

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

* [dpdk-dev] [PATCH v2 18/44] ip_pipeline: add cli interface
  2018-03-12 17:25   ` [dpdk-dev] [PATCH v2 00/44] ip_pipeline: refactoring Jasvinder Singh
                       ` (16 preceding siblings ...)
  2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 17/44] ip_pipeline: rework and improvements Jasvinder Singh
@ 2018-03-12 17:25     ` Jasvinder Singh
  2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 19/44] ip_pipeline: add mempool object for pipeline Jasvinder Singh
                       ` (25 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-12 17:25 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

CLI interface allowing connectivity with external agent(e.g. telnet,
netcat, Python script, etc) is added to the application.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/Makefile    |   4 +-
 examples/ip_pipeline/cli.c       |  85 ++++++++++
 examples/ip_pipeline/cli.h       |  18 +++
 examples/ip_pipeline/conn.c      | 326 +++++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/conn.h      |  47 ++++++
 examples/ip_pipeline/main.c      | 151 +++++++++++++++++-
 examples/ip_pipeline/meson.build |   2 +
 7 files changed, 631 insertions(+), 2 deletions(-)
 create mode 100644 examples/ip_pipeline/cli.c
 create mode 100644 examples/ip_pipeline/cli.h
 create mode 100644 examples/ip_pipeline/conn.c
 create mode 100644 examples/ip_pipeline/conn.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index 981c4f7..0c5b6b1 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -5,7 +5,9 @@
 APP = ip_pipeline
 
 # all source are stored in SRCS-y
-SRCS-y := main.c
+SRCS-y := cli.c
+SRCS-y += conn.c
+SRCS-y += main.c
 SRCS-y += parser.c
 #SRCS-y += thread.c
 
diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
new file mode 100644
index 0000000..3e97b29
--- /dev/null
+++ b/examples/ip_pipeline/cli.c
@@ -0,0 +1,85 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <rte_common.h>
+
+#include "cli.h"
+
+static int
+is_comment(char *in)
+{
+	if ((strlen(in) && index("!#%;", in[0])) ||
+		(strncmp(in, "//", 2) == 0) ||
+		(strncmp(in, "--", 2) == 0))
+		return 1;
+
+	return 0;
+}
+
+void
+cli_process(char *in, char *out __rte_unused, size_t out_size __rte_unused)
+{
+	if (is_comment(in))
+		return;
+
+}
+
+int
+cli_script_process(const char *file_name,
+	size_t msg_in_len_max,
+	size_t msg_out_len_max)
+{
+	char *msg_in = NULL, *msg_out = NULL;
+	FILE *f = NULL;
+
+	/* Check input arguments */
+	if ((file_name == NULL) ||
+		(strlen(file_name) == 0) ||
+		(msg_in_len_max == 0) ||
+		(msg_out_len_max == 0))
+		return -EINVAL;
+
+	msg_in = malloc(msg_in_len_max + 1);
+	msg_out = malloc(msg_out_len_max + 1);
+	if ((msg_in == NULL) ||
+		(msg_out == NULL)) {
+		free(msg_out);
+		free(msg_in);
+		return -ENOMEM;
+	}
+
+	/* Open input file */
+	f = fopen(file_name, "r");
+	if (f == NULL) {
+		free(msg_out);
+		free(msg_in);
+		return -EIO;
+	}
+
+	/* Read file */
+	for ( ; ; ) {
+		if (fgets(msg_in, msg_in_len_max + 1, f) == NULL)
+			break;
+
+		printf("%s", msg_in);
+
+		cli_process(msg_in,
+			msg_out,
+			msg_out_len_max);
+
+		if (strlen(msg_out))
+			printf("%s", msg_out);
+	}
+
+	/* Close file */
+	fclose(f);
+	free(msg_out);
+	free(msg_in);
+	return 0;
+}
diff --git a/examples/ip_pipeline/cli.h b/examples/ip_pipeline/cli.h
new file mode 100644
index 0000000..992e4c3
--- /dev/null
+++ b/examples/ip_pipeline/cli.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#ifndef __INCLUDE_CLI_H__
+#define __INCLUDE_CLI_H__
+
+#include <stddef.h>
+
+void
+cli_process(char *in, char *out, size_t out_size);
+
+int
+cli_script_process(const char *file_name,
+	size_t msg_in_len_max,
+	size_t msg_out_len_max);
+
+#endif
diff --git a/examples/ip_pipeline/conn.c b/examples/ip_pipeline/conn.c
new file mode 100644
index 0000000..2a9fa15
--- /dev/null
+++ b/examples/ip_pipeline/conn.c
@@ -0,0 +1,326 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+#define __USE_GNU
+#include <sys/socket.h>
+
+#include <sys/epoll.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <errno.h>
+
+#include "conn.h"
+
+#define MSG_CMD_TOO_LONG "Command too long."
+
+struct conn {
+	char *welcome;
+	char *prompt;
+	char *buf;
+	char *msg_in;
+	char *msg_out;
+	size_t buf_size;
+	size_t msg_in_len_max;
+	size_t msg_out_len_max;
+	size_t msg_in_len;
+	int fd_server;
+	int fd_client_group;
+	conn_msg_handle_t msg_handle;
+};
+
+struct conn *
+conn_init(struct conn_params *p)
+{
+	struct sockaddr_in server_address;
+	struct conn *conn;
+	int fd_server, fd_client_group, status;
+
+	memset(&server_address, 0, sizeof(server_address));
+
+	/* Check input arguments */
+	if ((p == NULL) ||
+		(p->welcome == NULL) ||
+		(p->prompt == NULL) ||
+		(p->addr == NULL) ||
+		(p->buf_size == 0) ||
+		(p->msg_in_len_max == 0) ||
+		(p->msg_out_len_max == 0) ||
+		(p->msg_handle == NULL))
+		return NULL;
+
+	status = inet_aton(p->addr, &server_address.sin_addr);
+	if (status == 0)
+		return NULL;
+
+	/* Memory allocation */
+	conn = calloc(1, sizeof(struct conn));
+	if (conn == NULL)
+		return NULL;
+
+	conn->welcome = calloc(1, CONN_WELCOME_LEN_MAX + 1);
+	conn->prompt = calloc(1, CONN_PROMPT_LEN_MAX + 1);
+	conn->buf = calloc(1, p->buf_size);
+	conn->msg_in = calloc(1, p->msg_in_len_max + 1);
+	conn->msg_out = calloc(1, p->msg_out_len_max + 1);
+
+	if ((conn->welcome == NULL) ||
+		(conn->prompt == NULL) ||
+		(conn->buf == NULL) ||
+		(conn->msg_in == NULL) ||
+		(conn->msg_out == NULL)) {
+		conn_free(conn);
+		return NULL;
+	}
+
+	/* Server socket */
+	server_address.sin_family = AF_INET;
+	server_address.sin_port = htons(p->port);
+
+	fd_server = socket(AF_INET,
+		SOCK_STREAM | SOCK_NONBLOCK,
+		0);
+	if (fd_server == -1) {
+		conn_free(conn);
+		return NULL;
+	}
+
+	status = bind(fd_server,
+		(struct sockaddr *) &server_address,
+		sizeof(server_address));
+	if (status == -1) {
+		conn_free(conn);
+		return NULL;
+	}
+
+	status = listen(fd_server, 16);
+	if (status == -1) {
+		conn_free(conn);
+		return NULL;
+	}
+
+	/* Client group */
+	fd_client_group = epoll_create(1);
+	if (fd_client_group == -1) {
+		conn_free(conn);
+		return NULL;
+	}
+
+	/* Fill in */
+	strncpy(conn->welcome, p->welcome, CONN_WELCOME_LEN_MAX);
+	strncpy(conn->prompt, p->prompt, CONN_PROMPT_LEN_MAX);
+	conn->buf_size = p->buf_size;
+	conn->msg_in_len_max = p->msg_in_len_max;
+	conn->msg_out_len_max = p->msg_out_len_max;
+	conn->msg_in_len = 0;
+	conn->fd_server = fd_server;
+	conn->fd_client_group = fd_client_group;
+	conn->msg_handle = p->msg_handle;
+
+	return conn;
+}
+
+void
+conn_free(struct conn *conn)
+{
+	if (conn == NULL)
+		return;
+
+	if (conn->fd_client_group)
+		close(conn->fd_client_group);
+
+	if (conn->fd_server)
+		close(conn->fd_server);
+
+	free(conn->msg_out);
+	free(conn->msg_in);
+	free(conn->prompt);
+	free(conn->welcome);
+	free(conn);
+}
+
+int
+conn_poll_for_conn(struct conn *conn)
+{
+	struct sockaddr_in client_address;
+	struct epoll_event event;
+	socklen_t client_address_length;
+	int fd_client, status;
+
+	/* Check input arguments */
+	if (conn == NULL)
+		return -1;
+
+	/* Server socket */
+	client_address_length = sizeof(client_address);
+	fd_client = accept4(conn->fd_server,
+		(struct sockaddr *) &client_address,
+		&client_address_length,
+		SOCK_NONBLOCK);
+	if (fd_client == -1) {
+		if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
+			return 0;
+
+		return -1;
+	}
+
+	/* Client group */
+	event.events = EPOLLIN | EPOLLRDHUP | EPOLLHUP;
+	event.data.fd = fd_client;
+
+	status = epoll_ctl(conn->fd_client_group,
+		EPOLL_CTL_ADD,
+		fd_client,
+		&event);
+	if (status == -1) {
+		close(fd_client);
+		return -1;
+	}
+
+	/* Client */
+	status = write(fd_client,
+		conn->welcome,
+		strlen(conn->welcome));
+	if (status == -1) {
+		close(fd_client);
+		return -1;
+	}
+
+	status = write(fd_client,
+		conn->prompt,
+		strlen(conn->prompt));
+	if (status == -1) {
+		close(fd_client);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+data_event_handle(struct conn *conn,
+	int fd_client)
+{
+	ssize_t len, i, status;
+
+	/* Read input message */
+
+	len = read(fd_client,
+		conn->buf,
+		conn->buf_size);
+	if (len == -1) {
+		if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
+			return 0;
+
+		return -1;
+	}
+	if (len == 0)
+		return 0;
+
+	/* Handle input messages */
+	for (i = 0; i < len; i++) {
+		if (conn->buf[i] == '\n') {
+			size_t n;
+
+			conn->msg_in[conn->msg_in_len] = 0;
+			conn->msg_out[0] = 0;
+
+			conn->msg_handle(conn->msg_in,
+				conn->msg_out,
+				conn->msg_out_len_max);
+
+			n = strlen(conn->msg_out);
+			if (n) {
+				status = write(fd_client,
+					conn->msg_out,
+					n);
+				if (status == -1)
+					return status;
+			}
+
+			conn->msg_in_len = 0;
+		} else if (conn->msg_in_len < conn->msg_in_len_max) {
+			conn->msg_in[conn->msg_in_len] = conn->buf[i];
+			conn->msg_in_len++;
+		} else {
+			status = write(fd_client,
+				MSG_CMD_TOO_LONG,
+				strlen(MSG_CMD_TOO_LONG));
+			if (status == -1)
+				return status;
+
+			conn->msg_in_len = 0;
+		}
+	}
+
+	/* Write prompt */
+	status = write(fd_client,
+		conn->prompt,
+		strlen(conn->prompt));
+	if (status == -1)
+		return status;
+
+	return 0;
+}
+
+static int
+control_event_handle(struct conn *conn,
+	int fd_client)
+{
+	int status;
+
+	status = epoll_ctl(conn->fd_client_group,
+		EPOLL_CTL_DEL,
+		fd_client,
+		NULL);
+	if (status == -1)
+		return -1;
+
+	status = close(fd_client);
+	if (status == -1)
+		return -1;
+
+	return 0;
+}
+
+int
+conn_poll_for_msg(struct conn *conn)
+{
+	struct epoll_event event;
+	int fd_client, status, status_data, status_control;
+
+	/* Check input arguments */
+	if (conn == NULL)
+		return -1;
+
+	/* Client group */
+	status = epoll_wait(conn->fd_client_group,
+		&event,
+		1,
+		0);
+	if (status == -1)
+		return -1;
+	if (status == 0)
+		return 0;
+
+	fd_client = event.data.fd;
+
+	/* Data available */
+	if (event.events & EPOLLIN)
+		status_data = data_event_handle(conn, fd_client);
+
+	/* Control events */
+	if (event.events & (EPOLLRDHUP | EPOLLERR | EPOLLHUP))
+		status_control = control_event_handle(conn, fd_client);
+
+	if (status_data || status_control)
+		return -1;
+
+	return 0;
+}
diff --git a/examples/ip_pipeline/conn.h b/examples/ip_pipeline/conn.h
new file mode 100644
index 0000000..46f9f95
--- /dev/null
+++ b/examples/ip_pipeline/conn.h
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#ifndef __INCLUDE_CONN_H__
+#define __INCLUDE_CONN_H__
+
+#include <stdint.h>
+
+struct conn;
+
+#ifndef CONN_WELCOME_LEN_MAX
+#define CONN_WELCOME_LEN_MAX                               1024
+#endif
+
+#ifndef CONN_PROMPT_LEN_MAX
+#define CONN_PROMPT_LEN_MAX                                16
+#endif
+
+typedef void (*conn_msg_handle_t)(char *msg_in,
+	char *msg_out,
+	size_t msg_out_len_max);
+
+struct conn_params {
+	const char *welcome;
+	const char *prompt;
+	const char *addr;
+	uint16_t port;
+	size_t buf_size;
+	size_t msg_in_len_max;
+	size_t msg_out_len_max;
+	conn_msg_handle_t msg_handle;
+};
+
+struct conn *
+conn_init(struct conn_params *p);
+
+void
+conn_free(struct conn *conn);
+
+int
+conn_poll_for_conn(struct conn *conn);
+
+int
+conn_poll_for_msg(struct conn *conn);
+
+#endif
diff --git a/examples/ip_pipeline/main.c b/examples/ip_pipeline/main.c
index 1696e36..60936f4 100644
--- a/examples/ip_pipeline/main.c
+++ b/examples/ip_pipeline/main.c
@@ -1,5 +1,5 @@
 /* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
+ * Copyright(c) 2010-2018 Intel Corporation
  */
 
 #include <stdio.h>
@@ -10,11 +10,140 @@
 
 #include <rte_eal.h>
 
+#include "cli.h"
+#include "conn.h"
+
+static const char usage[] =
+	"%s EAL_ARGS -- [-h HOST] [-p PORT] [-s SCRIPT]\n";
+
+static const char welcome[] =
+	"\n"
+	"Welcome to IP Pipeline!\n"
+	"\n";
+
+static const char prompt[] = "pipeline> ";
+
+static struct app_params {
+	struct conn_params conn;
+	char *script_name;
+} app = {
+	.conn = {
+		.welcome = welcome,
+		.prompt = prompt,
+		.addr = "0.0.0.0",
+		.port = 8086,
+		.buf_size = 1024 * 1024,
+		.msg_in_len_max = 1024,
+		.msg_out_len_max = 1024 * 1024,
+		.msg_handle = cli_process,
+	},
+	.script_name = NULL,
+};
+
+static int
+parse_args(int argc, char **argv)
+{
+	char *app_name = argv[0];
+	struct option lgopts[] = {
+		{ NULL,  0, 0, 0 }
+	};
+	int opt, option_index;
+	int h_present, p_present, s_present, n_args, i;
+
+	/* Skip EAL input args */
+	n_args = argc;
+	for (i = 0; i < n_args; i++)
+		if (strcmp(argv[i], "--") == 0) {
+			argc -= i;
+			argv += i;
+			break;
+		}
+
+	if (i == n_args)
+		return 0;
+
+	/* Parse args */
+	h_present = 0;
+	p_present = 0;
+	s_present = 0;
+
+	while ((opt = getopt_long(argc, argv, "h:p:s:", lgopts, &option_index))
+			!= EOF)
+		switch (opt) {
+		case 'h':
+			if (h_present) {
+				printf("Error: Multiple -h arguments\n");
+				return -1;
+			}
+			h_present = 1;
+
+			if (!strlen(optarg)) {
+				printf("Error: Argument for -h not provided\n");
+				return -1;
+			}
+
+			app.conn.addr = strdup(optarg);
+			if (app.conn.addr == NULL) {
+				printf("Error: Not enough memory\n");
+				return -1;
+			}
+			break;
+
+		case 'p':
+			if (p_present) {
+				printf("Error: Multiple -p arguments\n");
+				return -1;
+			}
+			p_present = 1;
+
+			if (!strlen(optarg)) {
+				printf("Error: Argument for -p not provided\n");
+				return -1;
+			}
+
+			app.conn.port = (uint16_t) atoi(optarg);
+			break;
+
+		case 's':
+			if (s_present) {
+				printf("Error: Multiple -s arguments\n");
+				return -1;
+			}
+			s_present = 1;
+
+			if (!strlen(optarg)) {
+				printf("Error: Argument for -s not provided\n");
+				return -1;
+			}
+
+			app.script_name = strdup(optarg);
+			if (app.script_name == NULL) {
+				printf("Error: Not enough memory\n");
+				return -1;
+			}
+			break;
+
+		default:
+			printf(usage, app_name);
+			return -1;
+		}
+
+	optind = 1; /* reset getopt lib */
+
+	return 0;
+}
+
 int
 main(int argc, char **argv)
 {
+	struct conn *conn;
 	int status;
 
+	/* Parse application arguments */
+	status = parse_args(argc, argv);
+	if (status < 0)
+		return status;
+
 	/* EAL */
 	status = rte_eal_init(argc, argv);
 	if (status < 0) {
@@ -22,4 +151,24 @@ main(int argc, char **argv)
 		return status;
 	};
 
+	/* Connectivity */
+	conn = conn_init(&app.conn);
+	if (conn == NULL) {
+		printf("Error: Connectivity initialization failed (%d)\n",
+			status);
+		return status;
+	};
+
+	/* Script */
+	if (app.script_name)
+		cli_script_process(app.script_name,
+			app.conn.msg_in_len_max,
+			app.conn.msg_out_len_max);
+
+	/* Dispatch loop */
+	for ( ; ; ) {
+		conn_poll_for_conn(conn);
+
+		conn_poll_for_msg(conn);
+	}
 }
diff --git a/examples/ip_pipeline/meson.build b/examples/ip_pipeline/meson.build
index 063865c..a89cb30 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -8,6 +8,8 @@
 
 deps += ['pipeline', 'bus_pci']
 sources = files(
+	'cli.c',
+	'conn.c',
 	'main.c',
 	'parser.c',
 )
-- 
2.9.3

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

* [dpdk-dev] [PATCH v2 19/44] ip_pipeline: add mempool object for pipeline
  2018-03-12 17:25   ` [dpdk-dev] [PATCH v2 00/44] ip_pipeline: refactoring Jasvinder Singh
                       ` (17 preceding siblings ...)
  2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 18/44] ip_pipeline: add cli interface Jasvinder Singh
@ 2018-03-12 17:25     ` Jasvinder Singh
  2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 20/44] ip_pipeline: add link object Jasvinder Singh
                       ` (24 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-12 17:25 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Fan Zhang

Add mempool object implementation to the application.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Fan Zhang <roy.fan.zhang@intel.com>
---
 examples/ip_pipeline/Makefile    |   1 +
 examples/ip_pipeline/cli.c       | 109 ++++++++++++++++++++++++++++++++++++++-
 examples/ip_pipeline/common.h    |  12 +++++
 examples/ip_pipeline/main.c      |   8 +++
 examples/ip_pipeline/mempool.c   |  81 +++++++++++++++++++++++++++++
 examples/ip_pipeline/mempool.h   |  40 ++++++++++++++
 examples/ip_pipeline/meson.build |   1 +
 7 files changed, 251 insertions(+), 1 deletion(-)
 create mode 100644 examples/ip_pipeline/common.h
 create mode 100644 examples/ip_pipeline/mempool.c
 create mode 100644 examples/ip_pipeline/mempool.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index 0c5b6b1..fca28c5 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -8,6 +8,7 @@ APP = ip_pipeline
 SRCS-y := cli.c
 SRCS-y += conn.c
 SRCS-y += main.c
+SRCS-y += mempool.c
 SRCS-y += parser.c
 #SRCS-y += thread.c
 
diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index 3e97b29..6fe3725 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -10,6 +10,23 @@
 #include <rte_common.h>
 
 #include "cli.h"
+#include "mempool.h"
+#include "parser.h"
+
+#ifndef CMD_MAX_TOKENS
+#define CMD_MAX_TOKENS     256
+#endif
+
+#define MSG_OUT_OF_MEMORY  "Not enough memory.\n"
+#define MSG_CMD_UNKNOWN    "Unknown command \"%s\".\n"
+#define MSG_CMD_UNIMPLEM   "Command \"%s\" not implemented.\n"
+#define MSG_ARG_NOT_ENOUGH "Not enough arguments for command \"%s\".\n"
+#define MSG_ARG_TOO_MANY   "Too many arguments for command \"%s\".\n"
+#define MSG_ARG_MISMATCH   "Wrong number of arguments for command \"%s\".\n"
+#define MSG_ARG_NOT_FOUND  "Argument \"%s\" not found.\n"
+#define MSG_ARG_INVALID    "Invalid value for argument \"%s\".\n"
+#define MSG_FILE_ERR       "Error in file \"%s\" at line %u.\n"
+#define MSG_CMD_FAIL       "Command \"%s\" failed.\n"
 
 static int
 is_comment(char *in)
@@ -22,12 +39,102 @@ is_comment(char *in)
 	return 0;
 }
 
+/**
+ * mempool <mempool_name>
+ *  buffer <buffer_size>
+ *  pool <pool_size>
+ *  cache <cache_size>
+ *  cpu <cpu_id>
+ */
+static void
+cmd_mempool(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct mempool_params p;
+	char *name;
+	struct mempool *mempool;
+
+	if (n_tokens != 10) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	name = tokens[1];
+
+	if (strcmp(tokens[2], "buffer") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "buffer");
+		return;
+	}
+
+	if (parser_read_uint32(&p.buffer_size, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "buffer_size");
+		return;
+	}
+
+	if (strcmp(tokens[4], "pool") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pool");
+		return;
+	}
+
+	if (parser_read_uint32(&p.pool_size, tokens[5]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "pool_size");
+		return;
+	}
+
+	if (strcmp(tokens[6], "cache") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cache");
+		return;
+	}
+
+	if (parser_read_uint32(&p.cache_size, tokens[7]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "cache_size");
+		return;
+	}
+
+	if (strcmp(tokens[8], "cpu") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu");
+		return;
+	}
+
+	if (parser_read_uint32(&p.cpu_id, tokens[9]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id");
+		return;
+	}
+
+	mempool = mempool_create(name, &p);
+	if (mempool == NULL) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
 void
-cli_process(char *in, char *out __rte_unused, size_t out_size __rte_unused)
+cli_process(char *in, char *out, size_t out_size)
 {
+	char *tokens[CMD_MAX_TOKENS];
+	uint32_t n_tokens = RTE_DIM(tokens);
+	int status;
+
 	if (is_comment(in))
 		return;
 
+	status = parse_tokenize_string(in, tokens, &n_tokens);
+	if (status) {
+		snprintf(out, out_size, MSG_ARG_TOO_MANY, "");
+		return;
+	}
+
+	if (n_tokens == 0)
+		return;
+
+	if (strcmp(tokens[0], "mempool") == 0) {
+		cmd_mempool(tokens, n_tokens, out, out_size);
+		return;
+	}
+
+	snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
 }
 
 int
diff --git a/examples/ip_pipeline/common.h b/examples/ip_pipeline/common.h
new file mode 100644
index 0000000..0886dfb
--- /dev/null
+++ b/examples/ip_pipeline/common.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#ifndef _INCLUDE_COMMON_H_
+#define _INCLUDE_COMMON_H_
+
+#ifndef NAME_SIZE
+#define NAME_SIZE                                            64
+#endif
+
+#endif /* _INCLUDE_COMMON_H_ */
diff --git a/examples/ip_pipeline/main.c b/examples/ip_pipeline/main.c
index 60936f4..b53f623 100644
--- a/examples/ip_pipeline/main.c
+++ b/examples/ip_pipeline/main.c
@@ -12,6 +12,7 @@
 
 #include "cli.h"
 #include "conn.h"
+#include "mempool.h"
 
 static const char usage[] =
 	"%s EAL_ARGS -- [-h HOST] [-p PORT] [-s SCRIPT]\n";
@@ -159,6 +160,13 @@ main(int argc, char **argv)
 		return status;
 	};
 
+	/* Mempool */
+	status = mempool_init();
+	if (status) {
+		printf("Error: Mempool initialization failed (%d)\n", status);
+		return status;
+	}
+
 	/* Script */
 	if (app.script_name)
 		cli_script_process(app.script_name,
diff --git a/examples/ip_pipeline/mempool.c b/examples/ip_pipeline/mempool.c
new file mode 100644
index 0000000..33b9243
--- /dev/null
+++ b/examples/ip_pipeline/mempool.c
@@ -0,0 +1,81 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <rte_mbuf.h>
+
+#include "mempool.h"
+
+#define BUFFER_SIZE_MIN        (sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM)
+
+static struct mempool_list mempool_list;
+
+int
+mempool_init(void)
+{
+	TAILQ_INIT(&mempool_list);
+
+	return 0;
+}
+
+struct mempool *
+mempool_find(const char *name)
+{
+	struct mempool *mempool;
+
+	if (name == NULL)
+		return NULL;
+
+	TAILQ_FOREACH(mempool, &mempool_list, node)
+		if (strcmp(mempool->name, name) == 0)
+			return mempool;
+
+	return NULL;
+}
+
+struct mempool *
+mempool_create(const char *name, struct mempool_params *params)
+{
+	struct mempool *mempool;
+	struct rte_mempool *m;
+
+	/* Check input params */
+	if ((name == NULL) ||
+		mempool_find(name) ||
+		(params == NULL) ||
+		(params->buffer_size < BUFFER_SIZE_MIN) ||
+		(params->pool_size == 0))
+		return NULL;
+
+	/* Resource create */
+	m = rte_pktmbuf_pool_create(
+		name,
+		params->pool_size,
+		params->cache_size,
+		0,
+		params->buffer_size - sizeof(struct rte_mbuf),
+		params->cpu_id);
+
+	if (m == NULL)
+		return NULL;
+
+	/* Node allocation */
+	mempool = calloc(1, sizeof(struct mempool));
+	if (mempool == NULL) {
+		rte_mempool_free(m);
+		return NULL;
+	}
+
+	/* Node fill in */
+	strncpy(mempool->name, name, sizeof(mempool->name));
+	mempool->m = m;
+	mempool->buffer_size = params->buffer_size;
+
+	/* Node add to list */
+	TAILQ_INSERT_TAIL(&mempool_list, mempool, node);
+
+	return mempool;
+}
diff --git a/examples/ip_pipeline/mempool.h b/examples/ip_pipeline/mempool.h
new file mode 100644
index 0000000..bd46a11
--- /dev/null
+++ b/examples/ip_pipeline/mempool.h
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#ifndef _INCLUDE_MEMPOOL_H_
+#define _INCLUDE_MEMPOOL_H_
+
+#include <stdint.h>
+#include <sys/queue.h>
+
+#include <rte_mempool.h>
+
+#include "common.h"
+
+struct mempool {
+	TAILQ_ENTRY(mempool) node;
+	char name[NAME_SIZE];
+	struct rte_mempool *m;
+	uint32_t buffer_size;
+};
+
+TAILQ_HEAD(mempool_list, mempool);
+
+int
+mempool_init(void);
+
+struct mempool *
+mempool_find(const char *name);
+
+struct mempool_params {
+	uint32_t buffer_size;
+	uint32_t pool_size;
+	uint32_t cache_size;
+	uint32_t cpu_id;
+};
+
+struct mempool *
+mempool_create(const char *name, struct mempool_params *params);
+
+#endif /* _INCLUDE_MEMPOOL_H_ */
diff --git a/examples/ip_pipeline/meson.build b/examples/ip_pipeline/meson.build
index a89cb30..f8a450f 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -11,5 +11,6 @@ sources = files(
 	'cli.c',
 	'conn.c',
 	'main.c',
+	'mempool.c',
 	'parser.c',
 )
-- 
2.9.3

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

* [dpdk-dev] [PATCH v2 20/44] ip_pipeline: add link object
  2018-03-12 17:25   ` [dpdk-dev] [PATCH v2 00/44] ip_pipeline: refactoring Jasvinder Singh
                       ` (18 preceding siblings ...)
  2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 19/44] ip_pipeline: add mempool object for pipeline Jasvinder Singh
@ 2018-03-12 17:25     ` Jasvinder Singh
  2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 21/44] ip_pipeline: add software queue object Jasvinder Singh
                       ` (23 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-12 17:25 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Fan Zhang

Add link object implementation to the application.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Fan Zhang <roy.fan.zhang@intel.com>
---
 examples/ip_pipeline/Makefile    |   1 +
 examples/ip_pipeline/cli.c       | 122 ++++++++++++++++++
 examples/ip_pipeline/link.c      | 268 +++++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/link.h      |  63 +++++++++
 examples/ip_pipeline/main.c      |   8 ++
 examples/ip_pipeline/meson.build |   1 +
 6 files changed, 463 insertions(+)
 create mode 100644 examples/ip_pipeline/link.c
 create mode 100644 examples/ip_pipeline/link.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index fca28c5..3dab932 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -7,6 +7,7 @@ APP = ip_pipeline
 # all source are stored in SRCS-y
 SRCS-y := cli.c
 SRCS-y += conn.c
+SRCS-y += link.c
 SRCS-y += main.c
 SRCS-y += mempool.c
 SRCS-y += parser.c
diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index 6fe3725..221b716 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -10,6 +10,7 @@
 #include <rte_common.h>
 
 #include "cli.h"
+#include "link.h"
 #include "mempool.h"
 #include "parser.h"
 
@@ -110,6 +111,122 @@ cmd_mempool(char **tokens,
 	}
 }
 
+/**
+ * link <link_name>
+ *  dev <device_name> | port <port_id>
+ *  rxq <n_queues> <queue_size> <mempool_name>
+ *  txq <n_queues> <queue_size>
+ *  promiscuous on | off
+ *  [rss <qid_0> ... <qid_n>]
+*/
+static void
+cmd_link(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct link_params p;
+	struct link_params_rss rss;
+	struct link *link;
+	char *name;
+
+	if ((n_tokens < 13) || (n_tokens > 14 + LINK_RXQ_RSS_MAX)) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+	name = tokens[1];
+
+	if (strcmp(tokens[2], "dev") == 0)
+		p.dev_name = tokens[3];
+	else if (strcmp(tokens[2], "port") == 0) {
+		p.dev_name = NULL;
+
+		if (parser_read_uint16(&p.port_id, tokens[3]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
+			return;
+		}
+	} else {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "dev or port");
+		return;
+	}
+
+	if (strcmp(tokens[4], "rxq") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rxq");
+	return;
+	}
+
+	if (parser_read_uint32(&p.rx.n_queues, tokens[5]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "n_queues");
+		return;
+	}
+	if (parser_read_uint32(&p.rx.queue_size, tokens[6]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "queue_size");
+		return;
+}
+
+	p.rx.mempool_name = tokens[7];
+
+	if (strcmp(tokens[8], "txq") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "txq");
+		return;
+	}
+
+	if (parser_read_uint32(&p.tx.n_queues, tokens[9]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "n_queues");
+		return;
+	}
+
+	if (parser_read_uint32(&p.tx.queue_size, tokens[10]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "queue_size");
+		return;
+	}
+
+	if (strcmp(tokens[11], "promiscuous") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "promiscuous");
+		return;
+	}
+
+	if (strcmp(tokens[12], "on") == 0)
+		p.promiscuous = 1;
+	else if (strcmp(tokens[12], "off") == 0)
+		p.promiscuous = 0;
+	else {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "on or off");
+		return;
+	}
+
+	/* RSS */
+	p.rx.rss = NULL;
+	if (n_tokens > 13) {
+		uint32_t queue_id, i;
+
+		if (strcmp(tokens[13], "rss") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rss");
+			return;
+		}
+
+		p.rx.rss = &rss;
+
+		rss.n_queues = 0;
+		for (i = 14; i < n_tokens; i++) {
+			if (parser_read_uint32(&queue_id, tokens[i]) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID,
+					"queue_id");
+				return;
+			}
+
+			rss.queue_id[rss.n_queues] = queue_id;
+			rss.n_queues++;
+		}
+	}
+
+	link = link_create(name, &p);
+	if (link == NULL) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
 void
 cli_process(char *in, char *out, size_t out_size)
 {
@@ -134,6 +251,11 @@ cli_process(char *in, char *out, size_t out_size)
 		return;
 	}
 
+	if (strcmp(tokens[0], "link") == 0) {
+		cmd_link(tokens, n_tokens, out, out_size);
+		return;
+	}
+
 	snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
 }
 
diff --git a/examples/ip_pipeline/link.c b/examples/ip_pipeline/link.c
new file mode 100644
index 0000000..26ff41b
--- /dev/null
+++ b/examples/ip_pipeline/link.c
@@ -0,0 +1,268 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <rte_ethdev.h>
+
+#include "link.h"
+#include "mempool.h"
+
+static struct link_list link_list;
+
+int
+link_init(void)
+{
+	TAILQ_INIT(&link_list);
+
+	return 0;
+}
+
+struct link *
+link_find(const char *name)
+{
+	struct link *link;
+
+	if (name == NULL)
+		return NULL;
+
+	TAILQ_FOREACH(link, &link_list, node)
+		if (strcmp(link->name, name) == 0)
+			return link;
+
+	return NULL;
+}
+
+static struct rte_eth_conf port_conf_default = {
+	.link_speeds = 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   = 1, /* CRC strip by HW */
+		.enable_scatter = 0, /* Scattered packets RX handler */
+
+		.max_rx_pkt_len = 9000, /* Jumbo frame max packet len */
+		.split_hdr_size = 0, /* Header split buffer size */
+	},
+	.rx_adv_conf = {
+		.rss_conf = {
+			.rss_key = NULL,
+			.rss_key_len = 40,
+			.rss_hf = 0,
+		},
+	},
+	.txmode = {
+		.mq_mode = ETH_MQ_TX_NONE,
+	},
+	.lpbk_mode = 0,
+};
+
+#define RETA_CONF_SIZE     (ETH_RSS_RETA_SIZE_512 / RTE_RETA_GROUP_SIZE)
+
+static int
+rss_setup(uint16_t port_id,
+	uint16_t reta_size,
+	struct link_params_rss *rss)
+{
+	struct rte_eth_rss_reta_entry64 reta_conf[RETA_CONF_SIZE];
+	uint32_t i;
+	int status;
+
+	/* RETA setting */
+	memset(reta_conf, 0, sizeof(reta_conf));
+
+	for (i = 0; i < reta_size; i++)
+		reta_conf[i / RTE_RETA_GROUP_SIZE].mask = UINT64_MAX;
+
+	for (i = 0; i < reta_size; i++) {
+		uint32_t reta_id = i / RTE_RETA_GROUP_SIZE;
+		uint32_t reta_pos = i % RTE_RETA_GROUP_SIZE;
+		uint32_t rss_qs_pos = i % rss->n_queues;
+
+		reta_conf[reta_id].reta[reta_pos] =
+			(uint16_t) rss->queue_id[rss_qs_pos];
+	}
+
+	/* RETA update */
+	status = rte_eth_dev_rss_reta_update(port_id,
+		reta_conf,
+		reta_size);
+
+	return status;
+}
+
+struct link *
+link_create(const char *name, struct link_params *params)
+{
+	struct rte_eth_dev_info port_info;
+	struct rte_eth_conf port_conf;
+	struct link *link;
+	struct link_params_rss *rss;
+	struct mempool *mempool;
+	uint32_t cpu_id, i;
+	int status;
+	uint16_t port_id;
+
+	/* Check input params */
+	if ((name == NULL) ||
+		link_find(name) ||
+		(params == NULL) ||
+		(params->rx.n_queues == 0) ||
+		(params->rx.queue_size == 0) ||
+		(params->tx.n_queues == 0) ||
+		(params->tx.queue_size == 0))
+		return NULL;
+
+	port_id = params->port_id;
+	if (params->dev_name) {
+		status = rte_eth_dev_get_port_by_name(params->dev_name,
+			&port_id);
+
+		if (status)
+			return NULL;
+	} else
+		if (!rte_eth_dev_is_valid_port(port_id))
+			return NULL;
+
+	rte_eth_dev_info_get(port_id, &port_info);
+
+	mempool = mempool_find(params->rx.mempool_name);
+	if (mempool == NULL)
+		return NULL;
+
+	rss = params->rx.rss;
+	if (rss) {
+		if ((port_info.reta_size == 0) ||
+			(port_info.reta_size > ETH_RSS_RETA_SIZE_512))
+			return NULL;
+
+		if ((rss->n_queues == 0) ||
+			(rss->n_queues >= LINK_RXQ_RSS_MAX))
+			return NULL;
+
+		for (i = 0; i < rss->n_queues; i++)
+			if (rss->queue_id[i] >= port_info.max_rx_queues)
+				return NULL;
+	}
+
+	/**
+	 * Resource create
+	 */
+	/* Port */
+	memcpy(&port_conf, &port_conf_default, sizeof(port_conf));
+	if (rss) {
+		port_conf.rxmode.mq_mode = ETH_MQ_RX_RSS;
+		port_conf.rx_adv_conf.rss_conf.rss_hf =
+			ETH_RSS_IPV4 | ETH_RSS_IPV6;
+	}
+
+	cpu_id = (uint32_t) rte_eth_dev_socket_id(port_id);
+	if (cpu_id == (uint32_t) SOCKET_ID_ANY)
+		cpu_id = 0;
+
+	status = rte_eth_dev_configure(
+		port_id,
+		params->rx.n_queues,
+		params->tx.n_queues,
+		&port_conf);
+
+	if (status < 0)
+		return NULL;
+
+	if (params->promiscuous)
+		rte_eth_promiscuous_enable(port_id);
+
+	/* Port RX */
+	for (i = 0; i < params->rx.n_queues; i++) {
+		status = rte_eth_rx_queue_setup(
+			port_id,
+			i,
+			params->rx.queue_size,
+			cpu_id,
+			NULL,
+			mempool->m);
+
+		if (status < 0)
+			return NULL;
+	}
+
+	/* Port TX */
+	for (i = 0; i < params->tx.n_queues; i++) {
+		status = rte_eth_tx_queue_setup(
+			port_id,
+			i,
+			params->tx.queue_size,
+			cpu_id,
+			NULL);
+
+		if (status < 0)
+			return NULL;
+	}
+
+	/* Port start */
+	status = rte_eth_dev_start(port_id);
+	if (status < 0)
+		return NULL;
+
+	if (rss) {
+		status = rss_setup(port_id, port_info.reta_size, rss);
+
+		if (status) {
+			rte_eth_dev_stop(port_id);
+			return NULL;
+		}
+	}
+
+	/* Port link up */
+	status = rte_eth_dev_set_link_up(port_id);
+	if ((status < 0) && (status != -ENOTSUP)) {
+		rte_eth_dev_stop(port_id);
+		return NULL;
+	}
+
+	/* Node allocation */
+	link = calloc(1, sizeof(struct link));
+	if (link == NULL) {
+		rte_eth_dev_stop(port_id);
+		return NULL;
+	}
+
+	/* Node fill in */
+	strncpy(link->name, name, sizeof(link->name));
+	link->port_id = port_id;
+	link->n_rxq = params->rx.n_queues;
+	link->n_txq = params->tx.n_queues;
+
+	/* Node add to list */
+	TAILQ_INSERT_TAIL(&link_list, link, node);
+
+	return link;
+}
+
+int
+link_is_up(const char *name)
+{
+	struct rte_eth_link link_params;
+	struct link *link;
+
+	/* Check input params */
+	if (name == NULL)
+		return 0;
+
+	link = link_find(name);
+	if (link == NULL)
+		return 0;
+
+	/* Resource */
+	rte_eth_link_get(link->port_id, &link_params);
+
+	return (link_params.link_status == ETH_LINK_DOWN) ? 0 : 1;
+}
diff --git a/examples/ip_pipeline/link.h b/examples/ip_pipeline/link.h
new file mode 100644
index 0000000..37d3dc4
--- /dev/null
+++ b/examples/ip_pipeline/link.h
@@ -0,0 +1,63 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#ifndef _INCLUDE_LINK_H_
+#define _INCLUDE_LINK_H_
+
+#include <stdint.h>
+#include <sys/queue.h>
+
+#include "common.h"
+
+#ifndef LINK_RXQ_RSS_MAX
+#define LINK_RXQ_RSS_MAX                                   16
+#endif
+
+struct link {
+	TAILQ_ENTRY(link) node;
+	char name[NAME_SIZE];
+	uint16_t port_id;
+	uint32_t n_rxq;
+	uint32_t n_txq;
+};
+
+TAILQ_HEAD(link_list, link);
+
+int
+link_init(void);
+
+struct link *
+link_find(const char *name);
+
+struct link_params_rss {
+	uint32_t queue_id[LINK_RXQ_RSS_MAX];
+	uint32_t n_queues;
+};
+
+struct link_params {
+	const char *dev_name;
+	uint16_t port_id; /**< Valid only when *dev_name* is NULL. */
+
+	struct {
+		uint32_t n_queues;
+		uint32_t queue_size;
+		const char *mempool_name;
+		struct link_params_rss *rss;
+	} rx;
+
+	struct {
+		uint32_t n_queues;
+		uint32_t queue_size;
+	} tx;
+
+	int promiscuous;
+};
+
+struct link *
+link_create(const char *name, struct link_params *params);
+
+int
+link_is_up(const char *name);
+
+#endif /* _INCLUDE_LINK_H_ */
diff --git a/examples/ip_pipeline/main.c b/examples/ip_pipeline/main.c
index b53f623..edfb523 100644
--- a/examples/ip_pipeline/main.c
+++ b/examples/ip_pipeline/main.c
@@ -12,6 +12,7 @@
 
 #include "cli.h"
 #include "conn.h"
+#include "link.h"
 #include "mempool.h"
 
 static const char usage[] =
@@ -167,6 +168,13 @@ main(int argc, char **argv)
 		return status;
 	}
 
+	/* Link */
+	status = link_init();
+	if (status) {
+		printf("Error: Link initialization failed (%d)\n", status);
+		return status;
+	}
+
 	/* Script */
 	if (app.script_name)
 		cli_script_process(app.script_name,
diff --git a/examples/ip_pipeline/meson.build b/examples/ip_pipeline/meson.build
index f8a450f..a2f9bb6 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -10,6 +10,7 @@ deps += ['pipeline', 'bus_pci']
 sources = files(
 	'cli.c',
 	'conn.c',
+	'link.c',
 	'main.c',
 	'mempool.c',
 	'parser.c',
-- 
2.9.3

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

* [dpdk-dev] [PATCH v2 21/44] ip_pipeline: add software queue object
  2018-03-12 17:25   ` [dpdk-dev] [PATCH v2 00/44] ip_pipeline: refactoring Jasvinder Singh
                       ` (19 preceding siblings ...)
  2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 20/44] ip_pipeline: add link object Jasvinder Singh
@ 2018-03-12 17:25     ` Jasvinder Singh
  2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 22/44] ip_pipeline: add traffic manager object Jasvinder Singh
                       ` (22 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-12 17:25 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Kevin Laatz

Add swq object implementation to the application.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
---
 examples/ip_pipeline/Makefile    |  1 +
 examples/ip_pipeline/cli.c       | 55 +++++++++++++++++++++++++++++
 examples/ip_pipeline/main.c      |  8 +++++
 examples/ip_pipeline/meson.build |  1 +
 examples/ip_pipeline/swq.c       | 74 ++++++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/swq.h       | 37 ++++++++++++++++++++
 6 files changed, 176 insertions(+)
 create mode 100644 examples/ip_pipeline/swq.c
 create mode 100644 examples/ip_pipeline/swq.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index 3dab932..0dc8442 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -11,6 +11,7 @@ SRCS-y += link.c
 SRCS-y += main.c
 SRCS-y += mempool.c
 SRCS-y += parser.c
+SRCS-y += swq.c
 #SRCS-y += thread.c
 
 # Build using pkg-config variables if possible
diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index 221b716..0f665eb 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -13,6 +13,7 @@
 #include "link.h"
 #include "mempool.h"
 #include "parser.h"
+#include "swq.h"
 
 #ifndef CMD_MAX_TOKENS
 #define CMD_MAX_TOKENS     256
@@ -227,6 +228,55 @@ cmd_link(char **tokens,
 	}
 }
 
+/**
+ * swq <swq_name>
+ *  size <size>
+ *  cpu <cpu_id>
+ */
+static void
+cmd_swq(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct swq_params p;
+	char *name;
+	struct swq *swq;
+
+	if (n_tokens != 6) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	name = tokens[1];
+
+	if (strcmp(tokens[2], "size") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
+		return;
+	}
+
+	if (parser_read_uint32(&p.size, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "size");
+		return;
+	}
+
+	if (strcmp(tokens[4], "cpu") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu");
+		return;
+	}
+
+	if (parser_read_uint32(&p.cpu_id, tokens[5]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id");
+		return;
+	}
+
+	swq = swq_create(name, &p);
+	if (swq == NULL) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
 void
 cli_process(char *in, char *out, size_t out_size)
 {
@@ -256,6 +306,11 @@ cli_process(char *in, char *out, size_t out_size)
 		return;
 	}
 
+	if (strcmp(tokens[0], "swq") == 0) {
+		cmd_swq(tokens, n_tokens, out, out_size);
+		return;
+	}
+
 	snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
 }
 
diff --git a/examples/ip_pipeline/main.c b/examples/ip_pipeline/main.c
index edfb523..456f016 100644
--- a/examples/ip_pipeline/main.c
+++ b/examples/ip_pipeline/main.c
@@ -14,6 +14,7 @@
 #include "conn.h"
 #include "link.h"
 #include "mempool.h"
+#include "swq.h"
 
 static const char usage[] =
 	"%s EAL_ARGS -- [-h HOST] [-p PORT] [-s SCRIPT]\n";
@@ -175,6 +176,13 @@ main(int argc, char **argv)
 		return status;
 	}
 
+	/* SWQ */
+	status = swq_init();
+	if (status) {
+		printf("Error: SWQ initialization failed (%d)\n", status);
+		return status;
+	}
+
 	/* Script */
 	if (app.script_name)
 		cli_script_process(app.script_name,
diff --git a/examples/ip_pipeline/meson.build b/examples/ip_pipeline/meson.build
index a2f9bb6..442f3e3 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -14,4 +14,5 @@ sources = files(
 	'main.c',
 	'mempool.c',
 	'parser.c',
+	'swq.c',
 )
diff --git a/examples/ip_pipeline/swq.c b/examples/ip_pipeline/swq.c
new file mode 100644
index 0000000..c11bbf2
--- /dev/null
+++ b/examples/ip_pipeline/swq.c
@@ -0,0 +1,74 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "swq.h"
+
+static struct swq_list swq_list;
+
+int
+swq_init(void)
+{
+	TAILQ_INIT(&swq_list);
+
+	return 0;
+}
+
+struct swq *
+swq_find(const char *name)
+{
+	struct swq *swq;
+
+	if (name == NULL)
+		return NULL;
+
+	TAILQ_FOREACH(swq, &swq_list, node)
+		if (strcmp(swq->name, name) == 0)
+			return swq;
+
+	return NULL;
+}
+
+struct swq *
+swq_create(const char *name, struct swq_params *params)
+{
+	struct swq *swq;
+	struct rte_ring *r;
+	unsigned int flags = RING_F_SP_ENQ | RING_F_SC_DEQ;
+
+	/* Check input params */
+	if ((name == NULL) ||
+		swq_find(name) ||
+		(params == NULL) ||
+		(params->size == 0))
+		return NULL;
+
+	/* Resource create */
+	r = rte_ring_create(
+		name,
+		params->size,
+		params->cpu_id,
+		flags);
+
+	if (r == NULL)
+		return NULL;
+
+	/* Node allocation */
+	swq = calloc(1, sizeof(struct swq));
+	if (swq == NULL) {
+		rte_ring_free(r);
+		return NULL;
+	}
+
+	/* Node fill in */
+	strncpy(swq->name, name, sizeof(swq->name));
+	swq->r = r;
+
+	/* Node add to list */
+	TAILQ_INSERT_TAIL(&swq_list, swq, node);
+
+	return swq;
+}
diff --git a/examples/ip_pipeline/swq.h b/examples/ip_pipeline/swq.h
new file mode 100644
index 0000000..c8440ee
--- /dev/null
+++ b/examples/ip_pipeline/swq.h
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#ifndef _INCLUDE_SWQ_H_
+#define _INCLUDE_SWQ_H_
+
+#include <stdint.h>
+#include <sys/queue.h>
+
+#include <rte_ring.h>
+
+#include "common.h"
+
+struct swq {
+	TAILQ_ENTRY(swq) node;
+	char name[NAME_SIZE];
+	struct rte_ring *r;
+};
+
+TAILQ_HEAD(swq_list, swq);
+
+int
+swq_init(void);
+
+struct swq *
+swq_find(const char *name);
+
+struct swq_params {
+	uint32_t size;
+	uint32_t cpu_id;
+};
+
+struct swq *
+swq_create(const char *name, struct swq_params *params);
+
+#endif /* _INCLUDE_SWQ_H_ */
-- 
2.9.3

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

* [dpdk-dev] [PATCH v2 22/44] ip_pipeline: add traffic manager object
  2018-03-12 17:25   ` [dpdk-dev] [PATCH v2 00/44] ip_pipeline: refactoring Jasvinder Singh
                       ` (20 preceding siblings ...)
  2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 21/44] ip_pipeline: add software queue object Jasvinder Singh
@ 2018-03-12 17:25     ` Jasvinder Singh
  2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 23/44] ip_pipeline: add tap object Jasvinder Singh
                       ` (21 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-12 17:25 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add traffic manager object implementation to the application.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/Makefile    |   1 +
 examples/ip_pipeline/cli.c       | 360 +++++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/main.c      |   8 +
 examples/ip_pipeline/meson.build |   1 +
 examples/ip_pipeline/tmgr.c      | 227 ++++++++++++++++++++++++
 examples/ip_pipeline/tmgr.h      |  70 ++++++++
 6 files changed, 667 insertions(+)
 create mode 100644 examples/ip_pipeline/tmgr.c
 create mode 100644 examples/ip_pipeline/tmgr.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index 0dc8442..35e4302 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -12,6 +12,7 @@ SRCS-y += main.c
 SRCS-y += mempool.c
 SRCS-y += parser.c
 SRCS-y += swq.c
+SRCS-y += tmgr.c
 #SRCS-y += thread.c
 
 # Build using pkg-config variables if possible
diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index 0f665eb..c6111e7 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -14,6 +14,7 @@
 #include "mempool.h"
 #include "parser.h"
 #include "swq.h"
+#include "tmgr.h"
 
 #ifndef CMD_MAX_TOKENS
 #define CMD_MAX_TOKENS     256
@@ -277,6 +278,331 @@ cmd_swq(char **tokens,
 	}
 }
 
+/**
+ * tmgr subport profile
+ *  <tb_rate> <tb_size>
+ *  <tc0_rate> <tc1_rate> <tc2_rate> <tc3_rate>
+ *  <tc_period>
+ */
+static void
+cmd_tmgr_subport_profile(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct rte_sched_subport_params p;
+	int status, i;
+
+	if (n_tokens != 10) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	if (parser_read_uint32(&p.tb_rate, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "tb_rate");
+		return;
+	}
+
+	if (parser_read_uint32(&p.tb_size, tokens[4]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "tb_size");
+		return;
+	}
+
+	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
+		if (parser_read_uint32(&p.tc_rate[i], tokens[5 + i]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "tc_rate");
+			return;
+		}
+
+	if (parser_read_uint32(&p.tc_period, tokens[9]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "tc_period");
+		return;
+	}
+
+	status = tmgr_subport_profile_add(&p);
+	if (status != 0) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
+ * tmgr pipe profile
+ *  <tb_rate> <tb_size>
+ *  <tc0_rate> <tc1_rate> <tc2_rate> <tc3_rate>
+ *  <tc_period>
+ *  <tc_ov_weight>
+ *  <wrr_weight0..15>
+ */
+static void
+cmd_tmgr_pipe_profile(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct rte_sched_pipe_params p;
+	int status, i;
+
+	if (n_tokens != 27) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	if (parser_read_uint32(&p.tb_rate, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "tb_rate");
+		return;
+	}
+
+	if (parser_read_uint32(&p.tb_size, tokens[4]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "tb_size");
+		return;
+	}
+
+	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
+		if (parser_read_uint32(&p.tc_rate[i], tokens[5 + i]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "tc_rate");
+			return;
+		}
+
+	if (parser_read_uint32(&p.tc_period, tokens[9]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "tc_period");
+		return;
+	}
+
+#ifdef RTE_SCHED_SUBPORT_TC_OV
+	if (parser_read_uint32(&p.tc_ov_weight, tokens[10]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "tc_ov_weight");
+		return;
+	}
+#endif
+
+	for (i = 0; i < RTE_SCHED_QUEUES_PER_PIPE; i++)
+		if (parser_read_uint8(&p.wrr_weights[i], tokens[11 + i]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "wrr_weights");
+			return;
+		}
+
+	status = tmgr_pipe_profile_add(&p);
+	if (status != 0) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
+ * tmgr <tmgr_name>
+ *  rate <rate>
+ *  spp <n_subports_per_port>
+ *  pps <n_pipes_per_subport>
+ *  qsize <qsize_tc0> <qsize_tc1> <qsize_tc2> <qsize_tc3>
+ *  fo <frame_overhead>
+ *  mtu <mtu>
+ *  cpu <cpu_id>
+ */
+static void
+cmd_tmgr(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct tmgr_port_params p;
+	char *name;
+	struct tmgr_port *tmgr_port;
+	int i;
+
+	if (n_tokens != 19) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	name = tokens[1];
+
+	if (strcmp(tokens[2], "rate") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rate");
+		return;
+	}
+
+	if (parser_read_uint32(&p.rate, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "rate");
+		return;
+	}
+
+	if (strcmp(tokens[4], "spp") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "spp");
+		return;
+	}
+
+	if (parser_read_uint32(&p.n_subports_per_port, tokens[5]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "n_subports_per_port");
+		return;
+	}
+
+	if (strcmp(tokens[6], "pps") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pps");
+		return;
+	}
+
+	if (parser_read_uint32(&p.n_pipes_per_subport, tokens[7]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "n_pipes_per_subport");
+		return;
+	}
+
+	if (strcmp(tokens[8], "qsize") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "qsize");
+		return;
+	}
+
+	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
+		if (parser_read_uint16(&p.qsize[i], tokens[9 + i]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "qsize");
+			return;
+		}
+
+	if (strcmp(tokens[13], "fo") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "fo");
+		return;
+	}
+
+	if (parser_read_uint32(&p.frame_overhead, tokens[14]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "frame_overhead");
+		return;
+	}
+
+	if (strcmp(tokens[15], "mtu") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mtu");
+		return;
+	}
+
+	if (parser_read_uint32(&p.mtu, tokens[16]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "mtu");
+		return;
+	}
+
+	if (strcmp(tokens[17], "cpu") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu");
+		return;
+	}
+
+	if (parser_read_uint32(&p.cpu_id, tokens[18]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id");
+		return;
+	}
+
+	tmgr_port = tmgr_port_create(name, &p);
+	if (tmgr_port == NULL) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
+ * tmgr <tmgr_name> subport <subport_id>
+ *  profile <subport_profile_id>
+ */
+static void
+cmd_tmgr_subport(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	uint32_t subport_id, subport_profile_id;
+	int status;
+	char *name;
+
+	if (n_tokens != 6) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	name = tokens[1];
+
+	if (parser_read_uint32(&subport_id, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "subport_id");
+		return;
+	}
+
+	if (parser_read_uint32(&subport_profile_id, tokens[5]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "subport_profile_id");
+		return;
+	}
+
+	status = tmgr_subport_config(name, subport_id, subport_profile_id);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
+ * tmgr <tmgr_name> subport <subport_id> pipe
+ *  from <pipe_id_first> to <pipe_id_last>
+ *  profile <pipe_profile_id>
+ */
+static void
+cmd_tmgr_subport_pipe(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	uint32_t subport_id, pipe_id_first, pipe_id_last, pipe_profile_id;
+	int status;
+	char *name;
+
+	if (n_tokens != 11) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	name = tokens[1];
+
+	if (parser_read_uint32(&subport_id, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "subport_id");
+		return;
+	}
+
+	if (strcmp(tokens[4], "pipe") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipe");
+		return;
+	}
+
+	if (strcmp(tokens[5], "from") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "from");
+		return;
+	}
+
+	if (parser_read_uint32(&pipe_id_first, tokens[6]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "pipe_id_first");
+		return;
+	}
+
+	if (strcmp(tokens[7], "to") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "to");
+		return;
+	}
+
+	if (parser_read_uint32(&pipe_id_last, tokens[8]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "pipe_id_last");
+		return;
+	}
+
+	if (strcmp(tokens[9], "profile") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
+		return;
+	}
+
+	if (parser_read_uint32(&pipe_profile_id, tokens[10]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "pipe_profile_id");
+		return;
+	}
+
+	status = tmgr_pipe_config(name, subport_id, pipe_id_first,
+			pipe_id_last, pipe_profile_id);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
 void
 cli_process(char *in, char *out, size_t out_size)
 {
@@ -311,6 +637,40 @@ cli_process(char *in, char *out, size_t out_size)
 		return;
 	}
 
+	if (strcmp(tokens[0], "tmgr") == 0) {
+		if ((n_tokens >= 3) &&
+			(strcmp(tokens[1], "subport") == 0) &&
+			(strcmp(tokens[2], "profile") == 0)) {
+			cmd_tmgr_subport_profile(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
+
+		if ((n_tokens >= 3) &&
+			(strcmp(tokens[1], "pipe") == 0) &&
+			(strcmp(tokens[2], "profile") == 0)) {
+			cmd_tmgr_pipe_profile(tokens, n_tokens, out, out_size);
+			return;
+		}
+
+		if ((n_tokens >= 5) &&
+			(strcmp(tokens[2], "subport") == 0) &&
+			(strcmp(tokens[4], "profile") == 0)) {
+			cmd_tmgr_subport(tokens, n_tokens, out, out_size);
+			return;
+		}
+
+		if ((n_tokens >= 5) &&
+			(strcmp(tokens[2], "subport") == 0) &&
+			(strcmp(tokens[4], "pipe") == 0)) {
+			cmd_tmgr_subport_pipe(tokens, n_tokens, out, out_size);
+			return;
+		}
+
+		cmd_tmgr(tokens, n_tokens, out, out_size);
+		return;
+	}
+
 	snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
 }
 
diff --git a/examples/ip_pipeline/main.c b/examples/ip_pipeline/main.c
index 456f016..490991f 100644
--- a/examples/ip_pipeline/main.c
+++ b/examples/ip_pipeline/main.c
@@ -15,6 +15,7 @@
 #include "link.h"
 #include "mempool.h"
 #include "swq.h"
+#include "tmgr.h"
 
 static const char usage[] =
 	"%s EAL_ARGS -- [-h HOST] [-p PORT] [-s SCRIPT]\n";
@@ -183,6 +184,13 @@ main(int argc, char **argv)
 		return status;
 	}
 
+	/* Traffic Manager */
+	status = tmgr_init();
+	if (status) {
+		printf("Error: TMGR initialization failed (%d)\n", status);
+		return status;
+	}
+
 	/* Script */
 	if (app.script_name)
 		cli_script_process(app.script_name,
diff --git a/examples/ip_pipeline/meson.build b/examples/ip_pipeline/meson.build
index 442f3e3..cb2154c 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -15,4 +15,5 @@ sources = files(
 	'mempool.c',
 	'parser.c',
 	'swq.c',
+	'tmgr.c'
 )
diff --git a/examples/ip_pipeline/tmgr.c b/examples/ip_pipeline/tmgr.c
new file mode 100644
index 0000000..b46ca96
--- /dev/null
+++ b/examples/ip_pipeline/tmgr.c
@@ -0,0 +1,227 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#include <stdlib.h>
+
+#include "tmgr.h"
+
+static struct rte_sched_subport_params
+	subport_profile[TMGR_SUBPORT_PROFILE_MAX];
+
+static uint32_t n_subport_profiles;
+
+static struct rte_sched_pipe_params
+	pipe_profile[TMGR_PIPE_PROFILE_MAX];
+
+static uint32_t n_pipe_profiles;
+
+static struct tmgr_port_list tmgr_port_list;
+
+int
+tmgr_init(void)
+{
+	TAILQ_INIT(&tmgr_port_list);
+
+	return 0;
+}
+
+struct tmgr_port *
+tmgr_port_find(const char *name)
+{
+	struct tmgr_port *tmgr_port;
+
+	if (name == NULL)
+		return NULL;
+
+	TAILQ_FOREACH(tmgr_port, &tmgr_port_list, node)
+		if (strcmp(tmgr_port->name, name) == 0)
+			return tmgr_port;
+
+	return NULL;
+}
+
+int
+tmgr_subport_profile_add(struct rte_sched_subport_params *p)
+{
+	/* Check input params */
+	if (p == NULL)
+		return -1;
+
+	/* Save profile */
+	memcpy(&subport_profile[n_subport_profiles],
+		p,
+		sizeof(*p));
+
+	n_subport_profiles++;
+
+	return 0;
+}
+
+int
+tmgr_pipe_profile_add(struct rte_sched_pipe_params *p)
+{
+	/* Check input params */
+	if (p == NULL)
+		return -1;
+
+	/* Save profile */
+	memcpy(&pipe_profile[n_pipe_profiles],
+		p,
+		sizeof(*p));
+
+	n_pipe_profiles++;
+
+	return 0;
+}
+
+struct tmgr_port *
+tmgr_port_create(const char *name, struct tmgr_port_params *params)
+{
+	struct rte_sched_port_params p;
+	struct tmgr_port *tmgr_port;
+	struct rte_sched_port *s;
+	uint32_t i, j;
+
+	/* Check input params */
+	if ((name == NULL) ||
+		tmgr_port_find(name) ||
+		(params == NULL) ||
+		(params->n_subports_per_port == 0) ||
+		(params->n_pipes_per_subport == 0) ||
+		(params->cpu_id >= RTE_MAX_NUMA_NODES) ||
+		(n_subport_profiles == 0) ||
+		(n_pipe_profiles == 0))
+		return NULL;
+
+	/* Resource create */
+	p.name = name;
+	p.socket = (int) params->cpu_id;
+	p.rate = params->rate;
+	p.mtu = params->mtu;
+	p.frame_overhead = params->frame_overhead;
+	p.n_subports_per_port = params->n_subports_per_port;
+	p.n_pipes_per_subport = params->n_pipes_per_subport;
+
+	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
+		p.qsize[i] = params->qsize[i];
+
+	p.pipe_profiles = pipe_profile;
+	p.n_pipe_profiles = n_pipe_profiles;
+
+	s = rte_sched_port_config(&p);
+	if (s == NULL)
+		return NULL;
+
+	for (i = 0; i < params->n_subports_per_port; i++) {
+		int status;
+
+		status = rte_sched_subport_config(
+			s,
+			i,
+			&subport_profile[0]);
+
+		if (status) {
+			rte_sched_port_free(s);
+			return NULL;
+		}
+
+		for (j = 0; j < params->n_pipes_per_subport; j++) {
+			status = rte_sched_pipe_config(
+				s,
+				i,
+				j,
+				0);
+
+			if (status) {
+				rte_sched_port_free(s);
+				return NULL;
+			}
+		}
+	}
+
+	/* Node allocation */
+	tmgr_port = calloc(1, sizeof(struct tmgr_port));
+	if (tmgr_port == NULL) {
+		rte_sched_port_free(s);
+		return NULL;
+	}
+
+	/* Node fill in */
+	strncpy(tmgr_port->name, name, sizeof(tmgr_port->name));
+	tmgr_port->s = s;
+	tmgr_port->n_subports_per_port = params->n_subports_per_port;
+	tmgr_port->n_pipes_per_subport = params->n_pipes_per_subport;
+
+	/* Node add to list */
+	TAILQ_INSERT_TAIL(&tmgr_port_list, tmgr_port, node);
+
+	return tmgr_port;
+}
+
+int
+tmgr_subport_config(const char *port_name,
+	uint32_t subport_id,
+	uint32_t subport_profile_id)
+{
+	struct tmgr_port *port;
+	int status;
+
+	/* Check input params */
+	if (port_name == NULL)
+		return -1;
+
+	port = tmgr_port_find(port_name);
+	if ((port == NULL) ||
+		(subport_id >= port->n_subports_per_port) ||
+		(subport_profile_id >= n_subport_profiles))
+		return -1;
+
+	/* Resource config */
+	status = rte_sched_subport_config(
+		port->s,
+		subport_id,
+		&subport_profile[subport_profile_id]);
+
+	return status;
+}
+
+int
+tmgr_pipe_config(const char *port_name,
+	uint32_t subport_id,
+	uint32_t pipe_id_first,
+	uint32_t pipe_id_last,
+	uint32_t pipe_profile_id)
+{
+	struct tmgr_port *port;
+	uint32_t i;
+
+	/* Check input params */
+	if (port_name == NULL)
+		return -1;
+
+	port = tmgr_port_find(port_name);
+	if ((port == NULL) ||
+		(subport_id >= port->n_subports_per_port) ||
+		(pipe_id_first >= port->n_pipes_per_subport) ||
+		(pipe_id_last >= port->n_pipes_per_subport) ||
+		(pipe_id_first > pipe_id_last) ||
+		(pipe_profile_id >= n_pipe_profiles))
+		return -1;
+
+	/* Resource config */
+	for (i = pipe_id_first; i <= pipe_id_last; i++) {
+		int status;
+
+		status = rte_sched_pipe_config(
+			port->s,
+			subport_id,
+			i,
+			(int) pipe_profile_id);
+
+		if (status)
+			return status;
+	}
+
+	return 0;
+}
diff --git a/examples/ip_pipeline/tmgr.h b/examples/ip_pipeline/tmgr.h
new file mode 100644
index 0000000..0b497e7
--- /dev/null
+++ b/examples/ip_pipeline/tmgr.h
@@ -0,0 +1,70 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#ifndef _INCLUDE_TMGR_H_
+#define _INCLUDE_TMGR_H_
+
+#include <stdint.h>
+#include <sys/queue.h>
+
+#include <rte_sched.h>
+
+#include "common.h"
+
+#ifndef TMGR_SUBPORT_PROFILE_MAX
+#define TMGR_SUBPORT_PROFILE_MAX                           256
+#endif
+
+#ifndef TMGR_PIPE_PROFILE_MAX
+#define TMGR_PIPE_PROFILE_MAX                              256
+#endif
+
+struct tmgr_port {
+	TAILQ_ENTRY(tmgr_port) node;
+	char name[NAME_SIZE];
+	struct rte_sched_port *s;
+	uint32_t n_subports_per_port;
+	uint32_t n_pipes_per_subport;
+};
+
+TAILQ_HEAD(tmgr_port_list, tmgr_port);
+
+int
+tmgr_init(void);
+
+struct tmgr_port *
+tmgr_port_find(const char *name);
+
+struct tmgr_port_params {
+	uint32_t rate;
+	uint32_t n_subports_per_port;
+	uint32_t n_pipes_per_subport;
+	uint16_t qsize[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
+	uint32_t frame_overhead;
+	uint32_t mtu;
+	uint32_t cpu_id;
+};
+
+int
+tmgr_subport_profile_add(struct rte_sched_subport_params *p);
+
+int
+tmgr_pipe_profile_add(struct rte_sched_pipe_params *p);
+
+struct tmgr_port *
+tmgr_port_create(const char *name, struct tmgr_port_params *params);
+
+int
+tmgr_subport_config(const char *port_name,
+	uint32_t subport_id,
+	uint32_t subport_profile_id);
+
+int
+tmgr_pipe_config(const char *port_name,
+	uint32_t subport_id,
+	uint32_t pipe_id_first,
+	uint32_t pipe_id_last,
+	uint32_t pipe_profile_id);
+
+#endif /* _INCLUDE_TMGR_H_ */
-- 
2.9.3

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

* [dpdk-dev] [PATCH v2 23/44] ip_pipeline: add tap object
  2018-03-12 17:25   ` [dpdk-dev] [PATCH v2 00/44] ip_pipeline: refactoring Jasvinder Singh
                       ` (21 preceding siblings ...)
  2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 22/44] ip_pipeline: add traffic manager object Jasvinder Singh
@ 2018-03-12 17:25     ` Jasvinder Singh
  2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 24/44] ip_pipeline: add kni object Jasvinder Singh
                       ` (20 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-12 17:25 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Kevin Laatz

Add tap object implementation to the application

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
---
 examples/ip_pipeline/Makefile    |  1 +
 examples/ip_pipeline/cli.c       | 32 +++++++++++++
 examples/ip_pipeline/main.c      |  8 ++++
 examples/ip_pipeline/meson.build |  1 +
 examples/ip_pipeline/tap.c       | 97 ++++++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/tap.h       | 29 ++++++++++++
 6 files changed, 168 insertions(+)
 create mode 100644 examples/ip_pipeline/tap.c
 create mode 100644 examples/ip_pipeline/tap.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index 35e4302..0f6bb78 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -12,6 +12,7 @@ SRCS-y += main.c
 SRCS-y += mempool.c
 SRCS-y += parser.c
 SRCS-y += swq.c
+SRCS-y += tap.c
 SRCS-y += tmgr.c
 #SRCS-y += thread.c
 
diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index c6111e7..b6c5269 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -14,6 +14,7 @@
 #include "mempool.h"
 #include "parser.h"
 #include "swq.h"
+#include "tap.h"
 #include "tmgr.h"
 
 #ifndef CMD_MAX_TOKENS
@@ -603,6 +604,32 @@ cmd_tmgr_subport_pipe(char **tokens,
 	}
 }
 
+/**
+ * tap <tap_name>
+ */
+static void
+cmd_tap(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	char *name;
+	struct tap *tap;
+
+	if (n_tokens != 2) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	name = tokens[1];
+
+	tap = tap_create(name);
+	if (tap == NULL) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
 void
 cli_process(char *in, char *out, size_t out_size)
 {
@@ -671,6 +698,11 @@ cli_process(char *in, char *out, size_t out_size)
 		return;
 	}
 
+	if (strcmp(tokens[0], "tap") == 0) {
+		cmd_tap(tokens, n_tokens, out, out_size);
+		return;
+	}
+
 	snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
 }
 
diff --git a/examples/ip_pipeline/main.c b/examples/ip_pipeline/main.c
index 490991f..33c3354 100644
--- a/examples/ip_pipeline/main.c
+++ b/examples/ip_pipeline/main.c
@@ -15,6 +15,7 @@
 #include "link.h"
 #include "mempool.h"
 #include "swq.h"
+#include "tap.h"
 #include "tmgr.h"
 
 static const char usage[] =
@@ -191,6 +192,13 @@ main(int argc, char **argv)
 		return status;
 	}
 
+	/* TAP */
+	status = tap_init();
+	if (status) {
+		printf("Error: TAP initialization failed (%d)\n", status);
+		return status;
+	}
+
 	/* Script */
 	if (app.script_name)
 		cli_script_process(app.script_name,
diff --git a/examples/ip_pipeline/meson.build b/examples/ip_pipeline/meson.build
index cb2154c..e875811 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -15,5 +15,6 @@ sources = files(
 	'mempool.c',
 	'parser.c',
 	'swq.c',
+	'tap.c',
 	'tmgr.c'
 )
diff --git a/examples/ip_pipeline/tap.c b/examples/ip_pipeline/tap.c
new file mode 100644
index 0000000..5b34032
--- /dev/null
+++ b/examples/ip_pipeline/tap.c
@@ -0,0 +1,97 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#include <netinet/in.h>
+#ifdef RTE_EXEC_ENV_LINUXAPP
+#include <linux/if.h>
+#include <linux/if_tun.h>
+#endif
+#include <sys/ioctl.h>
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "tap.h"
+
+#define TAP_DEV                                            "/dev/net/tun"
+
+static struct tap_list tap_list;
+
+int
+tap_init(void)
+{
+	TAILQ_INIT(&tap_list);
+
+	return 0;
+}
+
+struct tap *
+tap_find(const char *name)
+{
+	struct tap *tap;
+
+	if (name == NULL)
+		return NULL;
+
+	TAILQ_FOREACH(tap, &tap_list, node)
+		if (strcmp(tap->name, name) == 0)
+			return tap;
+
+	return NULL;
+}
+
+#ifndef RTE_EXEC_ENV_LINUXAPP
+
+struct tap *
+tap_create(const char *name __rte_unused)
+{
+	return NULL;
+}
+
+#else
+
+struct tap *
+tap_create(const char *name)
+{
+	struct tap *tap;
+	struct ifreq ifr;
+	int fd, status;
+
+	/* Check input params */
+	if ((name == NULL) ||
+		tap_find(name))
+		return NULL;
+
+	/* Resource create */
+	fd = open(TAP_DEV, O_RDWR | O_NONBLOCK);
+	if (fd < 0)
+		return NULL;
+
+	memset(&ifr, 0, sizeof(ifr));
+	ifr.ifr_flags = IFF_TAP | IFF_NO_PI; /* No packet information */
+	snprintf(ifr.ifr_name, IFNAMSIZ, "%s", name);
+
+	status = ioctl(fd, TUNSETIFF, (void *) &ifr);
+	if (status < 0)
+		return NULL;
+
+	/* Node allocation */
+	tap = calloc(1, sizeof(struct tap));
+	if (tap == NULL)
+		return NULL;
+
+	/* Node fill in */
+	strncpy(tap->name, name, sizeof(tap->name));
+	tap->fd = fd;
+
+	/* Node add to list */
+	TAILQ_INSERT_TAIL(&tap_list, tap, node);
+
+	return tap;
+}
+
+#endif
diff --git a/examples/ip_pipeline/tap.h b/examples/ip_pipeline/tap.h
new file mode 100644
index 0000000..0dce72f
--- /dev/null
+++ b/examples/ip_pipeline/tap.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#ifndef _INCLUDE_TAP_H_
+#define _INCLUDE_TAP_H_
+
+#include <sys/queue.h>
+
+#include "common.h"
+
+struct tap {
+	TAILQ_ENTRY(tap) node;
+	char name[NAME_SIZE];
+	int fd;
+};
+
+TAILQ_HEAD(tap_list, tap);
+
+int
+tap_init(void);
+
+struct tap *
+tap_find(const char *name);
+
+struct tap *
+tap_create(const char *name);
+
+#endif /* _INCLUDE_TAP_H_ */
-- 
2.9.3

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

* [dpdk-dev] [PATCH v2 24/44] ip_pipeline: add kni object
  2018-03-12 17:25   ` [dpdk-dev] [PATCH v2 00/44] ip_pipeline: refactoring Jasvinder Singh
                       ` (22 preceding siblings ...)
  2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 23/44] ip_pipeline: add tap object Jasvinder Singh
@ 2018-03-12 17:25     ` Jasvinder Singh
  2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 25/44] ip_pipeline: add action profile object Jasvinder Singh
                       ` (19 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-12 17:25 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Kevin Laatz

Add kni object implementation to the application.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
---
 examples/ip_pipeline/Makefile    |   1 +
 examples/ip_pipeline/cli.c       |  65 +++++++++++++++
 examples/ip_pipeline/kni.c       | 167 +++++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/kni.h       |  44 +++++++++++
 examples/ip_pipeline/main.c      |  10 +++
 examples/ip_pipeline/meson.build |   1 +
 6 files changed, 288 insertions(+)
 create mode 100644 examples/ip_pipeline/kni.c
 create mode 100644 examples/ip_pipeline/kni.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index 0f6bb78..dc56ebf 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -7,6 +7,7 @@ APP = ip_pipeline
 # all source are stored in SRCS-y
 SRCS-y := cli.c
 SRCS-y += conn.c
+SRCS-y += kni.c
 SRCS-y += link.c
 SRCS-y += main.c
 SRCS-y += mempool.c
diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index b6c5269..de9c5dd 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -10,6 +10,7 @@
 #include <rte_common.h>
 
 #include "cli.h"
+#include "kni.h"
 #include "link.h"
 #include "mempool.h"
 #include "parser.h"
@@ -630,6 +631,65 @@ cmd_tap(char **tokens,
 	}
 }
 
+/**
+ * kni <kni_name>
+ *  link <link_name>
+ *  mempool <mempool_name>
+ *  [thread <thread_id>]
+ */
+static void
+cmd_kni(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct kni_params p;
+	char *name;
+	struct kni *kni;
+
+	if ((n_tokens != 6) && (n_tokens != 8)) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	name = tokens[1];
+
+	if (strcmp(tokens[2], "link") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "link");
+		return;
+	}
+
+	p.link_name = tokens[3];
+
+	if (strcmp(tokens[4], "mempool") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mempool");
+		return;
+	}
+
+	p.mempool_name = tokens[5];
+
+	if (n_tokens == 8) {
+		if (strcmp(tokens[6], "thread") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "thread");
+			return;
+		}
+
+		if (parser_read_uint32(&p.thread_id, tokens[7]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
+			return;
+		}
+
+		p.force_bind = 1;
+	} else
+		p.force_bind = 0;
+
+	kni = kni_create(name, &p);
+	if (kni == NULL) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
 void
 cli_process(char *in, char *out, size_t out_size)
 {
@@ -703,6 +763,11 @@ cli_process(char *in, char *out, size_t out_size)
 		return;
 	}
 
+	if (strcmp(tokens[0], "kni") == 0) {
+		cmd_kni(tokens, n_tokens, out, out_size);
+		return;
+	}
+
 	snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
 }
 
diff --git a/examples/ip_pipeline/kni.c b/examples/ip_pipeline/kni.c
new file mode 100644
index 0000000..c8a9fbe
--- /dev/null
+++ b/examples/ip_pipeline/kni.c
@@ -0,0 +1,167 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <rte_ethdev.h>
+#include <rte_bus_pci.h>
+
+#include "kni.h"
+#include "mempool.h"
+#include "link.h"
+
+static struct kni_list kni_list;
+
+#ifndef KNI_MAX
+#define KNI_MAX                                            16
+#endif
+
+int
+kni_init(void)
+{
+	TAILQ_INIT(&kni_list);
+
+#ifdef RTE_LIBRTE_KNI
+	rte_kni_init(KNI_MAX);
+#endif
+
+	return 0;
+}
+
+struct kni *
+kni_find(const char *name)
+{
+	struct kni *kni;
+
+	if (name == NULL)
+		return NULL;
+
+	TAILQ_FOREACH(kni, &kni_list, node)
+		if (strcmp(kni->name, name) == 0)
+			return kni;
+
+	return NULL;
+}
+
+#ifndef RTE_LIBRTE_KNI
+
+struct kni *
+kni_create(const char *name __rte_unused,
+	struct kni_params *params __rte_unused)
+{
+	return NULL;
+}
+
+void
+kni_handle_request(void)
+{
+	return 0;
+}
+
+#else
+
+static int
+kni_config_network_interface(uint16_t port_id, uint8_t if_up)
+{
+	int ret = 0;
+
+	if (port_id >= rte_eth_dev_count())
+		return -EINVAL;
+
+	ret = (if_up) ?
+		rte_eth_dev_set_link_up(port_id) :
+		rte_eth_dev_set_link_down(port_id);
+
+	return ret;
+}
+
+static int
+kni_change_mtu(uint16_t port_id, unsigned int new_mtu)
+{
+	int ret;
+
+	if (port_id >= rte_eth_dev_count())
+		return -EINVAL;
+
+	if (new_mtu > ETHER_MAX_LEN)
+		return -EINVAL;
+
+	/* Set new MTU */
+	ret = rte_eth_dev_set_mtu(port_id, new_mtu);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+struct kni *
+kni_create(const char *name, struct kni_params *params)
+{
+	struct rte_eth_dev_info dev_info;
+	struct rte_kni_conf kni_conf;
+	struct rte_kni_ops kni_ops;
+	struct kni *kni;
+	struct mempool *mempool;
+	struct link *link;
+	struct rte_kni *k;
+
+	/* Check input params */
+	if ((name == NULL) ||
+		kni_find(name) ||
+		(params == NULL))
+		return NULL;
+
+	mempool = mempool_find(params->mempool_name);
+	link = link_find(params->link_name);
+	if ((mempool == NULL) ||
+		(link == NULL))
+		return NULL;
+
+	/* Resource create */
+	rte_eth_dev_info_get(link->port_id, &dev_info);
+
+	memset(&kni_conf, 0, sizeof(kni_conf));
+	snprintf(kni_conf.name, RTE_KNI_NAMESIZE, "%s", name);
+	kni_conf.force_bind = params->force_bind;
+	kni_conf.core_id = params->thread_id;
+	kni_conf.group_id = link->port_id;
+	kni_conf.mbuf_size = mempool->buffer_size;
+	kni_conf.addr = dev_info.pci_dev->addr;
+	kni_conf.id = dev_info.pci_dev->id;
+
+	memset(&kni_ops, 0, sizeof(kni_ops));
+	kni_ops.port_id = link->port_id;
+	kni_ops.config_network_if = kni_config_network_interface;
+	kni_ops.change_mtu = kni_change_mtu;
+
+	k = rte_kni_alloc(mempool->m, &kni_conf, &kni_ops);
+	if (k == NULL)
+		return NULL;
+
+	/* Node allocation */
+	kni = calloc(1, sizeof(struct kni));
+	if (kni == NULL)
+		return NULL;
+
+	/* Node fill in */
+	strncpy(kni->name, name, sizeof(kni->name));
+	kni->k = k;
+
+	/* Node add to list */
+	TAILQ_INSERT_TAIL(&kni_list, kni, node);
+
+	return kni;
+}
+
+void
+kni_handle_request(void)
+{
+	struct kni *kni;
+
+	TAILQ_FOREACH(kni, &kni_list, node)
+		rte_kni_handle_request(kni->k);
+}
+
+#endif
diff --git a/examples/ip_pipeline/kni.h b/examples/ip_pipeline/kni.h
new file mode 100644
index 0000000..e53de12
--- /dev/null
+++ b/examples/ip_pipeline/kni.h
@@ -0,0 +1,44 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#ifndef _INCLUDE_KNI_H_
+#define _INCLUDE_KNI_H_
+
+#include <stdint.h>
+#include <sys/queue.h>
+
+#ifdef RTE_LIBRTE_KNI
+#include <rte_kni.h>
+#endif
+
+#include "common.h"
+
+struct kni {
+	TAILQ_ENTRY(kni) node;
+	char name[NAME_SIZE];
+	struct rte_kni *k;
+};
+
+TAILQ_HEAD(kni_list, kni);
+
+int
+kni_init(void);
+
+struct kni *
+kni_find(const char *name);
+
+struct kni_params {
+	const char *link_name;
+	const char *mempool_name;
+	int force_bind;
+	uint32_t thread_id;
+};
+
+struct kni *
+kni_create(const char *name, struct kni_params *params);
+
+void
+kni_handle_request(void);
+
+#endif /* _INCLUDE_KNI_H_ */
diff --git a/examples/ip_pipeline/main.c b/examples/ip_pipeline/main.c
index 33c3354..b65762e 100644
--- a/examples/ip_pipeline/main.c
+++ b/examples/ip_pipeline/main.c
@@ -12,6 +12,7 @@
 
 #include "cli.h"
 #include "conn.h"
+#include "kni.h"
 #include "link.h"
 #include "mempool.h"
 #include "swq.h"
@@ -199,6 +200,13 @@ main(int argc, char **argv)
 		return status;
 	}
 
+	/* KNI */
+	status = kni_init();
+	if (status) {
+		printf("Error: KNI initialization failed (%d)\n", status);
+		return status;
+	}
+
 	/* Script */
 	if (app.script_name)
 		cli_script_process(app.script_name,
@@ -210,5 +218,7 @@ main(int argc, char **argv)
 		conn_poll_for_conn(conn);
 
 		conn_poll_for_msg(conn);
+
+		kni_handle_request();
 	}
 }
diff --git a/examples/ip_pipeline/meson.build b/examples/ip_pipeline/meson.build
index e875811..5ad79b2 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -10,6 +10,7 @@ deps += ['pipeline', 'bus_pci']
 sources = files(
 	'cli.c',
 	'conn.c',
+	'kni.c',
 	'link.c',
 	'main.c',
 	'mempool.c',
-- 
2.9.3

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

* [dpdk-dev] [PATCH v2 25/44] ip_pipeline: add action profile object
  2018-03-12 17:25   ` [dpdk-dev] [PATCH v2 00/44] ip_pipeline: refactoring Jasvinder Singh
                       ` (23 preceding siblings ...)
  2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 24/44] ip_pipeline: add kni object Jasvinder Singh
@ 2018-03-12 17:25     ` Jasvinder Singh
  2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 26/44] ip_pipeline: add pipeline object Jasvinder Singh
                       ` (18 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-12 17:25 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Fan Zhang

Add action profile object implementation to the application.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Fan Zhang <roy.fan.zhang@intel.com>
---
 examples/ip_pipeline/Makefile    |   4 +-
 examples/ip_pipeline/action.c    | 165 +++++++++++++++++++++
 examples/ip_pipeline/action.h    |  44 ++++++
 examples/ip_pipeline/cli.c       | 309 +++++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/cli.h       |   2 +
 examples/ip_pipeline/main.c      |   8 +
 examples/ip_pipeline/meson.build |   2 +
 7 files changed, 533 insertions(+), 1 deletion(-)
 create mode 100644 examples/ip_pipeline/action.c
 create mode 100644 examples/ip_pipeline/action.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index dc56ebf..d9c8d86 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -5,7 +5,8 @@
 APP = ip_pipeline
 
 # all source are stored in SRCS-y
-SRCS-y := cli.c
+SRCS-y := action.c
+SRCS-y += cli.c
 SRCS-y += conn.c
 SRCS-y += kni.c
 SRCS-y += link.c
@@ -69,6 +70,7 @@ INC += $(sort $(wildcard *.h))
 
 SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) := $(SRCS-y)
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -I$(SRCDIR)
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
diff --git a/examples/ip_pipeline/action.c b/examples/ip_pipeline/action.c
new file mode 100644
index 0000000..73220c9
--- /dev/null
+++ b/examples/ip_pipeline/action.c
@@ -0,0 +1,165 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "action.h"
+
+static struct table_action_profile_list table_action_profile_list;
+
+int
+table_action_profile_init(void)
+{
+	TAILQ_INIT(&table_action_profile_list);
+
+	return 0;
+}
+
+struct table_action_profile *
+table_action_profile_find(const char *name)
+{
+	struct table_action_profile *profile;
+
+	if (name == NULL)
+		return NULL;
+
+	TAILQ_FOREACH(profile, &table_action_profile_list, node)
+		if (strcmp(profile->name, name) == 0)
+			return profile;
+
+	return NULL;
+}
+
+struct table_action_profile *
+table_action_profile_create(const char *name,
+	struct table_action_profile_params *params)
+{
+	struct table_action_profile *profile;
+	struct rte_table_action_profile *ap;
+	int status;
+
+	/* Check input params */
+	if ((name == NULL) ||
+		table_action_profile_find(name) ||
+		(params == NULL) ||
+		((params->action_mask & (1LLU << RTE_TABLE_ACTION_FWD)) == 0))
+		return NULL;
+
+	/* Resource */
+	ap = rte_table_action_profile_create(&params->common);
+	if(ap == NULL)
+		return NULL;
+
+	if (params->action_mask & (1LLU << RTE_TABLE_ACTION_FWD)) {
+		status = rte_table_action_profile_action_register(ap,
+			RTE_TABLE_ACTION_FWD,
+			NULL);
+
+		if (status) {
+			rte_table_action_profile_free(ap);
+			return NULL;
+		}
+	}
+
+	if (params->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) {
+		status = rte_table_action_profile_action_register(ap,
+			RTE_TABLE_ACTION_MTR,
+			&params->mtr);
+
+		if (status) {
+			rte_table_action_profile_free(ap);
+			return NULL;
+		}
+	}
+
+	if (params->action_mask & (1LLU << RTE_TABLE_ACTION_TM)) {
+		status = rte_table_action_profile_action_register(ap,
+			RTE_TABLE_ACTION_TM,
+			&params->tm);
+
+		if (status) {
+			rte_table_action_profile_free(ap);
+			return NULL;
+		}
+	}
+
+	if (params->action_mask & (1LLU << RTE_TABLE_ACTION_ENCAP)) {
+		status = rte_table_action_profile_action_register(ap,
+			RTE_TABLE_ACTION_ENCAP,
+			&params->encap);
+
+		if (status) {
+			rte_table_action_profile_free(ap);
+			return NULL;
+		}
+	}
+
+	if (params->action_mask & (1LLU << RTE_TABLE_ACTION_NAT)) {
+		status = rte_table_action_profile_action_register(ap,
+			RTE_TABLE_ACTION_NAT,
+			&params->nat);
+
+		if (status) {
+			rte_table_action_profile_free(ap);
+			return NULL;
+		}
+	}
+
+	if (params->action_mask & (1LLU << RTE_TABLE_ACTION_TTL)) {
+		status = rte_table_action_profile_action_register(ap,
+			RTE_TABLE_ACTION_TTL,
+			&params->ttl);
+
+		if (status) {
+			rte_table_action_profile_free(ap);
+			return NULL;
+		}
+	}
+
+	if (params->action_mask & (1LLU << RTE_TABLE_ACTION_STATS)) {
+		status = rte_table_action_profile_action_register(ap,
+			RTE_TABLE_ACTION_STATS,
+			&params->stats);
+
+		if (status) {
+			rte_table_action_profile_free(ap);
+			return NULL;
+		}
+	}
+	if (params->action_mask & (1LLU << RTE_TABLE_ACTION_TIME)) {
+		status = rte_table_action_profile_action_register(ap,
+			RTE_TABLE_ACTION_TIME,
+			NULL);
+
+		if (status) {
+			rte_table_action_profile_free(ap);
+			return NULL;
+		}
+	}
+
+	status = rte_table_action_profile_freeze(ap);
+	if (status) {
+		rte_table_action_profile_free(ap);
+		return NULL;
+	}
+
+	/* Node allocation */
+	profile = calloc(1, sizeof(struct table_action_profile));
+	if (profile == NULL) {
+		rte_table_action_profile_free(ap);
+		return NULL;
+	}
+
+	/* Node fill in */
+	strncpy(profile->name, name, sizeof(profile->name));
+	memcpy(&profile->params, params, sizeof(*params));
+	profile->ap = ap;
+
+	/* Node add to list */
+	TAILQ_INSERT_TAIL(&table_action_profile_list, profile, node);
+
+	return profile;
+}
diff --git a/examples/ip_pipeline/action.h b/examples/ip_pipeline/action.h
new file mode 100644
index 0000000..5720b3e
--- /dev/null
+++ b/examples/ip_pipeline/action.h
@@ -0,0 +1,44 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#ifndef _INCLUDE_ACTION_H_
+#define _INCLUDE_ACTION_H_
+
+#include <sys/queue.h>
+
+#include <rte_table_action.h>
+
+#include "common.h"
+
+struct table_action_profile_params {
+	uint64_t action_mask;
+	struct rte_table_action_common_config common;
+	struct rte_table_action_mtr_config mtr;
+	struct rte_table_action_tm_config tm;
+	struct rte_table_action_encap_config encap;
+	struct rte_table_action_nat_config nat;
+	struct rte_table_action_ttl_config ttl;
+	struct rte_table_action_stats_config stats;
+};
+
+struct table_action_profile {
+	TAILQ_ENTRY(table_action_profile) node;
+	char name[NAME_SIZE];
+	struct table_action_profile_params params;
+	struct rte_table_action_profile *ap;
+};
+
+TAILQ_HEAD(table_action_profile_list, table_action_profile);
+
+int
+table_action_profile_init(void);
+
+struct table_action_profile *
+table_action_profile_find(const char *name);
+
+struct table_action_profile *
+table_action_profile_create(const char *name,
+	struct table_action_profile_params *params);
+
+#endif /* _INCLUDE_ACTION_H_ */
diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index de9c5dd..ff3a996 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -690,6 +690,310 @@ cmd_kni(char **tokens,
 	}
 }
 
+/**
+ * table action profile <profile_name>
+ *  ipv4 | ipv6
+ *  offset <ip_offset>
+ *      fwd
+ *  [meter srtcm | trtcm
+ *      tc <n_tc>
+ *      stats none | pkts | bytes | both]
+ *      [tm spp <n_subports_per_port> pps <n_pipes_per_subport>]
+ *  [encap ether | vlan | qinq | mpls | pppoe | esp | gre | gtpu]
+ *  [nat src | dst
+ *      proto udp | tcp]
+ *  [ttl drop | fwd
+ *              stats none | pkts]
+ *  [stats pkts | bytes | both]
+ *      [time]
+ */
+static void
+cmd_table_action_profile(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct table_action_profile_params p;
+	struct table_action_profile *ap;
+	char *name;
+	uint32_t t0;
+
+	memset(&p, 0, sizeof(p));
+
+	if (n_tokens < 8) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	if (strcmp(tokens[1], "action") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "action");
+		return;
+	}
+
+	if (strcmp(tokens[2], "profile") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
+		return;
+	}
+
+	name = tokens[3];
+
+	if (strcmp(tokens[4], "ipv4") == 0)
+		p.common.ip_version = 1;
+	else if (strcmp(tokens[4], "ipv6") == 0)
+		p.common.ip_version = 0;
+	else {
+		snprintf(out, out_size, MSG_ARG_INVALID, "ipv4 or ipv6");
+		return;
+	}
+
+	if (strcmp(tokens[5], "offset") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
+		return;
+	}
+
+	if (parser_read_uint32(&p.common.ip_offset, tokens[6]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "ip_offset");
+		return;
+	}
+
+	if (strcmp(tokens[7], "fwd") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "fwd");
+		return;
+	}
+
+	p.action_mask |= 1LLU << RTE_TABLE_ACTION_FWD;
+
+	t0 = 8;
+	if ((t0 < n_tokens) && (strcmp(tokens[t0], "meter") == 0)) {
+		if (n_tokens < t0 + 6) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"table action profile meter");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 1], "srtcm") == 0)
+			p.mtr.alg = RTE_TABLE_ACTION_METER_SRTCM;
+		else if (strcmp(tokens[t0 + 1], "trtcm") == 0)
+			p.mtr.alg = RTE_TABLE_ACTION_METER_TRTCM;
+		else {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+				"srtcm or trtcm");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 2], "tc") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc");
+			return;
+		}
+
+		if (parser_read_uint32(&p.mtr.n_tc, tokens[t0 + 3]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "n_tc");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 4], "stats") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 5], "none") == 0) {
+			p.mtr.n_packets_enabled = 0;
+			p.mtr.n_bytes_enabled = 0;
+		} else if (strcmp(tokens[t0 + 5], "pkts") == 0) {
+			p.mtr.n_packets_enabled = 1;
+			p.mtr.n_bytes_enabled = 0;
+		} else if (strcmp(tokens[t0 + 5], "bytes") == 0) {
+			p.mtr.n_packets_enabled = 0;
+			p.mtr.n_bytes_enabled = 1;
+		} else if (strcmp(tokens[t0 + 5], "both") == 0) {
+			p.mtr.n_packets_enabled = 1;
+			p.mtr.n_bytes_enabled = 1;
+		} else {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+				"none or pkts or bytes or both");
+			return;
+		}
+
+		p.action_mask |= 1LLU << RTE_TABLE_ACTION_MTR;
+		t0 += 6;
+	} /* meter */
+
+	if ((t0 < n_tokens) && (strcmp(tokens[t0], "tm") == 0)) {
+		if (n_tokens < t0 + 5) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"table action profile tm");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 1], "spp") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "spp");
+			return;
+		}
+
+		if (parser_read_uint32(&p.tm.n_subports_per_port,
+			tokens[t0 + 2]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID,
+				"n_subports_per_port");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 3], "pps") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pps");
+			return;
+		}
+
+		if (parser_read_uint32(&p.tm.n_pipes_per_subport,
+			tokens[t0 + 4]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID,
+				"n_pipes_per_subport");
+			return;
+		}
+
+		p.action_mask |= 1LLU << RTE_TABLE_ACTION_TM;
+		t0 += 5;
+	} /* tm */
+
+	if ((t0 < n_tokens) && (strcmp(tokens[t0], "encap") == 0)) {
+		if (n_tokens < t0 + 2) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"action profile encap");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 1], "ether") == 0)
+			p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_ETHER;
+		else if (strcmp(tokens[t0 + 1], "vlan") == 0)
+			p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_VLAN;
+		else if (strcmp(tokens[t0 + 1], "qinq") == 0)
+			p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_QINQ;
+		else if (strcmp(tokens[t0 + 1], "mpls") == 0)
+			p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_MPLS;
+		else if (strcmp(tokens[t0 + 1], "pppoe") == 0)
+			p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_PPPOE;
+		else {
+			snprintf(out, out_size, MSG_ARG_MISMATCH, "encap");
+			return;
+		}
+
+		p.action_mask |= 1LLU << RTE_TABLE_ACTION_ENCAP;
+		t0 += 2;
+	} /* encap */
+
+	if ((t0 < n_tokens) && (strcmp(tokens[t0], "nat") == 0)) {
+		if (n_tokens < t0 + 4) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"table action profile nat");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 1], "src") == 0)
+			p.nat.source_nat = 1;
+		else if (strcmp(tokens[t0 + 1], "dst") == 0)
+			p.nat.source_nat = 0;
+		else {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+				"src or dst");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 2], "proto") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "proto");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 3], "tcp") == 0)
+			p.nat.proto = 0x06;
+		else if (strcmp(tokens[t0 + 3], "udp") == 0)
+			p.nat.proto = 0x11;
+		else {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+				"tcp or udp");
+			return;
+		}
+
+		p.action_mask |= 1LLU << RTE_TABLE_ACTION_NAT;
+		t0 += 4;
+	} /* nat */
+
+	if ((t0 < n_tokens) && (strcmp(tokens[t0], "ttl") == 0)) {
+		if (n_tokens < t0 + 4) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"table action profile ttl");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 1], "drop") == 0)
+			p.ttl.drop = 1;
+		else if (strcmp(tokens[t0 + 1], "fwd") == 0)
+			p.ttl.drop = 0;
+		else {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+				"drop or fwd");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 2], "stats") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 3], "none") == 0)
+			p.ttl.n_packets_enabled = 0;
+		else if (strcmp(tokens[t0 + 3], "pkts") == 0)
+			p.ttl.n_packets_enabled = 1;
+		else {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+				"none or pkts");
+			return;
+		}
+
+		p.action_mask |= 1LLU << RTE_TABLE_ACTION_TTL;
+		t0 += 4;
+	} /* ttl */
+
+	if ((t0 < n_tokens) && (strcmp(tokens[t0], "stats") == 0)) {
+		if (n_tokens < t0 + 2) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"table action profile stats");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 1], "pkts") == 0) {
+			p.stats.n_packets_enabled = 1;
+			p.stats.n_bytes_enabled = 0;
+		} else if (strcmp(tokens[t0 + 1], "bytes") == 0) {
+			p.stats.n_packets_enabled = 0;
+			p.stats.n_bytes_enabled = 1;
+		} else if (strcmp(tokens[t0 + 1], "both") == 0) {
+			p.stats.n_packets_enabled = 1;
+			p.stats.n_bytes_enabled = 1;
+		} else {
+			snprintf(out, out_size,	MSG_ARG_NOT_FOUND,
+				"pkts or bytes or both");
+			return;
+		}
+
+		p.action_mask |= 1LLU << RTE_TABLE_ACTION_STATS;
+		t0 += 2;
+	} /* stats */
+
+	if ((t0 < n_tokens) && (strcmp(tokens[t0], "time") == 0)) {
+		p.action_mask |= 1LLU << RTE_TABLE_ACTION_TIME;
+		t0 += 1;
+	} /* time */
+
+	if (t0 < n_tokens) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	ap = table_action_profile_create(name, &p);
+	if (ap == NULL) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
 void
 cli_process(char *in, char *out, size_t out_size)
 {
@@ -768,6 +1072,11 @@ cli_process(char *in, char *out, size_t out_size)
 		return;
 	}
 
+	if (strcmp(tokens[0], "action") == 0) {
+		cmd_table_action_profile(tokens, n_tokens, out, out_size);
+		return;
+	}
+
 	snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
 }
 
diff --git a/examples/ip_pipeline/cli.h b/examples/ip_pipeline/cli.h
index 992e4c3..02564a6 100644
--- a/examples/ip_pipeline/cli.h
+++ b/examples/ip_pipeline/cli.h
@@ -7,6 +7,8 @@
 
 #include <stddef.h>
 
+#include "action.h"
+
 void
 cli_process(char *in, char *out, size_t out_size);
 
diff --git a/examples/ip_pipeline/main.c b/examples/ip_pipeline/main.c
index b65762e..24b74cf 100644
--- a/examples/ip_pipeline/main.c
+++ b/examples/ip_pipeline/main.c
@@ -207,6 +207,14 @@ main(int argc, char **argv)
 		return status;
 	}
 
+	/* Action profile */
+	status = table_action_profile_init();
+	if (status) {
+		printf("Error: Action profile initialization failed (%d)\n",
+			status);
+		return status;
+	}
+
 	/* Script */
 	if (app.script_name)
 		cli_script_process(app.script_name,
diff --git a/examples/ip_pipeline/meson.build b/examples/ip_pipeline/meson.build
index 5ad79b2..fb1b61d 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -7,7 +7,9 @@
 # DPDK instance, use 'make'
 
 deps += ['pipeline', 'bus_pci']
+allow_experimental_apis = true
 sources = files(
+	'action.c',
 	'cli.c',
 	'conn.c',
 	'kni.c',
-- 
2.9.3

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

* [dpdk-dev] [PATCH v2 26/44] ip_pipeline: add pipeline object
  2018-03-12 17:25   ` [dpdk-dev] [PATCH v2 00/44] ip_pipeline: refactoring Jasvinder Singh
                       ` (24 preceding siblings ...)
  2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 25/44] ip_pipeline: add action profile object Jasvinder Singh
@ 2018-03-12 17:25     ` Jasvinder Singh
  2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 27/44] ip_pipeline: add threads Jasvinder Singh
                       ` (17 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-12 17:25 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add pipeline object implementation to the application.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/Makefile    |   1 +
 examples/ip_pipeline/cli.c       | 786 +++++++++++++++++++++++++++++++++
 examples/ip_pipeline/cli.h       |   2 -
 examples/ip_pipeline/main.c      |   8 +
 examples/ip_pipeline/meson.build |   1 +
 examples/ip_pipeline/pipeline.c  | 930 +++++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/pipeline.h  | 265 +++++++++++
 7 files changed, 1991 insertions(+), 2 deletions(-)
 create mode 100644 examples/ip_pipeline/pipeline.c
 create mode 100644 examples/ip_pipeline/pipeline.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index d9c8d86..033319d 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -13,6 +13,7 @@ SRCS-y += link.c
 SRCS-y += main.c
 SRCS-y += mempool.c
 SRCS-y += parser.c
+SRCS-y += pipeline.c
 SRCS-y += swq.c
 SRCS-y += tap.c
 SRCS-y += tmgr.c
diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index ff3a996..acf4fe0 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -14,6 +14,7 @@
 #include "link.h"
 #include "mempool.h"
 #include "parser.h"
+#include "pipeline.h"
 #include "swq.h"
 #include "tap.h"
 #include "tmgr.h"
@@ -994,6 +995,751 @@ cmd_table_action_profile(char **tokens,
 	}
 }
 
+/**
+ * pipeline <pipeline_name>
+ *  period <timer_period_ms>
+ *  offset_port_id <offset_port_id>
+ *  cpu <cpu_id>
+ */
+static void
+cmd_pipeline(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct pipeline_params p;
+	char *name;
+	struct pipeline *pipeline;
+
+	if (n_tokens != 8) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	name = tokens[1];
+
+	if (strcmp(tokens[2], "period") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "period");
+		return;
+	}
+
+	if (parser_read_uint32(&p.timer_period_ms, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "timer_period_ms");
+		return;
+	}
+
+	if (strcmp(tokens[4], "offset_port_id") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset_port_id");
+		return;
+	}
+
+	if (parser_read_uint32(&p.offset_port_id, tokens[5]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "offset_port_id");
+		return;
+	}
+
+	if (strcmp(tokens[6], "cpu") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu");
+		return;
+	}
+
+	if (parser_read_uint32(&p.cpu_id, tokens[7]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id");
+		return;
+	}
+
+	pipeline = pipeline_create(name, &p);
+	if (pipeline == NULL) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
+ * pipeline <pipeline_name> port in
+ *  bsz <burst_size>
+ *  link <link_name> rxq <queue_id>
+ *  | swq <swq_name>
+ *  | tmgr <tmgr_name>
+ *  | tap <tap_name> mempool <mempool_name> mtu <mtu>
+ *  | kni <kni_name>
+ *  | source <source_name> mempool <mempool_name> file <file_name>
+ *      [disabled]
+ */
+static void
+cmd_pipeline_port_in(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct port_in_params p;
+	char *pipeline_name;
+	uint32_t t0;
+	int enabled, status;
+
+	if (n_tokens < 7) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "port") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
+		return;
+	}
+
+	if (strcmp(tokens[3], "in") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
+		return;
+	}
+
+	if (strcmp(tokens[4], "bsz") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
+		return;
+	}
+
+	if (parser_read_uint32(&p.burst_size, tokens[5]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "burst_size");
+		return;
+	}
+
+	t0 = 6;
+
+	if (strcmp(tokens[t0], "link") == 0) {
+		if (n_tokens < t0 + 4) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline port in link");
+			return;
+		}
+
+		p.type = PORT_IN_RXQ;
+
+		p.dev_name = tokens[t0 + 1];
+
+		if (strcmp(tokens[t0 + 2], "rxq") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rxq");
+			return;
+		}
+
+		if (parser_read_uint16(&p.rxq.queue_id, tokens[t0 + 3]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID,
+				"queue_id");
+			return;
+		}
+		t0 += 4;
+	} else if (strcmp(tokens[t0], "swq") == 0) {
+		if (n_tokens < t0 + 2) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline port in swq");
+			return;
+		}
+
+		p.type = PORT_IN_SWQ;
+
+		p.dev_name = tokens[t0 + 1];
+
+		t0 += 2;
+	} else if (strcmp(tokens[t0], "tmgr") == 0) {
+		if (n_tokens < t0 + 2) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline port in tmgr");
+			return;
+		}
+
+		p.type = PORT_IN_TMGR;
+
+		p.dev_name = tokens[t0 + 1];
+
+		t0 += 2;
+	} else if (strcmp(tokens[t0], "tap") == 0) {
+		if (n_tokens < t0 + 6) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline port in tap");
+			return;
+		}
+
+		p.type = PORT_IN_TAP;
+
+		p.dev_name = tokens[t0 + 1];
+
+		if (strcmp(tokens[t0 + 2], "mempool") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+				"mempool");
+			return;
+		}
+
+		p.tap.mempool_name = tokens[t0 + 3];
+
+		if (strcmp(tokens[t0 + 4], "mtu") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+				"mtu");
+			return;
+		}
+
+		if (parser_read_uint32(&p.tap.mtu, tokens[t0 + 5]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "mtu");
+			return;
+		}
+
+		t0 += 6;
+	} else if (strcmp(tokens[t0], "kni") == 0) {
+		if (n_tokens < t0 + 2) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline port in kni");
+			return;
+		}
+
+		p.type = PORT_IN_KNI;
+
+		p.dev_name = tokens[t0 + 1];
+
+		t0 += 2;
+	} else if (strcmp(tokens[t0], "source") == 0) {
+		if (n_tokens < t0 + 6) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline port in source");
+			return;
+		}
+
+		p.type = PORT_IN_SOURCE;
+
+		p.dev_name = tokens[t0 + 1];
+
+		if (strcmp(tokens[t0 + 2], "mempool") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+				"mempool");
+			return;
+		}
+
+		p.source.mempool_name = tokens[t0 + 3];
+
+		if (strcmp(tokens[t0 + 4], "file") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+				"file");
+			return;
+		}
+
+		p.source.file_name = tokens[t0 + 5];
+
+		p.source.n_bytes_per_pkt = 0;
+
+		t0 += 6;
+	} else {
+		snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
+		return;
+	}
+
+	enabled = 1;
+	if ((n_tokens > t0) &&
+		(strcmp(tokens[t0], "disabled") == 0)) {
+		enabled = 0;
+
+		t0 += 1;
+	}
+
+	if (n_tokens != t0) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	status = pipeline_port_in_create(pipeline_name,
+		&p, enabled);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
+ * pipeline <pipeline_name> port out
+ *  bsz <burst_size>
+ *  link <link_name> txq <txq_id>
+ *  | swq <swq_name>
+ *  | tmgr <tmgr_name>
+ *  | tap <tap_name>
+ *  | kni <kni_name>
+ *  | sink <sink_name> [file <file_name>]
+ */
+static void
+cmd_pipeline_port_out(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct port_out_params p;
+	char *pipeline_name;
+	int status;
+
+	memset(&p, 0, sizeof(p));
+
+	if (n_tokens < 7) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "port") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
+		return;
+	}
+
+	if (strcmp(tokens[3], "out") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "out");
+		return;
+	}
+
+	if (strcmp(tokens[4], "bsz") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
+		return;
+	}
+
+	if (parser_read_uint32(&p.burst_size, tokens[5]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "burst_size");
+		return;
+	}
+
+	if (strcmp(tokens[6], "link") == 0) {
+		if (n_tokens != 10) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline port out link");
+			return;
+		}
+
+		p.type = PORT_OUT_TXQ;
+
+		p.dev_name = tokens[7];
+
+		if (strcmp(tokens[8], "txq") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "txq");
+			return;
+		}
+
+		if (parser_read_uint16(&p.txq.queue_id, tokens[9]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "queue_id");
+			return;
+		}
+	} else if (strcmp(tokens[6], "swq") == 0) {
+		if (n_tokens != 8) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline port out swq");
+			return;
+		}
+
+		p.type = PORT_OUT_SWQ;
+
+		p.dev_name = tokens[7];
+	} else if (strcmp(tokens[6], "tmgr") == 0) {
+		if (n_tokens != 8) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline port out tmgr");
+			return;
+		}
+
+		p.type = PORT_OUT_TMGR;
+
+		p.dev_name = tokens[7];
+	} else if (strcmp(tokens[6], "tap") == 0) {
+		if (n_tokens != 8) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline port out tap");
+			return;
+		}
+
+		p.type = PORT_OUT_TAP;
+
+		p.dev_name = tokens[7];
+	} else if (strcmp(tokens[6], "kni") == 0) {
+		if (n_tokens != 8) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline port out kni");
+			return;
+		}
+
+		p.type = PORT_OUT_KNI;
+
+		p.dev_name = tokens[7];
+	} else if (strcmp(tokens[6], "sink") == 0) {
+		if ((n_tokens != 8) && (n_tokens != 10)) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline port out sink");
+			return;
+		}
+
+		p.type = PORT_OUT_SINK;
+
+		p.dev_name = tokens[7];
+
+		if (n_tokens == 8)
+			p.sink.file_name = NULL;
+		else {
+			if (strcmp(tokens[8], "file") != 0) {
+				snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+					"file");
+				return;
+			}
+
+			p.sink.file_name = tokens[9];
+		}
+
+		p.sink.max_n_pkts = 0;
+	} else {
+		snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
+		return;
+	}
+
+	status = pipeline_port_out_create(pipeline_name, &p);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
+ * pipeline <pipeline_name> table
+ *      match
+ *      acl
+ *          ipv4 | ipv6
+ *          offset <ip_header_offset>
+ *          size <n_rules>
+ *      | array
+ *          offset <key_offset>
+ *          size <n_keys>
+ *      | hash
+ *          ext | lru
+ *          key <key_size>
+ *          mask <key_mask>
+ *          offset <key_offset>
+ *          buckets <n_buckets>
+ *          size <n_keys>
+ *      | lpm
+ *          ipv4 | ipv6
+ *          offset <ip_header_offset>
+ *          size <n_rules>
+ *      | stub
+ *  action <action_profile_name>
+ */
+static void
+cmd_pipeline_table(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	uint8_t key_mask[TABLE_RULE_MATCH_SIZE_MAX];
+	struct table_params p;
+	char *pipeline_name;
+	uint32_t t0;
+	int status;
+
+	if (n_tokens < 5) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "table") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
+		return;
+	}
+
+	if (strcmp(tokens[3], "match") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match");
+		return;
+	}
+
+	t0 = 4;
+	if (strcmp(tokens[t0], "acl") == 0) {
+		if (n_tokens < t0 + 6) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline table acl");
+			return;
+		}
+
+		p.match_type = TABLE_ACL;
+
+		if (strcmp(tokens[t0 + 1], "ipv4") == 0)
+			p.match.acl.ip_version = 1;
+		else if (strcmp(tokens[t0 + 1], "ipv6") == 0)
+			p.match.acl.ip_version = 0;
+		else {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+				"ipv4 or ipv6");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 2], "offset") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
+			return;
+		}
+
+		if (parser_read_uint32(&p.match.acl.ip_header_offset,
+			tokens[t0 + 3]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID,
+				"ip_header_offset");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 4], "size") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
+			return;
+		}
+
+		if (parser_read_uint32(&p.match.acl.n_rules,
+			tokens[t0 + 5]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "n_rules");
+			return;
+		}
+
+		t0 += 6;
+	} else if (strcmp(tokens[t0], "array") == 0) {
+		if (n_tokens < t0 + 5) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline table array");
+			return;
+		}
+
+		p.match_type = TABLE_ARRAY;
+
+		if (strcmp(tokens[t0 + 1], "offset") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
+			return;
+		}
+
+		if (parser_read_uint32(&p.match.array.key_offset,
+			tokens[t0 + 2]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 3], "size") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
+			return;
+		}
+
+		if (parser_read_uint32(&p.match.array.n_keys,
+			tokens[t0 + 4]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "n_keys");
+			return;
+		}
+
+		t0 += 5;
+	} else if (strcmp(tokens[t0], "hash") == 0) {
+		uint32_t key_mask_size = TABLE_RULE_MATCH_SIZE_MAX;
+
+		if (n_tokens < t0 + 12) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline table hash");
+			return;
+		}
+
+		p.match_type = TABLE_HASH;
+
+		if (strcmp(tokens[t0 + 1], "ext") == 0)
+			p.match.hash.extendable_bucket = 1;
+		else if (strcmp(tokens[t0 + 1], "lru") == 0)
+			p.match.hash.extendable_bucket = 0;
+		else {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+				"ext or lru");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 2], "key") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "key");
+			return;
+		}
+
+		if ((parser_read_uint32(&p.match.hash.key_size,
+			tokens[t0 + 3]) != 0) ||
+			(p.match.hash.key_size == 0) ||
+			(p.match.hash.key_size > TABLE_RULE_MATCH_SIZE_MAX)) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "key_size");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 4], "mask") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask");
+			return;
+		}
+
+		if ((parse_hex_string(tokens[t0 + 5],
+			key_mask, &key_mask_size) != 0) ||
+			(key_mask_size != p.match.hash.key_size)) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "key_mask");
+			return;
+		}
+		p.match.hash.key_mask = key_mask;
+
+		if (strcmp(tokens[t0 + 6], "offset") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
+			return;
+		}
+
+		if (parser_read_uint32(&p.match.hash.key_offset,
+			tokens[t0 + 7]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 8], "buckets") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "buckets");
+			return;
+		}
+
+		if (parser_read_uint32(&p.match.hash.n_buckets,
+			tokens[t0 + 9]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "n_buckets");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 10], "size") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
+			return;
+		}
+
+		if (parser_read_uint32(&p.match.hash.n_keys,
+			tokens[t0 + 11]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "n_keys");
+			return;
+		}
+
+		t0 += 12;
+	} else if (strcmp(tokens[t0], "lpm") == 0) {
+		if (n_tokens < t0 + 6) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline table lpm");
+			return;
+		}
+
+		p.match_type = TABLE_LPM;
+
+		if (strcmp(tokens[t0 + 1], "ipv4") == 0)
+			p.match.lpm.key_size = 4;
+		else if (strcmp(tokens[t0 + 1], "ipv6") == 0)
+			p.match.lpm.key_size = 16;
+		else {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+				"ipv4 or ipv6");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 2], "offset") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
+			return;
+		}
+
+		if (parser_read_uint32(&p.match.lpm.key_offset,
+			tokens[t0 + 3]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 4], "size") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
+			return;
+		}
+
+		if (parser_read_uint32(&p.match.lpm.n_rules,
+			tokens[t0 + 5]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "n_rules");
+			return;
+		}
+
+		t0 += 6;
+	} else if (strcmp(tokens[t0], "stub") == 0) {
+		if (n_tokens < t0 + 1) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline table stub");
+			return;
+		}
+
+		p.match_type = TABLE_STUB;
+
+		t0 += 1;
+	} else {
+		snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
+		return;
+	}
+
+	if (n_tokens >= t0 + 2) {
+		if (strcmp(tokens[t0], "action") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "action");
+			return;
+		}
+
+		p.action_profile_name = tokens[t0 + 1];
+
+		t0 += 2;
+	}
+
+	if (n_tokens > t0) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	status = pipeline_table_create(pipeline_name, &p);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
+ * pipeline <pipeline_name> port in <port_id> table <table_id>
+ */
+static void
+cmd_pipeline_port_in_table(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	char *pipeline_name;
+	uint32_t port_id, table_id;
+	int status;
+
+	if (n_tokens != 7) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "port") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
+		return;
+	}
+
+	if (strcmp(tokens[3], "in") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
+		return;
+	}
+
+	if (parser_read_uint32(&port_id, tokens[4]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
+		return;
+	}
+
+	if (strcmp(tokens[5], "table") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
+		return;
+	}
+
+	if (parser_read_uint32(&table_id, tokens[6]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
+		return;
+	}
+
+	status = pipeline_port_in_connect_to_table(pipeline_name,
+		port_id,
+		table_id);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
 void
 cli_process(char *in, char *out, size_t out_size)
 {
@@ -1077,6 +1823,46 @@ cli_process(char *in, char *out, size_t out_size)
 		return;
 	}
 
+	if (strcmp(tokens[0], "pipeline") == 0) {
+		if ((n_tokens >= 3) &&
+			(strcmp(tokens[2], "period") == 0)) {
+			cmd_pipeline(tokens, n_tokens, out, out_size);
+			return;
+		}
+
+		if ((n_tokens >= 5) &&
+			(strcmp(tokens[2], "port") == 0) &&
+			(strcmp(tokens[3], "in") == 0) &&
+			(strcmp(tokens[4], "bsz") == 0)) {
+			cmd_pipeline_port_in(tokens, n_tokens, out, out_size);
+			return;
+		}
+
+		if ((n_tokens >= 5) &&
+			(strcmp(tokens[2], "port") == 0) &&
+			(strcmp(tokens[3], "out") == 0) &&
+			(strcmp(tokens[4], "bsz") == 0)) {
+			cmd_pipeline_port_out(tokens, n_tokens, out, out_size);
+			return;
+		}
+
+		if ((n_tokens >= 4) &&
+			(strcmp(tokens[2], "table") == 0) &&
+			(strcmp(tokens[3], "match") == 0)) {
+			cmd_pipeline_table(tokens, n_tokens, out, out_size);
+			return;
+		}
+
+		if ((n_tokens >= 6) &&
+			(strcmp(tokens[2], "port") == 0) &&
+			(strcmp(tokens[3], "in") == 0) &&
+			(strcmp(tokens[5], "table") == 0)) {
+			cmd_pipeline_port_in_table(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
+	}
+
 	snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
 }
 
diff --git a/examples/ip_pipeline/cli.h b/examples/ip_pipeline/cli.h
index 02564a6..992e4c3 100644
--- a/examples/ip_pipeline/cli.h
+++ b/examples/ip_pipeline/cli.h
@@ -7,8 +7,6 @@
 
 #include <stddef.h>
 
-#include "action.h"
-
 void
 cli_process(char *in, char *out, size_t out_size);
 
diff --git a/examples/ip_pipeline/main.c b/examples/ip_pipeline/main.c
index 24b74cf..a7f4486 100644
--- a/examples/ip_pipeline/main.c
+++ b/examples/ip_pipeline/main.c
@@ -15,6 +15,7 @@
 #include "kni.h"
 #include "link.h"
 #include "mempool.h"
+#include "pipeline.h"
 #include "swq.h"
 #include "tap.h"
 #include "tmgr.h"
@@ -215,6 +216,13 @@ main(int argc, char **argv)
 		return status;
 	}
 
+	/* Pipeline */
+	status = pipeline_init();
+	if (status) {
+		printf("Error: Pipeline initialization failed (%d)\n", status);
+		return status;
+	}
+
 	/* Script */
 	if (app.script_name)
 		cli_script_process(app.script_name,
diff --git a/examples/ip_pipeline/meson.build b/examples/ip_pipeline/meson.build
index fb1b61d..2366242 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -17,6 +17,7 @@ sources = files(
 	'main.c',
 	'mempool.c',
 	'parser.c',
+	'pipeline.c',
 	'swq.c',
 	'tap.c',
 	'tmgr.c'
diff --git a/examples/ip_pipeline/pipeline.c b/examples/ip_pipeline/pipeline.c
new file mode 100644
index 0000000..8efc70d
--- /dev/null
+++ b/examples/ip_pipeline/pipeline.c
@@ -0,0 +1,930 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <rte_common.h>
+#include <rte_ip.h>
+#include <rte_tcp.h>
+
+#include <rte_port_ethdev.h>
+#include <rte_port_kni.h>
+#include <rte_port_ring.h>
+#include <rte_port_source_sink.h>
+#include <rte_port_fd.h>
+#include <rte_port_sched.h>
+
+#include <rte_table_acl.h>
+#include <rte_table_array.h>
+#include <rte_table_hash.h>
+#include <rte_table_lpm.h>
+#include <rte_table_lpm_ipv6.h>
+#include <rte_table_stub.h>
+
+#include "kni.h"
+#include "link.h"
+#include "mempool.h"
+#include "pipeline.h"
+#include "tap.h"
+#include "tmgr.h"
+#include "swq.h"
+
+#include "hash_func.h"
+
+#ifndef PIPELINE_MSGQ_SIZE
+#define PIPELINE_MSGQ_SIZE                                 64
+#endif
+
+#ifndef TABLE_LPM_NUMBER_TBL8
+#define TABLE_LPM_NUMBER_TBL8                              256
+#endif
+
+static struct pipeline_list pipeline_list;
+
+int
+pipeline_init(void)
+{
+	TAILQ_INIT(&pipeline_list);
+
+	return 0;
+}
+
+struct pipeline *
+pipeline_find(const char *name)
+{
+	struct pipeline *pipeline;
+
+	if (name == NULL)
+		return NULL;
+
+	TAILQ_FOREACH(pipeline, &pipeline_list, node)
+		if (strcmp(name, pipeline->name) == 0)
+			return pipeline;
+
+	return NULL;
+}
+
+struct pipeline *
+pipeline_create(const char *name, struct pipeline_params *params)
+{
+	char msgq_name[NAME_MAX];
+	struct rte_pipeline_params pp;
+	struct pipeline *pipeline;
+	struct rte_pipeline *p;
+	struct rte_ring *msgq_req;
+	struct rte_ring *msgq_rsp;
+
+	/* Check input params */
+	if ((name == NULL) ||
+		pipeline_find(name) ||
+		(params == NULL) ||
+		(params->timer_period_ms == 0))
+		return NULL;
+
+	/* Resource create */
+	snprintf(msgq_name, sizeof(msgq_name), "%s-MSGQ-REQ", name);
+
+	msgq_req = rte_ring_create(msgq_name,
+		PIPELINE_MSGQ_SIZE,
+		params->cpu_id,
+		RING_F_SP_ENQ | RING_F_SC_DEQ);
+	if (msgq_req == NULL)
+		return NULL;
+
+	snprintf(msgq_name, sizeof(msgq_name), "%s-MSGQ-RSP", name);
+
+	msgq_rsp = rte_ring_create(msgq_name,
+		PIPELINE_MSGQ_SIZE,
+		params->cpu_id,
+		RING_F_SP_ENQ | RING_F_SC_DEQ);
+	if (msgq_rsp == NULL) {
+		rte_ring_free(msgq_req);
+		return NULL;
+	}
+
+	pp.name = name;
+	pp.socket_id = (int) params->cpu_id;
+	pp.offset_port_id = params->offset_port_id;
+
+	p = rte_pipeline_create(&pp);
+	if (p == NULL) {
+		rte_ring_free(msgq_rsp);
+		rte_ring_free(msgq_req);
+		return NULL;
+	}
+
+	/* Node allocation */
+	pipeline = calloc(1, sizeof(struct pipeline));
+	if (pipeline == NULL) {
+		rte_pipeline_free(p);
+		rte_ring_free(msgq_rsp);
+		rte_ring_free(msgq_req);
+		return NULL;
+	}
+
+	/* Node fill in */
+	strncpy(pipeline->name, name, sizeof(pipeline->name));
+	pipeline->p = p;
+	pipeline->n_ports_in = 0;
+	pipeline->n_ports_out = 0;
+	pipeline->n_tables = 0;
+	pipeline->msgq_req = msgq_req;
+	pipeline->msgq_rsp = msgq_rsp;
+	pipeline->timer_period_ms = params->timer_period_ms;
+	pipeline->enabled = 0;
+	pipeline->cpu_id = params->cpu_id;
+
+	/* Node add to list */
+	TAILQ_INSERT_TAIL(&pipeline_list, pipeline, node);
+
+	return pipeline;
+}
+
+int
+pipeline_port_in_create(const char *pipeline_name,
+	struct port_in_params *params,
+	int enabled)
+{
+	struct rte_pipeline_port_in_params p;
+
+	union {
+		struct rte_port_ethdev_reader_params ethdev;
+		struct rte_port_ring_reader_params ring;
+		struct rte_port_sched_reader_params sched;
+		struct rte_port_fd_reader_params fd;
+		struct rte_port_kni_reader_params kni;
+		struct rte_port_source_params source;
+	} pp;
+
+	struct pipeline *pipeline;
+	uint32_t port_id;
+	int status;
+
+	memset(&pp, 0, sizeof(pp));
+
+	/* Check input params */
+	if ((pipeline_name == NULL) ||
+		(params == NULL) ||
+		(params->burst_size == 0) ||
+		(params->burst_size > RTE_PORT_IN_BURST_SIZE_MAX))
+		return -1;
+
+	pipeline = pipeline_find(pipeline_name);
+	if (pipeline == NULL)
+		return -1;
+
+	switch (params->type) {
+	case PORT_IN_RXQ:
+	{
+		struct link *link;
+
+		link = link_find(params->dev_name);
+		if (link == NULL)
+			return -1;
+
+		if (params->rxq.queue_id >= link->n_rxq)
+			return -1;
+
+		pp.ethdev.port_id = link->port_id;
+		pp.ethdev.queue_id = params->rxq.queue_id;
+
+		p.ops = &rte_port_ethdev_reader_ops;
+		p.arg_create = &pp.ethdev;
+		break;
+	}
+
+	case PORT_IN_SWQ:
+	{
+		struct swq *swq;
+
+		swq = swq_find(params->dev_name);
+		if (swq == NULL)
+			return -1;
+
+		pp.ring.ring = swq->r;
+
+		p.ops = &rte_port_ring_reader_ops;
+		p.arg_create = &pp.ring;
+		break;
+	}
+
+	case PORT_IN_TMGR:
+	{
+		struct tmgr_port *tmgr_port;
+
+		tmgr_port = tmgr_port_find(params->dev_name);
+		if (tmgr_port == NULL)
+			return -1;
+
+		pp.sched.sched = tmgr_port->s;
+
+		p.ops = &rte_port_sched_reader_ops;
+		p.arg_create = &pp.sched;
+		break;
+	}
+
+	case PORT_IN_TAP:
+	{
+		struct tap *tap;
+		struct mempool *mempool;
+
+		tap = tap_find(params->dev_name);
+		mempool = mempool_find(params->tap.mempool_name);
+		if ((tap == NULL) || (mempool == NULL))
+			return -1;
+
+		pp.fd.fd = tap->fd;
+		pp.fd.mempool = mempool->m;
+		pp.fd.mtu = params->tap.mtu;
+
+		p.ops = &rte_port_fd_reader_ops;
+		p.arg_create = &pp.fd;
+		break;
+	}
+
+	case PORT_IN_KNI:
+	{
+		struct kni *kni;
+
+		kni = kni_find(params->dev_name);
+		if (kni == NULL)
+			return -1;
+
+		pp.kni.kni = kni->k;
+
+		p.ops = &rte_port_kni_reader_ops;
+		p.arg_create = &pp.kni;
+		break;
+	}
+
+	case PORT_IN_SOURCE:
+	{
+		struct mempool *mempool;
+
+		mempool = mempool_find(params->source.mempool_name);
+		if (mempool == NULL)
+			return -1;
+
+		pp.source.mempool = mempool->m;
+		pp.source.file_name = params->source.file_name;
+		pp.source.n_bytes_per_pkt = params->source.n_bytes_per_pkt;
+
+		p.ops = &rte_port_source_ops;
+		p.arg_create = &pp.source;
+		break;
+	}
+
+	default:
+		return -1;
+	}
+
+	p.f_action = NULL;
+	p.arg_ah = NULL;
+	p.burst_size = params->burst_size;
+
+	/* Resource create */
+	status = rte_pipeline_port_in_create(pipeline->p,
+		&p,
+		&port_id);
+
+	if (status)
+		return -1;
+
+	if (enabled)
+		rte_pipeline_port_in_enable(pipeline->p, port_id);
+
+	/* Pipeline */
+	pipeline->n_ports_in++;
+
+	return 0;
+}
+
+int
+pipeline_port_in_connect_to_table(const char *pipeline_name,
+	uint32_t port_id,
+	uint32_t table_id)
+{
+	struct pipeline *pipeline;
+	int status;
+
+	/* Check input params */
+	if (pipeline_name == NULL)
+		return -1;
+
+	pipeline = pipeline_find(pipeline_name);
+	if ((pipeline == NULL) ||
+		(port_id >= pipeline->n_ports_in) ||
+		(table_id >= pipeline->n_tables))
+		return -1;
+
+	/* Resource */
+	status = rte_pipeline_port_in_connect_to_table(pipeline->p,
+		port_id,
+		table_id);
+
+	return status;
+
+}
+
+int
+pipeline_port_out_create(const char *pipeline_name,
+	struct port_out_params *params)
+{
+	struct rte_pipeline_port_out_params p;
+
+	union {
+		struct rte_port_ethdev_writer_params ethdev;
+		struct rte_port_ring_writer_params ring;
+		struct rte_port_sched_writer_params sched;
+		struct rte_port_fd_writer_params fd;
+		struct rte_port_kni_writer_params kni;
+		struct rte_port_sink_params sink;
+	} pp;
+
+	union {
+		struct rte_port_ethdev_writer_nodrop_params ethdev;
+		struct rte_port_ring_writer_nodrop_params ring;
+		struct rte_port_fd_writer_nodrop_params fd;
+		struct rte_port_kni_writer_nodrop_params kni;
+	} pp_nodrop;
+
+	struct pipeline *pipeline;
+	uint32_t port_id;
+	int status;
+
+	memset(&pp, 0, sizeof(pp));
+	memset(&pp_nodrop, 0, sizeof(pp_nodrop));
+
+	/* Check input params */
+	if ((pipeline_name == NULL) ||
+		(params == NULL) ||
+		(params->burst_size == 0) ||
+		(params->burst_size > RTE_PORT_IN_BURST_SIZE_MAX))
+		return -1;
+
+	pipeline = pipeline_find(pipeline_name);
+	if (pipeline == NULL)
+		return -1;
+
+	switch (params->type) {
+	case PORT_OUT_TXQ:
+	{
+		struct link *link;
+
+		link = link_find(params->dev_name);
+		if (link == NULL)
+			return -1;
+
+		if (params->txq.queue_id >= link->n_txq)
+			return -1;
+
+		pp.ethdev.port_id = link->port_id;
+		pp.ethdev.queue_id = params->txq.queue_id;
+		pp.ethdev.tx_burst_sz = params->burst_size;
+
+		pp_nodrop.ethdev.port_id = link->port_id;
+		pp_nodrop.ethdev.queue_id = params->txq.queue_id;
+		pp_nodrop.ethdev.tx_burst_sz = params->burst_size;
+		pp_nodrop.ethdev.n_retries = params->n_retries;
+
+		if (params->retry == 0) {
+			p.ops = &rte_port_ethdev_writer_ops;
+			p.arg_create = &pp.ethdev;
+		} else {
+			p.ops = &rte_port_ethdev_writer_nodrop_ops;
+			p.arg_create = &pp_nodrop.ethdev;
+		}
+		break;
+	}
+
+	case PORT_OUT_SWQ:
+	{
+		struct swq *swq;
+
+		swq = swq_find(params->dev_name);
+		if (swq == NULL)
+			return -1;
+
+		pp.ring.ring = swq->r;
+		pp.ring.tx_burst_sz = params->burst_size;
+
+		pp_nodrop.ring.ring = swq->r;
+		pp_nodrop.ring.tx_burst_sz = params->burst_size;
+		pp_nodrop.ring.n_retries = params->n_retries;
+
+		if (params->retry == 0) {
+			p.ops = &rte_port_ring_writer_ops;
+			p.arg_create = &pp.ring;
+		} else {
+			p.ops = &rte_port_ring_writer_nodrop_ops;
+			p.arg_create = &pp_nodrop.ring;
+		}
+		break;
+	}
+
+	case PORT_OUT_TMGR:
+	{
+		struct tmgr_port *tmgr_port;
+
+		tmgr_port = tmgr_port_find(params->dev_name);
+		if (tmgr_port == NULL)
+			return -1;
+
+		pp.sched.sched = tmgr_port->s;
+		pp.sched.tx_burst_sz = params->burst_size;
+
+		p.ops = &rte_port_sched_writer_ops;
+		p.arg_create = &pp.sched;
+		break;
+	}
+
+	case PORT_OUT_TAP:
+	{
+		struct tap *tap;
+
+		tap = tap_find(params->dev_name);
+		if (tap == NULL)
+			return -1;
+
+		pp.fd.fd = tap->fd;
+		pp.fd.tx_burst_sz = params->burst_size;
+
+		pp_nodrop.fd.fd = tap->fd;
+		pp_nodrop.fd.tx_burst_sz = params->burst_size;
+		pp_nodrop.fd.n_retries = params->n_retries;
+
+		if (params->retry == 0) {
+			p.ops = &rte_port_fd_writer_ops;
+			p.arg_create = &pp.fd;
+		} else {
+			p.ops = &rte_port_fd_writer_nodrop_ops;
+			p.arg_create = &pp_nodrop.fd;
+		}
+		break;
+	}
+
+	case PORT_OUT_KNI:
+	{
+		struct kni *kni;
+
+		kni = kni_find(params->dev_name);
+		if (kni == NULL)
+			return -1;
+
+		pp.kni.kni = kni->k;
+		pp.kni.tx_burst_sz = params->burst_size;
+
+		pp_nodrop.kni.kni = kni->k;
+		pp_nodrop.kni.tx_burst_sz = params->burst_size;
+		pp_nodrop.kni.n_retries = params->n_retries;
+
+		if (params->retry == 0) {
+			p.ops = &rte_port_kni_writer_ops;
+			p.arg_create = &pp.kni;
+		} else {
+			p.ops = &rte_port_kni_writer_nodrop_ops;
+			p.arg_create = &pp_nodrop.kni;
+		}
+		break;
+	}
+
+	case PORT_OUT_SINK:
+	{
+		pp.sink.file_name = params->sink.file_name;
+		pp.sink.max_n_pkts = params->sink.max_n_pkts;
+
+		p.ops = &rte_port_sink_ops;
+		p.arg_create = &pp.sink;
+		break;
+	}
+
+	default:
+		return -1;
+	}
+
+	p.f_action = NULL;
+	p.arg_ah = NULL;
+
+	/* Resource create */
+	status = rte_pipeline_port_out_create(pipeline->p,
+		&p,
+		&port_id);
+
+	if (status)
+		return -1;
+
+	/* Pipeline */
+	pipeline->n_ports_out++;
+
+	return 0;
+}
+
+static const struct rte_acl_field_def table_acl_field_format_ipv4[] = {
+	/* Protocol */
+	[0] = {
+		.type = RTE_ACL_FIELD_TYPE_BITMASK,
+		.size = sizeof(uint8_t),
+		.field_index = 0,
+		.input_index = 0,
+		.offset = offsetof(struct ipv4_hdr, next_proto_id),
+	},
+
+	/* Source IP address (IPv4) */
+	[1] = {
+		.type = RTE_ACL_FIELD_TYPE_MASK,
+		.size = sizeof(uint32_t),
+		.field_index = 1,
+		.input_index = 1,
+		.offset = offsetof(struct ipv4_hdr, src_addr),
+	},
+
+	/* Destination IP address (IPv4) */
+	[2] = {
+		.type = RTE_ACL_FIELD_TYPE_MASK,
+		.size = sizeof(uint32_t),
+		.field_index = 2,
+		.input_index = 2,
+		.offset = offsetof(struct ipv4_hdr, dst_addr),
+	},
+
+	/* Source Port */
+	[3] = {
+		.type = RTE_ACL_FIELD_TYPE_RANGE,
+		.size = sizeof(uint16_t),
+		.field_index = 3,
+		.input_index = 3,
+		.offset = sizeof(struct ipv4_hdr) +
+			offsetof(struct tcp_hdr, src_port),
+	},
+
+	/* Destination Port */
+	[4] = {
+		.type = RTE_ACL_FIELD_TYPE_RANGE,
+		.size = sizeof(uint16_t),
+		.field_index = 4,
+		.input_index = 3,
+		.offset = sizeof(struct ipv4_hdr) +
+			offsetof(struct tcp_hdr, dst_port),
+	},
+};
+
+static const struct rte_acl_field_def table_acl_field_format_ipv6[] = {
+	/* Protocol */
+	[0] = {
+		.type = RTE_ACL_FIELD_TYPE_BITMASK,
+		.size = sizeof(uint8_t),
+		.field_index = 0,
+		.input_index = 0,
+		.offset = offsetof(struct ipv6_hdr, proto),
+	},
+
+	/* Source IP address (IPv6) */
+	[1] = {
+		.type = RTE_ACL_FIELD_TYPE_MASK,
+		.size = sizeof(uint32_t),
+		.field_index = 1,
+		.input_index = 1,
+		.offset = offsetof(struct ipv6_hdr, src_addr[0]),
+	},
+
+	[2] = {
+		.type = RTE_ACL_FIELD_TYPE_MASK,
+		.size = sizeof(uint32_t),
+		.field_index = 2,
+		.input_index = 2,
+		.offset = offsetof(struct ipv6_hdr, src_addr[4]),
+	},
+
+	[3] = {
+		.type = RTE_ACL_FIELD_TYPE_MASK,
+		.size = sizeof(uint32_t),
+		.field_index = 3,
+		.input_index = 3,
+		.offset = offsetof(struct ipv6_hdr, src_addr[8]),
+	},
+
+	[4] = {
+		.type = RTE_ACL_FIELD_TYPE_MASK,
+		.size = sizeof(uint32_t),
+		.field_index = 4,
+		.input_index = 4,
+		.offset = offsetof(struct ipv6_hdr, src_addr[12]),
+	},
+
+	/* Destination IP address (IPv6) */
+	[5] = {
+		.type = RTE_ACL_FIELD_TYPE_MASK,
+		.size = sizeof(uint32_t),
+		.field_index = 5,
+		.input_index = 5,
+		.offset = offsetof(struct ipv6_hdr, dst_addr[0]),
+	},
+
+	[6] = {
+		.type = RTE_ACL_FIELD_TYPE_MASK,
+		.size = sizeof(uint32_t),
+		.field_index = 6,
+		.input_index = 6,
+		.offset = offsetof(struct ipv6_hdr, dst_addr[4]),
+	},
+
+	[7] = {
+		.type = RTE_ACL_FIELD_TYPE_MASK,
+		.size = sizeof(uint32_t),
+		.field_index = 7,
+		.input_index = 7,
+		.offset = offsetof(struct ipv6_hdr, dst_addr[8]),
+	},
+
+	[8] = {
+		.type = RTE_ACL_FIELD_TYPE_MASK,
+		.size = sizeof(uint32_t),
+		.field_index = 8,
+		.input_index = 8,
+		.offset = offsetof(struct ipv6_hdr, dst_addr[12]),
+	},
+
+	/* Source Port */
+	[9] = {
+		.type = RTE_ACL_FIELD_TYPE_RANGE,
+		.size = sizeof(uint16_t),
+		.field_index = 9,
+		.input_index = 9,
+		.offset = sizeof(struct ipv6_hdr) +
+			offsetof(struct tcp_hdr, src_port),
+	},
+
+	/* Destination Port */
+	[10] = {
+		.type = RTE_ACL_FIELD_TYPE_RANGE,
+		.size = sizeof(uint16_t),
+		.field_index = 10,
+		.input_index = 9,
+		.offset = sizeof(struct ipv6_hdr) +
+			offsetof(struct tcp_hdr, dst_port),
+	},
+};
+
+int
+pipeline_table_create(const char *pipeline_name,
+	struct table_params *params)
+{
+	char name[NAME_MAX];
+	struct rte_pipeline_table_params p;
+
+	union {
+		struct rte_table_acl_params acl;
+		struct rte_table_array_params array;
+		struct rte_table_hash_params hash;
+		struct rte_table_lpm_params lpm;
+		struct rte_table_lpm_ipv6_params lpm_ipv6;
+	} pp;
+
+	struct pipeline *pipeline;
+	struct table *table;
+	struct table_action_profile *ap;
+	struct rte_table_action *action;
+	uint32_t table_id;
+	int status;
+
+	memset(&p, 0, sizeof(p));
+	memset(&pp, 0, sizeof(pp));
+
+	/* Check input params */
+	if ((pipeline_name == NULL) ||
+		(params == NULL) ||
+		(params->action_profile_name == NULL))
+		return -1;
+
+	pipeline = pipeline_find(pipeline_name);
+	if ((pipeline == NULL) ||
+		(pipeline->n_tables >= PIPELINE_TABLE_MAX))
+		return -1;
+
+	ap = table_action_profile_find(params->action_profile_name);
+	if (ap == NULL)
+		return -1;
+
+	snprintf(name, NAME_MAX, "%s_table%u",
+		pipeline_name, pipeline->n_tables);
+
+	switch (params->match_type) {
+	case TABLE_ACL:
+	{
+		uint32_t ip_header_offset = params->match.acl.ip_header_offset -
+			(sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM);
+		uint32_t i;
+
+		if (params->match.acl.n_rules == 0)
+			return -1;
+
+		pp.acl.name = name;
+		pp.acl.n_rules = params->match.acl.n_rules;
+		if (params->match.acl.ip_version) {
+			memcpy(&pp.acl.field_format,
+				&table_acl_field_format_ipv4,
+				sizeof(table_acl_field_format_ipv4));
+			pp.acl.n_rule_fields =
+				RTE_DIM(table_acl_field_format_ipv4);
+		} else {
+			memcpy(&pp.acl.field_format,
+				&table_acl_field_format_ipv6,
+				sizeof(table_acl_field_format_ipv6));
+			pp.acl.n_rule_fields =
+				RTE_DIM(table_acl_field_format_ipv6);
+		}
+
+		for (i = 0; i < pp.acl.n_rule_fields; i++)
+			pp.acl.field_format[i].offset += ip_header_offset;
+
+		p.ops = &rte_table_acl_ops;
+		p.arg_create = &pp.acl;
+		break;
+	}
+
+	case TABLE_ARRAY:
+	{
+		if (params->match.array.n_keys == 0)
+			return -1;
+
+		pp.array.n_entries = params->match.array.n_keys;
+		pp.array.offset = params->match.array.key_offset;
+
+		p.ops = &rte_table_array_ops;
+		p.arg_create = &pp.array;
+		break;
+	}
+
+	case TABLE_HASH:
+	{
+		struct rte_table_ops *ops;
+		rte_table_hash_op_hash f_hash;
+
+		if (params->match.hash.n_keys == 0)
+			return -1;
+
+		switch (params->match.hash.key_size) {
+		case  8:
+			f_hash = hash_default_key8;
+			break;
+		case 16:
+			f_hash = hash_default_key16;
+			break;
+		case 24:
+			f_hash = hash_default_key24;
+			break;
+		case 32:
+			f_hash = hash_default_key32;
+			break;
+		case 40:
+			f_hash = hash_default_key40;
+			break;
+		case 48:
+			f_hash = hash_default_key48;
+			break;
+		case 56:
+			f_hash = hash_default_key56;
+			break;
+		case 64:
+			f_hash = hash_default_key64;
+			break;
+		default:
+			return -1;
+		}
+
+		pp.hash.name = name;
+		pp.hash.key_size = params->match.hash.key_size;
+		pp.hash.key_offset = params->match.hash.key_offset;
+		pp.hash.key_mask = params->match.hash.key_mask;
+		pp.hash.n_keys = params->match.hash.n_keys;
+		pp.hash.n_buckets = params->match.hash.n_buckets;
+		pp.hash.f_hash = f_hash;
+		pp.hash.seed = 0;
+
+		if (params->match.hash.extendable_bucket)
+			switch (params->match.hash.key_size) {
+			case  8:
+				ops = &rte_table_hash_key8_ext_ops;
+				break;
+			case 16:
+				ops = &rte_table_hash_key16_ext_ops;
+				break;
+			default:
+				ops = &rte_table_hash_ext_ops;
+			}
+		else
+			switch (params->match.hash.key_size) {
+			case  8:
+				ops = &rte_table_hash_key8_lru_ops;
+				break;
+			case 16:
+				ops = &rte_table_hash_key16_lru_ops;
+				break;
+			default:
+				ops = &rte_table_hash_lru_ops;
+			}
+
+		p.ops = ops;
+		p.arg_create = &pp.hash;
+		break;
+	}
+
+	case TABLE_LPM:
+	{
+		if (params->match.lpm.n_rules == 0)
+			return -1;
+
+		switch (params->match.lpm.key_size) {
+		case 4:
+		{
+			pp.lpm.name = name;
+			pp.lpm.n_rules = params->match.lpm.n_rules;
+			pp.lpm.number_tbl8s = TABLE_LPM_NUMBER_TBL8;
+			pp.lpm.flags = 0;
+			pp.lpm.entry_unique_size = p.action_data_size +
+				sizeof(struct rte_pipeline_table_entry);
+			pp.lpm.offset = params->match.lpm.key_offset;
+
+			p.ops = &rte_table_lpm_ops;
+			p.arg_create = &pp.lpm;
+			break;
+		}
+
+		case 16:
+		{
+			pp.lpm_ipv6.name = name;
+			pp.lpm_ipv6.n_rules = params->match.lpm.n_rules;
+			pp.lpm_ipv6.number_tbl8s = TABLE_LPM_NUMBER_TBL8;
+			pp.lpm_ipv6.entry_unique_size = p.action_data_size +
+				sizeof(struct rte_pipeline_table_entry);
+			pp.lpm_ipv6.offset = params->match.lpm.key_offset;
+
+			p.ops = &rte_table_lpm_ipv6_ops;
+			p.arg_create = &pp.lpm_ipv6;
+			break;
+		}
+
+		default:
+			return -1;
+		}
+
+		break;
+	}
+
+	case TABLE_STUB:
+	{
+		p.ops = &rte_table_stub_ops;
+		p.arg_create = NULL;
+		break;
+	}
+
+	default:
+		return -1;
+	}
+
+	/* Resource create */
+	action = rte_table_action_create(ap->ap,
+		pipeline->cpu_id);
+	if (action == NULL)
+		return -1;
+
+	status = rte_table_action_table_params_get(
+		action,
+		&p);
+	if (status ||
+		((p.action_data_size +
+		sizeof(struct rte_pipeline_table_entry)) >
+		TABLE_RULE_ACTION_SIZE_MAX)) {
+		rte_table_action_free(action);
+		return -1;
+	}
+
+	if (params->match_type == TABLE_LPM) {
+		if (params->match.lpm.key_size == 4)
+			pp.lpm.entry_unique_size = p.action_data_size +
+				sizeof(struct rte_pipeline_table_entry);
+
+		if (params->match.lpm.key_size == 16)
+			pp.lpm_ipv6.entry_unique_size = p.action_data_size +
+				sizeof(struct rte_pipeline_table_entry);
+	}
+
+	status = rte_pipeline_table_create(pipeline->p,
+		&p,
+		&table_id);
+	if (status) {
+		rte_table_action_free(action);
+		return -1;
+	}
+
+	/* Pipeline */
+	table = &pipeline->table[pipeline->n_tables];
+	memcpy(&table->params, params, sizeof(*params));
+	table->ap = ap;
+	table->a = action;
+	pipeline->n_tables++;
+
+	return 0;
+}
diff --git a/examples/ip_pipeline/pipeline.h b/examples/ip_pipeline/pipeline.h
new file mode 100644
index 0000000..dbc6f77
--- /dev/null
+++ b/examples/ip_pipeline/pipeline.h
@@ -0,0 +1,265 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#ifndef _INCLUDE_PIPELINE_H_
+#define _INCLUDE_PIPELINE_H_
+
+#include <stdint.h>
+#include <sys/queue.h>
+
+#include <rte_pipeline.h>
+#include <rte_table_action.h>
+
+#include "common.h"
+#include "action.h"
+
+struct pipeline_params {
+	uint32_t timer_period_ms;
+	uint32_t offset_port_id;
+	uint32_t cpu_id;
+};
+
+enum port_in_type {
+	PORT_IN_RXQ,
+	PORT_IN_SWQ,
+	PORT_IN_TMGR,
+	PORT_IN_TAP,
+	PORT_IN_KNI,
+	PORT_IN_SOURCE,
+};
+
+struct port_in_params {
+	enum port_in_type type;
+	const char *dev_name;
+	union {
+		struct {
+			uint16_t queue_id;
+		} rxq;
+
+		struct {
+			const char *mempool_name;
+			uint32_t mtu;
+		} tap;
+
+		struct {
+			const char *mempool_name;
+			const char *file_name;
+			uint32_t n_bytes_per_pkt;
+		} source;
+	};
+	uint32_t burst_size;
+};
+
+enum port_out_type {
+	PORT_OUT_TXQ,
+	PORT_OUT_SWQ,
+	PORT_OUT_TMGR,
+	PORT_OUT_TAP,
+	PORT_OUT_KNI,
+	PORT_OUT_SINK,
+};
+
+struct port_out_params {
+	enum port_out_type type;
+	const char *dev_name;
+	union {
+		struct {
+			uint16_t queue_id;
+		} txq;
+
+		struct {
+			const char *file_name;
+			uint32_t max_n_pkts;
+		} sink;
+	};
+	uint32_t burst_size;
+	int retry;
+	uint32_t n_retries;
+};
+
+enum table_type {
+	TABLE_ACL,
+	TABLE_ARRAY,
+	TABLE_HASH,
+	TABLE_LPM,
+	TABLE_STUB,
+};
+
+struct table_acl_params {
+	uint32_t n_rules;
+	uint32_t ip_header_offset;
+	int ip_version;
+};
+
+struct table_array_params {
+	uint32_t n_keys;
+	uint32_t key_offset;
+};
+
+struct table_hash_params {
+	uint32_t n_keys;
+	uint32_t key_offset;
+	uint32_t key_size;
+	uint8_t *key_mask;
+	uint32_t n_buckets;
+	int extendable_bucket;
+};
+
+struct table_lpm_params {
+	uint32_t n_rules;
+	uint32_t key_offset;
+	uint32_t key_size;
+};
+
+struct table_params {
+	/* Match */
+	enum table_type match_type;
+	union {
+		struct table_acl_params acl;
+		struct table_array_params array;
+		struct table_hash_params hash;
+		struct table_lpm_params lpm;
+	} match;
+
+	/* Action */
+	const char *action_profile_name;
+};
+
+struct table {
+	struct table_params params;
+	struct table_action_profile *ap;
+	struct rte_table_action *a;
+};
+
+#ifndef PIPELINE_TABLE_MAX
+#define PIPELINE_TABLE_MAX                                 256
+#endif
+
+struct pipeline {
+	TAILQ_ENTRY(pipeline) node;
+	char name[NAME_SIZE];
+
+	struct rte_pipeline *p;
+	struct table table[PIPELINE_TABLE_MAX];
+	uint32_t n_ports_in;
+	uint32_t n_ports_out;
+	uint32_t n_tables;
+
+	struct rte_ring *msgq_req;
+	struct rte_ring *msgq_rsp;
+	uint32_t timer_period_ms;
+
+	int enabled;
+	uint32_t thread_id;
+	uint32_t cpu_id;
+};
+
+TAILQ_HEAD(pipeline_list, pipeline);
+
+int
+pipeline_init(void);
+
+struct pipeline *
+pipeline_find(const char *name);
+
+struct pipeline *
+pipeline_create(const char *name, struct pipeline_params *params);
+
+int
+pipeline_port_in_create(const char *pipeline_name,
+	struct port_in_params *params,
+	int enabled);
+
+int
+pipeline_port_in_connect_to_table(const char *pipeline_name,
+	uint32_t port_id,
+	uint32_t table_id);
+
+int
+pipeline_port_out_create(const char *pipeline_name,
+	struct port_out_params *params);
+
+int
+pipeline_table_create(const char *pipeline_name,
+	struct table_params *params);
+
+struct table_rule_match_acl {
+	int ip_version;
+
+	RTE_STD_C11
+	union {
+		struct {
+			uint32_t sa;
+			uint32_t da;
+		} ipv4;
+
+		struct {
+			uint8_t sa[16];
+			uint8_t da[16];
+		} ipv6;
+	};
+
+	uint32_t sa_depth;
+	uint32_t da_depth;
+	uint16_t sp0;
+	uint16_t sp1;
+	uint16_t dp0;
+	uint16_t dp1;
+	uint8_t proto;
+	uint8_t proto_mask;
+	uint32_t priority;
+};
+
+struct table_rule_match_array {
+	uint32_t pos;
+};
+
+#ifndef TABLE_RULE_MATCH_SIZE_MAX
+#define TABLE_RULE_MATCH_SIZE_MAX                          256
+#endif
+
+#ifndef TABLE_RULE_ACTION_SIZE_MAX
+#define TABLE_RULE_ACTION_SIZE_MAX                         2048
+#endif
+
+struct table_rule_match_hash {
+	uint8_t key[TABLE_RULE_MATCH_SIZE_MAX];
+};
+
+struct table_rule_match_lpm {
+	int ip_version;
+
+	RTE_STD_C11
+	union {
+		uint32_t ipv4;
+		uint8_t ipv6[16];
+	};
+
+	uint8_t depth;
+};
+
+struct table_rule_match {
+	enum table_type match_type;
+
+	union {
+		struct table_rule_match_acl acl;
+		struct table_rule_match_array array;
+		struct table_rule_match_hash hash;
+		struct table_rule_match_lpm lpm;
+	} match;
+};
+
+struct table_rule_action {
+	uint64_t action_mask;
+	struct rte_table_action_fwd_params fwd;
+	struct rte_table_action_mtr_params mtr;
+	struct rte_table_action_tm_params tm;
+	struct rte_table_action_encap_params encap;
+	struct rte_table_action_nat_params nat;
+	struct rte_table_action_ttl_params ttl;
+	struct rte_table_action_stats_params stats;
+	struct rte_table_action_time_params time;
+};
+
+#endif /* _INCLUDE_PIPELINE_H_ */
-- 
2.9.3

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

* [dpdk-dev] [PATCH v2 27/44] ip_pipeline: add threads
  2018-03-12 17:25   ` [dpdk-dev] [PATCH v2 00/44] ip_pipeline: refactoring Jasvinder Singh
                       ` (25 preceding siblings ...)
  2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 26/44] ip_pipeline: add pipeline object Jasvinder Singh
@ 2018-03-12 17:25     ` Jasvinder Singh
  2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 28/44] ip_pipeline: add thread runtime Jasvinder Singh
                       ` (16 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-12 17:25 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add threads data structure and initialisation functions to run
the pipeline.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/Makefile    |   2 +-
 examples/ip_pipeline/main.c      |   8 ++
 examples/ip_pipeline/meson.build |   1 +
 examples/ip_pipeline/thread.c    | 159 +++++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/thread.h    |  13 ++++
 5 files changed, 182 insertions(+), 1 deletion(-)
 create mode 100644 examples/ip_pipeline/thread.c
 create mode 100644 examples/ip_pipeline/thread.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index 033319d..c936d1e 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -16,8 +16,8 @@ SRCS-y += parser.c
 SRCS-y += pipeline.c
 SRCS-y += swq.c
 SRCS-y += tap.c
+SRCS-y += thread.c
 SRCS-y += tmgr.c
-#SRCS-y += thread.c
 
 # Build using pkg-config variables if possible
 $(shell pkg-config --exists libdpdk)
diff --git a/examples/ip_pipeline/main.c b/examples/ip_pipeline/main.c
index a7f4486..d139290 100644
--- a/examples/ip_pipeline/main.c
+++ b/examples/ip_pipeline/main.c
@@ -18,6 +18,7 @@
 #include "pipeline.h"
 #include "swq.h"
 #include "tap.h"
+#include "thread.h"
 #include "tmgr.h"
 
 static const char usage[] =
@@ -223,6 +224,13 @@ main(int argc, char **argv)
 		return status;
 	}
 
+	/* Thread */
+	status = thread_init();
+	if (status) {
+		printf("Error: Thread initialization failed (%d)\n", status);
+		return status;
+	}
+
 	/* Script */
 	if (app.script_name)
 		cli_script_process(app.script_name,
diff --git a/examples/ip_pipeline/meson.build b/examples/ip_pipeline/meson.build
index 2366242..a9f2ea4 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -20,5 +20,6 @@ sources = files(
 	'pipeline.c',
 	'swq.c',
 	'tap.c',
+	'thread.c',
 	'tmgr.c'
 )
diff --git a/examples/ip_pipeline/thread.c b/examples/ip_pipeline/thread.c
new file mode 100644
index 0000000..4da8db9
--- /dev/null
+++ b/examples/ip_pipeline/thread.c
@@ -0,0 +1,159 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#include <stdlib.h>
+
+#include <rte_common.h>
+#include <rte_cycles.h>
+#include <rte_lcore.h>
+#include <rte_ring.h>
+
+#include <rte_table_acl.h>
+#include <rte_table_array.h>
+#include <rte_table_hash.h>
+#include <rte_table_lpm.h>
+#include <rte_table_lpm_ipv6.h>
+
+#include "common.h"
+#include "thread.h"
+#include "pipeline.h"
+
+#ifndef THREAD_PIPELINES_MAX
+#define THREAD_PIPELINES_MAX                               256
+#endif
+
+#ifndef THREAD_MSGQ_SIZE
+#define THREAD_MSGQ_SIZE                                   64
+#endif
+
+#ifndef THREAD_TIMER_PERIOD_MS
+#define THREAD_TIMER_PERIOD_MS                             100
+#endif
+
+/**
+ * Master thead: data plane thread context
+ */
+struct thread {
+	struct rte_ring *msgq_req;
+	struct rte_ring *msgq_rsp;
+
+	uint32_t enabled;
+};
+
+static struct thread thread[RTE_MAX_LCORE];
+
+/**
+ * Data plane threads: context
+ */
+struct table_data {
+	void *ap_instance;
+};
+
+struct pipeline_data {
+	struct rte_pipeline *p;
+	struct table_data table_data[PIPELINE_TABLE_MAX];
+	uint32_t n_tables;
+
+	struct rte_ring *msgq_req;
+	struct rte_ring *msgq_rsp;
+	uint64_t timer_period; /* Measured in CPU cycles. */
+	uint64_t time_next;
+
+	uint8_t buffer[TABLE_RULE_ACTION_SIZE_MAX];
+};
+
+struct thread_data {
+	struct rte_pipeline *p[THREAD_PIPELINES_MAX];
+	uint32_t n_pipelines;
+
+	struct pipeline_data pipeline_data[THREAD_PIPELINES_MAX];
+	struct rte_ring *msgq_req;
+	struct rte_ring *msgq_rsp;
+	uint64_t timer_period; /* Measured in CPU cycles. */
+	uint64_t time_next;
+	uint64_t time_next_min;
+} __rte_cache_aligned;
+
+static struct thread_data thread_data[RTE_MAX_LCORE];
+
+/**
+ * Master thread: data plane thread init
+ */
+static void
+thread_free(void)
+{
+	uint32_t i;
+
+	for (i = 0; i < RTE_MAX_LCORE; i++) {
+		struct thread *t = &thread[i];
+
+		if (!rte_lcore_is_enabled(i))
+			continue;
+
+		/* MSGQs */
+		if (t->msgq_req)
+			rte_ring_free(t->msgq_req);
+
+		if (t->msgq_rsp)
+			rte_ring_free(t->msgq_rsp);
+	}
+}
+
+int
+thread_init(void)
+{
+	uint32_t i;
+
+	for (i = 0; i < RTE_MAX_LCORE; i++) {
+		char name[NAME_MAX];
+		struct rte_ring *msgq_req, *msgq_rsp;
+		struct thread *t = &thread[i];
+		struct thread_data *t_data = &thread_data[i];
+		uint32_t cpu_id = rte_lcore_to_socket_id(i);
+
+		if (!rte_lcore_is_enabled(i))
+			continue;
+
+		/* MSGQs */
+		snprintf(name, sizeof(name), "THREAD-%04x-MSGQ-REQ", i);
+
+		msgq_req = rte_ring_create(name,
+			THREAD_MSGQ_SIZE,
+			cpu_id,
+			RING_F_SP_ENQ | RING_F_SC_DEQ);
+
+		if (msgq_req == NULL) {
+			thread_free();
+			return -1;
+		}
+
+		snprintf(name, sizeof(name), "THREAD-%04x-MSGQ-RSP", i);
+
+		msgq_rsp = rte_ring_create(name,
+			THREAD_MSGQ_SIZE,
+			cpu_id,
+			RING_F_SP_ENQ | RING_F_SC_DEQ);
+
+		if (msgq_rsp == NULL) {
+			thread_free();
+			return -1;
+		}
+
+		/* Master thread records */
+		t->msgq_req = msgq_req;
+		t->msgq_rsp = msgq_rsp;
+		t->enabled = 1;
+
+		/* Data plane thread records */
+		t_data->n_pipelines = 0;
+		t_data->msgq_req = msgq_req;
+		t_data->msgq_rsp = msgq_rsp;
+		t_data->timer_period =
+			(rte_get_tsc_hz() * THREAD_TIMER_PERIOD_MS) / 1000;
+		t_data->time_next = rte_get_tsc_cycles() + t_data->timer_period;
+		t_data->time_next_min = t_data->time_next;
+	}
+
+	return 0;
+}
diff --git a/examples/ip_pipeline/thread.h b/examples/ip_pipeline/thread.h
new file mode 100644
index 0000000..39c0d89
--- /dev/null
+++ b/examples/ip_pipeline/thread.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#ifndef _INCLUDE_THREAD_H_
+#define _INCLUDE_THREAD_H_
+
+#include <stdint.h>
+
+int
+thread_init(void);
+
+#endif /* _INCLUDE_THREAD_H_ */
-- 
2.9.3

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

* [dpdk-dev] [PATCH v2 28/44] ip_pipeline: add thread runtime
  2018-03-12 17:25   ` [dpdk-dev] [PATCH v2 00/44] ip_pipeline: refactoring Jasvinder Singh
                       ` (26 preceding siblings ...)
  2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 27/44] ip_pipeline: add threads Jasvinder Singh
@ 2018-03-12 17:25     ` Jasvinder Singh
  2018-03-12 17:26     ` [dpdk-dev] [PATCH v2 29/44] ip_pipeline: add cli to enable and disable pipeline Jasvinder Singh
                       ` (15 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-12 17:25 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add runtime thread functions for the pipeline.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/main.c   |   6 ++
 examples/ip_pipeline/thread.c | 193 ++++++++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/thread.h |   3 +
 3 files changed, 202 insertions(+)

diff --git a/examples/ip_pipeline/main.c b/examples/ip_pipeline/main.c
index d139290..36da679 100644
--- a/examples/ip_pipeline/main.c
+++ b/examples/ip_pipeline/main.c
@@ -8,6 +8,7 @@
 #include <unistd.h>
 #include <getopt.h>
 
+#include <rte_launch.h>
 #include <rte_eal.h>
 
 #include "cli.h"
@@ -231,6 +232,11 @@ main(int argc, char **argv)
 		return status;
 	}
 
+	rte_eal_mp_remote_launch(
+		thread_main,
+		NULL,
+		SKIP_MASTER);
+
 	/* Script */
 	if (app.script_name)
 		cli_script_process(app.script_name,
diff --git a/examples/ip_pipeline/thread.c b/examples/ip_pipeline/thread.c
index 4da8db9..387e9bc 100644
--- a/examples/ip_pipeline/thread.c
+++ b/examples/ip_pipeline/thread.c
@@ -157,3 +157,196 @@ thread_init(void)
 
 	return 0;
 }
+
+/**
+ * Master thread & data plane threads: message passing
+ */
+enum thread_req_type {
+	THREAD_REQ_MAX
+};
+
+struct thread_msg_req {
+	enum thread_req_type type;
+};
+
+struct thread_msg_rsp {
+	int status;
+};
+
+/**
+ * Data plane threads: message handling
+ */
+static inline struct thread_msg_req *
+thread_msg_recv(struct rte_ring *msgq_req)
+{
+	struct thread_msg_req *req;
+
+	int status = rte_ring_sc_dequeue(msgq_req, (void **) &req);
+
+	if (status != 0)
+		return NULL;
+
+	return req;
+}
+
+static inline void
+thread_msg_send(struct rte_ring *msgq_rsp,
+	struct thread_msg_rsp *rsp)
+{
+	int status;
+
+	do {
+		status = rte_ring_sp_enqueue(msgq_rsp, rsp);
+	} while (status == -ENOBUFS);
+}
+
+static void
+thread_msg_handle(struct thread_data *t)
+{
+	for ( ; ; ) {
+		struct thread_msg_req *req;
+		struct thread_msg_rsp *rsp;
+
+		req = thread_msg_recv(t->msgq_req);
+		if (req == NULL)
+			break;
+
+		switch (req->type) {
+		default:
+			rsp = (struct thread_msg_rsp *) req;
+			rsp->status = -1;
+		}
+
+		thread_msg_send(t->msgq_rsp, rsp);
+	}
+}
+
+/**
+ * Master thread & data plane threads: message passing
+ */
+
+enum pipeline_req_type {
+	PIPELINE_REQ_MAX
+};
+
+struct pipeline_msg_req {
+	enum pipeline_req_type type;
+};
+
+struct pipeline_msg_rsp {
+	int status;
+};
+
+/**
+ * Data plane threads: message handling
+ */
+static inline struct pipeline_msg_req *
+pipeline_msg_recv(struct rte_ring *msgq_req)
+{
+	struct pipeline_msg_req *req;
+
+	int status = rte_ring_sc_dequeue(msgq_req, (void **) &req);
+
+	if (status != 0)
+		return NULL;
+
+	return req;
+}
+
+static inline void
+pipeline_msg_send(struct rte_ring *msgq_rsp,
+	struct pipeline_msg_rsp *rsp)
+{
+	int status;
+
+	do {
+		status = rte_ring_sp_enqueue(msgq_rsp, rsp);
+	} while (status == -ENOBUFS);
+}
+
+static void
+pipeline_msg_handle(struct pipeline_data *p)
+{
+	for ( ; ; ) {
+		struct pipeline_msg_req *req;
+		struct pipeline_msg_rsp *rsp;
+
+		req = pipeline_msg_recv(p->msgq_req);
+		if (req == NULL)
+			break;
+
+		switch (req->type) {
+		default:
+			rsp = (struct pipeline_msg_rsp *) req;
+			rsp->status = -1;
+		}
+
+		pipeline_msg_send(p->msgq_rsp, rsp);
+	}
+}
+
+/**
+ * Data plane threads: main
+ */
+int
+thread_main(void *arg __rte_unused)
+{
+	struct thread_data *t;
+	uint32_t thread_id, i;
+
+	thread_id = rte_lcore_id();
+	t = &thread_data[thread_id];
+
+	/* Dispatch loop */
+	for (i = 0; ; i++) {
+		uint32_t j;
+
+		/* Data Plane */
+		for (j = 0; j < t->n_pipelines; j++)
+			rte_pipeline_run(t->p[j]);
+
+		/* Control Plane */
+		if ((i & 0xF) == 0) {
+			uint64_t time = rte_get_tsc_cycles();
+			uint64_t time_next_min = UINT64_MAX;
+
+			if (time < t->time_next_min)
+				continue;
+
+			/* Pipeline message queues */
+			for (j = 0; j < t->n_pipelines; j++) {
+				struct pipeline_data *p =
+					&t->pipeline_data[j];
+				uint64_t time_next = p->time_next;
+
+				if (time_next <= time) {
+					pipeline_msg_handle(p);
+					rte_pipeline_flush(p->p);
+					time_next = time + p->timer_period;
+					p->time_next = time_next;
+				}
+
+				if (time_next < time_next_min)
+					time_next_min = time_next;
+			}
+
+			/* Thread message queues */
+			{
+				uint64_t time_next = t->time_next;
+
+				if (time_next <= time) {
+					thread_msg_handle(t);
+					time_next = time + t->timer_period;
+					t->time_next = time_next;
+				}
+
+				if (time_next < time_next_min)
+					time_next_min = time_next;
+			}
+
+			t->time_next_min = time_next_min;
+		}
+	}
+
+	return 0;
+}
diff --git a/examples/ip_pipeline/thread.h b/examples/ip_pipeline/thread.h
index 39c0d89..47db428 100644
--- a/examples/ip_pipeline/thread.h
+++ b/examples/ip_pipeline/thread.h
@@ -10,4 +10,7 @@
 int
 thread_init(void);
 
+int
+thread_main(void *arg);
+
 #endif /* _INCLUDE_THREAD_H_ */
-- 
2.9.3

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

* [dpdk-dev] [PATCH v2 29/44] ip_pipeline: add cli to enable and disable pipeline
  2018-03-12 17:25   ` [dpdk-dev] [PATCH v2 00/44] ip_pipeline: refactoring Jasvinder Singh
                       ` (27 preceding siblings ...)
  2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 28/44] ip_pipeline: add thread runtime Jasvinder Singh
@ 2018-03-12 17:26     ` Jasvinder Singh
  2018-03-12 17:26     ` [dpdk-dev] [PATCH v2 30/44] ip_pipeline: add cli to enable and disable pipeline port Jasvinder Singh
                       ` (14 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-12 17:26 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Fan Zhang

Add commands to enable and disable the pipeline on the thread.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Fan Zhang <roy.fan.zhang@intel.com>
---
 examples/ip_pipeline/cli.c    | 102 +++++++++++++++++
 examples/ip_pipeline/thread.c | 260 +++++++++++++++++++++++++++++++++++++++++-
 examples/ip_pipeline/thread.h |   8 ++
 3 files changed, 369 insertions(+), 1 deletion(-)

diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index acf4fe0..c149f2c 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -17,6 +17,7 @@
 #include "pipeline.h"
 #include "swq.h"
 #include "tap.h"
+#include "thread.h"
 #include "tmgr.h"
 
 #ifndef CMD_MAX_TOKENS
@@ -1740,6 +1741,91 @@ cmd_pipeline_port_in_table(char **tokens,
 	}
 }
 
+/**
+ * thread <thread_id> pipeline <pipeline_name> enable
+ */
+static void
+cmd_thread_pipeline_enable(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	char *pipeline_name;
+	uint32_t thread_id;
+	int status;
+
+	if (n_tokens != 5) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	if (parser_read_uint32(&thread_id, tokens[1]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
+		return;
+	}
+
+	if (strcmp(tokens[2], "pipeline") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
+		return;
+	}
+
+	pipeline_name = tokens[3];
+
+	if (strcmp(tokens[4], "enable") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable");
+		return;
+	}
+
+	status = thread_pipeline_enable(thread_id, pipeline_name);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, "thread pipeline enable");
+		return;
+	}
+}
+
+/**
+ * thread <thread_id> pipeline <pipeline_name> disable
+ */
+static void
+cmd_thread_pipeline_disable(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	char *pipeline_name;
+	uint32_t thread_id;
+	int status;
+
+	if (n_tokens != 5) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	if (parser_read_uint32(&thread_id, tokens[1]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
+		return;
+	}
+
+	if (strcmp(tokens[2], "pipeline") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
+		return;
+	}
+
+	pipeline_name = tokens[3];
+
+	if (strcmp(tokens[4], "disable") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable");
+		return;
+	}
+
+	status = thread_pipeline_disable(thread_id, pipeline_name);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL,
+			"thread pipeline disable");
+		return;
+	}
+}
+
 void
 cli_process(char *in, char *out, size_t out_size)
 {
@@ -1863,6 +1949,22 @@ cli_process(char *in, char *out, size_t out_size)
 		}
 	}
 
+	if (strcmp(tokens[0], "thread") == 0) {
+		if ((n_tokens >= 5) &&
+			(strcmp(tokens[4], "enable") == 0)) {
+			cmd_thread_pipeline_enable(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
+
+		if ((n_tokens >= 5) &&
+			(strcmp(tokens[4], "disable") == 0)) {
+			cmd_thread_pipeline_disable(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
+	}
+
 	snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
 }
 
diff --git a/examples/ip_pipeline/thread.c b/examples/ip_pipeline/thread.c
index 387e9bc..d707ad7 100644
--- a/examples/ip_pipeline/thread.c
+++ b/examples/ip_pipeline/thread.c
@@ -47,7 +47,7 @@ static struct thread thread[RTE_MAX_LCORE];
  * Data plane threads: context
  */
 struct table_data {
-	void *ap_instance;
+	struct rte_table_action *a;
 };
 
 struct pipeline_data {
@@ -162,11 +162,30 @@ thread_init(void)
  * Master thread & data plane threads: message passing
  */
 enum thread_req_type {
+	THREAD_REQ_PIPELINE_ENABLE = 0,
+	THREAD_REQ_PIPELINE_DISABLE,
 	THREAD_REQ_MAX
 };
 
 struct thread_msg_req {
 	enum thread_req_type type;
+
+	union {
+		struct {
+			struct rte_pipeline *p;
+			struct {
+				struct rte_table_action *a;
+			} table[PIPELINE_TABLE_MAX];
+			struct rte_ring *msgq_req;
+			struct rte_ring *msgq_rsp;
+			uint32_t timer_period_ms;
+			uint32_t n_tables;
+		} pipeline_enable;
+
+		struct {
+			struct rte_pipeline *p;
+		} pipeline_disable;
+	};
 };
 
 struct thread_msg_rsp {
@@ -174,6 +193,164 @@ struct thread_msg_rsp {
 };
 
 /**
+ * Master thread
+ */
+static struct thread_msg_req *
+thread_msg_alloc(void)
+{
+	size_t size = RTE_MAX(sizeof(struct thread_msg_req),
+		sizeof(struct thread_msg_rsp));
+
+	return calloc(1, size);
+}
+
+static void
+thread_msg_free(struct thread_msg_rsp *rsp)
+{
+	free(rsp);
+}
+
+static struct thread_msg_rsp *
+thread_msg_send_recv(uint32_t thread_id,
+	struct thread_msg_req *req)
+{
+	struct thread *t = &thread[thread_id];
+	struct rte_ring *msgq_req = t->msgq_req;
+	struct rte_ring *msgq_rsp = t->msgq_rsp;
+	struct thread_msg_rsp *rsp;
+	int status;
+
+	/* send */
+	do {
+		status = rte_ring_sp_enqueue(msgq_req, req);
+	} while (status == -ENOBUFS);
+
+	/* recv */
+	do {
+		status = rte_ring_sc_dequeue(msgq_rsp, (void **) &rsp);
+	} while (status != 0);
+
+	return rsp;
+}
+
+int
+thread_pipeline_enable(uint32_t thread_id,
+	const char *pipeline_name)
+{
+	struct pipeline *p = pipeline_find(pipeline_name);
+	struct thread *t;
+	struct thread_msg_req *req;
+	struct thread_msg_rsp *rsp;
+	uint32_t i;
+	int status;
+
+	/* Check input params */
+	if ((thread_id >= RTE_MAX_LCORE) ||
+		(p == NULL) ||
+		(p->n_ports_in == 0) ||
+		(p->n_ports_out == 0) ||
+		(p->n_tables == 0))
+		return -1;
+
+	t = &thread[thread_id];
+	if (t->enabled == 0)
+		return -1;
+
+	if (p->enabled && (p->thread_id == thread_id))
+		return 0;
+
+	/* Allocate request */
+	req = thread_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = THREAD_REQ_PIPELINE_ENABLE;
+	req->pipeline_enable.p = p->p;
+	for (i = 0; i < p->n_tables; i++)
+		req->pipeline_enable.table[i].a =
+			p->table[i].a;
+	req->pipeline_enable.msgq_req = p->msgq_req;
+	req->pipeline_enable.msgq_rsp = p->msgq_rsp;
+	req->pipeline_enable.timer_period_ms = p->timer_period_ms;
+	req->pipeline_enable.n_tables = p->n_tables;
+
+	/* Send request and wait for response */
+	rsp = thread_msg_send_recv(thread_id, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+
+	/* Free response */
+	thread_msg_free(rsp);
+
+	/* Request completion */
+	if (status)
+		return status;
+
+	p->thread_id = thread_id;
+	p->enabled = 1;
+
+	return 0;
+}
+
+int
+thread_pipeline_disable(uint32_t thread_id,
+	const char *pipeline_name)
+{
+	struct pipeline *p = pipeline_find(pipeline_name);
+	struct thread *t;
+	struct thread_msg_req *req;
+	struct thread_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if ((thread_id >= RTE_MAX_LCORE) ||
+		(p == NULL))
+		return -1;
+
+	t = &thread[thread_id];
+	if (t->enabled == 0)
+		return -1;
+
+	if (p->enabled == 0)
+		return 0;
+
+	if (p->thread_id != thread_id)
+		return -1;
+
+	/* Allocate request */
+	req = thread_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = THREAD_REQ_PIPELINE_DISABLE;
+	req->pipeline_disable.p = p->p;
+
+	/* Send request and wait for response */
+	rsp = thread_msg_send_recv(thread_id, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+
+	/* Free response */
+	thread_msg_free(rsp);
+
+	/* Request completion */
+	if (status)
+		return status;
+
+	p->enabled = 0;
+
+	return 0;
+}
+
+/**
  * Data plane threads: message handling
  */
 static inline struct thread_msg_req *
@@ -200,6 +377,79 @@ thread_msg_send(struct rte_ring *msgq_rsp,
 	} while (status == -ENOBUFS);
 }
 
+static struct thread_msg_rsp *
+thread_msg_handle_pipeline_enable(struct thread_data *t,
+	struct thread_msg_req *req)
+{
+	struct thread_msg_rsp *rsp = (struct thread_msg_rsp *) req;
+	struct pipeline_data *p = &t->pipeline_data[t->n_pipelines];
+	uint32_t i;
+
+	/* Request */
+	if (t->n_pipelines >= THREAD_PIPELINES_MAX) {
+		rsp->status = -1;
+		return rsp;
+	}
+
+	t->p[t->n_pipelines] = req->pipeline_enable.p;
+
+	p->p = req->pipeline_enable.p;
+	for (i = 0; i < req->pipeline_enable.n_tables; i++)
+		p->table_data[i].a =
+			req->pipeline_enable.table[i].a;
+
+	p->n_tables = req->pipeline_enable.n_tables;
+
+	p->msgq_req = req->pipeline_enable.msgq_req;
+	p->msgq_rsp = req->pipeline_enable.msgq_rsp;
+	p->timer_period =
+		(rte_get_tsc_hz() * req->pipeline_enable.timer_period_ms) / 1000;
+	p->time_next = rte_get_tsc_cycles() + p->timer_period;
+
+	t->n_pipelines++;
+
+	/* Response */
+	rsp->status = 0;
+	return rsp;
+}
+
+static struct thread_msg_rsp *
+thread_msg_handle_pipeline_disable(struct thread_data *t,
+	struct thread_msg_req *req)
+{
+	struct thread_msg_rsp *rsp = (struct thread_msg_rsp *) req;
+	uint32_t n_pipelines = t->n_pipelines;
+	struct rte_pipeline *pipeline = req->pipeline_disable.p;
+	uint32_t i;
+
+	/* find pipeline */
+	for (i = 0; i < n_pipelines; i++) {
+		struct pipeline_data *p = &t->pipeline_data[i];
+
+		if (p->p != pipeline)
+			continue;
+
+		if (i < n_pipelines - 1) {
+			struct rte_pipeline *pipeline_last =
+				t->p[n_pipelines - 1];
+			struct pipeline_data *p_last =
+				&t->pipeline_data[n_pipelines - 1];
+
+			t->p[i] = pipeline_last;
+			memcpy(p, p_last, sizeof(*p));
+		}
+
+		t->n_pipelines--;
+
+		rsp->status = 0;
+		return rsp;
+	}
+
+	/* should not get here */
+	rsp->status = 0;
+	return rsp;
+}
+
 static void
 thread_msg_handle(struct thread_data *t)
 {
@@ -212,6 +462,14 @@ thread_msg_handle(struct thread_data *t)
 			break;
 
 		switch (req->type) {
+		case THREAD_REQ_PIPELINE_ENABLE:
+			rsp = thread_msg_handle_pipeline_enable(t, req);
+			break;
+
+		case THREAD_REQ_PIPELINE_DISABLE:
+			rsp = thread_msg_handle_pipeline_disable(t, req);
+			break;
+
 		default:
 			rsp = (struct thread_msg_rsp *) req;
 			rsp->status = -1;
diff --git a/examples/ip_pipeline/thread.h b/examples/ip_pipeline/thread.h
index 47db428..facdf00 100644
--- a/examples/ip_pipeline/thread.h
+++ b/examples/ip_pipeline/thread.h
@@ -8,6 +8,14 @@
 #include <stdint.h>
 
 int
+thread_pipeline_enable(uint32_t thread_id,
+	const char *pipeline_name);
+
+int
+thread_pipeline_disable(uint32_t thread_id,
+	const char *pipeline_name);
+
+int
 thread_init(void);
 
 int
-- 
2.9.3

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

* [dpdk-dev] [PATCH v2 30/44] ip_pipeline: add cli to enable and disable pipeline port
  2018-03-12 17:25   ` [dpdk-dev] [PATCH v2 00/44] ip_pipeline: refactoring Jasvinder Singh
                       ` (28 preceding siblings ...)
  2018-03-12 17:26     ` [dpdk-dev] [PATCH v2 29/44] ip_pipeline: add cli to enable and disable pipeline Jasvinder Singh
@ 2018-03-12 17:26     ` Jasvinder Singh
  2018-03-12 17:26     ` [dpdk-dev] [PATCH v2 31/44] ip_pipeline: add cli to read pipeline port and table stats Jasvinder Singh
                       ` (13 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-12 17:26 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Fan Zhang

Add commands to enable and disable the pipeline ports.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Fan Zhang <roy.fan.zhang@intel.com>
---
 examples/ip_pipeline/cli.c      | 112 +++++++++++++++++++++++++++
 examples/ip_pipeline/pipeline.h |   8 ++
 examples/ip_pipeline/thread.c   | 163 +++++++++++++++++++++++++++++++++++++++-
 3 files changed, 282 insertions(+), 1 deletion(-)

diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index c149f2c..84fcd9d 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -1742,6 +1742,100 @@ cmd_pipeline_port_in_table(char **tokens,
 }
 
 /**
+ * pipeline <pipeline_name> port in <port_id> enable
+ */
+static void
+cmd_pipeline_port_in_enable(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	char *pipeline_name;
+	uint32_t port_id;
+	int status;
+
+	if (n_tokens != 6) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "port") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
+		return;
+	}
+
+	if (strcmp(tokens[3], "in") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
+		return;
+	}
+
+	if (parser_read_uint32(&port_id, tokens[4]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
+		return;
+	}
+
+	if (strcmp(tokens[5], "enable") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable");
+		return;
+	}
+
+	status = pipeline_port_in_enable(pipeline_name, port_id);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
+ * pipeline <pipeline_name> port in <port_id> disable
+ */
+static void
+cmd_pipeline_port_in_disable(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	char *pipeline_name;
+	uint32_t port_id;
+	int status;
+
+	if (n_tokens != 6) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "port") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
+		return;
+	}
+
+	if (strcmp(tokens[3], "in") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
+		return;
+	}
+
+	if (parser_read_uint32(&port_id, tokens[4]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
+		return;
+	}
+
+	if (strcmp(tokens[5], "disable") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable");
+		return;
+	}
+
+	status = pipeline_port_in_disable(pipeline_name, port_id);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
  * thread <thread_id> pipeline <pipeline_name> enable
  */
 static void
@@ -1947,6 +2041,24 @@ cli_process(char *in, char *out, size_t out_size)
 				out, out_size);
 			return;
 		}
+
+		if ((n_tokens >= 6) &&
+			(strcmp(tokens[2], "port") == 0) &&
+			(strcmp(tokens[3], "in") == 0) &&
+			(strcmp(tokens[5], "enable") == 0)) {
+			cmd_pipeline_port_in_enable(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
+
+		if ((n_tokens >= 6) &&
+			(strcmp(tokens[2], "port") == 0) &&
+			(strcmp(tokens[3], "in") == 0) &&
+			(strcmp(tokens[5], "disable") == 0)) {
+			cmd_pipeline_port_in_disable(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
 	}
 
 	if (strcmp(tokens[0], "thread") == 0) {
diff --git a/examples/ip_pipeline/pipeline.h b/examples/ip_pipeline/pipeline.h
index dbc6f77..9b79b67 100644
--- a/examples/ip_pipeline/pipeline.h
+++ b/examples/ip_pipeline/pipeline.h
@@ -262,4 +262,12 @@ struct table_rule_action {
 	struct rte_table_action_time_params time;
 };
 
+int
+pipeline_port_in_enable(const char *pipeline_name,
+	uint32_t port_id);
+
+int
+pipeline_port_in_disable(const char *pipeline_name,
+	uint32_t port_id);
+
 #endif /* _INCLUDE_PIPELINE_H_ */
diff --git a/examples/ip_pipeline/thread.c b/examples/ip_pipeline/thread.c
index d707ad7..a47b645 100644
--- a/examples/ip_pipeline/thread.c
+++ b/examples/ip_pipeline/thread.c
@@ -482,13 +482,17 @@ thread_msg_handle(struct thread_data *t)
 /**
  * Master thread & data plane threads: message passing
  */
-
 enum pipeline_req_type {
+	/* Port IN */
+	PIPELINE_REQ_PORT_IN_ENABLE,
+	PIPELINE_REQ_PORT_IN_DISABLE,
+
 	PIPELINE_REQ_MAX
 };
 
 struct pipeline_msg_req {
 	enum pipeline_req_type type;
+	uint32_t id; /* Port IN, port OUT or table ID */
 };
 
 struct pipeline_msg_rsp {
@@ -496,6 +500,129 @@ struct pipeline_msg_rsp {
 };
 
 /**
+ * Master thread
+ */
+static struct pipeline_msg_req *
+pipeline_msg_alloc(void)
+{
+	size_t size = RTE_MAX(sizeof(struct pipeline_msg_req),
+		sizeof(struct pipeline_msg_rsp));
+
+	return calloc(1, size);
+}
+
+static void
+pipeline_msg_free(struct pipeline_msg_rsp *rsp)
+{
+	free(rsp);
+}
+
+static struct pipeline_msg_rsp *
+pipeline_msg_send_recv(struct pipeline *p,
+	struct pipeline_msg_req *req)
+{
+	struct rte_ring *msgq_req = p->msgq_req;
+	struct rte_ring *msgq_rsp = p->msgq_rsp;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* send */
+	do {
+		status = rte_ring_sp_enqueue(msgq_req, req);
+	} while (status == -ENOBUFS);
+
+	/* recv */
+	do {
+		status = rte_ring_sc_dequeue(msgq_rsp, (void **) &rsp);
+	} while (status != 0);
+
+	return rsp;
+}
+
+int
+pipeline_port_in_enable(const char *pipeline_name,
+	uint32_t port_id)
+{
+	struct pipeline *p;
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if (pipeline_name == NULL)
+		return -1;
+
+	p = pipeline_find(pipeline_name);
+	if ((p == NULL) ||
+		(port_id >= p->n_ports_in))
+		return -1;
+
+	/* Allocate request */
+	req = pipeline_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = PIPELINE_REQ_PORT_IN_ENABLE;
+	req->id = port_id;
+
+	/* Send request and wait for response */
+	rsp = pipeline_msg_send_recv(p, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+
+	/* Free response */
+	pipeline_msg_free(rsp);
+
+	return status;
+}
+
+int
+pipeline_port_in_disable(const char *pipeline_name,
+	uint32_t port_id)
+{
+	struct pipeline *p;
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if (pipeline_name == NULL)
+		return -1;
+
+	p = pipeline_find(pipeline_name);
+	if ((p == NULL) ||
+		(port_id >= p->n_ports_in))
+		return -1;
+
+	/* Allocate request */
+	req = pipeline_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = PIPELINE_REQ_PORT_IN_DISABLE;
+	req->id = port_id;
+
+	/* Send request and wait for response */
+	rsp = pipeline_msg_send_recv(p, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+
+	/* Free response */
+	pipeline_msg_free(rsp);
+
+	return status;
+}
+
+
+/**
  * Data plane threads: message handling
  */
 static inline struct pipeline_msg_req *
@@ -522,6 +649,32 @@ pipeline_msg_send(struct rte_ring *msgq_rsp,
 	} while (status == -ENOBUFS);
 }
 
+static struct pipeline_msg_rsp *
+pipeline_msg_handle_port_in_enable(struct pipeline_data *p,
+	struct pipeline_msg_req *req)
+{
+	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+	uint32_t port_id = req->id;
+
+	rsp->status = rte_pipeline_port_in_enable(p->p,
+		port_id);
+
+	return rsp;
+}
+
+static struct pipeline_msg_rsp *
+pipeline_msg_handle_port_in_disable(struct pipeline_data *p,
+	struct pipeline_msg_req *req)
+{
+	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+	uint32_t port_id = req->id;
+
+	rsp->status = rte_pipeline_port_in_disable(p->p,
+		port_id);
+
+	return rsp;
+}
+
 static void
 pipeline_msg_handle(struct pipeline_data *p)
 {
@@ -534,6 +687,14 @@ pipeline_msg_handle(struct pipeline_data *p)
 			break;
 
 		switch (req->type) {
+		case PIPELINE_REQ_PORT_IN_ENABLE:
+			rsp = pipeline_msg_handle_port_in_enable(p, req);
+			break;
+
+		case PIPELINE_REQ_PORT_IN_DISABLE:
+			rsp = pipeline_msg_handle_port_in_disable(p, req);
+			break;
+
 		default:
 			rsp = (struct pipeline_msg_rsp *) req;
 			rsp->status = -1;
-- 
2.9.3

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

* [dpdk-dev] [PATCH v2 31/44] ip_pipeline: add cli to read pipeline port and table stats
  2018-03-12 17:25   ` [dpdk-dev] [PATCH v2 00/44] ip_pipeline: refactoring Jasvinder Singh
                       ` (29 preceding siblings ...)
  2018-03-12 17:26     ` [dpdk-dev] [PATCH v2 30/44] ip_pipeline: add cli to enable and disable pipeline port Jasvinder Singh
@ 2018-03-12 17:26     ` Jasvinder Singh
  2018-03-12 17:26     ` [dpdk-dev] [PATCH v2 32/44] ip_pipeline: add cli for pipeline table entries Jasvinder Singh
                       ` (12 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-12 17:26 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Fan Zhang

Add commands to read the pipeline  port in, port out
and table stats.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Fan Zhang <roy.fan.zhang@intel.com>
---
 examples/ip_pipeline/cli.c      | 256 ++++++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/pipeline.h |  18 +++
 examples/ip_pipeline/thread.c   | 246 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 520 insertions(+)

diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index 84fcd9d..a5329cd 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -1742,6 +1742,83 @@ cmd_pipeline_port_in_table(char **tokens,
 }
 
 /**
+ * pipeline <pipeline_name> port in <port_id> stats read [clear]
+ */
+
+#define MSG_PIPELINE_PORT_IN_STATS                         \
+	"Pkts in: %" PRIu64 "\n"                           \
+	"Pkts dropped by AH: %" PRIu64 "\n"                \
+	"Pkts dropped by other: %" PRIu64 "\n"
+
+static void
+cmd_pipeline_port_in_stats(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct rte_pipeline_port_in_stats stats;
+	char *pipeline_name;
+	uint32_t port_id;
+	int clear, status;
+
+	if ((n_tokens != 7) && (n_tokens != 8)) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "port") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
+		return;
+	}
+
+	if (strcmp(tokens[3], "in") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
+		return;
+	}
+
+	if (parser_read_uint32(&port_id, tokens[4]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
+		return;
+	}
+
+	if (strcmp(tokens[5], "stats") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
+		return;
+	}
+
+	if (strcmp(tokens[6], "read") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read");
+		return;
+	}
+
+	clear = 0;
+	if (n_tokens == 8) {
+		if (strcmp(tokens[7], "clear") != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "clear");
+			return;
+		}
+
+		clear = 1;
+	}
+
+	status = pipeline_port_in_stats_read(pipeline_name,
+		port_id,
+		&stats,
+		clear);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+
+	snprintf(out, out_size, MSG_PIPELINE_PORT_IN_STATS,
+		stats.stats.n_pkts_in,
+		stats.n_pkts_dropped_by_ah,
+		stats.stats.n_pkts_drop);
+}
+
+/**
  * pipeline <pipeline_name> port in <port_id> enable
  */
 static void
@@ -1836,6 +1913,159 @@ cmd_pipeline_port_in_disable(char **tokens,
 }
 
 /**
+ * pipeline <pipeline_name> port out <port_id> stats read [clear]
+ */
+#define MSG_PIPELINE_PORT_OUT_STATS                        \
+	"Pkts in: %" PRIu64 "\n"                           \
+	"Pkts dropped by AH: %" PRIu64 "\n"                \
+	"Pkts dropped by other: %" PRIu64 "\n"
+
+static void
+cmd_pipeline_port_out_stats(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct rte_pipeline_port_out_stats stats;
+	char *pipeline_name;
+	uint32_t port_id;
+	int clear, status;
+
+	if ((n_tokens != 7) && (n_tokens != 8)) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "port") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
+		return;
+	}
+
+	if (strcmp(tokens[3], "out") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "out");
+		return;
+	}
+
+	if (parser_read_uint32(&port_id, tokens[4]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
+		return;
+	}
+
+	if (strcmp(tokens[5], "stats") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
+		return;
+	}
+
+	if (strcmp(tokens[6], "read") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read");
+		return;
+	}
+
+	clear = 0;
+	if (n_tokens == 8) {
+		if (strcmp(tokens[7], "clear") != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "clear");
+			return;
+		}
+
+		clear = 1;
+	}
+
+	status = pipeline_port_out_stats_read(pipeline_name,
+		port_id,
+		&stats,
+		clear);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+
+	snprintf(out, out_size, MSG_PIPELINE_PORT_OUT_STATS,
+		stats.stats.n_pkts_in,
+		stats.n_pkts_dropped_by_ah,
+		stats.stats.n_pkts_drop);
+}
+
+/**
+ * pipeline <pipeline_name> table <table_id> stats read [clear]
+ */
+#define MSG_PIPELINE_TABLE_STATS                                     \
+	"Pkts in: %" PRIu64 "\n"                                     \
+	"Pkts in with lookup miss: %" PRIu64 "\n"                    \
+	"Pkts in with lookup hit dropped by AH: %" PRIu64 "\n"       \
+	"Pkts in with lookup hit dropped by others: %" PRIu64 "\n"   \
+	"Pkts in with lookup miss dropped by AH: %" PRIu64 "\n"      \
+	"Pkts in with lookup miss dropped by others: %" PRIu64 "\n"
+
+static void
+cmd_pipeline_table_stats(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct rte_pipeline_table_stats stats;
+	char *pipeline_name;
+	uint32_t table_id;
+	int clear, status;
+
+	if ((n_tokens != 6) && (n_tokens != 7)) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "table") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
+		return;
+	}
+
+	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
+		return;
+	}
+
+	if (strcmp(tokens[4], "stats") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
+		return;
+	}
+
+	if (strcmp(tokens[5], "read") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read");
+		return;
+	}
+
+	clear = 0;
+	if (n_tokens == 7) {
+		if (strcmp(tokens[6], "clear") != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "clear");
+			return;
+		}
+
+		clear = 1;
+	}
+
+	status = pipeline_table_stats_read(pipeline_name,
+		table_id,
+		&stats,
+		clear);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+
+	snprintf(out, out_size, MSG_PIPELINE_TABLE_STATS,
+		stats.stats.n_pkts_in,
+		stats.stats.n_pkts_lookup_miss,
+		stats.n_pkts_dropped_by_lkp_hit_ah,
+		stats.n_pkts_dropped_lkp_hit,
+		stats.n_pkts_dropped_by_lkp_miss_ah,
+		stats.n_pkts_dropped_lkp_miss);
+}
+
+/**
  * thread <thread_id> pipeline <pipeline_name> enable
  */
 static void
@@ -2045,6 +2275,15 @@ cli_process(char *in, char *out, size_t out_size)
 		if ((n_tokens >= 6) &&
 			(strcmp(tokens[2], "port") == 0) &&
 			(strcmp(tokens[3], "in") == 0) &&
+			(strcmp(tokens[5], "stats") == 0)) {
+			cmd_pipeline_port_in_stats(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
+
+		if ((n_tokens >= 6) &&
+			(strcmp(tokens[2], "port") == 0) &&
+			(strcmp(tokens[3], "in") == 0) &&
 			(strcmp(tokens[5], "enable") == 0)) {
 			cmd_pipeline_port_in_enable(tokens, n_tokens,
 				out, out_size);
@@ -2059,6 +2298,23 @@ cli_process(char *in, char *out, size_t out_size)
 				out, out_size);
 			return;
 		}
+
+		if ((n_tokens >= 6) &&
+			(strcmp(tokens[2], "port") == 0) &&
+			(strcmp(tokens[3], "out") == 0) &&
+			(strcmp(tokens[5], "stats") == 0)) {
+			cmd_pipeline_port_out_stats(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
+
+		if ((n_tokens >= 5) &&
+			(strcmp(tokens[2], "table") == 0) &&
+			(strcmp(tokens[4], "stats") == 0)) {
+			cmd_pipeline_table_stats(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
 	}
 
 	if (strcmp(tokens[0], "thread") == 0) {
diff --git a/examples/ip_pipeline/pipeline.h b/examples/ip_pipeline/pipeline.h
index 9b79b67..9b2c295 100644
--- a/examples/ip_pipeline/pipeline.h
+++ b/examples/ip_pipeline/pipeline.h
@@ -263,6 +263,12 @@ struct table_rule_action {
 };
 
 int
+pipeline_port_in_stats_read(const char *pipeline_name,
+	uint32_t port_id,
+	struct rte_pipeline_port_in_stats *stats,
+	int clear);
+
+int
 pipeline_port_in_enable(const char *pipeline_name,
 	uint32_t port_id);
 
@@ -270,4 +276,16 @@ int
 pipeline_port_in_disable(const char *pipeline_name,
 	uint32_t port_id);
 
+int
+pipeline_port_out_stats_read(const char *pipeline_name,
+	uint32_t port_id,
+	struct rte_pipeline_port_out_stats *stats,
+	int clear);
+
+int
+pipeline_table_stats_read(const char *pipeline_name,
+	uint32_t table_id,
+	struct rte_pipeline_table_stats *stats,
+	int clear);
+
 #endif /* _INCLUDE_PIPELINE_H_ */
diff --git a/examples/ip_pipeline/thread.c b/examples/ip_pipeline/thread.c
index a47b645..a18a820 100644
--- a/examples/ip_pipeline/thread.c
+++ b/examples/ip_pipeline/thread.c
@@ -484,19 +484,64 @@ thread_msg_handle(struct thread_data *t)
  */
 enum pipeline_req_type {
 	/* Port IN */
+	PIPELINE_REQ_PORT_IN_STATS_READ,
 	PIPELINE_REQ_PORT_IN_ENABLE,
 	PIPELINE_REQ_PORT_IN_DISABLE,
 
+	/* Port OUT */
+	PIPELINE_REQ_PORT_OUT_STATS_READ,
+
+	/* Table */
+	PIPELINE_REQ_TABLE_STATS_READ,
+
 	PIPELINE_REQ_MAX
 };
 
+struct pipeline_msg_req_port_in_stats_read {
+	int clear;
+};
+
+struct pipeline_msg_req_port_out_stats_read {
+	int clear;
+};
+
+struct pipeline_msg_req_table_stats_read {
+	int clear;
+};
+
 struct pipeline_msg_req {
 	enum pipeline_req_type type;
 	uint32_t id; /* Port IN, port OUT or table ID */
+
+	RTE_STD_C11
+	union {
+		struct pipeline_msg_req_port_in_stats_read port_in_stats_read;
+		struct pipeline_msg_req_port_out_stats_read port_out_stats_read;
+		struct pipeline_msg_req_table_stats_read table_stats_read;
+	};
+};
+
+struct pipeline_msg_rsp_port_in_stats_read {
+	struct rte_pipeline_port_in_stats stats;
+};
+
+struct pipeline_msg_rsp_port_out_stats_read {
+	struct rte_pipeline_port_out_stats stats;
+};
+
+struct pipeline_msg_rsp_table_stats_read {
+	struct rte_pipeline_table_stats stats;
 };
 
 struct pipeline_msg_rsp {
 	int status;
+
+	RTE_STD_C11
+	union {
+		struct pipeline_msg_rsp_port_in_stats_read port_in_stats_read;
+		struct pipeline_msg_rsp_port_out_stats_read port_out_stats_read;
+		struct pipeline_msg_rsp_table_stats_read table_stats_read;
+	};
 };
 
 /**
@@ -540,6 +585,53 @@ pipeline_msg_send_recv(struct pipeline *p,
 }
 
 int
+pipeline_port_in_stats_read(const char *pipeline_name,
+	uint32_t port_id,
+	struct rte_pipeline_port_in_stats *stats,
+	int clear)
+{
+	struct pipeline *p;
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if ((pipeline_name == NULL) ||
+		(stats == NULL))
+		return -1;
+
+	p = pipeline_find(pipeline_name);
+	if ((p == NULL) ||
+		(port_id >= p->n_ports_in))
+		return -1;
+
+	/* Allocate request */
+	req = pipeline_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = PIPELINE_REQ_PORT_IN_STATS_READ;
+	req->id = port_id;
+	req->port_in_stats_read.clear = clear;
+
+	/* Send request and wait for response */
+	rsp = pipeline_msg_send_recv(p, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+	if (status)
+		memcpy(stats, &rsp->port_in_stats_read.stats, sizeof(*stats));
+
+	/* Free response */
+	pipeline_msg_free(rsp);
+
+	return status;
+}
+
+int
 pipeline_port_in_enable(const char *pipeline_name,
 	uint32_t port_id)
 {
@@ -621,6 +713,99 @@ pipeline_port_in_disable(const char *pipeline_name,
 	return status;
 }
 
+int
+pipeline_port_out_stats_read(const char *pipeline_name,
+	uint32_t port_id,
+	struct rte_pipeline_port_out_stats *stats,
+	int clear)
+{
+	struct pipeline *p;
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if ((pipeline_name == NULL) ||
+		(stats == NULL))
+		return -1;
+
+	p = pipeline_find(pipeline_name);
+	if ((p == NULL) ||
+		(port_id >= p->n_ports_out))
+		return -1;
+
+	/* Allocate request */
+	req = pipeline_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = PIPELINE_REQ_PORT_OUT_STATS_READ;
+	req->id = port_id;
+	req->port_out_stats_read.clear = clear;
+
+	/* Send request and wait for response */
+	rsp = pipeline_msg_send_recv(p, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+	if (status)
+		memcpy(stats, &rsp->port_out_stats_read.stats, sizeof(*stats));
+
+	/* Free response */
+	pipeline_msg_free(rsp);
+
+	return status;
+}
+
+int
+pipeline_table_stats_read(const char *pipeline_name,
+	uint32_t table_id,
+	struct rte_pipeline_table_stats *stats,
+	int clear)
+{
+	struct pipeline *p;
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if ((pipeline_name == NULL) ||
+		(stats == NULL))
+		return -1;
+
+	p = pipeline_find(pipeline_name);
+	if ((p == NULL) ||
+		(table_id >= p->n_tables))
+		return -1;
+
+	/* Allocate request */
+	req = pipeline_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = PIPELINE_REQ_TABLE_STATS_READ;
+	req->id = table_id;
+	req->table_stats_read.clear = clear;
+
+	/* Send request and wait for response */
+	rsp = pipeline_msg_send_recv(p, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+	if (status)
+		memcpy(stats, &rsp->table_stats_read.stats, sizeof(*stats));
+
+	/* Free response */
+	pipeline_msg_free(rsp);
+
+	return status;
+}
 
 /**
  * Data plane threads: message handling
@@ -650,6 +835,22 @@ pipeline_msg_send(struct rte_ring *msgq_rsp,
 }
 
 static struct pipeline_msg_rsp *
+pipeline_msg_handle_port_in_stats_read(struct pipeline_data *p,
+	struct pipeline_msg_req *req)
+{
+	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+	uint32_t port_id = req->id;
+	int clear = req->port_in_stats_read.clear;
+
+	rsp->status = rte_pipeline_port_in_stats_read(p->p,
+		port_id,
+		&rsp->port_in_stats_read.stats,
+		clear);
+
+	return rsp;
+}
+
+static struct pipeline_msg_rsp *
 pipeline_msg_handle_port_in_enable(struct pipeline_data *p,
 	struct pipeline_msg_req *req)
 {
@@ -675,6 +876,38 @@ pipeline_msg_handle_port_in_disable(struct pipeline_data *p,
 	return rsp;
 }
 
+static struct pipeline_msg_rsp *
+pipeline_msg_handle_port_out_stats_read(struct pipeline_data *p,
+	struct pipeline_msg_req *req)
+{
+	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+	uint32_t port_id = req->id;
+	int clear = req->port_out_stats_read.clear;
+
+	rsp->status = rte_pipeline_port_out_stats_read(p->p,
+		port_id,
+		&rsp->port_out_stats_read.stats,
+		clear);
+
+	return rsp;
+}
+
+static struct pipeline_msg_rsp *
+pipeline_msg_handle_table_stats_read(struct pipeline_data *p,
+	struct pipeline_msg_req *req)
+{
+	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+	uint32_t port_id = req->id;
+	int clear = req->table_stats_read.clear;
+
+	rsp->status = rte_pipeline_table_stats_read(p->p,
+		port_id,
+		&rsp->table_stats_read.stats,
+		clear);
+
+	return rsp;
+}
+
 static void
 pipeline_msg_handle(struct pipeline_data *p)
 {
@@ -687,6 +920,10 @@ pipeline_msg_handle(struct pipeline_data *p)
 			break;
 
 		switch (req->type) {
+		case PIPELINE_REQ_PORT_IN_STATS_READ:
+			rsp = pipeline_msg_handle_port_in_stats_read(p, req);
+			break;
+
 		case PIPELINE_REQ_PORT_IN_ENABLE:
 			rsp = pipeline_msg_handle_port_in_enable(p, req);
 			break;
@@ -695,6 +932,15 @@ pipeline_msg_handle(struct pipeline_data *p)
 			rsp = pipeline_msg_handle_port_in_disable(p, req);
 			break;
 
+		case PIPELINE_REQ_PORT_OUT_STATS_READ:
+			rsp = pipeline_msg_handle_port_out_stats_read(p, req);
+			break;
+
+		case PIPELINE_REQ_TABLE_STATS_READ:
+			rsp = pipeline_msg_handle_table_stats_read(p, req);
+			break;
+
+
 		default:
 			rsp = (struct pipeline_msg_rsp *) req;
 			rsp->status = -1;
-- 
2.9.3

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

* [dpdk-dev] [PATCH v2 32/44] ip_pipeline: add cli for pipeline table entries
  2018-03-12 17:25   ` [dpdk-dev] [PATCH v2 00/44] ip_pipeline: refactoring Jasvinder Singh
                       ` (30 preceding siblings ...)
  2018-03-12 17:26     ` [dpdk-dev] [PATCH v2 31/44] ip_pipeline: add cli to read pipeline port and table stats Jasvinder Singh
@ 2018-03-12 17:26     ` Jasvinder Singh
  2018-03-12 17:26     ` [dpdk-dev] [PATCH v2 33/44] ip_pipeline: add cli to delete pipeline table entry Jasvinder Singh
                       ` (11 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-12 17:26 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add commands to add pipeline table entries which contains match and
action part.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/cli.c      | 1273 +++++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/pipeline.h |   13 +
 examples/ip_pipeline/thread.c   |  749 +++++++++++++++++++++++
 3 files changed, 2035 insertions(+)

diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index a5329cd..eda04dc 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -8,6 +8,7 @@
 #include <string.h>
 
 #include <rte_common.h>
+#include <rte_cycles.h>
 
 #include "cli.h"
 #include "kni.h"
@@ -2066,6 +2067,1261 @@ cmd_pipeline_table_stats(char **tokens,
 }
 
 /**
+ * <match> ::=
+ *
+ * match
+ *    acl
+ *       priority <priority>
+ *       ipv4 | ipv6 <sa> <sa_depth> <da> <da_depth>
+ *       <sp0> <sp1> <dp0> <dp1> <proto>
+ *    | array
+ *       pos
+ *    | hash
+ *       raw <key>
+ *       | ipv4_5tuple <sa> <da> <sp> <dp> <proto>
+ *       | ipv6_5tuple <sa> <da> <sp> <dp> <proto>
+ *       | ipv4_addr <addr>
+ *       | ipv6_addr <addr>
+ *       | qinq <svlan> <cvlan>
+ *    | lpm
+ *       ipv4 | ipv6 <addr> <depth>
+ */
+struct pkt_key_qinq {
+	uint16_t ethertype_svlan;
+	uint16_t svlan;
+	uint16_t ethertype_cvlan;
+	uint16_t cvlan;
+} __attribute__((__packed__));
+
+struct pkt_key_ipv4_5tuple {
+	uint8_t time_to_live;
+	uint8_t proto;
+	uint16_t hdr_checksum;
+	uint32_t sa;
+	uint32_t da;
+	uint16_t sp;
+	uint16_t dp;
+} __attribute__((__packed__));
+
+struct pkt_key_ipv6_5tuple {
+	uint16_t payload_length;
+	uint8_t proto;
+	uint8_t hop_limit;
+	uint8_t sa[16];
+	uint8_t da[16];
+	uint16_t sp;
+	uint16_t dp;
+} __attribute__((__packed__));
+
+struct pkt_key_ipv4_addr {
+	uint32_t addr;
+} __attribute__((__packed__));
+
+struct pkt_key_ipv6_addr {
+	uint8_t addr[16];
+} __attribute__((__packed__));
+
+static uint32_t
+parse_match(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size,
+	struct table_rule_match *m)
+{
+	memset(m, 0, sizeof(*m));
+
+	if (n_tokens < 2)
+		return 0;
+
+	if (strcmp(tokens[0], "match") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match");
+		return 0;
+	}
+
+	if (strcmp(tokens[1], "acl") == 0) {
+		if (n_tokens < 14) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+			return 0;
+		}
+
+		m->match_type = TABLE_ACL;
+
+		if (strcmp(tokens[2], "priority") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "priority");
+			return 0;
+		}
+
+		if (parser_read_uint32(&m->match.acl.priority,
+			tokens[3]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "priority");
+			return 0;
+		}
+
+		if (strcmp(tokens[4], "ipv4") == 0) {
+			struct in_addr saddr, daddr;
+
+			m->match.acl.ip_version = 1;
+
+			if (parse_ipv4_addr(tokens[5], &saddr) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID, "sa");
+				return 0;
+			}
+			m->match.acl.ipv4.sa = rte_be_to_cpu_32(saddr.s_addr);
+
+			if (parse_ipv4_addr(tokens[7], &daddr) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID, "da");
+				return 0;
+			}
+			m->match.acl.ipv4.da = rte_be_to_cpu_32(daddr.s_addr);
+		} else if (strcmp(tokens[4], "ipv6") == 0) {
+			struct in6_addr saddr, daddr;
+
+			m->match.acl.ip_version = 0;
+
+			if (parse_ipv6_addr(tokens[5], &saddr) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID, "sa");
+				return 0;
+			}
+			memcpy(m->match.acl.ipv6.sa, saddr.s6_addr, 16);
+
+			if (parse_ipv6_addr(tokens[7], &daddr) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID, "da");
+				return 0;
+			}
+			memcpy(m->match.acl.ipv6.da, daddr.s6_addr, 16);
+		} else {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+				"ipv4 or ipv6");
+			return 0;
+		}
+
+		if (parser_read_uint32(&m->match.acl.sa_depth,
+			tokens[6]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "sa_depth");
+			return 0;
+		}
+
+		if (parser_read_uint32(&m->match.acl.da_depth,
+			tokens[8]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "da_depth");
+			return 0;
+		}
+
+		if (parser_read_uint16(&m->match.acl.sp0, tokens[9]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "sp0");
+			return 0;
+		}
+
+		if (parser_read_uint16(&m->match.acl.sp1, tokens[10]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "sp1");
+			return 0;
+		}
+
+		if (parser_read_uint16(&m->match.acl.dp0, tokens[11]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "dp0");
+			return 0;
+		}
+
+		if (parser_read_uint16(&m->match.acl.dp1, tokens[12]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "dp1");
+			return 0;
+		}
+
+		if (parser_read_uint8(&m->match.acl.proto, tokens[13]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "proto");
+			return 0;
+		}
+
+		m->match.acl.proto_mask = 0xff;
+
+		return 14;
+	} /* acl */
+
+	if (strcmp(tokens[1], "array") == 0) {
+		if (n_tokens < 3) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+			return 0;
+		}
+
+		m->match_type = TABLE_ARRAY;
+
+		if (parser_read_uint32(&m->match.array.pos, tokens[2]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "pos");
+			return 0;
+		}
+
+		return 3;
+	} /* array */
+
+	if (strcmp(tokens[1], "hash") == 0) {
+		if (n_tokens < 3) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+			return 0;
+		}
+
+		m->match_type = TABLE_HASH;
+
+		if (strcmp(tokens[2], "raw") == 0) {
+			uint32_t key_size = TABLE_RULE_MATCH_SIZE_MAX;
+
+			if (n_tokens < 4) {
+				snprintf(out, out_size, MSG_ARG_MISMATCH,
+					tokens[0]);
+				return 0;
+			}
+
+			if (parse_hex_string(tokens[3],
+				m->match.hash.key, &key_size) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID, "key");
+				return 0;
+			}
+
+			return 4;
+		} /* hash raw */
+
+		if (strcmp(tokens[2], "ipv4_5tuple") == 0) {
+			struct pkt_key_ipv4_5tuple *ipv4 =
+				(struct pkt_key_ipv4_5tuple *) m->match.hash.key;
+			struct in_addr saddr, daddr;
+			uint16_t sp, dp;
+			uint8_t proto;
+
+			if (n_tokens < 8) {
+				snprintf(out, out_size, MSG_ARG_MISMATCH,
+					tokens[0]);
+				return 0;
+			}
+
+			if (parse_ipv4_addr(tokens[3], &saddr) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID, "sa");
+				return 0;
+			}
+
+			if (parse_ipv4_addr(tokens[4], &daddr) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID, "da");
+				return 0;
+			}
+
+			if (parser_read_uint16(&sp, tokens[5]) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID, "sp");
+				return 0;
+			}
+
+			if (parser_read_uint16(&dp, tokens[6]) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID, "dp");
+				return 0;
+			}
+
+			if (parser_read_uint8(&proto, tokens[7]) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID,
+					"proto");
+				return 0;
+			}
+
+			ipv4->sa = saddr.s_addr;
+			ipv4->da = daddr.s_addr;
+			ipv4->sp = rte_cpu_to_be_16(sp);
+			ipv4->dp = rte_cpu_to_be_16(dp);
+			ipv4->proto = proto;
+
+			return 8;
+		} /* hash ipv4_5tuple */
+
+		if (strcmp(tokens[2], "ipv6_5tuple") == 0) {
+			struct pkt_key_ipv6_5tuple *ipv6 =
+				(struct pkt_key_ipv6_5tuple *) m->match.hash.key;
+			struct in6_addr saddr, daddr;
+			uint16_t sp, dp;
+			uint8_t proto;
+
+			if (n_tokens < 8) {
+				snprintf(out, out_size, MSG_ARG_MISMATCH,
+					tokens[0]);
+				return 0;
+			}
+
+			if (parse_ipv6_addr(tokens[3], &saddr) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID, "sa");
+				return 0;
+			}
+
+			if (parse_ipv6_addr(tokens[4], &daddr) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID, "da");
+				return 0;
+			}
+
+			if (parser_read_uint16(&sp, tokens[5]) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID, "sp");
+				return 0;
+			}
+
+			if (parser_read_uint16(&dp, tokens[6]) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID, "dp");
+				return 0;
+			}
+
+			if (parser_read_uint8(&proto, tokens[7]) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID,
+					"proto");
+				return 0;
+			}
+
+			memcpy(ipv6->sa, saddr.s6_addr, 16);
+			memcpy(ipv6->da, daddr.s6_addr, 16);
+			ipv6->sp = rte_cpu_to_be_16(sp);
+			ipv6->dp = rte_cpu_to_be_16(dp);
+			ipv6->proto = proto;
+
+			return 8;
+		} /* hash ipv6_5tuple */
+
+		if (strcmp(tokens[2], "ipv4_addr") == 0) {
+			struct pkt_key_ipv4_addr *ipv4_addr =
+				(struct pkt_key_ipv4_addr *) m->match.hash.key;
+			struct in_addr addr;
+
+			if (n_tokens < 4) {
+				snprintf(out, out_size, MSG_ARG_MISMATCH,
+					tokens[0]);
+				return 0;
+			}
+
+			if (parse_ipv4_addr(tokens[3], &addr) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID,
+					"addr");
+				return 0;
+			}
+
+			ipv4_addr->addr = addr.s_addr;
+
+			return 4;
+		} /* hash ipv4_addr */
+
+		if (strcmp(tokens[2], "ipv6_addr") == 0) {
+			struct pkt_key_ipv6_addr *ipv6_addr =
+				(struct pkt_key_ipv6_addr *) m->match.hash.key;
+			struct in6_addr addr;
+
+			if (n_tokens < 4) {
+				snprintf(out, out_size, MSG_ARG_MISMATCH,
+					tokens[0]);
+				return 0;
+			}
+
+			if (parse_ipv6_addr(tokens[3], &addr) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID,
+					"addr");
+				return 0;
+			}
+
+			memcpy(ipv6_addr->addr, addr.s6_addr, 16);
+
+			return 4;
+		} /* hash ipv6_5tuple */
+
+		if (strcmp(tokens[2], "qinq") == 0) {
+			struct pkt_key_qinq *qinq =
+				(struct pkt_key_qinq *) m->match.hash.key;
+			uint16_t svlan, cvlan;
+
+			if (n_tokens < 5) {
+				snprintf(out, out_size, MSG_ARG_MISMATCH,
+					tokens[0]);
+				return 0;
+			}
+
+			if ((parser_read_uint16(&svlan, tokens[3]) != 0) ||
+				(svlan > 0xFFF)) {
+				snprintf(out, out_size, MSG_ARG_INVALID,
+					"svlan");
+				return 0;
+			}
+
+			if ((parser_read_uint16(&cvlan, tokens[4]) != 0) ||
+				(cvlan > 0xFFF)) {
+				snprintf(out, out_size, MSG_ARG_INVALID,
+					"cvlan");
+				return 0;
+			}
+
+			qinq->svlan = rte_cpu_to_be_16(svlan);
+			qinq->cvlan = rte_cpu_to_be_16(cvlan);
+
+			return 5;
+		} /* hash qinq */
+
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return 0;
+	} /* hash */
+
+	if (strcmp(tokens[1], "lpm") == 0) {
+		if (n_tokens < 5) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+			return 0;
+		}
+
+		m->match_type = TABLE_LPM;
+
+		if (strcmp(tokens[2], "ipv4") == 0) {
+			struct in_addr addr;
+
+			m->match.lpm.ip_version = 1;
+
+			if (parse_ipv4_addr(tokens[3], &addr) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID,
+					"addr");
+				return 0;
+			}
+
+			m->match.lpm.ipv4 = rte_be_to_cpu_32(addr.s_addr);
+		} else if (strcmp(tokens[2], "ipv6") == 0) {
+			struct in6_addr addr;
+
+			m->match.lpm.ip_version = 0;
+
+			if (parse_ipv6_addr(tokens[3], &addr) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID,
+					"addr");
+				return 0;
+			}
+
+			memcpy(m->match.lpm.ipv6, addr.s6_addr, 16);
+		} else {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"ipv4 or ipv6");
+			return 0;
+		}
+
+		if (parser_read_uint8(&m->match.lpm.depth, tokens[4]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "depth");
+			return 0;
+		}
+
+		return 5;
+	} /* lpm */
+
+	snprintf(out, out_size, MSG_ARG_MISMATCH,
+		"acl or array or hash or lpm");
+	return 0;
+}
+
+/**
+ * table_action ::=
+ *
+ * action
+ *    fwd drop | port <port_id> | table <table_id>
+ *    [meter
+ *       tc0 meter <meter_profile_id> policer g <pa> y <pa> r <pa>
+ *       [tc1 meter <meter_profile_id> policer g <pa> y <pa> r <pa>
+ *        tc2 meter <meter_profile_id> policer g <pa> y <pa> r <pa>
+ *        tc3 meter <meter_profile_id> policer g <pa> y <pa> r <pa>]]
+ *    [tm subport <subport_id> pipe <pipe_id>]
+ *    [encap
+ *       ether <da> <sa>
+ *       | vlan <da> <sa> <pcp> <dei> <vid>
+ *       | qinq <da> <sa> <pcp> <dei> <vid> <pcp> <dei> <vid>
+ *       | mpls unicast | multicast
+ *          <da> <sa>
+ *          label0 <label> <tc> <ttl>
+ *          [label1 <label> <tc> <ttl>
+ *          [label2 <label> <tc> <ttl>
+ *          [label3 <label> <tc> <ttl>]]]
+ *       | pppoe <da> <sa> <session_id>]
+ *    [nat ipv4 | ipv6 <addr> <port>]
+ *    [ttl dec | keep]
+ *    [stats]
+ *    [time]
+ *
+ * where:
+ *    <pa> ::= g | y | r | drop
+ */
+static uint32_t
+parse_table_action_fwd(char **tokens,
+	uint32_t n_tokens,
+	struct table_rule_action *a)
+{
+	if ((n_tokens == 0) || (strcmp(tokens[0], "fwd") != 0))
+		return 0;
+
+	tokens++;
+	n_tokens--;
+
+	if (n_tokens && (strcmp(tokens[0], "drop") == 0)) {
+		a->fwd.action = RTE_PIPELINE_ACTION_DROP;
+		a->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
+		return 1 + 1;
+	}
+
+	if (n_tokens && (strcmp(tokens[0], "port") == 0)) {
+		uint32_t id;
+
+		if ((n_tokens < 2) ||
+			parser_read_uint32(&id, tokens[1]))
+			return 0;
+
+		a->fwd.action = RTE_PIPELINE_ACTION_PORT;
+		a->fwd.id = id;
+		a->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
+		return 1 + 2;
+	}
+
+	if (n_tokens && (strcmp(tokens[0], "table") == 0)) {
+		uint32_t id;
+
+		if ((n_tokens < 2) ||
+			parser_read_uint32(&id, tokens[1]))
+			return 0;
+
+		a->fwd.action = RTE_PIPELINE_ACTION_TABLE;
+		a->fwd.id = id;
+		a->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
+		return 1 + 2;
+	}
+
+	return 0;
+}
+
+static int
+parse_policer_action(char *token, enum rte_table_action_policer *a)
+{
+	if (strcmp(token, "g") == 0) {
+		*a = RTE_TABLE_ACTION_POLICER_COLOR_GREEN;
+		return 0;
+	}
+
+	if (strcmp(token, "y") == 0) {
+		*a = RTE_TABLE_ACTION_POLICER_COLOR_YELLOW;
+		return 0;
+	}
+
+	if (strcmp(token, "r") == 0) {
+		*a = RTE_TABLE_ACTION_POLICER_COLOR_RED;
+		return 0;
+	}
+
+	if (strcmp(token, "drop") == 0) {
+		*a = RTE_TABLE_ACTION_POLICER_DROP;
+		return 0;
+	}
+
+	return -1;
+}
+
+static uint32_t
+parse_table_action_meter_tc(char **tokens,
+	uint32_t n_tokens,
+	struct rte_table_action_mtr_tc_params *mtr)
+{
+	if ((n_tokens < 9) ||
+		strcmp(tokens[0], "meter") ||
+		parser_read_uint32(&mtr->meter_profile_id, tokens[1]) ||
+		strcmp(tokens[2], "policer") ||
+		strcmp(tokens[3], "g") ||
+		parse_policer_action(tokens[4], &mtr->policer[e_RTE_METER_GREEN]) ||
+		strcmp(tokens[5], "y") ||
+		parse_policer_action(tokens[6], &mtr->policer[e_RTE_METER_YELLOW]) ||
+		strcmp(tokens[7], "r") ||
+		parse_policer_action(tokens[8], &mtr->policer[e_RTE_METER_RED]))
+		return 0;
+
+	return 9;
+}
+
+static uint32_t
+parse_table_action_meter(char **tokens,
+	uint32_t n_tokens,
+	struct table_rule_action *a)
+{
+	if ((n_tokens == 0) || strcmp(tokens[0], "meter"))
+		return 0;
+
+	tokens++;
+	n_tokens--;
+
+	if ((n_tokens < 10) ||
+		strcmp(tokens[0], "tc0") ||
+		(parse_table_action_meter_tc(tokens + 1,
+			n_tokens - 1,
+			&a->mtr.mtr[0]) == 0))
+		return 0;
+
+	tokens += 10;
+	n_tokens -= 10;
+
+	if ((n_tokens == 0) || strcmp(tokens[0], "tc1")) {
+		a->mtr.tc_mask = 1;
+		a->action_mask |= 1 << RTE_TABLE_ACTION_MTR;
+		return 1 + 10;
+	}
+
+	if ((n_tokens < 30) ||
+		(parse_table_action_meter_tc(tokens + 1,
+			n_tokens - 1, &a->mtr.mtr[1]) == 0) ||
+		strcmp(tokens[10], "tc2") ||
+		(parse_table_action_meter_tc(tokens + 11,
+			n_tokens - 11, &a->mtr.mtr[2]) == 0) ||
+		strcmp(tokens[20], "tc3") ||
+		(parse_table_action_meter_tc(tokens + 21,
+			n_tokens - 21, &a->mtr.mtr[3]) == 0))
+		return 0;
+
+	a->mtr.tc_mask = 0xF;
+	a->action_mask |= 1 << RTE_TABLE_ACTION_MTR;
+	return 1 + 10 + 3 * 10;
+}
+
+static uint32_t
+parse_table_action_tm(char **tokens,
+	uint32_t n_tokens,
+	struct table_rule_action *a)
+{
+	uint32_t subport_id, pipe_id;
+
+	if ((n_tokens < 5) ||
+		strcmp(tokens[0], "tm") ||
+		strcmp(tokens[1], "subport") ||
+		parser_read_uint32(&subport_id, tokens[2]) ||
+		strcmp(tokens[3], "pipe") ||
+		parser_read_uint32(&pipe_id, tokens[4]))
+		return 0;
+
+	a->tm.subport_id = subport_id;
+	a->tm.pipe_id = pipe_id;
+	a->action_mask |= 1 << RTE_TABLE_ACTION_TM;
+	return 5;
+}
+
+static uint32_t
+parse_table_action_encap(char **tokens,
+	uint32_t n_tokens,
+	struct table_rule_action *a)
+{
+	if ((n_tokens == 0) || strcmp(tokens[0], "encap"))
+		return 0;
+
+	tokens++;
+	n_tokens--;
+
+	/* ether */
+	if (n_tokens && (strcmp(tokens[0], "ether") == 0)) {
+		if ((n_tokens < 3) ||
+			parse_mac_addr(tokens[1], &a->encap.ether.ether.da) ||
+			parse_mac_addr(tokens[2], &a->encap.ether.ether.sa))
+			return 0;
+
+		a->encap.type = RTE_TABLE_ACTION_ENCAP_ETHER;
+		a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
+		return 1 + 3;
+	}
+
+	/* vlan */
+	if (n_tokens && (strcmp(tokens[0], "vlan") == 0)) {
+		uint32_t pcp, dei, vid;
+
+		if ((n_tokens < 6) ||
+			parse_mac_addr(tokens[1], &a->encap.vlan.ether.da) ||
+			parse_mac_addr(tokens[2], &a->encap.vlan.ether.sa) ||
+			parser_read_uint32(&pcp, tokens[3]) ||
+			(pcp > 0x7) ||
+			parser_read_uint32(&dei, tokens[4]) ||
+			(dei > 0x1) ||
+			parser_read_uint32(&vid, tokens[5]) ||
+			(vid > 0xFFF))
+			return 0;
+
+		a->encap.vlan.vlan.pcp = pcp & 0x7;
+		a->encap.vlan.vlan.dei = dei & 0x1;
+		a->encap.vlan.vlan.vid = vid & 0xFFF;
+		a->encap.type = RTE_TABLE_ACTION_ENCAP_VLAN;
+		a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
+		return 1 + 6;
+	}
+
+	/* qinq */
+	if (n_tokens && (strcmp(tokens[0], "qinq") == 0)) {
+		uint32_t svlan_pcp, svlan_dei, svlan_vid;
+		uint32_t cvlan_pcp, cvlan_dei, cvlan_vid;
+
+		if ((n_tokens < 9) ||
+			parse_mac_addr(tokens[1], &a->encap.qinq.ether.da) ||
+			parse_mac_addr(tokens[2], &a->encap.qinq.ether.sa) ||
+			parser_read_uint32(&svlan_pcp, tokens[3]) ||
+			(svlan_pcp > 0x7) ||
+			parser_read_uint32(&svlan_dei, tokens[4]) ||
+			(svlan_dei > 0x1) ||
+			parser_read_uint32(&svlan_vid, tokens[5]) ||
+			(svlan_vid > 0xFFF) ||
+			parser_read_uint32(&cvlan_pcp, tokens[6]) ||
+			(cvlan_pcp > 0x7) ||
+			parser_read_uint32(&cvlan_dei, tokens[7]) ||
+			(cvlan_dei > 0x1) ||
+			parser_read_uint32(&cvlan_vid, tokens[8]) ||
+			(cvlan_vid > 0xFFF))
+			return 0;
+
+		a->encap.qinq.svlan.pcp = svlan_pcp & 0x7;
+		a->encap.qinq.svlan.dei = svlan_dei & 0x1;
+		a->encap.qinq.svlan.vid = svlan_vid & 0xFFF;
+		a->encap.qinq.cvlan.pcp = cvlan_pcp & 0x7;
+		a->encap.qinq.cvlan.dei = cvlan_dei & 0x1;
+		a->encap.qinq.cvlan.vid = cvlan_vid & 0xFFF;
+		a->encap.type = RTE_TABLE_ACTION_ENCAP_QINQ;
+		a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
+		return 1 + 9;
+	}
+
+	/* mpls */
+	if (n_tokens && (strcmp(tokens[0], "mpls") == 0)) {
+		uint32_t label, tc, ttl;
+
+		if (n_tokens < 8)
+			return 0;
+
+		if (strcmp(tokens[1], "unicast") == 0)
+			a->encap.mpls.unicast = 1;
+		else if (strcmp(tokens[1], "multicast") == 0)
+			a->encap.mpls.unicast = 0;
+		else
+			return 0;
+
+		if (parse_mac_addr(tokens[2], &a->encap.mpls.ether.da) ||
+			parse_mac_addr(tokens[3], &a->encap.mpls.ether.sa) ||
+			strcmp(tokens[4], "label0") ||
+			parser_read_uint32(&label, tokens[5]) ||
+			(label > 0xFFFFF) ||
+			parser_read_uint32(&tc, tokens[6]) ||
+			(tc > 0x7) ||
+			parser_read_uint32(&ttl, tokens[7]) ||
+			(ttl > 0x3F))
+			return 0;
+
+		a->encap.mpls.mpls[0].label = label;
+		a->encap.mpls.mpls[0].tc = tc;
+		a->encap.mpls.mpls[0].ttl = ttl;
+
+		tokens += 8;
+		n_tokens -= 8;
+
+		if ((n_tokens == 0) || strcmp(tokens[0], "label1")) {
+			a->encap.mpls.mpls_count = 1;
+			a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS;
+			a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
+			return 1 + 8;
+		}
+
+		if ((n_tokens < 4) ||
+			parser_read_uint32(&label, tokens[1]) ||
+			(label > 0xFFFFF) ||
+			parser_read_uint32(&tc, tokens[2]) ||
+			(tc > 0x7) ||
+			parser_read_uint32(&ttl, tokens[3]) ||
+			(ttl > 0x3F))
+			return 0;
+
+		a->encap.mpls.mpls[1].label = label;
+		a->encap.mpls.mpls[1].tc = tc;
+		a->encap.mpls.mpls[1].ttl = ttl;
+
+		tokens += 4;
+		n_tokens -= 4;
+
+		if ((n_tokens == 0) || strcmp(tokens[0], "label2")) {
+			a->encap.mpls.mpls_count = 2;
+			a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS;
+			a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
+			return 1 + 8 + 4;
+		}
+
+		if ((n_tokens < 4) ||
+			parser_read_uint32(&label, tokens[1]) ||
+			(label > 0xFFFFF) ||
+			parser_read_uint32(&tc, tokens[2]) ||
+			(tc > 0x7) ||
+			parser_read_uint32(&ttl, tokens[3]) ||
+			(ttl > 0x3F))
+			return 0;
+
+		a->encap.mpls.mpls[2].label = label;
+		a->encap.mpls.mpls[2].tc = tc;
+		a->encap.mpls.mpls[2].ttl = ttl;
+
+		tokens += 4;
+		n_tokens -= 4;
+
+		if ((n_tokens == 0) || strcmp(tokens[0], "label3")) {
+			a->encap.mpls.mpls_count = 3;
+			a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS;
+			a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
+			return 1 + 8 + 4 + 4;
+		}
+
+		if ((n_tokens < 4) ||
+			parser_read_uint32(&label, tokens[1]) ||
+			(label > 0xFFFFF) ||
+			parser_read_uint32(&tc, tokens[2]) ||
+			(tc > 0x7) ||
+			parser_read_uint32(&ttl, tokens[3]) ||
+			(ttl > 0x3F))
+			return 0;
+
+		a->encap.mpls.mpls[3].label = label;
+		a->encap.mpls.mpls[3].tc = tc;
+		a->encap.mpls.mpls[3].ttl = ttl;
+
+		a->encap.mpls.mpls_count = 4;
+		a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS;
+		a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
+		return 1 + 8 + 4 + 4 + 4;
+	}
+
+	/* pppoe */
+	if (n_tokens && (strcmp(tokens[0], "pppoe") == 0)) {
+		if ((n_tokens < 4) ||
+			parse_mac_addr(tokens[1], &a->encap.pppoe.ether.da) ||
+			parse_mac_addr(tokens[2], &a->encap.pppoe.ether.sa) ||
+			parser_read_uint16(&a->encap.pppoe.pppoe.session_id,
+				tokens[3]))
+			return 0;
+
+		a->encap.type = RTE_TABLE_ACTION_ENCAP_PPPOE;
+		a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
+		return 1 + 4;
+	}
+
+	return 0;
+}
+
+static uint32_t
+parse_table_action_nat(char **tokens,
+	uint32_t n_tokens,
+	struct table_rule_action *a)
+{
+	if ((n_tokens < 4) ||
+		strcmp(tokens[0], "nat"))
+		return 0;
+
+	if (strcmp(tokens[1], "ipv4") == 0) {
+		struct in_addr addr;
+		uint16_t port;
+
+		if (parse_ipv4_addr(tokens[2], &addr) ||
+			parser_read_uint16(&port, tokens[3]))
+			return 0;
+
+		a->nat.ip_version = 1;
+		a->nat.addr.ipv4 = rte_be_to_cpu_32(addr.s_addr);
+		a->nat.port = port;
+		a->action_mask |= 1 << RTE_TABLE_ACTION_NAT;
+		return 4;
+	}
+
+	if (strcmp(tokens[1], "ipv6") == 0) {
+		struct in6_addr addr;
+		uint16_t port;
+
+		if (parse_ipv6_addr(tokens[2], &addr) ||
+			parser_read_uint16(&port, tokens[3]))
+			return 0;
+
+		a->nat.ip_version = 0;
+		memcpy(a->nat.addr.ipv6, addr.s6_addr, 16);
+		a->nat.port = port;
+		a->action_mask |= 1 << RTE_TABLE_ACTION_NAT;
+		return 4;
+	}
+
+	return 0;
+}
+
+static uint32_t
+parse_table_action_ttl(char **tokens,
+	uint32_t n_tokens,
+	struct table_rule_action *a)
+{
+	if ((n_tokens < 2) ||
+		strcmp(tokens[0], "ttl"))
+		return 0;
+
+	if (strcmp(tokens[1], "dec") == 0)
+		a->ttl.decrement = 1;
+	else if (strcmp(tokens[1], "keep") == 0)
+		a->ttl.decrement = 0;
+	else
+		return 0;
+
+	a->action_mask |= 1 << RTE_TABLE_ACTION_TTL;
+	return 2;
+}
+
+static uint32_t
+parse_table_action_stats(char **tokens,
+	uint32_t n_tokens,
+	struct table_rule_action *a)
+{
+	if ((n_tokens < 1) ||
+		strcmp(tokens[0], "stats"))
+		return 0;
+
+	a->stats.n_packets = 0;
+	a->stats.n_bytes = 0;
+	a->action_mask |= 1 << RTE_TABLE_ACTION_STATS;
+	return 1;
+}
+
+static uint32_t
+parse_table_action_time(char **tokens,
+	uint32_t n_tokens,
+	struct table_rule_action *a)
+{
+	if ((n_tokens < 1) ||
+		strcmp(tokens[0], "time"))
+		return 0;
+
+	a->time.time = rte_rdtsc();
+	a->action_mask |= 1 << RTE_TABLE_ACTION_TIME;
+	return 1;
+}
+
+static uint32_t
+parse_table_action(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size,
+	struct table_rule_action *a)
+{
+	uint32_t n_tokens0 = n_tokens;
+
+	memset(a, 0, sizeof(*a));
+
+	if ((n_tokens < 2) ||
+		strcmp(tokens[0], "action"))
+		return 0;
+
+	tokens++;
+	n_tokens--;
+
+	if (n_tokens && (strcmp(tokens[0], "fwd") == 0)) {
+		uint32_t n;
+
+		n = parse_table_action_fwd(tokens, n_tokens, a);
+		if (n == 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID,
+				"action fwd");
+			return 0;
+		}
+
+		tokens += n;
+		n_tokens -= n;
+	}
+
+	if (n_tokens && (strcmp(tokens[0], "meter") == 0)) {
+		uint32_t n;
+
+		n = parse_table_action_meter(tokens, n_tokens, a);
+		if (n == 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID,
+				"action meter");
+			return 0;
+		}
+
+		tokens += n;
+		n_tokens -= n;
+	}
+
+	if (n_tokens && (strcmp(tokens[0], "tm") == 0)) {
+		uint32_t n;
+
+		n = parse_table_action_tm(tokens, n_tokens, a);
+		if (n == 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID,
+				"action tm");
+			return 0;
+		}
+
+		tokens += n;
+		n_tokens -= n;
+	}
+
+	if (n_tokens && (strcmp(tokens[0], "encap") == 0)) {
+		uint32_t n;
+
+		n = parse_table_action_encap(tokens, n_tokens, a);
+		if (n == 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID,
+				"action encap");
+			return 0;
+		}
+
+		tokens += n;
+		n_tokens -= n;
+	}
+
+	if (n_tokens && (strcmp(tokens[0], "nat") == 0)) {
+		uint32_t n;
+
+		n = parse_table_action_nat(tokens, n_tokens, a);
+		if (n == 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID,
+				"action nat");
+			return 0;
+		}
+
+		tokens += n;
+		n_tokens -= n;
+	}
+
+	if (n_tokens && (strcmp(tokens[0], "ttl") == 0)) {
+		uint32_t n;
+
+		n = parse_table_action_ttl(tokens, n_tokens, a);
+		if (n == 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID,
+				"action ttl");
+			return 0;
+		}
+
+		tokens += n;
+		n_tokens -= n;
+	}
+
+	if (n_tokens && (strcmp(tokens[0], "stats") == 0)) {
+		uint32_t n;
+
+		n = parse_table_action_stats(tokens, n_tokens, a);
+		if (n == 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID,
+				"action stats");
+			return 0;
+		}
+
+		tokens += n;
+		n_tokens -= n;
+	}
+
+	if (n_tokens && (strcmp(tokens[0], "time") == 0)) {
+		uint32_t n;
+
+		n = parse_table_action_time(tokens, n_tokens, a);
+		if (n == 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID,
+				"action time");
+			return 0;
+		}
+
+		tokens += n;
+		n_tokens -= n;
+	}
+
+	if (n_tokens0 - n_tokens == 1) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "action");
+		return 0;
+	}
+
+	return n_tokens0 - n_tokens;
+}
+
+/**
+ * pipeline <pipeline_name> table <table_id> rule add
+ *    match <match>
+ *    action <table_action>
+ */
+static void
+cmd_pipeline_table_rule_add(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct table_rule_match m;
+	struct table_rule_action a;
+	char *pipeline_name;
+	void *data;
+	uint32_t table_id, t0, n_tokens_parsed;
+	int status;
+
+	if (n_tokens < 8) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "table") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
+		return;
+	}
+
+	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
+		return;
+	}
+
+	if (strcmp(tokens[4], "rule") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
+		return;
+	}
+
+	if (strcmp(tokens[5], "add") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
+		return;
+	}
+
+	t0 = 6;
+
+	/* match */
+	n_tokens_parsed = parse_match(tokens + t0,
+		n_tokens - t0,
+		out,
+		out_size,
+		&m);
+	if (n_tokens_parsed == 0)
+		return;
+	t0 += n_tokens_parsed;
+
+	/* action */
+	n_tokens_parsed = parse_table_action(tokens + t0,
+		n_tokens - t0,
+		out,
+		out_size,
+		&a);
+	if (n_tokens_parsed == 0)
+		return;
+	t0 += n_tokens_parsed;
+
+	if (t0 != n_tokens) {
+		snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
+		return;
+	}
+
+	status = pipeline_table_rule_add(pipeline_name, table_id,
+		&m, &a, &data);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
+ * pipeline <pipeline_name> table <table_id> rule add
+ *    match
+ *       default
+ *    action
+ *       fwd drop | port <port_id> | table <table_id>
+ */
+static void
+cmd_pipeline_table_rule_add_default(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct table_rule_action action;
+	void *data;
+	char *pipeline_name;
+	uint32_t table_id;
+	int status;
+
+	if ((n_tokens != 11) && (n_tokens != 12)) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "table") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
+		return;
+	}
+
+	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
+		return;
+	}
+
+	if (strcmp(tokens[4], "rule") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
+		return;
+	}
+
+	if (strcmp(tokens[5], "add") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
+		return;
+	}
+
+	if (strcmp(tokens[6], "match") != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "match");
+		return;
+	}
+
+	if (strcmp(tokens[7], "default") != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "default");
+		return;
+	}
+
+	if (strcmp(tokens[8], "action") != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "action");
+		return;
+	}
+
+	if (strcmp(tokens[9], "fwd") != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "fwd");
+		return;
+	}
+
+	action.action_mask = 1 << RTE_TABLE_ACTION_FWD;
+
+	if (strcmp(tokens[10], "drop") == 0) {
+		if (n_tokens != 11) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+			return;
+		}
+
+		action.fwd.action = RTE_PIPELINE_ACTION_DROP;
+	} else if (strcmp(tokens[10], "port") == 0) {
+		uint32_t id;
+
+		if (n_tokens != 12) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+			return;
+		}
+
+		if (parser_read_uint32(&id, tokens[11]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
+			return;
+		}
+
+		action.fwd.action = RTE_PIPELINE_ACTION_PORT;
+		action.fwd.id = id;
+	} else if (strcmp(tokens[10], "table") == 0) {
+		uint32_t id;
+
+		if (n_tokens != 12) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+			return;
+		}
+
+		if (parser_read_uint32(&id, tokens[11]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
+			return;
+		}
+
+		action.fwd.action = RTE_PIPELINE_ACTION_TABLE;
+		action.fwd.id = id;
+	} else {
+		snprintf(out, out_size, MSG_ARG_INVALID,
+			"drop or port or table");
+		return;
+	}
+
+	status = pipeline_table_rule_add_default(pipeline_name,
+		table_id,
+		&action,
+		&data);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
  * thread <thread_id> pipeline <pipeline_name> enable
  */
 static void
@@ -2315,6 +3571,23 @@ cli_process(char *in, char *out, size_t out_size)
 				out, out_size);
 			return;
 		}
+
+		if ((n_tokens >= 7) &&
+			(strcmp(tokens[2], "table") == 0) &&
+			(strcmp(tokens[4], "rule") == 0) &&
+			(strcmp(tokens[5], "add") == 0) &&
+			(strcmp(tokens[6], "match") == 0)) {
+			if ((n_tokens >= 8) &&
+				(strcmp(tokens[7], "default") == 0)) {
+				cmd_pipeline_table_rule_add_default(tokens,
+					n_tokens, out, out_size);
+				return;
+			}
+
+			cmd_pipeline_table_rule_add(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
 	}
 
 	if (strcmp(tokens[0], "thread") == 0) {
diff --git a/examples/ip_pipeline/pipeline.h b/examples/ip_pipeline/pipeline.h
index 9b2c295..9351024 100644
--- a/examples/ip_pipeline/pipeline.h
+++ b/examples/ip_pipeline/pipeline.h
@@ -288,4 +288,17 @@ pipeline_table_stats_read(const char *pipeline_name,
 	struct rte_pipeline_table_stats *stats,
 	int clear);
 
+int
+pipeline_table_rule_add(const char *pipeline_name,
+	uint32_t table_id,
+	struct table_rule_match *match,
+	struct table_rule_action *action,
+	void **data);
+
+int
+pipeline_table_rule_add_default(const char *pipeline_name,
+	uint32_t table_id,
+	struct table_rule_action *action,
+	void **data);
+
 #endif /* _INCLUDE_PIPELINE_H_ */
diff --git a/examples/ip_pipeline/thread.c b/examples/ip_pipeline/thread.c
index a18a820..be12d20 100644
--- a/examples/ip_pipeline/thread.c
+++ b/examples/ip_pipeline/thread.c
@@ -493,6 +493,8 @@ enum pipeline_req_type {
 
 	/* Table */
 	PIPELINE_REQ_TABLE_STATS_READ,
+	PIPELINE_REQ_TABLE_RULE_ADD,
+	PIPELINE_REQ_TABLE_RULE_ADD_DEFAULT,
 
 	PIPELINE_REQ_MAX
 };
@@ -509,6 +511,15 @@ struct pipeline_msg_req_table_stats_read {
 	int clear;
 };
 
+struct pipeline_msg_req_table_rule_add {
+	struct table_rule_match match;
+	struct table_rule_action action;
+};
+
+struct pipeline_msg_req_table_rule_add_default {
+	struct table_rule_action action;
+};
+
 struct pipeline_msg_req {
 	enum pipeline_req_type type;
 	uint32_t id; /* Port IN, port OUT or table ID */
@@ -518,6 +529,8 @@ struct pipeline_msg_req {
 		struct pipeline_msg_req_port_in_stats_read port_in_stats_read;
 		struct pipeline_msg_req_port_out_stats_read port_out_stats_read;
 		struct pipeline_msg_req_table_stats_read table_stats_read;
+		struct pipeline_msg_req_table_rule_add table_rule_add;
+		struct pipeline_msg_req_table_rule_add_default table_rule_add_default;
 	};
 };
 
@@ -533,6 +546,14 @@ struct pipeline_msg_rsp_table_stats_read {
 	struct rte_pipeline_table_stats stats;
 };
 
+struct pipeline_msg_rsp_table_rule_add {
+	void *data;
+};
+
+struct pipeline_msg_rsp_table_rule_add_default {
+	void *data;
+};
+
 struct pipeline_msg_rsp {
 	int status;
 
@@ -541,6 +562,8 @@ struct pipeline_msg_rsp {
 		struct pipeline_msg_rsp_port_in_stats_read port_in_stats_read;
 		struct pipeline_msg_rsp_port_out_stats_read port_out_stats_read;
 		struct pipeline_msg_rsp_table_stats_read table_stats_read;
+		struct pipeline_msg_rsp_table_rule_add table_rule_add;
+		struct pipeline_msg_rsp_table_rule_add_default table_rule_add_default;
 	};
 };
 
@@ -807,6 +830,270 @@ pipeline_table_stats_read(const char *pipeline_name,
 	return status;
 }
 
+static int
+match_check(struct table_rule_match *match,
+	struct pipeline *p,
+	uint32_t table_id)
+{
+	struct table *table;
+
+	if ((match == NULL) ||
+		(p == NULL) ||
+		(table_id >= p->n_tables))
+		return -1;
+
+	table = &p->table[table_id];
+	if (match->match_type != table->params.match_type)
+		return -1;
+
+	switch (match->match_type) {
+	case TABLE_ACL:
+	{
+		struct table_acl_params *t = &table->params.match.acl;
+		struct table_rule_match_acl *r = &match->match.acl;
+
+		if ((r->ip_version && (t->ip_version == 0)) ||
+			((r->ip_version == 0) && t->ip_version))
+			return -1;
+
+		if (r->ip_version) {
+			if ((r->sa_depth > 32) ||
+				(r->da_depth > 32))
+				return -1;
+		} else {
+			if ((r->sa_depth > 128) ||
+				(r->da_depth > 128))
+				return -1;
+		}
+		return 0;
+	}
+
+	case TABLE_ARRAY:
+		return 0;
+
+	case TABLE_HASH:
+		return 0;
+
+	case TABLE_LPM:
+	{
+		struct table_lpm_params *t = &table->params.match.lpm;
+		struct table_rule_match_lpm *r = &match->match.lpm;
+
+		if ((r->ip_version && (t->key_size != 4)) ||
+			((r->ip_version == 0) && (t->key_size != 16)))
+			return -1;
+
+		if (r->ip_version) {
+			if (r->depth > 32)
+				return -1;
+		} else {
+			if (r->depth > 128)
+				return -1;
+		}
+		return 0;
+	}
+
+	case TABLE_STUB:
+		return -1;
+
+	default:
+		return -1;
+	}
+}
+
+static int
+action_check(struct table_rule_action *action,
+	struct pipeline *p,
+	uint32_t table_id)
+{
+	struct table_action_profile *ap;
+
+	if ((action == NULL) ||
+		(p == NULL) ||
+		(table_id >= p->n_tables))
+		return -1;
+
+	ap = p->table[table_id].ap;
+	if (action->action_mask != ap->params.action_mask)
+		return -1;
+
+	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_FWD)) {
+		if ((action->fwd.action == RTE_PIPELINE_ACTION_PORT) &&
+			(action->fwd.id >= p->n_ports_out))
+			return -1;
+
+		if ((action->fwd.action == RTE_PIPELINE_ACTION_TABLE) &&
+			(action->fwd.id >= p->n_tables))
+			return -1;
+	}
+
+	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) {
+		uint32_t tc_mask0 = (1 << ap->params.mtr.n_tc) - 1;
+		uint32_t tc_mask1 = action->mtr.tc_mask;
+
+		if (tc_mask1 != tc_mask0)
+			return -1;
+	}
+
+	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_TM)) {
+		uint32_t n_subports_per_port =
+			ap->params.tm.n_subports_per_port;
+		uint32_t n_pipes_per_subport =
+			ap->params.tm.n_pipes_per_subport;
+		uint32_t subport_id = action->tm.subport_id;
+		uint32_t pipe_id = action->tm.pipe_id;
+
+		if ((subport_id >= n_subports_per_port) ||
+			(pipe_id >= n_pipes_per_subport))
+			return -1;
+	}
+
+	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_ENCAP)) {
+		uint64_t encap_mask = ap->params.encap.encap_mask;
+		enum rte_table_action_encap_type type = action->encap.type;
+
+		if ((encap_mask & (1LLU << type)) == 0)
+			return -1;
+	}
+
+	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_NAT)) {
+		int ip_version0 = ap->params.common.ip_version;
+		int ip_version1 = action->nat.ip_version;
+
+		if ((ip_version1 && (ip_version0 == 0)) ||
+			((ip_version1 == 0) && ip_version0))
+			return -1;
+	}
+
+	return 0;
+}
+
+static int
+action_default_check(struct table_rule_action *action,
+	struct pipeline *p,
+	uint32_t table_id)
+{
+	if ((action == NULL) ||
+		(action->action_mask != (1LLU << RTE_TABLE_ACTION_FWD)) ||
+		(p == NULL) ||
+		(table_id >= p->n_tables))
+		return -1;
+
+	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_FWD)) {
+		if ((action->fwd.action == RTE_PIPELINE_ACTION_PORT) &&
+			(action->fwd.id >= p->n_ports_out))
+			return -1;
+
+		if ((action->fwd.action == RTE_PIPELINE_ACTION_TABLE) &&
+			(action->fwd.id >= p->n_tables))
+			return -1;
+	}
+
+	return 0;
+}
+
+int
+pipeline_table_rule_add(const char *pipeline_name,
+	uint32_t table_id,
+	struct table_rule_match *match,
+	struct table_rule_action *action,
+	void **data)
+{
+	struct pipeline *p;
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if ((pipeline_name == NULL) ||
+		(match == NULL) ||
+		(action == NULL) ||
+		(data == NULL))
+		return -1;
+
+	p = pipeline_find(pipeline_name);
+	if ((p == NULL) ||
+		(table_id >= p->n_tables) ||
+		match_check(match, p, table_id) ||
+		action_check(action, p, table_id))
+		return -1;
+
+	/* Allocate request */
+	req = pipeline_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = PIPELINE_REQ_TABLE_RULE_ADD;
+	req->id = table_id;
+	memcpy(&req->table_rule_add.match, match, sizeof(*match));
+	memcpy(&req->table_rule_add.action, action, sizeof(*action));
+
+	/* Send request and wait for response */
+	rsp = pipeline_msg_send_recv(p, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+	if (status == 0)
+		*data = rsp->table_rule_add.data;
+
+	/* Free response */
+	pipeline_msg_free(rsp);
+
+	return status;
+}
+
+int
+pipeline_table_rule_add_default(const char *pipeline_name,
+	uint32_t table_id,
+	struct table_rule_action *action,
+	void **data)
+{
+	struct pipeline *p;
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if ((pipeline_name == NULL) ||
+		(action == NULL) ||
+		(data == NULL))
+		return -1;
+
+	p = pipeline_find(pipeline_name);
+	if ((p == NULL) ||
+		(table_id >= p->n_tables) ||
+		action_default_check(action, p, table_id))
+		return -1;
+
+	/* Allocate request */
+	req = pipeline_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = PIPELINE_REQ_TABLE_RULE_ADD_DEFAULT;
+	req->id = table_id;
+	memcpy(&req->table_rule_add_default.action, action, sizeof(*action));
+
+	/* Send request and wait for response */
+	rsp = pipeline_msg_send_recv(p, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+	if (status == 0)
+		*data = rsp->table_rule_add_default.data;
+
+	/* Free response */
+	pipeline_msg_free(rsp);
+
+	return status;
+}
+
 /**
  * Data plane threads: message handling
  */
@@ -908,6 +1195,461 @@ pipeline_msg_handle_table_stats_read(struct pipeline_data *p,
 	return rsp;
 }
 
+union table_rule_match_low_level {
+	struct rte_table_acl_rule_add_params acl_add;
+	struct rte_table_acl_rule_delete_params acl_delete;
+	struct rte_table_array_key array;
+	uint8_t hash[TABLE_RULE_MATCH_SIZE_MAX];
+	struct rte_table_lpm_key lpm_ipv4;
+	struct rte_table_lpm_ipv6_key lpm_ipv6;
+};
+
+static int
+match_convert_ipv6_depth(uint32_t depth, uint32_t *depth32)
+{
+	if (depth > 128)
+		return -1;
+
+	switch (depth / 32) {
+	case 0:
+		depth32[0] = depth;
+		depth32[1] = 0;
+		depth32[2] = 0;
+		depth32[3] = 0;
+		return 0;
+
+	case 1:
+		depth32[0] = 32;
+		depth32[1] = depth - 32;
+		depth32[2] = 0;
+		depth32[3] = 0;
+		return 0;
+
+	case 2:
+		depth32[0] = 32;
+		depth32[1] = 32;
+		depth32[2] = depth - 64;
+		depth32[3] = 0;
+		return 0;
+
+	case 3:
+		depth32[0] = 32;
+		depth32[1] = 32;
+		depth32[2] = 32;
+		depth32[3] = depth - 96;
+		return 0;
+
+	case 4:
+		depth32[0] = 32;
+		depth32[1] = 32;
+		depth32[2] = 32;
+		depth32[3] = 32;
+		return 0;
+
+	default:
+		return -1;
+	}
+}
+
+static int
+match_convert(struct table_rule_match *mh,
+	union table_rule_match_low_level *ml,
+	int add)
+{
+	memset(ml, 0, sizeof(*ml));
+
+	switch (mh->match_type) {
+	case TABLE_ACL:
+		if (mh->match.acl.ip_version)
+			if (add) {
+				ml->acl_add.field_value[0].value.u8 =
+					mh->match.acl.proto;
+				ml->acl_add.field_value[0].mask_range.u8 =
+					mh->match.acl.proto_mask;
+
+				ml->acl_add.field_value[1].value.u32 =
+					mh->match.acl.ipv4.sa;
+				ml->acl_add.field_value[1].mask_range.u32 =
+					mh->match.acl.sa_depth;
+
+				ml->acl_add.field_value[2].value.u32 =
+					mh->match.acl.ipv4.da;
+				ml->acl_add.field_value[2].mask_range.u32 =
+					mh->match.acl.da_depth;
+
+				ml->acl_add.field_value[3].value.u16 =
+					mh->match.acl.sp0;
+				ml->acl_add.field_value[3].mask_range.u16 =
+					mh->match.acl.sp1;
+
+				ml->acl_add.field_value[4].value.u16 =
+					mh->match.acl.dp0;
+				ml->acl_add.field_value[4].mask_range.u16 =
+					mh->match.acl.dp1;
+
+				ml->acl_add.priority =
+					(int32_t) mh->match.acl.priority;
+			} else {
+				ml->acl_delete.field_value[0].value.u8 =
+					mh->match.acl.proto;
+				ml->acl_delete.field_value[0].mask_range.u8 =
+					mh->match.acl.proto_mask;
+
+				ml->acl_delete.field_value[1].value.u32 =
+					mh->match.acl.ipv4.sa;
+				ml->acl_delete.field_value[1].mask_range.u32 =
+					mh->match.acl.sa_depth;
+
+				ml->acl_delete.field_value[2].value.u32 =
+					mh->match.acl.ipv4.da;
+				ml->acl_delete.field_value[2].mask_range.u32 =
+					mh->match.acl.da_depth;
+
+				ml->acl_delete.field_value[3].value.u16 =
+					mh->match.acl.sp0;
+				ml->acl_delete.field_value[3].mask_range.u16 =
+					mh->match.acl.sp1;
+
+				ml->acl_delete.field_value[4].value.u16 =
+					mh->match.acl.dp0;
+				ml->acl_delete.field_value[4].mask_range.u16 =
+					mh->match.acl.dp1;
+			}
+		else
+			if (add) {
+				uint32_t *sa32 =
+					(uint32_t *) mh->match.acl.ipv6.sa;
+				uint32_t *da32 =
+					(uint32_t *) mh->match.acl.ipv6.da;
+				uint32_t sa32_depth[4], da32_depth[4];
+				int status;
+
+				status = match_convert_ipv6_depth(
+					mh->match.acl.sa_depth,
+					sa32_depth);
+				if (status)
+					return status;
+
+				status = match_convert_ipv6_depth(
+					mh->match.acl.da_depth,
+					da32_depth);
+				if (status)
+					return status;
+
+				ml->acl_add.field_value[0].value.u8 =
+					mh->match.acl.proto;
+				ml->acl_add.field_value[0].mask_range.u8 =
+					mh->match.acl.proto_mask;
+
+				ml->acl_add.field_value[1].value.u32 = sa32[0];
+				ml->acl_add.field_value[1].mask_range.u32 =
+					sa32_depth[0];
+				ml->acl_add.field_value[2].value.u32 = sa32[1];
+				ml->acl_add.field_value[2].mask_range.u32 =
+					sa32_depth[1];
+				ml->acl_add.field_value[3].value.u32 = sa32[2];
+				ml->acl_add.field_value[3].mask_range.u32 =
+					sa32_depth[2];
+				ml->acl_add.field_value[4].value.u32 = sa32[3];
+				ml->acl_add.field_value[4].mask_range.u32 =
+					sa32_depth[3];
+
+				ml->acl_add.field_value[5].value.u32 = da32[0];
+				ml->acl_add.field_value[5].mask_range.u32 =
+					da32_depth[0];
+				ml->acl_add.field_value[6].value.u32 = da32[1];
+				ml->acl_add.field_value[6].mask_range.u32 =
+					da32_depth[1];
+				ml->acl_add.field_value[7].value.u32 = da32[2];
+				ml->acl_add.field_value[7].mask_range.u32 =
+					da32_depth[2];
+				ml->acl_add.field_value[8].value.u32 = da32[3];
+				ml->acl_add.field_value[8].mask_range.u32 =
+					da32_depth[3];
+
+				ml->acl_add.field_value[9].value.u16 =
+					mh->match.acl.sp0;
+				ml->acl_add.field_value[9].mask_range.u16 =
+					mh->match.acl.sp1;
+
+				ml->acl_add.field_value[10].value.u16 =
+					mh->match.acl.dp0;
+				ml->acl_add.field_value[10].mask_range.u16 =
+					mh->match.acl.dp1;
+
+				ml->acl_add.priority =
+					(int32_t) mh->match.acl.priority;
+			} else {
+				uint32_t *sa32 =
+					(uint32_t *) mh->match.acl.ipv6.sa;
+				uint32_t *da32 =
+					(uint32_t *) mh->match.acl.ipv6.da;
+				uint32_t sa32_depth[4], da32_depth[4];
+				int status;
+
+				status = match_convert_ipv6_depth(
+					mh->match.acl.sa_depth,
+					sa32_depth);
+				if (status)
+					return status;
+
+				status = match_convert_ipv6_depth(
+					mh->match.acl.da_depth,
+					da32_depth);
+				if (status)
+					return status;
+
+				ml->acl_delete.field_value[0].value.u8 =
+					mh->match.acl.proto;
+				ml->acl_delete.field_value[0].mask_range.u8 =
+					mh->match.acl.proto_mask;
+
+				ml->acl_delete.field_value[1].value.u32 =
+					sa32[0];
+				ml->acl_delete.field_value[1].mask_range.u32 =
+					sa32_depth[0];
+				ml->acl_delete.field_value[2].value.u32 =
+					sa32[1];
+				ml->acl_delete.field_value[2].mask_range.u32 =
+					sa32_depth[1];
+				ml->acl_delete.field_value[3].value.u32 =
+					sa32[2];
+				ml->acl_delete.field_value[3].mask_range.u32 =
+					sa32_depth[2];
+				ml->acl_delete.field_value[4].value.u32 =
+					sa32[3];
+				ml->acl_delete.field_value[4].mask_range.u32 =
+					sa32_depth[3];
+
+				ml->acl_delete.field_value[5].value.u32 =
+					da32[0];
+				ml->acl_delete.field_value[5].mask_range.u32 =
+					da32_depth[0];
+				ml->acl_delete.field_value[6].value.u32 =
+					da32[1];
+				ml->acl_delete.field_value[6].mask_range.u32 =
+					da32_depth[1];
+				ml->acl_delete.field_value[7].value.u32 =
+					da32[2];
+				ml->acl_delete.field_value[7].mask_range.u32 =
+					da32_depth[2];
+				ml->acl_delete.field_value[8].value.u32 =
+					da32[3];
+				ml->acl_delete.field_value[8].mask_range.u32 =
+					da32_depth[3];
+
+				ml->acl_delete.field_value[9].value.u16 =
+					mh->match.acl.sp0;
+				ml->acl_delete.field_value[9].mask_range.u16 =
+					mh->match.acl.sp1;
+
+				ml->acl_delete.field_value[10].value.u16 =
+					mh->match.acl.dp0;
+				ml->acl_delete.field_value[10].mask_range.u16 =
+					mh->match.acl.dp1;
+			}
+		return 0;
+
+	case TABLE_ARRAY:
+		ml->array.pos = mh->match.array.pos;
+		return 0;
+
+	case TABLE_HASH:
+		memcpy(ml->hash, mh->match.hash.key, sizeof(ml->hash));
+		return 0;
+
+	case TABLE_LPM:
+		if (mh->match.lpm.ip_version) {
+			ml->lpm_ipv4.ip = mh->match.lpm.ipv4;
+			ml->lpm_ipv4.depth = mh->match.lpm.depth;
+		} else {
+			memcpy(ml->lpm_ipv6.ip,
+				mh->match.lpm.ipv6, sizeof(ml->lpm_ipv6.ip));
+			ml->lpm_ipv6.depth = mh->match.lpm.depth;
+		}
+
+		return 0;
+
+	default:
+		return -1;
+	}
+}
+
+static struct pipeline_msg_rsp *
+pipeline_msg_handle_table_rule_add(struct pipeline_data *p,
+	struct pipeline_msg_req *req)
+{
+	union table_rule_match_low_level match_ll;
+	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+	struct table_rule_match *match = &req->table_rule_add.match;
+	struct table_rule_action *action = &req->table_rule_add.action;
+	struct rte_pipeline_table_entry *data_in, *data_out;
+	uint32_t table_id = req->id;
+	int key_found, status;
+	struct rte_table_action *a = p->table_data[table_id].a;
+
+	/* Apply actions */
+	memset(p->buffer, 0, sizeof(p->buffer));
+	data_in = (struct rte_pipeline_table_entry *) p->buffer;
+
+	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_FWD)) {
+		status = rte_table_action_apply(a,
+			data_in,
+			RTE_TABLE_ACTION_FWD,
+			&action->fwd);
+
+		if (status) {
+			rsp->status = -1;
+			return rsp;
+		}
+	}
+
+	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) {
+		status = rte_table_action_apply(a,
+			data_in,
+			RTE_TABLE_ACTION_MTR,
+			&action->mtr);
+
+		if (status) {
+			rsp->status = -1;
+			return rsp;
+		}
+	}
+
+	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_TM)) {
+		status = rte_table_action_apply(a,
+			data_in,
+			RTE_TABLE_ACTION_TM,
+			&action->tm);
+
+		if (status) {
+			rsp->status = -1;
+			return rsp;
+		}
+	}
+
+	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_ENCAP)) {
+		status = rte_table_action_apply(a,
+			data_in,
+			RTE_TABLE_ACTION_ENCAP,
+			&action->encap);
+
+		if (status) {
+			rsp->status = -1;
+			return rsp;
+		}
+	}
+
+	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_NAT)) {
+		status = rte_table_action_apply(a,
+			data_in,
+			RTE_TABLE_ACTION_NAT,
+			&action->nat);
+
+		if (status) {
+			rsp->status = -1;
+			return rsp;
+		}
+	}
+
+	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_TTL)) {
+		status = rte_table_action_apply(a,
+			data_in,
+			RTE_TABLE_ACTION_TTL,
+			&action->ttl);
+
+		if (status) {
+			rsp->status = -1;
+			return rsp;
+		}
+	}
+
+	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_STATS)) {
+		status = rte_table_action_apply(a,
+			data_in,
+			RTE_TABLE_ACTION_STATS,
+			&action->stats);
+
+		if (status) {
+			rsp->status = -1;
+			return rsp;
+		}
+	}
+
+	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_TIME)) {
+		status = rte_table_action_apply(a,
+			data_in,
+			RTE_TABLE_ACTION_TIME,
+			&action->time);
+
+		if (status) {
+			rsp->status = -1;
+			return rsp;
+		}
+	}
+
+	/* Add rule (match, action) to table */
+	status = match_convert(match, &match_ll, 1);
+	if (status) {
+		rsp->status = -1;
+		return rsp;
+	}
+
+	status = rte_pipeline_table_entry_add(p->p,
+		table_id,
+		&match_ll,
+		data_in,
+		&key_found,
+		&data_out);
+	if (status) {
+		rsp->status = -1;
+		return rsp;
+	}
+
+	/* Write response */
+	rsp->status = 0;
+	rsp->table_rule_add.data = data_out;
+
+	return rsp;
+}
+
+static struct pipeline_msg_rsp *
+pipeline_msg_handle_table_rule_add_default(struct pipeline_data *p,
+	struct pipeline_msg_req *req)
+{
+	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+	struct table_rule_action *action = &req->table_rule_add_default.action;
+	struct rte_pipeline_table_entry *data_in, *data_out;
+	uint32_t table_id = req->id;
+	int status;
+
+	/* Apply actions */
+	memset(p->buffer, 0, sizeof(p->buffer));
+	data_in = (struct rte_pipeline_table_entry *) p->buffer;
+
+	data_in->action = action->fwd.action;
+	if (action->fwd.action == RTE_PIPELINE_ACTION_PORT)
+		data_in->port_id = action->fwd.id;
+	if (action->fwd.action == RTE_PIPELINE_ACTION_TABLE)
+		data_in->table_id = action->fwd.id;
+
+	/* Add default rule to table */
+	status = rte_pipeline_table_default_entry_add(p->p,
+		table_id,
+		data_in,
+		&data_out);
+	if (status) {
+		rsp->status = -1;
+		return rsp;
+	}
+
+	/* Write response */
+	rsp->status = 0;
+	rsp->table_rule_add_default.data = data_out;
+
+	return rsp;
+}
+
 static void
 pipeline_msg_handle(struct pipeline_data *p)
 {
@@ -940,6 +1682,13 @@ pipeline_msg_handle(struct pipeline_data *p)
 			rsp = pipeline_msg_handle_table_stats_read(p, req);
 			break;
 
+		case PIPELINE_REQ_TABLE_RULE_ADD:
+			rsp = pipeline_msg_handle_table_rule_add(p, req);
+			break;
+
+		case PIPELINE_REQ_TABLE_RULE_ADD_DEFAULT:
+			rsp = pipeline_msg_handle_table_rule_add_default(p,	req);
+			break;
 
 		default:
 			rsp = (struct pipeline_msg_rsp *) req;
-- 
2.9.3

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

* [dpdk-dev] [PATCH v2 33/44] ip_pipeline: add cli to delete pipeline table entry
  2018-03-12 17:25   ` [dpdk-dev] [PATCH v2 00/44] ip_pipeline: refactoring Jasvinder Singh
                       ` (31 preceding siblings ...)
  2018-03-12 17:26     ` [dpdk-dev] [PATCH v2 32/44] ip_pipeline: add cli for pipeline table entries Jasvinder Singh
@ 2018-03-12 17:26     ` Jasvinder Singh
  2018-03-12 17:26     ` [dpdk-dev] [PATCH v2 34/44] ip_pipeline: add cli to read pipeline table entry stats Jasvinder Singh
                       ` (10 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-12 17:26 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add command to delete the pipeline table entry.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/cli.c      | 145 ++++++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/pipeline.h |   9 +++
 examples/ip_pipeline/thread.c   | 140 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 294 insertions(+)

diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index eda04dc..4938b55 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -3322,6 +3322,134 @@ cmd_pipeline_table_rule_add_default(char **tokens,
 }
 
 /**
+ * pipeline <pipeline_name> table <table_id> rule delete
+ *    match <match>
+ */
+static void
+cmd_pipeline_table_rule_delete(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct table_rule_match m;
+	char *pipeline_name;
+	uint32_t table_id, n_tokens_parsed, t0;
+	int status;
+
+	if (n_tokens < 8) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "table") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
+		return;
+	}
+
+	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
+		return;
+	}
+
+	if (strcmp(tokens[4], "rule") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
+		return;
+	}
+
+	if (strcmp(tokens[5], "delete") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete");
+		return;
+	}
+
+	t0 = 6;
+
+	/* match */
+	n_tokens_parsed = parse_match(tokens + t0,
+		n_tokens - t0,
+		out,
+		out_size,
+		&m);
+	if (n_tokens_parsed == 0)
+		return;
+	t0 += n_tokens_parsed;
+
+	if (n_tokens != t0) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	status = pipeline_table_rule_delete(pipeline_name,
+		table_id,
+		&m);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
+ * pipeline <pipeline_name> table <table_id> rule delete
+ *    match
+ *       default
+ */
+static void
+cmd_pipeline_table_rule_delete_default(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	char *pipeline_name;
+	uint32_t table_id;
+	int status;
+
+	if (n_tokens != 8) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "table") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
+		return;
+	}
+
+	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
+		return;
+	}
+
+	if (strcmp(tokens[4], "rule") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
+		return;
+	}
+
+	if (strcmp(tokens[5], "delete") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete");
+		return;
+	}
+
+	if (strcmp(tokens[6], "match") != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "match");
+		return;
+	}
+
+	if (strcmp(tokens[7], "default") != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "default");
+		return;
+	}
+
+	status = pipeline_table_rule_delete_default(pipeline_name,
+		table_id);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
  * thread <thread_id> pipeline <pipeline_name> enable
  */
 static void
@@ -3588,6 +3716,23 @@ cli_process(char *in, char *out, size_t out_size)
 				out, out_size);
 			return;
 		}
+
+		if ((n_tokens >= 7) &&
+			(strcmp(tokens[2], "table") == 0) &&
+			(strcmp(tokens[4], "rule") == 0) &&
+			(strcmp(tokens[5], "delete") == 0) &&
+			(strcmp(tokens[6], "match") == 0)) {
+			if ((n_tokens >= 8) &&
+				(strcmp(tokens[7], "default") == 0)) {
+				cmd_pipeline_table_rule_delete_default(tokens,
+					n_tokens, out, out_size);
+				return;
+				}
+
+			cmd_pipeline_table_rule_delete(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
 	}
 
 	if (strcmp(tokens[0], "thread") == 0) {
diff --git a/examples/ip_pipeline/pipeline.h b/examples/ip_pipeline/pipeline.h
index 9351024..2bf6360 100644
--- a/examples/ip_pipeline/pipeline.h
+++ b/examples/ip_pipeline/pipeline.h
@@ -301,4 +301,13 @@ pipeline_table_rule_add_default(const char *pipeline_name,
 	struct table_rule_action *action,
 	void **data);
 
+int
+pipeline_table_rule_delete(const char *pipeline_name,
+	uint32_t table_id,
+	struct table_rule_match *match);
+
+int
+pipeline_table_rule_delete_default(const char *pipeline_name,
+	uint32_t table_id);
+
 #endif /* _INCLUDE_PIPELINE_H_ */
diff --git a/examples/ip_pipeline/thread.c b/examples/ip_pipeline/thread.c
index be12d20..7f29f2d 100644
--- a/examples/ip_pipeline/thread.c
+++ b/examples/ip_pipeline/thread.c
@@ -495,6 +495,8 @@ enum pipeline_req_type {
 	PIPELINE_REQ_TABLE_STATS_READ,
 	PIPELINE_REQ_TABLE_RULE_ADD,
 	PIPELINE_REQ_TABLE_RULE_ADD_DEFAULT,
+	PIPELINE_REQ_TABLE_RULE_DELETE,
+	PIPELINE_REQ_TABLE_RULE_DELETE_DEFAULT,
 
 	PIPELINE_REQ_MAX
 };
@@ -520,6 +522,10 @@ struct pipeline_msg_req_table_rule_add_default {
 	struct table_rule_action action;
 };
 
+struct pipeline_msg_req_table_rule_delete {
+	struct table_rule_match match;
+};
+
 struct pipeline_msg_req {
 	enum pipeline_req_type type;
 	uint32_t id; /* Port IN, port OUT or table ID */
@@ -531,6 +537,7 @@ struct pipeline_msg_req {
 		struct pipeline_msg_req_table_stats_read table_stats_read;
 		struct pipeline_msg_req_table_rule_add table_rule_add;
 		struct pipeline_msg_req_table_rule_add_default table_rule_add_default;
+		struct pipeline_msg_req_table_rule_delete table_rule_delete;
 	};
 };
 
@@ -1094,6 +1101,92 @@ pipeline_table_rule_add_default(const char *pipeline_name,
 	return status;
 }
 
+int
+pipeline_table_rule_delete(const char *pipeline_name,
+	uint32_t table_id,
+	struct table_rule_match *match)
+{
+	struct pipeline *p;
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if ((pipeline_name == NULL) ||
+		(match == NULL))
+		return -1;
+
+	p = pipeline_find(pipeline_name);
+	if ((p == NULL) ||
+		(table_id >= p->n_tables) ||
+		match_check(match, p, table_id))
+		return -1;
+
+	/* Allocate request */
+	req = pipeline_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = PIPELINE_REQ_TABLE_RULE_DELETE;
+	req->id = table_id;
+	memcpy(&req->table_rule_delete.match, match, sizeof(*match));
+
+	/* Send request and wait for response */
+	rsp = pipeline_msg_send_recv(p, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+
+	/* Free response */
+	pipeline_msg_free(rsp);
+
+	return status;
+}
+
+int
+pipeline_table_rule_delete_default(const char *pipeline_name,
+	uint32_t table_id)
+{
+	struct pipeline *p;
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if (pipeline_name == NULL)
+		return -1;
+
+	p = pipeline_find(pipeline_name);
+	if ((p == NULL) ||
+		(table_id >= p->n_tables))
+		return -1;
+
+	/* Allocate request */
+	req = pipeline_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = PIPELINE_REQ_TABLE_RULE_DELETE_DEFAULT;
+	req->id = table_id;
+
+	/* Send request and wait for response */
+	rsp = pipeline_msg_send_recv(p, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+
+	/* Free response */
+	pipeline_msg_free(rsp);
+
+	return status;
+}
+
 /**
  * Data plane threads: message handling
  */
@@ -1650,6 +1743,45 @@ pipeline_msg_handle_table_rule_add_default(struct pipeline_data *p,
 	return rsp;
 }
 
+static struct pipeline_msg_rsp *
+pipeline_msg_handle_table_rule_delete(struct pipeline_data *p,
+	struct pipeline_msg_req *req)
+{
+	union table_rule_match_low_level match_ll;
+	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+	struct table_rule_match *match = &req->table_rule_delete.match;
+	uint32_t table_id = req->id;
+	int key_found, status;
+
+	status = match_convert(match, &match_ll, 0);
+	if (status) {
+		rsp->status = -1;
+		return rsp;
+	}
+
+	rsp->status = rte_pipeline_table_entry_delete(p->p,
+		table_id,
+		&match_ll,
+		&key_found,
+		NULL);
+
+	return rsp;
+}
+
+static struct pipeline_msg_rsp *
+pipeline_msg_handle_table_rule_delete_default(struct pipeline_data *p,
+	struct pipeline_msg_req *req)
+{
+	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+	uint32_t table_id = req->id;
+
+	rsp->status = rte_pipeline_table_default_entry_delete(p->p,
+		table_id,
+		NULL);
+
+	return rsp;
+}
+
 static void
 pipeline_msg_handle(struct pipeline_data *p)
 {
@@ -1690,6 +1822,14 @@ pipeline_msg_handle(struct pipeline_data *p)
 			rsp = pipeline_msg_handle_table_rule_add_default(p,	req);
 			break;
 
+		case PIPELINE_REQ_TABLE_RULE_DELETE:
+			rsp = pipeline_msg_handle_table_rule_delete(p, req);
+			break;
+
+		case PIPELINE_REQ_TABLE_RULE_DELETE_DEFAULT:
+			rsp = pipeline_msg_handle_table_rule_delete_default(p, req);
+			break;
+
 		default:
 			rsp = (struct pipeline_msg_rsp *) req;
 			rsp->status = -1;
-- 
2.9.3

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

* [dpdk-dev] [PATCH v2 34/44] ip_pipeline: add cli to read pipeline table entry stats
  2018-03-12 17:25   ` [dpdk-dev] [PATCH v2 00/44] ip_pipeline: refactoring Jasvinder Singh
                       ` (32 preceding siblings ...)
  2018-03-12 17:26     ` [dpdk-dev] [PATCH v2 33/44] ip_pipeline: add cli to delete pipeline table entry Jasvinder Singh
@ 2018-03-12 17:26     ` Jasvinder Singh
  2018-03-12 17:26     ` [dpdk-dev] [PATCH v2 35/44] ip_pipeline: add cli to configure meter profile Jasvinder Singh
                       ` (9 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-12 17:26 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Fan Zhang

Add command to read the pipeline table entry stats.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Fan Zhang <roy.fan.zhang@intel.com>
---
 examples/ip_pipeline/cli.c      | 22 +++++++++++
 examples/ip_pipeline/pipeline.h |  7 ++++
 examples/ip_pipeline/thread.c   | 84 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 113 insertions(+)

diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index 4938b55..b810294 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -3450,6 +3450,18 @@ cmd_pipeline_table_rule_delete_default(char **tokens,
 }
 
 /**
+ * pipeline <pipeline_name> table <table_id> rule read stats [clear]
+ */
+static void
+cmd_pipeline_table_rule_stats_read(char **tokens,
+	uint32_t n_tokens __rte_unused,
+	char *out,
+	size_t out_size)
+{
+	snprintf(out, out_size, MSG_CMD_UNIMPLEM, tokens[0]);
+}
+
+/**
  * thread <thread_id> pipeline <pipeline_name> enable
  */
 static void
@@ -3733,6 +3745,16 @@ cli_process(char *in, char *out, size_t out_size)
 				out, out_size);
 			return;
 		}
+
+		if ((n_tokens >= 7) &&
+			(strcmp(tokens[2], "table") == 0) &&
+			(strcmp(tokens[4], "rule") == 0) &&
+			(strcmp(tokens[5], "read") == 0) &&
+			(strcmp(tokens[6], "stats") == 0)) {
+			cmd_pipeline_table_rule_stats_read(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
 	}
 
 	if (strcmp(tokens[0], "thread") == 0) {
diff --git a/examples/ip_pipeline/pipeline.h b/examples/ip_pipeline/pipeline.h
index 2bf6360..296e4da 100644
--- a/examples/ip_pipeline/pipeline.h
+++ b/examples/ip_pipeline/pipeline.h
@@ -310,4 +310,11 @@ int
 pipeline_table_rule_delete_default(const char *pipeline_name,
 	uint32_t table_id);
 
+int
+pipeline_table_rule_stats_read(const char *pipeline_name,
+	uint32_t table_id,
+	void *data,
+	struct rte_table_action_stats_counters *stats,
+	int clear);
+
 #endif /* _INCLUDE_PIPELINE_H_ */
diff --git a/examples/ip_pipeline/thread.c b/examples/ip_pipeline/thread.c
index 7f29f2d..21f36ca 100644
--- a/examples/ip_pipeline/thread.c
+++ b/examples/ip_pipeline/thread.c
@@ -497,6 +497,7 @@ enum pipeline_req_type {
 	PIPELINE_REQ_TABLE_RULE_ADD_DEFAULT,
 	PIPELINE_REQ_TABLE_RULE_DELETE,
 	PIPELINE_REQ_TABLE_RULE_DELETE_DEFAULT,
+	PIPELINE_REQ_TABLE_RULE_STATS_READ,
 
 	PIPELINE_REQ_MAX
 };
@@ -526,6 +527,11 @@ struct pipeline_msg_req_table_rule_delete {
 	struct table_rule_match match;
 };
 
+struct pipeline_msg_req_table_rule_stats_read {
+	void *data;
+	int clear;
+};
+
 struct pipeline_msg_req {
 	enum pipeline_req_type type;
 	uint32_t id; /* Port IN, port OUT or table ID */
@@ -538,6 +544,7 @@ struct pipeline_msg_req {
 		struct pipeline_msg_req_table_rule_add table_rule_add;
 		struct pipeline_msg_req_table_rule_add_default table_rule_add_default;
 		struct pipeline_msg_req_table_rule_delete table_rule_delete;
+		struct pipeline_msg_req_table_rule_stats_read table_rule_stats_read;
 	};
 };
 
@@ -561,6 +568,10 @@ struct pipeline_msg_rsp_table_rule_add_default {
 	void *data;
 };
 
+struct pipeline_msg_rsp_table_rule_stats_read {
+	struct rte_table_action_stats_counters stats;
+};
+
 struct pipeline_msg_rsp {
 	int status;
 
@@ -571,6 +582,7 @@ struct pipeline_msg_rsp {
 		struct pipeline_msg_rsp_table_stats_read table_stats_read;
 		struct pipeline_msg_rsp_table_rule_add table_rule_add;
 		struct pipeline_msg_rsp_table_rule_add_default table_rule_add_default;
+		struct pipeline_msg_rsp_table_rule_stats_read table_rule_stats_read;
 	};
 };
 
@@ -1187,6 +1199,56 @@ pipeline_table_rule_delete_default(const char *pipeline_name,
 	return status;
 }
 
+int
+pipeline_table_rule_stats_read(const char *pipeline_name,
+	uint32_t table_id,
+	void *data,
+	struct rte_table_action_stats_counters *stats,
+	int clear)
+{
+	struct pipeline *p;
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if ((pipeline_name == NULL) ||
+		(data == NULL) ||
+		(stats == NULL))
+		return -1;
+
+	p = pipeline_find(pipeline_name);
+	if ((p == NULL) ||
+		(table_id >= p->n_tables))
+		return -1;
+
+	/* Allocate request */
+	req = pipeline_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = PIPELINE_REQ_TABLE_RULE_STATS_READ;
+	req->id = table_id;
+	req->table_rule_stats_read.data = data;
+	req->table_rule_stats_read.clear = clear;
+
+	/* Send request and wait for response */
+	rsp = pipeline_msg_send_recv(p, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+	if (status)
+		memcpy(stats, &rsp->table_rule_stats_read.stats, sizeof(*stats));
+
+	/* Free response */
+	pipeline_msg_free(rsp);
+
+	return status;
+}
+
 /**
  * Data plane threads: message handling
  */
@@ -1782,6 +1844,24 @@ pipeline_msg_handle_table_rule_delete_default(struct pipeline_data *p,
 	return rsp;
 }
 
+static struct pipeline_msg_rsp *
+pipeline_msg_handle_table_rule_stats_read(struct pipeline_data *p,
+	struct pipeline_msg_req *req)
+{
+	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+	uint32_t table_id = req->id;
+	void *data = req->table_rule_stats_read.data;
+	int clear = req->table_rule_stats_read.clear;
+	struct rte_table_action *a = p->table_data[table_id].a;
+
+	rsp->status = rte_table_action_stats_read(a,
+		data,
+		&rsp->table_rule_stats_read.stats,
+		clear);
+
+	return rsp;
+}
+
 static void
 pipeline_msg_handle(struct pipeline_data *p)
 {
@@ -1830,6 +1910,10 @@ pipeline_msg_handle(struct pipeline_data *p)
 			rsp = pipeline_msg_handle_table_rule_delete_default(p, req);
 			break;
 
+		case PIPELINE_REQ_TABLE_RULE_STATS_READ:
+			rsp = pipeline_msg_handle_table_rule_stats_read(p, req);
+			break;
+
 		default:
 			rsp = (struct pipeline_msg_rsp *) req;
 			rsp->status = -1;
-- 
2.9.3

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

* [dpdk-dev] [PATCH v2 35/44] ip_pipeline: add cli to configure meter profile
  2018-03-12 17:25   ` [dpdk-dev] [PATCH v2 00/44] ip_pipeline: refactoring Jasvinder Singh
                       ` (33 preceding siblings ...)
  2018-03-12 17:26     ` [dpdk-dev] [PATCH v2 34/44] ip_pipeline: add cli to read pipeline table entry stats Jasvinder Singh
@ 2018-03-12 17:26     ` Jasvinder Singh
  2018-03-12 17:26     ` [dpdk-dev] [PATCH v2 36/44] ip_pipeline: add cli to read meter stats Jasvinder Singh
                       ` (8 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-12 17:26 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add commands to configure the traffic meter profile.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/cli.c      | 232 ++++++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/pipeline.h |  11 ++
 examples/ip_pipeline/thread.c   | 145 ++++++++++++++++++++++++-
 3 files changed, 387 insertions(+), 1 deletion(-)

diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index b810294..ddc1dc5 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -3462,6 +3462,218 @@ cmd_pipeline_table_rule_stats_read(char **tokens,
 }
 
 /**
+ * pipeline <pipeline_name> table <table_id> meter profile <meter_profile_id>
+ *  add srtcm cir <cir> cbs <cbs> ebs <ebs>
+ *  | trtcm cir <cir> pir <pir> cbs <cbs> pbs <pbs>
+ */
+static void
+cmd_pipeline_table_meter_profile_add(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct rte_table_action_meter_profile p;
+	char *pipeline_name;
+	uint32_t table_id, meter_profile_id;
+	int status;
+
+	if (n_tokens < 9) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "table") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
+		return;
+	}
+
+	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
+		return;
+	}
+
+	if (strcmp(tokens[4], "meter") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
+		return;
+	}
+
+	if (strcmp(tokens[5], "profile") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
+		return;
+	}
+
+	if (parser_read_uint32(&meter_profile_id, tokens[6]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "meter_profile_id");
+		return;
+	}
+
+	if (strcmp(tokens[7], "add") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
+		return;
+	}
+
+	if (strcmp(tokens[8], "srtcm") == 0) {
+		if (n_tokens != 15) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				tokens[0]);
+			return;
+		}
+
+		p.alg = RTE_TABLE_ACTION_METER_SRTCM;
+
+		if (strcmp(tokens[9], "cir") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cir");
+			return;
+		}
+
+		if (parser_read_uint64(&p.srtcm.cir, tokens[10]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "cir");
+			return;
+		}
+
+		if (strcmp(tokens[11], "cbs") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cbs");
+			return;
+		}
+
+		if (parser_read_uint64(&p.srtcm.cbs, tokens[12]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "cbs");
+			return;
+		}
+
+		if (strcmp(tokens[13], "ebs") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "ebs");
+			return;
+		}
+
+		if (parser_read_uint64(&p.srtcm.ebs, tokens[14]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "ebs");
+			return;
+		}
+	} else if (strcmp(tokens[8], "trtcm") == 0) {
+		if (n_tokens != 17) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+			return;
+		}
+
+		p.alg = RTE_TABLE_ACTION_METER_TRTCM;
+
+		if (strcmp(tokens[9], "cir") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cir");
+			return;
+		}
+
+		if (parser_read_uint64(&p.trtcm.cir, tokens[10]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "cir");
+			return;
+		}
+
+		if (strcmp(tokens[11], "pir") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pir");
+			return;
+		}
+
+		if (parser_read_uint64(&p.trtcm.pir, tokens[12]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "pir");
+			return;
+		}
+		if (strcmp(tokens[13], "cbs") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cbs");
+			return;
+		}
+
+		if (parser_read_uint64(&p.trtcm.cbs, tokens[14]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "cbs");
+			return;
+		}
+
+		if (strcmp(tokens[15], "pbs") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pbs");
+			return;
+		}
+
+		if (parser_read_uint64(&p.trtcm.pbs, tokens[16]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "pbs");
+			return;
+		}
+	} else {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	status = pipeline_table_mtr_profile_add(pipeline_name,
+		table_id,
+		meter_profile_id,
+		&p);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
+ * pipeline <pipeline_name> table <table_id>
+ *  meter profile <meter_profile_id> delete
+ */
+static void
+cmd_pipeline_table_meter_profile_delete(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	char *pipeline_name;
+	uint32_t table_id, meter_profile_id;
+	int status;
+
+	if (n_tokens != 8) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "table") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
+		return;
+	}
+
+	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
+		return;
+	}
+
+	if (strcmp(tokens[4], "meter") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
+		return;
+	}
+
+	if (strcmp(tokens[5], "profile") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
+		return;
+	}
+
+	if (parser_read_uint32(&meter_profile_id, tokens[6]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "meter_profile_id");
+		return;
+	}
+
+	if (strcmp(tokens[7], "delete") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete");
+		return;
+	}
+
+	status = pipeline_table_mtr_profile_delete(pipeline_name,
+		table_id,
+		meter_profile_id);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
  * thread <thread_id> pipeline <pipeline_name> enable
  */
 static void
@@ -3755,6 +3967,26 @@ cli_process(char *in, char *out, size_t out_size)
 				out, out_size);
 			return;
 		}
+
+		if ((n_tokens >= 8) &&
+			(strcmp(tokens[2], "table") == 0) &&
+			(strcmp(tokens[4], "meter") == 0) &&
+			(strcmp(tokens[5], "profile") == 0) &&
+			(strcmp(tokens[7], "add") == 0)) {
+			cmd_pipeline_table_meter_profile_add(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
+
+		if ((n_tokens >= 8) &&
+			(strcmp(tokens[2], "table") == 0) &&
+			(strcmp(tokens[4], "meter") == 0) &&
+			(strcmp(tokens[5], "profile") == 0) &&
+			(strcmp(tokens[7], "delete") == 0)) {
+			cmd_pipeline_table_meter_profile_delete(tokens,
+				n_tokens, out, out_size);
+			return;
+		}
 	}
 
 	if (strcmp(tokens[0], "thread") == 0) {
diff --git a/examples/ip_pipeline/pipeline.h b/examples/ip_pipeline/pipeline.h
index 296e4da..d524145 100644
--- a/examples/ip_pipeline/pipeline.h
+++ b/examples/ip_pipeline/pipeline.h
@@ -317,4 +317,15 @@ pipeline_table_rule_stats_read(const char *pipeline_name,
 	struct rte_table_action_stats_counters *stats,
 	int clear);
 
+int
+pipeline_table_mtr_profile_add(const char *pipeline_name,
+	uint32_t table_id,
+	uint32_t meter_profile_id,
+	struct rte_table_action_meter_profile *profile);
+
+int
+pipeline_table_mtr_profile_delete(const char *pipeline_name,
+	uint32_t table_id,
+	uint32_t meter_profile_id);
+
 #endif /* _INCLUDE_PIPELINE_H_ */
diff --git a/examples/ip_pipeline/thread.c b/examples/ip_pipeline/thread.c
index 21f36ca..97fce1a 100644
--- a/examples/ip_pipeline/thread.c
+++ b/examples/ip_pipeline/thread.c
@@ -498,7 +498,8 @@ enum pipeline_req_type {
 	PIPELINE_REQ_TABLE_RULE_DELETE,
 	PIPELINE_REQ_TABLE_RULE_DELETE_DEFAULT,
 	PIPELINE_REQ_TABLE_RULE_STATS_READ,
-
+	PIPELINE_REQ_TABLE_MTR_PROFILE_ADD,
+	PIPELINE_REQ_TABLE_MTR_PROFILE_DELETE,
 	PIPELINE_REQ_MAX
 };
 
@@ -532,6 +533,15 @@ struct pipeline_msg_req_table_rule_stats_read {
 	int clear;
 };
 
+struct pipeline_msg_req_table_mtr_profile_add {
+	uint32_t meter_profile_id;
+	struct rte_table_action_meter_profile profile;
+};
+
+struct pipeline_msg_req_table_mtr_profile_delete {
+	uint32_t meter_profile_id;
+};
+
 struct pipeline_msg_req {
 	enum pipeline_req_type type;
 	uint32_t id; /* Port IN, port OUT or table ID */
@@ -545,6 +555,8 @@ struct pipeline_msg_req {
 		struct pipeline_msg_req_table_rule_add_default table_rule_add_default;
 		struct pipeline_msg_req_table_rule_delete table_rule_delete;
 		struct pipeline_msg_req_table_rule_stats_read table_rule_stats_read;
+		struct pipeline_msg_req_table_mtr_profile_add table_mtr_profile_add;
+		struct pipeline_msg_req_table_mtr_profile_delete table_mtr_profile_delete;
 	};
 };
 
@@ -1249,6 +1261,95 @@ pipeline_table_rule_stats_read(const char *pipeline_name,
 	return status;
 }
 
+int
+pipeline_table_mtr_profile_add(const char *pipeline_name,
+	uint32_t table_id,
+	uint32_t meter_profile_id,
+	struct rte_table_action_meter_profile *profile)
+{
+	struct pipeline *p;
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if ((pipeline_name == NULL) ||
+		(profile == NULL))
+		return -1;
+
+	p = pipeline_find(pipeline_name);
+	if ((p == NULL) ||
+		(table_id >= p->n_tables))
+		return -1;
+
+	/* Allocate request */
+	req = pipeline_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = PIPELINE_REQ_TABLE_MTR_PROFILE_ADD;
+	req->id = table_id;
+	req->table_mtr_profile_add.meter_profile_id = meter_profile_id;
+	memcpy(&req->table_mtr_profile_add.profile, profile, sizeof(*profile));
+
+	/* Send request and wait for response */
+	rsp = pipeline_msg_send_recv(p, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+
+	/* Free response */
+	pipeline_msg_free(rsp);
+
+	return status;
+}
+
+int
+pipeline_table_mtr_profile_delete(const char *pipeline_name,
+	uint32_t table_id,
+	uint32_t meter_profile_id)
+{
+	struct pipeline *p;
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if (pipeline_name == NULL)
+		return -1;
+
+	p = pipeline_find(pipeline_name);
+	if ((p == NULL) ||
+		(table_id >= p->n_tables))
+		return -1;
+
+	/* Allocate request */
+	req = pipeline_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = PIPELINE_REQ_TABLE_MTR_PROFILE_DELETE;
+	req->id = table_id;
+	req->table_mtr_profile_delete.meter_profile_id = meter_profile_id;
+
+	/* Send request and wait for response */
+	rsp = pipeline_msg_send_recv(p, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+
+	/* Free response */
+	pipeline_msg_free(rsp);
+
+	return status;
+}
+
 /**
  * Data plane threads: message handling
  */
@@ -1862,6 +1963,40 @@ pipeline_msg_handle_table_rule_stats_read(struct pipeline_data *p,
 	return rsp;
 }
 
+static struct pipeline_msg_rsp *
+pipeline_msg_handle_table_mtr_profile_add(struct pipeline_data *p,
+	struct pipeline_msg_req *req)
+{
+	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+	uint32_t table_id = req->id;
+	uint32_t meter_profile_id = req->table_mtr_profile_add.meter_profile_id;
+	struct rte_table_action_meter_profile *profile =
+		&req->table_mtr_profile_add.profile;
+	struct rte_table_action *a = p->table_data[table_id].a;
+
+	rsp->status = rte_table_action_meter_profile_add(a,
+		meter_profile_id,
+		profile);
+
+	return rsp;
+}
+
+static struct pipeline_msg_rsp *
+pipeline_msg_handle_table_mtr_profile_delete(struct pipeline_data *p,
+	struct pipeline_msg_req *req)
+{
+	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+	uint32_t table_id = req->id;
+	uint32_t meter_profile_id =
+		req->table_mtr_profile_delete.meter_profile_id;
+	struct rte_table_action *a = p->table_data[table_id].a;
+
+	rsp->status = rte_table_action_meter_profile_delete(a,
+		meter_profile_id);
+
+	return rsp;
+}
+
 static void
 pipeline_msg_handle(struct pipeline_data *p)
 {
@@ -1914,6 +2049,14 @@ pipeline_msg_handle(struct pipeline_data *p)
 			rsp = pipeline_msg_handle_table_rule_stats_read(p, req);
 			break;
 
+		case PIPELINE_REQ_TABLE_MTR_PROFILE_ADD:
+			rsp = pipeline_msg_handle_table_mtr_profile_add(p, req);
+			break;
+
+		case PIPELINE_REQ_TABLE_MTR_PROFILE_DELETE:
+			rsp = pipeline_msg_handle_table_mtr_profile_delete(p, req);
+			break;
+
 		default:
 			rsp = (struct pipeline_msg_rsp *) req;
 			rsp->status = -1;
-- 
2.9.3

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

* [dpdk-dev] [PATCH v2 36/44] ip_pipeline: add cli to read meter stats
  2018-03-12 17:25   ` [dpdk-dev] [PATCH v2 00/44] ip_pipeline: refactoring Jasvinder Singh
                       ` (34 preceding siblings ...)
  2018-03-12 17:26     ` [dpdk-dev] [PATCH v2 35/44] ip_pipeline: add cli to configure meter profile Jasvinder Singh
@ 2018-03-12 17:26     ` Jasvinder Singh
  2018-03-12 17:26     ` [dpdk-dev] [PATCH v2 37/44] ip_pipeline: add cli to update dscp table Jasvinder Singh
                       ` (7 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-12 17:26 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add command to read traffic meter stats.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/cli.c      | 22 +++++++++++
 examples/ip_pipeline/pipeline.h |  8 ++++
 examples/ip_pipeline/thread.c   | 88 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 118 insertions(+)

diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index ddc1dc5..a5a7c08 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -3674,6 +3674,18 @@ cmd_pipeline_table_meter_profile_delete(char **tokens,
 }
 
 /**
+ * pipeline <pipeline_name> table <table_id> rule read meter [clear]
+ */
+static void
+cmd_pipeline_table_rule_meter_read(char **tokens,
+	uint32_t n_tokens __rte_unused,
+	char *out,
+	size_t out_size)
+{
+	snprintf(out, out_size, MSG_CMD_UNIMPLEM, tokens[0]);
+}
+
+/**
  * thread <thread_id> pipeline <pipeline_name> enable
  */
 static void
@@ -3987,6 +3999,16 @@ cli_process(char *in, char *out, size_t out_size)
 				n_tokens, out, out_size);
 			return;
 		}
+
+		if ((n_tokens >= 7) &&
+			(strcmp(tokens[2], "table") == 0) &&
+			(strcmp(tokens[4], "rule") == 0) &&
+			(strcmp(tokens[5], "read") == 0) &&
+			(strcmp(tokens[6], "meter") == 0)) {
+			cmd_pipeline_table_rule_meter_read(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
 	}
 
 	if (strcmp(tokens[0], "thread") == 0) {
diff --git a/examples/ip_pipeline/pipeline.h b/examples/ip_pipeline/pipeline.h
index d524145..4978555 100644
--- a/examples/ip_pipeline/pipeline.h
+++ b/examples/ip_pipeline/pipeline.h
@@ -328,4 +328,12 @@ pipeline_table_mtr_profile_delete(const char *pipeline_name,
 	uint32_t table_id,
 	uint32_t meter_profile_id);
 
+int
+pipeline_table_rule_mtr_read(const char *pipeline_name,
+	uint32_t table_id,
+	void *data,
+	uint32_t tc_mask,
+	struct rte_table_action_mtr_counters *stats,
+	int clear);
+
 #endif /* _INCLUDE_PIPELINE_H_ */
diff --git a/examples/ip_pipeline/thread.c b/examples/ip_pipeline/thread.c
index 97fce1a..de89190 100644
--- a/examples/ip_pipeline/thread.c
+++ b/examples/ip_pipeline/thread.c
@@ -500,6 +500,7 @@ enum pipeline_req_type {
 	PIPELINE_REQ_TABLE_RULE_STATS_READ,
 	PIPELINE_REQ_TABLE_MTR_PROFILE_ADD,
 	PIPELINE_REQ_TABLE_MTR_PROFILE_DELETE,
+	PIPELINE_REQ_TABLE_RULE_MTR_READ,
 	PIPELINE_REQ_MAX
 };
 
@@ -542,6 +543,11 @@ struct pipeline_msg_req_table_mtr_profile_delete {
 	uint32_t meter_profile_id;
 };
 
+struct pipeline_msg_req_table_rule_mtr_read {
+	void *data;
+	uint32_t tc_mask;
+	int clear;
+};
 struct pipeline_msg_req {
 	enum pipeline_req_type type;
 	uint32_t id; /* Port IN, port OUT or table ID */
@@ -557,6 +563,7 @@ struct pipeline_msg_req {
 		struct pipeline_msg_req_table_rule_stats_read table_rule_stats_read;
 		struct pipeline_msg_req_table_mtr_profile_add table_mtr_profile_add;
 		struct pipeline_msg_req_table_mtr_profile_delete table_mtr_profile_delete;
+		struct pipeline_msg_req_table_rule_mtr_read table_rule_mtr_read;
 	};
 };
 
@@ -584,6 +591,10 @@ struct pipeline_msg_rsp_table_rule_stats_read {
 	struct rte_table_action_stats_counters stats;
 };
 
+struct pipeline_msg_rsp_table_rule_mtr_read {
+	struct rte_table_action_mtr_counters stats;
+};
+
 struct pipeline_msg_rsp {
 	int status;
 
@@ -595,6 +606,7 @@ struct pipeline_msg_rsp {
 		struct pipeline_msg_rsp_table_rule_add table_rule_add;
 		struct pipeline_msg_rsp_table_rule_add_default table_rule_add_default;
 		struct pipeline_msg_rsp_table_rule_stats_read table_rule_stats_read;
+		struct pipeline_msg_rsp_table_rule_mtr_read table_rule_mtr_read;
 	};
 };
 
@@ -1350,6 +1362,58 @@ pipeline_table_mtr_profile_delete(const char *pipeline_name,
 	return status;
 }
 
+int
+pipeline_table_rule_mtr_read(const char *pipeline_name,
+	uint32_t table_id,
+	void *data,
+	uint32_t tc_mask,
+	struct rte_table_action_mtr_counters *stats,
+	int clear)
+{
+	struct pipeline *p;
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if ((pipeline_name == NULL) ||
+		(data == NULL) ||
+		(stats == NULL))
+		return -1;
+
+	p = pipeline_find(pipeline_name);
+	if ((p == NULL) ||
+		(table_id >= p->n_tables))
+		return -1;
+
+	/* Allocate request */
+	req = pipeline_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = PIPELINE_REQ_TABLE_RULE_MTR_READ;
+	req->id = table_id;
+	req->table_rule_mtr_read.data = data;
+	req->table_rule_mtr_read.tc_mask = tc_mask;
+	req->table_rule_mtr_read.clear = clear;
+
+	/* Send request and wait for response */
+	rsp = pipeline_msg_send_recv(p, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+	if (status)
+		memcpy(stats, &rsp->table_rule_mtr_read.stats, sizeof(*stats));
+
+	/* Free response */
+	pipeline_msg_free(rsp);
+
+	return status;
+}
+
 /**
  * Data plane threads: message handling
  */
@@ -1997,6 +2061,26 @@ pipeline_msg_handle_table_mtr_profile_delete(struct pipeline_data *p,
 	return rsp;
 }
 
+static struct pipeline_msg_rsp *
+pipeline_msg_handle_table_rule_mtr_read(struct pipeline_data *p,
+	struct pipeline_msg_req *req)
+{
+	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+	uint32_t table_id = req->id;
+	void *data = req->table_rule_mtr_read.data;
+	uint32_t tc_mask = req->table_rule_mtr_read.tc_mask;
+	int clear = req->table_rule_mtr_read.clear;
+	struct rte_table_action *a = p->table_data[table_id].a;
+
+	rsp->status = rte_table_action_meter_read(a,
+		data,
+		tc_mask,
+		&rsp->table_rule_mtr_read.stats,
+		clear);
+
+	return rsp;
+}
+
 static void
 pipeline_msg_handle(struct pipeline_data *p)
 {
@@ -2057,6 +2141,10 @@ pipeline_msg_handle(struct pipeline_data *p)
 			rsp = pipeline_msg_handle_table_mtr_profile_delete(p, req);
 			break;
 
+		case PIPELINE_REQ_TABLE_RULE_MTR_READ:
+			rsp = pipeline_msg_handle_table_rule_mtr_read(p, req);
+			break;
+
 		default:
 			rsp = (struct pipeline_msg_rsp *) req;
 			rsp->status = -1;
-- 
2.9.3

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

* [dpdk-dev] [PATCH v2 37/44] ip_pipeline: add cli to update dscp table
  2018-03-12 17:25   ` [dpdk-dev] [PATCH v2 00/44] ip_pipeline: refactoring Jasvinder Singh
                       ` (35 preceding siblings ...)
  2018-03-12 17:26     ` [dpdk-dev] [PATCH v2 36/44] ip_pipeline: add cli to read meter stats Jasvinder Singh
@ 2018-03-12 17:26     ` Jasvinder Singh
  2018-03-12 17:26     ` [dpdk-dev] [PATCH v2 38/44] ip_pipeline: add cli to read ttl stats Jasvinder Singh
                       ` (6 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-12 17:26 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add command to update the dscp table for traffic meter and traffic
manager.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/cli.c      | 154 ++++++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/pipeline.h |   6 ++
 examples/ip_pipeline/thread.c   |  77 ++++++++++++++++++++
 3 files changed, 237 insertions(+)

diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index a5a7c08..3d74ece 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -3686,6 +3686,152 @@ cmd_pipeline_table_rule_meter_read(char **tokens,
 }
 
 /**
+ * pipeline <pipeline_name> table <table_id> dscp <file_name>
+ *
+ * File <file_name>:
+ *  - exactly 64 lines
+ *  - line format: <tc_id> <tc_queue_id> <color>, with <color> as: g | y | r
+ */
+static int
+load_dscp_table(struct rte_table_action_dscp_table *dscp_table,
+	const char *file_name,
+	uint32_t *line_number)
+{
+	FILE *f = NULL;
+	uint32_t dscp, l;
+
+	/* Check input arguments */
+	if ((dscp_table == NULL) ||
+		(file_name == NULL) ||
+		(line_number == NULL)) {
+		if (line_number)
+			*line_number = 0;
+		return -EINVAL;
+	}
+
+	/* Open input file */
+	f = fopen(file_name, "r");
+	if (f == NULL) {
+		*line_number = 0;
+		return -EINVAL;
+	}
+
+	/* Read file */
+	for (dscp = 0, l = 1; ; l++) {
+		char line[64];
+		char *tokens[3];
+		enum rte_meter_color color;
+		uint32_t tc_id, tc_queue_id, n_tokens = RTE_DIM(tokens);
+
+		if (fgets(line, sizeof(line), f) == NULL)
+			break;
+
+		if (is_comment(line))
+			continue;
+
+		if (parse_tokenize_string(line, tokens, &n_tokens)) {
+			*line_number = l;
+			return -EINVAL;
+		}
+
+		if (n_tokens == 0)
+			continue;
+
+		if ((dscp >= RTE_DIM(dscp_table->entry)) ||
+			(n_tokens != RTE_DIM(tokens)) ||
+			parser_read_uint32(&tc_id, tokens[0]) ||
+			(tc_id >= RTE_TABLE_ACTION_TC_MAX) ||
+			parser_read_uint32(&tc_queue_id, tokens[1]) ||
+			(tc_queue_id >= RTE_TABLE_ACTION_TC_QUEUE_MAX) ||
+			(strlen(tokens[2]) != 1)) {
+			*line_number = l;
+			return -EINVAL;
+		}
+
+		switch (tokens[2][0]) {
+		case 'g':
+		case 'G':
+			color = e_RTE_METER_GREEN;
+			break;
+
+		case 'y':
+		case 'Y':
+			color = e_RTE_METER_YELLOW;
+			break;
+
+		case 'r':
+		case 'R':
+			color = e_RTE_METER_RED;
+			break;
+
+		default:
+			*line_number = l;
+			return -EINVAL;
+		}
+
+		dscp_table->entry[dscp].tc_id = tc_id;
+		dscp_table->entry[dscp].tc_queue_id = tc_queue_id;
+		dscp_table->entry[dscp].color = color;
+		dscp++;
+	}
+
+	/* Close file */
+	fclose(f);
+	return 0;
+}
+
+static void
+cmd_pipeline_table_dscp(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct rte_table_action_dscp_table dscp_table;
+	char *pipeline_name, *file_name;
+	uint32_t table_id, line_number;
+	int status;
+
+	if (n_tokens != 6) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "table") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
+		return;
+	}
+
+	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
+		return;
+	}
+
+	if (strcmp(tokens[4], "dscp") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "dscp");
+		return;
+	}
+
+	file_name = tokens[5];
+
+	status = load_dscp_table(&dscp_table, file_name, &line_number);
+	if (status) {
+		snprintf(out, out_size, MSG_FILE_ERR, file_name, line_number);
+		return;
+	}
+
+	status = pipeline_table_dscp_table_update(pipeline_name,
+		table_id,
+		UINT64_MAX,
+		&dscp_table);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
  * thread <thread_id> pipeline <pipeline_name> enable
  */
 static void
@@ -4009,6 +4155,14 @@ cli_process(char *in, char *out, size_t out_size)
 				out, out_size);
 			return;
 		}
+
+		if ((n_tokens >= 5) &&
+			(strcmp(tokens[2], "table") == 0) &&
+			(strcmp(tokens[4], "dscp") == 0)) {
+			cmd_pipeline_table_dscp(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
 	}
 
 	if (strcmp(tokens[0], "thread") == 0) {
diff --git a/examples/ip_pipeline/pipeline.h b/examples/ip_pipeline/pipeline.h
index 4978555..598bed0 100644
--- a/examples/ip_pipeline/pipeline.h
+++ b/examples/ip_pipeline/pipeline.h
@@ -336,4 +336,10 @@ pipeline_table_rule_mtr_read(const char *pipeline_name,
 	struct rte_table_action_mtr_counters *stats,
 	int clear);
 
+int
+pipeline_table_dscp_table_update(const char *pipeline_name,
+	uint32_t table_id,
+	uint64_t dscp_mask,
+	struct rte_table_action_dscp_table *dscp_table);
+
 #endif /* _INCLUDE_PIPELINE_H_ */
diff --git a/examples/ip_pipeline/thread.c b/examples/ip_pipeline/thread.c
index de89190..3c1318d 100644
--- a/examples/ip_pipeline/thread.c
+++ b/examples/ip_pipeline/thread.c
@@ -501,6 +501,7 @@ enum pipeline_req_type {
 	PIPELINE_REQ_TABLE_MTR_PROFILE_ADD,
 	PIPELINE_REQ_TABLE_MTR_PROFILE_DELETE,
 	PIPELINE_REQ_TABLE_RULE_MTR_READ,
+	PIPELINE_REQ_TABLE_DSCP_TABLE_UPDATE,
 	PIPELINE_REQ_MAX
 };
 
@@ -548,6 +549,12 @@ struct pipeline_msg_req_table_rule_mtr_read {
 	uint32_t tc_mask;
 	int clear;
 };
+
+struct pipeline_msg_req_table_dscp_table_update {
+	uint64_t dscp_mask;
+	struct rte_table_action_dscp_table dscp_table;
+};
+
 struct pipeline_msg_req {
 	enum pipeline_req_type type;
 	uint32_t id; /* Port IN, port OUT or table ID */
@@ -564,6 +571,7 @@ struct pipeline_msg_req {
 		struct pipeline_msg_req_table_mtr_profile_add table_mtr_profile_add;
 		struct pipeline_msg_req_table_mtr_profile_delete table_mtr_profile_delete;
 		struct pipeline_msg_req_table_rule_mtr_read table_rule_mtr_read;
+		struct pipeline_msg_req_table_dscp_table_update table_dscp_table_update;
 	};
 };
 
@@ -1414,6 +1422,53 @@ pipeline_table_rule_mtr_read(const char *pipeline_name,
 	return status;
 }
 
+int
+pipeline_table_dscp_table_update(const char *pipeline_name,
+	uint32_t table_id,
+	uint64_t dscp_mask,
+	struct rte_table_action_dscp_table *dscp_table)
+{
+	struct pipeline *p;
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if ((pipeline_name == NULL) ||
+		(dscp_table == NULL))
+		return -1;
+
+	p = pipeline_find(pipeline_name);
+	if ((p == NULL) ||
+		(table_id >= p->n_tables))
+		return -1;
+
+	/* Allocate request */
+	req = pipeline_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = PIPELINE_REQ_TABLE_DSCP_TABLE_UPDATE;
+	req->id = table_id;
+	req->table_dscp_table_update.dscp_mask = dscp_mask;
+	memcpy(&req->table_dscp_table_update.dscp_table,
+		dscp_table, sizeof(*dscp_table));
+
+	/* Send request and wait for response */
+	rsp = pipeline_msg_send_recv(p, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+
+	/* Free response */
+	pipeline_msg_free(rsp);
+
+	return status;
+}
+
 /**
  * Data plane threads: message handling
  */
@@ -2081,6 +2136,24 @@ pipeline_msg_handle_table_rule_mtr_read(struct pipeline_data *p,
 	return rsp;
 }
 
+static struct pipeline_msg_rsp *
+pipeline_msg_handle_table_dscp_table_update(struct pipeline_data *p,
+	struct pipeline_msg_req *req)
+{
+	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+	uint32_t table_id = req->id;
+	uint64_t dscp_mask = req->table_dscp_table_update.dscp_mask;
+	struct rte_table_action_dscp_table *dscp_table =
+		&req->table_dscp_table_update.dscp_table;
+	struct rte_table_action *a = p->table_data[table_id].a;
+
+	rsp->status = rte_table_action_dscp_table_update(a,
+		dscp_mask,
+		dscp_table);
+
+	return rsp;
+}
+
 static void
 pipeline_msg_handle(struct pipeline_data *p)
 {
@@ -2145,6 +2218,10 @@ pipeline_msg_handle(struct pipeline_data *p)
 			rsp = pipeline_msg_handle_table_rule_mtr_read(p, req);
 			break;
 
+		case PIPELINE_REQ_TABLE_DSCP_TABLE_UPDATE:
+			rsp = pipeline_msg_handle_table_dscp_table_update(p, req);
+			break;
+
 		default:
 			rsp = (struct pipeline_msg_rsp *) req;
 			rsp->status = -1;
-- 
2.9.3

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

* [dpdk-dev] [PATCH v2 38/44] ip_pipeline: add cli to read ttl stats
  2018-03-12 17:25   ` [dpdk-dev] [PATCH v2 00/44] ip_pipeline: refactoring Jasvinder Singh
                       ` (36 preceding siblings ...)
  2018-03-12 17:26     ` [dpdk-dev] [PATCH v2 37/44] ip_pipeline: add cli to update dscp table Jasvinder Singh
@ 2018-03-12 17:26     ` Jasvinder Singh
  2018-03-12 17:26     ` [dpdk-dev] [PATCH v2 39/44] ip_pipeline: add l2fwd example Jasvinder Singh
                       ` (5 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-12 17:26 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add command to read the ttl stats.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/cli.c      | 22 +++++++++++
 examples/ip_pipeline/pipeline.h |  7 ++++
 examples/ip_pipeline/thread.c   | 84 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 113 insertions(+)

diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index 3d74ece..a4965a6 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -3832,6 +3832,18 @@ cmd_pipeline_table_dscp(char **tokens,
 }
 
 /**
+ * pipeline <pipeline_name> table <table_id> rule read ttl [clear]
+ */
+static void
+cmd_pipeline_table_rule_ttl_read(char **tokens,
+	uint32_t n_tokens __rte_unused,
+	char *out,
+	size_t out_size)
+{
+	snprintf(out, out_size, MSG_CMD_UNIMPLEM, tokens[0]);
+}
+
+/**
  * thread <thread_id> pipeline <pipeline_name> enable
  */
 static void
@@ -4163,6 +4175,16 @@ cli_process(char *in, char *out, size_t out_size)
 				out, out_size);
 			return;
 		}
+
+		if ((n_tokens >= 7) &&
+			(strcmp(tokens[2], "table") == 0) &&
+			(strcmp(tokens[4], "rule") == 0) &&
+			(strcmp(tokens[5], "read") == 0) &&
+			(strcmp(tokens[6], "ttl") == 0)) {
+			cmd_pipeline_table_rule_ttl_read(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
 	}
 
 	if (strcmp(tokens[0], "thread") == 0) {
diff --git a/examples/ip_pipeline/pipeline.h b/examples/ip_pipeline/pipeline.h
index 598bed0..208e407 100644
--- a/examples/ip_pipeline/pipeline.h
+++ b/examples/ip_pipeline/pipeline.h
@@ -342,4 +342,11 @@ pipeline_table_dscp_table_update(const char *pipeline_name,
 	uint64_t dscp_mask,
 	struct rte_table_action_dscp_table *dscp_table);
 
+int
+pipeline_table_rule_ttl_read(const char *pipeline_name,
+	uint32_t table_id,
+	void *data,
+	struct rte_table_action_ttl_counters *stats,
+	int clear);
+
 #endif /* _INCLUDE_PIPELINE_H_ */
diff --git a/examples/ip_pipeline/thread.c b/examples/ip_pipeline/thread.c
index 3c1318d..065435d 100644
--- a/examples/ip_pipeline/thread.c
+++ b/examples/ip_pipeline/thread.c
@@ -502,6 +502,7 @@ enum pipeline_req_type {
 	PIPELINE_REQ_TABLE_MTR_PROFILE_DELETE,
 	PIPELINE_REQ_TABLE_RULE_MTR_READ,
 	PIPELINE_REQ_TABLE_DSCP_TABLE_UPDATE,
+	PIPELINE_REQ_TABLE_RULE_TTL_READ,
 	PIPELINE_REQ_MAX
 };
 
@@ -555,6 +556,11 @@ struct pipeline_msg_req_table_dscp_table_update {
 	struct rte_table_action_dscp_table dscp_table;
 };
 
+struct pipeline_msg_req_table_rule_ttl_read {
+	void *data;
+	int clear;
+};
+
 struct pipeline_msg_req {
 	enum pipeline_req_type type;
 	uint32_t id; /* Port IN, port OUT or table ID */
@@ -572,6 +578,7 @@ struct pipeline_msg_req {
 		struct pipeline_msg_req_table_mtr_profile_delete table_mtr_profile_delete;
 		struct pipeline_msg_req_table_rule_mtr_read table_rule_mtr_read;
 		struct pipeline_msg_req_table_dscp_table_update table_dscp_table_update;
+		struct pipeline_msg_req_table_rule_ttl_read table_rule_ttl_read;
 	};
 };
 
@@ -603,6 +610,10 @@ struct pipeline_msg_rsp_table_rule_mtr_read {
 	struct rte_table_action_mtr_counters stats;
 };
 
+struct pipeline_msg_rsp_table_rule_ttl_read {
+	struct rte_table_action_ttl_counters stats;
+};
+
 struct pipeline_msg_rsp {
 	int status;
 
@@ -615,6 +626,7 @@ struct pipeline_msg_rsp {
 		struct pipeline_msg_rsp_table_rule_add_default table_rule_add_default;
 		struct pipeline_msg_rsp_table_rule_stats_read table_rule_stats_read;
 		struct pipeline_msg_rsp_table_rule_mtr_read table_rule_mtr_read;
+		struct pipeline_msg_rsp_table_rule_ttl_read table_rule_ttl_read;
 	};
 };
 
@@ -1469,6 +1481,56 @@ pipeline_table_dscp_table_update(const char *pipeline_name,
 	return status;
 }
 
+int
+pipeline_table_rule_ttl_read(const char *pipeline_name,
+	uint32_t table_id,
+	void *data,
+	struct rte_table_action_ttl_counters *stats,
+	int clear)
+{
+	struct pipeline *p;
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if ((pipeline_name == NULL) ||
+		(data == NULL) ||
+		(stats == NULL))
+		return -1;
+
+	p = pipeline_find(pipeline_name);
+	if ((p == NULL) ||
+		(table_id >= p->n_tables))
+		return -1;
+
+	/* Allocate request */
+	req = pipeline_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = PIPELINE_REQ_TABLE_RULE_TTL_READ;
+	req->id = table_id;
+	req->table_rule_ttl_read.data = data;
+	req->table_rule_ttl_read.clear = clear;
+
+	/* Send request and wait for response */
+	rsp = pipeline_msg_send_recv(p, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+	if (status)
+		memcpy(stats, &rsp->table_rule_ttl_read.stats, sizeof(*stats));
+
+	/* Free response */
+	pipeline_msg_free(rsp);
+
+	return status;
+}
+
 /**
  * Data plane threads: message handling
  */
@@ -2154,6 +2216,24 @@ pipeline_msg_handle_table_dscp_table_update(struct pipeline_data *p,
 	return rsp;
 }
 
+static struct pipeline_msg_rsp *
+pipeline_msg_handle_table_rule_ttl_read(struct pipeline_data *p,
+	struct pipeline_msg_req *req)
+{
+	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+	uint32_t table_id = req->id;
+	void *data = req->table_rule_ttl_read.data;
+	int clear = req->table_rule_ttl_read.clear;
+	struct rte_table_action *a = p->table_data[table_id].a;
+
+	rsp->status = rte_table_action_ttl_read(a,
+		data,
+		&rsp->table_rule_ttl_read.stats,
+		clear);
+
+	return rsp;
+}
+
 static void
 pipeline_msg_handle(struct pipeline_data *p)
 {
@@ -2222,6 +2302,10 @@ pipeline_msg_handle(struct pipeline_data *p)
 			rsp = pipeline_msg_handle_table_dscp_table_update(p, req);
 			break;
 
+		case PIPELINE_REQ_TABLE_RULE_TTL_READ:
+			rsp = pipeline_msg_handle_table_rule_ttl_read(p, req);
+			break;
+
 		default:
 			rsp = (struct pipeline_msg_rsp *) req;
 			rsp->status = -1;
-- 
2.9.3

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

* [dpdk-dev] [PATCH v2 39/44] ip_pipeline: add l2fwd example
  2018-03-12 17:25   ` [dpdk-dev] [PATCH v2 00/44] ip_pipeline: refactoring Jasvinder Singh
                       ` (37 preceding siblings ...)
  2018-03-12 17:26     ` [dpdk-dev] [PATCH v2 38/44] ip_pipeline: add cli to read ttl stats Jasvinder Singh
@ 2018-03-12 17:26     ` Jasvinder Singh
  2018-03-12 17:26     ` [dpdk-dev] [PATCH v2 40/44] ip_pipeline: add KNI port example Jasvinder Singh
                       ` (4 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-12 17:26 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Kevin Laatz

This patch add the configuration file for l2fwd example. It
includes commands to build the packet processing stage (pipeline),
defining action, add rules to its table, etc.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
---
 examples/ip_pipeline/examples/l2fwd.cli | 53 +++++++++++++++++++++++++++++++++
 1 file changed, 53 insertions(+)
 create mode 100644 examples/ip_pipeline/examples/l2fwd.cli

diff --git a/examples/ip_pipeline/examples/l2fwd.cli b/examples/ip_pipeline/examples/l2fwd.cli
new file mode 100644
index 0000000..5b9d529
--- /dev/null
+++ b/examples/ip_pipeline/examples/l2fwd.cli
@@ -0,0 +1,53 @@
+; SPDX-License-Identifier: BSD-3-Clause
+; Copyright(c) 2010-2018 Intel Corporation
+
+; The pipeline below implements a simple pass-through connection between the
+; input ports to the output ports, as in this diagram:
+;                 ________________
+; LINK0 RXQ0 --->|................|---> LINK1 TXQ0
+;                |                |
+; LINK1 RXQ0 --->|................|---> LINK0 TXQ0
+;                |    PIPELINE0   |
+; LINK2 RXQ0 --->|................|---> LINK3 TXQ0
+;                |                |
+; LINK3 RXQ0 --->|................|---> LINK2 TXQ0
+;                |________________|
+;
+
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+
+link LINK0 dev 0000:02:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+link LINK1 dev 0000:02:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+link LINK2 dev 0000:06:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+link LINK3 dev 0000:06:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+
+table action profile AP0 ipv4 offset 270 fwd
+
+pipeline PIPELINE0 period 10 offset_port_id 0 cpu 0
+
+pipeline PIPELINE0 port in bsz 32 link LINK0 rxq 0
+pipeline PIPELINE0 port in bsz 32 link LINK1 rxq 0
+pipeline PIPELINE0 port in bsz 32 link LINK2 rxq 0
+pipeline PIPELINE0 port in bsz 32 link LINK3 rxq 0
+
+pipeline PIPELINE0 port out bsz 32 link LINK0 txq 0
+pipeline PIPELINE0 port out bsz 32 link LINK1 txq 0
+pipeline PIPELINE0 port out bsz 32 link LINK2 txq 0
+pipeline PIPELINE0 port out bsz 32 link LINK3 txq 0
+
+pipeline PIPELINE0 table match stub action AP0
+pipeline PIPELINE0 table match stub action AP0
+pipeline PIPELINE0 table match stub action AP0
+pipeline PIPELINE0 table match stub action AP0
+
+pipeline PIPELINE0 port in 0 table 0
+pipeline PIPELINE0 port in 1 table 1
+pipeline PIPELINE0 port in 2 table 2
+pipeline PIPELINE0 port in 3 table 3
+
+thread 1 pipeline PIPELINE0 enable
+
+pipeline PIPELINE0 table 0 rule add match default action fwd port 1
+pipeline PIPELINE0 table 1 rule add match default action fwd port 0
+pipeline PIPELINE0 table 2 rule add match default action fwd port 3
+pipeline PIPELINE0 table 3 rule add match default action fwd port 2
-- 
2.9.3

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

* [dpdk-dev] [PATCH v2 40/44] ip_pipeline: add KNI port example
  2018-03-12 17:25   ` [dpdk-dev] [PATCH v2 00/44] ip_pipeline: refactoring Jasvinder Singh
                       ` (38 preceding siblings ...)
  2018-03-12 17:26     ` [dpdk-dev] [PATCH v2 39/44] ip_pipeline: add l2fwd example Jasvinder Singh
@ 2018-03-12 17:26     ` Jasvinder Singh
  2018-03-12 17:26     ` [dpdk-dev] [PATCH v2 41/44] ip_pipeline: add TAP " Jasvinder Singh
                       ` (3 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-12 17:26 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Kevin Laatz

Add example to illustrate the pipeline functioning with KNI
interface.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
---
 examples/ip_pipeline/examples/kni.cli | 69 +++++++++++++++++++++++++++++++++++
 1 file changed, 69 insertions(+)
 create mode 100644 examples/ip_pipeline/examples/kni.cli

diff --git a/examples/ip_pipeline/examples/kni.cli b/examples/ip_pipeline/examples/kni.cli
new file mode 100644
index 0000000..1438340
--- /dev/null
+++ b/examples/ip_pipeline/examples/kni.cli
@@ -0,0 +1,69 @@
+; SPDX-License-Identifier: BSD-3-Clause
+; Copyright(c) 2010-2018 Intel Corporation
+
+;                 _______________          ______________________
+;                |               |  KNI0  |                      |
+; LINK0 RXQ0 --->|...............|------->|--+                   |
+;                |               |  KNI1  |  | br0               |
+; LINK1 TXQ0 <---|...............|<-------|<-+                   |
+;                |               |        |     Linux Kernel     |
+;                |   PIPELINE0   |        |     Network Stack    |
+;                |               |  KNI1  |                      |
+; LINK1 RXQ0 --->|...............|------->|--+                   |
+;                |               |  KNI0  |  | br0               |
+; LINK0 TXQ0 <---|...............|<-------|<-+                   |
+;                |_______________|        |______________________|
+;
+; Insert Linux kernel KNI module:
+;    [Linux]$ insmod rte_kni.ko
+;
+; Configure Linux kernel bridge between KNI0 and KNI1 interfaces:
+;    [Linux]$ brctl addbr br0
+;    [Linux]$ brctl addif br0 KNI0
+;    [Linux]$ brctl addif br0 KNI1
+;    [Linux]$ ifconfig br0 up
+;    [Linux]$ ifconfig KNI0 up
+;    [Linux]$ ifconfig KNI1 up
+;
+; Monitor packet forwarding performed by Linux kernel between KNI0 and KNI1:
+;    [Linux]$ tcpdump -i KNI0
+;    [Linux]$ tcpdump -i KNI1
+
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+
+link LINK0 dev 0000:02:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+link LINK1 dev 0000:02:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+
+kni KNI0 link LINK0 mempool MEMPOOL0
+kni KNI1 link LINK1 mempool MEMPOOL0
+
+table action profile AP0 ipv4 offset 270 fwd
+
+pipeline PIPELINE0 period 10 offset_port_id 0 cpu 0
+
+pipeline PIPELINE0 port in bsz 32 link LINK0 rxq 0
+pipeline PIPELINE0 port in bsz 32 kni KNI1
+pipeline PIPELINE0 port in bsz 32 link LINK1 rxq 0
+pipeline PIPELINE0 port in bsz 32 kni KNI0
+
+pipeline PIPELINE0 port out bsz 32 kni KNI0
+pipeline PIPELINE0 port out bsz 32 link LINK1 txq 0
+pipeline PIPELINE0 port out bsz 32 kni KNI1
+pipeline PIPELINE0 port out bsz 32 link LINK0 txq 0
+
+pipeline PIPELINE0 table match stub action AP0
+pipeline PIPELINE0 table match stub action AP0
+pipeline PIPELINE0 table match stub action AP0
+pipeline PIPELINE0 table match stub action AP0
+
+pipeline PIPELINE0 port in 0 table 0
+pipeline PIPELINE0 port in 1 table 1
+pipeline PIPELINE0 port in 2 table 2
+pipeline PIPELINE0 port in 3 table 3
+
+thread 1 pipeline PIPELINE0 enable
+
+pipeline PIPELINE0 table 0 rule add match default action fwd port 0
+pipeline PIPELINE0 table 1 rule add match default action fwd port 1
+pipeline PIPELINE0 table 2 rule add match default action fwd port 2
+pipeline PIPELINE0 table 3 rule add match default action fwd port 3
-- 
2.9.3

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

* [dpdk-dev] [PATCH v2 41/44] ip_pipeline: add TAP port example
  2018-03-12 17:25   ` [dpdk-dev] [PATCH v2 00/44] ip_pipeline: refactoring Jasvinder Singh
                       ` (39 preceding siblings ...)
  2018-03-12 17:26     ` [dpdk-dev] [PATCH v2 40/44] ip_pipeline: add KNI port example Jasvinder Singh
@ 2018-03-12 17:26     ` Jasvinder Singh
  2018-03-12 17:26     ` [dpdk-dev] [PATCH v2 42/44] ip_pipeline: add route example Jasvinder Singh
                       ` (2 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-12 17:26 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Kevin Laatz

Add example to illustrate the pipeline functioning with TAP
interface.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
---
 examples/ip_pipeline/examples/tap.cli | 66 +++++++++++++++++++++++++++++++++++
 1 file changed, 66 insertions(+)
 create mode 100644 examples/ip_pipeline/examples/tap.cli

diff --git a/examples/ip_pipeline/examples/tap.cli b/examples/ip_pipeline/examples/tap.cli
new file mode 100644
index 0000000..600cea2
--- /dev/null
+++ b/examples/ip_pipeline/examples/tap.cli
@@ -0,0 +1,66 @@
+; SPDX-License-Identifier: BSD-3-Clause
+; Copyright(c) 2010-2018 Intel Corporation
+
+;                 _______________          ______________________
+;                |               |  TAP0  |                      |
+; LINK0 RXQ0 --->|...............|------->|--+                   |
+;                |               |  TAP1  |  | br0               |
+; LINK1 TXQ0 <---|...............|<-------|<-+                   |
+;                |               |        |     Linux Kernel     |
+;                |   PIPELINE0   |        |     Network Stack    |
+;                |               |  TAP1  |                      |
+; LINK1 RXQ0 --->|...............|------->|--+                   |
+;                |               |  TAP0  |  | br0               |
+; LINK0 TXQ0 <---|...............|<-------|<-+                   |
+;                |_______________|        |______________________|
+;
+; Configure Linux kernel bridge between TAP0 and TAP1 interfaces:
+;    [Linux]$ brctl addbr br0
+;    [Linux]$ brctl addif br0 TAP0
+;    [Linux]$ brctl addif br0 TAP1
+;    [Linux]$ ifconfig TAP0 up
+;    [Linux]$ ifconfig TAP1 up
+;    [Linux]$ ifconfig br0 up
+;
+; Monitor packet forwarding performed by Linux kernel between TAP0 and TAP1:
+;    [Linux]$ tcpdump -i TAP0
+;    [Linux]$ tcpdump -i TAP1
+
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+
+link LINK0 dev 0000:02:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+link LINK1 dev 0000:02:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+
+tap TAP0
+tap TAP1
+
+table action profile AP0 ipv4 offset 270 fwd
+
+pipeline PIPELINE0 period 10 offset_port_id 0 cpu 0
+
+pipeline PIPELINE0 port in bsz 32 link LINK0 rxq 0
+pipeline PIPELINE0 port in bsz 32 tap TAP1 mempool MEMPOOL0 mtu 1500
+pipeline PIPELINE0 port in bsz 32 link LINK1 rxq 0
+pipeline PIPELINE0 port in bsz 32 tap TAP0 mempool MEMPOOL0 mtu 1500
+
+pipeline PIPELINE0 port out bsz 32 tap TAP0
+pipeline PIPELINE0 port out bsz 32 link LINK1 txq 0
+pipeline PIPELINE0 port out bsz 32 tap TAP1
+pipeline PIPELINE0 port out bsz 32 link LINK0 txq 0
+
+pipeline PIPELINE0 table match stub action AP0
+pipeline PIPELINE0 table match stub action AP0
+pipeline PIPELINE0 table match stub action AP0
+pipeline PIPELINE0 table match stub action AP0
+
+pipeline PIPELINE0 port in 0 table 0
+pipeline PIPELINE0 port in 1 table 1
+pipeline PIPELINE0 port in 2 table 2
+pipeline PIPELINE0 port in 3 table 3
+
+thread 1 pipeline PIPELINE0 enable
+
+pipeline PIPELINE0 table 0 rule add match default action fwd port 0
+pipeline PIPELINE0 table 1 rule add match default action fwd port 1
+pipeline PIPELINE0 table 2 rule add match default action fwd port 2
+pipeline PIPELINE0 table 3 rule add match default action fwd port 3
-- 
2.9.3

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

* [dpdk-dev] [PATCH v2 42/44] ip_pipeline: add route example
  2018-03-12 17:25   ` [dpdk-dev] [PATCH v2 00/44] ip_pipeline: refactoring Jasvinder Singh
                       ` (40 preceding siblings ...)
  2018-03-12 17:26     ` [dpdk-dev] [PATCH v2 41/44] ip_pipeline: add TAP " Jasvinder Singh
@ 2018-03-12 17:26     ` Jasvinder Singh
  2018-03-12 17:26     ` [dpdk-dev] [PATCH v2 43/44] ip_pipeline: add firewall example Jasvinder Singh
  2018-03-12 17:26     ` [dpdk-dev] [PATCH v2 44/44] ip_pipeline: add flow classification example Jasvinder Singh
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-12 17:26 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Reshma Pattan

Add example to built pipeline with LPM table to demonstrate layer 3
routing.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Reshma Pattan <reshma.pattan@intel.com>
---
 examples/ip_pipeline/examples/route.cli | 60 +++++++++++++++++++++++++++++++++
 1 file changed, 60 insertions(+)
 create mode 100644 examples/ip_pipeline/examples/route.cli

diff --git a/examples/ip_pipeline/examples/route.cli b/examples/ip_pipeline/examples/route.cli
new file mode 100644
index 0000000..50f0a10
--- /dev/null
+++ b/examples/ip_pipeline/examples/route.cli
@@ -0,0 +1,60 @@
+; SPDX-License-Identifier: BSD-3-Clause
+; Copyright(c) 2010-2018 Intel Corporation
+
+;                 _______________
+; LINK0 RXQ0 --->|               |---> LINK0 TXQ0
+;                |               |
+; LINK1 RXQ0 --->|               |---> LINK1 TXQ0
+;                |    Routing    |
+; LINK2 RXQ0 --->|               |---> LINK2 TXQ0
+;                |               |
+; LINK3 RXQ0 --->|               |---> LINK3 TXQ0
+;                |_______________|
+;                        |
+;                        +-----------> SINK0 (route miss)
+;
+; Input packet: Ethernet/IPv4
+;
+; Packet buffer layout:
+; #   Field Name       Offset (Bytes)   Size (Bytes)
+; 0   Mbuf             0                128
+; 1   Headroom         128              128
+; 2   Ethernet header  256              14
+; 3   IPv4 header      270              20
+
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+
+link LINK0 dev 0000:02:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+link LINK1 dev 0000:02:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+link LINK2 dev 0000:06:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+link LINK3 dev 0000:06:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+
+table action profile AP0 ipv4 offset 270 fwd encap ether
+
+pipeline PIPELINE0 period 10 offset_port_id 0 cpu 0
+
+pipeline PIPELINE0 port in bsz 32 link LINK0 rxq 0
+pipeline PIPELINE0 port in bsz 32 link LINK1 rxq 0
+pipeline PIPELINE0 port in bsz 32 link LINK2 rxq 0
+pipeline PIPELINE0 port in bsz 32 link LINK3 rxq 0
+
+pipeline PIPELINE0 port out bsz 32 link LINK0 txq 0
+pipeline PIPELINE0 port out bsz 32 link LINK1 txq 0
+pipeline PIPELINE0 port out bsz 32 link LINK2 txq 0
+pipeline PIPELINE0 port out bsz 32 link LINK3 txq 0
+pipeline PIPELINE0 port out bsz 32 sink SINK0
+
+pipeline PIPELINE0 table match lpm ipv4 offset 286 size 4K action AP0
+
+pipeline PIPELINE0 port in 0 table 0
+pipeline PIPELINE0 port in 1 table 0
+pipeline PIPELINE0 port in 2 table 0
+pipeline PIPELINE0 port in 3 table 0
+
+thread 1 pipeline PIPELINE0 enable
+
+pipeline PIPELINE0 table 0 rule add match default action fwd port 4
+pipeline PIPELINE0 table 0 rule add match lpm ipv4 100.0.0.0 10 action fwd port 0 encap ether a0:a1:a2:a3:a4:a5 00:01:02:03:04:05
+pipeline PIPELINE0 table 0 rule add match lpm ipv4 100.64.0.0 10 action fwd port 1 encap ether b0:b1:b2:b3:b4:b5 10:11:12:13:14:15
+pipeline PIPELINE0 table 0 rule add match lpm ipv4 100.128.0.0 10 action fwd port 2 encap ether c0:c1:c2:c3:c4:c5 20:21:22:23:24:25
+pipeline PIPELINE0 table 0 rule add match lpm ipv4 100.192.0.0 10 action fwd port 3 encap ether d0:d1:d2:d3:d4:d5 30:31:32:33:34:35
-- 
2.9.3

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

* [dpdk-dev] [PATCH v2 43/44] ip_pipeline: add firewall example
  2018-03-12 17:25   ` [dpdk-dev] [PATCH v2 00/44] ip_pipeline: refactoring Jasvinder Singh
                       ` (41 preceding siblings ...)
  2018-03-12 17:26     ` [dpdk-dev] [PATCH v2 42/44] ip_pipeline: add route example Jasvinder Singh
@ 2018-03-12 17:26     ` Jasvinder Singh
  2018-03-12 17:26     ` [dpdk-dev] [PATCH v2 44/44] ip_pipeline: add flow classification example Jasvinder Singh
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-12 17:26 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add example to built pipeline with ACL table to demonstrate
the firewall operation.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/examples/firewall.cli | 59 ++++++++++++++++++++++++++++++
 1 file changed, 59 insertions(+)
 create mode 100644 examples/ip_pipeline/examples/firewall.cli

diff --git a/examples/ip_pipeline/examples/firewall.cli b/examples/ip_pipeline/examples/firewall.cli
new file mode 100644
index 0000000..269256c
--- /dev/null
+++ b/examples/ip_pipeline/examples/firewall.cli
@@ -0,0 +1,59 @@
+; SPDX-License-Identifier: BSD-3-Clause
+; Copyright(c) 2010-2018 Intel Corporation
+
+;                 _______________
+; LINK0 RXQ0 --->|               |---> LINK0 TXQ0
+;                |               |
+; LINK1 RXQ0 --->|               |---> LINK1 TXQ0
+;                |   Firewall    |
+; LINK2 RXQ0 --->|               |---> LINK2 TXQ0
+;                |               |
+; LINK3 RXQ0 --->|               |---> LINK3 TXQ0
+;                |_______________|
+;                        |
+;                       -+-
+;
+; Input packet: Ethernet/IPv4
+;
+; Packet buffer layout:
+; #   Field Name            Offset (Bytes)      Size (Bytes)
+; 0   Mbuf                  0                   128
+; 1   Headroom              128                 128
+; 2   Ethernet header       256                 14
+; 3   IPv4 header           270                 20
+
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+
+link LINK0 dev 0000:02:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+link LINK1 dev 0000:02:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+link LINK2 dev 0000:06:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+link LINK3 dev 0000:06:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+
+table action profile AP0 ipv4 offset 270 fwd
+
+pipeline PIPELINE0 period 10 offset_port_id 0 cpu 0
+
+pipeline PIPELINE0 port in bsz 32 link LINK0 rxq 0
+pipeline PIPELINE0 port in bsz 32 link LINK1 rxq 0
+pipeline PIPELINE0 port in bsz 32 link LINK2 rxq 0
+pipeline PIPELINE0 port in bsz 32 link LINK3 rxq 0
+
+pipeline PIPELINE0 port out bsz 32 link LINK0 txq 0
+pipeline PIPELINE0 port out bsz 32 link LINK1 txq 0
+pipeline PIPELINE0 port out bsz 32 link LINK2 txq 0
+pipeline PIPELINE0 port out bsz 32 link LINK3 txq 0
+
+pipeline PIPELINE0 table match acl ipv4 offset 270 size 4K action AP0
+
+pipeline PIPELINE0 port in 0 table 0
+pipeline PIPELINE0 port in 1 table 0
+pipeline PIPELINE0 port in 2 table 0
+pipeline PIPELINE0 port in 3 table 0
+
+thread 1 pipeline PIPELINE0 enable
+
+pipeline PIPELINE0 table 0 rule add match default action fwd drop
+pipeline PIPELINE0 table 0 rule add match acl priority 0 ipv4 0.0.0.0 0 100.0.0.0 10 0 65535 0 65535 6 action fwd port 0
+pipeline PIPELINE0 table 0 rule add match acl priority 0 ipv4 0.0.0.0 0 100.64.0.0 10 0 65535 0 65535 6 action fwd port 1
+pipeline PIPELINE0 table 0 rule add match acl priority 0 ipv4 0.0.0.0 0 100.128.0.0 10 0 65535 0 65535 6 action fwd port 2
+pipeline PIPELINE0 table 0 rule add match acl priority 0 ipv4 0.0.0.0 0 100.192.0.0 10 0 65535 0 65535 6 action fwd port 3
-- 
2.9.3

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

* [dpdk-dev] [PATCH v2 44/44] ip_pipeline: add flow classification example
  2018-03-12 17:25   ` [dpdk-dev] [PATCH v2 00/44] ip_pipeline: refactoring Jasvinder Singh
                       ` (42 preceding siblings ...)
  2018-03-12 17:26     ` [dpdk-dev] [PATCH v2 43/44] ip_pipeline: add firewall example Jasvinder Singh
@ 2018-03-12 17:26     ` Jasvinder Singh
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-12 17:26 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Fan Zhang

Add example to build pipeline with hash table to classify the
ingress traffic.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Fan Zhang <roy.fan.zhang@intel.com>
---
 examples/ip_pipeline/examples/flow.cli | 60 ++++++++++++++++++++++++++++++++++
 1 file changed, 60 insertions(+)
 create mode 100644 examples/ip_pipeline/examples/flow.cli

diff --git a/examples/ip_pipeline/examples/flow.cli b/examples/ip_pipeline/examples/flow.cli
new file mode 100644
index 0000000..60b8445
--- /dev/null
+++ b/examples/ip_pipeline/examples/flow.cli
@@ -0,0 +1,60 @@
+; SPDX-License-Identifier: BSD-3-Clause
+; Copyright(c) 2010-2018 Intel Corporation
+
+;                 ________________
+; LINK0 RXQ0 --->|                |---> LINK0 TXQ0
+;                |                |
+; LINK1 RXQ0 --->|                |---> LINK1 TXQ0
+;                |      Flow      |
+; LINK2 RXQ0 --->| Classification |---> LINK2 TXQ0
+;                |                |
+; LINK3 RXQ0 --->|                |---> LINK3 TXQ0
+;                |________________|
+;                        |
+;                        +-----------> SINK0 (flow lookup miss)
+;
+; Input packet: Ethernet/IPv4
+;
+; Packet buffer layout:
+; #   Field Name       Offset (Bytes)   Size (Bytes)
+; 0   Mbuf             0                128
+; 1   Headroom         128              128
+; 2   Ethernet header  256              14
+; 3   IPv4 header      270              20
+
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+
+link LINK0 dev 0000:02:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+link LINK1 dev 0000:02:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+link LINK2 dev 0000:06:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+link LINK3 dev 0000:06:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+
+table action profile AP0 ipv4 offset 270 fwd
+
+pipeline PIPELINE0 period 10 offset_port_id 0 cpu 0
+
+pipeline PIPELINE0 port in bsz 32 link LINK0 rxq 0
+pipeline PIPELINE0 port in bsz 32 link LINK1 rxq 0
+pipeline PIPELINE0 port in bsz 32 link LINK2 rxq 0
+pipeline PIPELINE0 port in bsz 32 link LINK3 rxq 0
+
+pipeline PIPELINE0 port out bsz 32 link LINK0 txq 0
+pipeline PIPELINE0 port out bsz 32 link LINK1 txq 0
+pipeline PIPELINE0 port out bsz 32 link LINK2 txq 0
+pipeline PIPELINE0 port out bsz 32 link LINK3 txq 0
+pipeline PIPELINE0 port out bsz 32 sink SINK0
+
+pipeline PIPELINE0 table match hash ext key 16 mask 00FF0000FFFFFFFFFFFFFFFFFFFFFFFF offset 278 buckets 16K size 65K action AP0
+
+pipeline PIPELINE0 port in 0 table 0
+pipeline PIPELINE0 port in 1 table 0
+pipeline PIPELINE0 port in 2 table 0
+pipeline PIPELINE0 port in 3 table 0
+
+thread 1 pipeline PIPELINE0 enable
+
+pipeline PIPELINE0 table 0 rule add match default action fwd port 4
+pipeline PIPELINE0 table 0 rule add match hash ipv4_5tuple 100.0.0.10 200.0.0.10 100 200 6 action fwd port 0
+pipeline PIPELINE0 table 0 rule add match hash ipv4_5tuple 100.0.0.11 200.0.0.11 101 201 6 action fwd port 1
+pipeline PIPELINE0 table 0 rule add match hash ipv4_5tuple 100.0.0.12 200.0.0.12 102 202 6 action fwd port 2
+pipeline PIPELINE0 table 0 rule add match hash ipv4_5tuple 100.0.0.13 200.0.0.13 103 203 6 action fwd port 3
-- 
2.9.3

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

* [dpdk-dev] [PATCH v3 00/44] ip_pipeline: refactoring
  2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 01/44] pipeline: add pipeline table action APIs Jasvinder Singh
@ 2018-03-16 17:56       ` Jasvinder Singh
  2018-03-16 17:56         ` [dpdk-dev] [PATCH v3 01/44] pipeline: add pipeline table action APIs Jasvinder Singh
  2018-03-16 17:58       ` [dpdk-dev] [PATCH v3 00/44] ip_pipeline: refactoring Jasvinder Singh
  1 sibling, 1 reply; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-16 17:56 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Refactored the IP pipeline application. As result, the code base
size (lines of code) reduces by ~60%.

1. Moved table actions into the librte_pipeline library. As result,
   the pre-fabricated pipelines from the application pipeline folder
   were removed. The flexibility is greatly improved, as now any
   action can be combined with any match (i.e. table type), which
   was not possible before.

2. Removed configuration file as the initialization method. Now
   all the pipelines are set up and assigned to threads through
   CLI commands for improved flexibility.

3. Replaced the local CLI with remote CLI. Any standard TCP
   client (e.g. telnet, netcat) can now connect to the app,
   send request as command string through the network and wait
   for the response string before pushing the next command.
   Results in better flexibility and automation.

v3:
- add IPv4, TCP/UDP checksum update for NAT action.
- add IPv4 Checksum update for TTL action.
- fix compilation warning

v2:
- split the patch that removes the existing pipeline components
  into multiple patches.
- fix checkpatch errors.

Jasvinder Singh (44):
  pipeline: add pipeline table action APIs
  pipeline: get pipeline table action params
  pipeline: add traffic metering action
  pipeline: add traffic manager action
  pipeline: add packet encapsulation action
  pipeline: add nat action
  pipeline: add ttl update action
  pipeline: add statistics read action
  pipeline: add timestamp action
  ip_pipeline: remove passthrough pipeline
  ip_pipeline: remove routing pipeline
  ip_pipeline: remove flow classification pipeline
  ip_pipeline: remove flow actions pipeline
  ip_pipeline: remove firewall pipeline
  ip_pipeline: remove master pipeline
  ip_pipeline: remove config
  ip_pipeline: rework and improvements
  ip_pipeline: add cli interface
  ip_pipeline: add mempool object for pipeline
  ip_pipeline: add link object
  ip_pipeline: add software queue object
  ip_pipeline: add traffic manager object
  ip_pipeline: add tap object
  ip_pipeline: add kni object
  ip_pipeline: add action profile object
  ip_pipeline: add pipeline object
  ip_pipeline: add threads
  ip_pipeline: add thread runtime
  ip_pipeline: add cli to enable and disable pipeline
  ip_pipeline: add cli to enable and disable pipeline port
  ip_pipeline: add cli to read pipeline port and table stats
  ip_pipeline: add cli for pipeline table entries
  ip_pipeline: add cli to delete pipeline table entry
  ip_pipeline: add cli to read pipeline table entry stats
  ip_pipeline: add cli to configure meter profile
  ip_pipeline: add cli to read meter stats
  ip_pipeline: add cli to update dscp table
  ip_pipeline: add cli to read ttl stats
  ip_pipeline: add l2fwd example
  ip_pipeline: add KNI port example
  ip_pipeline: add TAP port example
  ip_pipeline: add route example
  ip_pipeline: add firewall example
  ip_pipeline: add flow classification example

 doc/api/doxy-api-index.md                          |    1 +
 examples/ip_pipeline/Makefile                      |   49 +-
 examples/ip_pipeline/action.c                      |  165 +
 examples/ip_pipeline/action.h                      |   44 +
 examples/ip_pipeline/app.h                         | 1401 -------
 examples/ip_pipeline/cli.c                         | 4261 ++++++++++++++++++++
 examples/ip_pipeline/cli.h                         |   18 +
 examples/ip_pipeline/common.h                      |   12 +
 examples/ip_pipeline/config/action.cfg             |   68 -
 examples/ip_pipeline/config/action.sh              |  119 -
 examples/ip_pipeline/config/action.txt             |    8 -
 examples/ip_pipeline/config/diagram-generator.py   |  317 --
 .../ip_pipeline/config/edge_router_downstream.cfg  |   97 -
 .../ip_pipeline/config/edge_router_downstream.sh   |   13 -
 .../ip_pipeline/config/edge_router_upstream.cfg    |  124 -
 .../ip_pipeline/config/edge_router_upstream.sh     |   33 -
 examples/ip_pipeline/config/firewall.cfg           |   68 -
 examples/ip_pipeline/config/firewall.sh            |   13 -
 examples/ip_pipeline/config/firewall.txt           |    9 -
 examples/ip_pipeline/config/flow.cfg               |   72 -
 examples/ip_pipeline/config/flow.sh                |   25 -
 examples/ip_pipeline/config/flow.txt               |   17 -
 examples/ip_pipeline/config/ip_pipeline.cfg        |    9 -
 examples/ip_pipeline/config/ip_pipeline.sh         |    5 -
 examples/ip_pipeline/config/kni.cfg                |   67 -
 examples/ip_pipeline/config/l2fwd.cfg              |   58 -
 examples/ip_pipeline/config/l3fwd.cfg              |   68 -
 examples/ip_pipeline/config/l3fwd.sh               |   33 -
 examples/ip_pipeline/config/l3fwd_arp.cfg          |   70 -
 examples/ip_pipeline/config/l3fwd_arp.sh           |   43 -
 examples/ip_pipeline/config/network_layers.cfg     |  227 --
 examples/ip_pipeline/config/network_layers.sh      |   79 -
 .../ip_pipeline/config/pipeline-to-core-mapping.py |  906 -----
 examples/ip_pipeline/config/tap.cfg                |   64 -
 examples/ip_pipeline/config/tm_profile.cfg         |  105 -
 examples/ip_pipeline/config_check.c                |  488 ---
 examples/ip_pipeline/config_parse.c                | 3395 ----------------
 examples/ip_pipeline/config_parse_tm.c             |  419 --
 examples/ip_pipeline/conn.c                        |  326 ++
 examples/ip_pipeline/conn.h                        |   47 +
 examples/ip_pipeline/cpu_core_map.c                |  471 ---
 examples/ip_pipeline/cpu_core_map.h                |   40 -
 examples/ip_pipeline/examples/firewall.cli         |   59 +
 examples/ip_pipeline/examples/flow.cli             |   60 +
 examples/ip_pipeline/examples/kni.cli              |   69 +
 examples/ip_pipeline/examples/l2fwd.cli            |   53 +
 examples/ip_pipeline/examples/route.cli            |   60 +
 examples/ip_pipeline/examples/tap.cli              |   66 +
 examples/ip_pipeline/{pipeline => }/hash_func.h    |    3 +-
 .../ip_pipeline/{pipeline => }/hash_func_arm64.h   |    0
 examples/ip_pipeline/init.c                        | 1927 ---------
 examples/ip_pipeline/kni.c                         |  167 +
 examples/ip_pipeline/kni.h                         |   44 +
 examples/ip_pipeline/link.c                        |  268 ++
 examples/ip_pipeline/link.h                        |   63 +
 examples/ip_pipeline/main.c                        |  253 +-
 examples/ip_pipeline/mempool.c                     |   81 +
 examples/ip_pipeline/mempool.h                     |   40 +
 examples/ip_pipeline/meson.build                   |   35 +-
 examples/ip_pipeline/parser.c                      |   16 +-
 examples/ip_pipeline/parser.h                      |    8 +
 examples/ip_pipeline/pipeline.c                    |  930 +++++
 examples/ip_pipeline/pipeline.h                    |  373 +-
 .../ip_pipeline/pipeline/pipeline_actions_common.h |  202 -
 examples/ip_pipeline/pipeline/pipeline_common_be.c |  176 -
 examples/ip_pipeline/pipeline/pipeline_common_be.h |  134 -
 examples/ip_pipeline/pipeline/pipeline_common_fe.c | 1455 -------
 examples/ip_pipeline/pipeline/pipeline_common_fe.h |  231 --
 examples/ip_pipeline/pipeline/pipeline_firewall.c  | 1421 -------
 examples/ip_pipeline/pipeline/pipeline_firewall.h  |   60 -
 .../ip_pipeline/pipeline/pipeline_firewall_be.c    |  856 ----
 .../ip_pipeline/pipeline/pipeline_firewall_be.h    |  147 -
 .../ip_pipeline/pipeline/pipeline_flow_actions.c   | 1286 ------
 .../ip_pipeline/pipeline/pipeline_flow_actions.h   |   60 -
 .../pipeline/pipeline_flow_actions_be.c            |  983 -----
 .../pipeline/pipeline_flow_actions_be.h            |  139 -
 .../pipeline/pipeline_flow_classification.c        | 1878 ---------
 .../pipeline/pipeline_flow_classification.h        |  106 -
 .../pipeline/pipeline_flow_classification_be.c     |  723 ----
 .../pipeline/pipeline_flow_classification_be.h     |  113 -
 examples/ip_pipeline/pipeline/pipeline_master.c    |   20 -
 examples/ip_pipeline/pipeline/pipeline_master.h    |   12 -
 examples/ip_pipeline/pipeline/pipeline_master_be.c |  141 -
 examples/ip_pipeline/pipeline/pipeline_master_be.h |   12 -
 .../ip_pipeline/pipeline/pipeline_passthrough.c    |   45 -
 .../ip_pipeline/pipeline/pipeline_passthrough.h    |   12 -
 .../ip_pipeline/pipeline/pipeline_passthrough_be.c |  929 -----
 .../ip_pipeline/pipeline/pipeline_passthrough_be.h |   44 -
 examples/ip_pipeline/pipeline/pipeline_routing.c   | 1613 --------
 examples/ip_pipeline/pipeline/pipeline_routing.h   |   71 -
 .../ip_pipeline/pipeline/pipeline_routing_be.c     | 1966 ---------
 .../ip_pipeline/pipeline/pipeline_routing_be.h     |  283 --
 examples/ip_pipeline/pipeline_be.h                 |  322 --
 examples/ip_pipeline/swq.c                         |   74 +
 examples/ip_pipeline/swq.h                         |   37 +
 examples/ip_pipeline/tap.c                         |   97 +
 examples/ip_pipeline/tap.h                         |   29 +
 examples/ip_pipeline/thread.c                      | 2485 +++++++++++-
 examples/ip_pipeline/thread.h                      |   75 +-
 examples/ip_pipeline/thread_fe.c                   |  457 ---
 examples/ip_pipeline/thread_fe.h                   |   72 -
 examples/ip_pipeline/tmgr.c                        |  227 ++
 examples/ip_pipeline/tmgr.h                        |   70 +
 lib/librte_pipeline/Makefile                       |    6 +-
 lib/librte_pipeline/meson.build                    |    7 +-
 lib/librte_pipeline/rte_pipeline_version.map       |   21 +
 lib/librte_pipeline/rte_table_action.c             | 2284 +++++++++++
 lib/librte_pipeline/rte_table_action.h             |  853 ++++
 108 files changed, 13445 insertions(+), 27218 deletions(-)
 create mode 100644 examples/ip_pipeline/action.c
 create mode 100644 examples/ip_pipeline/action.h
 delete mode 100644 examples/ip_pipeline/app.h
 create mode 100644 examples/ip_pipeline/cli.c
 create mode 100644 examples/ip_pipeline/cli.h
 create mode 100644 examples/ip_pipeline/common.h
 delete mode 100644 examples/ip_pipeline/config/action.cfg
 delete mode 100644 examples/ip_pipeline/config/action.sh
 delete mode 100644 examples/ip_pipeline/config/action.txt
 delete mode 100755 examples/ip_pipeline/config/diagram-generator.py
 delete mode 100644 examples/ip_pipeline/config/edge_router_downstream.cfg
 delete mode 100644 examples/ip_pipeline/config/edge_router_downstream.sh
 delete mode 100644 examples/ip_pipeline/config/edge_router_upstream.cfg
 delete mode 100644 examples/ip_pipeline/config/edge_router_upstream.sh
 delete mode 100644 examples/ip_pipeline/config/firewall.cfg
 delete mode 100644 examples/ip_pipeline/config/firewall.sh
 delete mode 100644 examples/ip_pipeline/config/firewall.txt
 delete mode 100644 examples/ip_pipeline/config/flow.cfg
 delete mode 100644 examples/ip_pipeline/config/flow.sh
 delete mode 100644 examples/ip_pipeline/config/flow.txt
 delete mode 100644 examples/ip_pipeline/config/ip_pipeline.cfg
 delete mode 100644 examples/ip_pipeline/config/ip_pipeline.sh
 delete mode 100644 examples/ip_pipeline/config/kni.cfg
 delete mode 100644 examples/ip_pipeline/config/l2fwd.cfg
 delete mode 100644 examples/ip_pipeline/config/l3fwd.cfg
 delete mode 100644 examples/ip_pipeline/config/l3fwd.sh
 delete mode 100644 examples/ip_pipeline/config/l3fwd_arp.cfg
 delete mode 100644 examples/ip_pipeline/config/l3fwd_arp.sh
 delete mode 100644 examples/ip_pipeline/config/network_layers.cfg
 delete mode 100644 examples/ip_pipeline/config/network_layers.sh
 delete mode 100755 examples/ip_pipeline/config/pipeline-to-core-mapping.py
 delete mode 100644 examples/ip_pipeline/config/tap.cfg
 delete mode 100644 examples/ip_pipeline/config/tm_profile.cfg
 delete mode 100644 examples/ip_pipeline/config_check.c
 delete mode 100644 examples/ip_pipeline/config_parse.c
 delete mode 100644 examples/ip_pipeline/config_parse_tm.c
 create mode 100644 examples/ip_pipeline/conn.c
 create mode 100644 examples/ip_pipeline/conn.h
 delete mode 100644 examples/ip_pipeline/cpu_core_map.c
 delete mode 100644 examples/ip_pipeline/cpu_core_map.h
 create mode 100644 examples/ip_pipeline/examples/firewall.cli
 create mode 100644 examples/ip_pipeline/examples/flow.cli
 create mode 100644 examples/ip_pipeline/examples/kni.cli
 create mode 100644 examples/ip_pipeline/examples/l2fwd.cli
 create mode 100644 examples/ip_pipeline/examples/route.cli
 create mode 100644 examples/ip_pipeline/examples/tap.cli
 rename examples/ip_pipeline/{pipeline => }/hash_func.h (99%)
 rename examples/ip_pipeline/{pipeline => }/hash_func_arm64.h (100%)
 delete mode 100644 examples/ip_pipeline/init.c
 create mode 100644 examples/ip_pipeline/kni.c
 create mode 100644 examples/ip_pipeline/kni.h
 create mode 100644 examples/ip_pipeline/link.c
 create mode 100644 examples/ip_pipeline/link.h
 create mode 100644 examples/ip_pipeline/mempool.c
 create mode 100644 examples/ip_pipeline/mempool.h
 create mode 100644 examples/ip_pipeline/pipeline.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_actions_common.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_common_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_common_be.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_common_fe.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_common_fe.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_firewall.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_firewall.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_firewall_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_firewall_be.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_actions.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_actions.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_actions_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_actions_be.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_classification.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_classification.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_classification_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_classification_be.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_master.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_master.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_master_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_master_be.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_passthrough.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_passthrough.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_passthrough_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_passthrough_be.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_routing.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_routing.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_routing_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_routing_be.h
 delete mode 100644 examples/ip_pipeline/pipeline_be.h
 create mode 100644 examples/ip_pipeline/swq.c
 create mode 100644 examples/ip_pipeline/swq.h
 create mode 100644 examples/ip_pipeline/tap.c
 create mode 100644 examples/ip_pipeline/tap.h
 delete mode 100644 examples/ip_pipeline/thread_fe.c
 delete mode 100644 examples/ip_pipeline/thread_fe.h
 create mode 100644 examples/ip_pipeline/tmgr.c
 create mode 100644 examples/ip_pipeline/tmgr.h
 create mode 100644 lib/librte_pipeline/rte_table_action.c
 create mode 100644 lib/librte_pipeline/rte_table_action.h

-- 
2.9.3

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

* [dpdk-dev] [PATCH v3 01/44] pipeline: add pipeline table action APIs
  2018-03-16 17:56       ` [dpdk-dev] [PATCH v3 00/44] ip_pipeline: refactoring Jasvinder Singh
@ 2018-03-16 17:56         ` Jasvinder Singh
  0 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-16 17:56 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

This API provides a common set of actions for pipeline tables to speed up
application development.

Each match-action rule added to a pipeline table has associated data
that stores the action context. This data is input to the table
action handler called for every input packet that hits the rule as
part of the table lookup during the pipeline execution.

The pipeline library allows the user to define his own table
actions by providing customized table action handlers (table
lookup) and complete freedom of setting the rules and their data
(table rule add/delete). While the user can still follow this
process, this API is intended to provide a quicker development
alternative for a set of predefined actions.

The typical steps to use this API are:
* Define a table action profile.
* Instantiate the table action profile to create table action objects.
* Use the table action object to generate the pipeline table action
  handlers (invoked by the pipeline table lookup operation).
* Use the table action object to generate the rule data (for the
  pipeline table rule add operation) based on given action parameters.
* Use the table action object to read action data (e.g. stats counters)
  for any given rule.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 doc/api/doxy-api-index.md                    |   1 +
 lib/librte_pipeline/Makefile                 |   3 +-
 lib/librte_pipeline/meson.build              |   5 +-
 lib/librte_pipeline/rte_pipeline_version.map |  13 ++
 lib/librte_pipeline/rte_table_action.c       | 279 +++++++++++++++++++++++++++
 lib/librte_pipeline/rte_table_action.h       | 224 +++++++++++++++++++++
 6 files changed, 522 insertions(+), 3 deletions(-)
 create mode 100644 lib/librte_pipeline/rte_table_action.c
 create mode 100644 lib/librte_pipeline/rte_table_action.h

diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md
index d77f205..e24b70e 100644
--- a/doc/api/doxy-api-index.md
+++ b/doc/api/doxy-api-index.md
@@ -159,6 +159,7 @@ The public API headers are grouped by topics:
     [array]            (@ref rte_table_array.h),
     [stub]             (@ref rte_table_stub.h)
   * [pipeline]         (@ref rte_pipeline.h)
+    [table_action].....(@ref rte_table_action.h)
 
 - **basic**:
   [approx fraction]    (@ref rte_approx.h),
diff --git a/lib/librte_pipeline/Makefile b/lib/librte_pipeline/Makefile
index e94fbc0..e8c43c7 100644
--- a/lib/librte_pipeline/Makefile
+++ b/lib/librte_pipeline/Makefile
@@ -21,8 +21,9 @@ LIBABIVER := 3
 # all source are stored in SRCS-y
 #
 SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) := rte_pipeline.c
+SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += rte_table_action.c
 
 # install includes
-SYMLINK-$(CONFIG_RTE_LIBRTE_PIPELINE)-include += rte_pipeline.h
+SYMLINK-$(CONFIG_RTE_LIBRTE_PIPELINE)-include += rte_pipeline.h rte_table_action.h
 
 include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_pipeline/meson.build b/lib/librte_pipeline/meson.build
index a35b622..4dda560 100644
--- a/lib/librte_pipeline/meson.build
+++ b/lib/librte_pipeline/meson.build
@@ -2,6 +2,7 @@
 # Copyright(c) 2017 Intel Corporation
 
 version = 3
-sources = files('rte_pipeline.c')
-headers = files('rte_pipeline.h')
+allow_experimental_apis = true
+sources = files('rte_pipeline.c', 'rte_table_action.c')
+headers = files('rte_pipeline.h', 'rte_table_action.h')
 deps += ['port', 'table']
diff --git a/lib/librte_pipeline/rte_pipeline_version.map b/lib/librte_pipeline/rte_pipeline_version.map
index e4ee154..4bc414c 100644
--- a/lib/librte_pipeline/rte_pipeline_version.map
+++ b/lib/librte_pipeline/rte_pipeline_version.map
@@ -45,3 +45,16 @@ DPDK_16.04 {
 	rte_pipeline_ah_packet_drop;
 
 } DPDK_2.2;
+
+EXPERIMENTAL {
+	global:
+
+	rte_table_action_apply;
+	rte_table_action_create;
+	rte_table_action_free;
+	rte_table_action_profile_action_register;
+	rte_table_action_profile_create;
+	rte_table_action_profile_free;
+	rte_table_action_profile_freeze;
+
+} DPDK_16.04;
diff --git a/lib/librte_pipeline/rte_table_action.c b/lib/librte_pipeline/rte_table_action.c
new file mode 100644
index 0000000..f15847c
--- /dev/null
+++ b/lib/librte_pipeline/rte_table_action.c
@@ -0,0 +1,279 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <rte_malloc.h>
+
+#include <rte_common.h>
+#include <rte_malloc.h>
+
+#include "rte_table_action.h"
+
+/**
+ * RTE_TABLE_ACTION_FWD
+ */
+#define fwd_data rte_pipeline_table_entry
+
+static int
+fwd_apply(struct fwd_data *data,
+	struct rte_table_action_fwd_params *p)
+{
+	data->action = p->action;
+
+	if (p->action == RTE_PIPELINE_ACTION_PORT)
+		data->port_id = p->id;
+
+	if (p->action == RTE_PIPELINE_ACTION_TABLE)
+		data->table_id = p->id;
+
+	return 0;
+}
+
+/**
+ * Action profile
+ */
+static int
+action_valid(enum rte_table_action_type action)
+{
+	switch (action) {
+	case RTE_TABLE_ACTION_FWD:
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+
+#define RTE_TABLE_ACTION_MAX                      64
+
+struct ap_config {
+	uint64_t action_mask;
+	struct rte_table_action_common_config common;
+};
+
+static size_t
+action_cfg_size(enum rte_table_action_type action)
+{
+	switch (action) {
+	default:
+		return 0;
+	}
+}
+
+static void*
+action_cfg_get(struct ap_config *ap_config __rte_unused,
+	enum rte_table_action_type type)
+{
+	switch (type) {
+	default:
+		return NULL;
+	}
+}
+
+static void
+action_cfg_set(struct ap_config *ap_config,
+	enum rte_table_action_type type,
+	void *action_cfg)
+{
+	void *dst = action_cfg_get(ap_config, type);
+
+	if (dst)
+		memcpy(dst, action_cfg, action_cfg_size(type));
+
+	ap_config->action_mask |= 1LLU << type;
+}
+
+struct ap_data {
+	size_t offset[RTE_TABLE_ACTION_MAX];
+	size_t total_size;
+};
+
+static size_t
+action_data_size(enum rte_table_action_type action,
+	struct ap_config *ap_config __rte_unused)
+{
+	switch (action) {
+	case RTE_TABLE_ACTION_FWD:
+		return sizeof(struct fwd_data);
+
+	default:
+		return 0;
+	}
+}
+
+
+static void
+action_data_offset_set(struct ap_data *ap_data,
+	struct ap_config *ap_config)
+{
+	uint64_t action_mask = ap_config->action_mask;
+	size_t offset;
+	uint32_t action;
+
+	memset(ap_data->offset, 0, sizeof(ap_data->offset));
+
+	offset = 0;
+	for (action = 0; action < RTE_TABLE_ACTION_MAX; action++)
+		if (action_mask & (1LLU << action)) {
+			ap_data->offset[action] = offset;
+			offset += action_data_size((enum rte_table_action_type)action,
+				ap_config);
+		}
+
+	ap_data->total_size = offset;
+}
+
+struct rte_table_action_profile {
+	struct ap_config cfg;
+	struct ap_data data;
+	int frozen;
+};
+
+struct rte_table_action_profile *
+rte_table_action_profile_create(struct rte_table_action_common_config *common)
+{
+	struct rte_table_action_profile *ap;
+
+	/* Check input arguments */
+	if (common == NULL)
+		return NULL;
+
+	/* Memory allocation */
+	ap = calloc(1, sizeof(struct rte_table_action_profile));
+	if (ap == NULL)
+		return NULL;
+
+	/* Initialization */
+	memcpy(&ap->cfg.common, common, sizeof(*common));
+
+	return ap;
+}
+
+
+int
+rte_table_action_profile_action_register(struct rte_table_action_profile *profile,
+	enum rte_table_action_type type,
+	void *action_config)
+{
+	/* Check input arguments */
+	if ((profile == NULL) ||
+		profile->frozen ||
+		(action_valid(type) == 0) ||
+		(profile->cfg.action_mask & (1LLU << type)) ||
+		((action_cfg_size(type) == 0) && action_config) ||
+		(action_cfg_size(type) && (action_config == NULL)))
+		return -EINVAL;
+
+	/* Action enable */
+	action_cfg_set(&profile->cfg, type, action_config);
+
+	return 0;
+}
+
+int
+rte_table_action_profile_freeze(struct rte_table_action_profile *profile)
+{
+	if (profile->frozen)
+		return -EBUSY;
+
+	profile->cfg.action_mask |= 1LLU << RTE_TABLE_ACTION_FWD;
+	action_data_offset_set(&profile->data, &profile->cfg);
+	profile->frozen = 1;
+
+	return 0;
+}
+
+int
+rte_table_action_profile_free(struct rte_table_action_profile *profile)
+{
+	if (profile == NULL)
+		return 0;
+
+	free(profile);
+	return 0;
+}
+
+struct rte_table_action {
+	struct ap_config cfg;
+	struct ap_data data;
+};
+
+struct rte_table_action *
+rte_table_action_create(struct rte_table_action_profile *profile,
+	uint32_t socket_id)
+{
+	struct rte_table_action *action;
+
+	/* Check input arguments */
+	if ((profile == NULL) ||
+		(profile->frozen == 0))
+		return NULL;
+
+	/* Memory allocation */
+	action = rte_zmalloc_socket(NULL,
+		sizeof(struct rte_table_action),
+		RTE_CACHE_LINE_SIZE,
+		socket_id);
+	if (action == NULL)
+		return NULL;
+
+	/* Initialization */
+	memcpy(&action->cfg, &profile->cfg, sizeof(profile->cfg));
+	memcpy(&action->data, &profile->data, sizeof(profile->data));
+
+	return action;
+}
+
+static __rte_always_inline void *
+action_data_get(void *data,
+	struct rte_table_action *action,
+	enum rte_table_action_type type)
+{
+	size_t offset = action->data.offset[type];
+	uint8_t *data_bytes = data;
+
+	return &data_bytes[offset];
+}
+
+int
+rte_table_action_apply(struct rte_table_action *action,
+	void *data,
+	enum rte_table_action_type type,
+	void *action_params)
+{
+	void *action_data;
+
+	/* Check input arguments */
+	if ((action == NULL) ||
+		(data == NULL) ||
+		(action_valid(type) == 0) ||
+		((action->cfg.action_mask & (1LLU << type)) == 0) ||
+		(action_params == NULL))
+		return -EINVAL;
+
+	/* Data update */
+	action_data = action_data_get(data, action, type);
+
+	switch (type) {
+	case RTE_TABLE_ACTION_FWD:
+		return fwd_apply(action_data,
+			action_params);
+
+	default:
+		return -EINVAL;
+	}
+}
+
+int
+rte_table_action_free(struct rte_table_action *action)
+{
+	if (action == NULL)
+		return 0;
+
+	rte_free(action);
+
+	return 0;
+}
diff --git a/lib/librte_pipeline/rte_table_action.h b/lib/librte_pipeline/rte_table_action.h
new file mode 100644
index 0000000..da7f12c
--- /dev/null
+++ b/lib/librte_pipeline/rte_table_action.h
@@ -0,0 +1,224 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation
+ */
+
+#ifndef __INCLUDE_RTE_TABLE_ACTION_H__
+#define __INCLUDE_RTE_TABLE_ACTION_H__
+
+/**
+ * @file
+ * RTE Pipeline Table Actions
+ *
+ * This API provides a common set of actions for pipeline tables to speed up
+ * application development.
+ *
+ * Each match-action rule added to a pipeline table has associated data that
+ * stores the action context. This data is input to the table action handler
+ * called for every input packet that hits the rule as part of the table lookup
+ * during the pipeline execution. The pipeline library allows the user to define
+ * his own table actions by providing customized table action handlers (table
+ * lookup) and complete freedom of setting the rules and their data (table rule
+ * add/delete). While the user can still follow this process, this API is
+ * intended to provide a quicker development alternative for a set of predefined
+ * actions.
+ *
+ * The typical steps to use this API are:
+ *  - Define a table action profile. This is a configuration template that can
+ *    potentially be shared by multiple tables from the same or different
+ *    pipelines, with different tables from the same pipeline likely to use
+ *    different action profiles. For every table using a given action profile,
+ *    the profile defines the set of actions and the action configuration to be
+ *    implemented for all the table rules. API functions:
+ *    rte_table_action_profile_create(),
+ *    rte_table_action_profile_action_register(),
+ *    rte_table_action_profile_freeze().
+ *
+ *  - Instantiate the table action profile to create table action objects. Each
+ *    pipeline table has its own table action object. API functions:
+ *    rte_table_action_create().
+ *
+ *  - Use the table action object to generate the pipeline table action handlers
+ *    (invoked by the pipeline table lookup operation). API functions:
+ *    rte_table_action_table_params_get().
+ *
+ *  - Use the table action object to generate the rule data (for the pipeline
+ *    table rule add operation) based on given action parameters. API functions:
+ *    rte_table_action_apply().
+ *
+ *  - Use the table action object to read action data (e.g. stats counters) for
+ *    any given rule. API functions: rte_table_action_XYZ_read().
+ *
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+
+#include <rte_compat.h>
+
+#include "rte_pipeline.h"
+
+/** Table actions. */
+enum rte_table_action_type {
+	/** Forward to next pipeline table, output port or drop. */
+	RTE_TABLE_ACTION_FWD = 0,
+};
+
+/** Common action configuration (per table action profile). */
+struct rte_table_action_common_config {
+	/** Input packet Internet Protocol (IP) version. Non-zero for IPv4, zero
+	 * for IPv6.
+	 */
+	int ip_version;
+
+	/** IP header offset within the input packet buffer. Offset 0 points to
+	 * the first byte of the MBUF structure.
+	 */
+	uint32_t ip_offset;
+};
+
+/**
+ * RTE_TABLE_ACTION_FWD
+ */
+/** Forward action parameters (per table rule). */
+struct rte_table_action_fwd_params {
+	/** Forward action. */
+	enum rte_pipeline_action action;
+
+	/** Pipeline table ID or output port ID. */
+	uint32_t id;
+};
+
+/**
+ * Table action profile.
+ */
+struct rte_table_action_profile;
+
+/**
+ * Table action profile create.
+ *
+ * @param[in] common
+ *   Common action configuration.
+ * @return
+ *   Table action profile handle on success, NULL otherwise.
+ */
+struct rte_table_action_profile * __rte_experimental
+rte_table_action_profile_create(struct rte_table_action_common_config *common);
+
+/**
+ * Table action profile free.
+ *
+ * @param[in] profile
+ *   Table profile action handle (needs to be valid).
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_table_action_profile_free(struct rte_table_action_profile *profile);
+
+/**
+ * Table action profile action register.
+ *
+ * @param[in] profile
+ *   Table profile action handle (needs to be valid and not in frozen state).
+ * @param[in] type
+ *   Specific table action to be registered for *profile*.
+ * @param[in] action_config
+ *   Configuration for the *type* action.
+ *   If struct rte_table_action_*type*_config is defined by the Table Action
+ *   API, it needs to point to a valid instance of this structure, otherwise it
+ *   needs to be set to NULL.
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_table_action_profile_action_register(struct rte_table_action_profile *profile,
+	enum rte_table_action_type type,
+	void *action_config);
+
+/**
+ * Table action profile freeze.
+ *
+ * Once this function is called successfully, the given profile enters the
+ * frozen state with the following immediate effects: no more actions can be
+ * registered for this profile, so the profile can be instantiated to create
+ * table action objects.
+ *
+ * @param[in] profile
+ *   Table profile action handle (needs to be valid and not in frozen state).
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ *
+ * @see rte_table_action_create()
+ */
+int __rte_experimental
+rte_table_action_profile_freeze(struct rte_table_action_profile *profile);
+
+/**
+ * Table action.
+ */
+struct rte_table_action;
+
+/**
+ * Table action create.
+ *
+ * Instantiates the given table action profile to create a table action object.
+ *
+ * @param[in] profile
+ *   Table profile action handle (needs to be valid and in frozen state).
+ * @param[in] socket_id
+ *   CPU socket ID where the internal data structures required by the new table
+ *   action object should be allocated.
+ * @return
+ *   Handle to table action object on success, NULL on error.
+ *
+ * @see rte_table_action_create()
+ */
+struct rte_table_action * __rte_experimental
+rte_table_action_create(struct rte_table_action_profile *profile,
+	uint32_t socket_id);
+
+/**
+ * Table action free.
+ *
+ * @param[in] action
+ *   Handle to table action object (needs to be valid).
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_table_action_free(struct rte_table_action *action);
+
+/**
+ * Table action apply.
+ *
+ * @param[in] action
+ *   Handle to table action object (needs to be valid).
+ * @param[in] data
+ *   Data byte array (typically table rule data) to apply action *type* on.
+ * @param[in] type
+ *   Specific table action previously registered for the table action profile of
+ *   the *action* object.
+ * @param[in] action_params
+ *   Parameters for the *type* action.
+ *   If struct rte_table_action_*type*_params is defined by the Table Action
+ *   API, it needs to point to a valid instance of this structure, otherwise it
+ *   needs to be set to NULL.
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_table_action_apply(struct rte_table_action *action,
+	void *data,
+	enum rte_table_action_type type,
+	void *action_params);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __INCLUDE_RTE_TABLE_ACTION_H__ */
-- 
2.9.3

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

* [dpdk-dev] [PATCH v3 00/44] ip_pipeline: refactoring
  2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 01/44] pipeline: add pipeline table action APIs Jasvinder Singh
  2018-03-16 17:56       ` [dpdk-dev] [PATCH v3 00/44] ip_pipeline: refactoring Jasvinder Singh
@ 2018-03-16 17:58       ` Jasvinder Singh
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 01/44] pipeline: add pipeline table action APIs Jasvinder Singh
                           ` (43 more replies)
  1 sibling, 44 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-16 17:58 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Refactored the IP pipeline application. As result, the code base
size (lines of code) reduces by ~60%.

1. Moved table actions into the librte_pipeline library. As result,
   the pre-fabricated pipelines from the application pipeline folder
   were removed. The flexibility is greatly improved, as now any
   action can be combined with any match (i.e. table type), which
   was not possible before.

2. Removed configuration file as the initialization method. Now
   all the pipelines are set up and assigned to threads through
   CLI commands for improved flexibility.

3. Replaced the local CLI with remote CLI. Any standard TCP
   client (e.g. telnet, netcat) can now connect to the app,
   send request as command string through the network and wait
   for the response string before pushing the next command.
   Results in better flexibility and automation.

v3:
- add IPv4, TCP/UDP checksum update for NAT action.
- add IPv4 Checksum update for TTL action.
- fix compilation warning

v2:
- split the patch that removes the existing pipeline components
  into multiple patches.
- fix checkpatch errors.

Jasvinder Singh (44):
  pipeline: add pipeline table action APIs
  pipeline: get pipeline table action params
  pipeline: add traffic metering action
  pipeline: add traffic manager action
  pipeline: add packet encapsulation action
  pipeline: add nat action
  pipeline: add ttl update action
  pipeline: add statistics read action
  pipeline: add timestamp action
  ip_pipeline: remove passthrough pipeline
  ip_pipeline: remove routing pipeline
  ip_pipeline: remove flow classification pipeline
  ip_pipeline: remove flow actions pipeline
  ip_pipeline: remove firewall pipeline
  ip_pipeline: remove master pipeline
  ip_pipeline: remove config
  ip_pipeline: rework and improvements
  ip_pipeline: add cli interface
  ip_pipeline: add mempool object for pipeline
  ip_pipeline: add link object
  ip_pipeline: add software queue object
  ip_pipeline: add traffic manager object
  ip_pipeline: add tap object
  ip_pipeline: add kni object
  ip_pipeline: add action profile object
  ip_pipeline: add pipeline object
  ip_pipeline: add threads
  ip_pipeline: add thread runtime
  ip_pipeline: add cli to enable and disable pipeline
  ip_pipeline: add cli to enable and disable pipeline port
  ip_pipeline: add cli to read pipeline port and table stats
  ip_pipeline: add cli for pipeline table entries
  ip_pipeline: add cli to delete pipeline table entry
  ip_pipeline: add cli to read pipeline table entry stats
  ip_pipeline: add cli to configure meter profile
  ip_pipeline: add cli to read meter stats
  ip_pipeline: add cli to update dscp table
  ip_pipeline: add cli to read ttl stats
  ip_pipeline: add l2fwd example
  ip_pipeline: add KNI port example
  ip_pipeline: add TAP port example
  ip_pipeline: add route example
  ip_pipeline: add firewall example
  ip_pipeline: add flow classification example

 doc/api/doxy-api-index.md                          |    1 +
 examples/ip_pipeline/Makefile                      |   49 +-
 examples/ip_pipeline/action.c                      |  165 +
 examples/ip_pipeline/action.h                      |   44 +
 examples/ip_pipeline/app.h                         | 1401 -------
 examples/ip_pipeline/cli.c                         | 4261 ++++++++++++++++++++
 examples/ip_pipeline/cli.h                         |   18 +
 examples/ip_pipeline/common.h                      |   12 +
 examples/ip_pipeline/config/action.cfg             |   68 -
 examples/ip_pipeline/config/action.sh              |  119 -
 examples/ip_pipeline/config/action.txt             |    8 -
 examples/ip_pipeline/config/diagram-generator.py   |  317 --
 .../ip_pipeline/config/edge_router_downstream.cfg  |   97 -
 .../ip_pipeline/config/edge_router_downstream.sh   |   13 -
 .../ip_pipeline/config/edge_router_upstream.cfg    |  124 -
 .../ip_pipeline/config/edge_router_upstream.sh     |   33 -
 examples/ip_pipeline/config/firewall.cfg           |   68 -
 examples/ip_pipeline/config/firewall.sh            |   13 -
 examples/ip_pipeline/config/firewall.txt           |    9 -
 examples/ip_pipeline/config/flow.cfg               |   72 -
 examples/ip_pipeline/config/flow.sh                |   25 -
 examples/ip_pipeline/config/flow.txt               |   17 -
 examples/ip_pipeline/config/ip_pipeline.cfg        |    9 -
 examples/ip_pipeline/config/ip_pipeline.sh         |    5 -
 examples/ip_pipeline/config/kni.cfg                |   67 -
 examples/ip_pipeline/config/l2fwd.cfg              |   58 -
 examples/ip_pipeline/config/l3fwd.cfg              |   68 -
 examples/ip_pipeline/config/l3fwd.sh               |   33 -
 examples/ip_pipeline/config/l3fwd_arp.cfg          |   70 -
 examples/ip_pipeline/config/l3fwd_arp.sh           |   43 -
 examples/ip_pipeline/config/network_layers.cfg     |  227 --
 examples/ip_pipeline/config/network_layers.sh      |   79 -
 .../ip_pipeline/config/pipeline-to-core-mapping.py |  906 -----
 examples/ip_pipeline/config/tap.cfg                |   64 -
 examples/ip_pipeline/config/tm_profile.cfg         |  105 -
 examples/ip_pipeline/config_check.c                |  488 ---
 examples/ip_pipeline/config_parse.c                | 3395 ----------------
 examples/ip_pipeline/config_parse_tm.c             |  419 --
 examples/ip_pipeline/conn.c                        |  326 ++
 examples/ip_pipeline/conn.h                        |   47 +
 examples/ip_pipeline/cpu_core_map.c                |  471 ---
 examples/ip_pipeline/cpu_core_map.h                |   40 -
 examples/ip_pipeline/examples/firewall.cli         |   59 +
 examples/ip_pipeline/examples/flow.cli             |   60 +
 examples/ip_pipeline/examples/kni.cli              |   69 +
 examples/ip_pipeline/examples/l2fwd.cli            |   53 +
 examples/ip_pipeline/examples/route.cli            |   60 +
 examples/ip_pipeline/examples/tap.cli              |   66 +
 examples/ip_pipeline/{pipeline => }/hash_func.h    |    3 +-
 .../ip_pipeline/{pipeline => }/hash_func_arm64.h   |    0
 examples/ip_pipeline/init.c                        | 1927 ---------
 examples/ip_pipeline/kni.c                         |  167 +
 examples/ip_pipeline/kni.h                         |   44 +
 examples/ip_pipeline/link.c                        |  268 ++
 examples/ip_pipeline/link.h                        |   63 +
 examples/ip_pipeline/main.c                        |  253 +-
 examples/ip_pipeline/mempool.c                     |   81 +
 examples/ip_pipeline/mempool.h                     |   40 +
 examples/ip_pipeline/meson.build                   |   35 +-
 examples/ip_pipeline/parser.c                      |   16 +-
 examples/ip_pipeline/parser.h                      |    8 +
 examples/ip_pipeline/pipeline.c                    |  930 +++++
 examples/ip_pipeline/pipeline.h                    |  373 +-
 .../ip_pipeline/pipeline/pipeline_actions_common.h |  202 -
 examples/ip_pipeline/pipeline/pipeline_common_be.c |  176 -
 examples/ip_pipeline/pipeline/pipeline_common_be.h |  134 -
 examples/ip_pipeline/pipeline/pipeline_common_fe.c | 1455 -------
 examples/ip_pipeline/pipeline/pipeline_common_fe.h |  231 --
 examples/ip_pipeline/pipeline/pipeline_firewall.c  | 1421 -------
 examples/ip_pipeline/pipeline/pipeline_firewall.h  |   60 -
 .../ip_pipeline/pipeline/pipeline_firewall_be.c    |  856 ----
 .../ip_pipeline/pipeline/pipeline_firewall_be.h    |  147 -
 .../ip_pipeline/pipeline/pipeline_flow_actions.c   | 1286 ------
 .../ip_pipeline/pipeline/pipeline_flow_actions.h   |   60 -
 .../pipeline/pipeline_flow_actions_be.c            |  983 -----
 .../pipeline/pipeline_flow_actions_be.h            |  139 -
 .../pipeline/pipeline_flow_classification.c        | 1878 ---------
 .../pipeline/pipeline_flow_classification.h        |  106 -
 .../pipeline/pipeline_flow_classification_be.c     |  723 ----
 .../pipeline/pipeline_flow_classification_be.h     |  113 -
 examples/ip_pipeline/pipeline/pipeline_master.c    |   20 -
 examples/ip_pipeline/pipeline/pipeline_master.h    |   12 -
 examples/ip_pipeline/pipeline/pipeline_master_be.c |  141 -
 examples/ip_pipeline/pipeline/pipeline_master_be.h |   12 -
 .../ip_pipeline/pipeline/pipeline_passthrough.c    |   45 -
 .../ip_pipeline/pipeline/pipeline_passthrough.h    |   12 -
 .../ip_pipeline/pipeline/pipeline_passthrough_be.c |  929 -----
 .../ip_pipeline/pipeline/pipeline_passthrough_be.h |   44 -
 examples/ip_pipeline/pipeline/pipeline_routing.c   | 1613 --------
 examples/ip_pipeline/pipeline/pipeline_routing.h   |   71 -
 .../ip_pipeline/pipeline/pipeline_routing_be.c     | 1966 ---------
 .../ip_pipeline/pipeline/pipeline_routing_be.h     |  283 --
 examples/ip_pipeline/pipeline_be.h                 |  322 --
 examples/ip_pipeline/swq.c                         |   74 +
 examples/ip_pipeline/swq.h                         |   37 +
 examples/ip_pipeline/tap.c                         |   97 +
 examples/ip_pipeline/tap.h                         |   29 +
 examples/ip_pipeline/thread.c                      | 2485 +++++++++++-
 examples/ip_pipeline/thread.h                      |   75 +-
 examples/ip_pipeline/thread_fe.c                   |  457 ---
 examples/ip_pipeline/thread_fe.h                   |   72 -
 examples/ip_pipeline/tmgr.c                        |  227 ++
 examples/ip_pipeline/tmgr.h                        |   70 +
 lib/librte_pipeline/Makefile                       |    6 +-
 lib/librte_pipeline/meson.build                    |    7 +-
 lib/librte_pipeline/rte_pipeline_version.map       |   21 +
 lib/librte_pipeline/rte_table_action.c             | 2284 +++++++++++
 lib/librte_pipeline/rte_table_action.h             |  853 ++++
 108 files changed, 13445 insertions(+), 27218 deletions(-)
 create mode 100644 examples/ip_pipeline/action.c
 create mode 100644 examples/ip_pipeline/action.h
 delete mode 100644 examples/ip_pipeline/app.h
 create mode 100644 examples/ip_pipeline/cli.c
 create mode 100644 examples/ip_pipeline/cli.h
 create mode 100644 examples/ip_pipeline/common.h
 delete mode 100644 examples/ip_pipeline/config/action.cfg
 delete mode 100644 examples/ip_pipeline/config/action.sh
 delete mode 100644 examples/ip_pipeline/config/action.txt
 delete mode 100755 examples/ip_pipeline/config/diagram-generator.py
 delete mode 100644 examples/ip_pipeline/config/edge_router_downstream.cfg
 delete mode 100644 examples/ip_pipeline/config/edge_router_downstream.sh
 delete mode 100644 examples/ip_pipeline/config/edge_router_upstream.cfg
 delete mode 100644 examples/ip_pipeline/config/edge_router_upstream.sh
 delete mode 100644 examples/ip_pipeline/config/firewall.cfg
 delete mode 100644 examples/ip_pipeline/config/firewall.sh
 delete mode 100644 examples/ip_pipeline/config/firewall.txt
 delete mode 100644 examples/ip_pipeline/config/flow.cfg
 delete mode 100644 examples/ip_pipeline/config/flow.sh
 delete mode 100644 examples/ip_pipeline/config/flow.txt
 delete mode 100644 examples/ip_pipeline/config/ip_pipeline.cfg
 delete mode 100644 examples/ip_pipeline/config/ip_pipeline.sh
 delete mode 100644 examples/ip_pipeline/config/kni.cfg
 delete mode 100644 examples/ip_pipeline/config/l2fwd.cfg
 delete mode 100644 examples/ip_pipeline/config/l3fwd.cfg
 delete mode 100644 examples/ip_pipeline/config/l3fwd.sh
 delete mode 100644 examples/ip_pipeline/config/l3fwd_arp.cfg
 delete mode 100644 examples/ip_pipeline/config/l3fwd_arp.sh
 delete mode 100644 examples/ip_pipeline/config/network_layers.cfg
 delete mode 100644 examples/ip_pipeline/config/network_layers.sh
 delete mode 100755 examples/ip_pipeline/config/pipeline-to-core-mapping.py
 delete mode 100644 examples/ip_pipeline/config/tap.cfg
 delete mode 100644 examples/ip_pipeline/config/tm_profile.cfg
 delete mode 100644 examples/ip_pipeline/config_check.c
 delete mode 100644 examples/ip_pipeline/config_parse.c
 delete mode 100644 examples/ip_pipeline/config_parse_tm.c
 create mode 100644 examples/ip_pipeline/conn.c
 create mode 100644 examples/ip_pipeline/conn.h
 delete mode 100644 examples/ip_pipeline/cpu_core_map.c
 delete mode 100644 examples/ip_pipeline/cpu_core_map.h
 create mode 100644 examples/ip_pipeline/examples/firewall.cli
 create mode 100644 examples/ip_pipeline/examples/flow.cli
 create mode 100644 examples/ip_pipeline/examples/kni.cli
 create mode 100644 examples/ip_pipeline/examples/l2fwd.cli
 create mode 100644 examples/ip_pipeline/examples/route.cli
 create mode 100644 examples/ip_pipeline/examples/tap.cli
 rename examples/ip_pipeline/{pipeline => }/hash_func.h (99%)
 rename examples/ip_pipeline/{pipeline => }/hash_func_arm64.h (100%)
 delete mode 100644 examples/ip_pipeline/init.c
 create mode 100644 examples/ip_pipeline/kni.c
 create mode 100644 examples/ip_pipeline/kni.h
 create mode 100644 examples/ip_pipeline/link.c
 create mode 100644 examples/ip_pipeline/link.h
 create mode 100644 examples/ip_pipeline/mempool.c
 create mode 100644 examples/ip_pipeline/mempool.h
 create mode 100644 examples/ip_pipeline/pipeline.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_actions_common.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_common_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_common_be.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_common_fe.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_common_fe.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_firewall.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_firewall.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_firewall_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_firewall_be.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_actions.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_actions.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_actions_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_actions_be.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_classification.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_classification.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_classification_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_classification_be.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_master.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_master.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_master_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_master_be.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_passthrough.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_passthrough.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_passthrough_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_passthrough_be.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_routing.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_routing.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_routing_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_routing_be.h
 delete mode 100644 examples/ip_pipeline/pipeline_be.h
 create mode 100644 examples/ip_pipeline/swq.c
 create mode 100644 examples/ip_pipeline/swq.h
 create mode 100644 examples/ip_pipeline/tap.c
 create mode 100644 examples/ip_pipeline/tap.h
 delete mode 100644 examples/ip_pipeline/thread_fe.c
 delete mode 100644 examples/ip_pipeline/thread_fe.h
 create mode 100644 examples/ip_pipeline/tmgr.c
 create mode 100644 examples/ip_pipeline/tmgr.h
 create mode 100644 lib/librte_pipeline/rte_table_action.c
 create mode 100644 lib/librte_pipeline/rte_table_action.h

-- 
2.9.3

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

* [dpdk-dev] [PATCH v3 01/44] pipeline: add pipeline table action APIs
  2018-03-16 17:58       ` [dpdk-dev] [PATCH v3 00/44] ip_pipeline: refactoring Jasvinder Singh
@ 2018-03-16 17:58         ` Jasvinder Singh
  2018-03-29 18:31           ` [dpdk-dev] [PATCH v4 00/49] ip_pipeline: refactoring Jasvinder Singh
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 02/44] pipeline: get pipeline table action params Jasvinder Singh
                           ` (42 subsequent siblings)
  43 siblings, 1 reply; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-16 17:58 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

This API provides a common set of actions for pipeline tables to speed up
application development.

Each match-action rule added to a pipeline table has associated data
that stores the action context. This data is input to the table
action handler called for every input packet that hits the rule as
part of the table lookup during the pipeline execution.

The pipeline library allows the user to define his own table
actions by providing customized table action handlers (table
lookup) and complete freedom of setting the rules and their data
(table rule add/delete). While the user can still follow this
process, this API is intended to provide a quicker development
alternative for a set of predefined actions.

The typical steps to use this API are:
* Define a table action profile.
* Instantiate the table action profile to create table action objects.
* Use the table action object to generate the pipeline table action
  handlers (invoked by the pipeline table lookup operation).
* Use the table action object to generate the rule data (for the
  pipeline table rule add operation) based on given action parameters.
* Use the table action object to read action data (e.g. stats counters)
  for any given rule.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 doc/api/doxy-api-index.md                    |   1 +
 lib/librte_pipeline/Makefile                 |   3 +-
 lib/librte_pipeline/meson.build              |   5 +-
 lib/librte_pipeline/rte_pipeline_version.map |  13 ++
 lib/librte_pipeline/rte_table_action.c       | 279 +++++++++++++++++++++++++++
 lib/librte_pipeline/rte_table_action.h       | 224 +++++++++++++++++++++
 6 files changed, 522 insertions(+), 3 deletions(-)
 create mode 100644 lib/librte_pipeline/rte_table_action.c
 create mode 100644 lib/librte_pipeline/rte_table_action.h

diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md
index d77f205..e24b70e 100644
--- a/doc/api/doxy-api-index.md
+++ b/doc/api/doxy-api-index.md
@@ -159,6 +159,7 @@ The public API headers are grouped by topics:
     [array]            (@ref rte_table_array.h),
     [stub]             (@ref rte_table_stub.h)
   * [pipeline]         (@ref rte_pipeline.h)
+    [table_action].....(@ref rte_table_action.h)
 
 - **basic**:
   [approx fraction]    (@ref rte_approx.h),
diff --git a/lib/librte_pipeline/Makefile b/lib/librte_pipeline/Makefile
index e94fbc0..e8c43c7 100644
--- a/lib/librte_pipeline/Makefile
+++ b/lib/librte_pipeline/Makefile
@@ -21,8 +21,9 @@ LIBABIVER := 3
 # all source are stored in SRCS-y
 #
 SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) := rte_pipeline.c
+SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += rte_table_action.c
 
 # install includes
-SYMLINK-$(CONFIG_RTE_LIBRTE_PIPELINE)-include += rte_pipeline.h
+SYMLINK-$(CONFIG_RTE_LIBRTE_PIPELINE)-include += rte_pipeline.h rte_table_action.h
 
 include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_pipeline/meson.build b/lib/librte_pipeline/meson.build
index a35b622..4dda560 100644
--- a/lib/librte_pipeline/meson.build
+++ b/lib/librte_pipeline/meson.build
@@ -2,6 +2,7 @@
 # Copyright(c) 2017 Intel Corporation
 
 version = 3
-sources = files('rte_pipeline.c')
-headers = files('rte_pipeline.h')
+allow_experimental_apis = true
+sources = files('rte_pipeline.c', 'rte_table_action.c')
+headers = files('rte_pipeline.h', 'rte_table_action.h')
 deps += ['port', 'table']
diff --git a/lib/librte_pipeline/rte_pipeline_version.map b/lib/librte_pipeline/rte_pipeline_version.map
index e4ee154..4bc414c 100644
--- a/lib/librte_pipeline/rte_pipeline_version.map
+++ b/lib/librte_pipeline/rte_pipeline_version.map
@@ -45,3 +45,16 @@ DPDK_16.04 {
 	rte_pipeline_ah_packet_drop;
 
 } DPDK_2.2;
+
+EXPERIMENTAL {
+	global:
+
+	rte_table_action_apply;
+	rte_table_action_create;
+	rte_table_action_free;
+	rte_table_action_profile_action_register;
+	rte_table_action_profile_create;
+	rte_table_action_profile_free;
+	rte_table_action_profile_freeze;
+
+} DPDK_16.04;
diff --git a/lib/librte_pipeline/rte_table_action.c b/lib/librte_pipeline/rte_table_action.c
new file mode 100644
index 0000000..f15847c
--- /dev/null
+++ b/lib/librte_pipeline/rte_table_action.c
@@ -0,0 +1,279 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <rte_malloc.h>
+
+#include <rte_common.h>
+#include <rte_malloc.h>
+
+#include "rte_table_action.h"
+
+/**
+ * RTE_TABLE_ACTION_FWD
+ */
+#define fwd_data rte_pipeline_table_entry
+
+static int
+fwd_apply(struct fwd_data *data,
+	struct rte_table_action_fwd_params *p)
+{
+	data->action = p->action;
+
+	if (p->action == RTE_PIPELINE_ACTION_PORT)
+		data->port_id = p->id;
+
+	if (p->action == RTE_PIPELINE_ACTION_TABLE)
+		data->table_id = p->id;
+
+	return 0;
+}
+
+/**
+ * Action profile
+ */
+static int
+action_valid(enum rte_table_action_type action)
+{
+	switch (action) {
+	case RTE_TABLE_ACTION_FWD:
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+
+#define RTE_TABLE_ACTION_MAX                      64
+
+struct ap_config {
+	uint64_t action_mask;
+	struct rte_table_action_common_config common;
+};
+
+static size_t
+action_cfg_size(enum rte_table_action_type action)
+{
+	switch (action) {
+	default:
+		return 0;
+	}
+}
+
+static void*
+action_cfg_get(struct ap_config *ap_config __rte_unused,
+	enum rte_table_action_type type)
+{
+	switch (type) {
+	default:
+		return NULL;
+	}
+}
+
+static void
+action_cfg_set(struct ap_config *ap_config,
+	enum rte_table_action_type type,
+	void *action_cfg)
+{
+	void *dst = action_cfg_get(ap_config, type);
+
+	if (dst)
+		memcpy(dst, action_cfg, action_cfg_size(type));
+
+	ap_config->action_mask |= 1LLU << type;
+}
+
+struct ap_data {
+	size_t offset[RTE_TABLE_ACTION_MAX];
+	size_t total_size;
+};
+
+static size_t
+action_data_size(enum rte_table_action_type action,
+	struct ap_config *ap_config __rte_unused)
+{
+	switch (action) {
+	case RTE_TABLE_ACTION_FWD:
+		return sizeof(struct fwd_data);
+
+	default:
+		return 0;
+	}
+}
+
+
+static void
+action_data_offset_set(struct ap_data *ap_data,
+	struct ap_config *ap_config)
+{
+	uint64_t action_mask = ap_config->action_mask;
+	size_t offset;
+	uint32_t action;
+
+	memset(ap_data->offset, 0, sizeof(ap_data->offset));
+
+	offset = 0;
+	for (action = 0; action < RTE_TABLE_ACTION_MAX; action++)
+		if (action_mask & (1LLU << action)) {
+			ap_data->offset[action] = offset;
+			offset += action_data_size((enum rte_table_action_type)action,
+				ap_config);
+		}
+
+	ap_data->total_size = offset;
+}
+
+struct rte_table_action_profile {
+	struct ap_config cfg;
+	struct ap_data data;
+	int frozen;
+};
+
+struct rte_table_action_profile *
+rte_table_action_profile_create(struct rte_table_action_common_config *common)
+{
+	struct rte_table_action_profile *ap;
+
+	/* Check input arguments */
+	if (common == NULL)
+		return NULL;
+
+	/* Memory allocation */
+	ap = calloc(1, sizeof(struct rte_table_action_profile));
+	if (ap == NULL)
+		return NULL;
+
+	/* Initialization */
+	memcpy(&ap->cfg.common, common, sizeof(*common));
+
+	return ap;
+}
+
+
+int
+rte_table_action_profile_action_register(struct rte_table_action_profile *profile,
+	enum rte_table_action_type type,
+	void *action_config)
+{
+	/* Check input arguments */
+	if ((profile == NULL) ||
+		profile->frozen ||
+		(action_valid(type) == 0) ||
+		(profile->cfg.action_mask & (1LLU << type)) ||
+		((action_cfg_size(type) == 0) && action_config) ||
+		(action_cfg_size(type) && (action_config == NULL)))
+		return -EINVAL;
+
+	/* Action enable */
+	action_cfg_set(&profile->cfg, type, action_config);
+
+	return 0;
+}
+
+int
+rte_table_action_profile_freeze(struct rte_table_action_profile *profile)
+{
+	if (profile->frozen)
+		return -EBUSY;
+
+	profile->cfg.action_mask |= 1LLU << RTE_TABLE_ACTION_FWD;
+	action_data_offset_set(&profile->data, &profile->cfg);
+	profile->frozen = 1;
+
+	return 0;
+}
+
+int
+rte_table_action_profile_free(struct rte_table_action_profile *profile)
+{
+	if (profile == NULL)
+		return 0;
+
+	free(profile);
+	return 0;
+}
+
+struct rte_table_action {
+	struct ap_config cfg;
+	struct ap_data data;
+};
+
+struct rte_table_action *
+rte_table_action_create(struct rte_table_action_profile *profile,
+	uint32_t socket_id)
+{
+	struct rte_table_action *action;
+
+	/* Check input arguments */
+	if ((profile == NULL) ||
+		(profile->frozen == 0))
+		return NULL;
+
+	/* Memory allocation */
+	action = rte_zmalloc_socket(NULL,
+		sizeof(struct rte_table_action),
+		RTE_CACHE_LINE_SIZE,
+		socket_id);
+	if (action == NULL)
+		return NULL;
+
+	/* Initialization */
+	memcpy(&action->cfg, &profile->cfg, sizeof(profile->cfg));
+	memcpy(&action->data, &profile->data, sizeof(profile->data));
+
+	return action;
+}
+
+static __rte_always_inline void *
+action_data_get(void *data,
+	struct rte_table_action *action,
+	enum rte_table_action_type type)
+{
+	size_t offset = action->data.offset[type];
+	uint8_t *data_bytes = data;
+
+	return &data_bytes[offset];
+}
+
+int
+rte_table_action_apply(struct rte_table_action *action,
+	void *data,
+	enum rte_table_action_type type,
+	void *action_params)
+{
+	void *action_data;
+
+	/* Check input arguments */
+	if ((action == NULL) ||
+		(data == NULL) ||
+		(action_valid(type) == 0) ||
+		((action->cfg.action_mask & (1LLU << type)) == 0) ||
+		(action_params == NULL))
+		return -EINVAL;
+
+	/* Data update */
+	action_data = action_data_get(data, action, type);
+
+	switch (type) {
+	case RTE_TABLE_ACTION_FWD:
+		return fwd_apply(action_data,
+			action_params);
+
+	default:
+		return -EINVAL;
+	}
+}
+
+int
+rte_table_action_free(struct rte_table_action *action)
+{
+	if (action == NULL)
+		return 0;
+
+	rte_free(action);
+
+	return 0;
+}
diff --git a/lib/librte_pipeline/rte_table_action.h b/lib/librte_pipeline/rte_table_action.h
new file mode 100644
index 0000000..da7f12c
--- /dev/null
+++ b/lib/librte_pipeline/rte_table_action.h
@@ -0,0 +1,224 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation
+ */
+
+#ifndef __INCLUDE_RTE_TABLE_ACTION_H__
+#define __INCLUDE_RTE_TABLE_ACTION_H__
+
+/**
+ * @file
+ * RTE Pipeline Table Actions
+ *
+ * This API provides a common set of actions for pipeline tables to speed up
+ * application development.
+ *
+ * Each match-action rule added to a pipeline table has associated data that
+ * stores the action context. This data is input to the table action handler
+ * called for every input packet that hits the rule as part of the table lookup
+ * during the pipeline execution. The pipeline library allows the user to define
+ * his own table actions by providing customized table action handlers (table
+ * lookup) and complete freedom of setting the rules and their data (table rule
+ * add/delete). While the user can still follow this process, this API is
+ * intended to provide a quicker development alternative for a set of predefined
+ * actions.
+ *
+ * The typical steps to use this API are:
+ *  - Define a table action profile. This is a configuration template that can
+ *    potentially be shared by multiple tables from the same or different
+ *    pipelines, with different tables from the same pipeline likely to use
+ *    different action profiles. For every table using a given action profile,
+ *    the profile defines the set of actions and the action configuration to be
+ *    implemented for all the table rules. API functions:
+ *    rte_table_action_profile_create(),
+ *    rte_table_action_profile_action_register(),
+ *    rte_table_action_profile_freeze().
+ *
+ *  - Instantiate the table action profile to create table action objects. Each
+ *    pipeline table has its own table action object. API functions:
+ *    rte_table_action_create().
+ *
+ *  - Use the table action object to generate the pipeline table action handlers
+ *    (invoked by the pipeline table lookup operation). API functions:
+ *    rte_table_action_table_params_get().
+ *
+ *  - Use the table action object to generate the rule data (for the pipeline
+ *    table rule add operation) based on given action parameters. API functions:
+ *    rte_table_action_apply().
+ *
+ *  - Use the table action object to read action data (e.g. stats counters) for
+ *    any given rule. API functions: rte_table_action_XYZ_read().
+ *
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+
+#include <rte_compat.h>
+
+#include "rte_pipeline.h"
+
+/** Table actions. */
+enum rte_table_action_type {
+	/** Forward to next pipeline table, output port or drop. */
+	RTE_TABLE_ACTION_FWD = 0,
+};
+
+/** Common action configuration (per table action profile). */
+struct rte_table_action_common_config {
+	/** Input packet Internet Protocol (IP) version. Non-zero for IPv4, zero
+	 * for IPv6.
+	 */
+	int ip_version;
+
+	/** IP header offset within the input packet buffer. Offset 0 points to
+	 * the first byte of the MBUF structure.
+	 */
+	uint32_t ip_offset;
+};
+
+/**
+ * RTE_TABLE_ACTION_FWD
+ */
+/** Forward action parameters (per table rule). */
+struct rte_table_action_fwd_params {
+	/** Forward action. */
+	enum rte_pipeline_action action;
+
+	/** Pipeline table ID or output port ID. */
+	uint32_t id;
+};
+
+/**
+ * Table action profile.
+ */
+struct rte_table_action_profile;
+
+/**
+ * Table action profile create.
+ *
+ * @param[in] common
+ *   Common action configuration.
+ * @return
+ *   Table action profile handle on success, NULL otherwise.
+ */
+struct rte_table_action_profile * __rte_experimental
+rte_table_action_profile_create(struct rte_table_action_common_config *common);
+
+/**
+ * Table action profile free.
+ *
+ * @param[in] profile
+ *   Table profile action handle (needs to be valid).
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_table_action_profile_free(struct rte_table_action_profile *profile);
+
+/**
+ * Table action profile action register.
+ *
+ * @param[in] profile
+ *   Table profile action handle (needs to be valid and not in frozen state).
+ * @param[in] type
+ *   Specific table action to be registered for *profile*.
+ * @param[in] action_config
+ *   Configuration for the *type* action.
+ *   If struct rte_table_action_*type*_config is defined by the Table Action
+ *   API, it needs to point to a valid instance of this structure, otherwise it
+ *   needs to be set to NULL.
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_table_action_profile_action_register(struct rte_table_action_profile *profile,
+	enum rte_table_action_type type,
+	void *action_config);
+
+/**
+ * Table action profile freeze.
+ *
+ * Once this function is called successfully, the given profile enters the
+ * frozen state with the following immediate effects: no more actions can be
+ * registered for this profile, so the profile can be instantiated to create
+ * table action objects.
+ *
+ * @param[in] profile
+ *   Table profile action handle (needs to be valid and not in frozen state).
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ *
+ * @see rte_table_action_create()
+ */
+int __rte_experimental
+rte_table_action_profile_freeze(struct rte_table_action_profile *profile);
+
+/**
+ * Table action.
+ */
+struct rte_table_action;
+
+/**
+ * Table action create.
+ *
+ * Instantiates the given table action profile to create a table action object.
+ *
+ * @param[in] profile
+ *   Table profile action handle (needs to be valid and in frozen state).
+ * @param[in] socket_id
+ *   CPU socket ID where the internal data structures required by the new table
+ *   action object should be allocated.
+ * @return
+ *   Handle to table action object on success, NULL on error.
+ *
+ * @see rte_table_action_create()
+ */
+struct rte_table_action * __rte_experimental
+rte_table_action_create(struct rte_table_action_profile *profile,
+	uint32_t socket_id);
+
+/**
+ * Table action free.
+ *
+ * @param[in] action
+ *   Handle to table action object (needs to be valid).
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_table_action_free(struct rte_table_action *action);
+
+/**
+ * Table action apply.
+ *
+ * @param[in] action
+ *   Handle to table action object (needs to be valid).
+ * @param[in] data
+ *   Data byte array (typically table rule data) to apply action *type* on.
+ * @param[in] type
+ *   Specific table action previously registered for the table action profile of
+ *   the *action* object.
+ * @param[in] action_params
+ *   Parameters for the *type* action.
+ *   If struct rte_table_action_*type*_params is defined by the Table Action
+ *   API, it needs to point to a valid instance of this structure, otherwise it
+ *   needs to be set to NULL.
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_table_action_apply(struct rte_table_action *action,
+	void *data,
+	enum rte_table_action_type type,
+	void *action_params);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __INCLUDE_RTE_TABLE_ACTION_H__ */
-- 
2.9.3

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

* [dpdk-dev] [PATCH v3 02/44] pipeline: get pipeline table action params
  2018-03-16 17:58       ` [dpdk-dev] [PATCH v3 00/44] ip_pipeline: refactoring Jasvinder Singh
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 01/44] pipeline: add pipeline table action APIs Jasvinder Singh
@ 2018-03-16 17:58         ` Jasvinder Singh
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 03/44] pipeline: add traffic metering action Jasvinder Singh
                           ` (41 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-16 17:58 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add API to specify action related parameters such as action
handler, table entry data size, etc. for the pipeline table.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 lib/librte_pipeline/rte_pipeline_version.map |   1 +
 lib/librte_pipeline/rte_table_action.c       | 130 +++++++++++++++++++++++++++
 lib/librte_pipeline/rte_table_action.h       |  14 +++
 3 files changed, 145 insertions(+)

diff --git a/lib/librte_pipeline/rte_pipeline_version.map b/lib/librte_pipeline/rte_pipeline_version.map
index 4bc414c..13337de 100644
--- a/lib/librte_pipeline/rte_pipeline_version.map
+++ b/lib/librte_pipeline/rte_pipeline_version.map
@@ -56,5 +56,6 @@ EXPERIMENTAL {
 	rte_table_action_profile_create;
 	rte_table_action_profile_free;
 	rte_table_action_profile_freeze;
+	rte_table_action_table_params_get;
 
 } DPDK_16.04;
diff --git a/lib/librte_pipeline/rte_table_action.c b/lib/librte_pipeline/rte_table_action.c
index f15847c..09f26f5 100644
--- a/lib/librte_pipeline/rte_table_action.c
+++ b/lib/librte_pipeline/rte_table_action.c
@@ -267,6 +267,136 @@ rte_table_action_apply(struct rte_table_action *action,
 	}
 }
 
+static __rte_always_inline uint64_t
+pkt_work(struct rte_mbuf *mbuf __rte_unused,
+	struct rte_pipeline_table_entry *table_entry __rte_unused,
+	uint64_t time __rte_unused,
+	struct rte_table_action *action __rte_unused,
+	struct ap_config *cfg __rte_unused)
+{
+	return 0;
+}
+
+static __rte_always_inline uint64_t
+pkt4_work(struct rte_mbuf **mbufs __rte_unused,
+	struct rte_pipeline_table_entry **table_entries __rte_unused,
+	uint64_t time __rte_unused,
+	struct rte_table_action *action __rte_unused,
+	struct ap_config *cfg __rte_unused)
+{
+	return 0;
+}
+
+static __rte_always_inline int
+ah(struct rte_pipeline *p,
+	struct rte_mbuf **pkts,
+	uint64_t pkts_mask,
+	struct rte_pipeline_table_entry **entries,
+	struct rte_table_action *action,
+	struct ap_config *cfg)
+{
+	uint64_t pkts_drop_mask = 0;
+	uint64_t time = 0;
+
+	if ((pkts_mask & (pkts_mask + 1)) == 0) {
+		uint64_t n_pkts = __builtin_popcountll(pkts_mask);
+		uint32_t i;
+
+		for (i = 0; i < (n_pkts & (~0x3LLU)); i += 4) {
+			uint64_t drop_mask;
+
+			drop_mask = pkt4_work(&pkts[i],
+				&entries[i],
+				time,
+				action,
+				cfg);
+
+			pkts_drop_mask |= drop_mask << i;
+		}
+
+		for ( ; i < n_pkts; i++) {
+			uint64_t drop_mask;
+
+			drop_mask = pkt_work(pkts[i],
+				entries[i],
+				time,
+				action,
+				cfg);
+
+			pkts_drop_mask |= drop_mask << i;
+		}
+	} else
+		for ( ; pkts_mask; ) {
+			uint32_t pos = __builtin_ctzll(pkts_mask);
+			uint64_t pkt_mask = 1LLU << pos;
+			uint64_t drop_mask;
+
+			drop_mask = pkt_work(pkts[pos],
+				entries[pos],
+				time,
+				action,
+				cfg);
+
+			pkts_mask &= ~pkt_mask;
+			pkts_drop_mask |= drop_mask << pos;
+		}
+
+	rte_pipeline_ah_packet_drop(p, pkts_drop_mask);
+
+	return 0;
+}
+
+static int
+ah_default(struct rte_pipeline *p,
+	struct rte_mbuf **pkts,
+	uint64_t pkts_mask,
+	struct rte_pipeline_table_entry **entries,
+	void *arg)
+{
+	struct rte_table_action *action = arg;
+
+	return ah(p,
+		pkts,
+		pkts_mask,
+		entries,
+		action,
+		&action->cfg);
+}
+
+static rte_pipeline_table_action_handler_hit
+ah_selector(struct rte_table_action *action)
+{
+	if (action->cfg.action_mask == (1LLU << RTE_TABLE_ACTION_FWD))
+		return NULL;
+
+	return ah_default;
+}
+
+int
+rte_table_action_table_params_get(struct rte_table_action *action,
+	struct rte_pipeline_table_params *params)
+{
+	rte_pipeline_table_action_handler_hit f_action_hit;
+	uint32_t total_size;
+
+	/* Check input arguments */
+	if ((action == NULL) ||
+		(params == NULL))
+		return -EINVAL;
+
+	f_action_hit = ah_selector(action);
+	total_size = rte_align32pow2(action->data.total_size);
+
+	/* Fill in params */
+	params->f_action_hit = f_action_hit;
+	params->f_action_miss = NULL;
+	params->arg_ah = (f_action_hit) ? action : NULL;
+	params->action_data_size = total_size -
+		sizeof(struct rte_pipeline_table_entry);
+
+	return 0;
+}
+
 int
 rte_table_action_free(struct rte_table_action *action)
 {
diff --git a/lib/librte_pipeline/rte_table_action.h b/lib/librte_pipeline/rte_table_action.h
index da7f12c..03b77ca 100644
--- a/lib/librte_pipeline/rte_table_action.h
+++ b/lib/librte_pipeline/rte_table_action.h
@@ -194,6 +194,20 @@ int __rte_experimental
 rte_table_action_free(struct rte_table_action *action);
 
 /**
+ * Table action table params get.
+ *
+ * @param[in] action
+ *   Handle to table action object (needs to be valid).
+ * @param[inout] params
+ *   Pipeline table parameters (needs to be pre-allocated).
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_table_action_table_params_get(struct rte_table_action *action,
+	struct rte_pipeline_table_params *params);
+
+/**
  * Table action apply.
  *
  * @param[in] action
-- 
2.9.3

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

* [dpdk-dev] [PATCH v3 03/44] pipeline: add traffic metering action
  2018-03-16 17:58       ` [dpdk-dev] [PATCH v3 00/44] ip_pipeline: refactoring Jasvinder Singh
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 01/44] pipeline: add pipeline table action APIs Jasvinder Singh
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 02/44] pipeline: get pipeline table action params Jasvinder Singh
@ 2018-03-16 17:58         ` Jasvinder Singh
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 04/44] pipeline: add traffic manager action Jasvinder Singh
                           ` (40 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-16 17:58 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add traffic metering action implementation.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 lib/librte_pipeline/Makefile                 |   3 +-
 lib/librte_pipeline/meson.build              |   2 +-
 lib/librte_pipeline/rte_pipeline_version.map |   4 +
 lib/librte_pipeline/rte_table_action.c       | 640 ++++++++++++++++++++++++++-
 lib/librte_pipeline/rte_table_action.h       | 248 +++++++++++
 5 files changed, 879 insertions(+), 18 deletions(-)

diff --git a/lib/librte_pipeline/Makefile b/lib/librte_pipeline/Makefile
index e8c43c7..72e4c7c 100644
--- a/lib/librte_pipeline/Makefile
+++ b/lib/librte_pipeline/Makefile
@@ -8,10 +8,11 @@ include $(RTE_SDK)/mk/rte.vars.mk
 #
 LIB = librte_pipeline.a
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
 LDLIBS += -lrte_eal -lrte_mempool -lrte_mbuf -lrte_table
-LDLIBS += -lrte_port
+LDLIBS += -lrte_port -lrte_meter
 
 EXPORT_MAP := rte_pipeline_version.map
 
diff --git a/lib/librte_pipeline/meson.build b/lib/librte_pipeline/meson.build
index 4dda560..71da295 100644
--- a/lib/librte_pipeline/meson.build
+++ b/lib/librte_pipeline/meson.build
@@ -5,4 +5,4 @@ version = 3
 allow_experimental_apis = true
 sources = files('rte_pipeline.c', 'rte_table_action.c')
 headers = files('rte_pipeline.h', 'rte_table_action.h')
-deps += ['port', 'table']
+deps += ['port', 'table', 'meter']
diff --git a/lib/librte_pipeline/rte_pipeline_version.map b/lib/librte_pipeline/rte_pipeline_version.map
index 13337de..c7106dc 100644
--- a/lib/librte_pipeline/rte_pipeline_version.map
+++ b/lib/librte_pipeline/rte_pipeline_version.map
@@ -51,7 +51,11 @@ EXPERIMENTAL {
 
 	rte_table_action_apply;
 	rte_table_action_create;
+	rte_table_action_dscp_table_update;
 	rte_table_action_free;
+	rte_table_action_meter_profile_add;
+	rte_table_action_meter_profile_delete;
+	rte_table_action_meter_read;
 	rte_table_action_profile_action_register;
 	rte_table_action_profile_create;
 	rte_table_action_profile_free;
diff --git a/lib/librte_pipeline/rte_table_action.c b/lib/librte_pipeline/rte_table_action.c
index 09f26f5..f3be28a 100644
--- a/lib/librte_pipeline/rte_table_action.c
+++ b/lib/librte_pipeline/rte_table_action.c
@@ -5,13 +5,21 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include <rte_malloc.h>
-
 #include <rte_common.h>
+#include <rte_byteorder.h>
+#include <rte_cycles.h>
 #include <rte_malloc.h>
+#include <rte_ip.h>
+
 
 #include "rte_table_action.h"
 
+#define rte_htons rte_cpu_to_be_16
+#define rte_htonl rte_cpu_to_be_32
+
+#define rte_ntohs rte_be_to_cpu_16
+#define rte_ntohl rte_be_to_cpu_32
+
 /**
  * RTE_TABLE_ACTION_FWD
  */
@@ -33,6 +41,264 @@ fwd_apply(struct fwd_data *data,
 }
 
 /**
+ * RTE_TABLE_ACTION_MTR
+ */
+static int
+mtr_cfg_check(struct rte_table_action_mtr_config *mtr)
+{
+	if ((mtr->alg == RTE_TABLE_ACTION_METER_SRTCM) ||
+		((mtr->n_tc != 1) && (mtr->n_tc != 4)) ||
+		(mtr->n_bytes_enabled != 0))
+		return -ENOTSUP;
+	return 0;
+}
+
+#define MBUF_SCHED_QUEUE_TC_COLOR(queue, tc, color)        \
+	((uint16_t)((((uint64_t)(queue)) & 0x3) |          \
+	((((uint64_t)(tc)) & 0x3) << 2) |                  \
+	((((uint64_t)(color)) & 0x3) << 4)))
+
+#define MBUF_SCHED_COLOR(sched, color)                     \
+	(((sched) & (~0x30LLU)) | ((color) << 4))
+
+struct mtr_trtcm_data {
+	struct rte_meter_trtcm trtcm;
+	uint64_t stats[e_RTE_METER_COLORS];
+} __attribute__((__packed__));
+
+#define MTR_TRTCM_DATA_METER_PROFILE_ID_GET(data)          \
+	(((data)->stats[e_RTE_METER_GREEN] & 0xF8LLU) >> 3)
+
+static void
+mtr_trtcm_data_meter_profile_id_set(struct mtr_trtcm_data *data,
+	uint32_t profile_id)
+{
+	data->stats[e_RTE_METER_GREEN] &= ~0xF8LLU;
+	data->stats[e_RTE_METER_GREEN] |= (profile_id % 32) << 3;
+}
+
+#define MTR_TRTCM_DATA_POLICER_ACTION_DROP_GET(data, color)\
+	(((data)->stats[(color)] & 4LLU) >> 2)
+
+#define MTR_TRTCM_DATA_POLICER_ACTION_COLOR_GET(data, color)\
+	((enum rte_meter_color)((data)->stats[(color)] & 3LLU))
+
+static void
+mtr_trtcm_data_policer_action_set(struct mtr_trtcm_data *data,
+	enum rte_meter_color color,
+	enum rte_table_action_policer action)
+{
+	if (action == RTE_TABLE_ACTION_POLICER_DROP) {
+		data->stats[color] |= 4LLU;
+	} else {
+		data->stats[color] &= ~7LLU;
+		data->stats[color] |= color & 3LLU;
+	}
+}
+
+static uint64_t
+mtr_trtcm_data_stats_get(struct mtr_trtcm_data *data,
+	enum rte_meter_color color)
+{
+	return data->stats[color] >> 8;
+}
+
+static void
+mtr_trtcm_data_stats_reset(struct mtr_trtcm_data *data,
+	enum rte_meter_color color)
+{
+	data->stats[color] &= 0xFFLU;
+}
+
+#define MTR_TRTCM_DATA_STATS_INC(data, color)              \
+	((data)->stats[(color)] += (1LLU << 8))
+
+static size_t
+mtr_data_size(struct rte_table_action_mtr_config *mtr)
+{
+	return mtr->n_tc * sizeof(struct mtr_trtcm_data);
+}
+
+struct dscp_table_entry_data {
+	enum rte_meter_color color;
+	uint16_t tc;
+	uint16_t queue_tc_color;
+};
+
+struct dscp_table_data {
+	struct dscp_table_entry_data entry[64];
+};
+
+struct meter_profile_data {
+	struct rte_meter_trtcm_profile profile;
+	uint32_t profile_id;
+	int valid;
+};
+
+static struct meter_profile_data *
+meter_profile_data_find(struct meter_profile_data *mp,
+	uint32_t mp_size,
+	uint32_t profile_id)
+{
+	uint32_t i;
+
+	for (i = 0; i < mp_size; i++) {
+		struct meter_profile_data *mp_data = &mp[i];
+
+		if (mp_data->valid && (mp_data->profile_id == profile_id))
+			return mp_data;
+	}
+
+	return NULL;
+}
+
+static struct meter_profile_data *
+meter_profile_data_find_unused(struct meter_profile_data *mp,
+	uint32_t mp_size)
+{
+	uint32_t i;
+
+	for (i = 0; i < mp_size; i++) {
+		struct meter_profile_data *mp_data = &mp[i];
+
+		if (!mp_data->valid)
+			return mp_data;
+	}
+
+	return NULL;
+}
+
+static int
+mtr_apply_check(struct rte_table_action_mtr_params *p,
+	struct rte_table_action_mtr_config *cfg,
+	struct meter_profile_data *mp,
+	uint32_t mp_size)
+{
+	uint32_t i;
+
+	if (p->tc_mask > RTE_LEN2MASK(cfg->n_tc, uint32_t))
+		return -EINVAL;
+
+	for (i = 0; i < RTE_TABLE_ACTION_TC_MAX; i++) {
+		struct rte_table_action_mtr_tc_params *p_tc = &p->mtr[i];
+		struct meter_profile_data *mp_data;
+
+		if ((p->tc_mask & (1LLU << i)) == 0)
+			continue;
+
+		mp_data = meter_profile_data_find(mp,
+			mp_size,
+			p_tc->meter_profile_id);
+		if (!mp_data)
+			return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int
+mtr_apply(struct mtr_trtcm_data *data,
+	struct rte_table_action_mtr_params *p,
+	struct rte_table_action_mtr_config *cfg,
+	struct meter_profile_data *mp,
+	uint32_t mp_size)
+{
+	uint32_t i;
+	int status;
+
+	/* Check input arguments */
+	status = mtr_apply_check(p, cfg, mp, mp_size);
+	if (status)
+		return status;
+
+	/* Apply */
+	for (i = 0; i < RTE_TABLE_ACTION_TC_MAX; i++) {
+		struct rte_table_action_mtr_tc_params *p_tc = &p->mtr[i];
+		struct mtr_trtcm_data *data_tc = &data[i];
+		struct meter_profile_data *mp_data;
+
+		if ((p->tc_mask & (1LLU << i)) == 0)
+			continue;
+
+		/* Find profile */
+		mp_data = meter_profile_data_find(mp,
+			mp_size,
+			p_tc->meter_profile_id);
+		if (!mp_data)
+			return -EINVAL;
+
+		memset(data_tc, 0, sizeof(*data_tc));
+
+		/* Meter object */
+		status = rte_meter_trtcm_config(&data_tc->trtcm,
+			&mp_data->profile);
+		if (status)
+			return status;
+
+		/* Meter profile */
+		mtr_trtcm_data_meter_profile_id_set(data_tc,
+			mp_data - mp);
+
+		/* Policer actions */
+		mtr_trtcm_data_policer_action_set(data_tc,
+			e_RTE_METER_GREEN,
+			p_tc->policer[e_RTE_METER_GREEN]);
+
+		mtr_trtcm_data_policer_action_set(data_tc,
+			e_RTE_METER_YELLOW,
+			p_tc->policer[e_RTE_METER_YELLOW]);
+
+		mtr_trtcm_data_policer_action_set(data_tc,
+			e_RTE_METER_RED,
+			p_tc->policer[e_RTE_METER_RED]);
+	}
+
+	return 0;
+}
+
+static __rte_always_inline uint64_t
+pkt_work_mtr(struct rte_mbuf *mbuf,
+	struct mtr_trtcm_data *data,
+	struct dscp_table_data *dscp_table,
+	struct meter_profile_data *mp,
+	uint64_t time,
+	uint32_t dscp,
+	uint16_t total_length)
+{
+	uint64_t drop_mask, sched;
+	uint64_t *sched_ptr = (uint64_t *) &mbuf->hash.sched;
+	struct dscp_table_entry_data *dscp_entry = &dscp_table->entry[dscp];
+	enum rte_meter_color color_in, color_meter, color_policer;
+	uint32_t tc, mp_id;
+
+	tc = dscp_entry->tc;
+	color_in = dscp_entry->color;
+	data += tc;
+	mp_id = MTR_TRTCM_DATA_METER_PROFILE_ID_GET(data);
+	sched = *sched_ptr;
+
+	/* Meter */
+	color_meter = rte_meter_trtcm_color_aware_check(
+		&data->trtcm,
+		&mp[mp_id].profile,
+		time,
+		total_length,
+		color_in);
+
+	/* Stats */
+	MTR_TRTCM_DATA_STATS_INC(data, color_meter);
+
+	/* Police */
+	drop_mask = MTR_TRTCM_DATA_POLICER_ACTION_DROP_GET(data, color_meter);
+	color_policer =
+		MTR_TRTCM_DATA_POLICER_ACTION_COLOR_GET(data, color_meter);
+	*sched_ptr = MBUF_SCHED_COLOR(sched, color_policer);
+
+	return drop_mask;
+}
+
+
+/**
  * Action profile
  */
 static int
@@ -40,6 +306,7 @@ action_valid(enum rte_table_action_type action)
 {
 	switch (action) {
 	case RTE_TABLE_ACTION_FWD:
+	case RTE_TABLE_ACTION_MTR:
 		return 1;
 	default:
 		return 0;
@@ -52,22 +319,28 @@ action_valid(enum rte_table_action_type action)
 struct ap_config {
 	uint64_t action_mask;
 	struct rte_table_action_common_config common;
+	struct rte_table_action_mtr_config mtr;
 };
 
 static size_t
 action_cfg_size(enum rte_table_action_type action)
 {
 	switch (action) {
+	case RTE_TABLE_ACTION_MTR:
+		return sizeof(struct rte_table_action_mtr_config);
 	default:
 		return 0;
 	}
 }
 
 static void*
-action_cfg_get(struct ap_config *ap_config __rte_unused,
+action_cfg_get(struct ap_config *ap_config,
 	enum rte_table_action_type type)
 {
 	switch (type) {
+	case RTE_TABLE_ACTION_MTR:
+		return &ap_config->mtr;
+
 	default:
 		return NULL;
 	}
@@ -93,12 +366,15 @@ struct ap_data {
 
 static size_t
 action_data_size(enum rte_table_action_type action,
-	struct ap_config *ap_config __rte_unused)
+	struct ap_config *ap_config)
 {
 	switch (action) {
 	case RTE_TABLE_ACTION_FWD:
 		return sizeof(struct fwd_data);
 
+	case RTE_TABLE_ACTION_MTR:
+		return mtr_data_size(&ap_config->mtr);
+
 	default:
 		return 0;
 	}
@@ -158,6 +434,8 @@ rte_table_action_profile_action_register(struct rte_table_action_profile *profil
 	enum rte_table_action_type type,
 	void *action_config)
 {
+	int status;
+
 	/* Check input arguments */
 	if ((profile == NULL) ||
 		profile->frozen ||
@@ -167,6 +445,19 @@ rte_table_action_profile_action_register(struct rte_table_action_profile *profil
 		(action_cfg_size(type) && (action_config == NULL)))
 		return -EINVAL;
 
+	switch (type) {
+	case RTE_TABLE_ACTION_MTR:
+		status = mtr_cfg_check(action_config);
+		break;
+
+	default:
+		status = 0;
+		break;
+	}
+
+	if (status)
+		return status;
+
 	/* Action enable */
 	action_cfg_set(&profile->cfg, type, action_config);
 
@@ -196,9 +487,16 @@ rte_table_action_profile_free(struct rte_table_action_profile *profile)
 	return 0;
 }
 
+/**
+ * Action
+ */
+#define METER_PROFILES_MAX                                 32
+
 struct rte_table_action {
 	struct ap_config cfg;
 	struct ap_data data;
+	struct dscp_table_data dscp_table;
+	struct meter_profile_data mp[METER_PROFILES_MAX];
 };
 
 struct rte_table_action *
@@ -262,31 +560,338 @@ rte_table_action_apply(struct rte_table_action *action,
 		return fwd_apply(action_data,
 			action_params);
 
+	case RTE_TABLE_ACTION_MTR:
+		return mtr_apply(action_data,
+			action_params,
+			&action->cfg.mtr,
+			action->mp,
+			RTE_DIM(action->mp));
+
 	default:
 		return -EINVAL;
 	}
 }
 
-static __rte_always_inline uint64_t
-pkt_work(struct rte_mbuf *mbuf __rte_unused,
-	struct rte_pipeline_table_entry *table_entry __rte_unused,
-	uint64_t time __rte_unused,
-	struct rte_table_action *action __rte_unused,
-	struct ap_config *cfg __rte_unused)
+int
+rte_table_action_dscp_table_update(struct rte_table_action *action,
+	uint64_t dscp_mask,
+	struct rte_table_action_dscp_table *table)
 {
+	uint32_t i;
+
+	/* Check input arguments */
+	if ((action == NULL) ||
+		(action->cfg.action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) ||
+		(dscp_mask == 0) ||
+		(table == NULL))
+		return -EINVAL;
+
+	for (i = 0; i < RTE_DIM(table->entry); i++) {
+		struct dscp_table_entry_data *data =
+			&action->dscp_table.entry[i];
+		struct rte_table_action_dscp_table_entry *entry =
+			&table->entry[i];
+		uint16_t queue_tc_color =
+			MBUF_SCHED_QUEUE_TC_COLOR(entry->tc_queue_id,
+				entry->tc_id,
+				entry->color);
+
+		if ((dscp_mask & (1LLU << i)) == 0)
+			continue;
+
+		data->color = entry->color;
+		data->tc = entry->tc_id;
+		data->queue_tc_color = queue_tc_color;
+	}
+
 	return 0;
 }
 
-static __rte_always_inline uint64_t
-pkt4_work(struct rte_mbuf **mbufs __rte_unused,
-	struct rte_pipeline_table_entry **table_entries __rte_unused,
-	uint64_t time __rte_unused,
-	struct rte_table_action *action __rte_unused,
-	struct ap_config *cfg __rte_unused)
+int
+rte_table_action_meter_profile_add(struct rte_table_action *action,
+	uint32_t meter_profile_id,
+	struct rte_table_action_meter_profile *profile)
 {
+	struct meter_profile_data *mp_data;
+	uint32_t status;
+
+	/* Check input arguments */
+	if ((action == NULL) ||
+		((action->cfg.action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) == 0) ||
+		(profile == NULL))
+		return -EINVAL;
+
+	if (profile->alg != RTE_TABLE_ACTION_METER_TRTCM)
+		return -ENOTSUP;
+
+	mp_data = meter_profile_data_find(action->mp,
+		RTE_DIM(action->mp),
+		meter_profile_id);
+	if (mp_data)
+		return -EEXIST;
+
+	mp_data = meter_profile_data_find_unused(action->mp,
+		RTE_DIM(action->mp));
+	if (!mp_data)
+		return -ENOSPC;
+
+	/* Install new profile */
+	status = rte_meter_trtcm_profile_config(&mp_data->profile,
+		&profile->trtcm);
+	if (status)
+		return status;
+
+	mp_data->profile_id = meter_profile_id;
+	mp_data->valid = 1;
+
 	return 0;
 }
 
+int
+rte_table_action_meter_profile_delete(struct rte_table_action *action,
+	uint32_t meter_profile_id)
+{
+	struct meter_profile_data *mp_data;
+
+	/* Check input arguments */
+	if ((action == NULL) ||
+		((action->cfg.action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) == 0))
+		return -EINVAL;
+
+	mp_data = meter_profile_data_find(action->mp,
+		RTE_DIM(action->mp),
+		meter_profile_id);
+	if (!mp_data)
+		return 0;
+
+	/* Uninstall profile */
+	mp_data->valid = 0;
+
+	return 0;
+}
+
+int
+rte_table_action_meter_read(struct rte_table_action *action,
+	void *data,
+	uint32_t tc_mask,
+	struct rte_table_action_mtr_counters *stats,
+	int clear)
+{
+	struct mtr_trtcm_data *mtr_data;
+	uint32_t i;
+
+	/* Check input arguments */
+	if ((action == NULL) ||
+		((action->cfg.action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) == 0) ||
+		(data == NULL) ||
+		(tc_mask > RTE_LEN2MASK(action->cfg.mtr.n_tc, uint32_t)))
+		return -EINVAL;
+
+	mtr_data = action_data_get(data, action, RTE_TABLE_ACTION_MTR);
+
+	/* Read */
+	if (stats) {
+		for (i = 0; i < RTE_TABLE_ACTION_TC_MAX; i++) {
+			struct rte_table_action_mtr_counters_tc *dst =
+				&stats->stats[i];
+			struct mtr_trtcm_data *src = &mtr_data[i];
+
+			if ((tc_mask & (1 << i)) == 0)
+				continue;
+
+			dst->n_packets[e_RTE_METER_GREEN] =
+				mtr_trtcm_data_stats_get(src, e_RTE_METER_GREEN);
+
+			dst->n_packets[e_RTE_METER_YELLOW] =
+				mtr_trtcm_data_stats_get(src, e_RTE_METER_YELLOW);
+
+			dst->n_packets[e_RTE_METER_RED] =
+				mtr_trtcm_data_stats_get(src, e_RTE_METER_RED);
+
+			dst->n_packets_valid = 1;
+			dst->n_bytes_valid = 0;
+		}
+
+		stats->tc_mask = tc_mask;
+	}
+
+	/* Clear */
+	if (clear)
+		for (i = 0; i < RTE_TABLE_ACTION_TC_MAX; i++) {
+			struct mtr_trtcm_data *src = &mtr_data[i];
+
+			if ((tc_mask & (1 << i)) == 0)
+				continue;
+
+			mtr_trtcm_data_stats_reset(src, e_RTE_METER_GREEN);
+			mtr_trtcm_data_stats_reset(src, e_RTE_METER_YELLOW);
+			mtr_trtcm_data_stats_reset(src, e_RTE_METER_RED);
+		}
+
+
+	return 0;
+}
+
+static __rte_always_inline uint64_t
+pkt_work(struct rte_mbuf *mbuf,
+	struct rte_pipeline_table_entry *table_entry,
+	uint64_t time,
+	struct rte_table_action *action,
+	struct ap_config *cfg)
+{
+	uint64_t drop_mask = 0;
+
+	uint32_t ip_offset = action->cfg.common.ip_offset;
+	void *ip = RTE_MBUF_METADATA_UINT32_PTR(mbuf, ip_offset);
+
+	uint32_t dscp;
+	uint16_t total_length;
+
+	if (cfg->common.ip_version) {
+		struct ipv4_hdr *hdr = ip;
+
+		dscp = hdr->type_of_service >> 2;
+		total_length = rte_ntohs(hdr->total_length);
+	} else {
+		struct ipv6_hdr *hdr = ip;
+
+		dscp = (rte_ntohl(hdr->vtc_flow) & 0x0F600000) >> 18;
+		total_length =
+			rte_ntohs(hdr->payload_len) + sizeof(struct ipv6_hdr);
+	}
+
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) {
+		void *data =
+			action_data_get(table_entry, action, RTE_TABLE_ACTION_MTR);
+
+		drop_mask |= pkt_work_mtr(mbuf,
+			data,
+			&action->dscp_table,
+			action->mp,
+			time,
+			dscp,
+			total_length);
+	}
+
+	return drop_mask;
+}
+
+static __rte_always_inline uint64_t
+pkt4_work(struct rte_mbuf **mbufs,
+	struct rte_pipeline_table_entry **table_entries,
+	uint64_t time,
+	struct rte_table_action *action,
+	struct ap_config *cfg)
+{
+	uint64_t drop_mask0 = 0;
+	uint64_t drop_mask1 = 0;
+	uint64_t drop_mask2 = 0;
+	uint64_t drop_mask3 = 0;
+
+	struct rte_mbuf *mbuf0 = mbufs[0];
+	struct rte_mbuf *mbuf1 = mbufs[1];
+	struct rte_mbuf *mbuf2 = mbufs[2];
+	struct rte_mbuf *mbuf3 = mbufs[3];
+
+	struct rte_pipeline_table_entry *table_entry0 = table_entries[0];
+	struct rte_pipeline_table_entry *table_entry1 = table_entries[1];
+	struct rte_pipeline_table_entry *table_entry2 = table_entries[2];
+	struct rte_pipeline_table_entry *table_entry3 = table_entries[3];
+
+	uint32_t ip_offset = action->cfg.common.ip_offset;
+	void *ip0 = RTE_MBUF_METADATA_UINT32_PTR(mbuf0, ip_offset);
+	void *ip1 = RTE_MBUF_METADATA_UINT32_PTR(mbuf1, ip_offset);
+	void *ip2 = RTE_MBUF_METADATA_UINT32_PTR(mbuf2, ip_offset);
+	void *ip3 = RTE_MBUF_METADATA_UINT32_PTR(mbuf3, ip_offset);
+
+	uint32_t dscp0, dscp1, dscp2, dscp3;
+	uint16_t total_length0, total_length1, total_length2, total_length3;
+
+	if (cfg->common.ip_version) {
+		struct ipv4_hdr *hdr0 = ip0;
+		struct ipv4_hdr *hdr1 = ip1;
+		struct ipv4_hdr *hdr2 = ip2;
+		struct ipv4_hdr *hdr3 = ip3;
+
+		dscp0 = hdr0->type_of_service >> 2;
+		dscp1 = hdr1->type_of_service >> 2;
+		dscp2 = hdr2->type_of_service >> 2;
+		dscp3 = hdr3->type_of_service >> 2;
+
+		total_length0 = rte_ntohs(hdr0->total_length);
+		total_length1 = rte_ntohs(hdr1->total_length);
+		total_length2 = rte_ntohs(hdr2->total_length);
+		total_length3 = rte_ntohs(hdr3->total_length);
+	} else {
+		struct ipv6_hdr *hdr0 = ip0;
+		struct ipv6_hdr *hdr1 = ip1;
+		struct ipv6_hdr *hdr2 = ip2;
+		struct ipv6_hdr *hdr3 = ip3;
+
+		dscp0 = (rte_ntohl(hdr0->vtc_flow) & 0x0F600000) >> 18;
+		dscp1 = (rte_ntohl(hdr1->vtc_flow) & 0x0F600000) >> 18;
+		dscp2 = (rte_ntohl(hdr2->vtc_flow) & 0x0F600000) >> 18;
+		dscp3 = (rte_ntohl(hdr3->vtc_flow) & 0x0F600000) >> 18;
+
+		total_length0 =
+			rte_ntohs(hdr0->payload_len) + sizeof(struct ipv6_hdr);
+		total_length1 =
+			rte_ntohs(hdr1->payload_len) + sizeof(struct ipv6_hdr);
+		total_length2 =
+			rte_ntohs(hdr2->payload_len) + sizeof(struct ipv6_hdr);
+		total_length3 =
+			rte_ntohs(hdr3->payload_len) + sizeof(struct ipv6_hdr);
+	}
+
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) {
+		void *data0 =
+			action_data_get(table_entry0, action, RTE_TABLE_ACTION_MTR);
+		void *data1 =
+			action_data_get(table_entry1, action, RTE_TABLE_ACTION_MTR);
+		void *data2 =
+			action_data_get(table_entry2, action, RTE_TABLE_ACTION_MTR);
+		void *data3 =
+			action_data_get(table_entry3, action, RTE_TABLE_ACTION_MTR);
+
+		drop_mask0 |= pkt_work_mtr(mbuf0,
+			data0,
+			&action->dscp_table,
+			action->mp,
+			time,
+			dscp0,
+			total_length0);
+
+		drop_mask1 |= pkt_work_mtr(mbuf1,
+			data1,
+			&action->dscp_table,
+			action->mp,
+			time,
+			dscp1,
+			total_length1);
+
+		drop_mask2 |= pkt_work_mtr(mbuf2,
+			data2,
+			&action->dscp_table,
+			action->mp,
+			time,
+			dscp2,
+			total_length2);
+
+		drop_mask3 |= pkt_work_mtr(mbuf3,
+			data3,
+			&action->dscp_table,
+			action->mp,
+			time,
+			dscp3,
+			total_length3);
+	}
+
+	return drop_mask0 |
+		(drop_mask1 << 1) |
+		(drop_mask2 << 2) |
+		(drop_mask3 << 3);
+}
+
 static __rte_always_inline int
 ah(struct rte_pipeline *p,
 	struct rte_mbuf **pkts,
@@ -298,6 +903,9 @@ ah(struct rte_pipeline *p,
 	uint64_t pkts_drop_mask = 0;
 	uint64_t time = 0;
 
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_MTR))
+		time = rte_rdtsc();
+
 	if ((pkts_mask & (pkts_mask + 1)) == 0) {
 		uint64_t n_pkts = __builtin_popcountll(pkts_mask);
 		uint32_t i;
diff --git a/lib/librte_pipeline/rte_table_action.h b/lib/librte_pipeline/rte_table_action.h
index 03b77ca..c2f4a55 100644
--- a/lib/librte_pipeline/rte_table_action.h
+++ b/lib/librte_pipeline/rte_table_action.h
@@ -59,6 +59,7 @@ extern "C" {
 #include <stdint.h>
 
 #include <rte_compat.h>
+#include <rte_meter.h>
 
 #include "rte_pipeline.h"
 
@@ -66,6 +67,9 @@ extern "C" {
 enum rte_table_action_type {
 	/** Forward to next pipeline table, output port or drop. */
 	RTE_TABLE_ACTION_FWD = 0,
+
+	/**  Traffic Metering and Policing. */
+	RTE_TABLE_ACTION_MTR,
 };
 
 /** Common action configuration (per table action profile). */
@@ -94,6 +98,164 @@ struct rte_table_action_fwd_params {
 };
 
 /**
+ * RTE_TABLE_ACTION_MTR
+ */
+/** Max number of traffic classes (TCs). */
+#define RTE_TABLE_ACTION_TC_MAX                                  4
+
+/** Max number of queues per traffic class. */
+#define RTE_TABLE_ACTION_TC_QUEUE_MAX                            4
+
+/** Differentiated Services Code Point (DSCP) translation table entry. */
+struct rte_table_action_dscp_table_entry {
+	/** Traffic class. Used by the meter or the traffic management actions.
+	 * Has to be strictly smaller than *RTE_TABLE_ACTION_TC_MAX*. Traffic
+	 * class 0 is the highest priority.
+	 */
+	uint32_t tc_id;
+
+	/** Traffic class queue. Used by the traffic management action. Has to
+	 * be strictly smaller than *RTE_TABLE_ACTION_TC_QUEUE_MAX*.
+	 */
+	uint32_t tc_queue_id;
+
+	/** Packet color. Used by the meter action as the packet input color
+	 * for the color aware mode of the traffic metering algorithm.
+	 */
+	enum rte_meter_color color;
+};
+
+/** DSCP translation table. */
+struct rte_table_action_dscp_table {
+	/** Array of DSCP table entries */
+	struct rte_table_action_dscp_table_entry entry[64];
+};
+
+/** Supported traffic metering algorithms. */
+enum rte_table_action_meter_algorithm {
+	/** Single Rate Three Color Marker (srTCM) - IETF RFC 2697. */
+	RTE_TABLE_ACTION_METER_SRTCM,
+
+	/** Two Rate Three Color Marker (trTCM) - IETF RFC 2698. */
+	RTE_TABLE_ACTION_METER_TRTCM,
+};
+
+/** Traffic metering profile (configuration template). */
+struct rte_table_action_meter_profile {
+	/** Traffic metering algorithm. */
+	enum rte_table_action_meter_algorithm alg;
+
+	RTE_STD_C11
+	union {
+		/** Only valid when *alg* is set to srTCM - IETF RFC 2697. */
+		struct rte_meter_srtcm_params srtcm;
+
+		/** Only valid when *alg* is set to trTCM - IETF RFC 2698. */
+		struct rte_meter_trtcm_params trtcm;
+	};
+};
+
+/** Policer actions. */
+enum rte_table_action_policer {
+	/** Recolor the packet as green. */
+	RTE_TABLE_ACTION_POLICER_COLOR_GREEN = 0,
+
+	/** Recolor the packet as yellow. */
+	RTE_TABLE_ACTION_POLICER_COLOR_YELLOW,
+
+	/** Recolor the packet as red. */
+	RTE_TABLE_ACTION_POLICER_COLOR_RED,
+
+	/** Drop the packet. */
+	RTE_TABLE_ACTION_POLICER_DROP,
+
+	/** Number of policer actions. */
+	RTE_TABLE_ACTION_POLICER_MAX
+};
+
+/** Meter action configuration per traffic class. */
+struct rte_table_action_mtr_tc_params {
+	/** Meter profile ID. */
+	uint32_t meter_profile_id;
+
+	/** Policer actions. */
+	enum rte_table_action_policer policer[e_RTE_METER_COLORS];
+};
+
+/** Meter action statistics counters per traffic class. */
+struct rte_table_action_mtr_counters_tc {
+	/** Number of packets per color at the output of the traffic metering
+	 * and before the policer actions are executed. Only valid when
+	 * *n_packets_valid* is non-zero.
+	 */
+	uint64_t n_packets[e_RTE_METER_COLORS];
+
+	/** Number of packet bytes per color at the output of the traffic
+	 * metering and before the policer actions are executed. Only valid when
+	 * *n_bytes_valid* is non-zero.
+	 */
+	uint64_t n_bytes[e_RTE_METER_COLORS];
+
+	/** When non-zero, the *n_packets* field is valid. */
+	int n_packets_valid;
+
+	/** When non-zero, the *n_bytes* field is valid. */
+	int n_bytes_valid;
+};
+
+/** Meter action configuration (per table action profile). */
+struct rte_table_action_mtr_config {
+	/** Meter algorithm. */
+	enum rte_table_action_meter_algorithm alg;
+
+	/** Number of traffic classes. Each traffic class has its own traffic
+	 * meter and policer instances. Needs to be equal to either 1 or to
+	 * *RTE_TABLE_ACTION_TC_MAX*.
+	 */
+	uint32_t n_tc;
+
+	/** When non-zero, the *n_packets* meter stats counter is enabled,
+	 * otherwise it is disabled.
+	 *
+	 * @see struct rte_table_action_mtr_counters_tc
+	 */
+	int n_packets_enabled;
+
+	/** When non-zero, the *n_bytes* meter stats counter is enabled,
+	 * otherwise it is disabled.
+	 *
+	 * @see struct rte_table_action_mtr_counters_tc
+	 */
+	int n_bytes_enabled;
+};
+
+/** Meter action parameters (per table rule). */
+struct rte_table_action_mtr_params {
+	/** Traffic meter and policer parameters for each of the *tc_mask*
+	 * traffic classes.
+	 */
+	struct rte_table_action_mtr_tc_params mtr[RTE_TABLE_ACTION_TC_MAX];
+
+	/** Bit mask defining which traffic class parameters are valid in *mtr*.
+	 * If bit N is set in *tc_mask*, then parameters for traffic class N are
+	 * valid in *mtr*.
+	 */
+	uint32_t tc_mask;
+};
+
+/** Meter action statistics counters (per table rule). */
+struct rte_table_action_mtr_counters {
+	/** Stats counters for each of the *tc_mask* traffic classes. */
+	struct rte_table_action_mtr_counters_tc stats[RTE_TABLE_ACTION_TC_MAX];
+
+	/** Bit mask defining which traffic class parameters are valid in *mtr*.
+	 * If bit N is set in *tc_mask*, then parameters for traffic class N are
+	 * valid in *mtr*.
+	 */
+	uint32_t tc_mask;
+};
+
+/**
  * Table action profile.
  */
 struct rte_table_action_profile;
@@ -231,6 +393,92 @@ rte_table_action_apply(struct rte_table_action *action,
 	enum rte_table_action_type type,
 	void *action_params);
 
+/**
+ * Table action DSCP table update.
+ *
+ * @param[in] action
+ *   Handle to table action object (needs to be valid).
+ * @param[in] dscp_mask
+ *   64-bit mask defining the DSCP table entries to be updated. If bit N is set
+ *   in this bit mask, then DSCP table entry N is to be updated, otherwise not.
+ * @param[in] table
+ *   DSCP table.
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_table_action_dscp_table_update(struct rte_table_action *action,
+	uint64_t dscp_mask,
+	struct rte_table_action_dscp_table *table);
+
+/**
+ * Table action meter profile add.
+ *
+ * @param[in] action
+ *   Handle to table action object (needs to be valid).
+ * @param[in] meter_profile_id
+ *   Meter profile ID to be used for the *profile* once it is successfully added
+ *   to the *action* object (needs to be unused by the set of meter profiles
+ *   currently registered for the *action* object).
+ * @param[in] profile
+ *   Meter profile to be added.
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_table_action_meter_profile_add(struct rte_table_action *action,
+	uint32_t meter_profile_id,
+	struct rte_table_action_meter_profile *profile);
+
+/**
+ * Table action meter profile delete.
+ *
+ * @param[in] action
+ *   Handle to table action object (needs to be valid).
+ * @param[in] meter_profile_id
+ *   Meter profile ID of the meter profile to be deleted from the *action*
+ *   object (needs to be valid for the *action* object).
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_table_action_meter_profile_delete(struct rte_table_action *action,
+	uint32_t meter_profile_id);
+
+/**
+ * Table action meter read.
+ *
+ * @param[in] action
+ *   Handle to table action object (needs to be valid).
+ * @param[in] data
+ *   Data byte array (typically table rule data) with meter action previously
+ *   applied on it.
+ * @param[in] tc_mask
+ *   Bit mask defining which traffic classes should have the meter stats
+ *   counters read from *data* and stored into *stats*. If bit N is set in this
+ *   bit mask, then traffic class N is part of this operation, otherwise it is
+ *   not. If bit N is set in this bit mask, then traffic class N must be one of
+ *   the traffic classes that are enabled for the meter action in the table
+ *   action profile used by the *action* object.
+ * @param[inout] stats
+ *   When non-NULL, it points to the area where the meter stats counters read
+ *   from *data* are saved. Only the meter stats counters for the *tc_mask*
+ *   traffic classes are read and stored to *stats*.
+ * @param[in] clear
+ *   When non-zero, the meter stats counters are cleared (i.e. set to zero),
+ *   otherwise the counters are not modified. When the read operation is enabled
+ *   (*stats* is non-NULL), the clear operation is performed after the read
+ *   operation is completed.
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_table_action_meter_read(struct rte_table_action *action,
+	void *data,
+	uint32_t tc_mask,
+	struct rte_table_action_mtr_counters *stats,
+	int clear);
+
 #ifdef __cplusplus
 }
 #endif
-- 
2.9.3

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

* [dpdk-dev] [PATCH v3 04/44] pipeline: add traffic manager action
  2018-03-16 17:58       ` [dpdk-dev] [PATCH v3 00/44] ip_pipeline: refactoring Jasvinder Singh
                           ` (2 preceding siblings ...)
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 03/44] pipeline: add traffic metering action Jasvinder Singh
@ 2018-03-16 17:58         ` Jasvinder Singh
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 05/44] pipeline: add packet encapsulation action Jasvinder Singh
                           ` (39 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-16 17:58 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add implementation of traffic manager action.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 lib/librte_pipeline/Makefile           |   2 +-
 lib/librte_pipeline/meson.build        |   2 +-
 lib/librte_pipeline/rte_table_action.c | 130 ++++++++++++++++++++++++++++++++-
 lib/librte_pipeline/rte_table_action.h |  24 ++++++
 4 files changed, 155 insertions(+), 3 deletions(-)

diff --git a/lib/librte_pipeline/Makefile b/lib/librte_pipeline/Makefile
index 72e4c7c..c0eaa09 100644
--- a/lib/librte_pipeline/Makefile
+++ b/lib/librte_pipeline/Makefile
@@ -12,7 +12,7 @@ CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
 LDLIBS += -lrte_eal -lrte_mempool -lrte_mbuf -lrte_table
-LDLIBS += -lrte_port -lrte_meter
+LDLIBS += -lrte_port -lrte_meter -lrte_sched
 
 EXPORT_MAP := rte_pipeline_version.map
 
diff --git a/lib/librte_pipeline/meson.build b/lib/librte_pipeline/meson.build
index 71da295..1ee276f 100644
--- a/lib/librte_pipeline/meson.build
+++ b/lib/librte_pipeline/meson.build
@@ -5,4 +5,4 @@ version = 3
 allow_experimental_apis = true
 sources = files('rte_pipeline.c', 'rte_table_action.c')
 headers = files('rte_pipeline.h', 'rte_table_action.h')
-deps += ['port', 'table', 'meter']
+deps += ['port', 'table', 'meter', 'sched']
diff --git a/lib/librte_pipeline/rte_table_action.c b/lib/librte_pipeline/rte_table_action.c
index f3be28a..791fc20 100644
--- a/lib/librte_pipeline/rte_table_action.c
+++ b/lib/librte_pipeline/rte_table_action.c
@@ -297,6 +297,73 @@ pkt_work_mtr(struct rte_mbuf *mbuf,
 	return drop_mask;
 }
 
+/**
+ * RTE_TABLE_ACTION_TM
+ */
+static int
+tm_cfg_check(struct rte_table_action_tm_config *tm)
+{
+	if ((tm->n_subports_per_port == 0) ||
+		(rte_is_power_of_2(tm->n_subports_per_port) == 0) ||
+		(tm->n_subports_per_port > UINT16_MAX) ||
+		(tm->n_pipes_per_subport == 0) ||
+		(rte_is_power_of_2(tm->n_pipes_per_subport) == 0))
+		return -ENOTSUP;
+
+	return 0;
+}
+
+struct tm_data {
+	uint16_t queue_tc_color;
+	uint16_t subport;
+	uint32_t pipe;
+} __attribute__((__packed__));
+
+static int
+tm_apply_check(struct rte_table_action_tm_params *p,
+	struct rte_table_action_tm_config *cfg)
+{
+	if ((p->subport_id >= cfg->n_subports_per_port) ||
+		(p->pipe_id >= cfg->n_pipes_per_subport))
+		return -EINVAL;
+
+	return 0;
+}
+
+static int
+tm_apply(struct tm_data *data,
+	struct rte_table_action_tm_params *p,
+	struct rte_table_action_tm_config *cfg)
+{
+	int status;
+
+	/* Check input arguments */
+	status = tm_apply_check(p, cfg);
+	if (status)
+		return status;
+
+	/* Apply */
+	data->queue_tc_color = 0;
+	data->subport = (uint16_t) p->subport_id;
+	data->pipe = p->pipe_id;
+
+	return 0;
+}
+
+static __rte_always_inline void
+pkt_work_tm(struct rte_mbuf *mbuf,
+	struct tm_data *data,
+	struct dscp_table_data *dscp_table,
+	uint32_t dscp)
+{
+	struct dscp_table_entry_data *dscp_entry = &dscp_table->entry[dscp];
+	struct tm_data *sched_ptr = (struct tm_data *) &mbuf->hash.sched;
+	struct tm_data sched;
+
+	sched = *data;
+	sched.queue_tc_color = dscp_entry->queue_tc_color;
+	*sched_ptr = sched;
+}
 
 /**
  * Action profile
@@ -307,6 +374,7 @@ action_valid(enum rte_table_action_type action)
 	switch (action) {
 	case RTE_TABLE_ACTION_FWD:
 	case RTE_TABLE_ACTION_MTR:
+	case RTE_TABLE_ACTION_TM:
 		return 1;
 	default:
 		return 0;
@@ -320,6 +388,7 @@ struct ap_config {
 	uint64_t action_mask;
 	struct rte_table_action_common_config common;
 	struct rte_table_action_mtr_config mtr;
+	struct rte_table_action_tm_config tm;
 };
 
 static size_t
@@ -328,6 +397,8 @@ action_cfg_size(enum rte_table_action_type action)
 	switch (action) {
 	case RTE_TABLE_ACTION_MTR:
 		return sizeof(struct rte_table_action_mtr_config);
+	case RTE_TABLE_ACTION_TM:
+		return sizeof(struct rte_table_action_tm_config);
 	default:
 		return 0;
 	}
@@ -341,6 +412,9 @@ action_cfg_get(struct ap_config *ap_config,
 	case RTE_TABLE_ACTION_MTR:
 		return &ap_config->mtr;
 
+	case RTE_TABLE_ACTION_TM:
+		return &ap_config->tm;
+
 	default:
 		return NULL;
 	}
@@ -375,6 +449,9 @@ action_data_size(enum rte_table_action_type action,
 	case RTE_TABLE_ACTION_MTR:
 		return mtr_data_size(&ap_config->mtr);
 
+	case RTE_TABLE_ACTION_TM:
+		return sizeof(struct tm_data);
+
 	default:
 		return 0;
 	}
@@ -450,6 +527,10 @@ rte_table_action_profile_action_register(struct rte_table_action_profile *profil
 		status = mtr_cfg_check(action_config);
 		break;
 
+	case RTE_TABLE_ACTION_TM:
+		status = tm_cfg_check(action_config);
+		break;
+
 	default:
 		status = 0;
 		break;
@@ -567,6 +648,11 @@ rte_table_action_apply(struct rte_table_action *action,
 			action->mp,
 			RTE_DIM(action->mp));
 
+	case RTE_TABLE_ACTION_TM:
+		return tm_apply(action_data,
+			action_params,
+			&action->cfg.tm);
+
 	default:
 		return -EINVAL;
 	}
@@ -581,7 +667,8 @@ rte_table_action_dscp_table_update(struct rte_table_action *action,
 
 	/* Check input arguments */
 	if ((action == NULL) ||
-		(action->cfg.action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) ||
+		((action->cfg.action_mask & ((1LLU << RTE_TABLE_ACTION_MTR) |
+		(1LLU << RTE_TABLE_ACTION_TM))) == 0) ||
 		(dscp_mask == 0) ||
 		(table == NULL))
 		return -EINVAL;
@@ -773,6 +860,16 @@ pkt_work(struct rte_mbuf *mbuf,
 			total_length);
 	}
 
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_TM)) {
+		void *data =
+			action_data_get(table_entry, action, RTE_TABLE_ACTION_TM);
+
+		pkt_work_tm(mbuf,
+			data,
+			&action->dscp_table,
+			dscp);
+	}
+
 	return drop_mask;
 }
 
@@ -886,6 +983,37 @@ pkt4_work(struct rte_mbuf **mbufs,
 			total_length3);
 	}
 
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_TM)) {
+		void *data0 =
+			action_data_get(table_entry0, action, RTE_TABLE_ACTION_TM);
+		void *data1 =
+			action_data_get(table_entry1, action, RTE_TABLE_ACTION_TM);
+		void *data2 =
+			action_data_get(table_entry2, action, RTE_TABLE_ACTION_TM);
+		void *data3 =
+			action_data_get(table_entry3, action, RTE_TABLE_ACTION_TM);
+
+		pkt_work_tm(mbuf0,
+			data0,
+			&action->dscp_table,
+			dscp0);
+
+		pkt_work_tm(mbuf1,
+			data1,
+			&action->dscp_table,
+			dscp1);
+
+		pkt_work_tm(mbuf2,
+			data2,
+			&action->dscp_table,
+			dscp2);
+
+		pkt_work_tm(mbuf3,
+			data3,
+			&action->dscp_table,
+			dscp3);
+	}
+
 	return drop_mask0 |
 		(drop_mask1 << 1) |
 		(drop_mask2 << 2) |
diff --git a/lib/librte_pipeline/rte_table_action.h b/lib/librte_pipeline/rte_table_action.h
index c2f4a55..98babc5 100644
--- a/lib/librte_pipeline/rte_table_action.h
+++ b/lib/librte_pipeline/rte_table_action.h
@@ -70,6 +70,9 @@ enum rte_table_action_type {
 
 	/**  Traffic Metering and Policing. */
 	RTE_TABLE_ACTION_MTR,
+
+	/**  Traffic Management. */
+	RTE_TABLE_ACTION_TM,
 };
 
 /** Common action configuration (per table action profile). */
@@ -256,6 +259,27 @@ struct rte_table_action_mtr_counters {
 };
 
 /**
+ * RTE_TABLE_ACTION_TM
+ */
+/** Traffic management action configuration (per table action profile). */
+struct rte_table_action_tm_config {
+	/** Number of subports per port. */
+	uint32_t n_subports_per_port;
+
+	/** Number of pipes per subport. */
+	uint32_t n_pipes_per_subport;
+};
+
+/** Traffic management action parameters (per table rule). */
+struct rte_table_action_tm_params {
+	/** Subport ID. */
+	uint32_t subport_id;
+
+	/** Pipe ID. */
+	uint32_t pipe_id;
+};
+
+/**
  * Table action profile.
  */
 struct rte_table_action_profile;
-- 
2.9.3

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

* [dpdk-dev] [PATCH v3 05/44] pipeline: add packet encapsulation action
  2018-03-16 17:58       ` [dpdk-dev] [PATCH v3 00/44] ip_pipeline: refactoring Jasvinder Singh
                           ` (3 preceding siblings ...)
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 04/44] pipeline: add traffic manager action Jasvinder Singh
@ 2018-03-16 17:58         ` Jasvinder Singh
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 06/44] pipeline: add nat action Jasvinder Singh
                           ` (38 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-16 17:58 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add implementation of different type of packet encap
such as vlan, qinq, mpls, pppoe, etc.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 lib/librte_pipeline/rte_table_action.c | 440 ++++++++++++++++++++++++++++++++-
 lib/librte_pipeline/rte_table_action.h | 129 ++++++++++
 2 files changed, 568 insertions(+), 1 deletion(-)

diff --git a/lib/librte_pipeline/rte_table_action.c b/lib/librte_pipeline/rte_table_action.c
index 791fc20..fa528d8 100644
--- a/lib/librte_pipeline/rte_table_action.c
+++ b/lib/librte_pipeline/rte_table_action.c
@@ -9,8 +9,12 @@
 #include <rte_byteorder.h>
 #include <rte_cycles.h>
 #include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_ether.h>
 #include <rte_ip.h>
-
+#include <rte_esp.h>
+#include <rte_tcp.h>
+#include <rte_udp.h>
 
 #include "rte_table_action.h"
 
@@ -366,6 +370,369 @@ pkt_work_tm(struct rte_mbuf *mbuf,
 }
 
 /**
+ * RTE_TABLE_ACTION_ENCAP
+ */
+static int
+encap_valid(enum rte_table_action_encap_type encap)
+{
+	switch (encap) {
+	case RTE_TABLE_ACTION_ENCAP_ETHER:
+	case RTE_TABLE_ACTION_ENCAP_VLAN:
+	case RTE_TABLE_ACTION_ENCAP_QINQ:
+	case RTE_TABLE_ACTION_ENCAP_MPLS:
+	case RTE_TABLE_ACTION_ENCAP_PPPOE:
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+static int
+encap_cfg_check(struct rte_table_action_encap_config *encap)
+{
+	if ((encap->encap_mask == 0) ||
+		(__builtin_popcountll(encap->encap_mask) != 1))
+		return -ENOTSUP;
+
+	return 0;
+}
+
+struct encap_ether_data {
+	struct ether_hdr ether;
+} __attribute__((__packed__));
+
+#define VLAN(pcp, dei, vid)                                \
+	((uint16_t)((((uint64_t)(pcp)) & 0x7LLU) << 13) |  \
+	((((uint64_t)(dei)) & 0x1LLU) << 12) |             \
+	(((uint64_t)(vid)) & 0xFFFLLU))                    \
+
+struct encap_vlan_data {
+	struct ether_hdr ether;
+	struct vlan_hdr vlan;
+} __attribute__((__packed__));
+
+struct encap_qinq_data {
+	struct ether_hdr ether;
+	struct vlan_hdr svlan;
+	struct vlan_hdr cvlan;
+} __attribute__((__packed__));
+
+#define ETHER_TYPE_MPLS_UNICAST                            0x8847
+
+#define ETHER_TYPE_MPLS_MULTICAST                          0x8848
+
+#define MPLS(label, tc, s, ttl)                            \
+	((uint32_t)(((((uint64_t)(label)) & 0xFFFFFLLU) << 12) |\
+	((((uint64_t)(tc)) & 0x7LLU) << 9) |               \
+	((((uint64_t)(s)) & 0x1LLU) << 8) |                \
+	(((uint64_t)(ttl)) & 0xFFLLU)))
+
+struct encap_mpls_data {
+	struct ether_hdr ether;
+	uint32_t mpls[RTE_TABLE_ACTION_MPLS_LABELS_MAX];
+	uint32_t mpls_count;
+} __attribute__((__packed__));
+
+#define ETHER_TYPE_PPPOE_SESSION                           0x8864
+
+#define PPP_PROTOCOL_IP                                    0x0021
+
+struct pppoe_ppp_hdr {
+	uint16_t ver_type_code;
+	uint16_t session_id;
+	uint16_t length;
+	uint16_t protocol;
+} __attribute__((__packed__));
+
+struct encap_pppoe_data {
+	struct ether_hdr ether;
+	struct pppoe_ppp_hdr pppoe_ppp;
+} __attribute__((__packed__));
+
+static size_t
+encap_data_size(struct rte_table_action_encap_config *encap)
+{
+	switch (encap->encap_mask) {
+	case 1LLU << RTE_TABLE_ACTION_ENCAP_ETHER:
+		return sizeof(struct encap_ether_data);
+
+	case 1LLU << RTE_TABLE_ACTION_ENCAP_VLAN:
+		return sizeof(struct encap_vlan_data);
+
+	case 1LLU << RTE_TABLE_ACTION_ENCAP_QINQ:
+		return sizeof(struct encap_qinq_data);
+
+	case 1LLU << RTE_TABLE_ACTION_ENCAP_MPLS:
+		return sizeof(struct encap_mpls_data);
+
+	case 1LLU << RTE_TABLE_ACTION_ENCAP_PPPOE:
+		return sizeof(struct encap_pppoe_data);
+
+	default:
+		return 0;
+	}
+}
+
+static int
+encap_apply_check(struct rte_table_action_encap_params *p,
+	struct rte_table_action_encap_config *cfg)
+{
+	if ((encap_valid(p->type) == 0) ||
+		((cfg->encap_mask & (1LLU << p->type)) == 0))
+		return -EINVAL;
+
+	switch (p->type) {
+	case RTE_TABLE_ACTION_ENCAP_ETHER:
+		return 0;
+
+	case RTE_TABLE_ACTION_ENCAP_VLAN:
+		return 0;
+
+	case RTE_TABLE_ACTION_ENCAP_QINQ:
+		return 0;
+
+	case RTE_TABLE_ACTION_ENCAP_MPLS:
+		if ((p->mpls.mpls_count == 0) ||
+			(p->mpls.mpls_count > RTE_TABLE_ACTION_MPLS_LABELS_MAX))
+			return -EINVAL;
+
+		return 0;
+
+	case RTE_TABLE_ACTION_ENCAP_PPPOE:
+		return 0;
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static int
+encap_ether_apply(void *data,
+	struct rte_table_action_encap_params *p,
+	struct rte_table_action_common_config *common_cfg)
+{
+	struct encap_ether_data *d = data;
+	uint16_t ethertype = (common_cfg->ip_version) ?
+		ETHER_TYPE_IPv4 :
+		ETHER_TYPE_IPv6;
+
+	/* Ethernet */
+	ether_addr_copy(&p->ether.ether.da, &d->ether.d_addr);
+	ether_addr_copy(&p->ether.ether.sa, &d->ether.s_addr);
+	d->ether.ether_type = rte_htons(ethertype);
+
+	return 0;
+}
+
+static int
+encap_vlan_apply(void *data,
+	struct rte_table_action_encap_params *p,
+	struct rte_table_action_common_config *common_cfg)
+{
+	struct encap_vlan_data *d = data;
+	uint16_t ethertype = (common_cfg->ip_version) ?
+		ETHER_TYPE_IPv4 :
+		ETHER_TYPE_IPv6;
+
+	/* Ethernet */
+	ether_addr_copy(&p->vlan.ether.da, &d->ether.d_addr);
+	ether_addr_copy(&p->vlan.ether.sa, &d->ether.s_addr);
+	d->ether.ether_type = rte_htons(ETHER_TYPE_VLAN);
+
+	/* VLAN */
+	d->vlan.vlan_tci = rte_htons(VLAN(p->vlan.vlan.pcp,
+		p->vlan.vlan.dei,
+		p->vlan.vlan.vid));
+	d->vlan.eth_proto = rte_htons(ethertype);
+
+	return 0;
+}
+
+static int
+encap_qinq_apply(void *data,
+	struct rte_table_action_encap_params *p,
+	struct rte_table_action_common_config *common_cfg)
+{
+	struct encap_qinq_data *d = data;
+	uint16_t ethertype = (common_cfg->ip_version) ?
+		ETHER_TYPE_IPv4 :
+		ETHER_TYPE_IPv6;
+
+	/* Ethernet */
+	ether_addr_copy(&p->qinq.ether.da, &d->ether.d_addr);
+	ether_addr_copy(&p->qinq.ether.sa, &d->ether.s_addr);
+	d->ether.ether_type = rte_htons(ETHER_TYPE_QINQ);
+
+	/* SVLAN */
+	d->svlan.vlan_tci = rte_htons(VLAN(p->qinq.svlan.pcp,
+		p->qinq.svlan.dei,
+		p->qinq.svlan.vid));
+	d->svlan.eth_proto = rte_htons(ETHER_TYPE_VLAN);
+
+	/* CVLAN */
+	d->cvlan.vlan_tci = rte_htons(VLAN(p->qinq.cvlan.pcp,
+		p->qinq.cvlan.dei,
+		p->qinq.cvlan.vid));
+	d->cvlan.eth_proto = rte_htons(ethertype);
+
+	return 0;
+}
+
+static int
+encap_mpls_apply(void *data,
+	struct rte_table_action_encap_params *p)
+{
+	struct encap_mpls_data *d = data;
+	uint16_t ethertype = (p->mpls.unicast) ?
+		ETHER_TYPE_MPLS_UNICAST :
+		ETHER_TYPE_MPLS_MULTICAST;
+	uint32_t i;
+
+	/* Ethernet */
+	ether_addr_copy(&p->mpls.ether.da, &d->ether.d_addr);
+	ether_addr_copy(&p->mpls.ether.sa, &d->ether.s_addr);
+	d->ether.ether_type = rte_htons(ethertype);
+
+	/* MPLS */
+	for (i = 0; i < p->mpls.mpls_count - 1; i++)
+		d->mpls[i] = rte_htonl(MPLS(p->mpls.mpls[i].label,
+			p->mpls.mpls[i].tc,
+			0,
+			p->mpls.mpls[i].ttl));
+
+	d->mpls[i] = rte_htonl(MPLS(p->mpls.mpls[i].label,
+		p->mpls.mpls[i].tc,
+		1,
+		p->mpls.mpls[i].ttl));
+
+	d->mpls_count = p->mpls.mpls_count;
+	return 0;
+}
+
+static int
+encap_pppoe_apply(void *data,
+	struct rte_table_action_encap_params *p)
+{
+	struct encap_pppoe_data *d = data;
+
+	/* Ethernet */
+	ether_addr_copy(&p->pppoe.ether.da, &d->ether.d_addr);
+	ether_addr_copy(&p->pppoe.ether.sa, &d->ether.s_addr);
+	d->ether.ether_type = rte_htons(ETHER_TYPE_PPPOE_SESSION);
+
+	/* PPPoE and PPP*/
+	d->pppoe_ppp.ver_type_code = rte_htons(0x1100);
+	d->pppoe_ppp.session_id = rte_htons(p->pppoe.pppoe.session_id);
+	d->pppoe_ppp.length = 0; /* not pre-computed */
+	d->pppoe_ppp.protocol = rte_htons(PPP_PROTOCOL_IP);
+
+	return 0;
+}
+
+static int
+encap_apply(void *data,
+	struct rte_table_action_encap_params *p,
+	struct rte_table_action_encap_config *cfg,
+	struct rte_table_action_common_config *common_cfg)
+{
+	int status;
+
+	/* Check input arguments */
+	status = encap_apply_check(p, cfg);
+	if (status)
+		return status;
+
+	switch (p->type) {
+	case RTE_TABLE_ACTION_ENCAP_ETHER:
+		return encap_ether_apply(data, p, common_cfg);
+
+	case RTE_TABLE_ACTION_ENCAP_VLAN:
+		return encap_vlan_apply(data, p, common_cfg);
+
+	case RTE_TABLE_ACTION_ENCAP_QINQ:
+		return encap_qinq_apply(data, p, common_cfg);
+
+	case RTE_TABLE_ACTION_ENCAP_MPLS:
+		return encap_mpls_apply(data, p);
+
+	case RTE_TABLE_ACTION_ENCAP_PPPOE:
+		return encap_pppoe_apply(data, p);
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static __rte_always_inline void *
+encap(void *dst, const void *src, size_t n)
+{
+	dst = ((uint8_t *) dst) - n;
+	return rte_memcpy(dst, src, n);
+}
+
+static __rte_always_inline void
+pkt_work_encap(struct rte_mbuf *mbuf,
+	void *data,
+	struct rte_table_action_encap_config *cfg,
+	void *ip,
+	uint16_t total_length,
+	uint32_t ip_offset)
+{
+	switch (cfg->encap_mask) {
+	case 1LLU << RTE_TABLE_ACTION_ENCAP_ETHER:
+		encap(ip, data, sizeof(struct encap_ether_data));
+		mbuf->data_off = ip_offset - (sizeof(struct rte_mbuf) +
+			sizeof(struct encap_ether_data));
+		mbuf->pkt_len = mbuf->data_len = total_length +
+			sizeof(struct encap_ether_data);
+		break;
+
+	case 1LLU << RTE_TABLE_ACTION_ENCAP_VLAN:
+		encap(ip, data, sizeof(struct encap_vlan_data));
+		mbuf->data_off = ip_offset - (sizeof(struct rte_mbuf) +
+			sizeof(struct encap_vlan_data));
+		mbuf->pkt_len = mbuf->data_len = total_length +
+			sizeof(struct encap_vlan_data);
+		break;
+
+	case 1LLU << RTE_TABLE_ACTION_ENCAP_QINQ:
+		encap(ip, data, sizeof(struct encap_qinq_data));
+		mbuf->data_off = ip_offset - (sizeof(struct rte_mbuf) +
+			sizeof(struct encap_qinq_data));
+		mbuf->pkt_len = mbuf->data_len = total_length +
+			sizeof(struct encap_qinq_data);
+		break;
+
+	case 1LLU << RTE_TABLE_ACTION_ENCAP_MPLS:
+	{
+		struct encap_mpls_data *mpls = data;
+		size_t size = sizeof(struct ether_hdr) +
+			mpls->mpls_count * 4;
+
+		encap(ip, data, size);
+		mbuf->data_off = ip_offset - (sizeof(struct rte_mbuf) + size);
+		mbuf->pkt_len = mbuf->data_len = total_length + size;
+		break;
+	}
+
+	case 1LLU << RTE_TABLE_ACTION_ENCAP_PPPOE:
+	{
+		struct encap_pppoe_data *pppoe =
+			encap(ip, data, sizeof(struct encap_pppoe_data));
+		pppoe->pppoe_ppp.length = rte_htons(total_length + 2);
+		mbuf->data_off = ip_offset - (sizeof(struct rte_mbuf) +
+			sizeof(struct encap_pppoe_data));
+		mbuf->pkt_len = mbuf->data_len = total_length +
+			sizeof(struct encap_pppoe_data);
+		break;
+	}
+
+	default:
+		break;
+	}
+}
+
+/**
  * Action profile
  */
 static int
@@ -375,6 +742,7 @@ action_valid(enum rte_table_action_type action)
 	case RTE_TABLE_ACTION_FWD:
 	case RTE_TABLE_ACTION_MTR:
 	case RTE_TABLE_ACTION_TM:
+	case RTE_TABLE_ACTION_ENCAP:
 		return 1;
 	default:
 		return 0;
@@ -389,6 +757,7 @@ struct ap_config {
 	struct rte_table_action_common_config common;
 	struct rte_table_action_mtr_config mtr;
 	struct rte_table_action_tm_config tm;
+	struct rte_table_action_encap_config encap;
 };
 
 static size_t
@@ -399,6 +768,8 @@ action_cfg_size(enum rte_table_action_type action)
 		return sizeof(struct rte_table_action_mtr_config);
 	case RTE_TABLE_ACTION_TM:
 		return sizeof(struct rte_table_action_tm_config);
+	case RTE_TABLE_ACTION_ENCAP:
+		return sizeof(struct rte_table_action_encap_config);
 	default:
 		return 0;
 	}
@@ -415,6 +786,9 @@ action_cfg_get(struct ap_config *ap_config,
 	case RTE_TABLE_ACTION_TM:
 		return &ap_config->tm;
 
+	case RTE_TABLE_ACTION_ENCAP:
+		return &ap_config->encap;
+
 	default:
 		return NULL;
 	}
@@ -452,6 +826,9 @@ action_data_size(enum rte_table_action_type action,
 	case RTE_TABLE_ACTION_TM:
 		return sizeof(struct tm_data);
 
+	case RTE_TABLE_ACTION_ENCAP:
+		return encap_data_size(&ap_config->encap);
+
 	default:
 		return 0;
 	}
@@ -531,6 +908,10 @@ rte_table_action_profile_action_register(struct rte_table_action_profile *profil
 		status = tm_cfg_check(action_config);
 		break;
 
+	case RTE_TABLE_ACTION_ENCAP:
+		status = encap_cfg_check(action_config);
+		break;
+
 	default:
 		status = 0;
 		break;
@@ -653,6 +1034,12 @@ rte_table_action_apply(struct rte_table_action *action,
 			action_params,
 			&action->cfg.tm);
 
+	case RTE_TABLE_ACTION_ENCAP:
+		return encap_apply(action_data,
+			action_params,
+			&action->cfg.encap,
+			&action->cfg.common);
+
 	default:
 		return -EINVAL;
 	}
@@ -870,6 +1257,18 @@ pkt_work(struct rte_mbuf *mbuf,
 			dscp);
 	}
 
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_ENCAP)) {
+		void *data =
+			action_data_get(table_entry, action, RTE_TABLE_ACTION_ENCAP);
+
+		pkt_work_encap(mbuf,
+			data,
+			&cfg->encap,
+			ip,
+			total_length,
+			ip_offset);
+	}
+
 	return drop_mask;
 }
 
@@ -1014,6 +1413,45 @@ pkt4_work(struct rte_mbuf **mbufs,
 			dscp3);
 	}
 
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_ENCAP)) {
+		void *data0 =
+			action_data_get(table_entry0, action, RTE_TABLE_ACTION_ENCAP);
+		void *data1 =
+			action_data_get(table_entry1, action, RTE_TABLE_ACTION_ENCAP);
+		void *data2 =
+			action_data_get(table_entry2, action, RTE_TABLE_ACTION_ENCAP);
+		void *data3 =
+			action_data_get(table_entry3, action, RTE_TABLE_ACTION_ENCAP);
+
+		pkt_work_encap(mbuf0,
+			data0,
+			&cfg->encap,
+			ip0,
+			total_length0,
+			ip_offset);
+
+		pkt_work_encap(mbuf1,
+			data1,
+			&cfg->encap,
+			ip1,
+			total_length1,
+			ip_offset);
+
+		pkt_work_encap(mbuf2,
+			data2,
+			&cfg->encap,
+			ip2,
+			total_length2,
+			ip_offset);
+
+		pkt_work_encap(mbuf3,
+			data3,
+			&cfg->encap,
+			ip3,
+			total_length3,
+			ip_offset);
+	}
+
 	return drop_mask0 |
 		(drop_mask1 << 1) |
 		(drop_mask2 << 2) |
diff --git a/lib/librte_pipeline/rte_table_action.h b/lib/librte_pipeline/rte_table_action.h
index 98babc5..c5c987d 100644
--- a/lib/librte_pipeline/rte_table_action.h
+++ b/lib/librte_pipeline/rte_table_action.h
@@ -59,6 +59,7 @@ extern "C" {
 #include <stdint.h>
 
 #include <rte_compat.h>
+#include <rte_ether.h>
 #include <rte_meter.h>
 
 #include "rte_pipeline.h"
@@ -73,6 +74,9 @@ enum rte_table_action_type {
 
 	/**  Traffic Management. */
 	RTE_TABLE_ACTION_TM,
+
+	/** Packet encapsulations. */
+	RTE_TABLE_ACTION_ENCAP,
 };
 
 /** Common action configuration (per table action profile). */
@@ -280,6 +284,131 @@ struct rte_table_action_tm_params {
 };
 
 /**
+ * RTE_TABLE_ACTION_ENCAP
+ */
+/** Supported packet encapsulation types. */
+enum rte_table_action_encap_type {
+	/** IP -> { Ether | IP } */
+	RTE_TABLE_ACTION_ENCAP_ETHER = 0,
+
+	/** IP -> { Ether | VLAN | IP } */
+	RTE_TABLE_ACTION_ENCAP_VLAN,
+
+	/** IP -> { Ether | S-VLAN | C-VLAN | IP } */
+	RTE_TABLE_ACTION_ENCAP_QINQ,
+
+	/** IP -> { Ether | MPLS | IP } */
+	RTE_TABLE_ACTION_ENCAP_MPLS,
+
+	/** IP -> { Ether | PPPoE | PPP | IP } */
+	RTE_TABLE_ACTION_ENCAP_PPPOE,
+};
+
+/** Pre-computed Ethernet header fields for encapsulation action. */
+struct rte_table_action_ether_hdr {
+	struct ether_addr da; /**< Destination address. */
+	struct ether_addr sa; /**< Source address. */
+};
+
+/** Pre-computed VLAN header fields for encapsulation action. */
+struct rte_table_action_vlan_hdr {
+	uint8_t pcp; /**< Priority Code Point (PCP). */
+	uint8_t dei; /**< Drop Eligibility Indicator (DEI). */
+	uint16_t vid; /**< VLAN Identifier (VID). */
+};
+
+/** Pre-computed MPLS header fields for encapsulation action. */
+struct rte_table_action_mpls_hdr {
+	uint32_t label; /**< Label. */
+	uint8_t tc; /**< Traffic Class (TC). */
+	uint8_t ttl; /**< Time to Live (TTL). */
+};
+
+/** Pre-computed PPPoE header fields for encapsulation action. */
+struct rte_table_action_pppoe_hdr {
+	uint16_t session_id; /**< Session ID. */
+};
+
+/** Ether encap parameters. */
+struct rte_table_action_encap_ether_params {
+	struct rte_table_action_ether_hdr ether; /**< Ethernet header. */
+};
+
+/** VLAN encap parameters. */
+struct rte_table_action_encap_vlan_params {
+	struct rte_table_action_ether_hdr ether; /**< Ethernet header. */
+	struct rte_table_action_vlan_hdr vlan; /**< VLAN header. */
+};
+
+/** QinQ encap parameters. */
+struct rte_table_action_encap_qinq_params {
+	struct rte_table_action_ether_hdr ether; /**< Ethernet header. */
+	struct rte_table_action_vlan_hdr svlan; /**< Service VLAN header. */
+	struct rte_table_action_vlan_hdr cvlan; /**< Customer VLAN header. */
+};
+
+/** Max number of MPLS labels per output packet for MPLS encapsulation. */
+#ifndef RTE_TABLE_ACTION_MPLS_LABELS_MAX
+#define RTE_TABLE_ACTION_MPLS_LABELS_MAX                   4
+#endif
+
+/** MPLS encap parameters. */
+struct rte_table_action_encap_mpls_params {
+	/** Ethernet header. */
+	struct rte_table_action_ether_hdr ether;
+
+	/** MPLS header. */
+	struct rte_table_action_mpls_hdr mpls[RTE_TABLE_ACTION_MPLS_LABELS_MAX];
+
+	/** Number of MPLS labels in MPLS header. */
+	uint32_t mpls_count;
+
+	/** Non-zero for MPLS unicast, zero for MPLS multicast. */
+	int unicast;
+};
+
+/** PPPoE encap parameters. */
+struct rte_table_action_encap_pppoe_params {
+	struct rte_table_action_ether_hdr ether; /**< Ethernet header. */
+	struct rte_table_action_pppoe_hdr pppoe; /**< PPPoE/PPP headers. */
+};
+
+/** Encap action configuration (per table action profile). */
+struct rte_table_action_encap_config {
+	/** Bit mask defining the set of packet encapsulations enabled for the
+	 * current table action profile. If bit (1 << N) is set in *encap_mask*,
+	 * then packet encapsulation N is enabled, otherwise it is disabled.
+	 *
+	 * @see enum rte_table_action_encap_type
+	 */
+	uint64_t encap_mask;
+};
+
+/** Encap action parameters (per table rule). */
+struct rte_table_action_encap_params {
+	/** Encapsulation type. */
+	enum rte_table_action_encap_type type;
+
+	RTE_STD_C11
+	union {
+		/** Only valid when *type* is set to Ether. */
+		struct rte_table_action_encap_ether_params ether;
+
+		/** Only valid when *type* is set to VLAN. */
+		struct rte_table_action_encap_vlan_params vlan;
+
+		/** Only valid when *type* is set to QinQ. */
+		struct rte_table_action_encap_qinq_params qinq;
+
+		/** Only valid when *type* is set to MPLS. */
+		struct rte_table_action_encap_mpls_params mpls;
+
+		/** Only valid when *type* is set to PPPoE. */
+		struct rte_table_action_encap_pppoe_params pppoe;
+	};
+};
+
+/**
  * Table action profile.
  */
 struct rte_table_action_profile;
-- 
2.9.3

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

* [dpdk-dev] [PATCH v3 06/44] pipeline: add nat action
  2018-03-16 17:58       ` [dpdk-dev] [PATCH v3 00/44] ip_pipeline: refactoring Jasvinder Singh
                           ` (4 preceding siblings ...)
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 05/44] pipeline: add packet encapsulation action Jasvinder Singh
@ 2018-03-16 17:58         ` Jasvinder Singh
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 07/44] pipeline: add ttl update action Jasvinder Singh
                           ` (37 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-16 17:58 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add implementation of Network Address Translation(NAT) action.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 lib/librte_pipeline/rte_table_action.c | 351 +++++++++++++++++++++++++++++++++
 lib/librte_pipeline/rte_table_action.h |  39 ++++
 2 files changed, 390 insertions(+)

diff --git a/lib/librte_pipeline/rte_table_action.c b/lib/librte_pipeline/rte_table_action.c
index fa528d8..d22493a 100644
--- a/lib/librte_pipeline/rte_table_action.c
+++ b/lib/librte_pipeline/rte_table_action.c
@@ -733,6 +733,304 @@ pkt_work_encap(struct rte_mbuf *mbuf,
 }
 
 /**
+ * RTE_TABLE_ACTION_NAT
+ */
+static int
+nat_cfg_check(struct rte_table_action_nat_config *nat)
+{
+	if ((nat->proto != 0x06) &&
+		(nat->proto != 0x11))
+		return -ENOTSUP;
+
+	return 0;
+}
+
+struct nat_ipv4_data {
+	uint32_t addr;
+	uint16_t port;
+} __attribute__((__packed__));
+
+struct nat_ipv6_data {
+	uint8_t addr[16];
+	uint16_t port;
+} __attribute__((__packed__));
+
+static size_t
+nat_data_size(struct rte_table_action_nat_config *nat __rte_unused,
+	struct rte_table_action_common_config *common)
+{
+	int ip_version = common->ip_version;
+
+	return (ip_version) ?
+		sizeof(struct nat_ipv4_data) :
+		sizeof(struct nat_ipv6_data);
+}
+
+static int
+nat_apply_check(struct rte_table_action_nat_params *p,
+	struct rte_table_action_common_config *cfg)
+{
+	if ((p->ip_version && (cfg->ip_version == 0)) ||
+		((p->ip_version == 0) && cfg->ip_version))
+		return -EINVAL;
+
+	return 0;
+}
+
+static int
+nat_apply(void *data,
+	struct rte_table_action_nat_params *p,
+	struct rte_table_action_common_config *cfg)
+{
+	int status;
+
+	/* Check input arguments */
+	status = nat_apply_check(p, cfg);
+	if (status)
+		return status;
+
+	/* Apply */
+	if (p->ip_version) {
+		struct nat_ipv4_data *d = data;
+
+		d->addr = rte_htonl(p->addr.ipv4);
+		d->port = rte_htons(p->port);
+	} else {
+		struct nat_ipv6_data *d = data;
+
+		memcpy(d->addr, p->addr.ipv6, sizeof(d->addr));
+		d->port = rte_htons(p->port);
+	}
+
+	return 0;
+}
+
+static __rte_always_inline uint16_t
+nat_ipv4_checksum_update(uint16_t cksum0,
+	uint32_t ip0,
+	uint32_t ip1)
+{
+	int32_t cksum1;
+
+	cksum1 = cksum0;
+	cksum1 = ~cksum1 & 0xFFFF;
+
+	/* Subtract ip0 (one's complement logic) */
+	cksum1 -= (ip0 >> 16) + (ip0 & 0xFFFF);
+	cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
+	cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
+
+	/* Add ip1 (one's complement logic) */
+	cksum1 += (ip1 >> 16) + (ip1 & 0xFFFF);
+	cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
+	cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
+
+	return (uint16_t)(~cksum1);
+}
+
+static __rte_always_inline uint16_t
+nat_ipv4_tcp_udp_checksum_update(uint16_t cksum0,
+	uint32_t ip0,
+	uint32_t ip1,
+	uint16_t port0,
+	uint16_t port1)
+{
+	int32_t cksum1;
+
+	cksum1 = cksum0;
+	cksum1 = ~cksum1 & 0xFFFF;
+
+	/* Subtract ip0 and port 0 (one's complement logic) */
+	cksum1 -= (ip0 >> 16) + (ip0 & 0xFFFF) + port0;
+	cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
+	cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
+
+	/* Add ip1 and port1 (one's complement logic) */
+	cksum1 += (ip1 >> 16) + (ip1 & 0xFFFF) + port1;
+	cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
+	cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
+
+	return (uint16_t)(~cksum1);
+}
+
+static __rte_always_inline uint16_t
+nat_ipv6_tcp_udp_checksum_update(uint16_t cksum0,
+	uint16_t *ip0,
+	uint16_t *ip1,
+	uint16_t port0,
+	uint16_t port1)
+{
+	int32_t cksum1;
+
+	cksum1 = cksum0;
+	cksum1 = ~cksum1 & 0xFFFF;
+
+	/* Subtract ip0 and port 0 (one's complement logic) */
+	cksum1 -= ip0[0] + ip0[1] + ip0[2] + ip0[3] +
+		ip0[4] + ip0[5] + ip0[6] + ip0[7] + port0;
+	cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
+	cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
+
+	/* Add ip1 and port1 (one's complement logic) */
+	cksum1 += ip1[0] + ip1[1] + ip1[2] + ip1[3] +
+		ip1[4] + ip1[5] + ip1[6] + ip1[7] + port1;
+	cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
+	cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
+
+	return (uint16_t)(~cksum1);
+}
+
+static __rte_always_inline void
+pkt_ipv4_work_nat(struct ipv4_hdr *ip,
+	struct nat_ipv4_data *data,
+	struct rte_table_action_nat_config *cfg)
+{
+	if (cfg->source_nat) {
+		if (cfg->proto == 0x6) {
+			struct tcp_hdr *tcp = (struct tcp_hdr *) &ip[1];
+			uint16_t ip_cksum, tcp_cksum;
+
+			ip_cksum = nat_ipv4_checksum_update(ip->hdr_checksum,
+				ip->src_addr,
+				data->addr);
+
+			tcp_cksum = nat_ipv4_tcp_udp_checksum_update(tcp->cksum,
+				ip->src_addr,
+				data->addr,
+				tcp->src_port,
+				data->port);
+
+			ip->src_addr = data->addr;
+			ip->hdr_checksum = ip_cksum;
+			tcp->src_port = data->port;
+			tcp->cksum = tcp_cksum;
+		} else {
+			struct udp_hdr *udp = (struct udp_hdr *) &ip[1];
+			uint16_t ip_cksum, udp_cksum;
+
+			ip_cksum = nat_ipv4_checksum_update(ip->hdr_checksum,
+				ip->src_addr,
+				data->addr);
+
+			udp_cksum = nat_ipv4_tcp_udp_checksum_update(udp->dgram_cksum,
+				ip->src_addr,
+				data->addr,
+				udp->src_port,
+				data->port);
+
+			ip->src_addr = data->addr;
+			ip->hdr_checksum = ip_cksum;
+			udp->src_port = data->port;
+			if (udp->dgram_cksum)
+				udp->dgram_cksum = udp_cksum;
+		}
+	} else {
+		if (cfg->proto == 0x6) {
+			struct tcp_hdr *tcp = (struct tcp_hdr *) &ip[1];
+			uint16_t ip_cksum, tcp_cksum;
+
+			ip_cksum = nat_ipv4_checksum_update(ip->hdr_checksum,
+				ip->dst_addr,
+				data->addr);
+
+			tcp_cksum = nat_ipv4_tcp_udp_checksum_update(tcp->cksum,
+				ip->dst_addr,
+				data->addr,
+				tcp->dst_port,
+				data->port);
+
+			ip->dst_addr = data->addr;
+			ip->hdr_checksum = ip_cksum;
+			tcp->dst_port = data->port;
+			tcp->cksum = tcp_cksum;
+		} else {
+			struct udp_hdr *udp = (struct udp_hdr *) &ip[1];
+			uint16_t ip_cksum, udp_cksum;
+
+			ip_cksum = nat_ipv4_checksum_update(ip->hdr_checksum,
+				ip->dst_addr,
+				data->addr);
+
+			udp_cksum = nat_ipv4_tcp_udp_checksum_update(udp->dgram_cksum,
+				ip->dst_addr,
+				data->addr,
+				udp->dst_port,
+				data->port);
+
+			ip->dst_addr = data->addr;
+			ip->hdr_checksum = ip_cksum;
+			udp->dst_port = data->port;
+			if (udp->dgram_cksum)
+				udp->dgram_cksum = udp_cksum;
+		}
+	}
+}
+
+static __rte_always_inline void
+pkt_ipv6_work_nat(struct ipv6_hdr *ip,
+	struct nat_ipv6_data *data,
+	struct rte_table_action_nat_config *cfg)
+{
+	if (cfg->source_nat) {
+		if (cfg->proto == 0x6) {
+			struct tcp_hdr *tcp = (struct tcp_hdr *) &ip[1];
+			uint16_t tcp_cksum;
+
+			tcp_cksum = nat_ipv6_tcp_udp_checksum_update(tcp->cksum,
+				(uint16_t *)ip->src_addr,
+				(uint16_t *)data->addr,
+				tcp->src_port,
+				data->port);
+
+			rte_memcpy(ip->src_addr, data->addr, 16);
+			tcp->src_port = data->port;
+			tcp->cksum = tcp_cksum;
+		} else {
+			struct udp_hdr *udp = (struct udp_hdr *) &ip[1];
+			uint16_t udp_cksum;
+
+			udp_cksum = nat_ipv6_tcp_udp_checksum_update(udp->dgram_cksum,
+				(uint16_t *)ip->src_addr,
+				(uint16_t *)data->addr,
+				udp->src_port,
+				data->port);
+
+			rte_memcpy(ip->src_addr, data->addr, 16);
+			udp->src_port = data->port;
+			udp->dgram_cksum = udp_cksum;
+		}
+	} else {
+		if (cfg->proto == 0x6) {
+			struct tcp_hdr *tcp = (struct tcp_hdr *) &ip[1];
+			uint16_t tcp_cksum;
+
+			tcp_cksum = nat_ipv6_tcp_udp_checksum_update(tcp->cksum,
+				(uint16_t *)ip->dst_addr,
+				(uint16_t *)data->addr,
+				tcp->dst_port,
+				data->port);
+
+			rte_memcpy(ip->dst_addr, data->addr, 16);
+			tcp->dst_port = data->port;
+			tcp->cksum = tcp_cksum;
+		} else {
+			struct udp_hdr *udp = (struct udp_hdr *) &ip[1];
+			uint16_t udp_cksum;
+
+			udp_cksum = nat_ipv6_tcp_udp_checksum_update(udp->dgram_cksum,
+				(uint16_t *)ip->dst_addr,
+				(uint16_t *)data->addr,
+				udp->dst_port,
+				data->port);
+
+			rte_memcpy(ip->dst_addr, data->addr, 16);
+			udp->dst_port = data->port;
+			udp->dgram_cksum = udp_cksum;
+		}
+	}
+}
+
+/**
  * Action profile
  */
 static int
@@ -743,6 +1041,7 @@ action_valid(enum rte_table_action_type action)
 	case RTE_TABLE_ACTION_MTR:
 	case RTE_TABLE_ACTION_TM:
 	case RTE_TABLE_ACTION_ENCAP:
+	case RTE_TABLE_ACTION_NAT:
 		return 1;
 	default:
 		return 0;
@@ -758,6 +1057,7 @@ struct ap_config {
 	struct rte_table_action_mtr_config mtr;
 	struct rte_table_action_tm_config tm;
 	struct rte_table_action_encap_config encap;
+	struct rte_table_action_nat_config nat;
 };
 
 static size_t
@@ -770,6 +1070,8 @@ action_cfg_size(enum rte_table_action_type action)
 		return sizeof(struct rte_table_action_tm_config);
 	case RTE_TABLE_ACTION_ENCAP:
 		return sizeof(struct rte_table_action_encap_config);
+	case RTE_TABLE_ACTION_NAT:
+		return sizeof(struct rte_table_action_nat_config);
 	default:
 		return 0;
 	}
@@ -789,6 +1091,9 @@ action_cfg_get(struct ap_config *ap_config,
 	case RTE_TABLE_ACTION_ENCAP:
 		return &ap_config->encap;
 
+	case RTE_TABLE_ACTION_NAT:
+		return &ap_config->nat;
+
 	default:
 		return NULL;
 	}
@@ -829,6 +1134,10 @@ action_data_size(enum rte_table_action_type action,
 	case RTE_TABLE_ACTION_ENCAP:
 		return encap_data_size(&ap_config->encap);
 
+	case RTE_TABLE_ACTION_NAT:
+		return nat_data_size(&ap_config->nat,
+			&ap_config->common);
+
 	default:
 		return 0;
 	}
@@ -912,6 +1221,10 @@ rte_table_action_profile_action_register(struct rte_table_action_profile *profil
 		status = encap_cfg_check(action_config);
 		break;
 
+	case RTE_TABLE_ACTION_NAT:
+		status = nat_cfg_check(action_config);
+		break;
+
 	default:
 		status = 0;
 		break;
@@ -1040,6 +1353,11 @@ rte_table_action_apply(struct rte_table_action *action,
 			&action->cfg.encap,
 			&action->cfg.common);
 
+	case RTE_TABLE_ACTION_NAT:
+		return nat_apply(action_data,
+			action_params,
+			&action->cfg.common);
+
 	default:
 		return -EINVAL;
 	}
@@ -1269,6 +1587,16 @@ pkt_work(struct rte_mbuf *mbuf,
 			ip_offset);
 	}
 
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_NAT)) {
+		void *data =
+			action_data_get(table_entry, action, RTE_TABLE_ACTION_NAT);
+
+		if (cfg->common.ip_version)
+			pkt_ipv4_work_nat(ip, data, &cfg->nat);
+		else
+			pkt_ipv6_work_nat(ip, data, &cfg->nat);
+	}
+
 	return drop_mask;
 }
 
@@ -1452,6 +1780,29 @@ pkt4_work(struct rte_mbuf **mbufs,
 			ip_offset);
 	}
 
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_NAT)) {
+		void *data0 =
+			action_data_get(table_entry0, action, RTE_TABLE_ACTION_NAT);
+		void *data1 =
+			action_data_get(table_entry1, action, RTE_TABLE_ACTION_NAT);
+		void *data2 =
+			action_data_get(table_entry2, action, RTE_TABLE_ACTION_NAT);
+		void *data3 =
+			action_data_get(table_entry3, action, RTE_TABLE_ACTION_NAT);
+
+		if (cfg->common.ip_version) {
+			pkt_ipv4_work_nat(ip0, data0, &cfg->nat);
+			pkt_ipv4_work_nat(ip1, data1, &cfg->nat);
+			pkt_ipv4_work_nat(ip2, data2, &cfg->nat);
+			pkt_ipv4_work_nat(ip3, data3, &cfg->nat);
+		} else {
+			pkt_ipv6_work_nat(ip0, data0, &cfg->nat);
+			pkt_ipv6_work_nat(ip1, data1, &cfg->nat);
+			pkt_ipv6_work_nat(ip2, data2, &cfg->nat);
+			pkt_ipv6_work_nat(ip3, data3, &cfg->nat);
+		}
+	}
+
 	return drop_mask0 |
 		(drop_mask1 << 1) |
 		(drop_mask2 << 2) |
diff --git a/lib/librte_pipeline/rte_table_action.h b/lib/librte_pipeline/rte_table_action.h
index c5c987d..5204511 100644
--- a/lib/librte_pipeline/rte_table_action.h
+++ b/lib/librte_pipeline/rte_table_action.h
@@ -77,6 +77,9 @@ enum rte_table_action_type {
 
 	/** Packet encapsulations. */
 	RTE_TABLE_ACTION_ENCAP,
+
+	/** Network Address Translation (NAT). */
+	RTE_TABLE_ACTION_NAT,
 };
 
 /** Common action configuration (per table action profile). */
@@ -409,6 +412,42 @@ struct rte_table_action_encap_params {
 };
 
 /**
+ * RTE_TABLE_ACTION_NAT
+ */
+/** NAT action configuration (per table action profile). */
+struct rte_table_action_nat_config {
+	/** When non-zero, the IP source address and L4 protocol source port are
+	 * translated. When zero, the IP destination address and L4 protocol
+	 * destination port are translated.
+	 */
+	int source_nat;
+
+	/** Layer 4 protocol, for example TCP (0x06) or UDP (0x11). The checksum
+	 * field is computed differently and placed at different header offset
+	 * by each layer 4 protocol.
+	 */
+	uint8_t proto;
+};
+
+/** NAT action parameters (per table rule). */
+struct rte_table_action_nat_params {
+	/** IP version for *addr*: non-zero for IPv4, zero for IPv6. */
+	int ip_version;
+
+	/** IP address. */
+	union {
+		/** IPv4 address; only valid when *ip_version* is non-zero. */
+		uint32_t ipv4;
+
+		/** IPv6 address; only valid when *ip_version* is set to 0. */
+		uint8_t ipv6[16];
+	} addr;
+
+	/** Port. */
+	uint16_t port;
+};
+
+/**
  * Table action profile.
  */
 struct rte_table_action_profile;
-- 
2.9.3

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

* [dpdk-dev] [PATCH v3 07/44] pipeline: add ttl update action
  2018-03-16 17:58       ` [dpdk-dev] [PATCH v3 00/44] ip_pipeline: refactoring Jasvinder Singh
                           ` (5 preceding siblings ...)
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 06/44] pipeline: add nat action Jasvinder Singh
@ 2018-03-16 17:58         ` Jasvinder Singh
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 08/44] pipeline: add statistics read action Jasvinder Singh
                           ` (36 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-16 17:58 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add implementation of ttl update action.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 lib/librte_pipeline/rte_pipeline_version.map |   1 +
 lib/librte_pipeline/rte_table_action.c       | 162 +++++++++++++++++++++++++++
 lib/librte_pipeline/rte_table_action.h       |  66 +++++++++++
 3 files changed, 229 insertions(+)

diff --git a/lib/librte_pipeline/rte_pipeline_version.map b/lib/librte_pipeline/rte_pipeline_version.map
index c7106dc..9388585 100644
--- a/lib/librte_pipeline/rte_pipeline_version.map
+++ b/lib/librte_pipeline/rte_pipeline_version.map
@@ -61,5 +61,6 @@ EXPERIMENTAL {
 	rte_table_action_profile_free;
 	rte_table_action_profile_freeze;
 	rte_table_action_table_params_get;
+	rte_table_action_ttl_read;
 
 } DPDK_16.04;
diff --git a/lib/librte_pipeline/rte_table_action.c b/lib/librte_pipeline/rte_table_action.c
index d22493a..c77bfb7 100644
--- a/lib/librte_pipeline/rte_table_action.c
+++ b/lib/librte_pipeline/rte_table_action.c
@@ -1031,6 +1031,89 @@ pkt_ipv6_work_nat(struct ipv6_hdr *ip,
 }
 
 /**
+ * RTE_TABLE_ACTION_TTL
+ */
+static int
+ttl_cfg_check(struct rte_table_action_ttl_config *ttl)
+{
+	if (ttl->drop == 0)
+		return -ENOTSUP;
+
+	return 0;
+}
+
+struct ttl_data {
+	uint32_t n_packets;
+} __attribute__((__packed__));
+
+#define TTL_INIT(data, decrement)                         \
+	((data)->n_packets = (decrement) ? 1 : 0)
+
+#define TTL_DEC_GET(data)                                  \
+	((uint8_t)((data)->n_packets & 1))
+
+#define TTL_STATS_RESET(data)                             \
+	((data)->n_packets = ((data)->n_packets & 1))
+
+#define TTL_STATS_READ(data)                               \
+	((data)->n_packets >> 1)
+
+#define TTL_STATS_ADD(data, value)                        \
+	((data)->n_packets =                                  \
+		(((((data)->n_packets >> 1) + (value)) << 1) |    \
+		((data)->n_packets & 1)))
+
+static int
+ttl_apply(void *data,
+	struct rte_table_action_ttl_params *p)
+{
+	struct ttl_data *d = data;
+
+	TTL_INIT(d, p->decrement);
+
+	return 0;
+}
+
+static __rte_always_inline uint64_t
+pkt_ipv4_work_ttl(struct ipv4_hdr *ip,
+	struct ttl_data *data)
+{
+	uint32_t drop;
+	uint16_t cksum = ip->hdr_checksum;
+	uint8_t ttl = ip->time_to_live;
+	uint8_t ttl_diff = TTL_DEC_GET(data);
+
+	cksum += ttl_diff;
+	ttl -= ttl_diff;
+
+	ip->hdr_checksum = cksum;
+	ip->time_to_live = ttl;
+
+	drop = (ttl == 0) ? 1 : 0;
+	TTL_STATS_ADD(data, drop);
+
+	return drop;
+}
+
+static __rte_always_inline uint64_t
+pkt_ipv6_work_ttl(struct ipv6_hdr *ip,
+	struct ttl_data *data)
+{
+	uint32_t drop;
+	uint8_t ttl = ip->hop_limits;
+	uint8_t ttl_diff = TTL_DEC_GET(data);
+
+	ttl -= ttl_diff;
+
+	ip->hop_limits = ttl;
+
+	drop = (ttl == 0) ? 1 : 0;
+	TTL_STATS_ADD(data, drop);
+
+	return drop;
+}
+
+/**
  * Action profile
  */
 static int
@@ -1042,6 +1125,7 @@ action_valid(enum rte_table_action_type action)
 	case RTE_TABLE_ACTION_TM:
 	case RTE_TABLE_ACTION_ENCAP:
 	case RTE_TABLE_ACTION_NAT:
+	case RTE_TABLE_ACTION_TTL:
 		return 1;
 	default:
 		return 0;
@@ -1058,6 +1142,7 @@ struct ap_config {
 	struct rte_table_action_tm_config tm;
 	struct rte_table_action_encap_config encap;
 	struct rte_table_action_nat_config nat;
+	struct rte_table_action_ttl_config ttl;
 };
 
 static size_t
@@ -1072,6 +1157,8 @@ action_cfg_size(enum rte_table_action_type action)
 		return sizeof(struct rte_table_action_encap_config);
 	case RTE_TABLE_ACTION_NAT:
 		return sizeof(struct rte_table_action_nat_config);
+	case RTE_TABLE_ACTION_TTL:
+		return sizeof(struct rte_table_action_ttl_config);
 	default:
 		return 0;
 	}
@@ -1094,6 +1181,9 @@ action_cfg_get(struct ap_config *ap_config,
 	case RTE_TABLE_ACTION_NAT:
 		return &ap_config->nat;
 
+	case RTE_TABLE_ACTION_TTL:
+		return &ap_config->ttl;
+
 	default:
 		return NULL;
 	}
@@ -1138,6 +1228,9 @@ action_data_size(enum rte_table_action_type action,
 		return nat_data_size(&ap_config->nat,
 			&ap_config->common);
 
+	case RTE_TABLE_ACTION_TTL:
+		return sizeof(struct ttl_data);
+
 	default:
 		return 0;
 	}
@@ -1225,6 +1318,10 @@ rte_table_action_profile_action_register(struct rte_table_action_profile *profil
 		status = nat_cfg_check(action_config);
 		break;
 
+	case RTE_TABLE_ACTION_TTL:
+		status = ttl_cfg_check(action_config);
+		break;
+
 	default:
 		status = 0;
 		break;
@@ -1358,6 +1455,10 @@ rte_table_action_apply(struct rte_table_action *action,
 			action_params,
 			&action->cfg.common);
 
+	case RTE_TABLE_ACTION_TTL:
+		return ttl_apply(action_data,
+			action_params);
+
 	default:
 		return -EINVAL;
 	}
@@ -1524,6 +1625,34 @@ rte_table_action_meter_read(struct rte_table_action *action,
 	return 0;
 }
 
+int
+rte_table_action_ttl_read(struct rte_table_action *action,
+	void *data,
+	struct rte_table_action_ttl_counters *stats,
+	int clear)
+{
+	struct ttl_data *ttl_data;
+
+	/* Check input arguments */
+	if ((action == NULL) ||
+		((action->cfg.action_mask &
+		(1LLU << RTE_TABLE_ACTION_TTL)) == 0) ||
+		(data == NULL))
+		return -EINVAL;
+
+	ttl_data = action_data_get(data, action, RTE_TABLE_ACTION_TTL);
+
+	/* Read */
+	if (stats)
+		stats->n_packets = TTL_STATS_READ(ttl_data);
+
+	/* Clear */
+	if (clear)
+		TTL_STATS_RESET(ttl_data);
+
+	return 0;
+}
+
 static __rte_always_inline uint64_t
 pkt_work(struct rte_mbuf *mbuf,
 	struct rte_pipeline_table_entry *table_entry,
@@ -1597,6 +1726,16 @@ pkt_work(struct rte_mbuf *mbuf,
 			pkt_ipv6_work_nat(ip, data, &cfg->nat);
 	}
 
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_TTL)) {
+		void *data =
+			action_data_get(table_entry, action, RTE_TABLE_ACTION_TTL);
+
+		if (cfg->common.ip_version)
+			drop_mask |= pkt_ipv4_work_ttl(ip, data);
+		else
+			drop_mask |= pkt_ipv6_work_ttl(ip, data);
+	}
+
 	return drop_mask;
 }
 
@@ -1803,6 +1942,29 @@ pkt4_work(struct rte_mbuf **mbufs,
 		}
 	}
 
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_TTL)) {
+		void *data0 =
+			action_data_get(table_entry0, action, RTE_TABLE_ACTION_TTL);
+		void *data1 =
+			action_data_get(table_entry1, action, RTE_TABLE_ACTION_TTL);
+		void *data2 =
+			action_data_get(table_entry2, action, RTE_TABLE_ACTION_TTL);
+		void *data3 =
+			action_data_get(table_entry3, action, RTE_TABLE_ACTION_TTL);
+
+		if (cfg->common.ip_version) {
+			drop_mask0 |= pkt_ipv4_work_ttl(ip0, data0);
+			drop_mask1 |= pkt_ipv4_work_ttl(ip1, data1);
+			drop_mask2 |= pkt_ipv4_work_ttl(ip2, data2);
+			drop_mask3 |= pkt_ipv4_work_ttl(ip3, data3);
+		} else {
+			drop_mask0 |= pkt_ipv6_work_ttl(ip0, data0);
+			drop_mask1 |= pkt_ipv6_work_ttl(ip1, data1);
+			drop_mask2 |= pkt_ipv6_work_ttl(ip2, data2);
+			drop_mask3 |= pkt_ipv6_work_ttl(ip3, data3);
+		}
+	}
+
 	return drop_mask0 |
 		(drop_mask1 << 1) |
 		(drop_mask2 << 2) |
diff --git a/lib/librte_pipeline/rte_table_action.h b/lib/librte_pipeline/rte_table_action.h
index 5204511..57ac4f9 100644
--- a/lib/librte_pipeline/rte_table_action.h
+++ b/lib/librte_pipeline/rte_table_action.h
@@ -80,6 +80,9 @@ enum rte_table_action_type {
 
 	/** Network Address Translation (NAT). */
 	RTE_TABLE_ACTION_NAT,
+
+	/** Time to Live (TTL) update. */
+	RTE_TABLE_ACTION_TTL,
 };
 
 /** Common action configuration (per table action profile). */
@@ -448,6 +451,44 @@ struct rte_table_action_nat_params {
 };
 
 /**
+ * RTE_TABLE_ACTION_TTL
+ */
+/** TTL action configuration (per table action profile). */
+struct rte_table_action_ttl_config {
+	/** When non-zero, the input packets whose updated IPv4 Time to Live
+	 * (TTL) field or IPv6 Hop Limit (HL) field is zero are dropped.
+	 * When zero, the input packets whose updated IPv4 TTL field or IPv6 HL
+	 * field is zero are forwarded as usual (typically for debugging
+	 * purpose).
+	 */
+	int drop;
+
+	/** When non-zero, the *n_packets* stats counter for TTL action is
+	 * enabled, otherwise disabled.
+	 *
+	 * @see struct rte_table_action_ttl_counters
+	 */
+	int n_packets_enabled;
+};
+
+/** TTL action parameters (per table rule). */
+struct rte_table_action_ttl_params {
+	/** When non-zero, decrement the IPv4 TTL field and update the checksum
+	 * field, or decrement the IPv6 HL field. When zero, the IPv4 TTL field
+	 * or the IPv6 HL field is not changed.
+	 */
+	int decrement;
+};
+
+/** TTL action statistics packets (per table rule). */
+struct rte_table_action_ttl_counters {
+	/** Number of IPv4 packets whose updated TTL field is zero or IPv6
+	 * packets whose updated HL field is zero.
+	 */
+	uint64_t n_packets;
+};
+
+/**
  * Table action profile.
  */
 struct rte_table_action_profile;
@@ -671,6 +712,31 @@ rte_table_action_meter_read(struct rte_table_action *action,
 	struct rte_table_action_mtr_counters *stats,
 	int clear);
 
+/**
+ * Table action TTL read.
+ *
+ * @param[in] action
+ *   Handle to table action object (needs to be valid).
+ * @param[in] data
+ *   Data byte array (typically table rule data) with TTL action previously
+ *   applied on it.
+ * @param[inout] stats
+ *   When non-NULL, it points to the area where the TTL stats counters read from
+ *   *data* are saved.
+ * @param[in] clear
+ *   When non-zero, the TTL stats counters are cleared (i.e. set to zero),
+ *   otherwise the counters are not modified. When the read operation is enabled
+ *   (*stats* is non-NULL), the clear operation is performed after the read
+ *   operation is completed.
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_table_action_ttl_read(struct rte_table_action *action,
+	void *data,
+	struct rte_table_action_ttl_counters *stats,
+	int clear);
+
 #ifdef __cplusplus
 }
 #endif
-- 
2.9.3

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

* [dpdk-dev] [PATCH v3 08/44] pipeline: add statistics read action
  2018-03-16 17:58       ` [dpdk-dev] [PATCH v3 00/44] ip_pipeline: refactoring Jasvinder Singh
                           ` (6 preceding siblings ...)
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 07/44] pipeline: add ttl update action Jasvinder Singh
@ 2018-03-16 17:58         ` Jasvinder Singh
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 09/44] pipeline: add timestamp action Jasvinder Singh
                           ` (35 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-16 17:58 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add implementation of stats read action

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 lib/librte_pipeline/rte_pipeline_version.map |   1 +
 lib/librte_pipeline/rte_table_action.c       | 111 +++++++++++++++++++++++++++
 lib/librte_pipeline/rte_table_action.h       |  78 +++++++++++++++++++
 3 files changed, 190 insertions(+)

diff --git a/lib/librte_pipeline/rte_pipeline_version.map b/lib/librte_pipeline/rte_pipeline_version.map
index 9388585..8241efc 100644
--- a/lib/librte_pipeline/rte_pipeline_version.map
+++ b/lib/librte_pipeline/rte_pipeline_version.map
@@ -61,6 +61,7 @@ EXPERIMENTAL {
 	rte_table_action_profile_free;
 	rte_table_action_profile_freeze;
 	rte_table_action_table_params_get;
+	rte_table_action_stats_read;
 	rte_table_action_ttl_read;
 
 } DPDK_16.04;
diff --git a/lib/librte_pipeline/rte_table_action.c b/lib/librte_pipeline/rte_table_action.c
index c77bfb7..8bcc4eb 100644
--- a/lib/librte_pipeline/rte_table_action.c
+++ b/lib/librte_pipeline/rte_table_action.c
@@ -1114,6 +1114,41 @@ pkt_ipv6_work_ttl(struct ipv6_hdr *ip,
 }
 
 /**
+ * RTE_TABLE_ACTION_STATS
+ */
+static int
+stats_cfg_check(struct rte_table_action_stats_config *stats)
+{
+	if ((stats->n_packets_enabled == 0) && (stats->n_bytes_enabled == 0))
+		return -EINVAL;
+
+	return 0;
+}
+
+struct stats_data {
+	uint64_t n_packets;
+	uint64_t n_bytes;
+} __attribute__((__packed__));
+
+static int
+stats_apply(struct stats_data *data,
+	struct rte_table_action_stats_params *p)
+{
+	data->n_packets = p->n_packets;
+	data->n_bytes = p->n_bytes;
+
+	return 0;
+}
+
+static __rte_always_inline void
+pkt_work_stats(struct stats_data *data,
+	uint16_t total_length)
+{
+	data->n_packets++;
+	data->n_bytes += total_length;
+}
+
+/**
  * Action profile
  */
 static int
@@ -1126,6 +1161,7 @@ action_valid(enum rte_table_action_type action)
 	case RTE_TABLE_ACTION_ENCAP:
 	case RTE_TABLE_ACTION_NAT:
 	case RTE_TABLE_ACTION_TTL:
+	case RTE_TABLE_ACTION_STATS:
 		return 1;
 	default:
 		return 0;
@@ -1143,6 +1179,7 @@ struct ap_config {
 	struct rte_table_action_encap_config encap;
 	struct rte_table_action_nat_config nat;
 	struct rte_table_action_ttl_config ttl;
+	struct rte_table_action_stats_config stats;
 };
 
 static size_t
@@ -1159,6 +1196,8 @@ action_cfg_size(enum rte_table_action_type action)
 		return sizeof(struct rte_table_action_nat_config);
 	case RTE_TABLE_ACTION_TTL:
 		return sizeof(struct rte_table_action_ttl_config);
+	case RTE_TABLE_ACTION_STATS:
+		return sizeof(struct rte_table_action_stats_config);
 	default:
 		return 0;
 	}
@@ -1184,6 +1223,9 @@ action_cfg_get(struct ap_config *ap_config,
 	case RTE_TABLE_ACTION_TTL:
 		return &ap_config->ttl;
 
+	case RTE_TABLE_ACTION_STATS:
+		return &ap_config->stats;
+
 	default:
 		return NULL;
 	}
@@ -1231,6 +1273,9 @@ action_data_size(enum rte_table_action_type action,
 	case RTE_TABLE_ACTION_TTL:
 		return sizeof(struct ttl_data);
 
+	case RTE_TABLE_ACTION_STATS:
+		return sizeof(struct stats_data);
+
 	default:
 		return 0;
 	}
@@ -1322,6 +1367,10 @@ rte_table_action_profile_action_register(struct rte_table_action_profile *profil
 		status = ttl_cfg_check(action_config);
 		break;
 
+	case RTE_TABLE_ACTION_STATS:
+		status = stats_cfg_check(action_config);
+		break;
+
 	default:
 		status = 0;
 		break;
@@ -1459,6 +1508,10 @@ rte_table_action_apply(struct rte_table_action *action,
 		return ttl_apply(action_data,
 			action_params);
 
+	case RTE_TABLE_ACTION_STATS:
+		return stats_apply(action_data,
+			action_params);
+
 	default:
 		return -EINVAL;
 	}
@@ -1653,6 +1706,41 @@ rte_table_action_ttl_read(struct rte_table_action *action,
 	return 0;
 }
 
+int
+rte_table_action_stats_read(struct rte_table_action *action,
+	void *data,
+	struct rte_table_action_stats_counters *stats,
+	int clear)
+{
+	struct stats_data *stats_data;
+
+	/* Check input arguments */
+	if ((action == NULL) ||
+		((action->cfg.action_mask &
+		(1LLU << RTE_TABLE_ACTION_STATS)) == 0) ||
+		(data == NULL))
+		return -EINVAL;
+
+	stats_data = action_data_get(data, action,
+		RTE_TABLE_ACTION_STATS);
+
+	/* Read */
+	if (stats) {
+		stats->n_packets = stats_data->n_packets;
+		stats->n_bytes = stats_data->n_bytes;
+		stats->n_packets_valid = 1;
+		stats->n_bytes_valid = 1;
+	}
+
+	/* Clear */
+	if (clear) {
+		stats_data->n_packets = 0;
+		stats_data->n_bytes = 0;
+	}
+
+	return 0;
+}
+
 static __rte_always_inline uint64_t
 pkt_work(struct rte_mbuf *mbuf,
 	struct rte_pipeline_table_entry *table_entry,
@@ -1736,6 +1824,13 @@ pkt_work(struct rte_mbuf *mbuf,
 			drop_mask |= pkt_ipv6_work_ttl(ip, data);
 	}
 
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_STATS)) {
+		void *data =
+			action_data_get(table_entry, action, RTE_TABLE_ACTION_STATS);
+
+		pkt_work_stats(data, total_length);
+	}
+
 	return drop_mask;
 }
 
@@ -1965,6 +2060,22 @@ pkt4_work(struct rte_mbuf **mbufs,
 		}
 	}
 
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_STATS)) {
+		void *data0 =
+			action_data_get(table_entry0, action, RTE_TABLE_ACTION_STATS);
+		void *data1 =
+			action_data_get(table_entry1, action, RTE_TABLE_ACTION_STATS);
+		void *data2 =
+			action_data_get(table_entry2, action, RTE_TABLE_ACTION_STATS);
+		void *data3 =
+			action_data_get(table_entry3, action, RTE_TABLE_ACTION_STATS);
+
+		pkt_work_stats(data0, total_length0);
+		pkt_work_stats(data1, total_length1);
+		pkt_work_stats(data2, total_length2);
+		pkt_work_stats(data3, total_length3);
+	}
+
 	return drop_mask0 |
 		(drop_mask1 << 1) |
 		(drop_mask2 << 2) |
diff --git a/lib/librte_pipeline/rte_table_action.h b/lib/librte_pipeline/rte_table_action.h
index 57ac4f9..53b9866 100644
--- a/lib/librte_pipeline/rte_table_action.h
+++ b/lib/librte_pipeline/rte_table_action.h
@@ -83,6 +83,9 @@ enum rte_table_action_type {
 
 	/** Time to Live (TTL) update. */
 	RTE_TABLE_ACTION_TTL,
+
+	/** Statistics. */
+	RTE_TABLE_ACTION_STATS,
 };
 
 /** Common action configuration (per table action profile). */
@@ -489,6 +492,56 @@ struct rte_table_action_ttl_counters {
 };
 
 /**
+ * RTE_TABLE_ACTION_STATS
+ */
+/** Stats action configuration (per table action profile). */
+struct rte_table_action_stats_config {
+	/** When non-zero, the *n_packets* stats counter is enabled, otherwise
+	 * disabled.
+	 *
+	 * @see struct rte_table_action_stats_counters
+	 */
+	int n_packets_enabled;
+
+	/** When non-zero, the *n_bytes* stats counter is enabled, otherwise
+	 * disabled.
+	 *
+	 * @see struct rte_table_action_stats_counters
+	 */
+	int n_bytes_enabled;
+};
+
+/** Stats action parameters (per table rule). */
+struct rte_table_action_stats_params {
+	/** Initial value for the *n_packets* stats counter. Typically set to 0.
+	 *
+	 * @see struct rte_table_action_stats_counters
+	 */
+	uint64_t n_packets;
+
+	/** Initial value for the *n_bytes* stats counter. Typically set to 0.
+	 *
+	 * @see struct rte_table_action_stats_counters
+	 */
+	uint64_t n_bytes;
+};
+
+/** Stats action counters (per table rule). */
+struct rte_table_action_stats_counters {
+	/** Number of packets. Valid only when *n_packets_valid* is non-zero. */
+	uint64_t n_packets;
+
+	/** Number of bytes. Valid only when *n_bytes_valid* is non-zero. */
+	uint64_t n_bytes;
+
+	/** When non-zero, the *n_packets* field is valid, otherwise invalid. */
+	int n_packets_valid;
+
+	/** When non-zero, the *n_bytes* field is valid, otherwise invalid. */
+	int n_bytes_valid;
+};
+
+/**
  * Table action profile.
  */
 struct rte_table_action_profile;
@@ -737,6 +790,31 @@ rte_table_action_ttl_read(struct rte_table_action *action,
 	struct rte_table_action_ttl_counters *stats,
 	int clear);
 
+/**
+ * Table action stats read.
+ *
+ * @param[in] action
+ *   Handle to table action object (needs to be valid).
+ * @param[in] data
+ *   Data byte array (typically table rule data) with stats action previously
+ *   applied on it.
+ * @param[inout] stats
+ *   When non-NULL, it points to the area where the stats counters read from
+ *   *data* are saved.
+ * @param[in] clear
+ *   When non-zero, the stats counters are cleared (i.e. set to zero), otherwise
+ *   the counters are not modified. When the read operation is enabled (*stats*
+ *   is non-NULL), the clear operation is performed after the read operation is
+ *   completed.
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_table_action_stats_read(struct rte_table_action *action,
+	void *data,
+	struct rte_table_action_stats_counters *stats,
+	int clear);
+
 #ifdef __cplusplus
 }
 #endif
-- 
2.9.3

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

* [dpdk-dev] [PATCH v3 09/44] pipeline: add timestamp action
  2018-03-16 17:58       ` [dpdk-dev] [PATCH v3 00/44] ip_pipeline: refactoring Jasvinder Singh
                           ` (7 preceding siblings ...)
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 08/44] pipeline: add statistics read action Jasvinder Singh
@ 2018-03-16 17:58         ` Jasvinder Singh
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 10/44] ip_pipeline: remove passthrough pipeline Jasvinder Singh
                           ` (34 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-16 17:58 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add implementation of timestamp action.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 lib/librte_pipeline/rte_pipeline_version.map |  1 +
 lib/librte_pipeline/rte_table_action.c       | 79 +++++++++++++++++++++++++++-
 lib/librte_pipeline/rte_table_action.h       | 31 +++++++++++
 3 files changed, 110 insertions(+), 1 deletion(-)

diff --git a/lib/librte_pipeline/rte_pipeline_version.map b/lib/librte_pipeline/rte_pipeline_version.map
index 8241efc..4e948b8 100644
--- a/lib/librte_pipeline/rte_pipeline_version.map
+++ b/lib/librte_pipeline/rte_pipeline_version.map
@@ -62,6 +62,7 @@ EXPERIMENTAL {
 	rte_table_action_profile_freeze;
 	rte_table_action_table_params_get;
 	rte_table_action_stats_read;
+	rte_table_action_time_read;
 	rte_table_action_ttl_read;
 
 } DPDK_16.04;
diff --git a/lib/librte_pipeline/rte_table_action.c b/lib/librte_pipeline/rte_table_action.c
index 8bcc4eb..1a32c71 100644
--- a/lib/librte_pipeline/rte_table_action.c
+++ b/lib/librte_pipeline/rte_table_action.c
@@ -1149,6 +1149,28 @@ pkt_work_stats(struct stats_data *data,
 }
 
 /**
+ * RTE_TABLE_ACTION_TIME
+ */
+struct time_data {
+	uint64_t time;
+} __attribute__((__packed__));
+
+static int
+time_apply(struct time_data *data,
+	struct rte_table_action_time_params *p)
+{
+	data->time = p->time;
+	return 0;
+}
+
+static __rte_always_inline void
+pkt_work_time(struct time_data *data,
+	uint64_t time)
+{
+	data->time = time;
+}
+
+/**
  * Action profile
  */
 static int
@@ -1162,6 +1184,7 @@ action_valid(enum rte_table_action_type action)
 	case RTE_TABLE_ACTION_NAT:
 	case RTE_TABLE_ACTION_TTL:
 	case RTE_TABLE_ACTION_STATS:
+	case RTE_TABLE_ACTION_TIME:
 		return 1;
 	default:
 		return 0;
@@ -1276,6 +1299,9 @@ action_data_size(enum rte_table_action_type action,
 	case RTE_TABLE_ACTION_STATS:
 		return sizeof(struct stats_data);
 
+	case RTE_TABLE_ACTION_TIME:
+		return sizeof(struct time_data);
+
 	default:
 		return 0;
 	}
@@ -1512,6 +1538,10 @@ rte_table_action_apply(struct rte_table_action *action,
 		return stats_apply(action_data,
 			action_params);
 
+	case RTE_TABLE_ACTION_TIME:
+		return time_apply(action_data,
+			action_params);
+
 	default:
 		return -EINVAL;
 	}
@@ -1741,6 +1771,29 @@ rte_table_action_stats_read(struct rte_table_action *action,
 	return 0;
 }
 
+int
+rte_table_action_time_read(struct rte_table_action *action,
+	void *data,
+	uint64_t *timestamp)
+{
+	struct time_data *time_data;
+
+	/* Check input arguments */
+	if ((action == NULL) ||
+		((action->cfg.action_mask &
+		(1LLU << RTE_TABLE_ACTION_TIME)) == 0) ||
+		(data == NULL) ||
+		(timestamp == NULL))
+		return -EINVAL;
+
+	time_data = action_data_get(data, action, RTE_TABLE_ACTION_TIME);
+
+	/* Read */
+	*timestamp = time_data->time;
+
+	return 0;
+}
+
 static __rte_always_inline uint64_t
 pkt_work(struct rte_mbuf *mbuf,
 	struct rte_pipeline_table_entry *table_entry,
@@ -1831,6 +1884,13 @@ pkt_work(struct rte_mbuf *mbuf,
 		pkt_work_stats(data, total_length);
 	}
 
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_TIME)) {
+		void *data =
+			action_data_get(table_entry, action, RTE_TABLE_ACTION_TIME);
+
+		pkt_work_time(data, time);
+	}
+
 	return drop_mask;
 }
 
@@ -2076,6 +2136,22 @@ pkt4_work(struct rte_mbuf **mbufs,
 		pkt_work_stats(data3, total_length3);
 	}
 
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_TIME)) {
+		void *data0 =
+			action_data_get(table_entry0, action, RTE_TABLE_ACTION_TIME);
+		void *data1 =
+			action_data_get(table_entry1, action, RTE_TABLE_ACTION_TIME);
+		void *data2 =
+			action_data_get(table_entry2, action, RTE_TABLE_ACTION_TIME);
+		void *data3 =
+			action_data_get(table_entry3, action, RTE_TABLE_ACTION_TIME);
+
+		pkt_work_time(data0, time);
+		pkt_work_time(data1, time);
+		pkt_work_time(data2, time);
+		pkt_work_time(data3, time);
+	}
+
 	return drop_mask0 |
 		(drop_mask1 << 1) |
 		(drop_mask2 << 2) |
@@ -2093,7 +2169,8 @@ ah(struct rte_pipeline *p,
 	uint64_t pkts_drop_mask = 0;
 	uint64_t time = 0;
 
-	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_MTR))
+	if (cfg->action_mask & ((1LLU << RTE_TABLE_ACTION_MTR) |
+		(1LLU << RTE_TABLE_ACTION_TIME)))
 		time = rte_rdtsc();
 
 	if ((pkts_mask & (pkts_mask + 1)) == 0) {
diff --git a/lib/librte_pipeline/rte_table_action.h b/lib/librte_pipeline/rte_table_action.h
index 53b9866..e9b30ab 100644
--- a/lib/librte_pipeline/rte_table_action.h
+++ b/lib/librte_pipeline/rte_table_action.h
@@ -86,6 +86,9 @@ enum rte_table_action_type {
 
 	/** Statistics. */
 	RTE_TABLE_ACTION_STATS,
+
+	/** Timestamp. */
+	RTE_TABLE_ACTION_TIME,
 };
 
 /** Common action configuration (per table action profile). */
@@ -542,6 +545,15 @@ struct rte_table_action_stats_counters {
 };
 
 /**
+ * RTE_TABLE_ACTION_TIME
+ */
+/** Timestamp action parameters (per table rule). */
+struct rte_table_action_time_params {
+	/** Initial timestamp value. Typically set to current time. */
+	uint64_t time;
+};
+
+/**
  * Table action profile.
  */
 struct rte_table_action_profile;
@@ -815,6 +827,25 @@ rte_table_action_stats_read(struct rte_table_action *action,
 	struct rte_table_action_stats_counters *stats,
 	int clear);
 
+/**
+ * Table action timestamp read.
+ *
+ * @param[in] action
+ *   Handle to table action object (needs to be valid).
+ * @param[in] data
+ *   Data byte array (typically table rule data) with timestamp action
+ *   previously applied on it.
+ * @param[inout] timestamp
+ *   Pre-allocated memory where the timestamp read from *data* is saved (has to
+ *   be non-NULL).
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_table_action_time_read(struct rte_table_action *action,
+	void *data,
+	uint64_t *timestamp);
+
 #ifdef __cplusplus
 }
 #endif
-- 
2.9.3

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

* [dpdk-dev] [PATCH v3 10/44] ip_pipeline: remove passthrough pipeline
  2018-03-16 17:58       ` [dpdk-dev] [PATCH v3 00/44] ip_pipeline: refactoring Jasvinder Singh
                           ` (8 preceding siblings ...)
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 09/44] pipeline: add timestamp action Jasvinder Singh
@ 2018-03-16 17:58         ` Jasvinder Singh
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 11/44] ip_pipeline: remove routing pipeline Jasvinder Singh
                           ` (33 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-16 17:58 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

remove passthrough pipeline.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/Makefile                      |   2 -
 examples/ip_pipeline/init.c                        |   2 -
 examples/ip_pipeline/meson.build                   |   2 -
 .../ip_pipeline/pipeline/pipeline_passthrough.c    |  45 -
 .../ip_pipeline/pipeline/pipeline_passthrough.h    |  12 -
 .../ip_pipeline/pipeline/pipeline_passthrough_be.c | 929 ---------------------
 .../ip_pipeline/pipeline/pipeline_passthrough_be.h |  44 -
 7 files changed, 1036 deletions(-)
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_passthrough.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_passthrough.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_passthrough_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_passthrough_be.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index 85fbbaf..089c269 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -19,8 +19,6 @@ SRCS-y += pipeline_common_be.c
 SRCS-y += pipeline_common_fe.c
 SRCS-y += pipeline_master_be.c
 SRCS-y += pipeline_master.c
-SRCS-y += pipeline_passthrough_be.c
-SRCS-y += pipeline_passthrough.c
 SRCS-y += pipeline_firewall_be.c
 SRCS-y += pipeline_firewall.c
 SRCS-y += pipeline_flow_classification_be.c
diff --git a/examples/ip_pipeline/init.c b/examples/ip_pipeline/init.c
index bb07efa..73b93d7 100644
--- a/examples/ip_pipeline/init.c
+++ b/examples/ip_pipeline/init.c
@@ -26,7 +26,6 @@
 #include "pipeline.h"
 #include "pipeline_common_fe.h"
 #include "pipeline_master.h"
-#include "pipeline_passthrough.h"
 #include "pipeline_firewall.h"
 #include "pipeline_flow_classification.h"
 #include "pipeline_flow_actions.h"
@@ -1822,7 +1821,6 @@ int app_init(struct app_params *app)
 	app_pipeline_common_cmd_push(app);
 	app_pipeline_thread_cmd_push(app);
 	app_pipeline_type_register(app, &pipeline_master);
-	app_pipeline_type_register(app, &pipeline_passthrough);
 	app_pipeline_type_register(app, &pipeline_flow_classification);
 	app_pipeline_type_register(app, &pipeline_flow_actions);
 	app_pipeline_type_register(app, &pipeline_firewall);
diff --git a/examples/ip_pipeline/meson.build b/examples/ip_pipeline/meson.build
index 00d4033..17f4e16 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -29,8 +29,6 @@ sources = files(
 	'pipeline/pipeline_flow_classification.c',
 	'pipeline/pipeline_master_be.c',
 	'pipeline/pipeline_master.c',
-	'pipeline/pipeline_passthrough_be.c',
-	'pipeline/pipeline_passthrough.c',
 	'pipeline/pipeline_routing_be.c',
 	'pipeline/pipeline_routing.c',
 )
diff --git a/examples/ip_pipeline/pipeline/pipeline_passthrough.c b/examples/ip_pipeline/pipeline/pipeline_passthrough.c
deleted file mode 100644
index 031f5f0..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_passthrough.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#include "pipeline_passthrough.h"
-#include "pipeline_passthrough_be.h"
-
-static int
-app_pipeline_passthrough_track(struct pipeline_params *p,
-	uint32_t port_in,
-	uint32_t *port_out)
-{
-	struct pipeline_passthrough_params pp;
-	int status;
-
-	/* Check input arguments */
-	if ((p == NULL) ||
-		(port_in >= p->n_ports_in) ||
-		(port_out == NULL))
-		return -1;
-
-	status = pipeline_passthrough_parse_args(&pp, p);
-	if (status)
-		return -1;
-
-	if (pp.dma_hash_lb_enabled)
-		return -1;
-
-	*port_out = port_in / (p->n_ports_in / p->n_ports_out);
-	return 0;
-}
-
-static struct pipeline_fe_ops pipeline_passthrough_fe_ops = {
-	.f_init = NULL,
-	.f_post_init = NULL,
-	.f_free = NULL,
-	.f_track = app_pipeline_passthrough_track,
-	.cmds = NULL,
-};
-
-struct pipeline_type pipeline_passthrough = {
-	.name = "PASS-THROUGH",
-	.be_ops = &pipeline_passthrough_be_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
deleted file mode 100644
index 7a7a2fc..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_passthrough.h
+++ /dev/null
@@ -1,12 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#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_be.c b/examples/ip_pipeline/pipeline/pipeline_passthrough_be.c
deleted file mode 100644
index b2bbaed..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_passthrough_be.c
+++ /dev/null
@@ -1,929 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2016 Intel Corporation
- */
-
-#include <stdio.h>
-#include <string.h>
-
-#include <rte_common.h>
-#include <rte_malloc.h>
-#include <rte_byteorder.h>
-#include <rte_table_stub.h>
-#include <rte_table_hash.h>
-#include <rte_pipeline.h>
-
-#include "pipeline_passthrough_be.h"
-#include "pipeline_actions_common.h"
-#include "parser.h"
-#include "hash_func.h"
-
-#define SWAP_DIM (PIPELINE_PASSTHROUGH_SWAP_N_FIELDS_MAX * \
-	(PIPELINE_PASSTHROUGH_SWAP_FIELD_SIZE_MAX / sizeof(uint64_t)))
-
-struct pipeline_passthrough {
-	struct pipeline p;
-	struct pipeline_passthrough_params params;
-	rte_table_hash_op_hash f_hash;
-	uint32_t swap_field0_offset[SWAP_DIM];
-	uint32_t swap_field1_offset[SWAP_DIM];
-	uint64_t swap_field_mask[SWAP_DIM];
-	uint32_t swap_n_fields;
-} __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 __rte_always_inline void
-pkt_work_dma(
-	struct rte_mbuf *pkt,
-	void *arg,
-	uint32_t dma_size,
-	uint32_t hash_enabled,
-	uint32_t lb_hash,
-	uint32_t port_out_pow2)
-{
-	struct pipeline_passthrough *p = arg;
-
-	uint64_t *dma_dst = RTE_MBUF_METADATA_UINT64_PTR(pkt,
-		p->params.dma_dst_offset);
-	uint64_t *dma_src = RTE_MBUF_METADATA_UINT64_PTR(pkt,
-		p->params.dma_src_offset);
-	uint64_t *dma_mask = (uint64_t *) p->params.dma_src_mask;
-	uint32_t *dma_hash = RTE_MBUF_METADATA_UINT32_PTR(pkt,
-		p->params.dma_hash_offset);
-	uint32_t i;
-
-	/* Read (dma_src), compute (dma_dst), write (dma_dst) */
-	for (i = 0; i < (dma_size / 8); i++)
-		dma_dst[i] = dma_src[i] & dma_mask[i];
-
-	/* Read (dma_dst), compute (hash), write (hash) */
-	if (hash_enabled) {
-		uint32_t hash = p->f_hash(dma_src, dma_mask, dma_size, 0);
-		*dma_hash = hash;
-
-		if (lb_hash) {
-			uint32_t port_out;
-
-			if (port_out_pow2)
-				port_out
-					= hash & (p->p.n_ports_out - 1);
-			else
-				port_out
-					= hash % p->p.n_ports_out;
-
-			rte_pipeline_port_out_packet_insert(p->p.p,
-				port_out, pkt);
-		}
-	}
-}
-
-static __rte_always_inline void
-pkt4_work_dma(
-	struct rte_mbuf **pkts,
-	void *arg,
-	uint32_t dma_size,
-	uint32_t hash_enabled,
-	uint32_t lb_hash,
-	uint32_t port_out_pow2)
-{
-	struct pipeline_passthrough *p = arg;
-
-	uint64_t *dma_dst0 = RTE_MBUF_METADATA_UINT64_PTR(pkts[0],
-		p->params.dma_dst_offset);
-	uint64_t *dma_dst1 = RTE_MBUF_METADATA_UINT64_PTR(pkts[1],
-		p->params.dma_dst_offset);
-	uint64_t *dma_dst2 = RTE_MBUF_METADATA_UINT64_PTR(pkts[2],
-		p->params.dma_dst_offset);
-	uint64_t *dma_dst3 = RTE_MBUF_METADATA_UINT64_PTR(pkts[3],
-		p->params.dma_dst_offset);
-
-	uint64_t *dma_src0 = RTE_MBUF_METADATA_UINT64_PTR(pkts[0],
-		p->params.dma_src_offset);
-	uint64_t *dma_src1 = RTE_MBUF_METADATA_UINT64_PTR(pkts[1],
-		p->params.dma_src_offset);
-	uint64_t *dma_src2 = RTE_MBUF_METADATA_UINT64_PTR(pkts[2],
-		p->params.dma_src_offset);
-	uint64_t *dma_src3 = RTE_MBUF_METADATA_UINT64_PTR(pkts[3],
-		p->params.dma_src_offset);
-
-	uint64_t *dma_mask = (uint64_t *) p->params.dma_src_mask;
-
-	uint32_t *dma_hash0 = RTE_MBUF_METADATA_UINT32_PTR(pkts[0],
-		p->params.dma_hash_offset);
-	uint32_t *dma_hash1 = RTE_MBUF_METADATA_UINT32_PTR(pkts[1],
-		p->params.dma_hash_offset);
-	uint32_t *dma_hash2 = RTE_MBUF_METADATA_UINT32_PTR(pkts[2],
-		p->params.dma_hash_offset);
-	uint32_t *dma_hash3 = RTE_MBUF_METADATA_UINT32_PTR(pkts[3],
-		p->params.dma_hash_offset);
-
-	uint32_t i;
-
-	/* Read (dma_src), compute (dma_dst), write (dma_dst) */
-	for (i = 0; i < (dma_size / 8); i++) {
-		dma_dst0[i] = dma_src0[i] & dma_mask[i];
-		dma_dst1[i] = dma_src1[i] & dma_mask[i];
-		dma_dst2[i] = dma_src2[i] & dma_mask[i];
-		dma_dst3[i] = dma_src3[i] & dma_mask[i];
-	}
-
-	/* Read (dma_dst), compute (hash), write (hash) */
-	if (hash_enabled) {
-		uint32_t hash0 = p->f_hash(dma_src0, dma_mask, dma_size, 0);
-		uint32_t hash1 = p->f_hash(dma_src1, dma_mask, dma_size, 0);
-		uint32_t hash2 = p->f_hash(dma_src2, dma_mask, dma_size, 0);
-		uint32_t hash3 = p->f_hash(dma_src3, dma_mask, dma_size, 0);
-
-		*dma_hash0 = hash0;
-		*dma_hash1 = hash1;
-		*dma_hash2 = hash2;
-		*dma_hash3 = hash3;
-
-		if (lb_hash) {
-			uint32_t port_out0, port_out1, port_out2, port_out3;
-
-			if (port_out_pow2) {
-				port_out0
-					= hash0 & (p->p.n_ports_out - 1);
-				port_out1
-					= hash1 & (p->p.n_ports_out - 1);
-				port_out2
-					= hash2 & (p->p.n_ports_out - 1);
-				port_out3
-					= hash3 & (p->p.n_ports_out - 1);
-			} else {
-				port_out0
-					= hash0 % p->p.n_ports_out;
-				port_out1
-					= hash1 % p->p.n_ports_out;
-				port_out2
-					= hash2 % p->p.n_ports_out;
-				port_out3
-					= hash3 % p->p.n_ports_out;
-			}
-			rte_pipeline_port_out_packet_insert(p->p.p,
-				port_out0, pkts[0]);
-			rte_pipeline_port_out_packet_insert(p->p.p,
-				port_out1, pkts[1]);
-			rte_pipeline_port_out_packet_insert(p->p.p,
-				port_out2, pkts[2]);
-			rte_pipeline_port_out_packet_insert(p->p.p,
-				port_out3, pkts[3]);
-		}
-	}
-}
-
-static __rte_always_inline void
-pkt_work_swap(
-	struct rte_mbuf *pkt,
-	void *arg)
-{
-	struct pipeline_passthrough *p = arg;
-	uint32_t i;
-
-	/* Read(field0, field1), compute(field0, field1), write(field0, field1) */
-	for (i = 0; i < p->swap_n_fields; i++) {
-		uint64_t *field0_ptr = RTE_MBUF_METADATA_UINT64_PTR(pkt,
-			p->swap_field0_offset[i]);
-		uint64_t *field1_ptr = RTE_MBUF_METADATA_UINT64_PTR(pkt,
-			p->swap_field1_offset[i]);
-		uint64_t mask = p->swap_field_mask[i];
-
-		uint64_t field0 = *field0_ptr;
-		uint64_t field1 = *field1_ptr;
-
-		*field0_ptr = (field0 & (~mask)) + (field1 & mask);
-		*field1_ptr = (field0 & mask) + (field1 & (~mask));
-	}
-}
-
-static __rte_always_inline void
-pkt4_work_swap(
-	struct rte_mbuf **pkts,
-	void *arg)
-{
-	struct pipeline_passthrough *p = arg;
-	uint32_t i;
-
-	/* Read(field0, field1), compute(field0, field1), write(field0, field1) */
-	for (i = 0; i < p->swap_n_fields; i++) {
-		uint64_t *pkt0_field0_ptr = RTE_MBUF_METADATA_UINT64_PTR(pkts[0],
-			p->swap_field0_offset[i]);
-		uint64_t *pkt1_field0_ptr = RTE_MBUF_METADATA_UINT64_PTR(pkts[1],
-			p->swap_field0_offset[i]);
-		uint64_t *pkt2_field0_ptr = RTE_MBUF_METADATA_UINT64_PTR(pkts[2],
-			p->swap_field0_offset[i]);
-		uint64_t *pkt3_field0_ptr = RTE_MBUF_METADATA_UINT64_PTR(pkts[3],
-			p->swap_field0_offset[i]);
-
-		uint64_t *pkt0_field1_ptr = RTE_MBUF_METADATA_UINT64_PTR(pkts[0],
-			p->swap_field1_offset[i]);
-		uint64_t *pkt1_field1_ptr = RTE_MBUF_METADATA_UINT64_PTR(pkts[1],
-			p->swap_field1_offset[i]);
-		uint64_t *pkt2_field1_ptr = RTE_MBUF_METADATA_UINT64_PTR(pkts[2],
-			p->swap_field1_offset[i]);
-		uint64_t *pkt3_field1_ptr = RTE_MBUF_METADATA_UINT64_PTR(pkts[3],
-			p->swap_field1_offset[i]);
-
-		uint64_t mask = p->swap_field_mask[i];
-
-		uint64_t pkt0_field0 = *pkt0_field0_ptr;
-		uint64_t pkt1_field0 = *pkt1_field0_ptr;
-		uint64_t pkt2_field0 = *pkt2_field0_ptr;
-		uint64_t pkt3_field0 = *pkt3_field0_ptr;
-
-		uint64_t pkt0_field1 = *pkt0_field1_ptr;
-		uint64_t pkt1_field1 = *pkt1_field1_ptr;
-		uint64_t pkt2_field1 = *pkt2_field1_ptr;
-		uint64_t pkt3_field1 = *pkt3_field1_ptr;
-
-		*pkt0_field0_ptr = (pkt0_field0 & (~mask)) + (pkt0_field1 & mask);
-		*pkt1_field0_ptr = (pkt1_field0 & (~mask)) + (pkt1_field1 & mask);
-		*pkt2_field0_ptr = (pkt2_field0 & (~mask)) + (pkt2_field1 & mask);
-		*pkt3_field0_ptr = (pkt3_field0 & (~mask)) + (pkt3_field1 & mask);
-
-		*pkt0_field1_ptr = (pkt0_field0 & mask) + (pkt0_field1 & (~mask));
-		*pkt1_field1_ptr = (pkt1_field0 & mask) + (pkt1_field1 & (~mask));
-		*pkt2_field1_ptr = (pkt2_field0 & mask) + (pkt2_field1 & (~mask));
-		*pkt3_field1_ptr = (pkt3_field0 & mask) + (pkt3_field1 & (~mask));
-	}
-}
-
-#define PKT_WORK_DMA(dma_size, hash_enabled, lb_hash, port_pow2)	\
-static inline void						\
-pkt_work_dma_size##dma_size##_hash##hash_enabled		\
-	##_lb##lb_hash##_pw##port_pow2(			\
-	struct rte_mbuf *pkt,					\
-	void *arg)						\
-{								\
-	pkt_work_dma(pkt, arg, dma_size, hash_enabled, lb_hash, port_pow2);	\
-}
-
-#define PKT4_WORK_DMA(dma_size, hash_enabled, lb_hash, port_pow2)	\
-static inline void						\
-pkt4_work_dma_size##dma_size##_hash##hash_enabled			\
-	##_lb##lb_hash##_pw##port_pow2(			\
-	struct rte_mbuf **pkts,					\
-	void *arg)						\
-{								\
-	pkt4_work_dma(pkts, arg, dma_size, hash_enabled, lb_hash, port_pow2); \
-}
-
-#define port_in_ah_dma(dma_size, hash_enabled, lb_hash, port_pow2)	\
-PKT_WORK_DMA(dma_size, hash_enabled, lb_hash, port_pow2)			\
-PKT4_WORK_DMA(dma_size, hash_enabled, lb_hash, port_pow2)			\
-PIPELINE_PORT_IN_AH(port_in_ah_dma_size##dma_size##_hash	\
-	##hash_enabled##_lb##lb_hash##_pw##port_pow2,		\
-	pkt_work_dma_size##dma_size##_hash##hash_enabled		\
-	##_lb##lb_hash##_pw##port_pow2,			\
-	pkt4_work_dma_size##dma_size##_hash##hash_enabled		\
-	##_lb##lb_hash##_pw##port_pow2)
-
-
-#define port_in_ah_lb(dma_size, hash_enabled, lb_hash, port_pow2) \
-PKT_WORK_DMA(dma_size, hash_enabled, lb_hash, port_pow2)		\
-PKT4_WORK_DMA(dma_size, hash_enabled, lb_hash, port_pow2)	\
-PIPELINE_PORT_IN_AH_HIJACK_ALL(						\
-	port_in_ah_lb_size##dma_size##_hash##hash_enabled		\
-	##_lb##lb_hash##_pw##port_pow2,			\
-	pkt_work_dma_size##dma_size##_hash##hash_enabled		\
-	##_lb##lb_hash##_pw##port_pow2,	\
-	pkt4_work_dma_size##dma_size##_hash##hash_enabled		\
-	##_lb##lb_hash##_pw##port_pow2)
-
-PIPELINE_PORT_IN_AH(port_in_ah_swap, pkt_work_swap,	pkt4_work_swap)
-
-
-/* Port in AH DMA(dma_size, hash_enabled, lb_hash, port_pow2) */
-
-port_in_ah_dma(8, 0, 0, 0)
-port_in_ah_dma(8, 1, 0, 0)
-port_in_ah_lb(8, 1, 1, 0)
-port_in_ah_lb(8, 1, 1, 1)
-
-port_in_ah_dma(16, 0, 0, 0)
-port_in_ah_dma(16, 1, 0, 0)
-port_in_ah_lb(16, 1, 1, 0)
-port_in_ah_lb(16, 1, 1, 1)
-
-port_in_ah_dma(24, 0, 0, 0)
-port_in_ah_dma(24, 1, 0, 0)
-port_in_ah_lb(24, 1, 1, 0)
-port_in_ah_lb(24, 1, 1, 1)
-
-port_in_ah_dma(32, 0, 0, 0)
-port_in_ah_dma(32, 1, 0, 0)
-port_in_ah_lb(32, 1, 1, 0)
-port_in_ah_lb(32, 1, 1, 1)
-
-port_in_ah_dma(40, 0, 0, 0)
-port_in_ah_dma(40, 1, 0, 0)
-port_in_ah_lb(40, 1, 1, 0)
-port_in_ah_lb(40, 1, 1, 1)
-
-port_in_ah_dma(48, 0, 0, 0)
-port_in_ah_dma(48, 1, 0, 0)
-port_in_ah_lb(48, 1, 1, 0)
-port_in_ah_lb(48, 1, 1, 1)
-
-port_in_ah_dma(56, 0, 0, 0)
-port_in_ah_dma(56, 1, 0, 0)
-port_in_ah_lb(56, 1, 1, 0)
-port_in_ah_lb(56, 1, 1, 1)
-
-port_in_ah_dma(64, 0, 0, 0)
-port_in_ah_dma(64, 1, 0, 0)
-port_in_ah_lb(64, 1, 1, 0)
-port_in_ah_lb(64, 1, 1, 1)
-
-static rte_pipeline_port_in_action_handler
-get_port_in_ah(struct pipeline_passthrough *p)
-{
-	if ((p->params.dma_enabled == 0) &&
-		(p->params.swap_enabled == 0))
-		return NULL;
-
-	if (p->params.swap_enabled)
-		return port_in_ah_swap;
-
-	if (p->params.dma_hash_enabled) {
-		if (p->params.dma_hash_lb_enabled) {
-			if (rte_is_power_of_2(p->p.n_ports_out))
-				switch (p->params.dma_size) {
-
-				case 8: return port_in_ah_lb_size8_hash1_lb1_pw1;
-				case 16: return port_in_ah_lb_size16_hash1_lb1_pw1;
-				case 24: return port_in_ah_lb_size24_hash1_lb1_pw1;
-				case 32: return port_in_ah_lb_size32_hash1_lb1_pw1;
-				case 40: return port_in_ah_lb_size40_hash1_lb1_pw1;
-				case 48: return port_in_ah_lb_size48_hash1_lb1_pw1;
-				case 56: return port_in_ah_lb_size56_hash1_lb1_pw1;
-				case 64: return port_in_ah_lb_size64_hash1_lb1_pw1;
-				default: return NULL;
-				}
-			else
-				switch (p->params.dma_size) {
-
-				case 8: return port_in_ah_lb_size8_hash1_lb1_pw0;
-				case 16: return port_in_ah_lb_size16_hash1_lb1_pw0;
-				case 24: return port_in_ah_lb_size24_hash1_lb1_pw0;
-				case 32: return port_in_ah_lb_size32_hash1_lb1_pw0;
-				case 40: return port_in_ah_lb_size40_hash1_lb1_pw0;
-				case 48: return port_in_ah_lb_size48_hash1_lb1_pw0;
-				case 56: return port_in_ah_lb_size56_hash1_lb1_pw0;
-				case 64: return port_in_ah_lb_size64_hash1_lb1_pw0;
-				default: return NULL;
-			}
-		} else
-			switch (p->params.dma_size) {
-
-			case 8: return port_in_ah_dma_size8_hash1_lb0_pw0;
-			case 16: return port_in_ah_dma_size16_hash1_lb0_pw0;
-			case 24: return port_in_ah_dma_size24_hash1_lb0_pw0;
-			case 32: return port_in_ah_dma_size32_hash1_lb0_pw0;
-			case 40: return port_in_ah_dma_size40_hash1_lb0_pw0;
-			case 48: return port_in_ah_dma_size48_hash1_lb0_pw0;
-			case 56: return port_in_ah_dma_size56_hash1_lb0_pw0;
-			case 64: return port_in_ah_dma_size64_hash1_lb0_pw0;
-			default: return NULL;
-		}
-	} else
-		switch (p->params.dma_size) {
-
-		case 8: return port_in_ah_dma_size8_hash0_lb0_pw0;
-		case 16: return port_in_ah_dma_size16_hash0_lb0_pw0;
-		case 24: return port_in_ah_dma_size24_hash0_lb0_pw0;
-		case 32: return port_in_ah_dma_size32_hash0_lb0_pw0;
-		case 40: return port_in_ah_dma_size40_hash0_lb0_pw0;
-		case 48: return port_in_ah_dma_size48_hash0_lb0_pw0;
-		case 56: return port_in_ah_dma_size56_hash0_lb0_pw0;
-		case 64: return port_in_ah_dma_size64_hash0_lb0_pw0;
-		default: return NULL;
-		}
-}
-
-int
-pipeline_passthrough_parse_args(struct pipeline_passthrough_params *p,
-	struct pipeline_params *params)
-{
-	uint32_t dma_dst_offset_present = 0;
-	uint32_t dma_src_offset_present = 0;
-	uint32_t dma_src_mask_present = 0;
-	char dma_mask_str[PIPELINE_PASSTHROUGH_DMA_SIZE_MAX * 2 + 1];
-	uint32_t dma_size_present = 0;
-	uint32_t dma_hash_offset_present = 0;
-	uint32_t dma_hash_lb_present = 0;
-	uint32_t i;
-
-	/* default values */
-	p->dma_enabled = 0;
-	p->dma_hash_enabled = 0;
-	p->dma_hash_lb_enabled = 0;
-	memset(p->dma_src_mask, 0xFF, sizeof(p->dma_src_mask));
-	p->swap_enabled = 0;
-	p->swap_n_fields = 0;
-
-	for (i = 0; i < params->n_args; i++) {
-		char *arg_name = params->args_name[i];
-		char *arg_value = params->args_value[i];
-
-		/* dma_dst_offset */
-		if (strcmp(arg_name, "dma_dst_offset") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				dma_dst_offset_present == 0, params->name,
-				arg_name);
-			dma_dst_offset_present = 1;
-
-			status = parser_read_uint32(&p->dma_dst_offset,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			p->dma_enabled = 1;
-
-			continue;
-		}
-
-		/* dma_src_offset */
-		if (strcmp(arg_name, "dma_src_offset") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				dma_src_offset_present == 0, params->name,
-				arg_name);
-			dma_src_offset_present = 1;
-
-			status = parser_read_uint32(&p->dma_src_offset,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			p->dma_enabled = 1;
-
-			continue;
-		}
-
-		/* dma_size */
-		if (strcmp(arg_name, "dma_size") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				dma_size_present == 0, params->name,
-				arg_name);
-			dma_size_present = 1;
-
-			status = parser_read_uint32(&p->dma_size,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL(((status != -EINVAL) &&
-				(p->dma_size != 0) &&
-				((p->dma_size % 8) == 0)),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG(((status != -ERANGE) &&
-				(p->dma_size <=
-				PIPELINE_PASSTHROUGH_DMA_SIZE_MAX)),
-				params->name, arg_name, arg_value);
-
-			p->dma_enabled = 1;
-
-			continue;
-		}
-
-		/* dma_src_mask */
-		if (strcmp(arg_name, "dma_src_mask") == 0) {
-			int mask_str_len = strlen(arg_value);
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				dma_src_mask_present == 0,
-				params->name, arg_name);
-			dma_src_mask_present = 1;
-
-			PIPELINE_ARG_CHECK((mask_str_len <=
-				(PIPELINE_PASSTHROUGH_DMA_SIZE_MAX * 2)),
-				"Parse error in section \"%s\": entry "
-				"\"%s\" too long", params->name,
-				arg_name);
-
-			snprintf(dma_mask_str, mask_str_len + 1,
-				"%s", arg_value);
-
-			p->dma_enabled = 1;
-
-			continue;
-		}
-
-		/* dma_hash_offset */
-		if (strcmp(arg_name, "dma_hash_offset") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				dma_hash_offset_present == 0,
-				params->name, arg_name);
-			dma_hash_offset_present = 1;
-
-			status = parser_read_uint32(&p->dma_hash_offset,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			p->dma_hash_enabled = 1;
-
-			continue;
-		}
-
-		/* load_balance mode */
-		if (strcmp(arg_name, "lb") == 0) {
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				dma_hash_lb_present == 0,
-				params->name, arg_name);
-			dma_hash_lb_present = 1;
-
-			if (strcmp(arg_value, "hash") &&
-				strcmp(arg_value, "HASH"))
-
-				PIPELINE_PARSE_ERR_INV_VAL(0,
-					params->name,
-					arg_name,
-					arg_value);
-
-			p->dma_hash_lb_enabled = 1;
-
-			continue;
-		}
-
-		/* swap */
-		if (strcmp(arg_name, "swap") == 0) {
-			uint32_t a, b, n_args;
-			int len;
-
-			n_args = sscanf(arg_value, "%" SCNu32 " %" SCNu32 "%n",
-				&a, &b, &len);
-			PIPELINE_PARSE_ERR_INV_VAL(((n_args == 2) &&
-				((size_t) len == strlen(arg_value))),
-				params->name, arg_name, arg_value);
-
-			p->swap_field0_offset[p->swap_n_fields] = a;
-			p->swap_field1_offset[p->swap_n_fields] = b;
-			p->swap_n_fields++;
-			p->swap_enabled = 1;
-
-			continue;
-		}
-
-		/* any other */
-		PIPELINE_PARSE_ERR_INV_ENT(0, params->name, arg_name);
-	}
-
-	/* Check correlations between arguments */
-	PIPELINE_ARG_CHECK((p->dma_enabled + p->swap_enabled < 2),
-		"Parse error in section \"%s\": DMA and SWAP actions are both enabled",
-		params->name);
-	PIPELINE_ARG_CHECK((dma_dst_offset_present == p->dma_enabled),
-		"Parse error in section \"%s\": missing entry "
-		"\"dma_dst_offset\"", params->name);
-	PIPELINE_ARG_CHECK((dma_src_offset_present == p->dma_enabled),
-		"Parse error in section \"%s\": missing entry "
-		"\"dma_src_offset\"", params->name);
-	PIPELINE_ARG_CHECK((dma_size_present == p->dma_enabled),
-		"Parse error in section \"%s\": missing entry "
-		"\"dma_size\"", params->name);
-	PIPELINE_ARG_CHECK((p->dma_hash_enabled <= p->dma_enabled),
-		"Parse error in section \"%s\": missing all DMA entries",
-		params->name);
-	PIPELINE_ARG_CHECK((p->dma_hash_lb_enabled <= p->dma_hash_enabled),
-		"Parse error in section \"%s\": missing all DMA hash entries ",
-		params->name);
-
-	if (dma_src_mask_present) {
-		uint32_t dma_size = p->dma_size;
-		int status;
-
-		PIPELINE_ARG_CHECK((strlen(dma_mask_str) ==
-			(dma_size * 2)), "Parse error in section "
-			"\"%s\": dma_src_mask should have exactly %u hex "
-			"digits", params->name, (dma_size * 2));
-
-		status = parse_hex_string(dma_mask_str, p->dma_src_mask,
-			&p->dma_size);
-
-		PIPELINE_PARSE_ERR_INV_VAL(((status == 0) &&
-			(dma_size == p->dma_size)), params->name,
-			"dma_src_mask", dma_mask_str);
-	}
-
-	if (p->dma_hash_lb_enabled)
-		PIPELINE_ARG_CHECK((params->n_ports_out > 1),
-			"Parse error in section \"%s\": entry \"lb\" not "
-			"allowed for single output port pipeline",
-			params->name);
-	else
-		PIPELINE_ARG_CHECK(((params->n_ports_in >= params->n_ports_out)
-			&& ((params->n_ports_in % params->n_ports_out) == 0)),
-			"Parse error in section \"%s\": n_ports_in needs to be "
-			"a multiple of n_ports_out (lb mode disabled)",
-			params->name);
-
-	return 0;
-}
-
-static rte_table_hash_op_hash
-get_hash_function(struct pipeline_passthrough *p)
-{
-	switch (p->params.dma_size) {
-
-	case 8: return hash_default_key8;
-	case 16: return hash_default_key16;
-	case 24: return hash_default_key24;
-	case 32: return hash_default_key32;
-	case 40: return hash_default_key40;
-	case 48: return hash_default_key48;
-	case 56: return hash_default_key56;
-	case 64: return hash_default_key64;
-	default: return NULL;
-	}
-}
-
-static int
-pipeline_passthrough_swap_convert(struct pipeline_passthrough *p)
-{
-	uint32_t i;
-
-	p->swap_n_fields = 0;
-
-	for (i = 0; i < p->params.swap_n_fields; i++) {
-		uint32_t offset0 = p->params.swap_field0_offset[i];
-		uint32_t offset1 = p->params.swap_field1_offset[i];
-		uint32_t size = offset1 - offset0;
-		uint32_t j;
-
-		/* Check */
-		if ((offset0 >= offset1) ||
-			(size > PIPELINE_PASSTHROUGH_SWAP_FIELD_SIZE_MAX) ||
-			(p->swap_n_fields >= SWAP_DIM))
-			return -1;
-
-		for (j = 0; j < (size / sizeof(uint64_t)); j++) {
-			p->swap_field0_offset[p->swap_n_fields] = offset0;
-			p->swap_field1_offset[p->swap_n_fields] = offset1;
-			p->swap_field_mask[p->swap_n_fields] = UINT64_MAX;
-			p->swap_n_fields++;
-			offset0 += sizeof(uint64_t);
-			offset1 += sizeof(uint64_t);
-		}
-		if (size % sizeof(uint64_t)) {
-			uint32_t n_bits = (size % sizeof(uint64_t)) * 8;
-
-			p->swap_field0_offset[p->swap_n_fields] = offset0;
-			p->swap_field1_offset[p->swap_n_fields] = offset1;
-			p->swap_field_mask[p->swap_n_fields] =
-				RTE_LEN2MASK(n_bits, uint64_t);
-			p->swap_n_fields++;
-		}
-	}
-
-	return 0;
-}
-
-static void*
-pipeline_passthrough_init(struct pipeline_params *params,
-	__rte_unused void *arg)
-{
-	struct pipeline *p;
-	struct pipeline_passthrough *p_pt;
-	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_passthrough));
-	p = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
-	p_pt = (struct pipeline_passthrough *) p;
-	if (p == NULL)
-		return NULL;
-
-	strcpy(p->name, params->name);
-	p->log_level = params->log_level;
-
-	PLOG(p, HIGH, "Pass-through");
-
-	/* Parse arguments */
-	if (pipeline_passthrough_parse_args(&p_pt->params, params))
-		return NULL;
-	if (pipeline_passthrough_swap_convert(p_pt))
-		return NULL;
-	p_pt->f_hash = get_hash_function(p_pt);
-
-	/* 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;
-		}
-	}
-
-	p->n_ports_in = params->n_ports_in;
-	p->n_ports_out = params->n_ports_out;
-	p->n_tables = p->n_ports_in;
-
-	/*Input ports*/
-	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 = get_port_in_ah(p_pt),
-			.arg_ah = p_pt,
-			.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 */
-	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,
-			.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 */
-	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++) {
-		uint32_t port_out_id = (p_pt->params.dma_hash_lb_enabled == 0) ?
-			(i / (p->n_ports_in / p->n_ports_out)) :
-			0;
-
-		struct rte_pipeline_table_entry default_entry = {
-			.action = RTE_PIPELINE_ACTION_PORT,
-			{.port_id = p->port_out_id[port_out_id]},
-		};
-
-		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;
-}
-
-struct pipeline_be_ops pipeline_passthrough_be_ops = {
-	.f_init = pipeline_passthrough_init,
-	.f_free = pipeline_passthrough_free,
-	.f_run = NULL,
-	.f_timer = pipeline_passthrough_timer,
-};
diff --git a/examples/ip_pipeline/pipeline/pipeline_passthrough_be.h b/examples/ip_pipeline/pipeline/pipeline_passthrough_be.h
deleted file mode 100644
index 94d1d1c..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_passthrough_be.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#ifndef __INCLUDE_PIPELINE_PASSTHROUGH_BE_H__
-#define __INCLUDE_PIPELINE_PASSTHROUGH_BE_H__
-
-#include "pipeline_common_be.h"
-
-#define PIPELINE_PASSTHROUGH_DMA_SIZE_MAX                             64
-
-#ifndef PIPELINE_PASSTHROUGH_SWAP_N_FIELDS_MAX
-#define PIPELINE_PASSTHROUGH_SWAP_N_FIELDS_MAX                        8
-#endif
-
-#ifndef PIPELINE_PASSTHROUGH_SWAP_FIELD_SIZE_MAX
-#define PIPELINE_PASSTHROUGH_SWAP_FIELD_SIZE_MAX                      16
-#endif
-
-struct pipeline_passthrough_params {
-	uint32_t dma_enabled;
-	uint32_t dma_dst_offset;
-	uint32_t dma_src_offset;
-	uint8_t dma_src_mask[PIPELINE_PASSTHROUGH_DMA_SIZE_MAX];
-	uint32_t dma_size;
-
-	uint32_t dma_hash_enabled;
-	uint32_t dma_hash_offset;
-
-	uint32_t dma_hash_lb_enabled;
-
-	uint32_t swap_enabled;
-	uint32_t swap_field0_offset[PIPELINE_PASSTHROUGH_SWAP_N_FIELDS_MAX];
-	uint32_t swap_field1_offset[PIPELINE_PASSTHROUGH_SWAP_N_FIELDS_MAX];
-	uint32_t swap_n_fields;
-};
-
-int
-pipeline_passthrough_parse_args(struct pipeline_passthrough_params *p,
-	struct pipeline_params *params);
-
-extern struct pipeline_be_ops pipeline_passthrough_be_ops;
-
-#endif
-- 
2.9.3

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

* [dpdk-dev] [PATCH v3 11/44] ip_pipeline: remove routing pipeline
  2018-03-16 17:58       ` [dpdk-dev] [PATCH v3 00/44] ip_pipeline: refactoring Jasvinder Singh
                           ` (9 preceding siblings ...)
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 10/44] ip_pipeline: remove passthrough pipeline Jasvinder Singh
@ 2018-03-16 17:58         ` Jasvinder Singh
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 12/44] ip_pipeline: remove flow classification pipeline Jasvinder Singh
                           ` (32 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-16 17:58 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Remove routing pipeline.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/Makefile                      |    2 -
 examples/ip_pipeline/init.c                        |    2 -
 examples/ip_pipeline/meson.build                   |    2 -
 examples/ip_pipeline/pipeline/pipeline_routing.c   | 1613 ----------------
 examples/ip_pipeline/pipeline/pipeline_routing.h   |   71 -
 .../ip_pipeline/pipeline/pipeline_routing_be.c     | 1966 --------------------
 .../ip_pipeline/pipeline/pipeline_routing_be.h     |  283 ---
 7 files changed, 3939 deletions(-)
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_routing.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_routing.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_routing_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_routing_be.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index 089c269..f67cfe6 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -25,8 +25,6 @@ SRCS-y += pipeline_flow_classification_be.c
 SRCS-y += pipeline_flow_classification.c
 SRCS-y += pipeline_flow_actions_be.c
 SRCS-y += pipeline_flow_actions.c
-SRCS-y += pipeline_routing_be.c
-SRCS-y += pipeline_routing.c
 
 # Build using pkg-config variables if possible
 $(shell pkg-config --exists libdpdk)
diff --git a/examples/ip_pipeline/init.c b/examples/ip_pipeline/init.c
index 73b93d7..241d80a 100644
--- a/examples/ip_pipeline/init.c
+++ b/examples/ip_pipeline/init.c
@@ -29,7 +29,6 @@
 #include "pipeline_firewall.h"
 #include "pipeline_flow_classification.h"
 #include "pipeline_flow_actions.h"
-#include "pipeline_routing.h"
 #include "thread_fe.h"
 
 #define APP_NAME_SIZE	32
@@ -1824,7 +1823,6 @@ int app_init(struct app_params *app)
 	app_pipeline_type_register(app, &pipeline_flow_classification);
 	app_pipeline_type_register(app, &pipeline_flow_actions);
 	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/meson.build b/examples/ip_pipeline/meson.build
index 17f4e16..f9eab1b 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -29,6 +29,4 @@ sources = files(
 	'pipeline/pipeline_flow_classification.c',
 	'pipeline/pipeline_master_be.c',
 	'pipeline/pipeline_master.c',
-	'pipeline/pipeline_routing_be.c',
-	'pipeline/pipeline_routing.c',
 )
diff --git a/examples/ip_pipeline/pipeline/pipeline_routing.c b/examples/ip_pipeline/pipeline/pipeline_routing.c
deleted file mode 100644
index 0562c63..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_routing.c
+++ /dev/null
@@ -1,1613 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2016 Intel Corporation
- */
-
-#include <cmdline_parse.h>
-#include <cmdline_parse_num.h>
-#include <cmdline_parse_string.h>
-
-#include "app.h"
-#include "pipeline_common_fe.h"
-#include "pipeline_routing.h"
-#include "parser.h"
-
-struct app_pipeline_routing_route {
-	struct pipeline_routing_route_key key;
-	struct pipeline_routing_route_data data;
-	void *entry_ptr;
-
-	TAILQ_ENTRY(app_pipeline_routing_route) node;
-};
-
-struct app_pipeline_routing_arp_entry {
-	struct pipeline_routing_arp_key key;
-	struct ether_addr macaddr;
-	void *entry_ptr;
-
-	TAILQ_ENTRY(app_pipeline_routing_arp_entry) node;
-};
-
-struct pipeline_routing {
-	/* Parameters */
-	struct app_params *app;
-	uint32_t pipeline_id;
-	uint32_t n_ports_in;
-	uint32_t n_ports_out;
-	struct pipeline_routing_params rp;
-
-	/* Links */
-	uint32_t link_id[PIPELINE_MAX_PORT_OUT];
-
-	/* Routes */
-	TAILQ_HEAD(, app_pipeline_routing_route) routes;
-	uint32_t n_routes;
-
-	uint32_t default_route_present;
-	uint32_t default_route_port_id;
-	void *default_route_entry_ptr;
-
-	/* 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;
-};
-
-static int
-app_pipeline_routing_find_link(struct pipeline_routing *p,
-	uint32_t link_id,
-	uint32_t *port_id)
-{
-	uint32_t i;
-
-	for (i = 0; i < p->n_ports_out; i++)
-		if (p->link_id[i] == link_id) {
-			*port_id = i;
-			return 0;
-		}
-
-	return -1;
-}
-
-static void
-app_pipeline_routing_link_op(__rte_unused struct app_params *app,
-	uint32_t link_id,
-	uint32_t up,
-	void *arg)
-{
-	struct pipeline_routing_route_key key0, key1;
-	struct pipeline_routing *p = arg;
-	struct app_link_params *lp;
-	uint32_t port_id, netmask;
-	int status;
-
-	if (app == NULL)
-		return;
-
-	APP_PARAM_FIND_BY_ID(app->link_params, "LINK", link_id, lp);
-	if (lp == NULL)
-		return;
-
-	status = app_pipeline_routing_find_link(p,
-		link_id,
-		&port_id);
-	if (status)
-		return;
-
-	netmask = (~0U) << (32 - lp->depth);
-
-	/* Local network (directly attached network) */
-	key0.type = PIPELINE_ROUTING_ROUTE_IPV4;
-	key0.key.ipv4.ip = lp->ip & netmask;
-	key0.key.ipv4.depth = lp->depth;
-
-	/* Local termination */
-	key1.type = PIPELINE_ROUTING_ROUTE_IPV4;
-	key1.key.ipv4.ip = lp->ip;
-	key1.key.ipv4.depth = 32;
-
-	if (up) {
-		struct pipeline_routing_route_data data0, data1;
-
-		/* Local network (directly attached network) */
-		memset(&data0, 0, sizeof(data0));
-		data0.flags = PIPELINE_ROUTING_ROUTE_LOCAL |
-			PIPELINE_ROUTING_ROUTE_ARP;
-		if (p->rp.encap == PIPELINE_ROUTING_ENCAP_ETHERNET_QINQ)
-			data0.flags |= PIPELINE_ROUTING_ROUTE_QINQ;
-		if (p->rp.encap == PIPELINE_ROUTING_ENCAP_ETHERNET_MPLS) {
-			data0.flags |= PIPELINE_ROUTING_ROUTE_MPLS;
-			data0.l2.mpls.n_labels = 1;
-		}
-		data0.port_id = port_id;
-
-		if (p->rp.n_arp_entries)
-			app_pipeline_routing_add_route(app,
-				p->pipeline_id,
-				&key0,
-				&data0);
-
-		/* Local termination */
-		memset(&data1, 0, sizeof(data1));
-		data1.flags = PIPELINE_ROUTING_ROUTE_LOCAL |
-			PIPELINE_ROUTING_ROUTE_ARP;
-		if (p->rp.encap == PIPELINE_ROUTING_ENCAP_ETHERNET_QINQ)
-			data1.flags |= PIPELINE_ROUTING_ROUTE_QINQ;
-		if (p->rp.encap == PIPELINE_ROUTING_ENCAP_ETHERNET_MPLS) {
-			data1.flags |= PIPELINE_ROUTING_ROUTE_MPLS;
-			data1.l2.mpls.n_labels = 1;
-		}
-		data1.port_id = p->rp.port_local_dest;
-
-		app_pipeline_routing_add_route(app,
-			p->pipeline_id,
-			&key1,
-			&data1);
-	} else {
-		/* Local network (directly attached network) */
-		if (p->rp.n_arp_entries)
-			app_pipeline_routing_delete_route(app,
-				p->pipeline_id,
-				&key0);
-
-		/* Local termination */
-		app_pipeline_routing_delete_route(app,
-			p->pipeline_id,
-			&key1);
-	}
-}
-
-static int
-app_pipeline_routing_set_link_op(
-	struct app_params *app,
-	struct pipeline_routing *p)
-{
-	uint32_t port_id;
-
-	for (port_id = 0; port_id < p->n_ports_out; port_id++) {
-		struct app_link_params *link;
-		uint32_t link_id;
-		int status;
-
-		link = app_pipeline_track_pktq_out_to_link(app,
-			p->pipeline_id,
-			port_id);
-		if (link == NULL)
-			continue;
-
-		link_id = link - app->link_params;
-		p->link_id[port_id] = link_id;
-
-		status = app_link_set_op(app,
-			link_id,
-			p->pipeline_id,
-			app_pipeline_routing_link_op,
-			(void *) p);
-		if (status)
-			return status;
-	}
-
-	return 0;
-}
-
-static void *
-app_pipeline_routing_init(struct pipeline_params *params,
-	void *arg)
-{
-	struct app_params *app = (struct app_params *) arg;
-	struct pipeline_routing *p;
-	uint32_t pipeline_id, size;
-	int status;
-
-	/* Check input arguments */
-	if ((params == NULL) ||
-		(params->n_ports_in == 0) ||
-		(params->n_ports_out == 0))
-		return NULL;
-
-	APP_PARAM_GET_ID(params, "PIPELINE", pipeline_id);
-
-	/* 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->app = app;
-	p->pipeline_id = pipeline_id;
-	p->n_ports_in = params->n_ports_in;
-	p->n_ports_out = params->n_ports_out;
-
-	status = pipeline_routing_parse_args(&p->rp, params);
-	if (status) {
-		rte_free(p);
-		return NULL;
-	}
-	TAILQ_INIT(&p->routes);
-	p->n_routes = 0;
-
-	TAILQ_INIT(&p->arp_entries);
-	p->n_arp_entries = 0;
-
-	app_pipeline_routing_set_link_op(app, p);
-
-	return p;
-}
-
-static int
-app_pipeline_routing_post_init(void *pipeline)
-{
-	struct pipeline_routing *p = pipeline;
-
-	/* Check input arguments */
-	if (p == NULL)
-		return -1;
-
-	return app_pipeline_routing_set_macaddr(p->app, p->pipeline_id);
-}
-
-static int
-app_pipeline_routing_free(void *pipeline)
-{
-	struct pipeline_routing *p = pipeline;
-
-	/* Check input arguments */
-	if (p == NULL)
-		return -1;
-
-	/* Free resources */
-	while (!TAILQ_EMPTY(&p->routes)) {
-		struct app_pipeline_routing_route *route;
-
-		route = TAILQ_FIRST(&p->routes);
-		TAILQ_REMOVE(&p->routes, route, node);
-		rte_free(route);
-	}
-
-	while (!TAILQ_EMPTY(&p->arp_entries)) {
-		struct app_pipeline_routing_arp_entry *arp_entry;
-
-		arp_entry = TAILQ_FIRST(&p->arp_entries);
-		TAILQ_REMOVE(&p->arp_entries, arp_entry, node);
-		rte_free(arp_entry);
-	}
-
-	rte_free(p);
-	return 0;
-}
-
-static struct app_pipeline_routing_route *
-app_pipeline_routing_find_route(struct pipeline_routing *p,
-		const struct pipeline_routing_route_key *key)
-{
-	struct app_pipeline_routing_route *it, *found;
-
-	found = NULL;
-	TAILQ_FOREACH(it, &p->routes, node) {
-		if ((key->type == it->key.type) &&
-			(key->key.ipv4.ip == it->key.key.ipv4.ip) &&
-			(key->key.ipv4.depth == it->key.key.ipv4.depth)) {
-			found = it;
-			break;
-		}
-	}
-
-	return found;
-}
-
-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;
-
-	found = NULL;
-	TAILQ_FOREACH(it, &p->arp_entries, node) {
-		if ((key->type == it->key.type) &&
-			(key->key.ipv4.port_id == it->key.key.ipv4.port_id) &&
-			(key->key.ipv4.ip == it->key.key.ipv4.ip)) {
-			found = it;
-			break;
-		}
-	}
-
-	return found;
-}
-
-static void
-print_route(const struct app_pipeline_routing_route *route)
-{
-	if (route->key.type == PIPELINE_ROUTING_ROUTE_IPV4) {
-		const struct pipeline_routing_route_key_ipv4 *key =
-				&route->key.key.ipv4;
-
-		printf("IP Prefix = %" PRIu32 ".%" PRIu32
-			".%" PRIu32 ".%" PRIu32 "/%" PRIu32
-			" => (Port = %" PRIu32,
-
-			(key->ip >> 24) & 0xFF,
-			(key->ip >> 16) & 0xFF,
-			(key->ip >> 8) & 0xFF,
-			key->ip & 0xFF,
-
-			key->depth,
-			route->data.port_id);
-
-		if (route->data.flags & PIPELINE_ROUTING_ROUTE_LOCAL)
-			printf(", Local");
-		else if (route->data.flags & PIPELINE_ROUTING_ROUTE_ARP)
-			printf(
-				", Next Hop IP = %" PRIu32 ".%" PRIu32
-				".%" PRIu32 ".%" PRIu32,
-
-				(route->data.ethernet.ip >> 24) & 0xFF,
-				(route->data.ethernet.ip >> 16) & 0xFF,
-				(route->data.ethernet.ip >> 8) & 0xFF,
-				route->data.ethernet.ip & 0xFF);
-		else
-			printf(
-				", Next Hop HWaddress = %02" PRIx32
-				":%02" PRIx32 ":%02" PRIx32
-				":%02" PRIx32 ":%02" PRIx32
-				":%02" PRIx32,
-
-				route->data.ethernet.macaddr.addr_bytes[0],
-				route->data.ethernet.macaddr.addr_bytes[1],
-				route->data.ethernet.macaddr.addr_bytes[2],
-				route->data.ethernet.macaddr.addr_bytes[3],
-				route->data.ethernet.macaddr.addr_bytes[4],
-				route->data.ethernet.macaddr.addr_bytes[5]);
-
-		if (route->data.flags & PIPELINE_ROUTING_ROUTE_QINQ)
-			printf(", QinQ SVLAN = %" PRIu32 " CVLAN = %" PRIu32,
-				route->data.l2.qinq.svlan,
-				route->data.l2.qinq.cvlan);
-
-		if (route->data.flags & PIPELINE_ROUTING_ROUTE_MPLS) {
-			uint32_t i;
-
-			printf(", MPLS labels");
-			for (i = 0; i < route->data.l2.mpls.n_labels; i++)
-				printf(" %" PRIu32,
-					route->data.l2.mpls.labels[i]);
-		}
-
-		printf(")\n");
-	}
-}
-
-static void
-print_arp_entry(const struct app_pipeline_routing_arp_entry *entry)
-{
-	printf("(Port = %" PRIu32 ", IP = %" PRIu32 ".%" PRIu32
-		".%" PRIu32 ".%" PRIu32
-		") => HWaddress = %02" PRIx32 ":%02" PRIx32 ":%02" PRIx32
-		":%02" PRIx32 ":%02" PRIx32 ":%02" PRIx32 "\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->macaddr.addr_bytes[0],
-		entry->macaddr.addr_bytes[1],
-		entry->macaddr.addr_bytes[2],
-		entry->macaddr.addr_bytes[3],
-		entry->macaddr.addr_bytes[4],
-		entry->macaddr.addr_bytes[5]);
-}
-
-static int
-app_pipeline_routing_route_ls(struct app_params *app, uint32_t pipeline_id)
-{
-	struct pipeline_routing *p;
-	struct app_pipeline_routing_route *it;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_routing);
-	if (p == NULL)
-		return -EINVAL;
-
-	TAILQ_FOREACH(it, &p->routes, node)
-		print_route(it);
-
-	if (p->default_route_present)
-		printf("Default route: port %" PRIu32 " (entry ptr = %p)\n",
-				p->default_route_port_id,
-				p->default_route_entry_ptr);
-	else
-		printf("Default: DROP\n");
-
-	return 0;
-}
-
-int
-app_pipeline_routing_add_route(struct app_params *app,
-	uint32_t pipeline_id,
-	struct pipeline_routing_route_key *key,
-	struct pipeline_routing_route_data *data)
-{
-	struct pipeline_routing *p;
-
-	struct pipeline_routing_route_add_msg_req *req;
-	struct pipeline_routing_route_add_msg_rsp *rsp;
-
-	struct app_pipeline_routing_route *entry;
-
-	int new_entry;
-
-	/* Check input arguments */
-	if ((app == NULL) ||
-		(key == NULL) ||
-		(data == NULL))
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_routing);
-	if (p == NULL)
-		return -1;
-
-	switch (key->type) {
-	case PIPELINE_ROUTING_ROUTE_IPV4:
-	{
-		uint32_t depth = key->key.ipv4.depth;
-		uint32_t netmask;
-
-		/* key */
-		if ((depth == 0) || (depth > 32))
-			return -1;
-
-		netmask = (~0U) << (32 - depth);
-		key->key.ipv4.ip &= netmask;
-
-		/* data */
-		if (data->port_id >= p->n_ports_out)
-			return -1;
-
-		/* Valid range of VLAN tags 12 bits */
-		if (data->flags & PIPELINE_ROUTING_ROUTE_QINQ)
-			if ((data->l2.qinq.svlan & 0xF000) ||
-					(data->l2.qinq.cvlan & 0xF000))
-				return -1;
-
-		/* Max number of MPLS labels supported */
-		if (data->flags & PIPELINE_ROUTING_ROUTE_MPLS) {
-			uint32_t i;
-
-			if (data->l2.mpls.n_labels >
-					PIPELINE_ROUTING_MPLS_LABELS_MAX)
-				return -1;
-
-			/* Max MPLS label value 20 bits */
-			for (i = 0; i < data->l2.mpls.n_labels; i++)
-				if (data->l2.mpls.labels[i] & 0xFFF00000)
-					return -1;
-		}
-	}
-	break;
-
-	default:
-		return -1;
-	}
-
-	/* 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;
-	}
-
-	/* Allocate and write request */
-	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_ROUTE_ADD;
-	memcpy(&req->key, key, sizeof(*key));
-	memcpy(&req->data, data, sizeof(*data));
-
-	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL) {
-		if (new_entry)
-			rte_free(entry);
-		return -1;
-	}
-
-	/* Read response and write entry */
-	if (rsp->status ||
-		(rsp->entry_ptr == NULL) ||
-		((new_entry == 0) && (rsp->key_found == 0)) ||
-		((new_entry == 1) && (rsp->key_found == 1))) {
-		app_msg_free(app, rsp);
-		if (new_entry)
-			rte_free(entry);
-		return -1;
-	}
-
-	memcpy(&entry->key, key, sizeof(*key));
-	memcpy(&entry->data, data, sizeof(*data));
-	entry->entry_ptr = rsp->entry_ptr;
-
-	/* Commit entry */
-	if (new_entry) {
-		TAILQ_INSERT_TAIL(&p->routes, entry, node);
-		p->n_routes++;
-	}
-
-	/* 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_route *entry;
-
-	/* Check input arguments */
-	if ((app == NULL) ||
-		(key == NULL))
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_routing);
-	if (p == NULL)
-		return -1;
-
-	switch (key->type) {
-	case PIPELINE_ROUTING_ROUTE_IPV4:
-	{
-		uint32_t depth = key->key.ipv4.depth;
-		uint32_t netmask;
-
-		/* key */
-		if ((depth == 0) || (depth > 32))
-			return -1;
-
-		netmask = (~0U) << (32 - depth);
-		key->key.ipv4.ip &= netmask;
-	}
-	break;
-
-	default:
-		return -1;
-	}
-
-	/* 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_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	/* Read response */
-	if (rsp->status || !rsp->key_found) {
-		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;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_routing);
-	if (p == NULL)
-		return -1;
-
-	if (port_id >= p->n_ports_out)
-		return -1;
-
-	/* 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_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	/* Read response and write route */
-	if (rsp->status || (rsp->entry_ptr == NULL)) {
-		app_msg_free(app, rsp);
-		return -1;
-	}
-
-	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;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_routing);
-	if (p == NULL)
-		return -1;
-
-	/* 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_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	/* Read response and write route */
-	if (rsp->status) {
-		app_msg_free(app, rsp);
-		return -1;
-	}
-
-	/* Commit route */
-	p->default_route_present = 0;
-
-	/* Free response */
-	app_msg_free(app, rsp);
-
-	return 0;
-}
-
-static int
-app_pipeline_routing_arp_ls(struct app_params *app, uint32_t pipeline_id)
-{
-	struct pipeline_routing *p;
-	struct app_pipeline_routing_arp_entry *it;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_routing);
-	if (p == NULL)
-		return -EINVAL;
-
-	TAILQ_FOREACH(it, &p->arp_entries, node)
-		print_arp_entry(it);
-
-	if (p->default_arp_entry_present)
-		printf("Default entry: port %" PRIu32 " (entry ptr = %p)\n",
-				p->default_arp_entry_port_id,
-				p->default_arp_entry_ptr);
-	else
-		printf("Default: DROP\n");
-
-	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;
-
-	/* Check input arguments */
-	if ((app == NULL) ||
-		(key == NULL) ||
-		(macaddr == NULL))
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_routing);
-	if (p == NULL)
-		return -1;
-
-	switch (key->type) {
-	case PIPELINE_ROUTING_ARP_IPV4:
-	{
-		uint32_t port_id = key->key.ipv4.port_id;
-
-		/* key */
-		if (port_id >= p->n_ports_out)
-			return -1;
-	}
-	break;
-
-	default:
-		return -1;
-	}
-
-	/* 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_DEFAULT);
-	if (rsp == NULL) {
-		if (new_entry)
-			rte_free(entry);
-		return -1;
-	}
-
-	/* Read response and write entry */
-	if (rsp->status ||
-		(rsp->entry_ptr == NULL) ||
-		((new_entry == 0) && (rsp->key_found == 0)) ||
-		((new_entry == 1) && (rsp->key_found == 1))) {
-		app_msg_free(app, rsp);
-		if (new_entry)
-			rte_free(entry);
-		return -1;
-	}
-
-	memcpy(&entry->key, key, sizeof(*key));
-	ether_addr_copy(macaddr, &entry->macaddr);
-	entry->entry_ptr = rsp->entry_ptr;
-
-	/* Commit entry */
-	if (new_entry) {
-		TAILQ_INSERT_TAIL(&p->arp_entries, entry, node);
-		p->n_arp_entries++;
-	}
-
-	/* Message buffer free */
-	app_msg_free(app, rsp);
-	return 0;
-}
-
-int
-app_pipeline_routing_delete_arp_entry(struct app_params *app,
-	uint32_t pipeline_id,
-	struct pipeline_routing_arp_key *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;
-
-	/* Check input arguments */
-	if ((app == NULL) ||
-		(key == NULL))
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_routing);
-	if (p == NULL)
-		return -EINVAL;
-
-	switch (key->type) {
-	case PIPELINE_ROUTING_ARP_IPV4:
-	{
-		uint32_t port_id = key->key.ipv4.port_id;
-
-		/* key */
-		if (port_id >= p->n_ports_out)
-			return -1;
-	}
-	break;
-
-	default:
-		return -1;
-	}
-
-	/* 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_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	/* Read response */
-	if (rsp->status || !rsp->key_found) {
-		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;
-}
-
-int
-app_pipeline_routing_add_default_arp_entry(struct app_params *app,
-		uint32_t pipeline_id,
-		uint32_t port_id)
-{
-	struct pipeline_routing *p;
-
-	struct pipeline_routing_arp_add_default_msg_req *req;
-	struct pipeline_routing_arp_add_default_msg_rsp *rsp;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_routing);
-	if (p == NULL)
-		return -1;
-
-	if (port_id >= p->n_ports_out)
-		return -1;
-
-	/* 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_DEFAULT);
-	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;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_routing);
-	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_DEFAULT);
-	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;
-}
-
-int
-app_pipeline_routing_set_macaddr(struct app_params *app,
-	uint32_t pipeline_id)
-{
-	struct app_pipeline_params *p;
-	struct pipeline_routing_set_macaddr_msg_req *req;
-	struct pipeline_routing_set_macaddr_msg_rsp *rsp;
-	uint32_t port_id;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -EINVAL;
-
-	APP_PARAM_FIND_BY_ID(app->pipeline_params, "PIPELINE", pipeline_id, p);
-	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_SET_MACADDR;
-
-	memset(req->macaddr, 0, sizeof(req->macaddr));
-	for (port_id = 0; port_id < p->n_pktq_out; port_id++) {
-		struct app_link_params *link;
-
-		link = app_pipeline_track_pktq_out_to_link(app,
-			pipeline_id,
-			port_id);
-		if (link)
-			req->macaddr[port_id] = link->mac_addr;
-	}
-
-	/* Send request and wait for response */
-	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL)
-		return -ETIMEDOUT;
-
-	/* Read response and write entry */
-	if (rsp->status) {
-		app_msg_free(app, rsp);
-		return rsp->status;
-	}
-
-	/* Free response */
-	app_msg_free(app, rsp);
-
-	return 0;
-}
-
-/*
- * route
- *
- * route add (ARP = ON/OFF, MPLS = ON/OFF, QINQ = ON/OFF):
- *    p <pipelineid> route add <ipaddr> <depth> port <portid> ether <nhmacaddr>
- *    p <pipelineid> route add <ipaddr> <depth> port <portid> ether <nhipaddr>
- *    p <pipelineid> route add <ipaddr> <depth> port <portid> ether <nhmacaddr> qinq <svlan> <cvlan>
- *    p <pipelineid> route add <ipaddr> <depth> port <portid> ether <nhipaddr> qinq <svlan> <cvlan>
- *    p <pipelineid> route add <ipaddr> <depth> port <portid> ether <nhmacaddr> mpls <mpls labels>
- *    p <pipelineid> route add <ipaddr> <depth> port <portid> ether <nhipaddr> mpls <mpls labels>
- *
- * route add default:
- *    p <pipelineid> route add default <portid>
- *
- * route del:
- *    p <pipelineid> route del <ipaddr> <depth>
- *
- * route del default:
- *    p <pipelineid> route del default
- *
- * route ls:
- *    p <pipelineid> route ls
- */
-
-struct cmd_route_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t p;
-	cmdline_fixed_string_t route_string;
-	cmdline_multi_string_t multi_string;
-};
-
-static void
-cmd_route_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_route_result *params = parsed_result;
-	struct app_params *app = data;
-
-	char *tokens[16];
-	uint32_t n_tokens = RTE_DIM(tokens);
-	int status;
-
-	status = parse_tokenize_string(params->multi_string, tokens, &n_tokens);
-	if (status != 0) {
-		printf(CMD_MSG_TOO_MANY_ARGS, "route");
-		return;
-	}
-
-	/* route add */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "add") == 0) &&
-		strcmp(tokens[1], "default")) {
-		struct pipeline_routing_route_key key;
-		struct pipeline_routing_route_data route_data;
-		struct in_addr ipv4, nh_ipv4;
-		struct ether_addr mac_addr;
-		uint32_t depth, port_id, svlan, cvlan, i;
-		uint32_t mpls_labels[PIPELINE_ROUTING_MPLS_LABELS_MAX];
-		uint32_t n_labels = RTE_DIM(mpls_labels);
-
-		memset(&key, 0, sizeof(key));
-		memset(&route_data, 0, sizeof(route_data));
-
-		if (n_tokens < 7) {
-			printf(CMD_MSG_NOT_ENOUGH_ARGS, "route add");
-			return;
-		}
-
-		if (parse_ipv4_addr(tokens[1], &ipv4)) {
-			printf(CMD_MSG_INVALID_ARG, "ipaddr");
-			return;
-		}
-
-		if (parser_read_uint32(&depth, tokens[2])) {
-			printf(CMD_MSG_INVALID_ARG, "depth");
-			return;
-		}
-
-		if (strcmp(tokens[3], "port")) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "port");
-			return;
-		}
-
-		if (parser_read_uint32(&port_id, tokens[4])) {
-			printf(CMD_MSG_INVALID_ARG, "portid");
-			return;
-		}
-
-		if (strcmp(tokens[5], "ether")) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "ether");
-			return;
-		}
-
-		if (parse_mac_addr(tokens[6], &mac_addr)) {
-			if (parse_ipv4_addr(tokens[6], &nh_ipv4)) {
-				printf(CMD_MSG_INVALID_ARG, "nhmacaddr or nhipaddr");
-				return;
-			}
-
-			route_data.flags |= PIPELINE_ROUTING_ROUTE_ARP;
-		}
-
-		if (n_tokens > 7) {
-			if (strcmp(tokens[7], "mpls") == 0) {
-				if (n_tokens != 9) {
-					printf(CMD_MSG_MISMATCH_ARGS, "route add mpls");
-					return;
-				}
-
-				if (parse_mpls_labels(tokens[8], mpls_labels, &n_labels)) {
-					printf(CMD_MSG_INVALID_ARG, "mpls labels");
-					return;
-				}
-
-				route_data.flags |= PIPELINE_ROUTING_ROUTE_MPLS;
-			} else if (strcmp(tokens[7], "qinq") == 0) {
-				if (n_tokens != 10) {
-					printf(CMD_MSG_MISMATCH_ARGS, "route add qinq");
-					return;
-				}
-
-				if (parser_read_uint32(&svlan, tokens[8])) {
-					printf(CMD_MSG_INVALID_ARG, "svlan");
-					return;
-				}
-				if (parser_read_uint32(&cvlan, tokens[9])) {
-					printf(CMD_MSG_INVALID_ARG, "cvlan");
-					return;
-				}
-
-				route_data.flags |= PIPELINE_ROUTING_ROUTE_QINQ;
-			} else {
-				printf(CMD_MSG_ARG_NOT_FOUND, "mpls or qinq");
-				return;
-			}
-		}
-
-		switch (route_data.flags) {
-		case 0:
-			route_data.port_id = port_id;
-			route_data.ethernet.macaddr = mac_addr;
-			break;
-
-		case PIPELINE_ROUTING_ROUTE_ARP:
-			route_data.port_id = port_id;
-			route_data.ethernet.ip = rte_be_to_cpu_32(nh_ipv4.s_addr);
-			break;
-
-		case PIPELINE_ROUTING_ROUTE_MPLS:
-			route_data.port_id = port_id;
-			route_data.ethernet.macaddr = mac_addr;
-			for (i = 0; i < n_labels; i++)
-				route_data.l2.mpls.labels[i] = mpls_labels[i];
-			route_data.l2.mpls.n_labels = n_labels;
-			break;
-
-		case PIPELINE_ROUTING_ROUTE_MPLS | PIPELINE_ROUTING_ROUTE_ARP:
-			route_data.port_id = port_id;
-			route_data.ethernet.ip = rte_be_to_cpu_32(nh_ipv4.s_addr);
-			for (i = 0; i < n_labels; i++)
-				route_data.l2.mpls.labels[i] = mpls_labels[i];
-			route_data.l2.mpls.n_labels = n_labels;
-			break;
-
-		case PIPELINE_ROUTING_ROUTE_QINQ:
-			route_data.port_id = port_id;
-			route_data.ethernet.macaddr = mac_addr;
-			route_data.l2.qinq.svlan = svlan;
-			route_data.l2.qinq.cvlan = cvlan;
-			break;
-
-		case PIPELINE_ROUTING_ROUTE_QINQ | PIPELINE_ROUTING_ROUTE_ARP:
-		default:
-			route_data.port_id = port_id;
-			route_data.ethernet.ip = rte_be_to_cpu_32(nh_ipv4.s_addr);
-			route_data.l2.qinq.svlan = svlan;
-			route_data.l2.qinq.cvlan = cvlan;
-			break;
-		}
-
-		key.type = PIPELINE_ROUTING_ROUTE_IPV4;
-		key.key.ipv4.ip = rte_be_to_cpu_32(ipv4.s_addr);
-		key.key.ipv4.depth = depth;
-
-		status = app_pipeline_routing_add_route(app,
-			params->p,
-			&key,
-			&route_data);
-		if (status != 0)
-			printf(CMD_MSG_FAIL, "route add");
-
-		return;
-	} /* route add */
-
-	/* route add default */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "add") == 0) &&
-		(strcmp(tokens[1], "default") == 0)) {
-		uint32_t port_id;
-
-		if (n_tokens != 3) {
-			printf(CMD_MSG_MISMATCH_ARGS, "route add default");
-			return;
-		}
-
-		if (parser_read_uint32(&port_id, tokens[2])) {
-			printf(CMD_MSG_INVALID_ARG, "portid");
-			return;
-		}
-
-		status = app_pipeline_routing_add_default_route(app,
-			params->p,
-			port_id);
-		if (status != 0)
-			printf(CMD_MSG_FAIL, "route add default");
-
-		return;
-	} /* route add default */
-
-	/* route del*/
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "del") == 0) &&
-		strcmp(tokens[1], "default")) {
-		struct pipeline_routing_route_key key;
-		struct in_addr ipv4;
-		uint32_t depth;
-
-		memset(&key, 0, sizeof(key));
-
-		if (n_tokens != 3) {
-			printf(CMD_MSG_MISMATCH_ARGS, "route del");
-			return;
-		}
-
-		if (parse_ipv4_addr(tokens[1], &ipv4)) {
-			printf(CMD_MSG_INVALID_ARG, "ipaddr");
-			return;
-		}
-
-		if (parser_read_uint32(&depth, tokens[2])) {
-			printf(CMD_MSG_INVALID_ARG, "depth");
-			return;
-		}
-
-		key.type = PIPELINE_ROUTING_ROUTE_IPV4;
-		key.key.ipv4.ip = rte_be_to_cpu_32(ipv4.s_addr);
-		key.key.ipv4.depth = depth;
-
-		status = app_pipeline_routing_delete_route(app, params->p, &key);
-		if (status != 0)
-			printf(CMD_MSG_FAIL, "route del");
-
-		return;
-	} /* route del */
-
-	/* route del default */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "del") == 0) &&
-		(strcmp(tokens[1], "default") == 0)) {
-		if (n_tokens != 2) {
-			printf(CMD_MSG_MISMATCH_ARGS, "route del default");
-			return;
-		}
-
-		status = app_pipeline_routing_delete_default_route(app,
-			params->p);
-		if (status != 0)
-			printf(CMD_MSG_FAIL, "route del default");
-
-		return;
-	} /* route del default */
-
-	/* route ls */
-	if ((n_tokens >= 1) && (strcmp(tokens[0], "ls") == 0)) {
-		if (n_tokens != 1) {
-			printf(CMD_MSG_MISMATCH_ARGS, "route ls");
-			return;
-		}
-
-		status = app_pipeline_routing_route_ls(app, params->p);
-		if (status != 0)
-			printf(CMD_MSG_FAIL, "route ls");
-
-		return;
-	} /* route ls */
-
-	printf(CMD_MSG_MISMATCH_ARGS, "route");
-}
-
-static cmdline_parse_token_string_t cmd_route_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_result, p_string, "p");
-
-static cmdline_parse_token_num_t cmd_route_p =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_result, p, UINT32);
-
-static cmdline_parse_token_string_t cmd_route_route_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_result, route_string, "route");
-
-static cmdline_parse_token_string_t cmd_route_multi_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_result, multi_string,
-	TOKEN_STRING_MULTI);
-
-static cmdline_parse_inst_t cmd_route = {
-	.f = cmd_route_parsed,
-	.data = NULL,
-	.help_str = "route add / add default / del / del default / ls",
-	.tokens = {
-		(void *)&cmd_route_p_string,
-		(void *)&cmd_route_p,
-		(void *)&cmd_route_route_string,
-		(void *)&cmd_route_multi_string,
-		NULL,
-	},
-};
-
-/*
- * arp
- *
- * arp add:
- *    p <pipelineid> arp add <portid> <ipaddr> <macaddr>
- *
- * arp add default:
- *    p <pipelineid> arp add default <portid>
- *
- * arp del:
- *    p <pipelineid> arp del <portid> <ipaddr>
- *
- * arp del default:
- *    p <pipelineid> arp del default
- *
- * arp ls:
- *    p <pipelineid> arp ls
- */
-
-struct cmd_arp_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t p;
-	cmdline_fixed_string_t arp_string;
-	cmdline_multi_string_t multi_string;
-};
-
-static void
-cmd_arp_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_arp_result *params = parsed_result;
-	struct app_params *app = data;
-
-	char *tokens[16];
-	uint32_t n_tokens = RTE_DIM(tokens);
-	int status;
-
-	status = parse_tokenize_string(params->multi_string, tokens, &n_tokens);
-	if (status != 0) {
-		printf(CMD_MSG_TOO_MANY_ARGS, "arp");
-		return;
-	}
-
-	/* arp add */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "add") == 0) &&
-		strcmp(tokens[1], "default")) {
-		struct pipeline_routing_arp_key key;
-		struct in_addr ipv4;
-		struct ether_addr mac_addr;
-		uint32_t port_id;
-
-		memset(&key, 0, sizeof(key));
-
-		if (n_tokens != 4) {
-			printf(CMD_MSG_MISMATCH_ARGS, "arp add");
-			return;
-		}
-
-		if (parser_read_uint32(&port_id, tokens[1])) {
-			printf(CMD_MSG_INVALID_ARG, "portid");
-			return;
-		}
-
-		if (parse_ipv4_addr(tokens[2], &ipv4)) {
-			printf(CMD_MSG_INVALID_ARG, "ipaddr");
-			return;
-		}
-
-		if (parse_mac_addr(tokens[3], &mac_addr)) {
-			printf(CMD_MSG_INVALID_ARG, "macaddr");
-			return;
-		}
-
-		key.type = PIPELINE_ROUTING_ARP_IPV4;
-		key.key.ipv4.port_id = port_id;
-		key.key.ipv4.ip = rte_be_to_cpu_32(ipv4.s_addr);
-
-		status = app_pipeline_routing_add_arp_entry(app,
-			params->p,
-			&key,
-			&mac_addr);
-		if (status != 0)
-			printf(CMD_MSG_FAIL, "arp add");
-
-		return;
-	} /* arp add */
-
-	/* arp add default */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "add") == 0) &&
-		(strcmp(tokens[1], "default") == 0)) {
-		uint32_t port_id;
-
-		if (n_tokens != 3) {
-			printf(CMD_MSG_MISMATCH_ARGS, "arp add default");
-			return;
-		}
-
-		if (parser_read_uint32(&port_id, tokens[2])) {
-			printf(CMD_MSG_INVALID_ARG, "portid");
-			return;
-		}
-
-		status = app_pipeline_routing_add_default_arp_entry(app,
-			params->p,
-			port_id);
-		if (status != 0)
-			printf(CMD_MSG_FAIL, "arp add default");
-
-		return;
-	} /* arp add default */
-
-	/* arp del*/
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "del") == 0) &&
-		strcmp(tokens[1], "default")) {
-		struct pipeline_routing_arp_key key;
-		struct in_addr ipv4;
-		uint32_t port_id;
-
-		memset(&key, 0, sizeof(key));
-
-		if (n_tokens != 3) {
-			printf(CMD_MSG_MISMATCH_ARGS, "arp del");
-			return;
-		}
-
-		if (parser_read_uint32(&port_id, tokens[1])) {
-			printf(CMD_MSG_INVALID_ARG, "portid");
-			return;
-		}
-
-		if (parse_ipv4_addr(tokens[2], &ipv4)) {
-			printf(CMD_MSG_INVALID_ARG, "ipaddr");
-			return;
-		}
-
-		key.type = PIPELINE_ROUTING_ARP_IPV4;
-		key.key.ipv4.ip = rte_be_to_cpu_32(ipv4.s_addr);
-		key.key.ipv4.port_id = port_id;
-
-		status = app_pipeline_routing_delete_arp_entry(app,
-			params->p,
-			&key);
-		if (status != 0)
-			printf(CMD_MSG_FAIL, "arp del");
-
-		return;
-	} /* arp del */
-
-	/* arp del default */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "del") == 0) &&
-		(strcmp(tokens[1], "default") == 0)) {
-			if (n_tokens != 2) {
-				printf(CMD_MSG_MISMATCH_ARGS, "arp del default");
-				return;
-			}
-
-			status = app_pipeline_routing_delete_default_arp_entry(app,
-				params->p);
-			if (status != 0)
-				printf(CMD_MSG_FAIL, "arp del default");
-
-			return;
-	} /* arp del default */
-
-	/* arp ls */
-	if ((n_tokens >= 1) && (strcmp(tokens[0], "ls") == 0)) {
-		if (n_tokens != 1) {
-			printf(CMD_MSG_MISMATCH_ARGS, "arp ls");
-			return;
-		}
-
-		status = app_pipeline_routing_arp_ls(app, params->p);
-		if (status != 0)
-			printf(CMD_MSG_FAIL, "arp ls");
-
-		return;
-	} /* arp ls */
-
-	printf(CMD_MSG_FAIL, "arp");
-}
-
-static cmdline_parse_token_string_t cmd_arp_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_result, p_string, "p");
-
-static cmdline_parse_token_num_t cmd_arp_p =
-	TOKEN_NUM_INITIALIZER(struct cmd_arp_result, p, UINT32);
-
-static cmdline_parse_token_string_t cmd_arp_arp_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_result, arp_string, "arp");
-
-static cmdline_parse_token_string_t cmd_arp_multi_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_result, multi_string,
-	TOKEN_STRING_MULTI);
-
-static cmdline_parse_inst_t cmd_arp = {
-	.f = cmd_arp_parsed,
-	.data = NULL,
-	.help_str = "arp add / add default / del / del default / ls",
-	.tokens = {
-		(void *)&cmd_arp_p_string,
-		(void *)&cmd_arp_p,
-		(void *)&cmd_arp_arp_string,
-		(void *)&cmd_arp_multi_string,
-		NULL,
-	},
-};
-
-static cmdline_parse_ctx_t pipeline_cmds[] = {
-	(cmdline_parse_inst_t *)&cmd_route,
-	(cmdline_parse_inst_t *)&cmd_arp,
-	NULL,
-};
-
-static struct pipeline_fe_ops pipeline_routing_fe_ops = {
-	.f_init = app_pipeline_routing_init,
-	.f_post_init = app_pipeline_routing_post_init,
-	.f_free = app_pipeline_routing_free,
-	.f_track = app_pipeline_track_default,
-	.cmds = pipeline_cmds,
-};
-
-struct pipeline_type pipeline_routing = {
-	.name = "ROUTING",
-	.be_ops = &pipeline_routing_be_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
deleted file mode 100644
index f249295..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_routing.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#ifndef __INCLUDE_PIPELINE_ROUTING_H__
-#define __INCLUDE_PIPELINE_ROUTING_H__
-
-#include "pipeline.h"
-#include "pipeline_routing_be.h"
-
-/*
- * Route
- */
-
-int
-app_pipeline_routing_add_route(struct app_params *app,
-	uint32_t pipeline_id,
-	struct pipeline_routing_route_key *key,
-	struct pipeline_routing_route_data *data);
-
-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);
-
-/*
- * SETTINGS
- */
-int
-app_pipeline_routing_set_macaddr(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_be.c b/examples/ip_pipeline/pipeline/pipeline_routing_be.c
deleted file mode 100644
index 6258a1a..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_routing_be.c
+++ /dev/null
@@ -1,1966 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2016 Intel Corporation
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <rte_common.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_routing_be.h"
-#include "pipeline_actions_common.h"
-#include "parser.h"
-#include "hash_func.h"
-
-#define MPLS_LABEL(label, exp, s, ttl)					\
-	(((((uint64_t) (label)) & 0xFFFFFLLU) << 12) |		\
-	((((uint64_t) (exp)) & 0x7LLU) << 9) |				\
-	((((uint64_t) (s)) & 0x1LLU) << 8) |				\
-	(((uint64_t) (ttl)) & 0xFFLU))
-
-#define RTE_SCHED_PORT_HIERARCHY(subport, pipe,		\
-	traffic_class, queue, color)				\
-	((((uint64_t) (queue)) & 0x3) |                \
-	((((uint64_t) (traffic_class)) & 0x3) << 2) |  \
-	((((uint64_t) (color)) & 0x3) << 4) |          \
-	((((uint64_t) (subport)) & 0xFFFF) << 16) |    \
-	((((uint64_t) (pipe)) & 0xFFFFFFFF) << 32))
-
-
-/* Network Byte Order (NBO) */
-#define SLAB_NBO_MACADDRSRC_ETHERTYPE(macaddr, ethertype)	\
-	(((uint64_t) macaddr) | (((uint64_t) rte_cpu_to_be_16(ethertype)) << 48))
-
-#ifndef PIPELINE_ROUTING_LPM_TABLE_NUMBER_TABLE8s
-#define PIPELINE_ROUTING_LPM_TABLE_NUMBER_TABLE8s 256
-#endif
-
-struct pipeline_routing {
-	struct pipeline p;
-	struct pipeline_routing_params params;
-	pipeline_msg_req_handler custom_handlers[PIPELINE_ROUTING_MSG_REQS];
-	uint64_t macaddr[PIPELINE_MAX_PORT_OUT];
-} __rte_cache_aligned;
-
-/*
- * Message handlers
- */
-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 void *
-pipeline_routing_msg_req_set_macaddr_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,
-	[PIPELINE_ROUTING_MSG_REQ_SET_MACADDR] =
-		pipeline_routing_msg_req_set_macaddr_handler,
-};
-
-/*
- * Routing table
- */
-struct routing_table_entry {
-	struct rte_pipeline_table_entry head;
-	uint32_t flags;
-	uint32_t port_id; /* Output port ID */
-	uint32_t ip; /* Next hop IP address (only valid for remote routes) */
-
-	/* ether_l2 */
-	uint16_t data_offset;
-	uint16_t ether_l2_length;
-	uint64_t slab[4];
-	uint16_t slab_offset[4];
-};
-
-struct layout {
-	uint16_t a;
-	uint32_t b;
-	uint16_t c;
-} __attribute__((__packed__));
-
-#define MACADDR_DST_WRITE(slab_ptr, slab)			\
-{								\
-	struct layout *dst = (struct layout *) (slab_ptr);	\
-	struct layout *src = (struct layout *) &(slab);		\
-								\
-	dst->b = src->b;					\
-	dst->c = src->c;					\
-}
-
-static __rte_always_inline void
-pkt_work_routing(
-	struct rte_mbuf *pkt,
-	struct rte_pipeline_table_entry *table_entry,
-	void *arg,
-	int arp,
-	int qinq,
-	int qinq_sched,
-	int mpls,
-	int mpls_color_mark)
-{
-	struct pipeline_routing *p_rt = arg;
-
-	struct routing_table_entry *entry =
-		(struct routing_table_entry *) table_entry;
-
-	struct ipv4_hdr *ip = (struct ipv4_hdr *)
-		RTE_MBUF_METADATA_UINT8_PTR(pkt, p_rt->params.ip_hdr_offset);
-
-	enum rte_meter_color pkt_color = (enum rte_meter_color)
-		RTE_MBUF_METADATA_UINT32(pkt, p_rt->params.color_offset);
-
-	struct pipeline_routing_arp_key_ipv4 *arp_key =
-		(struct pipeline_routing_arp_key_ipv4 *)
-		RTE_MBUF_METADATA_UINT8_PTR(pkt, p_rt->params.arp_key_offset);
-
-	uint64_t *slab0_ptr, *slab1_ptr, *slab2_ptr, *slab3_ptr, sched;
-	uint32_t ip_da, nh_ip, port_id;
-	uint16_t total_length, data_offset, ether_l2_length;
-
-	/* Read */
-	total_length = rte_bswap16(ip->total_length);
-	ip_da = ip->dst_addr;
-	data_offset = entry->data_offset;
-	ether_l2_length = entry->ether_l2_length;
-	slab0_ptr = RTE_MBUF_METADATA_UINT64_PTR(pkt, entry->slab_offset[0]);
-	slab1_ptr = RTE_MBUF_METADATA_UINT64_PTR(pkt, entry->slab_offset[1]);
-	slab2_ptr = RTE_MBUF_METADATA_UINT64_PTR(pkt, entry->slab_offset[2]);
-	slab3_ptr = RTE_MBUF_METADATA_UINT64_PTR(pkt, entry->slab_offset[3]);
-
-	if (arp) {
-		port_id = entry->port_id;
-		nh_ip = entry->ip;
-		if (entry->flags & PIPELINE_ROUTING_ROUTE_LOCAL)
-			nh_ip = ip_da;
-	}
-
-	/* Compute */
-	total_length += ether_l2_length;
-
-	if (qinq && qinq_sched) {
-		uint32_t dscp = ip->type_of_service >> 2;
-		uint32_t svlan, cvlan, tc, tc_q;
-
-		if (qinq_sched == 1) {
-			uint64_t slab_qinq = rte_bswap64(entry->slab[0]);
-
-			svlan = (slab_qinq >> 48) & 0xFFF;
-			cvlan = (slab_qinq >> 16) & 0xFFF;
-			tc = (dscp >> 2) & 0x3;
-			tc_q = dscp & 0x3;
-		} else {
-			uint32_t ip_src = rte_bswap32(ip->src_addr);
-
-			svlan = 0;
-			cvlan = (ip_src >> 16) & 0xFFF;
-			tc = (ip_src >> 2) & 0x3;
-			tc_q = ip_src & 0x3;
-		}
-		sched = RTE_SCHED_PORT_HIERARCHY(svlan,
-			cvlan,
-			tc,
-			tc_q,
-			e_RTE_METER_GREEN);
-	}
-
-	/* Write */
-	pkt->data_off = data_offset;
-	pkt->data_len = total_length;
-	pkt->pkt_len = total_length;
-
-	if ((qinq == 0) && (mpls == 0)) {
-		*slab0_ptr = entry->slab[0];
-
-		if (arp == 0)
-			MACADDR_DST_WRITE(slab1_ptr, entry->slab[1]);
-	}
-
-	if (qinq) {
-		*slab0_ptr = entry->slab[0];
-		*slab1_ptr = entry->slab[1];
-
-		if (arp == 0)
-			MACADDR_DST_WRITE(slab2_ptr, entry->slab[2]);
-
-		if (qinq_sched) {
-			pkt->hash.sched.lo = sched & 0xFFFFFFFF;
-			pkt->hash.sched.hi = sched >> 32;
-		}
-	}
-
-	if (mpls) {
-		if (mpls_color_mark) {
-			uint64_t mpls_exp = rte_bswap64(
-				(MPLS_LABEL(0, pkt_color, 0, 0) << 32) |
-				MPLS_LABEL(0, pkt_color, 0, 0));
-
-			*slab0_ptr = entry->slab[0] | mpls_exp;
-			*slab1_ptr = entry->slab[1] | mpls_exp;
-			*slab2_ptr = entry->slab[2];
-		} else {
-			*slab0_ptr = entry->slab[0];
-			*slab1_ptr = entry->slab[1];
-			*slab2_ptr = entry->slab[2];
-		}
-
-		if (arp == 0)
-			MACADDR_DST_WRITE(slab3_ptr, entry->slab[3]);
-	}
-
-	if (arp) {
-		arp_key->port_id = port_id;
-		arp_key->ip = nh_ip;
-	}
-}
-
-static __rte_always_inline void
-pkt4_work_routing(
-	struct rte_mbuf **pkts,
-	struct rte_pipeline_table_entry **table_entries,
-	void *arg,
-	int arp,
-	int qinq,
-	int qinq_sched,
-	int mpls,
-	int mpls_color_mark)
-{
-	struct pipeline_routing *p_rt = arg;
-
-	struct routing_table_entry *entry0 =
-		(struct routing_table_entry *) table_entries[0];
-	struct routing_table_entry *entry1 =
-		(struct routing_table_entry *) table_entries[1];
-	struct routing_table_entry *entry2 =
-		(struct routing_table_entry *) table_entries[2];
-	struct routing_table_entry *entry3 =
-		(struct routing_table_entry *) table_entries[3];
-
-	struct ipv4_hdr *ip0 = (struct ipv4_hdr *)
-		RTE_MBUF_METADATA_UINT8_PTR(pkts[0],
-			p_rt->params.ip_hdr_offset);
-	struct ipv4_hdr *ip1 = (struct ipv4_hdr *)
-		RTE_MBUF_METADATA_UINT8_PTR(pkts[1],
-			p_rt->params.ip_hdr_offset);
-	struct ipv4_hdr *ip2 = (struct ipv4_hdr *)
-		RTE_MBUF_METADATA_UINT8_PTR(pkts[2],
-			p_rt->params.ip_hdr_offset);
-	struct ipv4_hdr *ip3 = (struct ipv4_hdr *)
-		RTE_MBUF_METADATA_UINT8_PTR(pkts[3],
-			p_rt->params.ip_hdr_offset);
-
-	enum rte_meter_color pkt0_color = (enum rte_meter_color)
-		RTE_MBUF_METADATA_UINT32(pkts[0], p_rt->params.color_offset);
-	enum rte_meter_color pkt1_color = (enum rte_meter_color)
-		RTE_MBUF_METADATA_UINT32(pkts[1], p_rt->params.color_offset);
-	enum rte_meter_color pkt2_color = (enum rte_meter_color)
-		RTE_MBUF_METADATA_UINT32(pkts[2], p_rt->params.color_offset);
-	enum rte_meter_color pkt3_color = (enum rte_meter_color)
-		RTE_MBUF_METADATA_UINT32(pkts[3], p_rt->params.color_offset);
-
-	struct pipeline_routing_arp_key_ipv4 *arp_key0 =
-		(struct pipeline_routing_arp_key_ipv4 *)
-		RTE_MBUF_METADATA_UINT8_PTR(pkts[0],
-			p_rt->params.arp_key_offset);
-	struct pipeline_routing_arp_key_ipv4 *arp_key1 =
-		(struct pipeline_routing_arp_key_ipv4 *)
-		RTE_MBUF_METADATA_UINT8_PTR(pkts[1],
-			p_rt->params.arp_key_offset);
-	struct pipeline_routing_arp_key_ipv4 *arp_key2 =
-		(struct pipeline_routing_arp_key_ipv4 *)
-		RTE_MBUF_METADATA_UINT8_PTR(pkts[2],
-			p_rt->params.arp_key_offset);
-	struct pipeline_routing_arp_key_ipv4 *arp_key3 =
-		(struct pipeline_routing_arp_key_ipv4 *)
-		RTE_MBUF_METADATA_UINT8_PTR(pkts[3],
-			p_rt->params.arp_key_offset);
-
-	uint64_t *slab0_ptr0, *slab1_ptr0, *slab2_ptr0, *slab3_ptr0;
-	uint64_t *slab0_ptr1, *slab1_ptr1, *slab2_ptr1, *slab3_ptr1;
-	uint64_t *slab0_ptr2, *slab1_ptr2, *slab2_ptr2, *slab3_ptr2;
-	uint64_t *slab0_ptr3, *slab1_ptr3, *slab2_ptr3, *slab3_ptr3;
-	uint64_t sched0, sched1, sched2, sched3;
-
-	uint32_t ip_da0, nh_ip0, port_id0;
-	uint32_t ip_da1, nh_ip1, port_id1;
-	uint32_t ip_da2, nh_ip2, port_id2;
-	uint32_t ip_da3, nh_ip3, port_id3;
-
-	uint16_t total_length0, data_offset0, ether_l2_length0;
-	uint16_t total_length1, data_offset1, ether_l2_length1;
-	uint16_t total_length2, data_offset2, ether_l2_length2;
-	uint16_t total_length3, data_offset3, ether_l2_length3;
-
-	/* Read */
-	total_length0 = rte_bswap16(ip0->total_length);
-	total_length1 = rte_bswap16(ip1->total_length);
-	total_length2 = rte_bswap16(ip2->total_length);
-	total_length3 = rte_bswap16(ip3->total_length);
-
-	ip_da0 = ip0->dst_addr;
-	ip_da1 = ip1->dst_addr;
-	ip_da2 = ip2->dst_addr;
-	ip_da3 = ip3->dst_addr;
-
-	data_offset0 = entry0->data_offset;
-	data_offset1 = entry1->data_offset;
-	data_offset2 = entry2->data_offset;
-	data_offset3 = entry3->data_offset;
-
-	ether_l2_length0 = entry0->ether_l2_length;
-	ether_l2_length1 = entry1->ether_l2_length;
-	ether_l2_length2 = entry2->ether_l2_length;
-	ether_l2_length3 = entry3->ether_l2_length;
-
-	slab0_ptr0 = RTE_MBUF_METADATA_UINT64_PTR(pkts[0],
-		entry0->slab_offset[0]);
-	slab1_ptr0 = RTE_MBUF_METADATA_UINT64_PTR(pkts[0],
-		entry0->slab_offset[1]);
-	slab2_ptr0 = RTE_MBUF_METADATA_UINT64_PTR(pkts[0],
-		entry0->slab_offset[2]);
-	slab3_ptr0 = RTE_MBUF_METADATA_UINT64_PTR(pkts[0],
-		entry0->slab_offset[3]);
-
-	slab0_ptr1 = RTE_MBUF_METADATA_UINT64_PTR(pkts[1],
-		entry1->slab_offset[0]);
-	slab1_ptr1 = RTE_MBUF_METADATA_UINT64_PTR(pkts[1],
-		entry1->slab_offset[1]);
-	slab2_ptr1 = RTE_MBUF_METADATA_UINT64_PTR(pkts[1],
-		entry1->slab_offset[2]);
-	slab3_ptr1 = RTE_MBUF_METADATA_UINT64_PTR(pkts[1],
-		entry1->slab_offset[3]);
-
-	slab0_ptr2 = RTE_MBUF_METADATA_UINT64_PTR(pkts[2],
-		entry2->slab_offset[0]);
-	slab1_ptr2 = RTE_MBUF_METADATA_UINT64_PTR(pkts[2],
-		entry2->slab_offset[1]);
-	slab2_ptr2 = RTE_MBUF_METADATA_UINT64_PTR(pkts[2],
-		entry2->slab_offset[2]);
-	slab3_ptr2 = RTE_MBUF_METADATA_UINT64_PTR(pkts[2],
-		entry2->slab_offset[3]);
-
-	slab0_ptr3 = RTE_MBUF_METADATA_UINT64_PTR(pkts[3],
-		entry3->slab_offset[0]);
-	slab1_ptr3 = RTE_MBUF_METADATA_UINT64_PTR(pkts[3],
-		entry3->slab_offset[1]);
-	slab2_ptr3 = RTE_MBUF_METADATA_UINT64_PTR(pkts[3],
-		entry3->slab_offset[2]);
-	slab3_ptr3 = RTE_MBUF_METADATA_UINT64_PTR(pkts[3],
-		entry3->slab_offset[3]);
-
-	if (arp) {
-		port_id0 = entry0->port_id;
-		nh_ip0 = entry0->ip;
-		if (entry0->flags & PIPELINE_ROUTING_ROUTE_LOCAL)
-			nh_ip0 = ip_da0;
-
-		port_id1 = entry1->port_id;
-		nh_ip1 = entry1->ip;
-		if (entry1->flags & PIPELINE_ROUTING_ROUTE_LOCAL)
-			nh_ip1 = ip_da1;
-
-		port_id2 = entry2->port_id;
-		nh_ip2 = entry2->ip;
-		if (entry2->flags & PIPELINE_ROUTING_ROUTE_LOCAL)
-			nh_ip2 = ip_da2;
-
-		port_id3 = entry3->port_id;
-		nh_ip3 = entry3->ip;
-		if (entry3->flags & PIPELINE_ROUTING_ROUTE_LOCAL)
-			nh_ip3 = ip_da3;
-	}
-
-	/* Compute */
-	total_length0 += ether_l2_length0;
-	total_length1 += ether_l2_length1;
-	total_length2 += ether_l2_length2;
-	total_length3 += ether_l2_length3;
-
-	if (qinq && qinq_sched) {
-		uint32_t dscp0 = ip0->type_of_service >> 2;
-		uint32_t dscp1 = ip1->type_of_service >> 2;
-		uint32_t dscp2 = ip2->type_of_service >> 2;
-		uint32_t dscp3 = ip3->type_of_service >> 2;
-		uint32_t svlan0, cvlan0, tc0, tc_q0;
-		uint32_t svlan1, cvlan1, tc1, tc_q1;
-		uint32_t svlan2, cvlan2, tc2, tc_q2;
-		uint32_t svlan3, cvlan3, tc3, tc_q3;
-
-		if (qinq_sched == 1) {
-			uint64_t slab_qinq0 = rte_bswap64(entry0->slab[0]);
-			uint64_t slab_qinq1 = rte_bswap64(entry1->slab[0]);
-			uint64_t slab_qinq2 = rte_bswap64(entry2->slab[0]);
-			uint64_t slab_qinq3 = rte_bswap64(entry3->slab[0]);
-
-			svlan0 = (slab_qinq0 >> 48) & 0xFFF;
-			svlan1 = (slab_qinq1 >> 48) & 0xFFF;
-			svlan2 = (slab_qinq2 >> 48) & 0xFFF;
-			svlan3 = (slab_qinq3 >> 48) & 0xFFF;
-
-			cvlan0 = (slab_qinq0 >> 16) & 0xFFF;
-			cvlan1 = (slab_qinq1 >> 16) & 0xFFF;
-			cvlan2 = (slab_qinq2 >> 16) & 0xFFF;
-			cvlan3 = (slab_qinq3 >> 16) & 0xFFF;
-
-			tc0 = (dscp0 >> 2) & 0x3;
-			tc1 = (dscp1 >> 2) & 0x3;
-			tc2 = (dscp2 >> 2) & 0x3;
-			tc3 = (dscp3 >> 2) & 0x3;
-
-			tc_q0 = dscp0 & 0x3;
-			tc_q1 = dscp1 & 0x3;
-			tc_q2 = dscp2 & 0x3;
-			tc_q3 = dscp3 & 0x3;
-		} else {
-			uint32_t ip_src0 = rte_bswap32(ip0->src_addr);
-			uint32_t ip_src1 = rte_bswap32(ip1->src_addr);
-			uint32_t ip_src2 = rte_bswap32(ip2->src_addr);
-			uint32_t ip_src3 = rte_bswap32(ip3->src_addr);
-
-			svlan0 = 0;
-			svlan1 = 0;
-			svlan2 = 0;
-			svlan3 = 0;
-
-			cvlan0 = (ip_src0 >> 16) & 0xFFF;
-			cvlan1 = (ip_src1 >> 16) & 0xFFF;
-			cvlan2 = (ip_src2 >> 16) & 0xFFF;
-			cvlan3 = (ip_src3 >> 16) & 0xFFF;
-
-			tc0 = (ip_src0 >> 2) & 0x3;
-			tc1 = (ip_src1 >> 2) & 0x3;
-			tc2 = (ip_src2 >> 2) & 0x3;
-			tc3 = (ip_src3 >> 2) & 0x3;
-
-			tc_q0 = ip_src0 & 0x3;
-			tc_q1 = ip_src1 & 0x3;
-			tc_q2 = ip_src2 & 0x3;
-			tc_q3 = ip_src3 & 0x3;
-		}
-
-		sched0 = RTE_SCHED_PORT_HIERARCHY(svlan0,
-			cvlan0,
-			tc0,
-			tc_q0,
-			e_RTE_METER_GREEN);
-		sched1 = RTE_SCHED_PORT_HIERARCHY(svlan1,
-			cvlan1,
-			tc1,
-			tc_q1,
-			e_RTE_METER_GREEN);
-		sched2 = RTE_SCHED_PORT_HIERARCHY(svlan2,
-			cvlan2,
-			tc2,
-			tc_q2,
-			e_RTE_METER_GREEN);
-		sched3 = RTE_SCHED_PORT_HIERARCHY(svlan3,
-			cvlan3,
-			tc3,
-			tc_q3,
-			e_RTE_METER_GREEN);
-
-	}
-
-	/* Write */
-	pkts[0]->data_off = data_offset0;
-	pkts[1]->data_off = data_offset1;
-	pkts[2]->data_off = data_offset2;
-	pkts[3]->data_off = data_offset3;
-
-	pkts[0]->data_len = total_length0;
-	pkts[1]->data_len = total_length1;
-	pkts[2]->data_len = total_length2;
-	pkts[3]->data_len = total_length3;
-
-	pkts[0]->pkt_len = total_length0;
-	pkts[1]->pkt_len = total_length1;
-	pkts[2]->pkt_len = total_length2;
-	pkts[3]->pkt_len = total_length3;
-
-	if ((qinq == 0) && (mpls == 0)) {
-		*slab0_ptr0 = entry0->slab[0];
-		*slab0_ptr1 = entry1->slab[0];
-		*slab0_ptr2 = entry2->slab[0];
-		*slab0_ptr3 = entry3->slab[0];
-
-		if (arp == 0) {
-			MACADDR_DST_WRITE(slab1_ptr0, entry0->slab[1]);
-			MACADDR_DST_WRITE(slab1_ptr1, entry1->slab[1]);
-			MACADDR_DST_WRITE(slab1_ptr2, entry2->slab[1]);
-			MACADDR_DST_WRITE(slab1_ptr3, entry3->slab[1]);
-		}
-	}
-
-	if (qinq) {
-		*slab0_ptr0 = entry0->slab[0];
-		*slab0_ptr1 = entry1->slab[0];
-		*slab0_ptr2 = entry2->slab[0];
-		*slab0_ptr3 = entry3->slab[0];
-
-		*slab1_ptr0 = entry0->slab[1];
-		*slab1_ptr1 = entry1->slab[1];
-		*slab1_ptr2 = entry2->slab[1];
-		*slab1_ptr3 = entry3->slab[1];
-
-		if (arp == 0) {
-			MACADDR_DST_WRITE(slab2_ptr0, entry0->slab[2]);
-			MACADDR_DST_WRITE(slab2_ptr1, entry1->slab[2]);
-			MACADDR_DST_WRITE(slab2_ptr2, entry2->slab[2]);
-			MACADDR_DST_WRITE(slab2_ptr3, entry3->slab[2]);
-		}
-
-		if (qinq_sched) {
-			pkts[0]->hash.sched.lo = sched0 & 0xFFFFFFFF;
-			pkts[0]->hash.sched.hi = sched0 >> 32;
-			pkts[1]->hash.sched.lo = sched1 & 0xFFFFFFFF;
-			pkts[1]->hash.sched.hi = sched1 >> 32;
-			pkts[2]->hash.sched.lo = sched2 & 0xFFFFFFFF;
-			pkts[2]->hash.sched.hi = sched2 >> 32;
-			pkts[3]->hash.sched.lo = sched3 & 0xFFFFFFFF;
-			pkts[3]->hash.sched.hi = sched3 >> 32;
-		}
-	}
-
-	if (mpls) {
-		if (mpls_color_mark) {
-			uint64_t mpls_exp0 = rte_bswap64(
-				(MPLS_LABEL(0, pkt0_color, 0, 0) << 32) |
-				MPLS_LABEL(0, pkt0_color, 0, 0));
-			uint64_t mpls_exp1 = rte_bswap64(
-				(MPLS_LABEL(0, pkt1_color, 0, 0) << 32) |
-				MPLS_LABEL(0, pkt1_color, 0, 0));
-			uint64_t mpls_exp2 = rte_bswap64(
-				(MPLS_LABEL(0, pkt2_color, 0, 0) << 32) |
-				MPLS_LABEL(0, pkt2_color, 0, 0));
-			uint64_t mpls_exp3 = rte_bswap64(
-				(MPLS_LABEL(0, pkt3_color, 0, 0) << 32) |
-				MPLS_LABEL(0, pkt3_color, 0, 0));
-
-			*slab0_ptr0 = entry0->slab[0] | mpls_exp0;
-			*slab0_ptr1 = entry1->slab[0] | mpls_exp1;
-			*slab0_ptr2 = entry2->slab[0] | mpls_exp2;
-			*slab0_ptr3 = entry3->slab[0] | mpls_exp3;
-
-			*slab1_ptr0 = entry0->slab[1] | mpls_exp0;
-			*slab1_ptr1 = entry1->slab[1] | mpls_exp1;
-			*slab1_ptr2 = entry2->slab[1] | mpls_exp2;
-			*slab1_ptr3 = entry3->slab[1] | mpls_exp3;
-
-			*slab2_ptr0 = entry0->slab[2];
-			*slab2_ptr1 = entry1->slab[2];
-			*slab2_ptr2 = entry2->slab[2];
-			*slab2_ptr3 = entry3->slab[2];
-		} else {
-			*slab0_ptr0 = entry0->slab[0];
-			*slab0_ptr1 = entry1->slab[0];
-			*slab0_ptr2 = entry2->slab[0];
-			*slab0_ptr3 = entry3->slab[0];
-
-			*slab1_ptr0 = entry0->slab[1];
-			*slab1_ptr1 = entry1->slab[1];
-			*slab1_ptr2 = entry2->slab[1];
-			*slab1_ptr3 = entry3->slab[1];
-
-			*slab2_ptr0 = entry0->slab[2];
-			*slab2_ptr1 = entry1->slab[2];
-			*slab2_ptr2 = entry2->slab[2];
-			*slab2_ptr3 = entry3->slab[2];
-		}
-
-		if (arp == 0) {
-			MACADDR_DST_WRITE(slab3_ptr0, entry0->slab[3]);
-			MACADDR_DST_WRITE(slab3_ptr1, entry1->slab[3]);
-			MACADDR_DST_WRITE(slab3_ptr2, entry2->slab[3]);
-			MACADDR_DST_WRITE(slab3_ptr3, entry3->slab[3]);
-		}
-	}
-
-	if (arp) {
-		arp_key0->port_id = port_id0;
-		arp_key1->port_id = port_id1;
-		arp_key2->port_id = port_id2;
-		arp_key3->port_id = port_id3;
-
-		arp_key0->ip = nh_ip0;
-		arp_key1->ip = nh_ip1;
-		arp_key2->ip = nh_ip2;
-		arp_key3->ip = nh_ip3;
-	}
-}
-
-#define PKT_WORK_ROUTING_ETHERNET(arp)				\
-static inline void						\
-pkt_work_routing_ether_arp##arp(				\
-	struct rte_mbuf *pkt,					\
-	struct rte_pipeline_table_entry *table_entry,		\
-	void *arg)						\
-{								\
-	pkt_work_routing(pkt, table_entry, arg, arp, 0, 0, 0, 0);\
-}
-
-#define PKT4_WORK_ROUTING_ETHERNET(arp)				\
-static inline void						\
-pkt4_work_routing_ether_arp##arp(				\
-	struct rte_mbuf **pkts,					\
-	struct rte_pipeline_table_entry **table_entries,	\
-	void *arg)						\
-{								\
-	pkt4_work_routing(pkts, table_entries, arg, arp, 0, 0, 0, 0);\
-}
-
-#define routing_table_ah_hit_ether(arp)				\
-PKT_WORK_ROUTING_ETHERNET(arp)					\
-PKT4_WORK_ROUTING_ETHERNET(arp)					\
-PIPELINE_TABLE_AH_HIT(routing_table_ah_hit_ether_arp##arp,	\
-	pkt_work_routing_ether_arp##arp,			\
-	pkt4_work_routing_ether_arp##arp)
-
-routing_table_ah_hit_ether(0)
-routing_table_ah_hit_ether(1)
-
-#define PKT_WORK_ROUTING_ETHERNET_QINQ(sched, arp)		\
-static inline void						\
-pkt_work_routing_ether_qinq_sched##sched##_arp##arp(		\
-	struct rte_mbuf *pkt,					\
-	struct rte_pipeline_table_entry *table_entry,		\
-	void *arg)						\
-{								\
-	pkt_work_routing(pkt, table_entry, arg, arp, 1, sched, 0, 0);\
-}
-
-#define PKT4_WORK_ROUTING_ETHERNET_QINQ(sched, arp)		\
-static inline void						\
-pkt4_work_routing_ether_qinq_sched##sched##_arp##arp(		\
-	struct rte_mbuf **pkts,					\
-	struct rte_pipeline_table_entry **table_entries,	\
-	void *arg)						\
-{								\
-	pkt4_work_routing(pkts, table_entries, arg, arp, 1, sched, 0, 0);\
-}
-
-#define routing_table_ah_hit_ether_qinq(sched, arp)		\
-PKT_WORK_ROUTING_ETHERNET_QINQ(sched, arp)			\
-PKT4_WORK_ROUTING_ETHERNET_QINQ(sched, arp)			\
-PIPELINE_TABLE_AH_HIT(routing_table_ah_hit_ether_qinq_sched##sched##_arp##arp,\
-	pkt_work_routing_ether_qinq_sched##sched##_arp##arp,	\
-	pkt4_work_routing_ether_qinq_sched##sched##_arp##arp)
-
-routing_table_ah_hit_ether_qinq(0, 0)
-routing_table_ah_hit_ether_qinq(1, 0)
-routing_table_ah_hit_ether_qinq(2, 0)
-routing_table_ah_hit_ether_qinq(0, 1)
-routing_table_ah_hit_ether_qinq(1, 1)
-routing_table_ah_hit_ether_qinq(2, 1)
-
-#define PKT_WORK_ROUTING_ETHERNET_MPLS(color, arp)		\
-static inline void						\
-pkt_work_routing_ether_mpls_color##color##_arp##arp(		\
-	struct rte_mbuf *pkt,					\
-	struct rte_pipeline_table_entry *table_entry,		\
-	void *arg)						\
-{								\
-	pkt_work_routing(pkt, table_entry, arg, arp, 0, 0, 1, color);\
-}
-
-#define PKT4_WORK_ROUTING_ETHERNET_MPLS(color, arp)		\
-static inline void						\
-pkt4_work_routing_ether_mpls_color##color##_arp##arp(		\
-	struct rte_mbuf **pkts,					\
-	struct rte_pipeline_table_entry **table_entries,	\
-	void *arg)						\
-{								\
-	pkt4_work_routing(pkts, table_entries, arg, arp, 0, 0, 1, color);\
-}
-
-#define routing_table_ah_hit_ether_mpls(color, arp)		\
-PKT_WORK_ROUTING_ETHERNET_MPLS(color, arp)			\
-PKT4_WORK_ROUTING_ETHERNET_MPLS(color, arp)			\
-PIPELINE_TABLE_AH_HIT(routing_table_ah_hit_ether_mpls_color##color##_arp##arp,\
-	pkt_work_routing_ether_mpls_color##color##_arp##arp,	\
-	pkt4_work_routing_ether_mpls_color##color##_arp##arp)
-
-routing_table_ah_hit_ether_mpls(0, 0)
-routing_table_ah_hit_ether_mpls(1, 0)
-routing_table_ah_hit_ether_mpls(0, 1)
-routing_table_ah_hit_ether_mpls(1, 1)
-
-static rte_pipeline_table_action_handler_hit
-get_routing_table_ah_hit(struct pipeline_routing *p)
-{
-	if (p->params.dbg_ah_disable)
-		return NULL;
-
-	switch (p->params.encap) {
-	case PIPELINE_ROUTING_ENCAP_ETHERNET:
-		return (p->params.n_arp_entries) ?
-			routing_table_ah_hit_ether_arp1 :
-			routing_table_ah_hit_ether_arp0;
-
-	case PIPELINE_ROUTING_ENCAP_ETHERNET_QINQ:
-		if (p->params.n_arp_entries)
-			switch (p->params.qinq_sched) {
-			case 0:
-				return routing_table_ah_hit_ether_qinq_sched0_arp1;
-			case 1:
-				return routing_table_ah_hit_ether_qinq_sched1_arp1;
-			case 2:
-				return routing_table_ah_hit_ether_qinq_sched2_arp1;
-			default:
-				return NULL;
-			}
-		 else
-			switch (p->params.qinq_sched) {
-			case 0:
-				return routing_table_ah_hit_ether_qinq_sched0_arp0;
-			case 1:
-				return routing_table_ah_hit_ether_qinq_sched1_arp0;
-			case 2:
-				return routing_table_ah_hit_ether_qinq_sched2_arp0;
-			default:
-				return NULL;
-			}
-
-	case PIPELINE_ROUTING_ENCAP_ETHERNET_MPLS:
-		if (p->params.n_arp_entries)
-			if (p->params.mpls_color_mark)
-				return routing_table_ah_hit_ether_mpls_color1_arp1;
-			else
-				return routing_table_ah_hit_ether_mpls_color0_arp1;
-		else
-			if (p->params.mpls_color_mark)
-				return routing_table_ah_hit_ether_mpls_color1_arp0;
-			else
-				return routing_table_ah_hit_ether_mpls_color0_arp0;
-
-	default:
-		return NULL;
-	}
-}
-
-/*
- * ARP table
- */
-struct arp_table_entry {
-	struct rte_pipeline_table_entry head;
-	uint64_t macaddr;
-};
-
-/**
- * ARP table AH
- */
-static inline void
-pkt_work_arp(
-	struct rte_mbuf *pkt,
-	struct rte_pipeline_table_entry *table_entry,
-	__rte_unused void *arg)
-{
-	struct arp_table_entry *entry = (struct arp_table_entry *) table_entry;
-
-	/* Read */
-	uint64_t macaddr_dst = entry->macaddr;
-	uint64_t *slab_ptr = (uint64_t *) ((char *) pkt->buf_addr +
-		(pkt->data_off - 2));
-
-	/* Compute */
-
-	/* Write */
-	MACADDR_DST_WRITE(slab_ptr, macaddr_dst);
-}
-
-static inline void
-pkt4_work_arp(
-	struct rte_mbuf **pkts,
-	struct rte_pipeline_table_entry **table_entries,
-	__rte_unused void *arg)
-{
-	struct arp_table_entry *entry0 =
-		(struct arp_table_entry *) table_entries[0];
-	struct arp_table_entry *entry1 =
-		(struct arp_table_entry *) table_entries[1];
-	struct arp_table_entry *entry2 =
-		(struct arp_table_entry *) table_entries[2];
-	struct arp_table_entry *entry3 =
-		(struct arp_table_entry *) table_entries[3];
-
-	/* Read */
-	uint64_t macaddr_dst0 = entry0->macaddr;
-	uint64_t macaddr_dst1 = entry1->macaddr;
-	uint64_t macaddr_dst2 = entry2->macaddr;
-	uint64_t macaddr_dst3 = entry3->macaddr;
-
-	uint64_t *slab_ptr0 = (uint64_t *) ((char *) pkts[0]->buf_addr +
-		(pkts[0]->data_off - 2));
-	uint64_t *slab_ptr1 = (uint64_t *) ((char *) pkts[1]->buf_addr +
-		(pkts[1]->data_off - 2));
-	uint64_t *slab_ptr2 = (uint64_t *) ((char *) pkts[2]->buf_addr +
-		(pkts[2]->data_off - 2));
-	uint64_t *slab_ptr3 = (uint64_t *) ((char *) pkts[3]->buf_addr +
-		(pkts[3]->data_off - 2));
-
-	/* Compute */
-
-	/* Write */
-	MACADDR_DST_WRITE(slab_ptr0, macaddr_dst0);
-	MACADDR_DST_WRITE(slab_ptr1, macaddr_dst1);
-	MACADDR_DST_WRITE(slab_ptr2, macaddr_dst2);
-	MACADDR_DST_WRITE(slab_ptr3, macaddr_dst3);
-}
-
-PIPELINE_TABLE_AH_HIT(arp_table_ah_hit,
-	pkt_work_arp,
-	pkt4_work_arp);
-
-static rte_pipeline_table_action_handler_hit
-get_arp_table_ah_hit(struct pipeline_routing *p)
-{
-	if (p->params.dbg_ah_disable)
-		return NULL;
-
-	return arp_table_ah_hit;
-}
-
-/*
- * Argument parsing
- */
-int
-pipeline_routing_parse_args(struct pipeline_routing_params *p,
-	struct pipeline_params *params)
-{
-	uint32_t n_routes_present = 0;
-	uint32_t port_local_dest_present = 0;
-	uint32_t encap_present = 0;
-	uint32_t qinq_sched_present = 0;
-	uint32_t mpls_color_mark_present = 0;
-	uint32_t n_arp_entries_present = 0;
-	uint32_t ip_hdr_offset_present = 0;
-	uint32_t arp_key_offset_present = 0;
-	uint32_t color_offset_present = 0;
-	uint32_t dbg_ah_disable_present = 0;
-	uint32_t i;
-
-	/* default values */
-	p->n_routes = PIPELINE_ROUTING_N_ROUTES_DEFAULT;
-	p->port_local_dest = params->n_ports_out - 1;
-	p->encap = PIPELINE_ROUTING_ENCAP_ETHERNET;
-	p->qinq_sched = 0;
-	p->mpls_color_mark = 0;
-	p->n_arp_entries = 0;
-	p->dbg_ah_disable = 0;
-
-	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) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				n_routes_present == 0, params->name,
-				arg_name);
-			n_routes_present = 1;
-
-			status = parser_read_uint32(&p->n_routes,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL(((status != -EINVAL) &&
-				(p->n_routes != 0)), params->name,
-				arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			continue;
-		}
-		/* port_local_dest */
-		if (strcmp(arg_name, "port_local_dest") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				port_local_dest_present == 0, params->name,
-				arg_name);
-			port_local_dest_present = 1;
-
-			status = parser_read_uint32(&p->port_local_dest,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL(((status == 0) &&
-				(p->port_local_dest < params->n_ports_out)),
-				params->name, arg_name, arg_value);
-
-			continue;
-		}
-
-		/* encap */
-		if (strcmp(arg_name, "encap") == 0) {
-			PIPELINE_PARSE_ERR_DUPLICATE(encap_present == 0,
-				params->name, arg_name);
-			encap_present = 1;
-
-			/* ethernet */
-			if (strcmp(arg_value, "ethernet") == 0) {
-				p->encap = PIPELINE_ROUTING_ENCAP_ETHERNET;
-				continue;
-			}
-
-			/* ethernet_qinq */
-			if (strcmp(arg_value, "ethernet_qinq") == 0) {
-				p->encap = PIPELINE_ROUTING_ENCAP_ETHERNET_QINQ;
-				continue;
-			}
-
-			/* ethernet_mpls */
-			if (strcmp(arg_value, "ethernet_mpls") == 0) {
-				p->encap = PIPELINE_ROUTING_ENCAP_ETHERNET_MPLS;
-				continue;
-			}
-
-			/* any other */
-			PIPELINE_PARSE_ERR_INV_VAL(0, params->name,
-				arg_name, arg_value);
-		}
-
-		/* qinq_sched */
-		if (strcmp(arg_name, "qinq_sched") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				qinq_sched_present == 0, params->name,
-				arg_name);
-			qinq_sched_present = 1;
-
-			status = parser_read_arg_bool(arg_value);
-			if (status == -EINVAL) {
-				if (strcmp(arg_value, "test") == 0) {
-					p->qinq_sched = 2;
-					continue;
-				}
-			} else {
-				p->qinq_sched = status;
-				continue;
-			}
-
-			PIPELINE_PARSE_ERR_INV_VAL(0, params->name,
-				arg_name, arg_value);
-		}
-
-		/* mpls_color_mark */
-		if (strcmp(arg_name, "mpls_color_mark") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				mpls_color_mark_present == 0,
-				params->name, arg_name);
-			mpls_color_mark_present = 1;
-
-
-			status = parser_read_arg_bool(arg_value);
-			if (status >= 0) {
-				p->mpls_color_mark = status;
-				continue;
-			}
-
-			PIPELINE_PARSE_ERR_INV_VAL(0, params->name,
-				arg_name, arg_value);
-		}
-
-		/* n_arp_entries */
-		if (strcmp(arg_name, "n_arp_entries") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				n_arp_entries_present == 0, params->name,
-				arg_name);
-			n_arp_entries_present = 1;
-
-			status = parser_read_uint32(&p->n_arp_entries,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			continue;
-		}
-
-		/* ip_hdr_offset */
-		if (strcmp(arg_name, "ip_hdr_offset") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				ip_hdr_offset_present == 0, params->name,
-				arg_name);
-			ip_hdr_offset_present = 1;
-
-			status = parser_read_uint32(&p->ip_hdr_offset,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			continue;
-		}
-
-		/* arp_key_offset */
-		if (strcmp(arg_name, "arp_key_offset") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				arp_key_offset_present == 0, params->name,
-				arg_name);
-			arp_key_offset_present = 1;
-
-			status = parser_read_uint32(&p->arp_key_offset,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			continue;
-		}
-
-		/* color_offset */
-		if (strcmp(arg_name, "color_offset") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				color_offset_present == 0, params->name,
-				arg_name);
-			color_offset_present = 1;
-
-			status = parser_read_uint32(&p->color_offset,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			continue;
-		}
-
-		/* debug */
-		if (strcmp(arg_name, "dbg_ah_disable") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				dbg_ah_disable_present == 0, params->name,
-				arg_name);
-			dbg_ah_disable_present = 1;
-
-			status = parser_read_arg_bool(arg_value);
-			if (status >= 0) {
-				p->dbg_ah_disable = status;
-				continue;
-			}
-
-			PIPELINE_PARSE_ERR_INV_VAL(0, params->name,
-				arg_name, arg_value);
-
-			continue;
-		}
-
-		/* any other */
-		PIPELINE_PARSE_ERR_INV_ENT(0, params->name, arg_name);
-	}
-
-	/* Check that mandatory arguments are present */
-	PIPELINE_PARSE_ERR_MANDATORY(ip_hdr_offset_present, params->name,
-		"ip_hdr_offset");
-
-	/* Check relations between arguments */
-	switch (p->encap) {
-	case PIPELINE_ROUTING_ENCAP_ETHERNET:
-		PIPELINE_ARG_CHECK((!p->qinq_sched), "Parse error in "
-			"section \"%s\": encap = ethernet, therefore "
-			"qinq_sched = yes/test is not allowed",
-			params->name);
-		PIPELINE_ARG_CHECK((!p->mpls_color_mark), "Parse error "
-			"in section \"%s\": encap = ethernet, therefore "
-			"mpls_color_mark = yes is not allowed",
-			params->name);
-		PIPELINE_ARG_CHECK((!color_offset_present), "Parse error "
-			"in section \"%s\": encap = ethernet, therefore "
-			"color_offset is not allowed",
-			params->name);
-		break;
-
-	case PIPELINE_ROUTING_ENCAP_ETHERNET_QINQ:
-		PIPELINE_ARG_CHECK((!p->mpls_color_mark), "Parse error "
-			"in section \"%s\": encap = ethernet_qinq, "
-			"therefore mpls_color_mark = yes is not allowed",
-			params->name);
-		PIPELINE_ARG_CHECK((!color_offset_present), "Parse error "
-			"in section \"%s\": encap = ethernet_qinq, "
-			"therefore color_offset is not allowed",
-			params->name);
-		break;
-
-	case PIPELINE_ROUTING_ENCAP_ETHERNET_MPLS:
-		PIPELINE_ARG_CHECK((!p->qinq_sched), "Parse error in "
-			"section \"%s\": encap = ethernet_mpls, therefore "
-			"qinq_sched  = yes/test is not allowed",
-			params->name);
-		break;
-	}
-
-	PIPELINE_ARG_CHECK((!(p->n_arp_entries &&
-		(!arp_key_offset_present))), "Parse error in section "
-			"\"%s\": n_arp_entries is set while "
-			"arp_key_offset is not set", params->name);
-
-	PIPELINE_ARG_CHECK((!((p->n_arp_entries == 0) &&
-		arp_key_offset_present)), "Parse error in section "
-			"\"%s\": arp_key_offset present while "
-			"n_arp_entries is not set", params->name);
-
-	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);
-	p->log_level = params->log_level;
-
-	PLOG(p, HIGH, "Routing");
-
-	/* Parse arguments */
-	if (pipeline_routing_parse_args(&p_rt->params, 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,
-			.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 = {
-			.name = p->name,
-			.n_rules = p_rt->params.n_routes,
-			.number_tbl8s = PIPELINE_ROUTING_LPM_TABLE_NUMBER_TABLE8s,
-			.flags = 0,
-			.entry_unique_size = sizeof(struct routing_table_entry),
-			.offset = p_rt->params.ip_hdr_offset +
-				__builtin_offsetof(struct ipv4_hdr, dst_addr),
-		};
-
-		struct rte_pipeline_table_params table_params = {
-				.ops = &rte_table_lpm_ops,
-				.arg_create = &table_lpm_params,
-				.f_action_hit = get_routing_table_ah_hit(p_rt),
-				.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->params.n_arp_entries) {
-		struct rte_table_hash_params table_arp_params = {
-			.name = p->name,
-			.key_size = 8,
-			.key_offset = p_rt->params.arp_key_offset,
-			.key_mask = NULL,
-			.n_keys = p_rt->params.n_arp_entries,
-			.n_buckets =
-				rte_align32pow2(p_rt->params.n_arp_entries / 4),
-			.f_hash = hash_default_key8,
-			.seed = 0,
-		};
-
-		struct rte_pipeline_table_params table_params = {
-			.ops = &rte_table_hash_key8_ext_ops,
-			.arg_create = &table_arp_params,
-			.f_action_hit = get_arp_table_ah_hit(p_rt),
-			.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_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 *p_rt = (struct pipeline_routing *) p;
-	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_arp0 = {
-		.head = {
-			.action = RTE_PIPELINE_ACTION_PORT,
-			{.port_id = p->port_out_id[req->data.port_id]},
-		},
-
-		.flags = req->data.flags,
-		.port_id = req->data.port_id,
-		.ip = 0,
-		.data_offset = 0,
-		.ether_l2_length = 0,
-		.slab = {0},
-		.slab_offset = {0},
-	};
-
-	struct routing_table_entry entry_arp1 = {
-		.head = {
-			.action = RTE_PIPELINE_ACTION_TABLE,
-			{.table_id = p->table_id[1]},
-		},
-
-		.flags = req->data.flags,
-		.port_id = req->data.port_id,
-		.ip = rte_bswap32(req->data.ethernet.ip),
-		.data_offset = 0,
-		.ether_l2_length = 0,
-		.slab = {0},
-		.slab_offset = {0},
-	};
-
-	struct rte_pipeline_table_entry *entry = (p_rt->params.n_arp_entries) ?
-		(struct rte_pipeline_table_entry *) &entry_arp1 :
-		(struct rte_pipeline_table_entry *) &entry_arp0;
-
-	if ((req->key.type != PIPELINE_ROUTING_ROUTE_IPV4) ||
-		((p_rt->params.n_arp_entries == 0) &&
-			(req->data.flags & PIPELINE_ROUTING_ROUTE_ARP)) ||
-		(p_rt->params.n_arp_entries &&
-			((req->data.flags & PIPELINE_ROUTING_ROUTE_ARP) == 0)) ||
-		((p_rt->params.encap != PIPELINE_ROUTING_ENCAP_ETHERNET_QINQ) &&
-			(req->data.flags & PIPELINE_ROUTING_ROUTE_QINQ)) ||
-		((p_rt->params.encap == PIPELINE_ROUTING_ENCAP_ETHERNET_QINQ) &&
-			((req->data.flags & PIPELINE_ROUTING_ROUTE_QINQ) == 0)) ||
-		((p_rt->params.encap != PIPELINE_ROUTING_ENCAP_ETHERNET_MPLS) &&
-			(req->data.flags & PIPELINE_ROUTING_ROUTE_MPLS)) ||
-		((p_rt->params.encap == PIPELINE_ROUTING_ENCAP_ETHERNET_MPLS) &&
-			((req->data.flags & PIPELINE_ROUTING_ROUTE_MPLS) == 0))) {
-		rsp->status = -1;
-		return rsp;
-	}
-
-	/* Ether - ARP off */
-	if ((p_rt->params.encap == PIPELINE_ROUTING_ENCAP_ETHERNET) &&
-		(p_rt->params.n_arp_entries == 0)) {
-		uint64_t macaddr_src = p_rt->macaddr[req->data.port_id];
-		uint64_t macaddr_dst;
-		uint64_t ethertype = ETHER_TYPE_IPv4;
-
-		macaddr_dst = *((uint64_t *)&(req->data.ethernet.macaddr));
-		macaddr_dst = rte_bswap64(macaddr_dst << 16);
-
-		entry_arp0.slab[0] =
-			SLAB_NBO_MACADDRSRC_ETHERTYPE(macaddr_src, ethertype);
-		entry_arp0.slab_offset[0] = p_rt->params.ip_hdr_offset - 8;
-
-		entry_arp0.slab[1] = rte_bswap64(macaddr_dst);
-		entry_arp0.slab_offset[1] = p_rt->params.ip_hdr_offset - 2 * 8;
-
-		entry_arp0.data_offset = entry_arp0.slab_offset[1] + 2
-			- sizeof(struct rte_mbuf);
-		entry_arp0.ether_l2_length = 14;
-	}
-
-	/* Ether - ARP on */
-	if ((p_rt->params.encap == PIPELINE_ROUTING_ENCAP_ETHERNET) &&
-		p_rt->params.n_arp_entries) {
-		uint64_t macaddr_src = p_rt->macaddr[req->data.port_id];
-		uint64_t ethertype = ETHER_TYPE_IPv4;
-
-		entry_arp1.slab[0] =
-			SLAB_NBO_MACADDRSRC_ETHERTYPE(macaddr_src, ethertype);
-		entry_arp1.slab_offset[0] = p_rt->params.ip_hdr_offset - 8;
-
-		entry_arp1.data_offset = entry_arp1.slab_offset[0] - 6
-			- sizeof(struct rte_mbuf);
-		entry_arp1.ether_l2_length = 14;
-	}
-
-	/* Ether QinQ - ARP off */
-	if ((p_rt->params.encap == PIPELINE_ROUTING_ENCAP_ETHERNET_QINQ) &&
-		(p_rt->params.n_arp_entries == 0)) {
-		uint64_t macaddr_src = p_rt->macaddr[req->data.port_id];
-		uint64_t macaddr_dst;
-		uint64_t ethertype_ipv4 = ETHER_TYPE_IPv4;
-		uint64_t ethertype_vlan = 0x8100;
-		uint64_t ethertype_qinq = 0x9100;
-		uint64_t svlan = req->data.l2.qinq.svlan;
-		uint64_t cvlan = req->data.l2.qinq.cvlan;
-
-		macaddr_dst = *((uint64_t *)&(req->data.ethernet.macaddr));
-		macaddr_dst = rte_bswap64(macaddr_dst << 16);
-
-		entry_arp0.slab[0] = rte_bswap64((svlan << 48) |
-			(ethertype_vlan << 32) |
-			(cvlan << 16) |
-			ethertype_ipv4);
-		entry_arp0.slab_offset[0] = p_rt->params.ip_hdr_offset - 8;
-
-		entry_arp0.slab[1] =
-			SLAB_NBO_MACADDRSRC_ETHERTYPE(macaddr_src, ethertype_qinq);
-		entry_arp0.slab_offset[1] = p_rt->params.ip_hdr_offset - 2 * 8;
-
-		entry_arp0.slab[2] = rte_bswap64(macaddr_dst);
-		entry_arp0.slab_offset[2] = p_rt->params.ip_hdr_offset - 3 * 8;
-
-		entry_arp0.data_offset = entry_arp0.slab_offset[2] + 2
-			- sizeof(struct rte_mbuf);
-		entry_arp0.ether_l2_length = 22;
-	}
-
-	/* Ether QinQ - ARP on */
-	if ((p_rt->params.encap == PIPELINE_ROUTING_ENCAP_ETHERNET_QINQ) &&
-		p_rt->params.n_arp_entries) {
-		uint64_t macaddr_src = p_rt->macaddr[req->data.port_id];
-		uint64_t ethertype_ipv4 = ETHER_TYPE_IPv4;
-		uint64_t ethertype_vlan = 0x8100;
-		uint64_t ethertype_qinq = 0x9100;
-		uint64_t svlan = req->data.l2.qinq.svlan;
-		uint64_t cvlan = req->data.l2.qinq.cvlan;
-
-		entry_arp1.slab[0] = rte_bswap64((svlan << 48) |
-			(ethertype_vlan << 32) |
-			(cvlan << 16) |
-			ethertype_ipv4);
-		entry_arp1.slab_offset[0] = p_rt->params.ip_hdr_offset - 8;
-
-		entry_arp1.slab[1] =
-			SLAB_NBO_MACADDRSRC_ETHERTYPE(macaddr_src, ethertype_qinq);
-		entry_arp1.slab_offset[1] = p_rt->params.ip_hdr_offset - 2 * 8;
-
-		entry_arp1.data_offset = entry_arp1.slab_offset[1] - 6
-			- sizeof(struct rte_mbuf);
-		entry_arp1.ether_l2_length = 22;
-	}
-
-	/* Ether MPLS - ARP off */
-	if ((p_rt->params.encap == PIPELINE_ROUTING_ENCAP_ETHERNET_MPLS) &&
-		(p_rt->params.n_arp_entries == 0)) {
-		uint64_t macaddr_src = p_rt->macaddr[req->data.port_id];
-		uint64_t macaddr_dst;
-		uint64_t ethertype_mpls = 0x8847;
-
-		uint64_t label0 = req->data.l2.mpls.labels[0];
-		uint64_t label1 = req->data.l2.mpls.labels[1];
-		uint64_t label2 = req->data.l2.mpls.labels[2];
-		uint64_t label3 = req->data.l2.mpls.labels[3];
-		uint32_t n_labels = req->data.l2.mpls.n_labels;
-
-		macaddr_dst = *((uint64_t *)&(req->data.ethernet.macaddr));
-		macaddr_dst = rte_bswap64(macaddr_dst << 16);
-
-		switch (n_labels) {
-		case 1:
-			entry_arp0.slab[0] = 0;
-			entry_arp0.slab_offset[0] =
-				p_rt->params.ip_hdr_offset - 8;
-
-			entry_arp0.slab[1] = rte_bswap64(
-				MPLS_LABEL(label0, 0, 1, 0));
-			entry_arp0.slab_offset[1] =
-				p_rt->params.ip_hdr_offset - 8;
-			break;
-
-		case 2:
-			entry_arp0.slab[0] = 0;
-			entry_arp0.slab_offset[0] =
-				p_rt->params.ip_hdr_offset - 8;
-
-			entry_arp0.slab[1] = rte_bswap64(
-				(MPLS_LABEL(label0, 0, 0, 0) << 32) |
-				MPLS_LABEL(label1, 0, 1, 0));
-			entry_arp0.slab_offset[1] =
-				p_rt->params.ip_hdr_offset - 8;
-			break;
-
-		case 3:
-			entry_arp0.slab[0] = rte_bswap64(
-				(MPLS_LABEL(label1, 0, 0, 0) << 32) |
-				MPLS_LABEL(label2, 0, 1, 0));
-			entry_arp0.slab_offset[0] =
-				p_rt->params.ip_hdr_offset - 8;
-
-			entry_arp0.slab[1] = rte_bswap64(
-				MPLS_LABEL(label0, 0, 0, 0));
-			entry_arp0.slab_offset[1] =
-				p_rt->params.ip_hdr_offset - 2 * 8;
-			break;
-
-		case 4:
-			entry_arp0.slab[0] = rte_bswap64(
-				(MPLS_LABEL(label2, 0, 0, 0) << 32) |
-				MPLS_LABEL(label3, 0, 1, 0));
-			entry_arp0.slab_offset[0] =
-				p_rt->params.ip_hdr_offset - 8;
-
-			entry_arp0.slab[1] = rte_bswap64(
-				(MPLS_LABEL(label0, 0, 0, 0) << 32) |
-				MPLS_LABEL(label1, 0, 0, 0));
-			entry_arp0.slab_offset[1] =
-				p_rt->params.ip_hdr_offset - 2 * 8;
-			break;
-
-		default:
-			rsp->status = -1;
-			return rsp;
-		}
-
-		entry_arp0.slab[2] =
-			SLAB_NBO_MACADDRSRC_ETHERTYPE(macaddr_src, ethertype_mpls);
-		entry_arp0.slab_offset[2] = p_rt->params.ip_hdr_offset -
-			(n_labels * 4 + 8);
-
-		entry_arp0.slab[3] = rte_bswap64(macaddr_dst);
-		entry_arp0.slab_offset[3] = p_rt->params.ip_hdr_offset -
-			(n_labels * 4 + 2 * 8);
-
-		entry_arp0.data_offset = entry_arp0.slab_offset[3] + 2
-			- sizeof(struct rte_mbuf);
-		entry_arp0.ether_l2_length = n_labels * 4 + 14;
-	}
-
-	/* Ether MPLS - ARP on */
-	if ((p_rt->params.encap == PIPELINE_ROUTING_ENCAP_ETHERNET_MPLS) &&
-		p_rt->params.n_arp_entries) {
-		uint64_t macaddr_src = p_rt->macaddr[req->data.port_id];
-		uint64_t ethertype_mpls = 0x8847;
-
-		uint64_t label0 = req->data.l2.mpls.labels[0];
-		uint64_t label1 = req->data.l2.mpls.labels[1];
-		uint64_t label2 = req->data.l2.mpls.labels[2];
-		uint64_t label3 = req->data.l2.mpls.labels[3];
-		uint32_t n_labels = req->data.l2.mpls.n_labels;
-
-		switch (n_labels) {
-		case 1:
-			entry_arp1.slab[0] = 0;
-			entry_arp1.slab_offset[0] =
-				p_rt->params.ip_hdr_offset - 8;
-
-			entry_arp1.slab[1] = rte_bswap64(
-				MPLS_LABEL(label0, 0, 1, 0));
-			entry_arp1.slab_offset[1] =
-				p_rt->params.ip_hdr_offset - 8;
-			break;
-
-		case 2:
-			entry_arp1.slab[0] = 0;
-			entry_arp1.slab_offset[0] =
-				p_rt->params.ip_hdr_offset - 8;
-
-			entry_arp1.slab[1] = rte_bswap64(
-				(MPLS_LABEL(label0, 0, 0, 0) << 32) |
-				MPLS_LABEL(label1, 0, 1, 0));
-			entry_arp1.slab_offset[1] =
-				p_rt->params.ip_hdr_offset - 8;
-			break;
-
-		case 3:
-			entry_arp1.slab[0] = rte_bswap64(
-				(MPLS_LABEL(label1, 0, 0, 0) << 32) |
-				MPLS_LABEL(label2, 0, 1, 0));
-			entry_arp1.slab_offset[0] =
-				p_rt->params.ip_hdr_offset - 8;
-
-			entry_arp1.slab[1] = rte_bswap64(
-				MPLS_LABEL(label0, 0, 0, 0));
-			entry_arp1.slab_offset[1] =
-				p_rt->params.ip_hdr_offset - 2 * 8;
-			break;
-
-		case 4:
-			entry_arp1.slab[0] = rte_bswap64(
-				(MPLS_LABEL(label2, 0, 0, 0) << 32) |
-				MPLS_LABEL(label3, 0, 1, 0));
-			entry_arp1.slab_offset[0] =
-				p_rt->params.ip_hdr_offset - 8;
-
-			entry_arp1.slab[1] = rte_bswap64(
-				(MPLS_LABEL(label0, 0, 0, 0) << 32) |
-				MPLS_LABEL(label1, 0, 0, 0));
-			entry_arp1.slab_offset[1] =
-				p_rt->params.ip_hdr_offset - 2 * 8;
-			break;
-
-		default:
-			rsp->status = -1;
-			return rsp;
-		}
-
-		entry_arp1.slab[2] =
-			SLAB_NBO_MACADDRSRC_ETHERTYPE(macaddr_src, ethertype_mpls);
-		entry_arp1.slab_offset[2] = p_rt->params.ip_hdr_offset -
-			(n_labels * 4 + 8);
-
-		entry_arp1.data_offset = entry_arp1.slab_offset[2] - 6
-			- sizeof(struct rte_mbuf);
-		entry_arp1.ether_l2_length = n_labels * 4 + 14;
-	}
-
-	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);
-
-	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);
-
-	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_ipv4 key = {
-		.port_id = req->key.key.ipv4.port_id,
-		.ip = rte_bswap32(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, /* set below */
-	};
-
-	if (req->key.type != PIPELINE_ROUTING_ARP_IPV4) {
-		rsp->status = -1;
-		return rsp;
-	}
-
-	entry.macaddr = *((uint64_t *)&(req->macaddr));
-	entry.macaddr = entry.macaddr << 16;
-
-	rsp->status = rte_pipeline_table_entry_add(p->p,
-		p->table_id[1],
-		&key,
-		(struct rte_pipeline_table_entry *) &entry,
-		&rsp->key_found,
-		(struct rte_pipeline_table_entry **) &rsp->entry_ptr);
-
-	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_ipv4 key = {
-		.port_id = req->key.key.ipv4.port_id,
-		.ip = rte_bswap32(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);
-
-	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;
-}
-
-void *
-pipeline_routing_msg_req_set_macaddr_handler(struct pipeline *p, void *msg)
-{
-	struct pipeline_routing *p_rt = (struct pipeline_routing *) p;
-	struct pipeline_routing_set_macaddr_msg_req *req = msg;
-	struct pipeline_routing_set_macaddr_msg_rsp *rsp = msg;
-	uint32_t port_id;
-
-	for (port_id = 0; port_id < p->n_ports_out; port_id++)
-		p_rt->macaddr[port_id] = req->macaddr[port_id];
-
-	rsp->status = 0;
-
-	return rsp;
-}
-
-struct pipeline_be_ops pipeline_routing_be_ops = {
-	.f_init = pipeline_routing_init,
-	.f_free = pipeline_routing_free,
-	.f_run = NULL,
-	.f_timer = pipeline_routing_timer,
-};
diff --git a/examples/ip_pipeline/pipeline/pipeline_routing_be.h b/examples/ip_pipeline/pipeline/pipeline_routing_be.h
deleted file mode 100644
index 7140ee4..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_routing_be.h
+++ /dev/null
@@ -1,283 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#ifndef __INCLUDE_PIPELINE_ROUTING_BE_H__
-#define __INCLUDE_PIPELINE_ROUTING_BE_H__
-
-#include <rte_ether.h>
-
-#include "pipeline_common_be.h"
-
-/*
- * Pipeline argument parsing
- */
-#ifndef PIPELINE_ROUTING_N_ROUTES_DEFAULT
-#define PIPELINE_ROUTING_N_ROUTES_DEFAULT                  4096
-#endif
-
-enum pipeline_routing_encap {
-	PIPELINE_ROUTING_ENCAP_ETHERNET = 0,
-	PIPELINE_ROUTING_ENCAP_ETHERNET_QINQ,
-	PIPELINE_ROUTING_ENCAP_ETHERNET_MPLS,
-};
-
-struct pipeline_routing_params {
-	/* routing */
-	uint32_t n_routes;
-	uint32_t port_local_dest;
-
-	/* routing packet encapsulation */
-	enum pipeline_routing_encap encap;
-	uint32_t qinq_sched;
-	uint32_t mpls_color_mark;
-
-	/* arp */
-	uint32_t n_arp_entries;
-
-	/* packet buffer offsets */
-	uint32_t ip_hdr_offset;
-	uint32_t arp_key_offset;
-	uint32_t color_offset;
-
-	/* debug */
-	uint32_t dbg_ah_disable;
-};
-
-int
-pipeline_routing_parse_args(struct pipeline_routing_params *p,
-	struct pipeline_params *params);
-
-/*
- * Route
- */
-enum pipeline_routing_route_key_type {
-	PIPELINE_ROUTING_ROUTE_IPV4,
-};
-
-struct pipeline_routing_route_key_ipv4 {
-	uint32_t ip;
-	uint32_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 */
-	PIPELINE_ROUTING_ROUTE_ARP = 1 << 1, /* 0 = ARP OFF; 1 = ARP ON */
-	PIPELINE_ROUTING_ROUTE_QINQ = 1 << 2, /* 0 = QINQ OFF; 1 = QINQ ON */
-	PIPELINE_ROUTING_ROUTE_MPLS = 1 << 3, /* 0 = MPLS OFF; 1 = MPLS ON */
-};
-
-#define PIPELINE_ROUTING_MPLS_LABELS_MAX         4
-
-struct pipeline_routing_route_data {
-	uint32_t flags;
-	uint32_t port_id; /* Output port ID */
-
-	union {
-		/* Next hop IP (valid only when ARP is enabled) */
-		uint32_t ip;
-
-		/* Next hop MAC address (valid only when ARP disabled */
-		struct ether_addr macaddr;
-	} ethernet;
-
-	union {
-		struct {
-			uint16_t svlan;
-			uint16_t cvlan;
-		} qinq;
-
-		struct {
-			uint32_t labels[PIPELINE_ROUTING_MPLS_LABELS_MAX];
-			uint32_t n_labels;
-		} mpls;
-	} l2;
-};
-
-/*
- * 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_REQ_SET_MACADDR,
-	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 */
-	struct pipeline_routing_route_data data;
-};
-
-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;
-};
-
-/*
- * MSG SET MACADDR
- */
-struct pipeline_routing_set_macaddr_msg_req {
-	enum pipeline_msg_req_type type;
-	enum pipeline_routing_msg_req_type subtype;
-
-	uint64_t macaddr[PIPELINE_MAX_PORT_OUT];
-};
-
-struct pipeline_routing_set_macaddr_msg_rsp {
-	int status;
-};
-
-extern struct pipeline_be_ops pipeline_routing_be_ops;
-
-#endif
-- 
2.9.3

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

* [dpdk-dev] [PATCH v3 12/44] ip_pipeline: remove flow classification pipeline
  2018-03-16 17:58       ` [dpdk-dev] [PATCH v3 00/44] ip_pipeline: refactoring Jasvinder Singh
                           ` (10 preceding siblings ...)
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 11/44] ip_pipeline: remove routing pipeline Jasvinder Singh
@ 2018-03-16 17:58         ` Jasvinder Singh
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 13/44] ip_pipeline: remove flow actions pipeline Jasvinder Singh
                           ` (31 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-16 17:58 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Remove flow classification pipeline.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/Makefile                      |    2 -
 examples/ip_pipeline/init.c                        |    2 -
 examples/ip_pipeline/meson.build                   |    2 -
 .../pipeline/pipeline_flow_classification.c        | 1878 --------------------
 .../pipeline/pipeline_flow_classification.h        |  106 --
 .../pipeline/pipeline_flow_classification_be.c     |  723 --------
 .../pipeline/pipeline_flow_classification_be.h     |  113 --
 7 files changed, 2826 deletions(-)
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_classification.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_classification.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_classification_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_classification_be.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index f67cfe6..e43001f 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -21,8 +21,6 @@ SRCS-y += pipeline_master_be.c
 SRCS-y += pipeline_master.c
 SRCS-y += pipeline_firewall_be.c
 SRCS-y += pipeline_firewall.c
-SRCS-y += pipeline_flow_classification_be.c
-SRCS-y += pipeline_flow_classification.c
 SRCS-y += pipeline_flow_actions_be.c
 SRCS-y += pipeline_flow_actions.c
 
diff --git a/examples/ip_pipeline/init.c b/examples/ip_pipeline/init.c
index 241d80a..4780bb1 100644
--- a/examples/ip_pipeline/init.c
+++ b/examples/ip_pipeline/init.c
@@ -27,7 +27,6 @@
 #include "pipeline_common_fe.h"
 #include "pipeline_master.h"
 #include "pipeline_firewall.h"
-#include "pipeline_flow_classification.h"
 #include "pipeline_flow_actions.h"
 #include "thread_fe.h"
 
@@ -1820,7 +1819,6 @@ int app_init(struct app_params *app)
 	app_pipeline_common_cmd_push(app);
 	app_pipeline_thread_cmd_push(app);
 	app_pipeline_type_register(app, &pipeline_master);
-	app_pipeline_type_register(app, &pipeline_flow_classification);
 	app_pipeline_type_register(app, &pipeline_flow_actions);
 	app_pipeline_type_register(app, &pipeline_firewall);
 
diff --git a/examples/ip_pipeline/meson.build b/examples/ip_pipeline/meson.build
index f9eab1b..dd12870 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -25,8 +25,6 @@ sources = files(
 	'pipeline/pipeline_firewall.c',
 	'pipeline/pipeline_flow_actions_be.c',
 	'pipeline/pipeline_flow_actions.c',
-	'pipeline/pipeline_flow_classification_be.c',
-	'pipeline/pipeline_flow_classification.c',
 	'pipeline/pipeline_master_be.c',
 	'pipeline/pipeline_master.c',
 )
diff --git a/examples/ip_pipeline/pipeline/pipeline_flow_classification.c b/examples/ip_pipeline/pipeline/pipeline_flow_classification.c
deleted file mode 100644
index d39e0fb..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_flow_classification.c
+++ /dev/null
@@ -1,1878 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2016 Intel Corporation
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <sys/queue.h>
-#include <netinet/in.h>
-#include <unistd.h>
-
-#include <rte_common.h>
-#include <rte_hexdump.h>
-#include <rte_malloc.h>
-#include <cmdline_rdline.h>
-#include <cmdline_parse.h>
-#include <cmdline_parse_num.h>
-#include <cmdline_parse_string.h>
-
-#include "app.h"
-#include "pipeline_common_fe.h"
-#include "pipeline_flow_classification.h"
-#include "hash_func.h"
-#include "parser.h"
-
-/*
- * Key conversion
- */
-
-struct pkt_key_qinq {
-	uint16_t ethertype_svlan;
-	uint16_t svlan;
-	uint16_t ethertype_cvlan;
-	uint16_t cvlan;
-} __attribute__((__packed__));
-
-struct pkt_key_ipv4_5tuple {
-	uint8_t ttl;
-	uint8_t proto;
-	uint16_t checksum;
-	uint32_t ip_src;
-	uint32_t ip_dst;
-	uint16_t port_src;
-	uint16_t port_dst;
-} __attribute__((__packed__));
-
-struct pkt_key_ipv6_5tuple {
-	uint16_t payload_length;
-	uint8_t proto;
-	uint8_t hop_limit;
-	uint8_t ip_src[16];
-	uint8_t ip_dst[16];
-	uint16_t port_src;
-	uint16_t port_dst;
-} __attribute__((__packed__));
-
-static int
-app_pipeline_fc_key_convert(struct pipeline_fc_key *key_in,
-	uint8_t *key_out,
-	uint32_t *signature)
-{
-	uint8_t buffer[PIPELINE_FC_FLOW_KEY_MAX_SIZE];
-	uint8_t m[PIPELINE_FC_FLOW_KEY_MAX_SIZE]; /* key mask */
-	void *key_buffer = (key_out) ? key_out : buffer;
-
-	memset(m, 0xFF, sizeof(m));
-	switch (key_in->type) {
-	case FLOW_KEY_QINQ:
-	{
-		struct pkt_key_qinq *qinq = key_buffer;
-
-		qinq->ethertype_svlan = 0;
-		qinq->svlan = rte_cpu_to_be_16(key_in->key.qinq.svlan);
-		qinq->ethertype_cvlan = 0;
-		qinq->cvlan = rte_cpu_to_be_16(key_in->key.qinq.cvlan);
-
-		if (signature)
-			*signature = (uint32_t) hash_default_key8(qinq, m, 8, 0);
-		return 0;
-	}
-
-	case FLOW_KEY_IPV4_5TUPLE:
-	{
-		struct pkt_key_ipv4_5tuple *ipv4 = key_buffer;
-
-		ipv4->ttl = 0;
-		ipv4->proto = key_in->key.ipv4_5tuple.proto;
-		ipv4->checksum = 0;
-		ipv4->ip_src = rte_cpu_to_be_32(key_in->key.ipv4_5tuple.ip_src);
-		ipv4->ip_dst = rte_cpu_to_be_32(key_in->key.ipv4_5tuple.ip_dst);
-		ipv4->port_src = rte_cpu_to_be_16(key_in->key.ipv4_5tuple.port_src);
-		ipv4->port_dst = rte_cpu_to_be_16(key_in->key.ipv4_5tuple.port_dst);
-
-		if (signature)
-			*signature = (uint32_t) hash_default_key16(ipv4, m, 16, 0);
-		return 0;
-	}
-
-	case FLOW_KEY_IPV6_5TUPLE:
-	{
-		struct pkt_key_ipv6_5tuple *ipv6 = key_buffer;
-
-		memset(ipv6, 0, 64);
-		ipv6->payload_length = 0;
-		ipv6->proto = key_in->key.ipv6_5tuple.proto;
-		ipv6->hop_limit = 0;
-		memcpy(&ipv6->ip_src, &key_in->key.ipv6_5tuple.ip_src, 16);
-		memcpy(&ipv6->ip_dst, &key_in->key.ipv6_5tuple.ip_dst, 16);
-		ipv6->port_src = rte_cpu_to_be_16(key_in->key.ipv6_5tuple.port_src);
-		ipv6->port_dst = rte_cpu_to_be_16(key_in->key.ipv6_5tuple.port_dst);
-
-		if (signature)
-			*signature = (uint32_t) hash_default_key64(ipv6, m, 64, 0);
-		return 0;
-	}
-
-	default:
-		return -1;
-	}
-}
-
-/*
- * Flow classification pipeline
- */
-
-struct app_pipeline_fc_flow {
-	struct pipeline_fc_key key;
-	uint32_t port_id;
-	uint32_t flow_id;
-	uint32_t signature;
-	void *entry_ptr;
-
-	TAILQ_ENTRY(app_pipeline_fc_flow) node;
-};
-
-#define N_BUCKETS                                65536
-
-struct app_pipeline_fc {
-	/* Parameters */
-	uint32_t n_ports_in;
-	uint32_t n_ports_out;
-
-	/* Flows */
-	TAILQ_HEAD(, app_pipeline_fc_flow) flows[N_BUCKETS];
-	uint32_t n_flows;
-
-	/* Default flow */
-	uint32_t default_flow_present;
-	uint32_t default_flow_port_id;
-	void *default_flow_entry_ptr;
-};
-
-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;
-	uint32_t signature, bucket_id;
-
-	app_pipeline_fc_key_convert(key, NULL, &signature);
-	bucket_id = signature & (N_BUCKETS - 1);
-
-	TAILQ_FOREACH(f, &p->flows[bucket_id], node)
-		if ((signature == f->signature) &&
-			(memcmp(key,
-				&f->key,
-				sizeof(struct pipeline_fc_key)) == 0))
-			return f;
-
-	return NULL;
-}
-
-static void*
-app_pipeline_fc_init(struct pipeline_params *params,
-	__rte_unused void *arg)
-{
-	struct app_pipeline_fc *p;
-	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 app_pipeline_fc));
-	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;
-
-	for (i = 0; i < N_BUCKETS; i++)
-		TAILQ_INIT(&p->flows[i]);
-	p->n_flows = 0;
-
-	return (void *) p;
-}
-
-static int
-app_pipeline_fc_free(void *pipeline)
-{
-	struct app_pipeline_fc *p = pipeline;
-	uint32_t i;
-
-	/* Check input arguments */
-	if (p == NULL)
-		return -1;
-
-	/* Free resources */
-	for (i = 0; i < N_BUCKETS; i++)
-		while (!TAILQ_EMPTY(&p->flows[i])) {
-			struct app_pipeline_fc_flow *flow;
-
-			flow = TAILQ_FIRST(&p->flows[i]);
-			TAILQ_REMOVE(&p->flows[i], flow, node);
-			rte_free(flow);
-		}
-
-	rte_free(p);
-	return 0;
-}
-
-static int
-app_pipeline_fc_key_check(struct pipeline_fc_key *key)
-{
-	switch (key->type) {
-	case FLOW_KEY_QINQ:
-	{
-		uint16_t svlan = key->key.qinq.svlan;
-		uint16_t cvlan = key->key.qinq.cvlan;
-
-		if ((svlan & 0xF000) ||
-			(cvlan & 0xF000))
-			return -1;
-
-		return 0;
-	}
-
-	case FLOW_KEY_IPV4_5TUPLE:
-		return 0;
-
-	case FLOW_KEY_IPV6_5TUPLE:
-		return 0;
-
-	default:
-		return -1;
-	}
-}
-
-int
-app_pipeline_fc_load_file_qinq(char *filename,
-	struct pipeline_fc_key *keys,
-	uint32_t *port_ids,
-	uint32_t *flow_ids,
-	uint32_t *n_keys,
-	uint32_t *line)
-{
-	FILE *f = NULL;
-	char file_buf[1024];
-	uint32_t i, l;
-
-	/* Check input arguments */
-	if ((filename == NULL) ||
-		(keys == NULL) ||
-		(port_ids == NULL) ||
-		(flow_ids == NULL) ||
-		(n_keys == NULL) ||
-		(*n_keys == 0) ||
-		(line == NULL)) {
-		if (line)
-			*line = 0;
-		return -1;
-		}
-
-	/* Open input file */
-	f = fopen(filename, "r");
-	if (f == NULL) {
-		*line = 0;
-		return -1;
-	}
-
-	/* Read file */
-	for (i = 0, l = 1; i < *n_keys; l++) {
-		char *tokens[32];
-		uint32_t n_tokens = RTE_DIM(tokens);
-
-		uint16_t svlan, cvlan;
-		uint32_t portid, flowid;
-		int status;
-
-		if (fgets(file_buf, sizeof(file_buf), f) == NULL)
-			break;
-
-		status = parse_tokenize_string(file_buf, tokens, &n_tokens);
-		if (status)
-			goto error1;
-
-		if ((n_tokens == 0) || (tokens[0][0] == '#'))
-			continue;
-
-		if ((n_tokens != 7) ||
-			strcmp(tokens[0], "qinq") ||
-			parser_read_uint16(&svlan, tokens[1]) ||
-			parser_read_uint16(&cvlan, tokens[2]) ||
-			strcmp(tokens[3], "port") ||
-			parser_read_uint32(&portid, tokens[4]) ||
-			strcmp(tokens[5], "id") ||
-			parser_read_uint32(&flowid, tokens[6]))
-			goto error1;
-
-		keys[i].type = FLOW_KEY_QINQ;
-		keys[i].key.qinq.svlan = svlan;
-		keys[i].key.qinq.cvlan = cvlan;
-
-		port_ids[i] = portid;
-		flow_ids[i] = flowid;
-
-		if (app_pipeline_fc_key_check(&keys[i]))
-			goto error1;
-
-		i++;
-	}
-
-	/* Close file */
-	*n_keys = i;
-	fclose(f);
-	return 0;
-
-error1:
-	*line = l;
-	fclose(f);
-	return -1;
-}
-
-int
-app_pipeline_fc_load_file_ipv4(char *filename,
-	struct pipeline_fc_key *keys,
-	uint32_t *port_ids,
-	uint32_t *flow_ids,
-	uint32_t *n_keys,
-	uint32_t *line)
-{
-	FILE *f = NULL;
-	char file_buf[1024];
-	uint32_t i, l;
-
-	/* Check input arguments */
-	if ((filename == NULL) ||
-		(keys == NULL) ||
-		(port_ids == NULL) ||
-		(flow_ids == NULL) ||
-		(n_keys == NULL) ||
-		(*n_keys == 0) ||
-		(line == NULL)) {
-		if (line)
-			*line = 0;
-		return -1;
-		}
-
-	/* Open input file */
-	f = fopen(filename, "r");
-	if (f == NULL) {
-		*line = 0;
-		return -1;
-	}
-
-	/* Read file */
-	for (i = 0, l = 1; i < *n_keys; l++) {
-		char *tokens[32];
-		uint32_t n_tokens = RTE_DIM(tokens);
-
-		struct in_addr sipaddr, dipaddr;
-		uint16_t sport, dport;
-		uint8_t proto;
-		uint32_t portid, flowid;
-		int status;
-
-		if (fgets(file_buf, sizeof(file_buf), f) == NULL)
-			break;
-
-		status = parse_tokenize_string(file_buf, tokens, &n_tokens);
-		if (status)
-			goto error2;
-
-		if ((n_tokens == 0) || (tokens[0][0] == '#'))
-			continue;
-
-		if ((n_tokens != 10) ||
-			strcmp(tokens[0], "ipv4") ||
-			parse_ipv4_addr(tokens[1], &sipaddr) ||
-			parse_ipv4_addr(tokens[2], &dipaddr) ||
-			parser_read_uint16(&sport, tokens[3]) ||
-			parser_read_uint16(&dport, tokens[4]) ||
-			parser_read_uint8(&proto, tokens[5]) ||
-			strcmp(tokens[6], "port") ||
-			parser_read_uint32(&portid, tokens[7]) ||
-			strcmp(tokens[8], "id") ||
-			parser_read_uint32(&flowid, tokens[9]))
-			goto error2;
-
-		keys[i].type = FLOW_KEY_IPV4_5TUPLE;
-		keys[i].key.ipv4_5tuple.ip_src = rte_be_to_cpu_32(sipaddr.s_addr);
-		keys[i].key.ipv4_5tuple.ip_dst = rte_be_to_cpu_32(dipaddr.s_addr);
-		keys[i].key.ipv4_5tuple.port_src = sport;
-		keys[i].key.ipv4_5tuple.port_dst = dport;
-		keys[i].key.ipv4_5tuple.proto = proto;
-
-		port_ids[i] = portid;
-		flow_ids[i] = flowid;
-
-		if (app_pipeline_fc_key_check(&keys[i]))
-			goto error2;
-
-		i++;
-	}
-
-	/* Close file */
-	*n_keys = i;
-	fclose(f);
-	return 0;
-
-error2:
-	*line = l;
-	fclose(f);
-	return -1;
-}
-
-int
-app_pipeline_fc_load_file_ipv6(char *filename,
-	struct pipeline_fc_key *keys,
-	uint32_t *port_ids,
-	uint32_t *flow_ids,
-	uint32_t *n_keys,
-	uint32_t *line)
-{
-	FILE *f = NULL;
-	char file_buf[1024];
-	uint32_t i, l;
-
-	/* Check input arguments */
-	if ((filename == NULL) ||
-		(keys == NULL) ||
-		(port_ids == NULL) ||
-		(flow_ids == NULL) ||
-		(n_keys == NULL) ||
-		(*n_keys == 0) ||
-		(line == NULL)) {
-		if (line)
-			*line = 0;
-		return -1;
-		}
-
-	/* Open input file */
-	f = fopen(filename, "r");
-	if (f == NULL) {
-		*line = 0;
-		return -1;
-	}
-
-	/* Read file */
-	for (i = 0, l = 1; i < *n_keys; l++) {
-		char *tokens[32];
-		uint32_t n_tokens = RTE_DIM(tokens);
-
-		struct in6_addr sipaddr, dipaddr;
-		uint16_t sport, dport;
-		uint8_t proto;
-		uint32_t portid, flowid;
-		int status;
-
-		if (fgets(file_buf, sizeof(file_buf), f) == NULL)
-			break;
-
-		status = parse_tokenize_string(file_buf, tokens, &n_tokens);
-		if (status)
-			goto error3;
-
-		if ((n_tokens == 0) || (tokens[0][0] == '#'))
-			continue;
-
-		if ((n_tokens != 10) ||
-			strcmp(tokens[0], "ipv6") ||
-			parse_ipv6_addr(tokens[1], &sipaddr) ||
-			parse_ipv6_addr(tokens[2], &dipaddr) ||
-			parser_read_uint16(&sport, tokens[3]) ||
-			parser_read_uint16(&dport, tokens[4]) ||
-			parser_read_uint8(&proto, tokens[5]) ||
-			strcmp(tokens[6], "port") ||
-			parser_read_uint32(&portid, tokens[7]) ||
-			strcmp(tokens[8], "id") ||
-			parser_read_uint32(&flowid, tokens[9]))
-			goto error3;
-
-		keys[i].type = FLOW_KEY_IPV6_5TUPLE;
-		memcpy(keys[i].key.ipv6_5tuple.ip_src,
-			sipaddr.s6_addr,
-			sizeof(sipaddr.s6_addr));
-		memcpy(keys[i].key.ipv6_5tuple.ip_dst,
-			dipaddr.s6_addr,
-			sizeof(dipaddr.s6_addr));
-		keys[i].key.ipv6_5tuple.port_src = sport;
-		keys[i].key.ipv6_5tuple.port_dst = dport;
-		keys[i].key.ipv6_5tuple.proto = proto;
-
-		port_ids[i] = portid;
-		flow_ids[i] = flowid;
-
-		if (app_pipeline_fc_key_check(&keys[i]))
-			goto error3;
-
-		i++;
-	}
-
-	/* Close file */
-	*n_keys = i;
-	fclose(f);
-	return 0;
-
-error3:
-	*line = l;
-	fclose(f);
-	return -1;
-}
-
-
-
-int
-app_pipeline_fc_add(struct app_params *app,
-	uint32_t pipeline_id,
-	struct pipeline_fc_key *key,
-	uint32_t port_id,
-	uint32_t flow_id)
-{
-	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;
-
-	uint32_t signature;
-	int new_flow;
-
-	/* Check input arguments */
-	if ((app == NULL) ||
-		(key == NULL))
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_flow_classification);
-	if (p == NULL)
-		return -1;
-
-	if (port_id >= p->n_ports_out)
-		return -1;
-
-	if (app_pipeline_fc_key_check(key) != 0)
-		return -1;
-
-	/* 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;
-	}
-
-	/* 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;
-	app_pipeline_fc_key_convert(key, req->key, &signature);
-	req->port_id = port_id;
-	req->flow_id = flow_id;
-
-	/* Send request and wait for response */
-	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL) {
-		if (new_flow)
-			rte_free(flow);
-		return -1;
-	}
-
-	/* Read response and write flow */
-	if (rsp->status ||
-		(rsp->entry_ptr == NULL) ||
-		((new_flow == 0) && (rsp->key_found == 0)) ||
-		((new_flow == 1) && (rsp->key_found == 1))) {
-		app_msg_free(app, rsp);
-		if (new_flow)
-			rte_free(flow);
-		return -1;
-	}
-
-	memset(&flow->key, 0, sizeof(flow->key));
-	memcpy(&flow->key, key, sizeof(flow->key));
-	flow->port_id = port_id;
-	flow->flow_id = flow_id;
-	flow->signature = signature;
-	flow->entry_ptr = rsp->entry_ptr;
-
-	/* Commit rule */
-	if (new_flow) {
-		uint32_t bucket_id = signature & (N_BUCKETS - 1);
-
-		TAILQ_INSERT_TAIL(&p->flows[bucket_id], flow, node);
-		p->n_flows++;
-	}
-
-	/* Free response */
-	app_msg_free(app, rsp);
-
-	return 0;
-}
-
-int
-app_pipeline_fc_add_bulk(struct app_params *app,
-	uint32_t pipeline_id,
-	struct pipeline_fc_key *key,
-	uint32_t *port_id,
-	uint32_t *flow_id,
-	uint32_t n_keys)
-{
-	struct app_pipeline_fc *p;
-	struct pipeline_fc_add_bulk_msg_req *req;
-	struct pipeline_fc_add_bulk_msg_rsp *rsp;
-
-	struct app_pipeline_fc_flow **flow;
-	uint32_t *signature;
-	int *new_flow;
-	struct pipeline_fc_add_bulk_flow_req *flow_req;
-	struct pipeline_fc_add_bulk_flow_rsp *flow_rsp;
-
-	uint32_t i;
-	int status;
-
-	/* Check input arguments */
-	if ((app == NULL) ||
-		(key == NULL) ||
-		(port_id == NULL) ||
-		(flow_id == NULL) ||
-		(n_keys == 0))
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_flow_classification);
-	if (p == NULL)
-		return -1;
-
-	for (i = 0; i < n_keys; i++)
-		if (port_id[i] >= p->n_ports_out)
-			return -1;
-
-	for (i = 0; i < n_keys; i++)
-		if (app_pipeline_fc_key_check(&key[i]) != 0)
-			return -1;
-
-	/* Memory allocation */
-	flow = rte_malloc(NULL,
-		n_keys * sizeof(struct app_pipeline_fc_flow *),
-		RTE_CACHE_LINE_SIZE);
-	if (flow == NULL)
-		return -1;
-
-	signature = rte_malloc(NULL,
-		n_keys * sizeof(uint32_t),
-		RTE_CACHE_LINE_SIZE);
-	if (signature == NULL) {
-		rte_free(flow);
-		return -1;
-	}
-
-	new_flow = rte_malloc(
-		NULL,
-		n_keys * sizeof(int),
-		RTE_CACHE_LINE_SIZE);
-	if (new_flow == NULL) {
-		rte_free(signature);
-		rte_free(flow);
-		return -1;
-	}
-
-	flow_req = rte_malloc(NULL,
-		n_keys * sizeof(struct pipeline_fc_add_bulk_flow_req),
-		RTE_CACHE_LINE_SIZE);
-	if (flow_req == NULL) {
-		rte_free(new_flow);
-		rte_free(signature);
-		rte_free(flow);
-		return -1;
-	}
-
-	flow_rsp = rte_malloc(NULL,
-		n_keys * sizeof(struct pipeline_fc_add_bulk_flow_rsp),
-		RTE_CACHE_LINE_SIZE);
-	if (flow_rsp == NULL) {
-		rte_free(flow_req);
-		rte_free(new_flow);
-		rte_free(signature);
-		rte_free(flow);
-		return -1;
-	}
-
-	/* Find existing flow or allocate new flow */
-	for (i = 0; i < n_keys; i++) {
-		flow[i] = app_pipeline_fc_flow_find(p, &key[i]);
-		new_flow[i] = (flow[i] == NULL);
-		if (flow[i] == NULL) {
-			flow[i] = rte_zmalloc(NULL,
-				sizeof(struct app_pipeline_fc_flow),
-				RTE_CACHE_LINE_SIZE);
-
-			if (flow[i] == NULL) {
-				uint32_t j;
-
-				for (j = 0; j < i; j++)
-					if (new_flow[j])
-						rte_free(flow[j]);
-
-				rte_free(flow_rsp);
-				rte_free(flow_req);
-				rte_free(new_flow);
-				rte_free(signature);
-				rte_free(flow);
-				return -1;
-			}
-		}
-	}
-
-	/* Allocate and write request */
-	req = app_msg_alloc(app);
-	if (req == NULL) {
-		for (i = 0; i < n_keys; i++)
-			if (new_flow[i])
-				rte_free(flow[i]);
-
-		rte_free(flow_rsp);
-		rte_free(flow_req);
-		rte_free(new_flow);
-		rte_free(signature);
-		rte_free(flow);
-		return -1;
-	}
-
-	for (i = 0; i < n_keys; i++) {
-		app_pipeline_fc_key_convert(&key[i],
-			flow_req[i].key,
-			&signature[i]);
-		flow_req[i].port_id = port_id[i];
-		flow_req[i].flow_id = flow_id[i];
-	}
-
-	req->type = PIPELINE_MSG_REQ_CUSTOM;
-	req->subtype = PIPELINE_FC_MSG_REQ_FLOW_ADD_BULK;
-	req->req = flow_req;
-	req->rsp = flow_rsp;
-	req->n_keys = n_keys;
-
-	/* Send request and wait for response */
-	rsp = app_msg_send_recv(app, pipeline_id, req, 10000);
-	if (rsp == NULL) {
-		for (i = 0; i < n_keys; i++)
-			if (new_flow[i])
-				rte_free(flow[i]);
-
-		rte_free(flow_rsp);
-		rte_free(flow_req);
-		rte_free(new_flow);
-		rte_free(signature);
-		rte_free(flow);
-		return -1;
-	}
-
-	/* Read response */
-	status = 0;
-
-	for (i = 0; i < rsp->n_keys; i++)
-		if ((flow_rsp[i].entry_ptr == NULL) ||
-			((new_flow[i] == 0) && (flow_rsp[i].key_found == 0)) ||
-			((new_flow[i] == 1) && (flow_rsp[i].key_found == 1)))
-			status = -1;
-
-	if (rsp->n_keys < n_keys)
-		status = -1;
-
-	/* Commit flows */
-	for (i = 0; i < rsp->n_keys; i++) {
-		memcpy(&flow[i]->key, &key[i], sizeof(flow[i]->key));
-		flow[i]->port_id = port_id[i];
-		flow[i]->flow_id = flow_id[i];
-		flow[i]->signature = signature[i];
-		flow[i]->entry_ptr = flow_rsp[i].entry_ptr;
-
-		if (new_flow[i]) {
-			uint32_t bucket_id = signature[i] & (N_BUCKETS - 1);
-
-			TAILQ_INSERT_TAIL(&p->flows[bucket_id], flow[i], node);
-			p->n_flows++;
-		}
-	}
-
-	/* Free resources */
-
-	for (i = rsp->n_keys; i < n_keys; i++)
-		if (new_flow[i])
-			rte_free(flow[i]);
-
-	app_msg_free(app, rsp);
-	rte_free(flow_rsp);
-	rte_free(flow_req);
-	rte_free(new_flow);
-	rte_free(signature);
-	rte_free(flow);
-
-	return status;
-}
-
-int
-app_pipeline_fc_del(struct app_params *app,
-	uint32_t pipeline_id,
-	struct pipeline_fc_key *key)
-{
-	struct app_pipeline_fc *p;
-	struct app_pipeline_fc_flow *flow;
-
-	struct pipeline_fc_del_msg_req *req;
-	struct pipeline_fc_del_msg_rsp *rsp;
-
-	uint32_t signature, bucket_id;
-
-	/* Check input arguments */
-	if ((app == NULL) ||
-		(key == NULL))
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_flow_classification);
-	if (p == NULL)
-		return -1;
-
-	if (app_pipeline_fc_key_check(key) != 0)
-		return -1;
-
-	/* 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;
-	app_pipeline_fc_key_convert(key, req->key, &signature);
-
-	/* Send request and wait for response */
-	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	/* Read response */
-	if (rsp->status || !rsp->key_found) {
-		app_msg_free(app, rsp);
-		return -1;
-	}
-
-	/* Remove rule */
-	bucket_id = signature & (N_BUCKETS - 1);
-	TAILQ_REMOVE(&p->flows[bucket_id], flow, node);
-	p->n_flows--;
-	rte_free(flow);
-
-	/* Free response */
-	app_msg_free(app, rsp);
-
-	return 0;
-}
-
-int
-app_pipeline_fc_add_default(struct app_params *app,
-	uint32_t pipeline_id,
-	uint32_t port_id)
-{
-	struct app_pipeline_fc *p;
-
-	struct pipeline_fc_add_default_msg_req *req;
-	struct pipeline_fc_add_default_msg_rsp *rsp;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_flow_classification);
-	if (p == NULL)
-		return -1;
-
-	if (port_id >= p->n_ports_out)
-		return -1;
-
-	/* 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_DEFAULT;
-	req->port_id = port_id;
-
-	/* Send request and wait for response */
-	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	/* Read response and write flow */
-	if (rsp->status || (rsp->entry_ptr == NULL)) {
-		app_msg_free(app, rsp);
-		return -1;
-	}
-
-	p->default_flow_port_id = port_id;
-	p->default_flow_entry_ptr = rsp->entry_ptr;
-
-	/* Commit route */
-	p->default_flow_present = 1;
-
-	/* Free response */
-	app_msg_free(app, rsp);
-
-	return 0;
-}
-
-int
-app_pipeline_fc_del_default(struct app_params *app,
-	uint32_t pipeline_id)
-{
-	struct app_pipeline_fc *p;
-
-	struct pipeline_fc_del_default_msg_req *req;
-	struct pipeline_fc_del_default_msg_rsp *rsp;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_flow_classification);
-	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_FC_MSG_REQ_FLOW_DEL_DEFAULT;
-
-	/* Send request and wait for response */
-	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	/* Read response */
-	if (rsp->status) {
-		app_msg_free(app, rsp);
-		return -1;
-	}
-
-	/* Commit route */
-	p->default_flow_present = 0;
-
-	/* Free response */
-	app_msg_free(app, rsp);
-
-	return 0;
-}
-
-/*
- * Flow ls
- */
-
-static void
-print_fc_qinq_flow(struct app_pipeline_fc_flow *flow)
-{
-	printf("(SVLAN = %" PRIu32 ", "
-		"CVLAN = %" PRIu32 ") => "
-		"Port = %" PRIu32 ", "
-		"Flow ID = %" PRIu32 ", "
-		"(signature = 0x%08" PRIx32 ", "
-		"entry_ptr = %p)\n",
-
-		flow->key.key.qinq.svlan,
-		flow->key.key.qinq.cvlan,
-		flow->port_id,
-		flow->flow_id,
-		flow->signature,
-		flow->entry_ptr);
-}
-
-static void
-print_fc_ipv4_5tuple_flow(struct app_pipeline_fc_flow *flow)
-{
-	printf("(SA = %" PRIu32 ".%" PRIu32 ".%" PRIu32 ".%" PRIu32 ", "
-		   "DA = %" PRIu32 ".%" PRIu32 ".%" PRIu32 ".%" PRIu32 ", "
-		   "SP = %" PRIu32 ", "
-		   "DP = %" PRIu32 ", "
-		   "Proto = %" PRIu32 ") => "
-		   "Port = %" PRIu32 ", "
-		   "Flow ID = %" PRIu32 " "
-		   "(signature = 0x%08" PRIx32 ", "
-		   "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->flow_id,
-		   flow->signature,
-		   flow->entry_ptr);
-}
-
-static void
-print_fc_ipv6_5tuple_flow(struct app_pipeline_fc_flow *flow) {
-	printf("(SA = %02" PRIx32 "%02" PRIx32 ":%02" PRIx32 "%02" PRIx32
-		":%02" PRIx32 "%02" PRIx32 ":%02" PRIx32 "%02" PRIx32
-		":%02" PRIx32 "%02" PRIx32 ":%02" PRIx32 "%02" PRIx32
-		":%02" PRIx32 "%02" PRIx32 ":%02" PRIx32 "%02" PRIx32 ", "
-		"DA = %02" PRIx32 "%02" PRIx32 ":%02" PRIx32 "%02" PRIx32
-		":%02" PRIx32 "%02" PRIx32 ":%02" PRIx32 "%02" PRIx32
-		":%02" PRIx32 "%02" PRIx32 ":%02" PRIx32 "%02" PRIx32
-		":%02" PRIx32 "%02" PRIx32 ":%02" PRIx32 "%02" PRIx32 ", "
-		"SP = %" PRIu32 ", "
-		"DP = %" PRIu32 " "
-		"Proto = %" PRIu32 " "
-		"=> Port = %" PRIu32 ", "
-		"Flow ID = %" PRIu32 " "
-		"(signature = 0x%08" PRIx32 ", "
-		"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],
-
-		flow->key.key.ipv6_5tuple.port_src,
-		flow->key.key.ipv6_5tuple.port_dst,
-
-		flow->key.key.ipv6_5tuple.proto,
-
-		flow->port_id,
-		flow->flow_id,
-		flow->signature,
-		flow->entry_ptr);
-}
-
-static void
-print_fc_flow(struct app_pipeline_fc_flow *flow)
-{
-	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;
-	}
-}
-
-static int
-app_pipeline_fc_ls(struct app_params *app,
-		uint32_t pipeline_id)
-{
-	struct app_pipeline_fc *p;
-	struct app_pipeline_fc_flow *flow;
-	uint32_t i;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_flow_classification);
-	if (p == NULL)
-		return -1;
-
-	for (i = 0; i < N_BUCKETS; i++)
-		TAILQ_FOREACH(flow, &p->flows[i], node)
-			print_fc_flow(flow);
-
-	if (p->default_flow_present)
-		printf("Default flow: port %" PRIu32 " (entry ptr = %p)\n",
-			p->default_flow_port_id,
-			p->default_flow_entry_ptr);
-	else
-		printf("Default: DROP\n");
-
-	return 0;
-}
-/*
- * flow
- *
- * flow add:
- *    p <pipelineid> flow add qinq <svlan> <cvlan> port <portid> id <flowid>
- *    p <pipelineid> flow add qinq bulk <file>
- *    p <pipelineid> flow add ipv4 <sipaddr> <dipaddr> <sport> <dport> <proto> port <port ID> id <flowid>
- *    p <pipelineid> flow add ipv4 bulk <file>
- *    p <pipelineid> flow add ipv6 <sipaddr> <dipaddr> <sport> <dport> <proto> port <port ID> id <flowid>
- *    p <pipelineid> flow add ipv6 bulk <file>
- *
- * flow add default:
- *    p <pipelineid> flow add default <portid>
- *
- * flow del:
- *    p <pipelineid> flow del qinq <svlan> <cvlan>
- *    p <pipelineid> flow del ipv4 <sipaddr> <dipaddr> <sport> <dport> <proto>
- *    p <pipelineid> flow del ipv6 <sipaddr> <dipaddr> <sport> <dport> <proto>
- *
- * flow del default:
- *    p <pipelineid> flow del default
- *
- * flow ls:
- *    p <pipelineid> flow ls
- */
-
-struct cmd_flow_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t flow_string;
-	cmdline_multi_string_t multi_string;
-};
-
-static void
-cmd_flow_parsed(void *parsed_result,
-	__attribute__((unused)) struct cmdline *cl,
-	void *data)
-{
-	struct cmd_flow_result *results = parsed_result;
-	struct app_params *app = data;
-
-	char *tokens[16];
-	uint32_t n_tokens = RTE_DIM(tokens);
-	int status;
-
-	status = parse_tokenize_string(results->multi_string, tokens, &n_tokens);
-	if (status) {
-		printf(CMD_MSG_TOO_MANY_ARGS, "flow");
-		return;
-	}
-
-	/* flow add qinq */
-	if ((n_tokens >= 3) &&
-		(strcmp(tokens[0], "add") == 0) &&
-		(strcmp(tokens[1], "qinq") == 0) &&
-		strcmp(tokens[2], "bulk")) {
-		struct pipeline_fc_key key;
-		uint32_t svlan;
-		uint32_t cvlan;
-		uint32_t port_id;
-		uint32_t flow_id;
-
-		memset(&key, 0, sizeof(key));
-
-		if (n_tokens != 8) {
-			printf(CMD_MSG_MISMATCH_ARGS, "flow add qinq");
-			return;
-		}
-
-		if (parser_read_uint32(&svlan, tokens[2]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "svlan");
-			return;
-		}
-
-		if (parser_read_uint32(&cvlan, tokens[3]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "cvlan");
-			return;
-		}
-
-		if (strcmp(tokens[4], "port") != 0) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "port");
-			return;
-		}
-
-		if (parser_read_uint32(&port_id, tokens[5]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "portid");
-			return;
-		}
-
-		if (strcmp(tokens[6], "id") != 0) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "id");
-			return;
-		}
-
-		if (parser_read_uint32(&flow_id, tokens[7]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "flowid");
-			return;
-		}
-
-		key.type = FLOW_KEY_QINQ;
-		key.key.qinq.svlan = svlan;
-		key.key.qinq.cvlan = cvlan;
-
-		status = app_pipeline_fc_add(app,
-			results->pipeline_id,
-			&key,
-			port_id,
-			flow_id);
-		if (status)
-			printf(CMD_MSG_FAIL, "flow add qinq");
-
-		return;
-	} /* flow add qinq */
-
-	/* flow add ipv4 */
-	if ((n_tokens >= 3) &&
-		(strcmp(tokens[0], "add") == 0) &&
-		(strcmp(tokens[1], "ipv4") == 0) &&
-		strcmp(tokens[2], "bulk")) {
-		struct pipeline_fc_key key;
-		struct in_addr sipaddr;
-		struct in_addr dipaddr;
-		uint32_t sport;
-		uint32_t dport;
-		uint32_t proto;
-		uint32_t port_id;
-		uint32_t flow_id;
-
-		memset(&key, 0, sizeof(key));
-
-		if (n_tokens != 11) {
-			printf(CMD_MSG_MISMATCH_ARGS, "flow add ipv4");
-			return;
-		}
-
-		if (parse_ipv4_addr(tokens[2], &sipaddr) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "sipv4addr");
-			return;
-		}
-		if (parse_ipv4_addr(tokens[3], &dipaddr) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "dipv4addr");
-			return;
-		}
-
-		if (parser_read_uint32(&sport, tokens[4]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "sport");
-			return;
-		}
-
-		if (parser_read_uint32(&dport, tokens[5]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "dport");
-			return;
-		}
-
-		if (parser_read_uint32(&proto, tokens[6]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "proto");
-			return;
-		}
-
-		if (strcmp(tokens[7], "port") != 0) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "port");
-			return;
-		}
-
-		if (parser_read_uint32(&port_id, tokens[8]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "portid");
-			return;
-		}
-
-		if (strcmp(tokens[9], "id") != 0) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "id");
-			return;
-		}
-
-		if (parser_read_uint32(&flow_id, tokens[10]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "flowid");
-			return;
-		}
-
-		key.type = FLOW_KEY_IPV4_5TUPLE;
-		key.key.ipv4_5tuple.ip_src = rte_be_to_cpu_32(sipaddr.s_addr);
-		key.key.ipv4_5tuple.ip_dst = rte_be_to_cpu_32(dipaddr.s_addr);
-		key.key.ipv4_5tuple.port_src = sport;
-		key.key.ipv4_5tuple.port_dst = dport;
-		key.key.ipv4_5tuple.proto = proto;
-
-		status = app_pipeline_fc_add(app,
-			results->pipeline_id,
-			&key,
-			port_id,
-			flow_id);
-		if (status)
-			printf(CMD_MSG_FAIL, "flow add ipv4");
-
-		return;
-	} /* flow add ipv4 */
-
-	/* flow add ipv6 */
-	if ((n_tokens >= 3) &&
-		(strcmp(tokens[0], "add") == 0) &&
-		(strcmp(tokens[1], "ipv6") == 0) &&
-		strcmp(tokens[2], "bulk")) {
-		struct pipeline_fc_key key;
-		struct in6_addr sipaddr;
-		struct in6_addr dipaddr;
-		uint32_t sport;
-		uint32_t dport;
-		uint32_t proto;
-		uint32_t port_id;
-		uint32_t flow_id;
-
-		memset(&key, 0, sizeof(key));
-
-		if (n_tokens != 11) {
-			printf(CMD_MSG_MISMATCH_ARGS, "flow add ipv6");
-			return;
-		}
-
-		if (parse_ipv6_addr(tokens[2], &sipaddr) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "sipv6addr");
-			return;
-		}
-		if (parse_ipv6_addr(tokens[3], &dipaddr) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "dipv6addr");
-			return;
-		}
-
-		if (parser_read_uint32(&sport, tokens[4]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "sport");
-			return;
-		}
-
-		if (parser_read_uint32(&dport, tokens[5]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "dport");
-			return;
-		}
-
-		if (parser_read_uint32(&proto, tokens[6]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "proto");
-			return;
-		}
-
-		if (strcmp(tokens[7], "port") != 0) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "port");
-			return;
-		}
-
-		if (parser_read_uint32(&port_id, tokens[8]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "portid");
-			return;
-		}
-
-		if (strcmp(tokens[9], "id") != 0) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "id");
-			return;
-		}
-
-		if (parser_read_uint32(&flow_id, tokens[10]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "flowid");
-			return;
-		}
-
-		key.type = FLOW_KEY_IPV6_5TUPLE;
-		memcpy(key.key.ipv6_5tuple.ip_src, (void *)&sipaddr, 16);
-		memcpy(key.key.ipv6_5tuple.ip_dst, (void *)&dipaddr, 16);
-		key.key.ipv6_5tuple.port_src = sport;
-		key.key.ipv6_5tuple.port_dst = dport;
-		key.key.ipv6_5tuple.proto = proto;
-
-		status = app_pipeline_fc_add(app,
-			results->pipeline_id,
-			&key,
-			port_id,
-			flow_id);
-		if (status)
-			printf(CMD_MSG_FAIL, "flow add ipv6");
-
-		return;
-	} /* flow add ipv6 */
-
-	/* flow add qinq bulk */
-	if ((n_tokens >= 3) &&
-		(strcmp(tokens[0], "add") == 0) &&
-		(strcmp(tokens[1], "qinq") == 0) &&
-		(strcmp(tokens[2], "bulk") == 0)) {
-		struct pipeline_fc_key *keys;
-		uint32_t *port_ids, *flow_ids, n_keys, line;
-		char *filename;
-
-		if (n_tokens != 4) {
-			printf(CMD_MSG_MISMATCH_ARGS, "flow add qinq bulk");
-			return;
-		}
-
-		filename = tokens[3];
-
-		n_keys = APP_PIPELINE_FC_MAX_FLOWS_IN_FILE;
-		keys = malloc(n_keys * sizeof(struct pipeline_fc_key));
-		if (keys == NULL)
-			return;
-		memset(keys, 0, n_keys * sizeof(struct pipeline_fc_key));
-
-		port_ids = malloc(n_keys * sizeof(uint32_t));
-		if (port_ids == NULL) {
-			free(keys);
-			return;
-		}
-
-		flow_ids = malloc(n_keys * sizeof(uint32_t));
-		if (flow_ids == NULL) {
-			free(port_ids);
-			free(keys);
-			return;
-		}
-
-		status = app_pipeline_fc_load_file_qinq(filename,
-			keys,
-			port_ids,
-			flow_ids,
-			&n_keys,
-			&line);
-		if (status != 0) {
-			printf(CMD_MSG_FILE_ERR, filename, line);
-			free(flow_ids);
-			free(port_ids);
-			free(keys);
-			return;
-		}
-
-		status = app_pipeline_fc_add_bulk(app,
-			results->pipeline_id,
-			keys,
-			port_ids,
-			flow_ids,
-			n_keys);
-		if (status)
-			printf(CMD_MSG_FAIL, "flow add qinq bulk");
-
-		free(flow_ids);
-		free(port_ids);
-		free(keys);
-		return;
-	} /* flow add qinq bulk */
-
-	/* flow add ipv4 bulk */
-	if ((n_tokens >= 3) &&
-		(strcmp(tokens[0], "add") == 0) &&
-		(strcmp(tokens[1], "ipv4") == 0) &&
-		(strcmp(tokens[2], "bulk") == 0)) {
-		struct pipeline_fc_key *keys;
-		uint32_t *port_ids, *flow_ids, n_keys, line;
-		char *filename;
-
-		if (n_tokens != 4) {
-			printf(CMD_MSG_MISMATCH_ARGS, "flow add ipv4 bulk");
-			return;
-		}
-
-		filename = tokens[3];
-
-		n_keys = APP_PIPELINE_FC_MAX_FLOWS_IN_FILE;
-		keys = malloc(n_keys * sizeof(struct pipeline_fc_key));
-		if (keys == NULL)
-			return;
-		memset(keys, 0, n_keys * sizeof(struct pipeline_fc_key));
-
-		port_ids = malloc(n_keys * sizeof(uint32_t));
-		if (port_ids == NULL) {
-			free(keys);
-			return;
-		}
-
-		flow_ids = malloc(n_keys * sizeof(uint32_t));
-		if (flow_ids == NULL) {
-			free(port_ids);
-			free(keys);
-			return;
-		}
-
-		status = app_pipeline_fc_load_file_ipv4(filename,
-			keys,
-			port_ids,
-			flow_ids,
-			&n_keys,
-			&line);
-		if (status != 0) {
-			printf(CMD_MSG_FILE_ERR, filename, line);
-			free(flow_ids);
-			free(port_ids);
-			free(keys);
-			return;
-		}
-
-		status = app_pipeline_fc_add_bulk(app,
-			results->pipeline_id,
-			keys,
-			port_ids,
-			flow_ids,
-			n_keys);
-		if (status)
-			printf(CMD_MSG_FAIL, "flow add ipv4 bulk");
-
-		free(flow_ids);
-		free(port_ids);
-		free(keys);
-		return;
-	} /* flow add ipv4 bulk */
-
-	/* flow add ipv6 bulk */
-	if ((n_tokens >= 3) &&
-		(strcmp(tokens[0], "add") == 0) &&
-		(strcmp(tokens[1], "ipv6") == 0) &&
-		(strcmp(tokens[2], "bulk") == 0)) {
-		struct pipeline_fc_key *keys;
-		uint32_t *port_ids, *flow_ids, n_keys, line;
-		char *filename;
-
-		if (n_tokens != 4) {
-			printf(CMD_MSG_MISMATCH_ARGS, "flow add ipv6 bulk");
-			return;
-		}
-
-		filename = tokens[3];
-
-		n_keys = APP_PIPELINE_FC_MAX_FLOWS_IN_FILE;
-		keys = malloc(n_keys * sizeof(struct pipeline_fc_key));
-		if (keys == NULL)
-			return;
-		memset(keys, 0, n_keys * sizeof(struct pipeline_fc_key));
-
-		port_ids = malloc(n_keys * sizeof(uint32_t));
-		if (port_ids == NULL) {
-			free(keys);
-			return;
-		}
-
-		flow_ids = malloc(n_keys * sizeof(uint32_t));
-		if (flow_ids == NULL) {
-			free(port_ids);
-			free(keys);
-			return;
-		}
-
-		status = app_pipeline_fc_load_file_ipv6(filename,
-			keys,
-			port_ids,
-			flow_ids,
-			&n_keys,
-			&line);
-		if (status != 0) {
-			printf(CMD_MSG_FILE_ERR, filename, line);
-			free(flow_ids);
-			free(port_ids);
-			free(keys);
-			return;
-		}
-
-		status = app_pipeline_fc_add_bulk(app,
-			results->pipeline_id,
-			keys,
-			port_ids,
-			flow_ids,
-			n_keys);
-		if (status)
-			printf(CMD_MSG_FAIL, "flow add ipv6 bulk");
-
-		free(flow_ids);
-		free(port_ids);
-		free(keys);
-		return;
-	} /* flow add ipv6 bulk */
-
-	/* flow add default*/
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "add") == 0) &&
-		(strcmp(tokens[1], "default") == 0)) {
-		uint32_t port_id;
-
-		if (n_tokens != 3) {
-			printf(CMD_MSG_MISMATCH_ARGS, "flow add default");
-			return;
-		}
-
-		if (parser_read_uint32(&port_id, tokens[2]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "portid");
-			return;
-		}
-
-		status = app_pipeline_fc_add_default(app,
-			results->pipeline_id,
-			port_id);
-		if (status)
-			printf(CMD_MSG_FAIL, "flow add default");
-
-		return;
-	} /* flow add default */
-
-	/* flow del qinq */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "del") == 0) &&
-		(strcmp(tokens[1], "qinq") == 0)) {
-		struct pipeline_fc_key key;
-		uint32_t svlan;
-		uint32_t cvlan;
-
-		memset(&key, 0, sizeof(key));
-
-		if (n_tokens != 4) {
-			printf(CMD_MSG_MISMATCH_ARGS, "flow del qinq");
-			return;
-		}
-
-		if (parser_read_uint32(&svlan, tokens[2]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "svlan");
-			return;
-		}
-
-		if (parser_read_uint32(&cvlan, tokens[3]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "cvlan");
-			return;
-		}
-
-		key.type = FLOW_KEY_QINQ;
-		key.key.qinq.svlan = svlan;
-		key.key.qinq.cvlan = cvlan;
-
-		status = app_pipeline_fc_del(app,
-			results->pipeline_id,
-			&key);
-		if (status)
-			printf(CMD_MSG_FAIL, "flow del qinq");
-
-		return;
-	} /* flow del qinq */
-
-	/* flow del ipv4 */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "del") == 0) &&
-		(strcmp(tokens[1], "ipv4") == 0)) {
-		struct pipeline_fc_key key;
-		struct in_addr sipaddr;
-		struct in_addr dipaddr;
-		uint32_t sport;
-		uint32_t dport;
-		uint32_t proto;
-
-		memset(&key, 0, sizeof(key));
-
-		if (n_tokens != 7) {
-			printf(CMD_MSG_MISMATCH_ARGS, "flow del ipv4");
-			return;
-		}
-
-		if (parse_ipv4_addr(tokens[2], &sipaddr) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "sipv4addr");
-			return;
-		}
-		if (parse_ipv4_addr(tokens[3], &dipaddr) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "dipv4addr");
-			return;
-		}
-
-		if (parser_read_uint32(&sport, tokens[4]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "sport");
-			return;
-		}
-
-		if (parser_read_uint32(&dport, tokens[5]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "dport");
-			return;
-		}
-
-		if (parser_read_uint32(&proto, tokens[6]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "proto");
-			return;
-		}
-
-		key.type = FLOW_KEY_IPV4_5TUPLE;
-		key.key.ipv4_5tuple.ip_src = rte_be_to_cpu_32(sipaddr.s_addr);
-		key.key.ipv4_5tuple.ip_dst = rte_be_to_cpu_32(dipaddr.s_addr);
-		key.key.ipv4_5tuple.port_src = sport;
-		key.key.ipv4_5tuple.port_dst = dport;
-		key.key.ipv4_5tuple.proto = proto;
-
-		status = app_pipeline_fc_del(app,
-			results->pipeline_id,
-			&key);
-		if (status)
-			printf(CMD_MSG_FAIL, "flow del ipv4");
-
-		return;
-	} /* flow del ipv4 */
-
-	/* flow del ipv6 */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "del") == 0) &&
-		(strcmp(tokens[1], "ipv6") == 0)) {
-		struct pipeline_fc_key key;
-		struct in6_addr sipaddr;
-		struct in6_addr dipaddr;
-		uint32_t sport;
-		uint32_t dport;
-		uint32_t proto;
-
-		memset(&key, 0, sizeof(key));
-
-		if (n_tokens != 7) {
-			printf(CMD_MSG_MISMATCH_ARGS, "flow del ipv6");
-			return;
-		}
-
-		if (parse_ipv6_addr(tokens[2], &sipaddr) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "sipv6addr");
-			return;
-		}
-
-		if (parse_ipv6_addr(tokens[3], &dipaddr) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "dipv6addr");
-			return;
-		}
-
-		if (parser_read_uint32(&sport, tokens[4]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "sport");
-			return;
-		}
-
-		if (parser_read_uint32(&dport, tokens[5]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "dport");
-			return;
-		}
-
-		if (parser_read_uint32(&proto, tokens[6]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "proto");
-			return;
-		}
-
-		key.type = FLOW_KEY_IPV6_5TUPLE;
-		memcpy(key.key.ipv6_5tuple.ip_src, &sipaddr, 16);
-		memcpy(key.key.ipv6_5tuple.ip_dst, &dipaddr, 16);
-		key.key.ipv6_5tuple.port_src = sport;
-		key.key.ipv6_5tuple.port_dst = dport;
-		key.key.ipv6_5tuple.proto = proto;
-
-		status = app_pipeline_fc_del(app,
-			results->pipeline_id,
-			&key);
-		if (status)
-			printf(CMD_MSG_FAIL, "flow del ipv6");
-
-		return;
-	} /* flow del ipv6 */
-
-	/* flow del default*/
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "del") == 0) &&
-		(strcmp(tokens[1], "default") == 0)) {
-		if (n_tokens != 2) {
-			printf(CMD_MSG_MISMATCH_ARGS, "flow del default");
-			return;
-		}
-
-		status = app_pipeline_fc_del_default(app,
-			results->pipeline_id);
-		if (status)
-			printf(CMD_MSG_FAIL, "flow del default");
-
-		return;
-	} /* flow del default */
-
-	/* flow ls */
-	if ((n_tokens >= 1) && (strcmp(tokens[0], "ls") == 0)) {
-		if (n_tokens != 1) {
-			printf(CMD_MSG_MISMATCH_ARGS, "flow ls");
-			return;
-		}
-
-		status = app_pipeline_fc_ls(app, results->pipeline_id);
-		if (status)
-			printf(CMD_MSG_FAIL, "flow ls");
-
-		return;
-	} /* flow ls */
-
-	printf(CMD_MSG_MISMATCH_ARGS, "flow");
-}
-
-static cmdline_parse_token_string_t cmd_flow_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_flow_result, p_string, "p");
-
-static cmdline_parse_token_num_t cmd_flow_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_flow_result, pipeline_id, UINT32);
-
-static cmdline_parse_token_string_t cmd_flow_flow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_flow_result, flow_string, "flow");
-
-static cmdline_parse_token_string_t cmd_flow_multi_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_flow_result, multi_string,
-		TOKEN_STRING_MULTI);
-
-static cmdline_parse_inst_t cmd_flow = {
-	.f = cmd_flow_parsed,
-	.data = NULL,
-	.help_str = "flow add / add bulk / add default / del / del default / ls",
-	.tokens = {
-		(void *) &cmd_flow_p_string,
-		(void *) &cmd_flow_pipeline_id,
-		(void *) &cmd_flow_flow_string,
-		(void *) &cmd_flow_multi_string,
-		NULL,
-	},
-};
-
-static cmdline_parse_ctx_t pipeline_cmds[] = {
-	(cmdline_parse_inst_t *) &cmd_flow,
-	NULL,
-};
-
-static struct pipeline_fe_ops pipeline_flow_classification_fe_ops = {
-	.f_init = app_pipeline_fc_init,
-	.f_post_init = NULL,
-	.f_free = app_pipeline_fc_free,
-	.f_track = app_pipeline_track_default,
-	.cmds = pipeline_cmds,
-};
-
-struct pipeline_type pipeline_flow_classification = {
-	.name = "FLOW_CLASSIFICATION",
-	.be_ops = &pipeline_flow_classification_be_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
deleted file mode 100644
index 8c35498..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_flow_classification.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#ifndef __INCLUDE_PIPELINE_FLOW_CLASSIFICATION_H__
-#define __INCLUDE_PIPELINE_FLOW_CLASSIFICATION_H__
-
-#include "pipeline.h"
-#include "pipeline_flow_classification_be.h"
-
-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;
-	} key;
-};
-
-int
-app_pipeline_fc_add(struct app_params *app,
-	uint32_t pipeline_id,
-	struct pipeline_fc_key *key,
-	uint32_t port_id,
-	uint32_t flow_id);
-
-int
-app_pipeline_fc_add_bulk(struct app_params *app,
-	uint32_t pipeline_id,
-	struct pipeline_fc_key *key,
-	uint32_t *port_id,
-	uint32_t *flow_id,
-	uint32_t n_keys);
-
-int
-app_pipeline_fc_del(struct app_params *app,
-	uint32_t pipeline_id,
-	struct pipeline_fc_key *key);
-
-int
-app_pipeline_fc_add_default(struct app_params *app,
-	uint32_t pipeline_id,
-	uint32_t port_id);
-
-int
-app_pipeline_fc_del_default(struct app_params *app,
-	uint32_t pipeline_id);
-
-#ifndef APP_PIPELINE_FC_MAX_FLOWS_IN_FILE
-#define APP_PIPELINE_FC_MAX_FLOWS_IN_FILE	(16 * 1024 * 1024)
-#endif
-
-int
-app_pipeline_fc_load_file_qinq(char *filename,
-	struct pipeline_fc_key *keys,
-	uint32_t *port_ids,
-	uint32_t *flow_ids,
-	uint32_t *n_keys,
-	uint32_t *line);
-
-int
-app_pipeline_fc_load_file_ipv4(char *filename,
-	struct pipeline_fc_key *keys,
-	uint32_t *port_ids,
-	uint32_t *flow_ids,
-	uint32_t *n_keys,
-	uint32_t *line);
-
-int
-app_pipeline_fc_load_file_ipv6(char *filename,
-	struct pipeline_fc_key *keys,
-	uint32_t *port_ids,
-	uint32_t *flow_ids,
-	uint32_t *n_keys,
-	uint32_t *line);
-
-extern struct pipeline_type pipeline_flow_classification;
-
-#endif
diff --git a/examples/ip_pipeline/pipeline/pipeline_flow_classification_be.c b/examples/ip_pipeline/pipeline/pipeline_flow_classification_be.c
deleted file mode 100644
index 097ec34..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_flow_classification_be.c
+++ /dev/null
@@ -1,723 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2016 Intel Corporation
- */
-
-#include <string.h>
-
-#include <rte_common.h>
-#include <rte_malloc.h>
-#include <rte_table_hash.h>
-#include <rte_byteorder.h>
-#include <pipeline.h>
-
-#include "pipeline_flow_classification_be.h"
-#include "pipeline_actions_common.h"
-#include "parser.h"
-#include "hash_func.h"
-
-struct pipeline_flow_classification {
-	struct pipeline p;
-	pipeline_msg_req_handler custom_handlers[PIPELINE_FC_MSG_REQS];
-
-	uint32_t n_flows;
-	uint32_t key_size;
-	uint32_t flow_id;
-
-	uint32_t key_offset;
-	uint32_t hash_offset;
-	uint8_t key_mask[PIPELINE_FC_FLOW_KEY_MAX_SIZE];
-	uint32_t key_mask_present;
-	uint32_t flow_id_offset;
-
-} __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_add_bulk_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 pipeline_msg_req_handler custom_handlers[] = {
-	[PIPELINE_FC_MSG_REQ_FLOW_ADD] =
-		pipeline_fc_msg_req_add_handler,
-	[PIPELINE_FC_MSG_REQ_FLOW_ADD_BULK] =
-		pipeline_fc_msg_req_add_bulk_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,
-};
-
-/*
- * Flow table
- */
-struct flow_table_entry {
-	struct rte_pipeline_table_entry head;
-
-	uint32_t flow_id;
-	uint32_t pad;
-};
-
-rte_table_hash_op_hash hash_func[] = {
-	hash_default_key8,
-	hash_default_key16,
-	hash_default_key24,
-	hash_default_key32,
-	hash_default_key40,
-	hash_default_key48,
-	hash_default_key56,
-	hash_default_key64
-};
-
-/*
- * Flow table AH - Write flow_id to packet meta-data
- */
-static inline void
-pkt_work_flow_id(
-	struct rte_mbuf *pkt,
-	struct rte_pipeline_table_entry *table_entry,
-	void *arg)
-{
-	struct pipeline_flow_classification *p_fc = arg;
-	uint32_t *flow_id_ptr =
-		RTE_MBUF_METADATA_UINT32_PTR(pkt, p_fc->flow_id_offset);
-	struct flow_table_entry *entry =
-		(struct flow_table_entry *) table_entry;
-
-	/* Read */
-	uint32_t flow_id = entry->flow_id;
-
-	/* Compute */
-
-	/* Write */
-	*flow_id_ptr = flow_id;
-}
-
-static inline void
-pkt4_work_flow_id(
-	struct rte_mbuf **pkts,
-	struct rte_pipeline_table_entry **table_entries,
-	void *arg)
-{
-	struct pipeline_flow_classification *p_fc = arg;
-
-	uint32_t *flow_id_ptr0 =
-		RTE_MBUF_METADATA_UINT32_PTR(pkts[0], p_fc->flow_id_offset);
-	uint32_t *flow_id_ptr1 =
-		RTE_MBUF_METADATA_UINT32_PTR(pkts[1], p_fc->flow_id_offset);
-	uint32_t *flow_id_ptr2 =
-		RTE_MBUF_METADATA_UINT32_PTR(pkts[2], p_fc->flow_id_offset);
-	uint32_t *flow_id_ptr3 =
-		RTE_MBUF_METADATA_UINT32_PTR(pkts[3], p_fc->flow_id_offset);
-
-	struct flow_table_entry *entry0 =
-		(struct flow_table_entry *) table_entries[0];
-	struct flow_table_entry *entry1 =
-		(struct flow_table_entry *) table_entries[1];
-	struct flow_table_entry *entry2 =
-		(struct flow_table_entry *) table_entries[2];
-	struct flow_table_entry *entry3 =
-		(struct flow_table_entry *) table_entries[3];
-
-	/* Read */
-	uint32_t flow_id0 = entry0->flow_id;
-	uint32_t flow_id1 = entry1->flow_id;
-	uint32_t flow_id2 = entry2->flow_id;
-	uint32_t flow_id3 = entry3->flow_id;
-
-	/* Compute */
-
-	/* Write */
-	*flow_id_ptr0 = flow_id0;
-	*flow_id_ptr1 = flow_id1;
-	*flow_id_ptr2 = flow_id2;
-	*flow_id_ptr3 = flow_id3;
-}
-
-PIPELINE_TABLE_AH_HIT(fc_table_ah_hit,
-		pkt_work_flow_id, pkt4_work_flow_id);
-
-static rte_pipeline_table_action_handler_hit
-get_fc_table_ah_hit(struct pipeline_flow_classification *p)
-{
-	if (p->flow_id)
-		return fc_table_ah_hit;
-
-	return NULL;
-}
-
-/*
- * Argument parsing
- */
-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 key_mask_present = 0;
-	uint32_t flow_id_offset_present = 0;
-
-	uint32_t i;
-	char key_mask_str[PIPELINE_FC_FLOW_KEY_MAX_SIZE * 2 + 1];
-
-	p->hash_offset = 0;
-
-	/* default values */
-	p->flow_id = 0;
-
-	for (i = 0; i < params->n_args; i++) {
-		char *arg_name = params->args_name[i];
-		char *arg_value = params->args_value[i];
-
-		/* n_flows */
-		if (strcmp(arg_name, "n_flows") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				n_flows_present == 0, params->name,
-				arg_name);
-			n_flows_present = 1;
-
-			status = parser_read_uint32(&p->n_flows,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL(((status != -EINVAL) &&
-				(p->n_flows != 0)), params->name,
-				arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			continue;
-		}
-
-		/* key_offset */
-		if (strcmp(arg_name, "key_offset") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				key_offset_present == 0, params->name,
-				arg_name);
-			key_offset_present = 1;
-
-			status = parser_read_uint32(&p->key_offset,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			continue;
-		}
-
-		/* key_size */
-		if (strcmp(arg_name, "key_size") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				key_size_present == 0, params->name,
-				arg_name);
-			key_size_present = 1;
-
-			status = parser_read_uint32(&p->key_size,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL(((status != -EINVAL) &&
-				(p->key_size != 0) &&
-				(p->key_size % 8 == 0)),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG(((status != -ERANGE) &&
-				(p->key_size <=
-				PIPELINE_FC_FLOW_KEY_MAX_SIZE)),
-				params->name, arg_name, arg_value);
-
-			continue;
-		}
-
-		/* key_mask */
-		if (strcmp(arg_name, "key_mask") == 0) {
-			int mask_str_len = strlen(arg_value);
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				key_mask_present == 0,
-				params->name, arg_name);
-			key_mask_present = 1;
-
-			PIPELINE_ARG_CHECK((mask_str_len <=
-				(PIPELINE_FC_FLOW_KEY_MAX_SIZE * 2)),
-				"Parse error in section \"%s\": entry "
-				"\"%s\" is too long", params->name,
-				arg_name);
-
-			snprintf(key_mask_str, mask_str_len + 1, "%s",
-				arg_value);
-
-			continue;
-		}
-
-		/* hash_offset */
-		if (strcmp(arg_name, "hash_offset") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				hash_offset_present == 0, params->name,
-				arg_name);
-			hash_offset_present = 1;
-
-			status = parser_read_uint32(&p->hash_offset,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			continue;
-		}
-
-		/* flow_id_offset */
-		if (strcmp(arg_name, "flowid_offset") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				flow_id_offset_present == 0, params->name,
-				arg_name);
-			flow_id_offset_present = 1;
-
-			status = parser_read_uint32(&p->flow_id_offset,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			p->flow_id = 1;
-
-			continue;
-		}
-
-		/* Unknown argument */
-		PIPELINE_PARSE_ERR_INV_ENT(0, params->name, arg_name);
-	}
-
-	/* Check that mandatory arguments are present */
-	PIPELINE_PARSE_ERR_MANDATORY((n_flows_present), params->name,
-		"n_flows");
-	PIPELINE_PARSE_ERR_MANDATORY((key_offset_present), params->name,
-		"key_offset");
-	PIPELINE_PARSE_ERR_MANDATORY((key_size_present), params->name,
-		"key_size");
-
-	if (key_mask_present) {
-		uint32_t key_size = p->key_size;
-		int status;
-
-		PIPELINE_ARG_CHECK(((key_size == 8) || (key_size == 16)),
-			"Parse error in section \"%s\": entry key_mask "
-			"only allowed for key_size of 8 or 16 bytes",
-			params->name);
-
-		PIPELINE_ARG_CHECK((strlen(key_mask_str) ==
-			(key_size * 2)), "Parse error in section "
-			"\"%s\": key_mask should have exactly %u hex "
-			"digits", params->name, (key_size * 2));
-
-		PIPELINE_ARG_CHECK((hash_offset_present == 0), "Parse "
-			"error in section \"%s\": entry hash_offset only "
-			"allowed when key_mask is not present",
-			params->name);
-
-		status = parse_hex_string(key_mask_str, p->key_mask,
-			&p->key_size);
-
-		PIPELINE_PARSE_ERR_INV_VAL(((status == 0) &&
-			(key_size == p->key_size)), params->name,
-			"key_mask", key_mask_str);
-	}
-
-	p->key_mask_present = key_mask_present;
-
-	return 0;
-}
-
-static void *pipeline_fc_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 = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
-	if (p == NULL)
-		return NULL;
-	p_fc = (struct pipeline_flow_classification *) p;
-
-	strcpy(p->name, params->name);
-	p->log_level = params->log_level;
-
-	PLOG(p, HIGH, "Flow classification");
-
-	/* Parse arguments */
-	if (pipeline_fc_parse_args(p_fc, 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,
-			.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_params table_hash_params = {
-			.name = p->name,
-			.key_size = p_fc->key_size,
-			.key_offset = p_fc->key_offset,
-			.key_mask = (p_fc->key_mask_present) ?
-				p_fc->key_mask : NULL,
-			.n_keys = p_fc->n_flows,
-			.n_buckets = rte_align32pow2(p_fc->n_flows / 4),
-			.f_hash = hash_func[(p_fc->key_size / 8) - 1],
-			.seed = 0,
-		};
-
-		struct rte_pipeline_table_params table_params = {
-			.ops = NULL, /* set below */
-			.arg_create = NULL, /* set below */
-			.f_action_hit = get_fc_table_ah_hit(p_fc),
-			.f_action_miss = NULL,
-			.arg_ah = p_fc,
-			.action_data_size = sizeof(struct flow_table_entry) -
-				sizeof(struct rte_pipeline_table_entry),
-		};
-
-		int status;
-
-		switch (p_fc->key_size) {
-		case 8:
-			table_params.ops = &rte_table_hash_key8_ext_ops;
-			break;
-
-		case 16:
-			table_params.ops = &rte_table_hash_key16_ext_ops;
-			break;
-
-		default:
-			table_params.ops = &rte_table_hash_ext_ops;
-		}
-
-		table_params.arg_create = &table_hash_params;
-
-		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_fc_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_fc_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 flow_table_entry entry = {
-		.head = {
-			.action = RTE_PIPELINE_ACTION_PORT,
-			{.port_id = p->port_out_id[req->port_id]},
-		},
-		.flow_id = req->flow_id,
-	};
-
-	rsp->status = rte_pipeline_table_entry_add(p->p,
-		p->table_id[0],
-		&req->key,
-		(struct rte_pipeline_table_entry *) &entry,
-		&rsp->key_found,
-		(struct rte_pipeline_table_entry **) &rsp->entry_ptr);
-
-	return rsp;
-}
-
-static void *
-pipeline_fc_msg_req_add_bulk_handler(struct pipeline *p, void *msg)
-{
-	struct pipeline_fc_add_bulk_msg_req *req = msg;
-	struct pipeline_fc_add_bulk_msg_rsp *rsp = msg;
-	uint32_t i;
-
-	for (i = 0; i < req->n_keys; i++) {
-		struct pipeline_fc_add_bulk_flow_req *flow_req = &req->req[i];
-		struct pipeline_fc_add_bulk_flow_rsp *flow_rsp = &req->rsp[i];
-
-		struct flow_table_entry entry = {
-			.head = {
-				.action = RTE_PIPELINE_ACTION_PORT,
-				{.port_id = p->port_out_id[flow_req->port_id]},
-			},
-			.flow_id = flow_req->flow_id,
-		};
-
-		int status = rte_pipeline_table_entry_add(p->p,
-			p->table_id[0],
-			&flow_req->key,
-			(struct rte_pipeline_table_entry *) &entry,
-			&flow_rsp->key_found,
-			(struct rte_pipeline_table_entry **)
-				&flow_rsp->entry_ptr);
-
-		if (status)
-			break;
-	}
-
-	rsp->n_keys = i;
-
-	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;
-
-	rsp->status = rte_pipeline_table_entry_delete(p->p,
-		p->table_id[0],
-		&req->key,
-		&rsp->key_found,
-		NULL);
-
-	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 flow_table_entry default_entry = {
-		.head = {
-			.action = RTE_PIPELINE_ACTION_PORT,
-			{.port_id = p->port_out_id[req->port_id]},
-		},
-
-		.flow_id = 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;
-}
-
-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;
-}
-
-struct pipeline_be_ops pipeline_flow_classification_be_ops = {
-	.f_init = pipeline_fc_init,
-	.f_free = pipeline_fc_free,
-	.f_run = NULL,
-	.f_timer = pipeline_fc_timer,
-};
diff --git a/examples/ip_pipeline/pipeline/pipeline_flow_classification_be.h b/examples/ip_pipeline/pipeline/pipeline_flow_classification_be.h
deleted file mode 100644
index 18f5bb4..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_flow_classification_be.h
+++ /dev/null
@@ -1,113 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#ifndef __INCLUDE_PIPELINE_FLOW_CLASSIFICATION_BE_H__
-#define __INCLUDE_PIPELINE_FLOW_CLASSIFICATION_BE_H__
-
-#include "pipeline_common_be.h"
-
-enum pipeline_fc_msg_req_type {
-	PIPELINE_FC_MSG_REQ_FLOW_ADD = 0,
-	PIPELINE_FC_MSG_REQ_FLOW_ADD_BULK,
-	PIPELINE_FC_MSG_REQ_FLOW_DEL,
-	PIPELINE_FC_MSG_REQ_FLOW_ADD_DEFAULT,
-	PIPELINE_FC_MSG_REQ_FLOW_DEL_DEFAULT,
-	PIPELINE_FC_MSG_REQS,
-};
-
-#ifndef PIPELINE_FC_FLOW_KEY_MAX_SIZE
-#define PIPELINE_FC_FLOW_KEY_MAX_SIZE            64
-#endif
-
-/*
- * MSG ADD
- */
-struct pipeline_fc_add_msg_req {
-	enum pipeline_msg_req_type type;
-	enum pipeline_fc_msg_req_type subtype;
-
-	uint8_t key[PIPELINE_FC_FLOW_KEY_MAX_SIZE];
-
-	uint32_t port_id;
-	uint32_t flow_id;
-};
-
-struct pipeline_fc_add_msg_rsp {
-	int status;
-	int key_found;
-	void *entry_ptr;
-};
-
-/*
- * MSG ADD BULK
- */
-struct pipeline_fc_add_bulk_flow_req {
-	uint8_t key[PIPELINE_FC_FLOW_KEY_MAX_SIZE];
-	uint32_t port_id;
-	uint32_t flow_id;
-};
-
-struct pipeline_fc_add_bulk_flow_rsp {
-	int key_found;
-	void *entry_ptr;
-};
-
-struct pipeline_fc_add_bulk_msg_req {
-	enum pipeline_msg_req_type type;
-	enum pipeline_fc_msg_req_type subtype;
-
-	struct pipeline_fc_add_bulk_flow_req *req;
-	struct pipeline_fc_add_bulk_flow_rsp *rsp;
-	uint32_t n_keys;
-};
-
-struct pipeline_fc_add_bulk_msg_rsp {
-	uint32_t n_keys;
-};
-
-/*
- * MSG DEL
- */
-struct pipeline_fc_del_msg_req {
-	enum pipeline_msg_req_type type;
-	enum pipeline_fc_msg_req_type subtype;
-
-	uint8_t key[PIPELINE_FC_FLOW_KEY_MAX_SIZE];
-};
-
-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 *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_be_ops pipeline_flow_classification_be_ops;
-
-#endif
-- 
2.9.3

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

* [dpdk-dev] [PATCH v3 13/44] ip_pipeline: remove flow actions pipeline
  2018-03-16 17:58       ` [dpdk-dev] [PATCH v3 00/44] ip_pipeline: refactoring Jasvinder Singh
                           ` (11 preceding siblings ...)
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 12/44] ip_pipeline: remove flow classification pipeline Jasvinder Singh
@ 2018-03-16 17:58         ` Jasvinder Singh
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 14/44] ip_pipeline: remove firewall pipeline Jasvinder Singh
                           ` (30 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-16 17:58 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Remove flow actions pipeline.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/Makefile                      |    2 -
 examples/ip_pipeline/init.c                        |    2 -
 examples/ip_pipeline/meson.build                   |    2 -
 .../ip_pipeline/pipeline/pipeline_flow_actions.c   | 1286 --------------------
 .../ip_pipeline/pipeline/pipeline_flow_actions.h   |   60 -
 .../pipeline/pipeline_flow_actions_be.c            |  983 ---------------
 .../pipeline/pipeline_flow_actions_be.h            |  139 ---
 7 files changed, 2474 deletions(-)
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_actions.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_actions.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_actions_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_actions_be.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index e43001f..0782308 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -21,8 +21,6 @@ SRCS-y += pipeline_master_be.c
 SRCS-y += pipeline_master.c
 SRCS-y += pipeline_firewall_be.c
 SRCS-y += pipeline_firewall.c
-SRCS-y += pipeline_flow_actions_be.c
-SRCS-y += pipeline_flow_actions.c
 
 # Build using pkg-config variables if possible
 $(shell pkg-config --exists libdpdk)
diff --git a/examples/ip_pipeline/init.c b/examples/ip_pipeline/init.c
index 4780bb1..6599b0d 100644
--- a/examples/ip_pipeline/init.c
+++ b/examples/ip_pipeline/init.c
@@ -27,7 +27,6 @@
 #include "pipeline_common_fe.h"
 #include "pipeline_master.h"
 #include "pipeline_firewall.h"
-#include "pipeline_flow_actions.h"
 #include "thread_fe.h"
 
 #define APP_NAME_SIZE	32
@@ -1819,7 +1818,6 @@ int app_init(struct app_params *app)
 	app_pipeline_common_cmd_push(app);
 	app_pipeline_thread_cmd_push(app);
 	app_pipeline_type_register(app, &pipeline_master);
-	app_pipeline_type_register(app, &pipeline_flow_actions);
 	app_pipeline_type_register(app, &pipeline_firewall);
 
 	app_init_pipelines(app);
diff --git a/examples/ip_pipeline/meson.build b/examples/ip_pipeline/meson.build
index dd12870..71812f4 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -23,8 +23,6 @@ sources = files(
 	'pipeline/pipeline_common_fe.c',
 	'pipeline/pipeline_firewall_be.c',
 	'pipeline/pipeline_firewall.c',
-	'pipeline/pipeline_flow_actions_be.c',
-	'pipeline/pipeline_flow_actions.c',
 	'pipeline/pipeline_master_be.c',
 	'pipeline/pipeline_master.c',
 )
diff --git a/examples/ip_pipeline/pipeline/pipeline_flow_actions.c b/examples/ip_pipeline/pipeline/pipeline_flow_actions.c
deleted file mode 100644
index 021aee1..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_flow_actions.c
+++ /dev/null
@@ -1,1286 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <sys/queue.h>
-#include <netinet/in.h>
-#include <unistd.h>
-
-#include <rte_common.h>
-#include <rte_hexdump.h>
-#include <rte_malloc.h>
-#include <cmdline_rdline.h>
-#include <cmdline_parse.h>
-#include <cmdline_parse_num.h>
-#include <cmdline_parse_string.h>
-
-#include "app.h"
-#include "pipeline_common_fe.h"
-#include "pipeline_flow_actions.h"
-#include "hash_func.h"
-#include "parser.h"
-
-/*
- * Flow actions pipeline
- */
-#ifndef N_FLOWS_BULK
-#define N_FLOWS_BULK					4096
-#endif
-
-struct app_pipeline_fa_flow {
-	struct pipeline_fa_flow_params params;
-	void *entry_ptr;
-};
-
-struct app_pipeline_fa_dscp {
-	uint32_t traffic_class;
-	enum rte_meter_color color;
-};
-
-struct app_pipeline_fa {
-	/* Parameters */
-	uint32_t n_ports_in;
-	uint32_t n_ports_out;
-	struct pipeline_fa_params params;
-
-	/* Flows */
-	struct app_pipeline_fa_dscp dscp[PIPELINE_FA_N_DSCP];
-	struct app_pipeline_fa_flow *flows;
-} __rte_cache_aligned;
-
-static void*
-app_pipeline_fa_init(struct pipeline_params *params,
-	__rte_unused void *arg)
-{
-	struct app_pipeline_fa *p;
-	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 app_pipeline_fa));
-	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;
-	if (pipeline_fa_parse_args(&p->params, params)) {
-		rte_free(p);
-		return NULL;
-	}
-
-	/* Memory allocation */
-	size = RTE_CACHE_LINE_ROUNDUP(
-		p->params.n_flows * sizeof(struct app_pipeline_fa_flow));
-	p->flows = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
-	if (p->flows == NULL) {
-		rte_free(p);
-		return NULL;
-	}
-
-	/* Initialization of flow table */
-	for (i = 0; i < p->params.n_flows; i++)
-		pipeline_fa_flow_params_set_default(&p->flows[i].params);
-
-	/* Initialization of DSCP table */
-	for (i = 0; i < RTE_DIM(p->dscp); i++) {
-		p->dscp[i].traffic_class = 0;
-		p->dscp[i].color = e_RTE_METER_GREEN;
-	}
-
-	return (void *) p;
-}
-
-static int
-app_pipeline_fa_free(void *pipeline)
-{
-	struct app_pipeline_fa *p = pipeline;
-
-	/* Check input arguments */
-	if (p == NULL)
-		return -1;
-
-	/* Free resources */
-	rte_free(p->flows);
-	rte_free(p);
-
-	return 0;
-}
-
-static int
-flow_params_check(struct app_pipeline_fa *p,
-	__rte_unused uint32_t meter_update_mask,
-	uint32_t policer_update_mask,
-	uint32_t port_update,
-	struct pipeline_fa_flow_params *params)
-{
-	uint32_t mask, i;
-
-	/* Meter */
-
-	/* Policer */
-	for (i = 0, mask = 1; i < PIPELINE_FA_N_TC_MAX; i++, mask <<= 1) {
-		struct pipeline_fa_policer_params *p = &params->p[i];
-		uint32_t j;
-
-		if ((mask & policer_update_mask) == 0)
-			continue;
-
-		for (j = 0; j < e_RTE_METER_COLORS; j++) {
-			struct pipeline_fa_policer_action *action =
-				&p->action[j];
-
-			if ((action->drop == 0) &&
-				(action->color >= e_RTE_METER_COLORS))
-				return -1;
-		}
-	}
-
-	/* Port */
-	if (port_update && (params->port_id >= p->n_ports_out))
-		return -1;
-
-	return 0;
-}
-
-int
-app_pipeline_fa_flow_config(struct app_params *app,
-	uint32_t pipeline_id,
-	uint32_t flow_id,
-	uint32_t meter_update_mask,
-	uint32_t policer_update_mask,
-	uint32_t port_update,
-	struct pipeline_fa_flow_params *params)
-{
-	struct app_pipeline_fa *p;
-	struct app_pipeline_fa_flow *flow;
-
-	struct pipeline_fa_flow_config_msg_req *req;
-	struct pipeline_fa_flow_config_msg_rsp *rsp;
-
-	uint32_t i, mask;
-
-	/* Check input arguments */
-	if ((app == NULL) ||
-		((meter_update_mask == 0) &&
-		(policer_update_mask == 0) &&
-		(port_update == 0)) ||
-		(meter_update_mask >= (1 << PIPELINE_FA_N_TC_MAX)) ||
-		(policer_update_mask >= (1 << PIPELINE_FA_N_TC_MAX)) ||
-		(params == NULL))
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id,
-		&pipeline_flow_actions);
-	if (p == NULL)
-		return -1;
-
-	if (flow_params_check(p,
-		meter_update_mask,
-		policer_update_mask,
-		port_update,
-		params) != 0)
-		return -1;
-
-	flow_id %= p->params.n_flows;
-	flow = &p->flows[flow_id];
-
-	/* Allocate and write request */
-	req = app_msg_alloc(app);
-	if (req == NULL)
-		return -1;
-
-	req->type = PIPELINE_MSG_REQ_CUSTOM;
-	req->subtype = PIPELINE_FA_MSG_REQ_FLOW_CONFIG;
-	req->entry_ptr = flow->entry_ptr;
-	req->flow_id = flow_id;
-	req->meter_update_mask = meter_update_mask;
-	req->policer_update_mask = policer_update_mask;
-	req->port_update = port_update;
-	memcpy(&req->params, params, sizeof(*params));
-
-	/* Send request and wait for response */
-	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	/* Read response */
-	if (rsp->status ||
-		(rsp->entry_ptr == NULL)) {
-		app_msg_free(app, rsp);
-		return -1;
-	}
-
-	/* Commit flow */
-	for (i = 0, mask = 1; i < PIPELINE_FA_N_TC_MAX; i++, mask <<= 1) {
-		if ((mask & meter_update_mask) == 0)
-			continue;
-
-		memcpy(&flow->params.m[i], &params->m[i], sizeof(params->m[i]));
-	}
-
-	for (i = 0, mask = 1; i < PIPELINE_FA_N_TC_MAX; i++, mask <<= 1) {
-		if ((mask & policer_update_mask) == 0)
-			continue;
-
-		memcpy(&flow->params.p[i], &params->p[i], sizeof(params->p[i]));
-	}
-
-	if (port_update)
-		flow->params.port_id = params->port_id;
-
-	flow->entry_ptr = rsp->entry_ptr;
-
-	/* Free response */
-	app_msg_free(app, rsp);
-
-	return 0;
-}
-
-int
-app_pipeline_fa_flow_config_bulk(struct app_params *app,
-	uint32_t pipeline_id,
-	uint32_t *flow_id,
-	uint32_t n_flows,
-	uint32_t meter_update_mask,
-	uint32_t policer_update_mask,
-	uint32_t port_update,
-	struct pipeline_fa_flow_params *params)
-{
-	struct app_pipeline_fa *p;
-	struct pipeline_fa_flow_config_bulk_msg_req *req;
-	struct pipeline_fa_flow_config_bulk_msg_rsp *rsp;
-	void **req_entry_ptr;
-	uint32_t *req_flow_id;
-	uint32_t i;
-	int status;
-
-	/* Check input arguments */
-	if ((app == NULL) ||
-		(flow_id == NULL) ||
-		(n_flows == 0) ||
-		((meter_update_mask == 0) &&
-		(policer_update_mask == 0) &&
-		(port_update == 0)) ||
-		(meter_update_mask >= (1 << PIPELINE_FA_N_TC_MAX)) ||
-		(policer_update_mask >= (1 << PIPELINE_FA_N_TC_MAX)) ||
-		(params == NULL))
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id,
-		&pipeline_flow_actions);
-	if (p == NULL)
-		return -1;
-
-	for (i = 0; i < n_flows; i++) {
-		struct pipeline_fa_flow_params *flow_params = &params[i];
-
-		if (flow_params_check(p,
-			meter_update_mask,
-			policer_update_mask,
-			port_update,
-			flow_params) != 0)
-			return -1;
-	}
-
-	/* Allocate and write request */
-	req_entry_ptr = (void **) rte_malloc(NULL,
-		n_flows * sizeof(void *),
-		RTE_CACHE_LINE_SIZE);
-	if (req_entry_ptr == NULL)
-		return -1;
-
-	req_flow_id = (uint32_t *) rte_malloc(NULL,
-		n_flows * sizeof(uint32_t),
-		RTE_CACHE_LINE_SIZE);
-	if (req_flow_id == NULL) {
-		rte_free(req_entry_ptr);
-		return -1;
-	}
-
-	for (i = 0; i < n_flows; i++) {
-		uint32_t fid = flow_id[i] % p->params.n_flows;
-		struct app_pipeline_fa_flow *flow = &p->flows[fid];
-
-		req_flow_id[i] = fid;
-		req_entry_ptr[i] = flow->entry_ptr;
-	}
-
-	req = app_msg_alloc(app);
-	if (req == NULL) {
-		rte_free(req_flow_id);
-		rte_free(req_entry_ptr);
-		return -1;
-	}
-
-	req->type = PIPELINE_MSG_REQ_CUSTOM;
-	req->subtype = PIPELINE_FA_MSG_REQ_FLOW_CONFIG_BULK;
-	req->entry_ptr = req_entry_ptr;
-	req->flow_id = req_flow_id;
-	req->n_flows = n_flows;
-	req->meter_update_mask = meter_update_mask;
-	req->policer_update_mask = policer_update_mask;
-	req->port_update = port_update;
-	req->params = params;
-
-	/* Send request and wait for response */
-	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL) {
-		rte_free(req_flow_id);
-		rte_free(req_entry_ptr);
-		return -1;
-	}
-
-	/* Read response */
-	status = (rsp->n_flows == n_flows) ? 0 : -1;
-
-	/* Commit flows */
-	for (i = 0; i < rsp->n_flows; i++) {
-		uint32_t fid = flow_id[i] % p->params.n_flows;
-		struct app_pipeline_fa_flow *flow = &p->flows[fid];
-		struct pipeline_fa_flow_params *flow_params = &params[i];
-		void *entry_ptr = req_entry_ptr[i];
-		uint32_t j, mask;
-
-		for (j = 0, mask = 1; j < PIPELINE_FA_N_TC_MAX;
-			j++, mask <<= 1) {
-			if ((mask & meter_update_mask) == 0)
-				continue;
-
-			memcpy(&flow->params.m[j],
-				&flow_params->m[j],
-				sizeof(flow_params->m[j]));
-		}
-
-		for (j = 0, mask = 1; j < PIPELINE_FA_N_TC_MAX;
-			j++, mask <<= 1) {
-			if ((mask & policer_update_mask) == 0)
-				continue;
-
-			memcpy(&flow->params.p[j],
-				&flow_params->p[j],
-				sizeof(flow_params->p[j]));
-		}
-
-		if (port_update)
-			flow->params.port_id = flow_params->port_id;
-
-		flow->entry_ptr = entry_ptr;
-	}
-
-	/* Free response */
-	app_msg_free(app, rsp);
-	rte_free(req_flow_id);
-	rte_free(req_entry_ptr);
-
-	return status;
-}
-
-int
-app_pipeline_fa_dscp_config(struct app_params *app,
-	uint32_t pipeline_id,
-	uint32_t dscp,
-	uint32_t traffic_class,
-	enum rte_meter_color color)
-{
-	struct app_pipeline_fa *p;
-
-	struct pipeline_fa_dscp_config_msg_req *req;
-	struct pipeline_fa_dscp_config_msg_rsp *rsp;
-
-	/* Check input arguments */
-	if ((app == NULL) ||
-		(dscp >= PIPELINE_FA_N_DSCP) ||
-		(traffic_class >= PIPELINE_FA_N_TC_MAX) ||
-		(color >= e_RTE_METER_COLORS))
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id,
-		&pipeline_flow_actions);
-	if (p == NULL)
-		return -1;
-
-	if (p->params.dscp_enabled == 0)
-		return -1;
-
-	/* Allocate and write request */
-	req = app_msg_alloc(app);
-	if (req == NULL)
-		return -1;
-
-	req->type = PIPELINE_MSG_REQ_CUSTOM;
-	req->subtype = PIPELINE_FA_MSG_REQ_DSCP_CONFIG;
-	req->dscp = dscp;
-	req->traffic_class = traffic_class;
-	req->color = color;
-
-	/* Send request and wait for response */
-	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	/* Read response */
-	if (rsp->status) {
-		app_msg_free(app, rsp);
-		return -1;
-	}
-
-	/* Commit DSCP */
-	p->dscp[dscp].traffic_class = traffic_class;
-	p->dscp[dscp].color = color;
-
-	/* Free response */
-	app_msg_free(app, rsp);
-
-	return 0;
-}
-
-int
-app_pipeline_fa_flow_policer_stats_read(struct app_params *app,
-	uint32_t pipeline_id,
-	uint32_t flow_id,
-	uint32_t policer_id,
-	int clear,
-	struct pipeline_fa_policer_stats *stats)
-{
-	struct app_pipeline_fa *p;
-	struct app_pipeline_fa_flow *flow;
-
-	struct pipeline_fa_policer_stats_msg_req *req;
-	struct pipeline_fa_policer_stats_msg_rsp *rsp;
-
-	/* Check input arguments */
-	if ((app == NULL) || (stats == NULL))
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id,
-		&pipeline_flow_actions);
-	if (p == NULL)
-		return -1;
-
-	flow_id %= p->params.n_flows;
-	flow = &p->flows[flow_id];
-
-	if ((policer_id >= p->params.n_meters_per_flow) ||
-		(flow->entry_ptr == NULL))
-		return -1;
-
-	/* Allocate and write request */
-	req = app_msg_alloc(app);
-	if (req == NULL)
-		return -1;
-
-	req->type = PIPELINE_MSG_REQ_CUSTOM;
-	req->subtype = PIPELINE_FA_MSG_REQ_POLICER_STATS_READ;
-	req->entry_ptr = flow->entry_ptr;
-	req->policer_id = policer_id;
-	req->clear = clear;
-
-	/* Send request and wait for response */
-	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	/* Read response */
-	if (rsp->status) {
-		app_msg_free(app, rsp);
-		return -1;
-	}
-
-	memcpy(stats, &rsp->stats, sizeof(*stats));
-
-	/* Free response */
-	app_msg_free(app, rsp);
-
-	return 0;
-}
-
-static const char *
-color_to_string(enum rte_meter_color color)
-{
-	switch (color) {
-	case e_RTE_METER_GREEN: return "G";
-	case e_RTE_METER_YELLOW: return "Y";
-	case e_RTE_METER_RED: return "R";
-	default: return "?";
-	}
-}
-
-static int
-string_to_color(char *s, enum rte_meter_color *c)
-{
-	if (strcmp(s, "G") == 0) {
-		*c = e_RTE_METER_GREEN;
-		return 0;
-	}
-
-	if (strcmp(s, "Y") == 0) {
-		*c = e_RTE_METER_YELLOW;
-		return 0;
-	}
-
-	if (strcmp(s, "R") == 0) {
-		*c = e_RTE_METER_RED;
-		return 0;
-	}
-
-	return -1;
-}
-
-static const char *
-policer_action_to_string(struct pipeline_fa_policer_action *a)
-{
-	if (a->drop)
-		return "D";
-
-	return color_to_string(a->color);
-}
-
-static int
-string_to_policer_action(char *s, struct pipeline_fa_policer_action *a)
-{
-	if (strcmp(s, "G") == 0) {
-		a->drop = 0;
-		a->color = e_RTE_METER_GREEN;
-		return 0;
-	}
-
-	if (strcmp(s, "Y") == 0) {
-		a->drop = 0;
-		a->color = e_RTE_METER_YELLOW;
-		return 0;
-	}
-
-	if (strcmp(s, "R") == 0) {
-		a->drop = 0;
-		a->color = e_RTE_METER_RED;
-		return 0;
-	}
-
-	if (strcmp(s, "D") == 0) {
-		a->drop = 1;
-		a->color = e_RTE_METER_GREEN;
-		return 0;
-	}
-
-	return -1;
-}
-
-static void
-print_flow(struct app_pipeline_fa *p,
-	uint32_t flow_id,
-	struct app_pipeline_fa_flow *flow)
-{
-	uint32_t i;
-
-	printf("Flow ID = %" PRIu32 "\n", flow_id);
-
-	for (i = 0; i < p->params.n_meters_per_flow; i++) {
-		struct rte_meter_trtcm_params *meter = &flow->params.m[i];
-		struct pipeline_fa_policer_params *policer = &flow->params.p[i];
-
-	printf("\ttrTCM [CIR = %" PRIu64
-		", CBS = %" PRIu64 ", PIR = %" PRIu64
-		", PBS = %" PRIu64	"] Policer [G : %s, Y : %s, R : %s]\n",
-		meter->cir,
-		meter->cbs,
-		meter->pir,
-		meter->pbs,
-		policer_action_to_string(&policer->action[e_RTE_METER_GREEN]),
-		policer_action_to_string(&policer->action[e_RTE_METER_YELLOW]),
-		policer_action_to_string(&policer->action[e_RTE_METER_RED]));
-	}
-
-	printf("\tPort %u (entry_ptr = %p)\n",
-		flow->params.port_id,
-		flow->entry_ptr);
-}
-
-
-static int
-app_pipeline_fa_flow_ls(struct app_params *app,
-		uint32_t pipeline_id)
-{
-	struct app_pipeline_fa *p;
-	uint32_t i;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id,
-		&pipeline_flow_actions);
-	if (p == NULL)
-		return -1;
-
-	for (i = 0; i < p->params.n_flows; i++) {
-		struct app_pipeline_fa_flow *flow = &p->flows[i];
-
-		print_flow(p, i, flow);
-	}
-
-	return 0;
-}
-
-static int
-app_pipeline_fa_dscp_ls(struct app_params *app,
-		uint32_t pipeline_id)
-{
-	struct app_pipeline_fa *p;
-	uint32_t i;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id,
-		&pipeline_flow_actions);
-	if (p == NULL)
-		return -1;
-
-	if (p->params.dscp_enabled == 0)
-		return -1;
-
-	for (i = 0; i < RTE_DIM(p->dscp); i++) {
-		struct app_pipeline_fa_dscp *dscp =	&p->dscp[i];
-
-		printf("DSCP = %2" PRIu32 ": Traffic class = %" PRIu32
-			", Color = %s\n",
-			i,
-			dscp->traffic_class,
-			color_to_string(dscp->color));
-	}
-
-	return 0;
-}
-
-int
-app_pipeline_fa_load_file(char *filename,
-	uint32_t *flow_ids,
-	struct pipeline_fa_flow_params *p,
-	uint32_t *n_flows,
-	uint32_t *line)
-{
-	FILE *f = NULL;
-	char file_buf[1024];
-	uint32_t i, l;
-
-	/* Check input arguments */
-	if ((filename == NULL) ||
-		(flow_ids == NULL) ||
-		(p == NULL) ||
-		(n_flows == NULL) ||
-		(*n_flows == 0) ||
-		(line == NULL)) {
-		if (line)
-			*line = 0;
-		return -1;
-		}
-
-	/* Open input file */
-	f = fopen(filename, "r");
-	if (f == NULL) {
-		*line = 0;
-		return -1;
-	}
-
-	/* Read file */
-	for (i = 0, l = 1; i < *n_flows; l++) {
-		char *tokens[64];
-		uint32_t n_tokens = RTE_DIM(tokens);
-
-		int status;
-
-		if (fgets(file_buf, sizeof(file_buf), f) == NULL)
-			break;
-
-		status = parse_tokenize_string(file_buf, tokens, &n_tokens);
-		if (status)
-			goto error1;
-
-		if ((n_tokens == 0) || (tokens[0][0] == '#'))
-			continue;
-
-
-		if ((n_tokens != 64) ||
-			/* flow */
-			strcmp(tokens[0], "flow") ||
-			parser_read_uint32(&flow_ids[i], tokens[1]) ||
-
-			/* meter & policer 0 */
-			strcmp(tokens[2], "meter") ||
-			strcmp(tokens[3], "0") ||
-			strcmp(tokens[4], "trtcm") ||
-			parser_read_uint64(&p[i].m[0].cir, tokens[5]) ||
-			parser_read_uint64(&p[i].m[0].pir, tokens[6]) ||
-			parser_read_uint64(&p[i].m[0].cbs, tokens[7]) ||
-			parser_read_uint64(&p[i].m[0].pbs, tokens[8]) ||
-			strcmp(tokens[9], "policer") ||
-			strcmp(tokens[10], "0") ||
-			strcmp(tokens[11], "g") ||
-			string_to_policer_action(tokens[12],
-				&p[i].p[0].action[e_RTE_METER_GREEN]) ||
-			strcmp(tokens[13], "y") ||
-			string_to_policer_action(tokens[14],
-				&p[i].p[0].action[e_RTE_METER_YELLOW]) ||
-			strcmp(tokens[15], "r") ||
-			string_to_policer_action(tokens[16],
-				&p[i].p[0].action[e_RTE_METER_RED]) ||
-
-			/* meter & policer 1 */
-			strcmp(tokens[17], "meter") ||
-			strcmp(tokens[18], "1") ||
-			strcmp(tokens[19], "trtcm") ||
-			parser_read_uint64(&p[i].m[1].cir, tokens[20]) ||
-			parser_read_uint64(&p[i].m[1].pir, tokens[21]) ||
-			parser_read_uint64(&p[i].m[1].cbs, tokens[22]) ||
-			parser_read_uint64(&p[i].m[1].pbs, tokens[23]) ||
-			strcmp(tokens[24], "policer") ||
-			strcmp(tokens[25], "1") ||
-			strcmp(tokens[26], "g") ||
-			string_to_policer_action(tokens[27],
-				&p[i].p[1].action[e_RTE_METER_GREEN]) ||
-			strcmp(tokens[28], "y") ||
-			string_to_policer_action(tokens[29],
-				&p[i].p[1].action[e_RTE_METER_YELLOW]) ||
-			strcmp(tokens[30], "r") ||
-			string_to_policer_action(tokens[31],
-				&p[i].p[1].action[e_RTE_METER_RED]) ||
-
-			/* meter & policer 2 */
-			strcmp(tokens[32], "meter") ||
-			strcmp(tokens[33], "2") ||
-			strcmp(tokens[34], "trtcm") ||
-			parser_read_uint64(&p[i].m[2].cir, tokens[35]) ||
-			parser_read_uint64(&p[i].m[2].pir, tokens[36]) ||
-			parser_read_uint64(&p[i].m[2].cbs, tokens[37]) ||
-			parser_read_uint64(&p[i].m[2].pbs, tokens[38]) ||
-			strcmp(tokens[39], "policer") ||
-			strcmp(tokens[40], "2") ||
-			strcmp(tokens[41], "g") ||
-			string_to_policer_action(tokens[42],
-				&p[i].p[2].action[e_RTE_METER_GREEN]) ||
-			strcmp(tokens[43], "y") ||
-			string_to_policer_action(tokens[44],
-				&p[i].p[2].action[e_RTE_METER_YELLOW]) ||
-			strcmp(tokens[45], "r") ||
-			string_to_policer_action(tokens[46],
-				&p[i].p[2].action[e_RTE_METER_RED]) ||
-
-			/* meter & policer 3 */
-			strcmp(tokens[47], "meter") ||
-			strcmp(tokens[48], "3") ||
-			strcmp(tokens[49], "trtcm") ||
-			parser_read_uint64(&p[i].m[3].cir, tokens[50]) ||
-			parser_read_uint64(&p[i].m[3].pir, tokens[51]) ||
-			parser_read_uint64(&p[i].m[3].cbs, tokens[52]) ||
-			parser_read_uint64(&p[i].m[3].pbs, tokens[53]) ||
-			strcmp(tokens[54], "policer") ||
-			strcmp(tokens[55], "3") ||
-			strcmp(tokens[56], "g") ||
-			string_to_policer_action(tokens[57],
-				&p[i].p[3].action[e_RTE_METER_GREEN]) ||
-			strcmp(tokens[58], "y") ||
-			string_to_policer_action(tokens[59],
-				&p[i].p[3].action[e_RTE_METER_YELLOW]) ||
-			strcmp(tokens[60], "r") ||
-			string_to_policer_action(tokens[61],
-				&p[i].p[3].action[e_RTE_METER_RED]) ||
-
-			/* port */
-			strcmp(tokens[62], "port") ||
-			parser_read_uint32(&p[i].port_id, tokens[63]))
-			goto error1;
-
-		i++;
-	}
-
-	/* Close file */
-	*n_flows = i;
-	fclose(f);
-	return 0;
-
-error1:
-	*line = l;
-	fclose(f);
-	return -1;
-}
-
-/*
- * action
- *
- * flow meter, policer and output port configuration:
- *    p <pipelineid> action flow <flowid> meter <meterid> trtcm <cir> <pir> <cbs> <pbs>
- *
- *    p <pipelineid> action flow <flowid> policer <policerid> g <gaction> y <yaction> r <raction>
- *  <action> is one of the following:
- *      G = recolor to green
- *      Y = recolor as yellow
- *      R = recolor as red
- *      D = drop
- *
- *    p <pipelineid> action flow <flowid> port <port ID>
- *
- *    p <pipelineid> action flow bulk <file>
- *
- * flow policer stats read:
- *    p <pipelineid> action flow <flowid> stats
- *
- * flow ls:
- *    p <pipelineid> action flow ls
- *
- * dscp table configuration:
- *    p <pipelineid> action dscp <dscpid> class <class ID> color <color>
- *
- * dscp table ls:
- *    p <pipelineid> action dscp ls
-**/
-
-struct cmd_action_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t action_string;
-	cmdline_multi_string_t multi_string;
-};
-
-static void
-cmd_action_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_action_result *params = parsed_result;
-	struct app_params *app = data;
-
-	char *tokens[16];
-	uint32_t n_tokens = RTE_DIM(tokens);
-	int status;
-
-	status = parse_tokenize_string(params->multi_string, tokens, &n_tokens);
-	if (status != 0) {
-		printf(CMD_MSG_TOO_MANY_ARGS, "action");
-		return;
-	}
-
-	/* action flow meter */
-	if ((n_tokens >= 3) &&
-		(strcmp(tokens[0], "flow") == 0) &&
-		strcmp(tokens[1], "bulk") &&
-		strcmp(tokens[1], "ls") &&
-		(strcmp(tokens[2], "meter") == 0)) {
-		struct pipeline_fa_flow_params flow_params;
-		uint32_t flow_id, meter_id;
-
-		if (n_tokens != 9) {
-			printf(CMD_MSG_MISMATCH_ARGS, "action flow meter");
-			return;
-		}
-
-		memset(&flow_params, 0, sizeof(flow_params));
-
-		if (parser_read_uint32(&flow_id, tokens[1])) {
-			printf(CMD_MSG_INVALID_ARG, "flowid");
-			return;
-		}
-
-		if (parser_read_uint32(&meter_id, tokens[3]) ||
-			(meter_id >= PIPELINE_FA_N_TC_MAX)) {
-			printf(CMD_MSG_INVALID_ARG, "meterid");
-			return;
-		}
-
-		if (strcmp(tokens[4], "trtcm")) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "trtcm");
-			return;
-		}
-
-		if (parser_read_uint64(&flow_params.m[meter_id].cir, tokens[5])) {
-			printf(CMD_MSG_INVALID_ARG, "cir");
-			return;
-		}
-
-		if (parser_read_uint64(&flow_params.m[meter_id].pir, tokens[6])) {
-			printf(CMD_MSG_INVALID_ARG, "pir");
-			return;
-		}
-
-		if (parser_read_uint64(&flow_params.m[meter_id].cbs, tokens[7])) {
-			printf(CMD_MSG_INVALID_ARG, "cbs");
-			return;
-		}
-
-		if (parser_read_uint64(&flow_params.m[meter_id].pbs, tokens[8])) {
-			printf(CMD_MSG_INVALID_ARG, "pbs");
-			return;
-		}
-
-		status = app_pipeline_fa_flow_config(app,
-			params->pipeline_id,
-			flow_id,
-			1 << meter_id,
-			0,
-			0,
-			&flow_params);
-		if (status)
-			printf(CMD_MSG_FAIL, "action flow meter");
-
-		return;
-	} /* action flow meter */
-
-	/* action flow policer */
-	if ((n_tokens >= 3) &&
-		(strcmp(tokens[0], "flow") == 0) &&
-		strcmp(tokens[1], "bulk") &&
-		strcmp(tokens[1], "ls") &&
-		(strcmp(tokens[2], "policer") == 0)) {
-		struct pipeline_fa_flow_params flow_params;
-		uint32_t flow_id, policer_id;
-
-		if (n_tokens != 10) {
-			printf(CMD_MSG_MISMATCH_ARGS, "action flow policer");
-			return;
-		}
-
-		memset(&flow_params, 0, sizeof(flow_params));
-
-		if (parser_read_uint32(&flow_id, tokens[1])) {
-			printf(CMD_MSG_INVALID_ARG, "flowid");
-			return;
-		}
-
-		if (parser_read_uint32(&policer_id, tokens[3]) ||
-			(policer_id >= PIPELINE_FA_N_TC_MAX)) {
-			printf(CMD_MSG_INVALID_ARG, "policerid");
-			return;
-		}
-
-		if (strcmp(tokens[4], "g")) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "g");
-			return;
-		}
-
-		if (string_to_policer_action(tokens[5],
-			&flow_params.p[policer_id].action[e_RTE_METER_GREEN])) {
-			printf(CMD_MSG_INVALID_ARG, "gaction");
-			return;
-		}
-
-		if (strcmp(tokens[6], "y")) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "y");
-			return;
-		}
-
-		if (string_to_policer_action(tokens[7],
-			&flow_params.p[policer_id].action[e_RTE_METER_YELLOW])) {
-			printf(CMD_MSG_INVALID_ARG, "yaction");
-			return;
-		}
-
-		if (strcmp(tokens[8], "r")) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "r");
-			return;
-		}
-
-		if (string_to_policer_action(tokens[9],
-			&flow_params.p[policer_id].action[e_RTE_METER_RED])) {
-			printf(CMD_MSG_INVALID_ARG, "raction");
-			return;
-		}
-
-		status = app_pipeline_fa_flow_config(app,
-			params->pipeline_id,
-			flow_id,
-			0,
-			1 << policer_id,
-			0,
-			&flow_params);
-		if (status != 0)
-			printf(CMD_MSG_FAIL, "action flow policer");
-
-		return;
-	} /* action flow policer */
-
-	/* action flow port */
-	if ((n_tokens >= 3) &&
-		(strcmp(tokens[0], "flow") == 0) &&
-		strcmp(tokens[1], "bulk") &&
-		strcmp(tokens[1], "ls") &&
-		(strcmp(tokens[2], "port") == 0)) {
-		struct pipeline_fa_flow_params flow_params;
-		uint32_t flow_id, port_id;
-
-		if (n_tokens != 4) {
-			printf(CMD_MSG_MISMATCH_ARGS, "action flow port");
-			return;
-		}
-
-		memset(&flow_params, 0, sizeof(flow_params));
-
-		if (parser_read_uint32(&flow_id, tokens[1])) {
-			printf(CMD_MSG_INVALID_ARG, "flowid");
-			return;
-		}
-
-		if (parser_read_uint32(&port_id, tokens[3])) {
-			printf(CMD_MSG_INVALID_ARG, "portid");
-			return;
-		}
-
-		flow_params.port_id = port_id;
-
-		status = app_pipeline_fa_flow_config(app,
-			params->pipeline_id,
-			flow_id,
-			0,
-			0,
-			1,
-			&flow_params);
-		if (status)
-			printf(CMD_MSG_FAIL, "action flow port");
-
-		return;
-	} /* action flow port */
-
-	/* action flow stats */
-	if ((n_tokens >= 3) &&
-		(strcmp(tokens[0], "flow") == 0) &&
-		strcmp(tokens[1], "bulk") &&
-		strcmp(tokens[1], "ls") &&
-		(strcmp(tokens[2], "stats") == 0)) {
-		struct pipeline_fa_policer_stats stats;
-		uint32_t flow_id, policer_id;
-
-		if (n_tokens != 3) {
-			printf(CMD_MSG_MISMATCH_ARGS, "action flow stats");
-			return;
-		}
-
-		if (parser_read_uint32(&flow_id, tokens[1])) {
-			printf(CMD_MSG_INVALID_ARG, "flowid");
-			return;
-		}
-
-		for (policer_id = 0;
-			policer_id < PIPELINE_FA_N_TC_MAX;
-			policer_id++) {
-			status = app_pipeline_fa_flow_policer_stats_read(app,
-				params->pipeline_id,
-				flow_id,
-				policer_id,
-				1,
-				&stats);
-			if (status != 0) {
-				printf(CMD_MSG_FAIL, "action flow stats");
-				return;
-			}
-
-			/* Display stats */
-			printf("\tPolicer: %" PRIu32
-				"\tPkts G: %" PRIu64
-				"\tPkts Y: %" PRIu64
-				"\tPkts R: %" PRIu64
-				"\tPkts D: %" PRIu64 "\n",
-				policer_id,
-				stats.n_pkts[e_RTE_METER_GREEN],
-				stats.n_pkts[e_RTE_METER_YELLOW],
-				stats.n_pkts[e_RTE_METER_RED],
-				stats.n_pkts_drop);
-		}
-
-		return;
-	} /* action flow stats */
-
-	/* action flow bulk */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "flow") == 0) &&
-		(strcmp(tokens[1], "bulk") == 0)) {
-		struct pipeline_fa_flow_params *flow_params;
-		uint32_t *flow_ids, n_flows, line;
-		char *filename;
-
-		if (n_tokens != 3) {
-			printf(CMD_MSG_MISMATCH_ARGS, "action flow bulk");
-			return;
-		}
-
-		filename = tokens[2];
-
-		n_flows = APP_PIPELINE_FA_MAX_RECORDS_IN_FILE;
-		flow_ids = malloc(n_flows * sizeof(uint32_t));
-		if (flow_ids == NULL) {
-			printf(CMD_MSG_OUT_OF_MEMORY);
-			return;
-		}
-
-		flow_params = malloc(n_flows * sizeof(struct pipeline_fa_flow_params));
-		if (flow_params == NULL) {
-			printf(CMD_MSG_OUT_OF_MEMORY);
-			free(flow_ids);
-			return;
-		}
-
-		status = app_pipeline_fa_load_file(filename,
-			flow_ids,
-			flow_params,
-			&n_flows,
-			&line);
-		if (status) {
-			printf(CMD_MSG_FILE_ERR, filename, line);
-			free(flow_params);
-			free(flow_ids);
-			return;
-		}
-
-		status = app_pipeline_fa_flow_config_bulk(app,
-			params->pipeline_id,
-			flow_ids,
-			n_flows,
-			0xF,
-			0xF,
-			1,
-			flow_params);
-		if (status)
-			printf(CMD_MSG_FAIL, "action flow bulk");
-
-		free(flow_params);
-		free(flow_ids);
-		return;
-	} /* action flow bulk */
-
-	/* action flow ls */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "flow") == 0) &&
-		(strcmp(tokens[1], "ls") == 0)) {
-		if (n_tokens != 2) {
-			printf(CMD_MSG_MISMATCH_ARGS, "action flow ls");
-			return;
-		}
-
-		status = app_pipeline_fa_flow_ls(app,
-			params->pipeline_id);
-		if (status)
-			printf(CMD_MSG_FAIL, "action flow ls");
-
-		return;
-	} /* action flow ls */
-
-	/* action dscp */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "dscp") == 0) &&
-		strcmp(tokens[1], "ls")) {
-		uint32_t dscp_id, tc_id;
-		enum rte_meter_color color;
-
-		if (n_tokens != 6) {
-			printf(CMD_MSG_MISMATCH_ARGS, "action dscp");
-			return;
-		}
-
-		if (parser_read_uint32(&dscp_id, tokens[1])) {
-			printf(CMD_MSG_INVALID_ARG, "dscpid");
-			return;
-		}
-
-		if (strcmp(tokens[2], "class")) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "class");
-			return;
-		}
-
-		if (parser_read_uint32(&tc_id, tokens[3])) {
-			printf(CMD_MSG_INVALID_ARG, "classid");
-			return;
-		}
-
-		if (strcmp(tokens[4], "color")) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "color");
-			return;
-		}
-
-		if (string_to_color(tokens[5], &color)) {
-			printf(CMD_MSG_INVALID_ARG, "colorid");
-			return;
-		}
-
-		status = app_pipeline_fa_dscp_config(app,
-			params->pipeline_id,
-			dscp_id,
-			tc_id,
-			color);
-		if (status != 0)
-			printf(CMD_MSG_FAIL, "action dscp");
-
-		return;
-	} /* action dscp */
-
-	/* action dscp ls */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "dscp") == 0) &&
-		(strcmp(tokens[1], "ls") == 0)) {
-		if (n_tokens != 2) {
-			printf(CMD_MSG_MISMATCH_ARGS, "action dscp ls");
-			return;
-		}
-
-		status = app_pipeline_fa_dscp_ls(app,
-			params->pipeline_id);
-		if (status)
-			printf(CMD_MSG_FAIL, "action dscp ls");
-
-		return;
-	} /* action dscp ls */
-
-	printf(CMD_MSG_FAIL, "action");
-}
-
-static cmdline_parse_token_string_t cmd_action_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_action_result, p_string, "p");
-
-static cmdline_parse_token_num_t cmd_action_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_action_result, pipeline_id, UINT32);
-
-static cmdline_parse_token_string_t cmd_action_action_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_action_result, action_string, "action");
-
-static cmdline_parse_token_string_t cmd_action_multi_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_action_result, multi_string,
-	TOKEN_STRING_MULTI);
-
-cmdline_parse_inst_t cmd_action = {
-	.f = cmd_action_parsed,
-	.data = NULL,
-	.help_str = "flow actions (meter, policer, policer stats, dscp table)",
-	.tokens = {
-		(void *) &cmd_action_p_string,
-		(void *) &cmd_action_pipeline_id,
-		(void *) &cmd_action_action_string,
-		(void *) &cmd_action_multi_string,
-		NULL,
-	},
-};
-
-static cmdline_parse_ctx_t pipeline_cmds[] = {
-	(cmdline_parse_inst_t *) &cmd_action,
-	NULL,
-};
-
-static struct pipeline_fe_ops pipeline_flow_actions_fe_ops = {
-	.f_init = app_pipeline_fa_init,
-	.f_post_init = NULL,
-	.f_free = app_pipeline_fa_free,
-	.f_track = app_pipeline_track_default,
-	.cmds = pipeline_cmds,
-};
-
-struct pipeline_type pipeline_flow_actions = {
-	.name = "FLOW_ACTIONS",
-	.be_ops = &pipeline_flow_actions_be_ops,
-	.fe_ops = &pipeline_flow_actions_fe_ops,
-};
diff --git a/examples/ip_pipeline/pipeline/pipeline_flow_actions.h b/examples/ip_pipeline/pipeline/pipeline_flow_actions.h
deleted file mode 100644
index 885923e..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_flow_actions.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#ifndef __INCLUDE_PIPELINE_FLOW_ACTIONS_H__
-#define __INCLUDE_PIPELINE_FLOW_ACTIONS_H__
-
-#include <rte_meter.h>
-
-#include "pipeline.h"
-#include "pipeline_flow_actions_be.h"
-
-int
-app_pipeline_fa_flow_config(struct app_params *app,
-	uint32_t pipeline_id,
-	uint32_t flow_id,
-	uint32_t meter_update_mask,
-	uint32_t policer_update_mask,
-	uint32_t port_update,
-	struct pipeline_fa_flow_params *params);
-
-int
-app_pipeline_fa_flow_config_bulk(struct app_params *app,
-	uint32_t pipeline_id,
-	uint32_t *flow_id,
-	uint32_t n_flows,
-	uint32_t meter_update_mask,
-	uint32_t policer_update_mask,
-	uint32_t port_update,
-	struct pipeline_fa_flow_params *params);
-
-int
-app_pipeline_fa_dscp_config(struct app_params *app,
-	uint32_t pipeline_id,
-	uint32_t dscp,
-	uint32_t traffic_class,
-	enum rte_meter_color color);
-
-int
-app_pipeline_fa_flow_policer_stats_read(struct app_params *app,
-	uint32_t pipeline_id,
-	uint32_t flow_id,
-	uint32_t policer_id,
-	int clear,
-	struct pipeline_fa_policer_stats *stats);
-
-#ifndef APP_PIPELINE_FA_MAX_RECORDS_IN_FILE
-#define APP_PIPELINE_FA_MAX_RECORDS_IN_FILE		65536
-#endif
-
-int
-app_pipeline_fa_load_file(char *filename,
-	uint32_t *flow_ids,
-	struct pipeline_fa_flow_params *p,
-	uint32_t *n_flows,
-	uint32_t *line);
-
-extern struct pipeline_type pipeline_flow_actions;
-
-#endif
diff --git a/examples/ip_pipeline/pipeline/pipeline_flow_actions_be.c b/examples/ip_pipeline/pipeline/pipeline_flow_actions_be.c
deleted file mode 100644
index 33f1c41..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_flow_actions_be.c
+++ /dev/null
@@ -1,983 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2016 Intel Corporation
- */
-
-#include <string.h>
-
-#include <rte_common.h>
-#include <rte_malloc.h>
-#include <rte_cycles.h>
-#include <rte_table_array.h>
-#include <rte_byteorder.h>
-#include <rte_ip.h>
-
-#include "pipeline_actions_common.h"
-#include "pipeline_flow_actions_be.h"
-#include "parser.h"
-#include "hash_func.h"
-
-int
-pipeline_fa_flow_params_set_default(struct pipeline_fa_flow_params *params)
-{
-	uint32_t i;
-
-	if (params == NULL)
-		return -1;
-
-	for (i = 0; i < PIPELINE_FA_N_TC_MAX; i++) {
-		struct rte_meter_trtcm_params *m = &params->m[i];
-
-		m->cir = 1;
-		m->cbs = 1;
-		m->pir = 1;
-		m->pbs = 2;
-	}
-
-	for (i = 0; i < PIPELINE_FA_N_TC_MAX; i++) {
-		struct pipeline_fa_policer_params *p = &params->p[i];
-		uint32_t j;
-
-		for (j = 0; j < e_RTE_METER_COLORS; j++) {
-			struct pipeline_fa_policer_action *a = &p->action[j];
-
-			a->drop = 0;
-			a->color = (enum rte_meter_color) j;
-		}
-	}
-
-	params->port_id = 0;
-
-	return 0;
-}
-
-struct dscp_entry {
-	uint32_t traffic_class;
-	enum rte_meter_color color;
-};
-
-struct pipeline_flow_actions {
-	struct pipeline p;
-	struct pipeline_fa_params params;
-	pipeline_msg_req_handler custom_handlers[PIPELINE_FA_MSG_REQS];
-
-	struct dscp_entry dscp[PIPELINE_FA_N_DSCP];
-} __rte_cache_aligned;
-
-static void *
-pipeline_fa_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_fa_msg_req_custom_handler,
-};
-
-static void *
-pipeline_fa_msg_req_flow_config_handler(struct pipeline *p, void *msg);
-
-static void *
-pipeline_fa_msg_req_flow_config_bulk_handler(struct pipeline *p, void *msg);
-
-static void *
-pipeline_fa_msg_req_dscp_config_handler(struct pipeline *p, void *msg);
-
-static void *
-pipeline_fa_msg_req_policer_stats_read_handler(struct pipeline *p, void *msg);
-
-static pipeline_msg_req_handler custom_handlers[] = {
-	[PIPELINE_FA_MSG_REQ_FLOW_CONFIG] =
-		pipeline_fa_msg_req_flow_config_handler,
-	[PIPELINE_FA_MSG_REQ_FLOW_CONFIG_BULK] =
-		pipeline_fa_msg_req_flow_config_bulk_handler,
-	[PIPELINE_FA_MSG_REQ_DSCP_CONFIG] =
-		pipeline_fa_msg_req_dscp_config_handler,
-	[PIPELINE_FA_MSG_REQ_POLICER_STATS_READ] =
-		pipeline_fa_msg_req_policer_stats_read_handler,
-};
-
-/*
- * Flow table
- */
-struct meter_policer {
-	struct rte_meter_trtcm meter;
-	struct rte_meter_trtcm_profile meter_profile;
-	struct pipeline_fa_policer_params policer;
-	struct pipeline_fa_policer_stats stats;
-};
-
-struct flow_table_entry {
-	struct rte_pipeline_table_entry head;
-	struct meter_policer mp[PIPELINE_FA_N_TC_MAX];
-};
-
-static int
-flow_table_entry_set_meter(struct flow_table_entry *entry,
-	uint32_t meter_id,
-	struct pipeline_fa_flow_params *params)
-{
-	struct rte_meter_trtcm *meter = &entry->mp[meter_id].meter;
-	struct rte_meter_trtcm_params *meter_params = &params->m[meter_id];
-	struct rte_meter_trtcm_profile *meter_profile =
-					&entry->mp[meter_id].meter_profile;
-	int status;
-
-	status = rte_meter_trtcm_profile_config(meter_profile, meter_params);
-	if (status)
-		return status;
-
-	return rte_meter_trtcm_config(meter, meter_profile);
-}
-
-static void
-flow_table_entry_set_policer(struct flow_table_entry *entry,
-	uint32_t policer_id,
-	struct pipeline_fa_flow_params *params)
-{
-	struct pipeline_fa_policer_params *p0 = &entry->mp[policer_id].policer;
-	struct pipeline_fa_policer_params *p1 = &params->p[policer_id];
-
-	memcpy(p0, p1, sizeof(*p0));
-}
-
-static void
-flow_table_entry_set_port_id(struct pipeline_flow_actions *p,
-	struct flow_table_entry *entry,
-	struct pipeline_fa_flow_params *params)
-{
-	entry->head.action = RTE_PIPELINE_ACTION_PORT;
-	entry->head.port_id = p->p.port_out_id[params->port_id];
-}
-
-static int
-flow_table_entry_set_default(struct pipeline_flow_actions *p,
-	struct flow_table_entry *entry)
-{
-	struct pipeline_fa_flow_params params;
-	uint32_t i;
-
-	pipeline_fa_flow_params_set_default(&params);
-
-	memset(entry, 0, sizeof(*entry));
-
-	flow_table_entry_set_port_id(p, entry, &params);
-
-	for (i = 0; i < PIPELINE_FA_N_TC_MAX; i++) {
-		int status;
-
-		status = flow_table_entry_set_meter(entry, i, &params);
-		if (status)
-			return status;
-	}
-
-	for (i = 0; i < PIPELINE_FA_N_TC_MAX; i++)
-		flow_table_entry_set_policer(entry, i, &params);
-
-	return 0;
-}
-
-static inline uint64_t
-pkt_work(
-	struct rte_mbuf *pkt,
-	struct rte_pipeline_table_entry *table_entry,
-	void *arg,
-	uint64_t time)
-{
-	struct pipeline_flow_actions *p = arg;
-	struct flow_table_entry *entry =
-		(struct flow_table_entry *) table_entry;
-
-	struct ipv4_hdr *pkt_ip = (struct ipv4_hdr *)
-		RTE_MBUF_METADATA_UINT32_PTR(pkt, p->params.ip_hdr_offset);
-	enum rte_meter_color *pkt_color = (enum rte_meter_color *)
-		RTE_MBUF_METADATA_UINT32_PTR(pkt, p->params.color_offset);
-
-	/* Read (IP header) */
-	uint32_t total_length = rte_bswap16(pkt_ip->total_length);
-	uint32_t dscp = pkt_ip->type_of_service >> 2;
-
-	uint32_t tc = p->dscp[dscp].traffic_class;
-	enum rte_meter_color color = p->dscp[dscp].color;
-
-	struct rte_meter_trtcm *meter = &entry->mp[tc].meter;
-	struct rte_meter_trtcm_profile *meter_profile =
-					&entry->mp[tc].meter_profile;
-	struct pipeline_fa_policer_params *policer = &entry->mp[tc].policer;
-	struct pipeline_fa_policer_stats *stats = &entry->mp[tc].stats;
-
-	/* Read (entry), compute */
-	enum rte_meter_color color2 = rte_meter_trtcm_color_aware_check(meter,
-		meter_profile,
-		time,
-		total_length,
-		color);
-
-	enum rte_meter_color color3 = policer->action[color2].color;
-	uint64_t drop = policer->action[color2].drop;
-
-	/* Read (entry), write (entry, color) */
-	stats->n_pkts[color3] += drop ^ 1LLU;
-	stats->n_pkts_drop += drop;
-	*pkt_color = color3;
-
-	return drop;
-}
-
-static inline uint64_t
-pkt4_work(
-	struct rte_mbuf **pkts,
-	struct rte_pipeline_table_entry **table_entries,
-	void *arg,
-	uint64_t time)
-{
-	struct pipeline_flow_actions *p = arg;
-
-	struct flow_table_entry *entry0 =
-		(struct flow_table_entry *) table_entries[0];
-	struct flow_table_entry *entry1 =
-		(struct flow_table_entry *) table_entries[1];
-	struct flow_table_entry *entry2 =
-		(struct flow_table_entry *) table_entries[2];
-	struct flow_table_entry *entry3 =
-		(struct flow_table_entry *) table_entries[3];
-
-	struct ipv4_hdr *pkt0_ip = (struct ipv4_hdr *)
-		RTE_MBUF_METADATA_UINT32_PTR(pkts[0], p->params.ip_hdr_offset);
-	struct ipv4_hdr *pkt1_ip = (struct ipv4_hdr *)
-		RTE_MBUF_METADATA_UINT32_PTR(pkts[1], p->params.ip_hdr_offset);
-	struct ipv4_hdr *pkt2_ip = (struct ipv4_hdr *)
-		RTE_MBUF_METADATA_UINT32_PTR(pkts[2], p->params.ip_hdr_offset);
-	struct ipv4_hdr *pkt3_ip = (struct ipv4_hdr *)
-		RTE_MBUF_METADATA_UINT32_PTR(pkts[3], p->params.ip_hdr_offset);
-
-	enum rte_meter_color *pkt0_color = (enum rte_meter_color *)
-		RTE_MBUF_METADATA_UINT32_PTR(pkts[0], p->params.color_offset);
-	enum rte_meter_color *pkt1_color = (enum rte_meter_color *)
-		RTE_MBUF_METADATA_UINT32_PTR(pkts[1], p->params.color_offset);
-	enum rte_meter_color *pkt2_color = (enum rte_meter_color *)
-		RTE_MBUF_METADATA_UINT32_PTR(pkts[2], p->params.color_offset);
-	enum rte_meter_color *pkt3_color = (enum rte_meter_color *)
-		RTE_MBUF_METADATA_UINT32_PTR(pkts[3], p->params.color_offset);
-
-	/* Read (IP header) */
-	uint32_t total_length0 = rte_bswap16(pkt0_ip->total_length);
-	uint32_t dscp0 = pkt0_ip->type_of_service >> 2;
-
-	uint32_t total_length1 = rte_bswap16(pkt1_ip->total_length);
-	uint32_t dscp1 = pkt1_ip->type_of_service >> 2;
-
-	uint32_t total_length2 = rte_bswap16(pkt2_ip->total_length);
-	uint32_t dscp2 = pkt2_ip->type_of_service >> 2;
-
-	uint32_t total_length3 = rte_bswap16(pkt3_ip->total_length);
-	uint32_t dscp3 = pkt3_ip->type_of_service >> 2;
-
-	uint32_t tc0 = p->dscp[dscp0].traffic_class;
-	enum rte_meter_color color0 = p->dscp[dscp0].color;
-
-	uint32_t tc1 = p->dscp[dscp1].traffic_class;
-	enum rte_meter_color color1 = p->dscp[dscp1].color;
-
-	uint32_t tc2 = p->dscp[dscp2].traffic_class;
-	enum rte_meter_color color2 = p->dscp[dscp2].color;
-
-	uint32_t tc3 = p->dscp[dscp3].traffic_class;
-	enum rte_meter_color color3 = p->dscp[dscp3].color;
-
-	struct rte_meter_trtcm *meter0 = &entry0->mp[tc0].meter;
-	struct rte_meter_trtcm_profile *meter0_profile =
-				&entry0->mp[tc0].meter_profile;
-	struct pipeline_fa_policer_params *policer0 = &entry0->mp[tc0].policer;
-	struct pipeline_fa_policer_stats *stats0 = &entry0->mp[tc0].stats;
-
-	struct rte_meter_trtcm *meter1 = &entry1->mp[tc1].meter;
-	struct rte_meter_trtcm_profile *meter1_profile =
-				&entry1->mp[tc1].meter_profile;
-	struct pipeline_fa_policer_params *policer1 = &entry1->mp[tc1].policer;
-	struct pipeline_fa_policer_stats *stats1 = &entry1->mp[tc1].stats;
-
-	struct rte_meter_trtcm *meter2 = &entry2->mp[tc2].meter;
-	struct rte_meter_trtcm_profile *meter2_profile =
-				&entry2->mp[tc2].meter_profile;
-	struct pipeline_fa_policer_params *policer2 = &entry2->mp[tc2].policer;
-	struct pipeline_fa_policer_stats *stats2 = &entry2->mp[tc2].stats;
-
-	struct rte_meter_trtcm *meter3 = &entry3->mp[tc3].meter;
-	struct rte_meter_trtcm_profile *meter3_profile =
-				&entry3->mp[tc3].meter_profile;
-	struct pipeline_fa_policer_params *policer3 = &entry3->mp[tc3].policer;
-	struct pipeline_fa_policer_stats *stats3 = &entry3->mp[tc3].stats;
-
-	/* Read (entry), compute, write (entry) */
-	enum rte_meter_color color2_0 = rte_meter_trtcm_color_aware_check(
-		meter0,
-		meter0_profile,
-		time,
-		total_length0,
-		color0);
-
-	enum rte_meter_color color2_1 = rte_meter_trtcm_color_aware_check(
-		meter1,
-		meter1_profile,
-		time,
-		total_length1,
-		color1);
-
-	enum rte_meter_color color2_2 = rte_meter_trtcm_color_aware_check(
-		meter2,
-		meter2_profile,
-		time,
-		total_length2,
-		color2);
-
-	enum rte_meter_color color2_3 = rte_meter_trtcm_color_aware_check(
-		meter3,
-		meter3_profile,
-		time,
-		total_length3,
-		color3);
-
-	enum rte_meter_color color3_0 = policer0->action[color2_0].color;
-	enum rte_meter_color color3_1 = policer1->action[color2_1].color;
-	enum rte_meter_color color3_2 = policer2->action[color2_2].color;
-	enum rte_meter_color color3_3 = policer3->action[color2_3].color;
-
-	uint64_t drop0 = policer0->action[color2_0].drop;
-	uint64_t drop1 = policer1->action[color2_1].drop;
-	uint64_t drop2 = policer2->action[color2_2].drop;
-	uint64_t drop3 = policer3->action[color2_3].drop;
-
-	/* Read (entry), write (entry, color) */
-	stats0->n_pkts[color3_0] += drop0 ^ 1LLU;
-	stats0->n_pkts_drop += drop0;
-
-	stats1->n_pkts[color3_1] += drop1 ^ 1LLU;
-	stats1->n_pkts_drop += drop1;
-
-	stats2->n_pkts[color3_2] += drop2 ^ 1LLU;
-	stats2->n_pkts_drop += drop2;
-
-	stats3->n_pkts[color3_3] += drop3 ^ 1LLU;
-	stats3->n_pkts_drop += drop3;
-
-	*pkt0_color = color3_0;
-	*pkt1_color = color3_1;
-	*pkt2_color = color3_2;
-	*pkt3_color = color3_3;
-
-	return drop0 | (drop1 << 1) | (drop2 << 2) | (drop3 << 3);
-}
-
-PIPELINE_TABLE_AH_HIT_DROP_TIME(fa_table_ah_hit, pkt_work, pkt4_work);
-
-static rte_pipeline_table_action_handler_hit
-get_fa_table_ah_hit(__rte_unused struct pipeline_flow_actions *p)
-{
-	return fa_table_ah_hit;
-}
-
-/*
- * Argument parsing
- */
-int
-pipeline_fa_parse_args(struct pipeline_fa_params *p,
-	struct pipeline_params *params)
-{
-	uint32_t n_flows_present = 0;
-	uint32_t n_meters_per_flow_present = 0;
-	uint32_t flow_id_offset_present = 0;
-	uint32_t ip_hdr_offset_present = 0;
-	uint32_t color_offset_present = 0;
-	uint32_t i;
-
-	/* Default values */
-	p->n_meters_per_flow = 1;
-	p->dscp_enabled = 0;
-
-	for (i = 0; i < params->n_args; i++) {
-		char *arg_name = params->args_name[i];
-		char *arg_value = params->args_value[i];
-
-		/* n_flows */
-		if (strcmp(arg_name, "n_flows") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				n_flows_present == 0, params->name,
-				arg_name);
-			n_flows_present = 1;
-
-			status = parser_read_uint32(&p->n_flows,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL(((status != -EINVAL) &&
-				(p->n_flows != 0)), params->name,
-				arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			continue;
-		}
-
-		/* n_meters_per_flow */
-		if (strcmp(arg_name, "n_meters_per_flow") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				n_meters_per_flow_present == 0,
-				params->name, arg_name);
-			n_meters_per_flow_present = 1;
-
-			status = parser_read_uint32(&p->n_meters_per_flow,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL(((status != -EINVAL) &&
-				(p->n_meters_per_flow != 0)),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG(((status != -ERANGE) &&
-				(p->n_meters_per_flow <=
-				PIPELINE_FA_N_TC_MAX)), params->name,
-				arg_name, arg_value);
-
-			continue;
-		}
-
-		/* flow_id_offset */
-		if (strcmp(arg_name, "flow_id_offset") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				flow_id_offset_present == 0,
-				params->name, arg_name);
-			flow_id_offset_present = 1;
-
-			status = parser_read_uint32(&p->flow_id_offset,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			continue;
-		}
-
-		/* ip_hdr_offset */
-		if (strcmp(arg_name, "ip_hdr_offset") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				ip_hdr_offset_present == 0,
-				params->name, arg_name);
-			ip_hdr_offset_present = 1;
-
-			status = parser_read_uint32(&p->ip_hdr_offset,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			continue;
-		}
-
-		/* color_offset */
-		if (strcmp(arg_name, "color_offset") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				color_offset_present == 0, params->name,
-				arg_name);
-			color_offset_present = 1;
-
-			status = parser_read_uint32(&p->color_offset,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			p->dscp_enabled = 1;
-
-			continue;
-		}
-
-		/* Unknown argument */
-		PIPELINE_PARSE_ERR_INV_ENT(0, params->name, arg_name);
-	}
-
-	/* Check that mandatory arguments are present */
-	PIPELINE_PARSE_ERR_MANDATORY((n_flows_present), params->name,
-		"n_flows");
-	PIPELINE_PARSE_ERR_MANDATORY((flow_id_offset_present),
-		params->name, "flow_id_offset");
-	PIPELINE_PARSE_ERR_MANDATORY((ip_hdr_offset_present),
-		params->name, "ip_hdr_offset");
-	PIPELINE_PARSE_ERR_MANDATORY((color_offset_present), params->name,
-		"color_offset");
-
-	return 0;
-}
-
-static void
-dscp_init(struct pipeline_flow_actions *p)
-{
-	uint32_t i;
-
-	for (i = 0; i < PIPELINE_FA_N_DSCP; i++) {
-		p->dscp[i].traffic_class = 0;
-		p->dscp[i].color = e_RTE_METER_GREEN;
-	}
-}
-
-static void *pipeline_fa_init(struct pipeline_params *params,
-	__rte_unused void *arg)
-{
-	struct pipeline *p;
-	struct pipeline_flow_actions *p_fa;
-	uint32_t size, i;
-
-	/* Check input arguments */
-	if (params == NULL)
-		return NULL;
-
-	if (params->n_ports_in != params->n_ports_out)
-		return NULL;
-
-	/* Memory allocation */
-	size = RTE_CACHE_LINE_ROUNDUP(
-		sizeof(struct pipeline_flow_actions));
-	p = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
-	if (p == NULL)
-		return NULL;
-	p_fa = (struct pipeline_flow_actions *) p;
-
-	strcpy(p->name, params->name);
-	p->log_level = params->log_level;
-
-	PLOG(p, HIGH, "Flow actions");
-
-	/* Parse arguments */
-	if (pipeline_fa_parse_args(&p_fa->params, params))
-		return NULL;
-
-	dscp_init(p_fa);
-
-	/* 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,
-			.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_array_params table_array_params = {
-			.n_entries = p_fa->params.n_flows,
-			.offset = p_fa->params.flow_id_offset,
-		};
-
-		struct rte_pipeline_table_params table_params = {
-			.ops = &rte_table_array_ops,
-			.arg_create = &table_array_params,
-			.f_action_hit = get_fa_table_ah_hit(p_fa),
-			.f_action_miss = NULL,
-			.arg_ah = p_fa,
-			.action_data_size =
-				sizeof(struct flow_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;
-		}
-	}
-
-	/* 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;
-		}
-	}
-
-	/* Initialize table entries */
-	for (i = 0; i < p_fa->params.n_flows; i++) {
-		struct rte_table_array_key key = {
-			.pos = i,
-		};
-
-		struct flow_table_entry entry;
-		struct rte_pipeline_table_entry *entry_ptr;
-		int key_found, status;
-
-		flow_table_entry_set_default(p_fa, &entry);
-
-		status = rte_pipeline_table_entry_add(p->p,
-			p->table_id[0],
-			&key,
-			(struct rte_pipeline_table_entry *) &entry,
-			&key_found,
-			&entry_ptr);
-
-		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_fa->custom_handlers,
-		custom_handlers,
-		sizeof(p_fa->custom_handlers));
-
-	return p;
-}
-
-static int
-pipeline_fa_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_fa_timer(void *pipeline)
-{
-	struct pipeline *p = (struct pipeline *) pipeline;
-
-	pipeline_msg_req_handle(p);
-	rte_pipeline_flush(p->p);
-
-	return 0;
-}
-
-void *
-pipeline_fa_msg_req_custom_handler(struct pipeline *p, void *msg)
-{
-	struct pipeline_flow_actions *p_fa =
-			(struct pipeline_flow_actions *) p;
-	struct pipeline_custom_msg_req *req = msg;
-	pipeline_msg_req_handler f_handle;
-
-	f_handle = (req->subtype < PIPELINE_FA_MSG_REQS) ?
-		p_fa->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_fa_msg_req_flow_config_handler(struct pipeline *p, void *msg)
-{
-	struct pipeline_flow_actions *p_fa = (struct pipeline_flow_actions *) p;
-	struct pipeline_fa_flow_config_msg_req *req = msg;
-	struct pipeline_fa_flow_config_msg_rsp *rsp = msg;
-	struct flow_table_entry *entry;
-	uint32_t mask, i;
-
-	/* Set flow table entry to default if not configured before */
-	if (req->entry_ptr == NULL) {
-		struct rte_table_array_key key = {
-			.pos = req->flow_id % p_fa->params.n_flows,
-		};
-
-		struct flow_table_entry default_entry;
-
-		int key_found, status;
-
-		flow_table_entry_set_default(p_fa, &default_entry);
-
-		status = rte_pipeline_table_entry_add(p->p,
-			p->table_id[0],
-			&key,
-			(struct rte_pipeline_table_entry *) &default_entry,
-			&key_found,
-			(struct rte_pipeline_table_entry **) &entry);
-		if (status) {
-			rsp->status = -1;
-			return rsp;
-		}
-	} else
-		entry = (struct flow_table_entry *) req->entry_ptr;
-
-	/* Meter */
-	for (i = 0, mask = 1; i < PIPELINE_FA_N_TC_MAX; i++, mask <<= 1) {
-		int status;
-
-		if ((mask & req->meter_update_mask) == 0)
-			continue;
-
-		status = flow_table_entry_set_meter(entry, i, &req->params);
-		if (status) {
-			rsp->status = -1;
-			return rsp;
-		}
-	}
-
-	/* Policer */
-	for (i = 0, mask = 1; i < PIPELINE_FA_N_TC_MAX; i++, mask <<= 1) {
-		if ((mask & req->policer_update_mask) == 0)
-			continue;
-
-		flow_table_entry_set_policer(entry, i, &req->params);
-	}
-
-	/* Port */
-	if (req->port_update)
-		flow_table_entry_set_port_id(p_fa, entry, &req->params);
-
-	/* Response */
-	rsp->status = 0;
-	rsp->entry_ptr = (void *) entry;
-	return rsp;
-}
-
-void *
-pipeline_fa_msg_req_flow_config_bulk_handler(struct pipeline *p, void *msg)
-{
-	struct pipeline_flow_actions *p_fa = (struct pipeline_flow_actions *) p;
-	struct pipeline_fa_flow_config_bulk_msg_req *req = msg;
-	struct pipeline_fa_flow_config_bulk_msg_rsp *rsp = msg;
-	uint32_t i;
-
-	for (i = 0; i < req->n_flows; i++) {
-		struct flow_table_entry *entry;
-		uint32_t j, mask;
-
-		/* Set flow table entry to default if not configured before */
-		if (req->entry_ptr[i] == NULL) {
-			struct rte_table_array_key key = {
-				.pos = req->flow_id[i] % p_fa->params.n_flows,
-			};
-
-			struct flow_table_entry entry_to_add;
-
-			int key_found, status;
-
-			flow_table_entry_set_default(p_fa, &entry_to_add);
-
-			status = rte_pipeline_table_entry_add(p->p,
-			 p->table_id[0],
-			 &key,
-			 (struct rte_pipeline_table_entry *) &entry_to_add,
-			 &key_found,
-			 (struct rte_pipeline_table_entry **) &entry);
-			if (status) {
-				rsp->n_flows = i;
-				return rsp;
-			}
-
-			req->entry_ptr[i] = (void *) entry;
-		} else
-			entry = (struct flow_table_entry *) req->entry_ptr[i];
-
-		/* Meter */
-		for (j = 0, mask = 1;
-			j < PIPELINE_FA_N_TC_MAX;
-			j++, mask <<= 1) {
-			int status;
-
-			if ((mask & req->meter_update_mask) == 0)
-				continue;
-
-			status = flow_table_entry_set_meter(entry,
-				j, &req->params[i]);
-			if (status) {
-				rsp->n_flows = i;
-				return rsp;
-			}
-		}
-
-		/* Policer */
-		for (j = 0, mask = 1;
-			j < PIPELINE_FA_N_TC_MAX;
-			j++, mask <<= 1) {
-			if ((mask & req->policer_update_mask) == 0)
-				continue;
-
-			flow_table_entry_set_policer(entry,
-			 j, &req->params[i]);
-		}
-
-		/* Port */
-		if (req->port_update)
-			flow_table_entry_set_port_id(p_fa,
-			 entry, &req->params[i]);
-	}
-
-	/* Response */
-	rsp->n_flows = i;
-	return rsp;
-}
-
-void *
-pipeline_fa_msg_req_dscp_config_handler(struct pipeline *p, void *msg)
-{
-	struct pipeline_flow_actions *p_fa = (struct pipeline_flow_actions *) p;
-	struct pipeline_fa_dscp_config_msg_req *req = msg;
-	struct pipeline_fa_dscp_config_msg_rsp *rsp = msg;
-
-	/* Check request */
-	if ((req->dscp >= PIPELINE_FA_N_DSCP) ||
-		(req->traffic_class >= PIPELINE_FA_N_TC_MAX) ||
-		(req->color >= e_RTE_METER_COLORS)) {
-		rsp->status = -1;
-		return rsp;
-	}
-
-	p_fa->dscp[req->dscp].traffic_class = req->traffic_class;
-	p_fa->dscp[req->dscp].color = req->color;
-	rsp->status = 0;
-	return rsp;
-}
-
-void *
-pipeline_fa_msg_req_policer_stats_read_handler(__rte_unused struct pipeline *p,
-	void *msg)
-{
-	struct pipeline_fa_policer_stats_msg_req *req = msg;
-	struct pipeline_fa_policer_stats_msg_rsp *rsp = msg;
-
-	struct flow_table_entry *entry = req->entry_ptr;
-	uint32_t policer_id = req->policer_id;
-	int clear = req->clear;
-
-	/* Check request */
-	if ((req->entry_ptr == NULL) ||
-		(req->policer_id >= PIPELINE_FA_N_TC_MAX)) {
-		rsp->status = -1;
-		return rsp;
-	}
-
-	memcpy(&rsp->stats,
-		&entry->mp[policer_id].stats,
-		sizeof(rsp->stats));
-	if (clear)
-		memset(&entry->mp[policer_id].stats,
-			0, sizeof(entry->mp[policer_id].stats));
-	rsp->status = 0;
-	return rsp;
-}
-
-struct pipeline_be_ops pipeline_flow_actions_be_ops = {
-	.f_init = pipeline_fa_init,
-	.f_free = pipeline_fa_free,
-	.f_run = NULL,
-	.f_timer = pipeline_fa_timer,
-};
diff --git a/examples/ip_pipeline/pipeline/pipeline_flow_actions_be.h b/examples/ip_pipeline/pipeline/pipeline_flow_actions_be.h
deleted file mode 100644
index ef6cb26..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_flow_actions_be.h
+++ /dev/null
@@ -1,139 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#ifndef __INCLUDE_PIPELINE_FLOW_ACTIONS_BE_H__
-#define __INCLUDE_PIPELINE_FLOW_ACTIONS_BE_H__
-
-#include <rte_meter.h>
-
-#include "pipeline_common_be.h"
-
-#ifndef PIPELINE_FA_N_TC_MAX
-#define PIPELINE_FA_N_TC_MAX                               4
-#endif
-
-#define PIPELINE_FA_N_DSCP                                 64
-
-struct pipeline_fa_params {
-	uint32_t n_flows;
-	uint32_t n_meters_per_flow;
-	uint32_t flow_id_offset;
-	uint32_t ip_hdr_offset;
-	uint32_t color_offset;
-	uint32_t dscp_enabled;
-};
-
-int
-pipeline_fa_parse_args(struct pipeline_fa_params *p,
-	struct pipeline_params *params);
-
-struct pipeline_fa_policer_action {
-	uint32_t drop;
-	enum rte_meter_color color;
-};
-
-struct pipeline_fa_policer_params {
-	struct pipeline_fa_policer_action action[e_RTE_METER_COLORS];
-};
-
-struct pipeline_fa_flow_params {
-	struct rte_meter_trtcm_params m[PIPELINE_FA_N_TC_MAX];
-	struct pipeline_fa_policer_params p[PIPELINE_FA_N_TC_MAX];
-	uint32_t port_id;
-};
-
-int
-pipeline_fa_flow_params_set_default(struct pipeline_fa_flow_params *params);
-
-struct pipeline_fa_policer_stats {
-	uint64_t n_pkts[e_RTE_METER_COLORS];
-	uint64_t n_pkts_drop;
-};
-
-enum pipeline_fa_msg_req_type {
-	PIPELINE_FA_MSG_REQ_FLOW_CONFIG = 0,
-	PIPELINE_FA_MSG_REQ_FLOW_CONFIG_BULK,
-	PIPELINE_FA_MSG_REQ_DSCP_CONFIG,
-	PIPELINE_FA_MSG_REQ_POLICER_STATS_READ,
-	PIPELINE_FA_MSG_REQS,
-};
-
-/*
- * MSG FLOW CONFIG
- */
-struct pipeline_fa_flow_config_msg_req {
-	enum pipeline_msg_req_type type;
-	enum pipeline_fa_msg_req_type subtype;
-
-	void *entry_ptr;
-	uint32_t flow_id;
-
-	uint32_t meter_update_mask;
-	uint32_t policer_update_mask;
-	uint32_t port_update;
-	struct pipeline_fa_flow_params params;
-};
-
-struct pipeline_fa_flow_config_msg_rsp {
-	int status;
-	void *entry_ptr;
-};
-
-/*
- * MSG FLOW CONFIG BULK
- */
-struct pipeline_fa_flow_config_bulk_msg_req {
-	enum pipeline_msg_req_type type;
-	enum pipeline_fa_msg_req_type subtype;
-
-	void **entry_ptr;
-	uint32_t *flow_id;
-	uint32_t n_flows;
-
-	uint32_t meter_update_mask;
-	uint32_t policer_update_mask;
-	uint32_t port_update;
-	struct pipeline_fa_flow_params *params;
-};
-
-struct pipeline_fa_flow_config_bulk_msg_rsp {
-	uint32_t n_flows;
-};
-
-/*
- * MSG DSCP CONFIG
- */
-struct pipeline_fa_dscp_config_msg_req {
-	enum pipeline_msg_req_type type;
-	enum pipeline_fa_msg_req_type subtype;
-
-	uint32_t dscp;
-	uint32_t traffic_class;
-	enum rte_meter_color color;
-};
-
-struct pipeline_fa_dscp_config_msg_rsp {
-	int status;
-};
-
-/*
- * MSG POLICER STATS READ
- */
-struct pipeline_fa_policer_stats_msg_req {
-	enum pipeline_msg_req_type type;
-	enum pipeline_fa_msg_req_type subtype;
-
-	void *entry_ptr;
-	uint32_t policer_id;
-	int clear;
-};
-
-struct pipeline_fa_policer_stats_msg_rsp {
-	int status;
-	struct pipeline_fa_policer_stats stats;
-};
-
-extern struct pipeline_be_ops pipeline_flow_actions_be_ops;
-
-#endif
-- 
2.9.3

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

* [dpdk-dev] [PATCH v3 14/44] ip_pipeline: remove firewall pipeline
  2018-03-16 17:58       ` [dpdk-dev] [PATCH v3 00/44] ip_pipeline: refactoring Jasvinder Singh
                           ` (12 preceding siblings ...)
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 13/44] ip_pipeline: remove flow actions pipeline Jasvinder Singh
@ 2018-03-16 17:58         ` Jasvinder Singh
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 15/44] ip_pipeline: remove master pipeline Jasvinder Singh
                           ` (29 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-16 17:58 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Remove firewall pipeline.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/Makefile                      |    2 -
 examples/ip_pipeline/init.c                        |    2 -
 examples/ip_pipeline/meson.build                   |    2 -
 examples/ip_pipeline/pipeline/pipeline_firewall.c  | 1421 --------------------
 examples/ip_pipeline/pipeline/pipeline_firewall.h  |   60 -
 .../ip_pipeline/pipeline/pipeline_firewall_be.c    |  856 ------------
 .../ip_pipeline/pipeline/pipeline_firewall_be.h    |  147 --
 7 files changed, 2490 deletions(-)
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_firewall.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_firewall.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_firewall_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_firewall_be.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index 0782308..ae76edc 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -19,8 +19,6 @@ SRCS-y += pipeline_common_be.c
 SRCS-y += pipeline_common_fe.c
 SRCS-y += pipeline_master_be.c
 SRCS-y += pipeline_master.c
-SRCS-y += pipeline_firewall_be.c
-SRCS-y += pipeline_firewall.c
 
 # Build using pkg-config variables if possible
 $(shell pkg-config --exists libdpdk)
diff --git a/examples/ip_pipeline/init.c b/examples/ip_pipeline/init.c
index 6599b0d..f848310 100644
--- a/examples/ip_pipeline/init.c
+++ b/examples/ip_pipeline/init.c
@@ -26,7 +26,6 @@
 #include "pipeline.h"
 #include "pipeline_common_fe.h"
 #include "pipeline_master.h"
-#include "pipeline_firewall.h"
 #include "thread_fe.h"
 
 #define APP_NAME_SIZE	32
@@ -1818,7 +1817,6 @@ int app_init(struct app_params *app)
 	app_pipeline_common_cmd_push(app);
 	app_pipeline_thread_cmd_push(app);
 	app_pipeline_type_register(app, &pipeline_master);
-	app_pipeline_type_register(app, &pipeline_firewall);
 
 	app_init_pipelines(app);
 	app_init_threads(app);
diff --git a/examples/ip_pipeline/meson.build b/examples/ip_pipeline/meson.build
index 71812f4..1fdfc48 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -21,8 +21,6 @@ sources = files(
 	'thread_fe.c',
 	'pipeline/pipeline_common_be.c',
 	'pipeline/pipeline_common_fe.c',
-	'pipeline/pipeline_firewall_be.c',
-	'pipeline/pipeline_firewall.c',
 	'pipeline/pipeline_master_be.c',
 	'pipeline/pipeline_master.c',
 )
diff --git a/examples/ip_pipeline/pipeline/pipeline_firewall.c b/examples/ip_pipeline/pipeline/pipeline_firewall.c
deleted file mode 100644
index 0cae9d7..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_firewall.c
+++ /dev/null
@@ -1,1421 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-#include <errno.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/queue.h>
-#include <netinet/in.h>
-
-#include <rte_common.h>
-#include <rte_hexdump.h>
-#include <rte_malloc.h>
-#include <cmdline_rdline.h>
-#include <cmdline_parse.h>
-#include <cmdline_parse_num.h>
-#include <cmdline_parse_string.h>
-
-#include "app.h"
-#include "pipeline_common_fe.h"
-#include "pipeline_firewall.h"
-#include "parser.h"
-
-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;
-};
-
-static void
-print_firewall_ipv4_rule(struct app_pipeline_firewall_rule *rule)
-{
-	printf("Prio = %" PRId32 " (SA = %" PRIu32 ".%" PRIu32
-		".%" PRIu32 ".%" PRIu32 "/%" PRIu32 ", "
-		"DA = %" PRIu32 ".%" PRIu32
-		".%"PRIu32 ".%" PRIu32 "/%" PRIu32 ", "
-		"SP = %" PRIu32 "-%" PRIu32 ", "
-		"DP = %" PRIu32 "-%" PRIu32 ", "
-		"Proto = %" PRIu32 " / 0x%" PRIx32 ") => "
-		"Port = %" PRIu32 " (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);
-}
-
-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;
-
-	TAILQ_FOREACH(r, &p->rules, node)
-		if (memcmp(key,
-			&r->key,
-			sizeof(struct pipeline_firewall_key)) == 0)
-			return r;
-
-	return NULL;
-}
-
-static int
-app_pipeline_firewall_ls(
-	struct app_params *app,
-	uint32_t pipeline_id)
-{
-	struct app_pipeline_firewall *p;
-	struct app_pipeline_firewall_rule *rule;
-	uint32_t n_rules;
-	int priority;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_firewall);
-	if (p == NULL)
-		return -1;
-
-	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 %" PRIu32 " (entry ptr = %p)\n",
-			p->default_rule_port_id,
-			p->default_rule_entry_ptr);
-	else
-		printf("Default rule: DROP\n");
-
-	printf("\n");
-
-	return 0;
-}
-
-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;
-
-	/* Initialization */
-	p->n_ports_in = params->n_ports_in;
-	p->n_ports_out = params->n_ports_out;
-
-	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;
-
-	return (void *) p;
-}
-
-static int
-app_pipeline_firewall_free(void *pipeline)
-{
-	struct app_pipeline_firewall *p = pipeline;
-
-	/* Check input arguments */
-	if (p == NULL)
-		return -1;
-
-	/* Free resources */
-	while (!TAILQ_EMPTY(&p->rules)) {
-		struct app_pipeline_firewall_rule *rule;
-
-		rule = TAILQ_FIRST(&p->rules);
-		TAILQ_REMOVE(&p->rules, rule, node);
-		rte_free(rule);
-	}
-
-	rte_free(p);
-	return 0;
-}
-
-static int
-app_pipeline_firewall_key_check_and_normalize(struct pipeline_firewall_key *key)
-{
-	switch (key->type) {
-	case PIPELINE_FIREWALL_IPV4_5TUPLE:
-	{
-		uint32_t src_ip_depth = key->key.ipv4_5tuple.src_ip_mask;
-		uint32_t dst_ip_depth = key->key.ipv4_5tuple.dst_ip_mask;
-		uint16_t src_port_from = key->key.ipv4_5tuple.src_port_from;
-		uint16_t src_port_to = key->key.ipv4_5tuple.src_port_to;
-		uint16_t dst_port_from = key->key.ipv4_5tuple.dst_port_from;
-		uint16_t dst_port_to = key->key.ipv4_5tuple.dst_port_to;
-
-		uint32_t src_ip_netmask = 0;
-		uint32_t dst_ip_netmask = 0;
-
-		if ((src_ip_depth > 32) ||
-			(dst_ip_depth > 32) ||
-			(src_port_from > src_port_to) ||
-			(dst_port_from > dst_port_to))
-			return -1;
-
-		if (src_ip_depth)
-			src_ip_netmask = (~0U) << (32 - src_ip_depth);
-
-		if (dst_ip_depth)
-			dst_ip_netmask = ((~0U) << (32 - dst_ip_depth));
-
-		key->key.ipv4_5tuple.src_ip &= src_ip_netmask;
-		key->key.ipv4_5tuple.dst_ip &= dst_ip_netmask;
-
-		return 0;
-	}
-
-	default:
-		return -1;
-	}
-}
-
-int
-app_pipeline_firewall_load_file(char *filename,
-	struct pipeline_firewall_key *keys,
-	uint32_t *priorities,
-	uint32_t *port_ids,
-	uint32_t *n_keys,
-	uint32_t *line)
-{
-	FILE *f = NULL;
-	char file_buf[1024];
-	uint32_t i, l;
-
-	/* Check input arguments */
-	if ((filename == NULL) ||
-		(keys == NULL) ||
-		(priorities == NULL) ||
-		(port_ids == NULL) ||
-		(n_keys == NULL) ||
-		(*n_keys == 0) ||
-		(line == NULL)) {
-		if (line)
-			*line = 0;
-		return -1;
-		}
-
-	/* Open input file */
-	f = fopen(filename, "r");
-	if (f == NULL) {
-		*line = 0;
-		return -1;
-	}
-
-	/* Read file */
-	for (i = 0, l = 1; i < *n_keys; l++) {
-		char *tokens[32];
-		uint32_t n_tokens = RTE_DIM(tokens);
-
-		uint32_t priority = 0;
-		struct in_addr sipaddr;
-		uint32_t sipdepth = 0;
-		struct in_addr dipaddr;
-		uint32_t dipdepth = 0;
-		uint16_t sport0 = 0;
-		uint16_t sport1 = 0;
-		uint16_t dport0 = 0;
-		uint16_t dport1 = 0;
-		uint8_t proto = 0;
-		uint8_t protomask = 0;
-		uint32_t port_id = 0;
-
-		int status;
-
-		if (fgets(file_buf, sizeof(file_buf), f) == NULL)
-			break;
-
-		status = parse_tokenize_string(file_buf, tokens, &n_tokens);
-		if (status)
-			goto error1;
-
-		if ((n_tokens == 0) || (tokens[0][0] == '#'))
-			continue;
-
-		if ((n_tokens != 15) ||
-			strcmp(tokens[0], "priority") ||
-			parser_read_uint32(&priority, tokens[1]) ||
-			strcmp(tokens[2], "ipv4") ||
-			parse_ipv4_addr(tokens[3], &sipaddr) ||
-			parser_read_uint32(&sipdepth, tokens[4]) ||
-			parse_ipv4_addr(tokens[5], &dipaddr) ||
-			parser_read_uint32(&dipdepth, tokens[6]) ||
-			parser_read_uint16(&sport0, tokens[7]) ||
-			parser_read_uint16(&sport1, tokens[8]) ||
-			parser_read_uint16(&dport0, tokens[9]) ||
-			parser_read_uint16(&dport1, tokens[10]) ||
-			parser_read_uint8(&proto, tokens[11]) ||
-			parser_read_uint8_hex(&protomask, tokens[12]) ||
-			strcmp(tokens[13], "port") ||
-			parser_read_uint32(&port_id, tokens[14]))
-			goto error1;
-
-		keys[i].type = PIPELINE_FIREWALL_IPV4_5TUPLE;
-		keys[i].key.ipv4_5tuple.src_ip =
-			rte_be_to_cpu_32(sipaddr.s_addr);
-		keys[i].key.ipv4_5tuple.src_ip_mask = sipdepth;
-		keys[i].key.ipv4_5tuple.dst_ip =
-			rte_be_to_cpu_32(dipaddr.s_addr);
-		keys[i].key.ipv4_5tuple.dst_ip_mask = dipdepth;
-		keys[i].key.ipv4_5tuple.src_port_from = sport0;
-		keys[i].key.ipv4_5tuple.src_port_to = sport1;
-		keys[i].key.ipv4_5tuple.dst_port_from = dport0;
-		keys[i].key.ipv4_5tuple.dst_port_to = dport1;
-		keys[i].key.ipv4_5tuple.proto = proto;
-		keys[i].key.ipv4_5tuple.proto_mask = protomask;
-
-		port_ids[i] = port_id;
-		priorities[i] = priority;
-
-		if (app_pipeline_firewall_key_check_and_normalize(&keys[i]))
-			goto error1;
-
-		i++;
-	}
-
-	/* Close file */
-	*n_keys = i;
-	fclose(f);
-	return 0;
-
-error1:
-	*line = l;
-	fclose(f);
-	return -1;
-}
-
-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_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;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_firewall);
-	if (p == NULL)
-		return -1;
-
-	if (port_id >= p->n_ports_out)
-		return -1;
-
-	if (app_pipeline_firewall_key_check_and_normalize(key) != 0)
-		return -1;
-
-	/* 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;
-	}
-
-	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_DEFAULT);
-	if (rsp == NULL) {
-		if (new_rule)
-			rte_free(rule);
-		return -1;
-	}
-
-	/* Read response and write rule */
-	if (rsp->status ||
-		(rsp->entry_ptr == NULL) ||
-		((new_rule == 0) && (rsp->key_found == 0)) ||
-		((new_rule == 1) && (rsp->key_found == 1))) {
-		app_msg_free(app, rsp);
-		if (new_rule)
-			rte_free(rule);
-		return -1;
-	}
-
-	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;
-}
-
-int
-app_pipeline_firewall_delete_rule(struct app_params *app,
-	uint32_t pipeline_id,
-	struct pipeline_firewall_key *key)
-{
-	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;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_firewall);
-	if (p == NULL)
-		return -1;
-
-	if (app_pipeline_firewall_key_check_and_normalize(key) != 0)
-		return -1;
-
-	/* 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_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	/* Read response */
-	if (rsp->status || !rsp->key_found) {
-		app_msg_free(app, rsp);
-		return -1;
-	}
-
-	/* Remove rule */
-	TAILQ_REMOVE(&p->rules, rule, node);
-	p->n_rules--;
-	rte_free(rule);
-
-	/* Free response */
-	app_msg_free(app, rsp);
-
-	return 0;
-}
-
-int
-app_pipeline_firewall_add_bulk(struct app_params *app,
-		uint32_t pipeline_id,
-		struct pipeline_firewall_key *keys,
-		uint32_t n_keys,
-		uint32_t *priorities,
-		uint32_t *port_ids)
-{
-	struct app_pipeline_firewall *p;
-	struct pipeline_firewall_add_bulk_msg_req *req;
-	struct pipeline_firewall_add_bulk_msg_rsp *rsp;
-
-	struct app_pipeline_firewall_rule **rules;
-	int *new_rules;
-
-	int *keys_found;
-	void **entries_ptr;
-
-	uint32_t i;
-	int status = 0;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_firewall);
-	if (p == NULL)
-		return -1;
-
-	rules = rte_malloc(NULL,
-		n_keys * sizeof(struct app_pipeline_firewall_rule *),
-		RTE_CACHE_LINE_SIZE);
-	if (rules == NULL)
-		return -1;
-
-	new_rules = rte_malloc(NULL,
-		n_keys * sizeof(int),
-		RTE_CACHE_LINE_SIZE);
-	if (new_rules == NULL) {
-		rte_free(rules);
-		return -1;
-	}
-
-	/* check data integrity and add to rule list */
-	for (i = 0; i < n_keys; i++) {
-		if (port_ids[i]  >= p->n_ports_out) {
-			rte_free(rules);
-			rte_free(new_rules);
-			return -1;
-		}
-
-		if (app_pipeline_firewall_key_check_and_normalize(&keys[i]) != 0) {
-			rte_free(rules);
-			rte_free(new_rules);
-			return -1;
-		}
-
-		rules[i] = app_pipeline_firewall_rule_find(p, &keys[i]);
-		new_rules[i] = (rules[i] == NULL);
-		if (rules[i] == NULL) {
-			rules[i] = rte_malloc(NULL,
-				sizeof(*rules[i]),
-				RTE_CACHE_LINE_SIZE);
-
-			if (rules[i] == NULL) {
-				uint32_t j;
-
-				for (j = 0; j <= i; j++)
-					if (new_rules[j])
-						rte_free(rules[j]);
-
-				rte_free(rules);
-				rte_free(new_rules);
-				return -1;
-			}
-		}
-	}
-
-	keys_found = rte_malloc(NULL,
-		n_keys * sizeof(int),
-		RTE_CACHE_LINE_SIZE);
-	if (keys_found == NULL) {
-		uint32_t j;
-
-		for (j = 0; j < n_keys; j++)
-			if (new_rules[j])
-				rte_free(rules[j]);
-
-		rte_free(rules);
-		rte_free(new_rules);
-		return -1;
-	}
-
-	entries_ptr = rte_malloc(NULL,
-		n_keys * sizeof(struct rte_pipeline_table_entry *),
-		RTE_CACHE_LINE_SIZE);
-	if (entries_ptr == NULL) {
-		uint32_t j;
-
-		for (j = 0; j < n_keys; j++)
-			if (new_rules[j])
-				rte_free(rules[j]);
-
-		rte_free(rules);
-		rte_free(new_rules);
-		rte_free(keys_found);
-		return -1;
-	}
-	for (i = 0; i < n_keys; i++) {
-		entries_ptr[i] = rte_malloc(NULL,
-			sizeof(struct rte_pipeline_table_entry),
-			RTE_CACHE_LINE_SIZE);
-
-		if (entries_ptr[i] == NULL) {
-			uint32_t j;
-
-			for (j = 0; j < n_keys; j++)
-				if (new_rules[j])
-					rte_free(rules[j]);
-
-			for (j = 0; j <= i; j++)
-				rte_free(entries_ptr[j]);
-
-			rte_free(rules);
-			rte_free(new_rules);
-			rte_free(keys_found);
-			rte_free(entries_ptr);
-			return -1;
-		}
-	}
-
-	/* Allocate and write request */
-	req = app_msg_alloc(app);
-	if (req == NULL) {
-		uint32_t j;
-
-		for (j = 0; j < n_keys; j++)
-			if (new_rules[j])
-				rte_free(rules[j]);
-
-		for (j = 0; j < n_keys; j++)
-			rte_free(entries_ptr[j]);
-
-		rte_free(rules);
-		rte_free(new_rules);
-		rte_free(keys_found);
-		rte_free(entries_ptr);
-		return -1;
-	}
-
-	req->type = PIPELINE_MSG_REQ_CUSTOM;
-	req->subtype = PIPELINE_FIREWALL_MSG_REQ_ADD_BULK;
-
-	req->keys = keys;
-	req->n_keys = n_keys;
-	req->port_ids = port_ids;
-	req->priorities = priorities;
-	req->keys_found = keys_found;
-	req->entries_ptr = entries_ptr;
-
-	/* Send request and wait for response */
-	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL) {
-		uint32_t j;
-
-		for (j = 0; j < n_keys; j++)
-			if (new_rules[j])
-				rte_free(rules[j]);
-
-		for (j = 0; j < n_keys; j++)
-			rte_free(entries_ptr[j]);
-
-		rte_free(rules);
-		rte_free(new_rules);
-		rte_free(keys_found);
-		rte_free(entries_ptr);
-		return -1;
-	}
-
-	if (rsp->status) {
-		for (i = 0; i < n_keys; i++)
-			if (new_rules[i])
-				rte_free(rules[i]);
-
-		for (i = 0; i < n_keys; i++)
-			rte_free(entries_ptr[i]);
-
-		status = -1;
-		goto cleanup;
-	}
-
-	for (i = 0; i < n_keys; i++) {
-		if (entries_ptr[i] == NULL ||
-			((new_rules[i] == 0) && (keys_found[i] == 0)) ||
-			((new_rules[i] == 1) && (keys_found[i] == 1))) {
-			for (i = 0; i < n_keys; i++)
-				if (new_rules[i])
-					rte_free(rules[i]);
-
-			for (i = 0; i < n_keys; i++)
-				rte_free(entries_ptr[i]);
-
-			status = -1;
-			goto cleanup;
-		}
-	}
-
-	for (i = 0; i < n_keys; i++) {
-		memcpy(&rules[i]->key, &keys[i], sizeof(keys[i]));
-		rules[i]->priority = priorities[i];
-		rules[i]->port_id = port_ids[i];
-		rules[i]->entry_ptr = entries_ptr[i];
-
-		/* Commit rule */
-		if (new_rules[i]) {
-			TAILQ_INSERT_TAIL(&p->rules, rules[i], node);
-			p->n_rules++;
-		}
-
-		print_firewall_ipv4_rule(rules[i]);
-	}
-
-cleanup:
-	app_msg_free(app, rsp);
-	rte_free(rules);
-	rte_free(new_rules);
-	rte_free(keys_found);
-	rte_free(entries_ptr);
-
-	return status;
-}
-
-int
-app_pipeline_firewall_delete_bulk(struct app_params *app,
-	uint32_t pipeline_id,
-	struct pipeline_firewall_key *keys,
-	uint32_t n_keys)
-{
-	struct app_pipeline_firewall *p;
-	struct pipeline_firewall_del_bulk_msg_req *req;
-	struct pipeline_firewall_del_bulk_msg_rsp *rsp;
-
-	struct app_pipeline_firewall_rule **rules;
-	int *keys_found;
-
-	uint32_t i;
-	int status = 0;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_firewall);
-	if (p == NULL)
-		return -1;
-
-	rules = rte_malloc(NULL,
-		n_keys * sizeof(struct app_pipeline_firewall_rule *),
-		RTE_CACHE_LINE_SIZE);
-	if (rules == NULL)
-		return -1;
-
-	for (i = 0; i < n_keys; i++) {
-		if (app_pipeline_firewall_key_check_and_normalize(&keys[i]) != 0) {
-			return -1;
-		}
-
-		rules[i] = app_pipeline_firewall_rule_find(p, &keys[i]);
-	}
-
-	keys_found = rte_malloc(NULL,
-		n_keys * sizeof(int),
-		RTE_CACHE_LINE_SIZE);
-	if (keys_found == NULL) {
-		rte_free(rules);
-		return -1;
-	}
-
-	/* Allocate and write request */
-	req = app_msg_alloc(app);
-	if (req == NULL) {
-		rte_free(rules);
-		rte_free(keys_found);
-		return -1;
-	}
-
-	req->type = PIPELINE_MSG_REQ_CUSTOM;
-	req->subtype = PIPELINE_FIREWALL_MSG_REQ_DEL_BULK;
-
-	req->keys = keys;
-	req->n_keys = n_keys;
-	req->keys_found = keys_found;
-
-	/* Send request and wait for response */
-	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL) {
-		rte_free(rules);
-		rte_free(keys_found);
-		return -1;
-	}
-
-	if (rsp->status) {
-		status = -1;
-		goto cleanup;
-	}
-
-	for (i = 0; i < n_keys; i++) {
-		if (keys_found[i] == 0) {
-			status = -1;
-			goto cleanup;
-		}
-	}
-
-	for (i = 0; i < n_keys; i++) {
-		TAILQ_REMOVE(&p->rules, rules[i], node);
-		p->n_rules--;
-		rte_free(rules[i]);
-	}
-
-cleanup:
-	app_msg_free(app, rsp);
-	rte_free(rules);
-	rte_free(keys_found);
-
-	return status;
-}
-
-int
-app_pipeline_firewall_add_default_rule(struct app_params *app,
-	uint32_t pipeline_id,
-	uint32_t port_id)
-{
-	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;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_firewall);
-	if (p == NULL)
-		return -1;
-
-	if (port_id >= p->n_ports_out)
-		return -1;
-
-	/* 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_DEFAULT);
-	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_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;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_firewall);
-	if (p == NULL)
-		return -1;
-
-	/* 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_DEFAULT);
-	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);
-
-	return 0;
-}
-
-/*
- * firewall
- *
- * firewall add:
- *    p <pipelineid> firewall add priority <priority>
- *       ipv4 <sipaddr> <sipdepth> <dipaddr> <dipdepth>
- *       <sport0> <sport1> <dport0> <dport1> <proto> <protomask>
- *       port <portid>
- *       Note: <protomask> is a hex value
- *
- *    p <pipelineid> firewall add bulk <file>
- *
- * firewall add default:
- *    p <pipelineid> firewall add default <port ID>
- *
- * firewall del:
- *    p <pipelineid> firewall del
- *       ipv4 <sipaddr> <sipdepth> <dipaddr> <dipdepth>
- *       <sport0> <sport1> <dport0> <dport1> <proto> <protomask>
- *
- *    p <pipelineid> firewall del bulk <file>
- *
- * firewall del default:
- *    p <pipelineid> firewall del default
- *
- * firewall ls:
- *    p <pipelineid> firewall ls
- */
-
-struct cmd_firewall_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t firewall_string;
-	cmdline_multi_string_t multi_string;
-};
-
-static void cmd_firewall_parsed(void *parsed_result,
-	__attribute__((unused))  struct cmdline *cl,
-	void *data)
-{
-	struct cmd_firewall_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
-
-	char *tokens[17];
-	uint32_t n_tokens = RTE_DIM(tokens);
-
-	status = parse_tokenize_string(params->multi_string, tokens, &n_tokens);
-	if (status) {
-		printf(CMD_MSG_TOO_MANY_ARGS, "firewall");
-		return;
-	}
-
-	/* firewall add */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "add") == 0) &&
-		(strcmp(tokens[1], "priority") == 0)) {
-		struct pipeline_firewall_key key;
-		uint32_t priority;
-		struct in_addr sipaddr;
-		uint32_t sipdepth;
-		struct in_addr dipaddr;
-		uint32_t dipdepth;
-		uint16_t sport0;
-		uint16_t sport1;
-		uint16_t dport0;
-		uint16_t dport1;
-		uint8_t proto;
-		uint8_t protomask;
-		uint32_t port_id;
-
-		memset(&key, 0, sizeof(key));
-
-		if (n_tokens != 16) {
-			printf(CMD_MSG_MISMATCH_ARGS, "firewall add");
-			return;
-		}
-
-		if (parser_read_uint32(&priority, tokens[2])) {
-			printf(CMD_MSG_INVALID_ARG, "priority");
-			return;
-		}
-
-		if (strcmp(tokens[3], "ipv4")) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "ipv4");
-			return;
-		}
-
-		if (parse_ipv4_addr(tokens[4], &sipaddr)) {
-			printf(CMD_MSG_INVALID_ARG, "sipaddr");
-			return;
-		}
-
-		if (parser_read_uint32(&sipdepth, tokens[5])) {
-			printf(CMD_MSG_INVALID_ARG, "sipdepth");
-			return;
-		}
-
-		if (parse_ipv4_addr(tokens[6], &dipaddr)) {
-			printf(CMD_MSG_INVALID_ARG, "dipaddr");
-			return;
-		}
-
-		if (parser_read_uint32(&dipdepth, tokens[7])) {
-			printf(CMD_MSG_INVALID_ARG, "dipdepth");
-			return;
-		}
-
-		if (parser_read_uint16(&sport0, tokens[8])) {
-			printf(CMD_MSG_INVALID_ARG, "sport0");
-			return;
-		}
-
-		if (parser_read_uint16(&sport1, tokens[9])) {
-			printf(CMD_MSG_INVALID_ARG, "sport1");
-			return;
-		}
-
-		if (parser_read_uint16(&dport0, tokens[10])) {
-			printf(CMD_MSG_INVALID_ARG, "dport0");
-			return;
-		}
-
-		if (parser_read_uint16(&dport1, tokens[11])) {
-			printf(CMD_MSG_INVALID_ARG, "dport1");
-			return;
-		}
-
-		if (parser_read_uint8(&proto, tokens[12])) {
-			printf(CMD_MSG_INVALID_ARG, "proto");
-			return;
-		}
-
-		if (parser_read_uint8_hex(&protomask, tokens[13])) {
-			printf(CMD_MSG_INVALID_ARG, "protomask");
-			return;
-		}
-
-		if (strcmp(tokens[14], "port")) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "port");
-			return;
-		}
-
-		if (parser_read_uint32(&port_id, tokens[15])) {
-			printf(CMD_MSG_INVALID_ARG, "portid");
-			return;
-		}
-
-		key.type = PIPELINE_FIREWALL_IPV4_5TUPLE;
-		key.key.ipv4_5tuple.src_ip = rte_be_to_cpu_32(sipaddr.s_addr);
-		key.key.ipv4_5tuple.src_ip_mask = sipdepth;
-		key.key.ipv4_5tuple.dst_ip = rte_be_to_cpu_32(dipaddr.s_addr);
-		key.key.ipv4_5tuple.dst_ip_mask = dipdepth;
-		key.key.ipv4_5tuple.src_port_from = sport0;
-		key.key.ipv4_5tuple.src_port_to = sport1;
-		key.key.ipv4_5tuple.dst_port_from = dport0;
-		key.key.ipv4_5tuple.dst_port_to = dport1;
-		key.key.ipv4_5tuple.proto = proto;
-		key.key.ipv4_5tuple.proto_mask = protomask;
-
-		status = app_pipeline_firewall_add_rule(app,
-			params->pipeline_id,
-			&key,
-			priority,
-			port_id);
-		if (status)
-			printf(CMD_MSG_FAIL, "firewall add");
-
-		return;
-	} /* firewall add */
-
-	/* firewall add bulk */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "add") == 0) &&
-		(strcmp(tokens[1], "bulk") == 0)) {
-		struct pipeline_firewall_key *keys;
-		uint32_t *priorities, *port_ids, n_keys, line;
-		char *filename;
-
-		if (n_tokens != 3) {
-			printf(CMD_MSG_MISMATCH_ARGS, "firewall add bulk");
-			return;
-		}
-
-		filename = tokens[2];
-
-		n_keys = APP_PIPELINE_FIREWALL_MAX_RULES_IN_FILE;
-		keys = malloc(n_keys * sizeof(struct pipeline_firewall_key));
-		if (keys == NULL) {
-			printf(CMD_MSG_OUT_OF_MEMORY);
-			return;
-		}
-		memset(keys, 0, n_keys * sizeof(struct pipeline_firewall_key));
-
-		priorities = malloc(n_keys * sizeof(uint32_t));
-		if (priorities == NULL) {
-			printf(CMD_MSG_OUT_OF_MEMORY);
-			free(keys);
-			return;
-		}
-
-		port_ids = malloc(n_keys * sizeof(uint32_t));
-		if (port_ids == NULL) {
-			printf(CMD_MSG_OUT_OF_MEMORY);
-			free(priorities);
-			free(keys);
-			return;
-		}
-
-		status = app_pipeline_firewall_load_file(filename,
-			keys,
-			priorities,
-			port_ids,
-			&n_keys,
-			&line);
-		if (status != 0) {
-			printf(CMD_MSG_FILE_ERR, filename, line);
-			free(port_ids);
-			free(priorities);
-			free(keys);
-			return;
-		}
-
-		status = app_pipeline_firewall_add_bulk(app,
-			params->pipeline_id,
-			keys,
-			n_keys,
-			priorities,
-			port_ids);
-		if (status)
-			printf(CMD_MSG_FAIL, "firewall add bulk");
-
-		free(keys);
-		free(priorities);
-		free(port_ids);
-		return;
-	} /* firewall add bulk */
-
-	/* firewall add default */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "add") == 0) &&
-		(strcmp(tokens[1], "default") == 0)) {
-		uint32_t port_id;
-
-		if (n_tokens != 3) {
-			printf(CMD_MSG_MISMATCH_ARGS, "firewall add default");
-			return;
-		}
-
-		if (parser_read_uint32(&port_id, tokens[2])) {
-			printf(CMD_MSG_INVALID_ARG, "portid");
-			return;
-		}
-
-		status = app_pipeline_firewall_add_default_rule(app,
-			params->pipeline_id,
-			port_id);
-		if (status)
-			printf(CMD_MSG_FAIL, "firewall add default");
-
-		return;
-	} /* firewall add default */
-
-	/* firewall del */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "del") == 0) &&
-		(strcmp(tokens[1], "ipv4") == 0)) {
-		struct pipeline_firewall_key key;
-		struct in_addr sipaddr;
-		uint32_t sipdepth;
-		struct in_addr dipaddr;
-		uint32_t dipdepth;
-		uint16_t sport0;
-		uint16_t sport1;
-		uint16_t dport0;
-		uint16_t dport1;
-		uint8_t proto;
-		uint8_t protomask;
-
-		memset(&key, 0, sizeof(key));
-
-		if (n_tokens != 12) {
-			printf(CMD_MSG_MISMATCH_ARGS, "firewall del");
-			return;
-		}
-
-		if (parse_ipv4_addr(tokens[2], &sipaddr)) {
-			printf(CMD_MSG_INVALID_ARG, "sipaddr");
-			return;
-		}
-
-		if (parser_read_uint32(&sipdepth, tokens[3])) {
-			printf(CMD_MSG_INVALID_ARG, "sipdepth");
-			return;
-		}
-
-		if (parse_ipv4_addr(tokens[4], &dipaddr)) {
-			printf(CMD_MSG_INVALID_ARG, "dipaddr");
-			return;
-		}
-
-		if (parser_read_uint32(&dipdepth, tokens[5])) {
-			printf(CMD_MSG_INVALID_ARG, "dipdepth");
-			return;
-		}
-
-		if (parser_read_uint16(&sport0, tokens[6])) {
-			printf(CMD_MSG_INVALID_ARG, "sport0");
-			return;
-		}
-
-		if (parser_read_uint16(&sport1, tokens[7])) {
-			printf(CMD_MSG_INVALID_ARG, "sport1");
-			return;
-		}
-
-		if (parser_read_uint16(&dport0, tokens[8])) {
-			printf(CMD_MSG_INVALID_ARG, "dport0");
-			return;
-		}
-
-		if (parser_read_uint16(&dport1, tokens[9])) {
-			printf(CMD_MSG_INVALID_ARG, "dport1");
-			return;
-		}
-
-		if (parser_read_uint8(&proto, tokens[10])) {
-			printf(CMD_MSG_INVALID_ARG, "proto");
-			return;
-		}
-
-		if (parser_read_uint8_hex(&protomask, tokens[11])) {
-			printf(CMD_MSG_INVALID_ARG, "protomask");
-			return;
-		}
-
-		key.type = PIPELINE_FIREWALL_IPV4_5TUPLE;
-		key.key.ipv4_5tuple.src_ip = rte_be_to_cpu_32(sipaddr.s_addr);
-		key.key.ipv4_5tuple.src_ip_mask = sipdepth;
-		key.key.ipv4_5tuple.dst_ip = rte_be_to_cpu_32(dipaddr.s_addr);
-		key.key.ipv4_5tuple.dst_ip_mask = dipdepth;
-		key.key.ipv4_5tuple.src_port_from = sport0;
-		key.key.ipv4_5tuple.src_port_to = sport1;
-		key.key.ipv4_5tuple.dst_port_from = dport0;
-		key.key.ipv4_5tuple.dst_port_to = dport1;
-		key.key.ipv4_5tuple.proto = proto;
-		key.key.ipv4_5tuple.proto_mask = protomask;
-
-		status = app_pipeline_firewall_delete_rule(app,
-			params->pipeline_id,
-			&key);
-		if (status)
-			printf(CMD_MSG_FAIL, "firewall del");
-
-		return;
-	} /* firewall del */
-
-	/* firewall del bulk */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "del") == 0) &&
-		(strcmp(tokens[1], "bulk") == 0)) {
-		struct pipeline_firewall_key *keys;
-		uint32_t *priorities, *port_ids, n_keys, line;
-		char *filename;
-
-		if (n_tokens != 3) {
-			printf(CMD_MSG_MISMATCH_ARGS, "firewall del bulk");
-			return;
-		}
-
-		filename = tokens[2];
-
-		n_keys = APP_PIPELINE_FIREWALL_MAX_RULES_IN_FILE;
-		keys = malloc(n_keys * sizeof(struct pipeline_firewall_key));
-		if (keys == NULL) {
-			printf(CMD_MSG_OUT_OF_MEMORY);
-			return;
-		}
-		memset(keys, 0, n_keys * sizeof(struct pipeline_firewall_key));
-
-		priorities = malloc(n_keys * sizeof(uint32_t));
-		if (priorities == NULL) {
-			printf(CMD_MSG_OUT_OF_MEMORY);
-			free(keys);
-			return;
-		}
-
-		port_ids = malloc(n_keys * sizeof(uint32_t));
-		if (port_ids == NULL) {
-			printf(CMD_MSG_OUT_OF_MEMORY);
-			free(priorities);
-			free(keys);
-			return;
-		}
-
-		status = app_pipeline_firewall_load_file(filename,
-			keys,
-			priorities,
-			port_ids,
-			&n_keys,
-			&line);
-		if (status != 0) {
-			printf(CMD_MSG_FILE_ERR, filename, line);
-			free(port_ids);
-			free(priorities);
-			free(keys);
-			return;
-		}
-
-		status = app_pipeline_firewall_delete_bulk(app,
-			params->pipeline_id,
-			keys,
-			n_keys);
-		if (status)
-			printf(CMD_MSG_FAIL, "firewall del bulk");
-
-		free(port_ids);
-		free(priorities);
-		free(keys);
-		return;
-	} /* firewall del bulk */
-
-	/* firewall del default */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "del") == 0) &&
-		(strcmp(tokens[1], "default") == 0)) {
-		if (n_tokens != 2) {
-			printf(CMD_MSG_MISMATCH_ARGS, "firewall del default");
-			return;
-		}
-
-		status = app_pipeline_firewall_delete_default_rule(app,
-			params->pipeline_id);
-		if (status)
-			printf(CMD_MSG_FAIL, "firewall del default");
-
-		return;
-
-	} /* firewall del default */
-
-	/* firewall ls */
-	if ((n_tokens >= 1) && (strcmp(tokens[0], "ls") == 0)) {
-		if (n_tokens != 1) {
-			printf(CMD_MSG_MISMATCH_ARGS, "firewall ls");
-			return;
-		}
-
-		status = app_pipeline_firewall_ls(app, params->pipeline_id);
-		if (status)
-			printf(CMD_MSG_FAIL, "firewall ls");
-
-		return;
-	} /* firewall ls */
-
-	printf(CMD_MSG_MISMATCH_ARGS, "firewall");
-}
-
-static cmdline_parse_token_string_t cmd_firewall_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_result, p_string, "p");
-
-static cmdline_parse_token_num_t cmd_firewall_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_result, pipeline_id, UINT32);
-
-static cmdline_parse_token_string_t cmd_firewall_firewall_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_result, firewall_string,
-	"firewall");
-
-static cmdline_parse_token_string_t cmd_firewall_multi_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_result, multi_string,
-	TOKEN_STRING_MULTI);
-
-static cmdline_parse_inst_t cmd_firewall = {
-	.f = cmd_firewall_parsed,
-	.data = NULL,
-	.help_str =	"firewall add / add bulk / add default / del / del bulk"
-		" / del default / ls",
-	.tokens = {
-		(void *) &cmd_firewall_p_string,
-		(void *) &cmd_firewall_pipeline_id,
-		(void *) &cmd_firewall_firewall_string,
-		(void *) &cmd_firewall_multi_string,
-		NULL,
-	},
-};
-
-static cmdline_parse_ctx_t pipeline_cmds[] = {
-	(cmdline_parse_inst_t *) &cmd_firewall,
-	NULL,
-};
-
-static struct pipeline_fe_ops pipeline_firewall_fe_ops = {
-	.f_init = app_pipeline_firewall_init,
-	.f_post_init = NULL,
-	.f_free = app_pipeline_firewall_free,
-	.f_track = app_pipeline_track_default,
-	.cmds = pipeline_cmds,
-};
-
-struct pipeline_type pipeline_firewall = {
-	.name = "FIREWALL",
-	.be_ops = &pipeline_firewall_be_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
deleted file mode 100644
index 27304b0..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_firewall.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#ifndef __INCLUDE_PIPELINE_FIREWALL_H__
-#define __INCLUDE_PIPELINE_FIREWALL_H__
-
-#include "pipeline.h"
-#include "pipeline_firewall_be.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_bulk(struct app_params *app,
-		uint32_t pipeline_id,
-		struct pipeline_firewall_key *keys,
-		uint32_t n_keys,
-		uint32_t *priorities,
-		uint32_t *port_ids);
-
-int
-app_pipeline_firewall_delete_bulk(struct app_params *app,
-	uint32_t pipeline_id,
-	struct pipeline_firewall_key *keys,
-	uint32_t n_keys);
-
-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);
-
-#ifndef APP_PIPELINE_FIREWALL_MAX_RULES_IN_FILE
-#define APP_PIPELINE_FIREWALL_MAX_RULES_IN_FILE		65536
-#endif
-
-int
-app_pipeline_firewall_load_file(char *filename,
-	struct pipeline_firewall_key *keys,
-	uint32_t *priorities,
-	uint32_t *port_ids,
-	uint32_t *n_keys,
-	uint32_t *line);
-
-extern struct pipeline_type pipeline_firewall;
-
-#endif
diff --git a/examples/ip_pipeline/pipeline/pipeline_firewall_be.c b/examples/ip_pipeline/pipeline/pipeline_firewall_be.c
deleted file mode 100644
index bd5e1b2..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_firewall_be.c
+++ /dev/null
@@ -1,856 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2016 Intel Corporation
- */
-
-#include <string.h>
-
-#include <rte_common.h>
-#include <rte_malloc.h>
-#include <rte_ether.h>
-#include <rte_ip.h>
-#include <rte_tcp.h>
-#include <rte_byteorder.h>
-#include <rte_table_acl.h>
-
-#include "pipeline_firewall_be.h"
-#include "parser.h"
-
-struct pipeline_firewall {
-	struct pipeline p;
-	pipeline_msg_req_handler custom_handlers[PIPELINE_FIREWALL_MSG_REQS];
-
-	uint32_t n_rules;
-	uint32_t n_rule_fields;
-	struct rte_acl_field_def *field_format;
-	uint32_t field_format_size;
-} __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_bulk_handler(struct pipeline *p, void *msg);
-
-static void *
-pipeline_firewall_msg_req_del_bulk_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_BULK] =
-		pipeline_firewall_msg_req_add_bulk_handler,
-	[PIPELINE_FIREWALL_MSG_REQ_DEL_BULK] =
-		pipeline_firewall_msg_req_del_bulk_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,
-};
-
-/*
- * Firewall table
- */
-struct firewall_table_entry {
-	struct rte_pipeline_table_entry head;
-};
-
-static struct rte_acl_field_def field_format_ipv4[] = {
-	/* Protocol */
-	[0] = {
-		.type = RTE_ACL_FIELD_TYPE_BITMASK,
-		.size = sizeof(uint8_t),
-		.field_index = 0,
-		.input_index = 0,
-		.offset = sizeof(struct ether_hdr) +
-			offsetof(struct ipv4_hdr, next_proto_id),
-	},
-
-	/* Source IP address (IPv4) */
-	[1] = {
-		.type = RTE_ACL_FIELD_TYPE_MASK,
-		.size = sizeof(uint32_t),
-		.field_index = 1,
-		.input_index = 1,
-		.offset = sizeof(struct ether_hdr) +
-			offsetof(struct ipv4_hdr, src_addr),
-	},
-
-	/* Destination IP address (IPv4) */
-	[2] = {
-		.type = RTE_ACL_FIELD_TYPE_MASK,
-		.size = sizeof(uint32_t),
-		.field_index = 2,
-		.input_index = 2,
-		.offset = sizeof(struct ether_hdr) +
-			offsetof(struct ipv4_hdr, dst_addr),
-	},
-
-	/* Source Port */
-	[3] = {
-		.type = RTE_ACL_FIELD_TYPE_RANGE,
-		.size = sizeof(uint16_t),
-		.field_index = 3,
-		.input_index = 3,
-		.offset = sizeof(struct ether_hdr) +
-			sizeof(struct ipv4_hdr) +
-			offsetof(struct tcp_hdr, src_port),
-	},
-
-	/* Destination Port */
-	[4] = {
-		.type = RTE_ACL_FIELD_TYPE_RANGE,
-		.size = sizeof(uint16_t),
-		.field_index = 4,
-		.input_index = 3,
-		.offset = sizeof(struct ether_hdr) +
-			sizeof(struct ipv4_hdr) +
-			offsetof(struct tcp_hdr, dst_port),
-	},
-};
-
-#define SIZEOF_VLAN_HDR                          4
-
-static struct rte_acl_field_def field_format_vlan_ipv4[] = {
-	/* Protocol */
-	[0] = {
-		.type = RTE_ACL_FIELD_TYPE_BITMASK,
-		.size = sizeof(uint8_t),
-		.field_index = 0,
-		.input_index = 0,
-		.offset = sizeof(struct ether_hdr) +
-			SIZEOF_VLAN_HDR +
-			offsetof(struct ipv4_hdr, next_proto_id),
-	},
-
-	/* Source IP address (IPv4) */
-	[1] = {
-		.type = RTE_ACL_FIELD_TYPE_MASK,
-		.size = sizeof(uint32_t),
-		.field_index = 1,
-		.input_index = 1,
-		.offset = sizeof(struct ether_hdr) +
-			SIZEOF_VLAN_HDR +
-			offsetof(struct ipv4_hdr, src_addr),
-	},
-
-	/* Destination IP address (IPv4) */
-	[2] = {
-		.type = RTE_ACL_FIELD_TYPE_MASK,
-		.size = sizeof(uint32_t),
-		.field_index = 2,
-		.input_index = 2,
-		.offset = sizeof(struct ether_hdr) +
-			SIZEOF_VLAN_HDR +
-			offsetof(struct ipv4_hdr, dst_addr),
-	},
-
-	/* Source Port */
-	[3] = {
-		.type = RTE_ACL_FIELD_TYPE_RANGE,
-		.size = sizeof(uint16_t),
-		.field_index = 3,
-		.input_index = 3,
-		.offset = sizeof(struct ether_hdr) +
-			SIZEOF_VLAN_HDR +
-			sizeof(struct ipv4_hdr) +
-			offsetof(struct tcp_hdr, src_port),
-	},
-
-	/* Destination Port */
-	[4] = {
-		.type = RTE_ACL_FIELD_TYPE_RANGE,
-		.size = sizeof(uint16_t),
-		.field_index = 4,
-		.input_index = 3,
-		.offset = sizeof(struct ether_hdr) +
-			SIZEOF_VLAN_HDR +
-			sizeof(struct ipv4_hdr) +
-			offsetof(struct tcp_hdr, dst_port),
-	},
-};
-
-#define SIZEOF_QINQ_HEADER                       8
-
-static struct rte_acl_field_def field_format_qinq_ipv4[] = {
-	/* Protocol */
-	[0] = {
-		.type = RTE_ACL_FIELD_TYPE_BITMASK,
-		.size = sizeof(uint8_t),
-		.field_index = 0,
-		.input_index = 0,
-		.offset = sizeof(struct ether_hdr) +
-			SIZEOF_QINQ_HEADER +
-			offsetof(struct ipv4_hdr, next_proto_id),
-	},
-
-	/* Source IP address (IPv4) */
-	[1] = {
-		.type = RTE_ACL_FIELD_TYPE_MASK,
-		.size = sizeof(uint32_t),
-		.field_index = 1,
-		.input_index = 1,
-		.offset = sizeof(struct ether_hdr) +
-			SIZEOF_QINQ_HEADER +
-			offsetof(struct ipv4_hdr, src_addr),
-	},
-
-	/* Destination IP address (IPv4) */
-	[2] = {
-		.type = RTE_ACL_FIELD_TYPE_MASK,
-		.size = sizeof(uint32_t),
-		.field_index = 2,
-		.input_index = 2,
-		.offset = sizeof(struct ether_hdr) +
-			SIZEOF_QINQ_HEADER +
-			offsetof(struct ipv4_hdr, dst_addr),
-	},
-
-	/* Source Port */
-	[3] = {
-		.type = RTE_ACL_FIELD_TYPE_RANGE,
-		.size = sizeof(uint16_t),
-		.field_index = 3,
-		.input_index = 3,
-		.offset = sizeof(struct ether_hdr) +
-			SIZEOF_QINQ_HEADER +
-			sizeof(struct ipv4_hdr) +
-			offsetof(struct tcp_hdr, src_port),
-	},
-
-	/* Destination Port */
-	[4] = {
-		.type = RTE_ACL_FIELD_TYPE_RANGE,
-		.size = sizeof(uint16_t),
-		.field_index = 4,
-		.input_index = 3,
-		.offset = sizeof(struct ether_hdr) +
-			SIZEOF_QINQ_HEADER +
-			sizeof(struct ipv4_hdr) +
-			offsetof(struct tcp_hdr, dst_port),
-	},
-};
-
-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;
-
-	/* defaults */
-	p->n_rules = 4 * 1024;
-	p->n_rule_fields = RTE_DIM(field_format_ipv4);
-	p->field_format = field_format_ipv4;
-	p->field_format_size = sizeof(field_format_ipv4);
-
-	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) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				n_rules_present == 0, params->name,
-				arg_name);
-			n_rules_present = 1;
-
-			status = parser_read_uint32(&p->n_rules,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-			continue;
-		}
-
-		if (strcmp(arg_name, "pkt_type") == 0) {
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				pkt_type_present == 0, params->name,
-				arg_name);
-			pkt_type_present = 1;
-
-			/* ipv4 */
-			if (strcmp(arg_value, "ipv4") == 0) {
-				p->n_rule_fields = RTE_DIM(field_format_ipv4);
-				p->field_format = field_format_ipv4;
-				p->field_format_size =
-					sizeof(field_format_ipv4);
-				continue;
-			}
-
-			/* vlan_ipv4 */
-			if (strcmp(arg_value, "vlan_ipv4") == 0) {
-				p->n_rule_fields =
-					RTE_DIM(field_format_vlan_ipv4);
-				p->field_format = field_format_vlan_ipv4;
-				p->field_format_size =
-					sizeof(field_format_vlan_ipv4);
-				continue;
-			}
-
-			/* qinq_ipv4 */
-			if (strcmp(arg_value, "qinq_ipv4") == 0) {
-				p->n_rule_fields =
-					RTE_DIM(field_format_qinq_ipv4);
-				p->field_format = field_format_qinq_ipv4;
-				p->field_format_size =
-					sizeof(field_format_qinq_ipv4);
-				continue;
-			}
-
-			/* other */
-			PIPELINE_PARSE_ERR_INV_VAL(0, params->name,
-				arg_name, arg_value);
-		}
-
-		/* other */
-		PIPELINE_PARSE_ERR_INV_ENT(0, params->name, arg_name);
-	}
-
-	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);
-	p->log_level = params->log_level;
-
-	PLOG(p, HIGH, "Firewall");
-
-	/* 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,
-			.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 = params->name,
-			.n_rules = p_fw->n_rules,
-			.n_rule_fields = p_fw->n_rule_fields,
-		};
-
-		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 =
-					sizeof(struct firewall_table_entry) -
-					sizeof(struct rte_pipeline_table_entry),
-			};
-
-		int status;
-
-		memcpy(table_acl_params.field_format,
-			p_fw->field_format,
-			p_fw->field_format_size);
-
-		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_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 firewall_table_entry entry = {
-		.head = {
-			.action = RTE_PIPELINE_ACTION_PORT,
-			{.port_id = p->port_out_id[req->port_id]},
-		},
-	};
-
-	memset(&params, 0, sizeof(params));
-
-	switch (req->key.type) {
-	case PIPELINE_FIREWALL_IPV4_5TUPLE:
-		params.priority = req->priority;
-		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,
-		(struct rte_pipeline_table_entry *) &entry,
-		&rsp->key_found,
-		(struct rte_pipeline_table_entry **) &rsp->entry_ptr);
-
-	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;
-
-	memset(&params, 0, sizeof(params));
-
-	switch (req->key.type) {
-	case PIPELINE_FIREWALL_IPV4_5TUPLE:
-		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);
-
-	return rsp;
-}
-
-static void *
-pipeline_firewall_msg_req_add_bulk_handler(struct pipeline *p, void *msg)
-{
-	struct pipeline_firewall_add_bulk_msg_req *req = msg;
-	struct pipeline_firewall_add_bulk_msg_rsp *rsp = msg;
-
-	struct rte_table_acl_rule_add_params *params[req->n_keys];
-	struct firewall_table_entry *entries[req->n_keys];
-
-	uint32_t i, n_keys;
-
-	n_keys = req->n_keys;
-
-	for (i = 0; i < n_keys; i++) {
-		entries[i] = rte_zmalloc(NULL,
-				sizeof(struct firewall_table_entry),
-				RTE_CACHE_LINE_SIZE);
-		if (entries[i] == NULL) {
-			rsp->status = -1;
-			return rsp;
-		}
-
-		params[i] = rte_zmalloc(NULL,
-				sizeof(struct rte_table_acl_rule_add_params),
-				RTE_CACHE_LINE_SIZE);
-		if (params[i] == NULL) {
-			rsp->status = -1;
-			return rsp;
-		}
-
-		entries[i]->head.action = RTE_PIPELINE_ACTION_PORT;
-		entries[i]->head.port_id = p->port_out_id[req->port_ids[i]];
-
-		switch (req->keys[i].type) {
-		case PIPELINE_FIREWALL_IPV4_5TUPLE:
-			params[i]->priority = req->priorities[i];
-			params[i]->field_value[0].value.u8 =
-				req->keys[i].key.ipv4_5tuple.proto;
-			params[i]->field_value[0].mask_range.u8 =
-				req->keys[i].key.ipv4_5tuple.proto_mask;
-			params[i]->field_value[1].value.u32 =
-				req->keys[i].key.ipv4_5tuple.src_ip;
-			params[i]->field_value[1].mask_range.u32 =
-				req->keys[i].key.ipv4_5tuple.src_ip_mask;
-			params[i]->field_value[2].value.u32 =
-				req->keys[i].key.ipv4_5tuple.dst_ip;
-			params[i]->field_value[2].mask_range.u32 =
-				req->keys[i].key.ipv4_5tuple.dst_ip_mask;
-			params[i]->field_value[3].value.u16 =
-				req->keys[i].key.ipv4_5tuple.src_port_from;
-			params[i]->field_value[3].mask_range.u16 =
-				req->keys[i].key.ipv4_5tuple.src_port_to;
-			params[i]->field_value[4].value.u16 =
-				req->keys[i].key.ipv4_5tuple.dst_port_from;
-			params[i]->field_value[4].mask_range.u16 =
-				req->keys[i].key.ipv4_5tuple.dst_port_to;
-			break;
-
-		default:
-			rsp->status = -1; /* Error */
-
-			for (i = 0; i < n_keys; i++) {
-				rte_free(entries[i]);
-				rte_free(params[i]);
-			}
-
-			return rsp;
-		}
-	}
-
-	rsp->status = rte_pipeline_table_entry_add_bulk(p->p, p->table_id[0],
-			(void *)params, (struct rte_pipeline_table_entry **)entries,
-			n_keys, req->keys_found,
-			(struct rte_pipeline_table_entry **)req->entries_ptr);
-
-	for (i = 0; i < n_keys; i++) {
-		rte_free(entries[i]);
-		rte_free(params[i]);
-	}
-
-	return rsp;
-}
-
-static void *
-pipeline_firewall_msg_req_del_bulk_handler(struct pipeline *p, void *msg)
-{
-	struct pipeline_firewall_del_bulk_msg_req *req = msg;
-	struct pipeline_firewall_del_bulk_msg_rsp *rsp = msg;
-
-	struct rte_table_acl_rule_delete_params *params[req->n_keys];
-
-	uint32_t i, n_keys;
-
-	n_keys = req->n_keys;
-
-	for (i = 0; i < n_keys; i++) {
-		params[i] = rte_zmalloc(NULL,
-				sizeof(struct rte_table_acl_rule_delete_params),
-				RTE_CACHE_LINE_SIZE);
-		if (params[i] == NULL) {
-			rsp->status = -1;
-			return rsp;
-		}
-
-		switch (req->keys[i].type) {
-		case PIPELINE_FIREWALL_IPV4_5TUPLE:
-			params[i]->field_value[0].value.u8 =
-				req->keys[i].key.ipv4_5tuple.proto;
-			params[i]->field_value[0].mask_range.u8 =
-				req->keys[i].key.ipv4_5tuple.proto_mask;
-			params[i]->field_value[1].value.u32 =
-				req->keys[i].key.ipv4_5tuple.src_ip;
-			params[i]->field_value[1].mask_range.u32 =
-				req->keys[i].key.ipv4_5tuple.src_ip_mask;
-			params[i]->field_value[2].value.u32 =
-				req->keys[i].key.ipv4_5tuple.dst_ip;
-			params[i]->field_value[2].mask_range.u32 =
-				req->keys[i].key.ipv4_5tuple.dst_ip_mask;
-			params[i]->field_value[3].value.u16 =
-				req->keys[i].key.ipv4_5tuple.src_port_from;
-			params[i]->field_value[3].mask_range.u16 =
-				req->keys[i].key.ipv4_5tuple.src_port_to;
-			params[i]->field_value[4].value.u16 =
-				req->keys[i].key.ipv4_5tuple.dst_port_from;
-			params[i]->field_value[4].mask_range.u16 =
-				req->keys[i].key.ipv4_5tuple.dst_port_to;
-			break;
-
-		default:
-			rsp->status = -1; /* Error */
-
-			for (i = 0; i < n_keys; i++)
-				rte_free(params[i]);
-
-			return rsp;
-		}
-	}
-
-	rsp->status = rte_pipeline_table_entry_delete_bulk(p->p, p->table_id[0],
-			(void **)&params, n_keys, req->keys_found, NULL);
-
-	for (i = 0; i < n_keys; i++)
-		rte_free(params[i]);
-
-	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 firewall_table_entry default_entry = {
-		.head = {
-			.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],
-		(struct rte_pipeline_table_entry *) &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_be_ops pipeline_firewall_be_ops = {
-	.f_init = pipeline_firewall_init,
-	.f_free = pipeline_firewall_free,
-	.f_run = NULL,
-	.f_timer = pipeline_firewall_timer,
-};
diff --git a/examples/ip_pipeline/pipeline/pipeline_firewall_be.h b/examples/ip_pipeline/pipeline/pipeline_firewall_be.h
deleted file mode 100644
index 246f0a6..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_firewall_be.h
+++ /dev/null
@@ -1,147 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#ifndef __INCLUDE_PIPELINE_FIREWALL_BE_H__
-#define __INCLUDE_PIPELINE_FIREWALL_BE_H__
-
-#include "pipeline_common_be.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_BULK,
-	PIPELINE_FIREWALL_MSG_REQ_DEL_BULK,
-	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 BULK
- */
-struct pipeline_firewall_add_bulk_msg_req {
-	enum pipeline_msg_req_type type;
-	enum pipeline_firewall_msg_req_type subtype;
-
-	struct pipeline_firewall_key *keys;
-	uint32_t n_keys;
-
-	uint32_t *priorities;
-	uint32_t *port_ids;
-	int *keys_found;
-	void **entries_ptr;
-};
-struct pipeline_firewall_add_bulk_msg_rsp {
-	int status;
-};
-
-/*
- * MSG DEL BULK
- */
-struct pipeline_firewall_del_bulk_msg_req {
-	enum pipeline_msg_req_type type;
-	enum pipeline_firewall_msg_req_type subtype;
-
-	/* key */
-	struct pipeline_firewall_key *keys;
-	uint32_t n_keys;
-	int *keys_found;
-};
-
-struct pipeline_firewall_del_bulk_msg_rsp {
-	int status;
-};
-
-/*
- * 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_be_ops pipeline_firewall_be_ops;
-
-#endif
-- 
2.9.3

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

* [dpdk-dev] [PATCH v3 15/44] ip_pipeline: remove master pipeline
  2018-03-16 17:58       ` [dpdk-dev] [PATCH v3 00/44] ip_pipeline: refactoring Jasvinder Singh
                           ` (13 preceding siblings ...)
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 14/44] ip_pipeline: remove firewall pipeline Jasvinder Singh
@ 2018-03-16 17:58         ` Jasvinder Singh
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 16/44] ip_pipeline: remove config Jasvinder Singh
                           ` (28 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-16 17:58 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

remove master pipeline.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/Makefile                      |    6 -
 examples/ip_pipeline/app.h                         |   12 -
 examples/ip_pipeline/{pipeline => }/hash_func.h    |    3 +-
 .../ip_pipeline/{pipeline => }/hash_func_arm64.h   |    0
 examples/ip_pipeline/init.c                        |  574 --------
 examples/ip_pipeline/meson.build                   |    9 +-
 .../ip_pipeline/pipeline/pipeline_actions_common.h |  202 ---
 examples/ip_pipeline/pipeline/pipeline_common_be.c |  176 ---
 examples/ip_pipeline/pipeline/pipeline_common_be.h |  134 --
 examples/ip_pipeline/pipeline/pipeline_common_fe.c | 1455 --------------------
 examples/ip_pipeline/pipeline/pipeline_common_fe.h |  231 ----
 examples/ip_pipeline/pipeline/pipeline_master.c    |   20 -
 examples/ip_pipeline/pipeline/pipeline_master.h    |   12 -
 examples/ip_pipeline/pipeline/pipeline_master_be.c |  141 --
 examples/ip_pipeline/pipeline/pipeline_master_be.h |   12 -
 examples/ip_pipeline/thread.c                      |   53 -
 examples/ip_pipeline/thread_fe.c                   |  457 ------
 examples/ip_pipeline/thread_fe.h                   |   72 -
 18 files changed, 3 insertions(+), 3566 deletions(-)
 rename examples/ip_pipeline/{pipeline => }/hash_func.h (99%)
 rename examples/ip_pipeline/{pipeline => }/hash_func_arm64.h (100%)
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_actions_common.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_common_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_common_be.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_common_fe.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_common_fe.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_master.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_master.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_master_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_master_be.h
 delete mode 100644 examples/ip_pipeline/thread_fe.c
 delete mode 100644 examples/ip_pipeline/thread_fe.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index ae76edc..8ba7887 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -12,14 +12,8 @@ SRCS-y += config_parse_tm.c
 SRCS-y += config_check.c
 SRCS-y += init.c
 SRCS-y += thread.c
-SRCS-y += thread_fe.c
 SRCS-y += cpu_core_map.c
 
-SRCS-y += pipeline_common_be.c
-SRCS-y += pipeline_common_fe.c
-SRCS-y += pipeline_master_be.c
-SRCS-y += pipeline_master.c
-
 # Build using pkg-config variables if possible
 $(shell pkg-config --exists libdpdk)
 ifeq ($(.SHELLSTATUS),0)
diff --git a/examples/ip_pipeline/app.h b/examples/ip_pipeline/app.h
index 907d4e7..dadaf2b 100644
--- a/examples/ip_pipeline/app.h
+++ b/examples/ip_pipeline/app.h
@@ -1359,10 +1359,6 @@ app_core_build_core_mask_string(struct app_params *app, char *mask_buffer)
 	}
 }
 
-void app_pipeline_params_get(struct app_params *app,
-	struct app_pipeline_params *p_in,
-	struct pipeline_params *p_out);
-
 int app_config_init(struct app_params *app);
 
 int app_config_args(struct app_params *app,
@@ -1382,16 +1378,8 @@ int app_config_check(struct app_params *app);
 
 int app_init(struct app_params *app);
 
-int app_post_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);
 
diff --git a/examples/ip_pipeline/pipeline/hash_func.h b/examples/ip_pipeline/hash_func.h
similarity index 99%
rename from examples/ip_pipeline/pipeline/hash_func.h
rename to examples/ip_pipeline/hash_func.h
index 806ac22..f1b9d94 100644
--- a/examples/ip_pipeline/pipeline/hash_func.h
+++ b/examples/ip_pipeline/hash_func.h
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
+ * Copyright(c) 2010-2018 Intel Corporation
  */
+
 #ifndef __INCLUDE_HASH_FUNC_H__
 #define __INCLUDE_HASH_FUNC_H__
 
diff --git a/examples/ip_pipeline/pipeline/hash_func_arm64.h b/examples/ip_pipeline/hash_func_arm64.h
similarity index 100%
rename from examples/ip_pipeline/pipeline/hash_func_arm64.h
rename to examples/ip_pipeline/hash_func_arm64.h
diff --git a/examples/ip_pipeline/init.c b/examples/ip_pipeline/init.c
index f848310..9430809 100644
--- a/examples/ip_pipeline/init.c
+++ b/examples/ip_pipeline/init.c
@@ -24,9 +24,6 @@
 
 #include "app.h"
 #include "pipeline.h"
-#include "pipeline_common_fe.h"
-#include "pipeline_master.h"
-#include "thread_fe.h"
 
 #define APP_NAME_SIZE	32
 
@@ -1328,478 +1325,6 @@ app_init_msgq(struct app_params *app)
 	}
 }
 
-void app_pipeline_params_get(struct app_params *app,
-	struct app_pipeline_params *p_in,
-	struct pipeline_params *p_out)
-{
-	uint32_t i;
-
-	snprintf(p_out->name, PIPELINE_NAME_SIZE, "%s", p_in->name);
-
-	snprintf(p_out->type, PIPELINE_TYPE_SIZE, "%s", p_in->type);
-
-	p_out->socket_id = (int) p_in->socket_id;
-
-	p_out->log_level = app->log_level;
-
-	/* 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];
-
-		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%" SCNu32 ".%" SCNu32,
-				&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:
-		{
-			struct app_pktq_swq_params *swq_params = &app->swq_params[in->id];
-
-			if ((swq_params->ipv4_frag == 0) && (swq_params->ipv6_frag == 0)) {
-				if (app_swq_get_readers(app, swq_params) == 1) {
-					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;
-				} else {
-					out->type = PIPELINE_PORT_IN_RING_MULTI_READER;
-					out->params.ring_multi.ring = app->swq[in->id];
-					out->burst_size = swq_params->burst_read;
-				}
-			} else {
-				if (swq_params->ipv4_frag == 1) {
-					struct rte_port_ring_reader_ipv4_frag_params *params =
-						&out->params.ring_ipv4_frag;
-
-					out->type = PIPELINE_PORT_IN_RING_READER_IPV4_FRAG;
-					params->ring = app->swq[in->id];
-					params->mtu = swq_params->mtu;
-					params->metadata_size = swq_params->metadata_size;
-					params->pool_direct =
-						app->mempool[swq_params->mempool_direct_id];
-					params->pool_indirect =
-						app->mempool[swq_params->mempool_indirect_id];
-					out->burst_size = swq_params->burst_read;
-				} else {
-					struct rte_port_ring_reader_ipv6_frag_params *params =
-						&out->params.ring_ipv6_frag;
-
-					out->type = PIPELINE_PORT_IN_RING_READER_IPV6_FRAG;
-					params->ring = app->swq[in->id];
-					params->mtu = swq_params->mtu;
-					params->metadata_size = swq_params->metadata_size;
-					params->pool_direct =
-						app->mempool[swq_params->mempool_direct_id];
-					params->pool_indirect =
-						app->mempool[swq_params->mempool_indirect_id];
-					out->burst_size = swq_params->burst_read;
-				}
-			}
-			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;
-		}
-#ifdef RTE_EXEC_ENV_LINUXAPP
-		case APP_PKTQ_IN_TAP:
-		{
-			struct app_pktq_tap_params *tap_params =
-				&app->tap_params[in->id];
-			struct app_mempool_params *mempool_params =
-				&app->mempool_params[tap_params->mempool_id];
-			struct rte_mempool *mempool =
-				app->mempool[tap_params->mempool_id];
-
-			out->type = PIPELINE_PORT_IN_FD_READER;
-			out->params.fd.fd = app->tap[in->id];
-			out->params.fd.mtu = mempool_params->buffer_size;
-			out->params.fd.mempool = mempool;
-			out->burst_size = app->tap_params[in->id].burst_read;
-			break;
-		}
-#endif
-#ifdef RTE_LIBRTE_KNI
-		case APP_PKTQ_IN_KNI:
-		{
-			out->type = PIPELINE_PORT_IN_KNI_READER;
-			out->params.kni.kni = app->kni[in->id];
-			out->burst_size = app->kni_params[in->id].burst_read;
-			break;
-		}
-#endif /* RTE_LIBRTE_KNI */
-		case APP_PKTQ_IN_SOURCE:
-		{
-			uint32_t mempool_id =
-				app->source_params[in->id].mempool_id;
-
-			out->type = PIPELINE_PORT_IN_SOURCE;
-			out->params.source.mempool = app->mempool[mempool_id];
-			out->burst_size = app->source_params[in->id].burst;
-			out->params.source.file_name =
-				app->source_params[in->id].file_name;
-			out->params.source.n_bytes_per_pkt =
-				app->source_params[in->id].n_bytes_per_pkt;
-			break;
-		}
-		default:
-			break;
-		}
-	}
-
-	/* 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%" SCNu32 ".%" SCNu32,
-				&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:
-		{
-			struct app_pktq_swq_params *swq_params = &app->swq_params[in->id];
-
-			if ((swq_params->ipv4_ras == 0) && (swq_params->ipv6_ras == 0)) {
-				if (app_swq_get_writers(app, swq_params) == 1) {
-					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;
-					}
-				} else {
-					if (swq_params->dropless == 0) {
-						struct rte_port_ring_multi_writer_params *params =
-							&out->params.ring_multi;
-
-						out->type = PIPELINE_PORT_OUT_RING_MULTI_WRITER;
-						params->ring = app->swq[in->id];
-						params->tx_burst_sz = swq_params->burst_write;
-					} else {
-						struct rte_port_ring_multi_writer_nodrop_params
-							*params = &out->params.ring_multi_nodrop;
-
-						out->type = PIPELINE_PORT_OUT_RING_MULTI_WRITER_NODROP;
-						params->ring = app->swq[in->id];
-						params->tx_burst_sz = swq_params->burst_write;
-						params->n_retries = swq_params->n_retries;
-					}
-				}
-			} else {
-				if (swq_params->ipv4_ras == 1) {
-					struct rte_port_ring_writer_ipv4_ras_params *params =
-						&out->params.ring_ipv4_ras;
-
-					out->type = PIPELINE_PORT_OUT_RING_WRITER_IPV4_RAS;
-					params->ring = app->swq[in->id];
-					params->tx_burst_sz = swq_params->burst_write;
-				} else {
-					struct rte_port_ring_writer_ipv6_ras_params *params =
-						&out->params.ring_ipv6_ras;
-
-					out->type = PIPELINE_PORT_OUT_RING_WRITER_IPV6_RAS;
-					params->ring = app->swq[in->id];
-					params->tx_burst_sz = swq_params->burst_write;
-				}
-			}
-			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;
-		}
-#ifdef RTE_EXEC_ENV_LINUXAPP
-		case APP_PKTQ_OUT_TAP:
-		{
-			struct rte_port_fd_writer_params *params =
-				&out->params.fd;
-
-			out->type = PIPELINE_PORT_OUT_FD_WRITER;
-			params->fd = app->tap[in->id];
-			params->tx_burst_sz =
-				app->tap_params[in->id].burst_write;
-			break;
-		}
-#endif
-#ifdef RTE_LIBRTE_KNI
-		case APP_PKTQ_OUT_KNI:
-		{
-			struct app_pktq_kni_params *p_kni =
-				&app->kni_params[in->id];
-
-			if (p_kni->dropless == 0) {
-				struct rte_port_kni_writer_params *params =
-					&out->params.kni;
-
-				out->type = PIPELINE_PORT_OUT_KNI_WRITER;
-				params->kni = app->kni[in->id];
-				params->tx_burst_sz =
-					app->kni_params[in->id].burst_write;
-			} else {
-				struct rte_port_kni_writer_nodrop_params
-					*params = &out->params.kni_nodrop;
-
-				out->type = PIPELINE_PORT_OUT_KNI_WRITER_NODROP;
-				params->kni = app->kni[in->id];
-				params->tx_burst_sz =
-					app->kni_params[in->id].burst_write;
-				params->n_retries =
-					app->kni_params[in->id].n_retries;
-			}
-			break;
-		}
-#endif /* RTE_LIBRTE_KNI */
-		case APP_PKTQ_OUT_SINK:
-		{
-			out->type = PIPELINE_PORT_OUT_SINK;
-			out->params.sink.file_name =
-				app->sink_params[in->id].file_name;
-			out->params.sink.max_n_pkts =
-				app->sink_params[in->id].
-				n_pkts_to_dump;
-
-			break;
-		}
-		default:
-			break;
-		}
-	}
-
-	/* msgq */
-	p_out->n_msgq = p_in->n_msgq_in;
-
-	for (i = 0; i < p_in->n_msgq_in; i++)
-		p_out->msgq_in[i] = app->msgq[p_in->msgq_in[i]];
-
-	for (i = 0; i < p_in->n_msgq_out; i++)
-		p_out->msgq_out[i] = app->msgq[p_in->msgq_out[i]];
-
-	/* 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];
-	}
-}
-
-static void
-app_init_pipelines(struct app_params *app)
-{
-	uint32_t p_id;
-
-	for (p_id = 0; p_id < app->n_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;
-
-		APP_LOG(app, HIGH, "Initializing %s ...", 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->be_ops->f_init) {
-			data->be = ptype->be_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->ptype = ptype;
-
-		data->timer_period = (rte_get_tsc_hz() *
-			params->timer_period) / 1000;
-	}
-}
-
-static void
-app_post_init_pipelines(struct app_params *app)
-{
-	uint32_t p_id;
-
-	for (p_id = 0; p_id < app->n_pipelines; p_id++) {
-		struct app_pipeline_params *params =
-			&app->pipeline_params[p_id];
-		struct app_pipeline_data *data = &app->pipeline_data[p_id];
-		int status;
-
-		if (data->ptype->fe_ops->f_post_init == NULL)
-			continue;
-
-		status = data->ptype->fe_ops->f_post_init(data->fe);
-		if (status)
-			rte_panic("Pipeline instance \"%s\" front-end "
-				"post-init error\n", params->name);
-	}
-}
-
-static void
-app_init_threads(struct app_params *app)
-{
-	uint64_t time = rte_get_tsc_cycles();
-	uint32_t p_id;
-
-	for (p_id = 0; p_id < app->n_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;
-
-		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%" PRIu32 "c%" PRIu32 "%s\n",
-				params->socket_id,
-				params->core_id,
-				(params->hyper_th_id) ? "h" : "");
-
-		t = &app->thread_data[lcore_id];
-
-		t->timer_period = (rte_get_tsc_hz() * APP_THREAD_TIMER_PERIOD) / 1000;
-		t->thread_req_deadline = time + t->timer_period;
-
-		t->headroom_cycles = 0;
-		t->headroom_time = rte_get_tsc_cycles();
-		t->headroom_ratio = 0.0;
-
-		t->msgq_in = app_thread_msgq_in_get(app,
-				params->socket_id,
-				params->core_id,
-				params->hyper_th_id);
-		if (t->msgq_in == NULL)
-			rte_panic("Init error: Cannot find MSGQ_IN for thread %" PRId32,
-				lcore_id);
-
-		t->msgq_out = app_thread_msgq_out_get(app,
-				params->socket_id,
-				params->core_id,
-				params->hyper_th_id);
-		if (t->msgq_out == NULL)
-			rte_panic("Init error: Cannot find MSGQ_OUT for thread %" PRId32,
-				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->be_ops->f_run == NULL) ?
-			&t->regular[t->n_regular] :
-			&t->custom[t->n_custom];
-
-		p->pipeline_id = p_id;
-		p->be = data->be;
-		p->f_run = ptype->be_ops->f_run;
-		p->f_timer = ptype->be_ops->f_timer;
-		p->timer_period = data->timer_period;
-		p->deadline = time + data->timer_period;
-
-		data->enabled = 1;
-
-		if (ptype->be_ops->f_run == NULL)
-			t->n_regular++;
-		else
-			t->n_custom++;
-	}
-}
-
 int app_init(struct app_params *app)
 {
 	app_init_core_map(app);
@@ -1814,104 +1339,5 @@ int app_init(struct app_params *app)
 	app_init_kni(app);
 	app_init_msgq(app);
 
-	app_pipeline_common_cmd_push(app);
-	app_pipeline_thread_cmd_push(app);
-	app_pipeline_type_register(app, &pipeline_master);
-
-	app_init_pipelines(app);
-	app_init_threads(app);
-
 	return 0;
 }
-
-int app_post_init(struct app_params *app)
-{
-	app_post_init_pipelines(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)
-{
-	uint32_t n_cmds, i;
-
-	/* Check input arguments */
-	if ((app == NULL) ||
-		(ptype == NULL) ||
-		(ptype->name == NULL) ||
-		(strlen(ptype->name) == 0) ||
-		(ptype->be_ops->f_init == NULL) ||
-		(ptype->be_ops->f_timer == 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;
-}
-
-struct
-pipeline_type *app_pipeline_type_find(struct app_params *app, char *name)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_pipeline_types; i++)
-		if (strcmp(app->pipeline_type[i].name, name) == 0)
-			return &app->pipeline_type[i];
-
-	return NULL;
-}
diff --git a/examples/ip_pipeline/meson.build b/examples/ip_pipeline/meson.build
index 1fdfc48..be3f3e5 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -6,9 +6,7 @@
 # To build this example as a standalone application with an already-installed
 # DPDK instance, use 'make'
 
-deps += ['cfgfile', 'pipeline', 'bus_pci']
-allow_experimental_apis = true
-includes += include_directories('pipeline')
+deps += ['cfgfile', 'bus_pci']
 sources = files(
 	'config_check.c',
 	'config_parse.c',
@@ -18,9 +16,4 @@ sources = files(
 	'main.c',
 	'parser.c',
 	'thread.c',
-	'thread_fe.c',
-	'pipeline/pipeline_common_be.c',
-	'pipeline/pipeline_common_fe.c',
-	'pipeline/pipeline_master_be.c',
-	'pipeline/pipeline_master.c',
 )
diff --git a/examples/ip_pipeline/pipeline/pipeline_actions_common.h b/examples/ip_pipeline/pipeline/pipeline_actions_common.h
deleted file mode 100644
index 23f8836..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_actions_common.h
+++ /dev/null
@@ -1,202 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2016 Intel Corporation
- */
-#ifndef __INCLUDE_PIPELINE_ACTIONS_COMMON_H__
-#define __INCLUDE_PIPELINE_ACTIONS_COMMON_H__
-
-#include <stdint.h>
-
-#include <rte_common.h>
-#include <rte_cycles.h>
-#include <rte_mbuf.h>
-#include <rte_pipeline.h>
-
-#define PIPELINE_PORT_IN_AH(f_ah, f_pkt_work, f_pkt4_work)		\
-static int								\
-f_ah(									\
-	__rte_unused struct rte_pipeline *p,				\
-	struct rte_mbuf **pkts,						\
-	uint32_t n_pkts,						\
-	void *arg)							\
-{									\
-	uint32_t i;							\
-									\
-	for (i = 0; i < (n_pkts & (~0x3LLU)); i += 4)			\
-		f_pkt4_work(&pkts[i], arg);				\
-									\
-	for ( ; i < n_pkts; i++)					\
-		f_pkt_work(pkts[i], arg);				\
-									\
-	return 0;							\
-}
-
-#define PIPELINE_PORT_IN_AH_HIJACK_ALL(f_ah, f_pkt_work, f_pkt4_work) \
-static int								\
-f_ah(									\
-	struct rte_pipeline *p,				\
-	struct rte_mbuf **pkts,					\
-	uint32_t n_pkts,						\
-	void *arg)						\
-{									\
-	uint64_t pkt_mask = RTE_LEN2MASK(n_pkts, uint64_t);	\
-	uint32_t i;							\
-									\
-	rte_pipeline_ah_packet_hijack(p, pkt_mask);	\
-									\
-	for (i = 0; i < (n_pkts & (~0x3LLU)); i += 4)	\
-		f_pkt4_work(&pkts[i], arg);				\
-									\
-	for ( ; i < n_pkts; i++)				\
-		f_pkt_work(pkts[i], arg);			\
-									\
-	return 0;							\
-}
-
-#define PIPELINE_TABLE_AH_HIT(f_ah, f_pkt_work, f_pkt4_work)		\
-static int								\
-f_ah(									\
-	__rte_unused struct rte_pipeline *p,				\
-	struct rte_mbuf **pkts,						\
-	uint64_t pkts_in_mask,						\
-	struct rte_pipeline_table_entry **entries,			\
-	void *arg)							\
-{									\
-	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 & (~0x3LLU)); i += 4)		\
-			f_pkt4_work(&pkts[i], &entries[i], arg);	\
-									\
-		for ( ; i < n_pkts; i++)				\
-			f_pkt_work(pkts[i], entries[i], arg);		\
-	} else								\
-		for ( ; pkts_in_mask; ) {				\
-			uint32_t pos = __builtin_ctzll(pkts_in_mask);	\
-			uint64_t pkt_mask = 1LLU << pos;		\
-									\
-			pkts_in_mask &= ~pkt_mask;			\
-			f_pkt_work(pkts[pos], entries[pos], arg);	\
-		}							\
-									\
-	return 0;							\
-}
-
-#define PIPELINE_TABLE_AH_MISS(f_ah, f_pkt_work, f_pkt4_work)		\
-static int								\
-f_ah(									\
-	__rte_unused struct rte_pipeline *p,				\
-	struct rte_mbuf **pkts,						\
-	uint64_t pkts_in_mask,						\
-	struct rte_pipeline_table_entry *entry,				\
-	void *arg)							\
-{									\
-	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 & (~0x3LLU)); i += 4)		\
-			f_pkt4_work(&pkts[i], entry, arg);		\
-									\
-		for ( ; i < n_pkts; i++)				\
-			f_pkt_work(pkts[i], entry, arg);		\
-	} else								\
-		for ( ; pkts_in_mask; ) {				\
-			uint32_t pos = __builtin_ctzll(pkts_in_mask);	\
-			uint64_t pkt_mask = 1LLU << pos;		\
-									\
-			pkts_in_mask &= ~pkt_mask;			\
-			f_pkt_work(pkts[pos], entry, arg);		\
-		}							\
-									\
-	return 0;							\
-}
-
-#define PIPELINE_TABLE_AH_HIT_DROP_TIME(f_ah, f_pkt_work, f_pkt4_work)	\
-static int								\
-f_ah(									\
-	struct rte_pipeline *p,						\
-	struct rte_mbuf **pkts,						\
-	uint64_t pkts_mask,						\
-	struct rte_pipeline_table_entry **entries,			\
-	void *arg)							\
-{									\
-	uint64_t pkts_in_mask = pkts_mask;				\
-	uint64_t pkts_out_mask = pkts_mask;				\
-	uint64_t time = rte_rdtsc();					\
-									\
-	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 & (~0x3LLU)); i += 4) {		\
-			uint64_t mask = f_pkt4_work(&pkts[i],		\
-				&entries[i], arg, time);		\
-			pkts_out_mask ^= mask << i;			\
-		}							\
-									\
-		for ( ; i < n_pkts; i++) {				\
-			uint64_t mask = f_pkt_work(pkts[i],		\
-				entries[i], arg, time);			\
-			pkts_out_mask ^= mask << i;			\
-		}							\
-	} else								\
-		for ( ; pkts_in_mask; ) {				\
-			uint32_t pos = __builtin_ctzll(pkts_in_mask);	\
-			uint64_t pkt_mask = 1LLU << pos;		\
-			uint64_t mask = f_pkt_work(pkts[pos],		\
-				entries[pos], arg, time);		\
-									\
-			pkts_in_mask &= ~pkt_mask;			\
-			pkts_out_mask ^= mask << pos;			\
-		}							\
-									\
-	rte_pipeline_ah_packet_drop(p, pkts_out_mask ^ pkts_mask);	\
-									\
-	return 0;							\
-}
-
-#define PIPELINE_TABLE_AH_MISS_DROP_TIME(f_ah, f_pkt_work, f_pkt4_work)	\
-static int								\
-f_ah(									\
-	struct rte_pipeline *p,						\
-	struct rte_mbuf **pkts,						\
-	uint64_t pkts_mask,						\
-	struct rte_pipeline_table_entry *entry,				\
-	void *arg)							\
-{									\
-	uint64_t pkts_in_mask = pkts_mask;				\
-	uint64_t pkts_out_mask = pkts_mask;				\
-	uint64_t time = rte_rdtsc();					\
-									\
-	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 & (~0x3LLU)); i += 4) {		\
-			uint64_t mask = f_pkt4_work(&pkts[i],		\
-				entry, arg, time);			\
-			pkts_out_mask ^= mask << i;			\
-		}							\
-									\
-		for ( ; i < n_pkts; i++) {				\
-			uint64_t mask = f_pkt_work(pkts[i], entry, arg, time);\
-			pkts_out_mask ^= mask << i;			\
-		}							\
-	} else								\
-		for ( ; pkts_in_mask; ) {				\
-			uint32_t pos = __builtin_ctzll(pkts_in_mask);	\
-			uint64_t pkt_mask = 1LLU << pos;		\
-			uint64_t mask = f_pkt_work(pkts[pos],		\
-				entry, arg, time);		\
-									\
-			pkts_in_mask &= ~pkt_mask;			\
-			pkts_out_mask ^= mask << pos;			\
-		}							\
-									\
-	rte_pipeline_ah_packet_drop(p, pkts_out_mask ^ pkts_mask);	\
-									\
-	return 0;							\
-}
-
-#endif
diff --git a/examples/ip_pipeline/pipeline/pipeline_common_be.c b/examples/ip_pipeline/pipeline/pipeline_common_be.c
deleted file mode 100644
index 5d84989..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_common_be.c
+++ /dev/null
@@ -1,176 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#include <rte_common.h>
-#include <rte_malloc.h>
-
-#include "pipeline_common_be.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(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(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(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(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(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_be.h b/examples/ip_pipeline/pipeline/pipeline_common_be.h
deleted file mode 100644
index 83bd04e..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_common_be.h
+++ /dev/null
@@ -1,134 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#ifndef __INCLUDE_PIPELINE_COMMON_BE_H__
-#define __INCLUDE_PIPELINE_COMMON_BE_H__
-
-#include <rte_common.h>
-#include <rte_ring.h>
-#include <rte_pipeline.h>
-
-#include "pipeline_be.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];
-	uint32_t log_level;
-};
-
-enum pipeline_log_level {
-	PIPELINE_LOG_LEVEL_HIGH = 1,
-	PIPELINE_LOG_LEVEL_LOW,
-	PIPELINE_LOG_LEVELS
-};
-
-#define PLOG(p, level, fmt, ...)					\
-do {									\
-	if (p->log_level >= PIPELINE_LOG_LEVEL_ ## level)		\
-		fprintf(stdout, "[%s] " fmt "\n", p->name, ## __VA_ARGS__);\
-} while (0)
-
-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_common_fe.c b/examples/ip_pipeline/pipeline/pipeline_common_fe.c
deleted file mode 100644
index cc5214c..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_common_fe.c
+++ /dev/null
@@ -1,1455 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2016 Intel Corporation
- */
-
-#include <stdio.h>
-#include <fcntl.h>
-#include <unistd.h>
-
-#include <rte_common.h>
-#include <rte_malloc.h>
-#include <cmdline_rdline.h>
-#include <cmdline_parse.h>
-#include <cmdline_parse_num.h>
-#include <cmdline_parse_string.h>
-#include <cmdline.h>
-
-#include "pipeline_common_fe.h"
-#include "parser.h"
-
-struct app_link_params *
-app_pipeline_track_pktq_out_to_link(struct app_params *app,
-	uint32_t pipeline_id,
-	uint32_t pktq_out_id)
-{
-	struct app_pipeline_params *p;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return NULL;
-
-	APP_PARAM_FIND_BY_ID(app->pipeline_params, "PIPELINE", pipeline_id, p);
-	if (p == NULL)
-		return NULL;
-
-	for ( ; ; ) {
-		struct app_pktq_out_params *pktq_out =
-			&p->pktq_out[pktq_out_id];
-
-		switch (pktq_out->type) {
-		case APP_PKTQ_OUT_HWQ:
-		{
-			struct app_pktq_hwq_out_params *hwq_out;
-
-			hwq_out = &app->hwq_out_params[pktq_out->id];
-
-			return app_get_link_for_txq(app, hwq_out);
-		}
-
-		case APP_PKTQ_OUT_SWQ:
-		{
-			struct pipeline_params pp;
-			struct pipeline_type *ptype;
-			struct app_pktq_swq_params *swq;
-			uint32_t pktq_in_id;
-			int status;
-
-			swq = &app->swq_params[pktq_out->id];
-			p = app_swq_get_reader(app, swq, &pktq_in_id);
-			if (p == NULL)
-				return NULL;
-
-			ptype = app_pipeline_type_find(app, p->type);
-			if ((ptype == NULL) || (ptype->fe_ops->f_track == NULL))
-				return NULL;
-
-			app_pipeline_params_get(app, p, &pp);
-			status = ptype->fe_ops->f_track(&pp,
-				pktq_in_id,
-				&pktq_out_id);
-			if (status)
-				return NULL;
-
-			break;
-		}
-
-		case APP_PKTQ_OUT_TM:
-		{
-			struct pipeline_params pp;
-			struct pipeline_type *ptype;
-			struct app_pktq_tm_params *tm;
-			uint32_t pktq_in_id;
-			int status;
-
-			tm = &app->tm_params[pktq_out->id];
-			p = app_tm_get_reader(app, tm, &pktq_in_id);
-			if (p == NULL)
-				return NULL;
-
-			ptype = app_pipeline_type_find(app, p->type);
-			if ((ptype == NULL) || (ptype->fe_ops->f_track == NULL))
-				return NULL;
-
-			app_pipeline_params_get(app, p, &pp);
-			status = ptype->fe_ops->f_track(&pp,
-				pktq_in_id,
-				&pktq_out_id);
-			if (status)
-				return NULL;
-
-			break;
-		}
-
-		case APP_PKTQ_OUT_KNI:
-		{
-			struct pipeline_params pp;
-			struct pipeline_type *ptype;
-			struct app_pktq_kni_params *kni;
-			uint32_t pktq_in_id;
-			int status;
-
-			kni = &app->kni_params[pktq_out->id];
-			p = app_kni_get_reader(app, kni, &pktq_in_id);
-			if (p == NULL)
-				return NULL;
-
-			ptype = app_pipeline_type_find(app, p->type);
-			if ((ptype == NULL) || (ptype->fe_ops->f_track == NULL))
-				return NULL;
-
-			app_pipeline_params_get(app, p, &pp);
-			status = ptype->fe_ops->f_track(&pp,
-				pktq_in_id,
-				&pktq_out_id);
-			if (status)
-				return NULL;
-
-			break;
-		}
-
-		case APP_PKTQ_OUT_TAP:
-		case APP_PKTQ_OUT_SINK:
-		default:
-			return NULL;
-		}
-	}
-}
-
-int
-app_pipeline_track_default(struct pipeline_params *p,
-	uint32_t port_in,
-	uint32_t *port_out)
-{
-	/* Check input arguments */
-	if ((p == NULL) ||
-		(port_in >= p->n_ports_in) ||
-		(port_out == NULL))
-		return -1;
-
-	if (p->n_ports_out == 1) {
-		*port_out = 0;
-		return 0;
-	}
-
-	return -1;
-}
-
-int
-app_pipeline_ping(struct app_params *app,
-	uint32_t pipeline_id)
-{
-	struct app_pipeline_params *p;
-	struct pipeline_msg_req *req;
-	struct pipeline_msg_rsp *rsp;
-	int status = 0;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	APP_PARAM_FIND_BY_ID(app->pipeline_params, "PIPELINE", pipeline_id, p);
-	if (p == NULL)
-		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, MSG_TIMEOUT_DEFAULT);
-	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 app_pipeline_params *p;
-	struct pipeline_stats_msg_req *req;
-	struct pipeline_stats_port_in_msg_rsp *rsp;
-	int status = 0;
-
-	/* Check input arguments */
-	if ((app == NULL) ||
-		(stats == NULL))
-		return -1;
-
-	APP_PARAM_FIND_BY_ID(app->pipeline_params, "PIPELINE", pipeline_id, p);
-	if ((p == NULL) ||
-		(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, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	/* Check response */
-	status = rsp->status;
-	if (status == 0)
-		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 app_pipeline_params *p;
-	struct pipeline_stats_msg_req *req;
-	struct pipeline_stats_port_out_msg_rsp *rsp;
-	int status = 0;
-
-	/* Check input arguments */
-	if ((app == NULL) ||
-		(pipeline_id >= app->n_pipelines) ||
-		(stats == NULL))
-		return -1;
-
-	APP_PARAM_FIND_BY_ID(app->pipeline_params, "PIPELINE", pipeline_id, p);
-	if ((p == NULL) ||
-		(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, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	/* Check response */
-	status = rsp->status;
-	if (status == 0)
-		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 app_pipeline_params *p;
-	struct pipeline_stats_msg_req *req;
-	struct pipeline_stats_table_msg_rsp *rsp;
-	int status = 0;
-
-	/* Check input arguments */
-	if ((app == NULL) ||
-		(stats == NULL))
-		return -1;
-
-	APP_PARAM_FIND_BY_ID(app->pipeline_params, "PIPELINE", pipeline_id, p);
-	if (p == 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, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	/* Check response */
-	status = rsp->status;
-	if (status == 0)
-		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 app_pipeline_params *p;
-	struct pipeline_port_in_msg_req *req;
-	struct pipeline_msg_rsp *rsp;
-	int status = 0;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	APP_PARAM_FIND_BY_ID(app->pipeline_params, "PIPELINE", pipeline_id, p);
-	if ((p == NULL) ||
-		(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, MSG_TIMEOUT_DEFAULT);
-	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 app_pipeline_params *p;
-	struct pipeline_port_in_msg_req *req;
-	struct pipeline_msg_rsp *rsp;
-	int status = 0;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	APP_PARAM_FIND_BY_ID(app->pipeline_params, "PIPELINE", pipeline_id, p);
-	if ((p == NULL) ||
-		(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, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	/* Check response */
-	status = rsp->status;
-
-	/* Message buffer free */
-	app_msg_free(app, rsp);
-
-	return status;
-}
-
-int
-app_link_set_op(struct app_params *app,
-	uint32_t link_id,
-	uint32_t pipeline_id,
-	app_link_op op,
-	void *arg)
-{
-	struct app_pipeline_params *pp;
-	struct app_link_params *lp;
-	struct app_link_data *ld;
-	uint32_t ppos, lpos;
-
-	/* Check input arguments */
-	if ((app == NULL) ||
-		(op == NULL))
-		return -1;
-
-	APP_PARAM_FIND_BY_ID(app->link_params, "LINK", link_id, lp);
-	if (lp == NULL)
-		return -1;
-	lpos = lp - app->link_params;
-	ld = &app->link_data[lpos];
-
-	APP_PARAM_FIND_BY_ID(app->pipeline_params, "PIPELINE", pipeline_id, pp);
-	if (pp == NULL)
-		return -1;
-	ppos = pp - app->pipeline_params;
-
-	ld->f_link[ppos] = op;
-	ld->arg[ppos] = arg;
-
-	return 0;
-}
-
-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;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	APP_PARAM_FIND_BY_ID(app->link_params, "LINK", link_id, p);
-	if (p == NULL) {
-		APP_LOG(app, HIGH, "LINK%" PRIu32 " is not a valid link",
-			link_id);
-		return -1;
-	}
-
-	if (p->state) {
-		APP_LOG(app, HIGH, "%s is UP, please bring it DOWN first",
-			p->name);
-		return -1;
-	}
-
-	netmask = (~0U) << (32 - depth);
-	host = ip & netmask;
-	bcast = host | (~netmask);
-
-	if ((ip == 0) ||
-		(ip == UINT32_MAX) ||
-		(ip == host) ||
-		(ip == bcast)) {
-		APP_LOG(app, HIGH, "Illegal IP address");
-		return -1;
-	}
-
-	for (i = 0; i < app->n_links; i++) {
-		struct app_link_params *link = &app->link_params[i];
-
-		if (strcmp(p->name, link->name) == 0)
-			continue;
-
-		if (link->ip == ip) {
-			APP_LOG(app, HIGH,
-				"%s is already assigned this IP address",
-				link->name);
-			return -1;
-		}
-	}
-
-	if ((depth == 0) || (depth > 32)) {
-		APP_LOG(app, HIGH, "Illegal value for depth parameter "
-			"(%" PRIu32 ")",
-			depth);
-		return -1;
-	}
-
-	/* Save link parameters */
-	p->ip = ip;
-	p->depth = depth;
-
-	return 0;
-}
-
-int
-app_link_up(struct app_params *app,
-	uint32_t link_id)
-{
-	struct app_link_params *p;
-	struct app_link_data *d;
-	int i;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	APP_PARAM_FIND_BY_ID(app->link_params, "LINK", link_id, p);
-	if (p == NULL) {
-		APP_LOG(app, HIGH, "LINK%" PRIu32 " is not a valid link",
-			link_id);
-		return -1;
-	}
-
-	d = &app->link_data[p - app->link_params];
-
-	/* Check link state */
-	if (p->state) {
-		APP_LOG(app, HIGH, "%s is already UP", p->name);
-		return 0;
-	}
-
-	/* Check that IP address is valid */
-	if (p->ip == 0) {
-		APP_LOG(app, HIGH, "%s IP address is not set", p->name);
-		return 0;
-	}
-
-	app_link_up_internal(app, p);
-
-	/* Callbacks */
-	for (i = 0; i < APP_MAX_PIPELINES; i++)
-		if (d->f_link[i])
-			d->f_link[i](app, link_id, 1, d->arg[i]);
-
-	return 0;
-}
-
-int
-app_link_down(struct app_params *app,
-	uint32_t link_id)
-{
-	struct app_link_params *p;
-	struct app_link_data *d;
-	uint32_t i;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	APP_PARAM_FIND_BY_ID(app->link_params, "LINK", link_id, p);
-	if (p == NULL) {
-		APP_LOG(app, HIGH, "LINK%" PRIu32 " is not a valid link",
-			link_id);
-		return -1;
-	}
-
-	d = &app->link_data[p - app->link_params];
-
-	/* Check link state */
-	if (p->state == 0) {
-		APP_LOG(app, HIGH, "%s is already DOWN", p->name);
-		return 0;
-	}
-
-	app_link_down_internal(app, p);
-
-	/* Callbacks */
-	for (i = 0; i < APP_MAX_PIPELINES; i++)
-		if (d->f_link[i])
-			d->f_link[i](app, link_id, 0, d->arg[i]);
-
-	return 0;
-}
-
-/*
- * 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("Command failed\n");
-}
-
-static cmdline_parse_token_string_t cmd_ping_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_ping_result, p_string, "p");
-
-static cmdline_parse_token_num_t cmd_ping_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_ping_result, pipeline_id, UINT32);
-
-static cmdline_parse_token_string_t cmd_ping_ping_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_ping_result, ping_string, "ping");
-
-static cmdline_parse_inst_t cmd_ping = {
-	.f = cmd_ping_parsed,
-	.data = NULL,
-	.help_str = "Pipeline ping",
-	.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("Command failed\n");
-		return;
-	}
-
-	/* Display stats */
-	printf("Pipeline %" PRIu32 " - stats for input port %" PRIu32 ":\n"
-		"\tPkts in: %" PRIu64 "\n"
-		"\tPkts dropped by AH: %" PRIu64 "\n"
-		"\tPkts dropped by other: %" PRIu64 "\n",
-		params->pipeline_id,
-		params->port_in_id,
-		stats.stats.n_pkts_in,
-		stats.n_pkts_dropped_by_ah,
-		stats.stats.n_pkts_drop);
-}
-
-static cmdline_parse_token_string_t cmd_stats_port_in_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_stats_port_in_result, p_string,
-		"p");
-
-static cmdline_parse_token_num_t cmd_stats_port_in_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_stats_port_in_result, pipeline_id,
-		UINT32);
-
-static cmdline_parse_token_string_t cmd_stats_port_in_stats_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_stats_port_in_result, stats_string,
-		"stats");
-
-static cmdline_parse_token_string_t cmd_stats_port_in_port_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_stats_port_in_result, port_string,
-		"port");
-
-static 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);
-
-static cmdline_parse_inst_t cmd_stats_port_in = {
-	.f = cmd_stats_port_in_parsed,
-	.data = NULL,
-	.help_str = "Pipeline input port stats",
-	.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("Command failed\n");
-		return;
-	}
-
-	/* Display stats */
-	printf("Pipeline %" PRIu32 " - stats for output port %" PRIu32 ":\n"
-		"\tPkts in: %" PRIu64 "\n"
-		"\tPkts dropped by AH: %" PRIu64 "\n"
-		"\tPkts dropped by other: %" PRIu64 "\n",
-		params->pipeline_id,
-		params->port_out_id,
-		stats.stats.n_pkts_in,
-		stats.n_pkts_dropped_by_ah,
-		stats.stats.n_pkts_drop);
-}
-
-static cmdline_parse_token_string_t cmd_stats_port_out_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_stats_port_out_result, p_string,
-	"p");
-
-static cmdline_parse_token_num_t cmd_stats_port_out_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_stats_port_out_result, pipeline_id,
-		UINT32);
-
-static cmdline_parse_token_string_t cmd_stats_port_out_stats_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_stats_port_out_result, stats_string,
-		"stats");
-
-static cmdline_parse_token_string_t cmd_stats_port_out_port_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_stats_port_out_result, port_string,
-		"port");
-
-static cmdline_parse_token_string_t cmd_stats_port_out_out_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_stats_port_out_result, out_string,
-		"out");
-
-static 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);
-
-static cmdline_parse_inst_t cmd_stats_port_out = {
-	.f = cmd_stats_port_out_parsed,
-	.data = NULL,
-	.help_str = "Pipeline output port stats",
-	.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("Command failed\n");
-		return;
-	}
-
-	/* Display stats */
-	printf("Pipeline %" PRIu32 " - stats for table %" PRIu32 ":\n"
-		"\tPkts in: %" PRIu64 "\n"
-		"\tPkts in with lookup miss: %" PRIu64 "\n"
-		"\tPkts in with lookup hit dropped by AH: %" PRIu64 "\n"
-		"\tPkts in with lookup hit dropped by others: %" PRIu64 "\n"
-		"\tPkts in with lookup miss dropped by AH: %" PRIu64 "\n"
-		"\tPkts in with lookup miss dropped by others: %" PRIu64 "\n",
-		params->pipeline_id,
-		params->table_id,
-		stats.stats.n_pkts_in,
-		stats.stats.n_pkts_lookup_miss,
-		stats.n_pkts_dropped_by_lkp_hit_ah,
-		stats.n_pkts_dropped_lkp_hit,
-		stats.n_pkts_dropped_by_lkp_miss_ah,
-		stats.n_pkts_dropped_lkp_miss);
-}
-
-static cmdline_parse_token_string_t cmd_stats_table_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_stats_table_result, p_string,
-		"p");
-
-static cmdline_parse_token_num_t cmd_stats_table_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_stats_table_result, pipeline_id,
-		UINT32);
-
-static cmdline_parse_token_string_t cmd_stats_table_stats_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_stats_table_result, stats_string,
-		"stats");
-
-static cmdline_parse_token_string_t cmd_stats_table_table_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_stats_table_result, table_string,
-		"table");
-
-static cmdline_parse_token_num_t cmd_stats_table_table_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_stats_table_result, table_id, UINT32);
-
-static cmdline_parse_inst_t cmd_stats_table = {
-	.f = cmd_stats_table_parsed,
-	.data = NULL,
-	.help_str = "Pipeline table stats",
-	.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("Command failed\n");
-}
-
-static cmdline_parse_token_string_t cmd_port_in_enable_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_port_in_enable_result, p_string,
-		"p");
-
-static cmdline_parse_token_num_t cmd_port_in_enable_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_port_in_enable_result, pipeline_id,
-		UINT32);
-
-static cmdline_parse_token_string_t cmd_port_in_enable_port_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_port_in_enable_result, port_string,
-	"port");
-
-static cmdline_parse_token_string_t cmd_port_in_enable_in_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_port_in_enable_result, in_string,
-		"in");
-
-static 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);
-
-static cmdline_parse_token_string_t cmd_port_in_enable_enable_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_port_in_enable_result,
-		enable_string, "enable");
-
-static 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("Command failed\n");
-}
-
-static cmdline_parse_token_string_t cmd_port_in_disable_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_port_in_disable_result, p_string,
-		"p");
-
-static cmdline_parse_token_num_t cmd_port_in_disable_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_port_in_disable_result, pipeline_id,
-		UINT32);
-
-static cmdline_parse_token_string_t cmd_port_in_disable_port_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_port_in_disable_result, port_string,
-		"port");
-
-static cmdline_parse_token_string_t cmd_port_in_disable_in_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_port_in_disable_result, in_string,
-		"in");
-
-static 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);
-
-static cmdline_parse_token_string_t cmd_port_in_disable_disable_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_port_in_disable_result,
-		disable_string, "disable");
-
-static 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,
-	},
-};
-
-/*
- * 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 = (~0U) << (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;
-
-	if (strlen(p->pci_bdf))
-		printf("%s(%s): flags=<%s>\n",
-			p->name,
-			p->pci_bdf,
-			(p->state) ? "UP" : "DOWN");
-	else
-		printf("%s: flags=<%s>\n",
-			p->name,
-			(p->state) ? "UP" : "DOWN");
-
-	if (p->ip)
-		printf("\tinet %" PRIu32 ".%" PRIu32
-			".%" PRIu32 ".%" PRIu32
-			" netmask %" PRIu32 ".%" PRIu32
-			".%" PRIu32 ".%" PRIu32 " "
-			"broadcast %" PRIu32 ".%" PRIu32
-			".%" PRIu32 ".%" PRIu32 "\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 %02" PRIx32 ":%02" PRIx32 ":%02" PRIx32
-		":%02" PRIx32 ":%02" PRIx32 ":%02" PRIx32 "\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 errors %" PRIu64
-		"  missed %" PRIu64
-		"  no-mbuf %" PRIu64
-		"\n",
-		stats.ierrors,
-		stats.imissed,
-		stats.rx_nombuf);
-
-	printf("\tTX packets %" PRIu64
-		"  bytes %" PRIu64 "\n",
-		stats.opackets,
-		stats.obytes);
-
-	printf("\tTX errors %" PRIu64
-		"\n",
-		stats.oerrors);
-
-	printf("\n");
-}
-
-/*
- * link
- *
- * link config:
- *    link <linkid> config <ipaddr> <depth>
- *
- * link up:
- *    link <linkid> up
- *
- * link down:
- *    link <linkid> down
- *
- * link ls:
- *    link ls
- */
-
-struct cmd_link_result {
-	cmdline_fixed_string_t link_string;
-	cmdline_multi_string_t multi_string;
-};
-
-static void
-cmd_link_parsed(
-	void *parsed_result,
-	__attribute__((unused)) struct cmdline *cl,
-	 void *data)
-{
-	struct cmd_link_result *params = parsed_result;
-	struct app_params *app = data;
-
-	char *tokens[16];
-	uint32_t n_tokens = RTE_DIM(tokens);
-	int status;
-
-	uint32_t link_id;
-
-	status = parse_tokenize_string(params->multi_string, tokens, &n_tokens);
-	if (status != 0) {
-		printf(CMD_MSG_TOO_MANY_ARGS, "link");
-		return;
-	}
-
-	/* link ls */
-	if ((n_tokens == 1) && (strcmp(tokens[0], "ls") == 0)) {
-		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);
-		}
-		return;
-	} /* link ls */
-
-	if (n_tokens < 2) {
-		printf(CMD_MSG_MISMATCH_ARGS, "link");
-		return;
-	}
-
-	if (parser_read_uint32(&link_id, tokens[0])) {
-		printf(CMD_MSG_INVALID_ARG, "linkid");
-		return;
-	}
-
-	/* link config */
-	if (strcmp(tokens[1], "config") == 0) {
-		struct in_addr ipaddr_ipv4;
-		uint32_t depth;
-
-		if (n_tokens != 4) {
-			printf(CMD_MSG_MISMATCH_ARGS, "link config");
-			return;
-		}
-
-		if (parse_ipv4_addr(tokens[2], &ipaddr_ipv4)) {
-			printf(CMD_MSG_INVALID_ARG, "ipaddr");
-			return;
-		}
-
-		if (parser_read_uint32(&depth, tokens[3])) {
-			printf(CMD_MSG_INVALID_ARG, "depth");
-			return;
-		}
-
-		status = app_link_config(app,
-			link_id,
-			rte_be_to_cpu_32(ipaddr_ipv4.s_addr),
-			depth);
-		if (status)
-			printf(CMD_MSG_FAIL, "link config");
-
-		return;
-	} /* link config */
-
-	/* link up */
-	if (strcmp(tokens[1], "up") == 0) {
-		if (n_tokens != 2) {
-			printf(CMD_MSG_MISMATCH_ARGS, "link up");
-			return;
-		}
-
-		status = app_link_up(app, link_id);
-		if (status)
-			printf(CMD_MSG_FAIL, "link up");
-
-		return;
-	} /* link up */
-
-	/* link down */
-	if (strcmp(tokens[1], "down") == 0) {
-		if (n_tokens != 2) {
-			printf(CMD_MSG_MISMATCH_ARGS, "link down");
-			return;
-		}
-
-		status = app_link_down(app, link_id);
-		if (status)
-			printf(CMD_MSG_FAIL, "link down");
-
-		return;
-	} /* link down */
-
-	printf(CMD_MSG_MISMATCH_ARGS, "link");
-}
-
-static cmdline_parse_token_string_t cmd_link_link_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_link_result, link_string, "link");
-
-static cmdline_parse_token_string_t cmd_link_multi_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_link_result, multi_string,
-	TOKEN_STRING_MULTI);
-
-static cmdline_parse_inst_t cmd_link = {
-	.f = cmd_link_parsed,
-	.data = NULL,
-	.help_str = "link config / up / down / ls",
-	.tokens = {
-		(void *) &cmd_link_link_string,
-		(void *) &cmd_link_multi_string,
-		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,
-	},
-};
-
-/*
- * run
- *
- *    run <file>
- *    run <file> [<count> [<interval>]]
-	 <count> default is 1
- *       <interval> is measured in milliseconds, default is 1 second
- */
-
-static void
-app_run_file(
-	cmdline_parse_ctx_t *ctx,
-	const char *file_name)
-{
-	struct cmdline *file_cl;
-	int fd;
-
-	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_result {
-	cmdline_fixed_string_t run_string;
-	cmdline_multi_string_t multi_string;
-};
-
-static void
-cmd_run_parsed(
-	void *parsed_result,
-	struct cmdline *cl,
-	__attribute__((unused)) void *data)
-{
-	struct cmd_run_result *params = parsed_result;
-
-	char *tokens[16];
-	uint32_t n_tokens = RTE_DIM(tokens);
-	int status;
-
-	char *file_name;
-	uint32_t count, interval, i;
-
-	status = parse_tokenize_string(params->multi_string, tokens, &n_tokens);
-	if (status) {
-		printf(CMD_MSG_TOO_MANY_ARGS, "run");
-		return;
-	}
-
-	switch (n_tokens) {
-	case 0:
-		printf(CMD_MSG_NOT_ENOUGH_ARGS, "run");
-		return;
-
-	case 1:
-		file_name = tokens[0];
-		count = 1;
-		interval = 1000;
-		break;
-
-	case 2:
-		file_name = tokens[0];
-
-		if (parser_read_uint32(&count, tokens[1]) ||
-			(count == 0)) {
-			printf(CMD_MSG_INVALID_ARG, "count");
-			return;
-		}
-
-		interval = 1000;
-		break;
-
-	case 3:
-		file_name = tokens[0];
-
-		if (parser_read_uint32(&count, tokens[1]) ||
-			(count == 0)) {
-			printf(CMD_MSG_INVALID_ARG, "count");
-			return;
-		}
-
-		if (parser_read_uint32(&interval, tokens[2]) ||
-			(interval == 0)) {
-			printf(CMD_MSG_INVALID_ARG, "interval");
-			return;
-		}
-		break;
-
-	default:
-		printf(CMD_MSG_MISMATCH_ARGS, "run");
-		return;
-	}
-
-	for (i = 0; i < count; i++) {
-		app_run_file(cl->ctx, file_name);
-		if (interval)
-			usleep(interval * 1000);
-	}
-}
-
-static cmdline_parse_token_string_t cmd_run_run_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_run_result, run_string, "run");
-
-static cmdline_parse_token_string_t cmd_run_multi_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_run_result, multi_string,
-	TOKEN_STRING_MULTI);
-
-
-static 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_multi_string,
-		NULL,
-	},
-};
-
-static cmdline_parse_ctx_t pipeline_common_cmds[] = {
-	(cmdline_parse_inst_t *) &cmd_quit,
-	(cmdline_parse_inst_t *) &cmd_run,
-	(cmdline_parse_inst_t *) &cmd_link,
-	(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,
-	NULL,
-};
-
-int
-app_pipeline_common_cmd_push(struct app_params *app)
-{
-	uint32_t n_cmds, i;
-
-	/* Check for available slots in the application commands array */
-	n_cmds = RTE_DIM(pipeline_common_cmds) - 1;
-	if (n_cmds > APP_MAX_CMDS - app->n_cmds)
-		return -ENOMEM;
-
-	/* Push pipeline commands into the application */
-	memcpy(&app->cmds[app->n_cmds],
-		pipeline_common_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;
-}
diff --git a/examples/ip_pipeline/pipeline/pipeline_common_fe.h b/examples/ip_pipeline/pipeline/pipeline_common_fe.h
deleted file mode 100644
index 7227544..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_common_fe.h
+++ /dev/null
@@ -1,231 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#ifndef __INCLUDE_PIPELINE_COMMON_FE_H__
-#define __INCLUDE_PIPELINE_COMMON_FE_H__
-
-#include <rte_common.h>
-#include <rte_cycles.h>
-#include <rte_malloc.h>
-#include <cmdline_parse.h>
-
-#include "pipeline_common_be.h"
-#include "pipeline.h"
-#include "app.h"
-
-#ifndef MSG_TIMEOUT_DEFAULT
-#define MSG_TIMEOUT_DEFAULT                      1000
-#endif
-
-static inline struct app_pipeline_data *
-app_pipeline_data(struct app_params *app, uint32_t id)
-{
-	struct app_pipeline_params *params;
-
-	APP_PARAM_FIND_BY_ID(app->pipeline_params, "PIPELINE", id, params);
-	if (params == NULL)
-		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 pipeline_type *ptype)
-{
-	struct app_pipeline_data *pipeline_data;
-
-	pipeline_data = app_pipeline_data(app, id);
-	if (pipeline_data == NULL)
-		return NULL;
-
-	if (strcmp(pipeline_data->ptype->name, ptype->name) != 0)
-		return NULL;
-
-	if (pipeline_data->enabled == 0)
-		return NULL;
-
-	return pipeline_data->fe;
-}
-
-static inline struct rte_ring *
-app_pipeline_msgq_in_get(struct app_params *app,
-	uint32_t pipeline_id)
-{
-	struct app_msgq_params *p;
-
-	APP_PARAM_FIND_BY_ID(app->msgq_params,
-		"MSGQ-REQ-PIPELINE",
-		pipeline_id,
-		p);
-	if (p == NULL)
-		return NULL;
-
-	return app->msgq[p - app->msgq_params];
-}
-
-static inline struct rte_ring *
-app_pipeline_msgq_out_get(struct app_params *app,
-	uint32_t pipeline_id)
-{
-	struct app_msgq_params *p;
-
-	APP_PARAM_FIND_BY_ID(app->msgq_params,
-		"MSGQ-RSP-PIPELINE",
-		pipeline_id,
-		p);
-	if (p == NULL)
-		return NULL;
-
-	return app->msgq[p - app->msgq_params];
-}
-
-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;
-}
-
-struct app_link_params *
-app_pipeline_track_pktq_out_to_link(struct app_params *app,
-	uint32_t pipeline_id,
-	uint32_t pktq_out_id);
-
-int
-app_pipeline_track_default(struct pipeline_params *params,
-	uint32_t port_in,
-	uint32_t *port_out);
-
-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_set_op(struct app_params *app,
-	uint32_t link_id,
-	uint32_t pipeline_id,
-	app_link_op op,
-	void *arg);
-
-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);
-
-int
-app_pipeline_common_cmd_push(struct app_params *app);
-
-#define CMD_MSG_OUT_OF_MEMORY	"Not enough memory\n"
-#define CMD_MSG_NOT_ENOUGH_ARGS	"Not enough arguments for command \"%s\"\n"
-#define CMD_MSG_TOO_MANY_ARGS	"Too many arguments for command \"%s\"\n"
-#define CMD_MSG_MISMATCH_ARGS	"Incorrect set of arguments for command \"%s\"\n"
-#define CMD_MSG_INVALID_ARG	"Invalid value for argument \"%s\"\n"
-#define CMD_MSG_ARG_NOT_FOUND	"Syntax error: \"%s\" not found\n"
-#define CMD_MSG_FILE_ERR	"Error in file \"%s\" at line %u\n"
-#define CMD_MSG_FAIL		"Command \"%s\" failed\n"
-
-#endif
diff --git a/examples/ip_pipeline/pipeline/pipeline_master.c b/examples/ip_pipeline/pipeline/pipeline_master.c
deleted file mode 100644
index b0d730a..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_master.c
+++ /dev/null
@@ -1,20 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#include "pipeline_master.h"
-#include "pipeline_master_be.h"
-
-static struct pipeline_fe_ops pipeline_master_fe_ops = {
-	.f_init = NULL,
-	.f_post_init = NULL,
-	.f_free = NULL,
-	.f_track = NULL,
-	.cmds = NULL,
-};
-
-struct pipeline_type pipeline_master = {
-	.name = "MASTER",
-	.be_ops = &pipeline_master_be_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
deleted file mode 100644
index a5183e3..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_master.h
+++ /dev/null
@@ -1,12 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#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_be.c b/examples/ip_pipeline/pipeline/pipeline_master_be.c
deleted file mode 100644
index c72038e..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_master_be.c
+++ /dev/null
@@ -1,141 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#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_be.h"
-
-struct pipeline_master {
-	struct app_params *app;
-	struct cmdline *cl;
-	int post_init_done;
-	int script_file_done;
-} __rte_cache_aligned;
-
-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 (app == NULL)
-		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;
-
-	/* Initialization */
-	p->app = app;
-
-	p->cl = cmdline_stdin_new(app->cmds, "pipeline> ");
-	if (p->cl == NULL) {
-		rte_free(p);
-		return NULL;
-	}
-
-	p->post_init_done = 0;
-	p->script_file_done = 0;
-	if (app->script_file == NULL)
-		p->script_file_done = 1;
-
-	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;
-	struct app_params *app = p->app;
-	int status;
-#ifdef RTE_LIBRTE_KNI
-	uint32_t i;
-#endif /* RTE_LIBRTE_KNI */
-
-	/* Application post-init phase */
-	if (p->post_init_done == 0) {
-		app_post_init(app);
-
-		p->post_init_done = 1;
-	}
-
-	/* Run startup script file */
-	if (p->script_file_done == 0) {
-		struct app_params *app = p->app;
-		int fd = open(app->script_file, O_RDONLY);
-
-		if (fd < 0)
-			printf("Cannot open CLI script file \"%s\"\n",
-				app->script_file);
-		else {
-			struct cmdline *file_cl;
-
-			printf("Running CLI script file \"%s\" ...\n",
-				app->script_file);
-			file_cl = cmdline_new(p->cl->ctx, "", fd, 1);
-			cmdline_interact(file_cl);
-			close(fd);
-		}
-
-		p->script_file_done = 1;
-	}
-
-	/* Command Line Interface (CLI) */
-	status = cmdline_poll(p->cl);
-	if (status < 0)
-		rte_panic("CLI poll error (%" PRId32 ")\n", status);
-	else if (status == RDLINE_EXITED) {
-		cmdline_stdin_exit(p->cl);
-		rte_exit(0, "Bye!\n");
-	}
-
-#ifdef RTE_LIBRTE_KNI
-	/* Handle KNI requests from Linux kernel */
-	for (i = 0; i < app->n_pktq_kni; i++)
-		rte_kni_handle_request(app->kni[i]);
-#endif /* RTE_LIBRTE_KNI */
-
-	return 0;
-}
-
-static int
-pipeline_timer(__rte_unused void *pipeline)
-{
-	return 0;
-}
-
-struct pipeline_be_ops pipeline_master_be_ops = {
-		.f_init = pipeline_init,
-		.f_free = pipeline_free,
-		.f_run = pipeline_run,
-		.f_timer = pipeline_timer,
-};
diff --git a/examples/ip_pipeline/pipeline/pipeline_master_be.h b/examples/ip_pipeline/pipeline/pipeline_master_be.h
deleted file mode 100644
index 847c564..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_master_be.h
+++ /dev/null
@@ -1,12 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#ifndef __INCLUDE_PIPELINE_MASTER_BE_H__
-#define __INCLUDE_PIPELINE_MASTER_BE_H__
-
-#include "pipeline_common_be.h"
-
-extern struct pipeline_be_ops pipeline_master_be_ops;
-
-#endif
diff --git a/examples/ip_pipeline/thread.c b/examples/ip_pipeline/thread.c
index 9013afd..a36bf92 100644
--- a/examples/ip_pipeline/thread.c
+++ b/examples/ip_pipeline/thread.c
@@ -6,47 +6,9 @@
 #include <rte_cycles.h>
 #include <rte_pipeline.h>
 
-#include "pipeline_common_be.h"
 #include "app.h"
 #include "thread.h"
 
-#if APP_THREAD_HEADROOM_STATS_COLLECT
-
-#define PIPELINE_RUN_REGULAR(thread, pipeline)		\
-do {							\
-	uint64_t t0 = rte_rdtsc_precise();		\
-	int n_pkts = rte_pipeline_run(pipeline->p);	\
-							\
-	if (n_pkts == 0) {				\
-		uint64_t t1 = rte_rdtsc_precise();	\
-							\
-		thread->headroom_cycles += t1 - t0;	\
-	}						\
-} while (0)
-
-
-#define PIPELINE_RUN_CUSTOM(thread, data)		\
-do {							\
-	uint64_t t0 = rte_rdtsc_precise();		\
-	int n_pkts = data->f_run(data->be);		\
-							\
-	if (n_pkts == 0) {				\
-		uint64_t t1 = rte_rdtsc_precise();	\
-							\
-		thread->headroom_cycles += t1 - t0;	\
-	}						\
-} while (0)
-
-#else
-
-#define PIPELINE_RUN_REGULAR(thread, pipeline)		\
-	rte_pipeline_run(pipeline->p)
-
-#define PIPELINE_RUN_CUSTOM(thread, data)		\
-	data->f_run(data->be)
-
-#endif
-
 static inline void *
 thread_msg_recv(struct rte_ring *r)
 {
@@ -214,21 +176,6 @@ app_thread(void *arg)
 		uint32_t n_regular = RTE_MIN(t->n_regular, RTE_DIM(t->regular));
 		uint32_t n_custom = RTE_MIN(t->n_custom, RTE_DIM(t->custom));
 
-		/* Run regular pipelines */
-		for (j = 0; j < n_regular; j++) {
-			struct app_thread_pipeline_data *data = &t->regular[j];
-			struct pipeline *p = data->be;
-
-			PIPELINE_RUN_REGULAR(t, p);
-		}
-
-		/* Run custom pipelines */
-		for (j = 0; j < n_custom; j++) {
-			struct app_thread_pipeline_data *data = &t->custom[j];
-
-			PIPELINE_RUN_CUSTOM(t, data);
-		}
-
 		/* Timer */
 		if ((i & 0xF) == 0) {
 			uint64_t time = rte_get_tsc_cycles();
diff --git a/examples/ip_pipeline/thread_fe.c b/examples/ip_pipeline/thread_fe.c
deleted file mode 100644
index 4590c2b..0000000
--- a/examples/ip_pipeline/thread_fe.c
+++ /dev/null
@@ -1,457 +0,0 @@
-#include <rte_common.h>
-#include <rte_ring.h>
-#include <rte_malloc.h>
-#include <cmdline_rdline.h>
-#include <cmdline_parse.h>
-#include <cmdline_parse_num.h>
-#include <cmdline_parse_string.h>
-
-#include "thread.h"
-#include "thread_fe.h"
-#include "pipeline.h"
-#include "pipeline_common_fe.h"
-#include "app.h"
-
-static inline void *
-thread_msg_send_recv(struct app_params *app,
-	uint32_t socket_id, uint32_t core_id, uint32_t ht_id,
-	void *msg,
-	uint32_t timeout_ms)
-{
-	struct rte_ring *r_req = app_thread_msgq_in_get(app,
-		socket_id, core_id, ht_id);
-	struct rte_ring *r_rsp = app_thread_msgq_out_get(app,
-		socket_id, core_id, ht_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_enable(struct app_params *app,
-		uint32_t socket_id,
-		uint32_t core_id,
-		uint32_t hyper_th_id,
-		uint32_t pipeline_id)
-{
-	struct thread_pipeline_enable_msg_req *req;
-	struct thread_pipeline_enable_msg_rsp *rsp;
-	int thread_id;
-	struct app_pipeline_data *p;
-	struct app_pipeline_params *p_params;
-	struct pipeline_type *p_type;
-	int status;
-
-	if (app == NULL)
-		return -1;
-
-	thread_id = cpu_core_map_get_lcore_id(app->core_map,
-			socket_id,
-			core_id,
-			hyper_th_id);
-
-	if ((thread_id < 0) || !app_core_is_enabled(app, thread_id))
-		return -1;
-
-	if (app_pipeline_data(app, pipeline_id) == NULL)
-		return -1;
-
-	p = &app->pipeline_data[pipeline_id];
-	p_params = &app->pipeline_params[pipeline_id];
-	p_type = app_pipeline_type_find(app, p_params->type);
-
-	if (p_type == NULL)
-		return -1;
-
-	if (p->enabled == 1)
-		return -1;
-
-	req = app_msg_alloc(app);
-	if (req == NULL)
-		return -1;
-
-	req->type = THREAD_MSG_REQ_PIPELINE_ENABLE;
-	req->pipeline_id = pipeline_id;
-	req->be = p->be;
-	req->f_run = p_type->be_ops->f_run;
-	req->f_timer = p_type->be_ops->f_timer;
-	req->timer_period = p->timer_period;
-
-	rsp = thread_msg_send_recv(app,
-		socket_id, core_id, hyper_th_id, req, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	status = rsp->status;
-	app_msg_free(app, rsp);
-
-	if (status != 0)
-		return -1;
-
-	p->enabled = 1;
-	return 0;
-}
-
-int
-app_pipeline_disable(struct app_params *app,
-		uint32_t socket_id,
-		uint32_t core_id,
-		uint32_t hyper_th_id,
-		uint32_t pipeline_id)
-{
-	struct thread_pipeline_disable_msg_req *req;
-	struct thread_pipeline_disable_msg_rsp *rsp;
-	int thread_id;
-	struct app_pipeline_data *p;
-	int status;
-
-	if (app == NULL)
-		return -1;
-
-	thread_id = cpu_core_map_get_lcore_id(app->core_map,
-			socket_id,
-			core_id,
-			hyper_th_id);
-
-	if ((thread_id < 0) || !app_core_is_enabled(app, thread_id))
-		return -1;
-
-	if (app_pipeline_data(app, pipeline_id) == NULL)
-		return -1;
-
-	p = &app->pipeline_data[pipeline_id];
-
-	if (p->enabled == 0)
-		return -1;
-
-	req = app_msg_alloc(app);
-	if (req == NULL)
-		return -1;
-
-	req->type = THREAD_MSG_REQ_PIPELINE_DISABLE;
-	req->pipeline_id = pipeline_id;
-
-	rsp = thread_msg_send_recv(app,
-		socket_id, core_id, hyper_th_id, req, MSG_TIMEOUT_DEFAULT);
-
-	if (rsp == NULL)
-		return -1;
-
-	status = rsp->status;
-	app_msg_free(app, rsp);
-
-	if (status != 0)
-		return -1;
-
-	p->enabled = 0;
-	return 0;
-}
-
-int
-app_thread_headroom(struct app_params *app,
-		uint32_t socket_id,
-		uint32_t core_id,
-		uint32_t hyper_th_id)
-{
-	struct thread_headroom_read_msg_req *req;
-	struct thread_headroom_read_msg_rsp *rsp;
-	int thread_id;
-	int status;
-
-	if (app == NULL)
-		return -1;
-
-	thread_id = cpu_core_map_get_lcore_id(app->core_map,
-			socket_id,
-			core_id,
-			hyper_th_id);
-
-	if ((thread_id < 0) || !app_core_is_enabled(app, thread_id))
-		return -1;
-
-	req = app_msg_alloc(app);
-	if (req == NULL)
-		return -1;
-
-	req->type = THREAD_MSG_REQ_HEADROOM_READ;
-
-	rsp = thread_msg_send_recv(app,
-		socket_id, core_id, hyper_th_id, req, MSG_TIMEOUT_DEFAULT);
-
-	if (rsp == NULL)
-		return -1;
-
-	status = rsp->status;
-
-	if (status != 0)
-		return -1;
-
-	printf("%.3f%%\n", rsp->headroom_ratio * 100);
-
-
-	app_msg_free(app, rsp);
-
-	return 0;
-}
-
-/*
- * pipeline enable
- */
-
-struct cmd_pipeline_enable_result {
-	cmdline_fixed_string_t t_string;
-	cmdline_fixed_string_t t_id_string;
-	cmdline_fixed_string_t pipeline_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t enable_string;
-};
-
-static void
-cmd_pipeline_enable_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	 void *data)
-{
-	struct cmd_pipeline_enable_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
-	uint32_t core_id, socket_id, hyper_th_id;
-
-	if (parse_pipeline_core(&socket_id,
-			&core_id,
-			&hyper_th_id,
-			params->t_id_string) != 0) {
-		printf("Command failed\n");
-		return;
-	}
-
-	status = app_pipeline_enable(app,
-			socket_id,
-			core_id,
-			hyper_th_id,
-			params->pipeline_id);
-
-	if (status != 0)
-		printf("Command failed\n");
-}
-
-static cmdline_parse_token_string_t cmd_pipeline_enable_t_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_pipeline_enable_result, t_string, "t");
-
-static cmdline_parse_token_string_t cmd_pipeline_enable_t_id_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_pipeline_enable_result, t_id_string,
-		NULL);
-
-static cmdline_parse_token_string_t cmd_pipeline_enable_pipeline_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_pipeline_enable_result, pipeline_string,
-		"pipeline");
-
-static cmdline_parse_token_num_t cmd_pipeline_enable_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_pipeline_enable_result, pipeline_id,
-		UINT32);
-
-static cmdline_parse_token_string_t cmd_pipeline_enable_enable_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_pipeline_enable_result, enable_string,
-		"enable");
-
-static cmdline_parse_inst_t cmd_pipeline_enable = {
-	.f = cmd_pipeline_enable_parsed,
-	.data = NULL,
-	.help_str = "Enable pipeline on specified core",
-	.tokens = {
-		(void *)&cmd_pipeline_enable_t_string,
-		(void *)&cmd_pipeline_enable_t_id_string,
-		(void *)&cmd_pipeline_enable_pipeline_string,
-		(void *)&cmd_pipeline_enable_pipeline_id,
-		(void *)&cmd_pipeline_enable_enable_string,
-		NULL,
-	},
-};
-
-/*
- * pipeline disable
- */
-
-struct cmd_pipeline_disable_result {
-	cmdline_fixed_string_t t_string;
-	cmdline_fixed_string_t t_id_string;
-	cmdline_fixed_string_t pipeline_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t disable_string;
-};
-
-static void
-cmd_pipeline_disable_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	 void *data)
-{
-	struct cmd_pipeline_disable_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
-	uint32_t core_id, socket_id, hyper_th_id;
-
-	if (parse_pipeline_core(&socket_id,
-			&core_id,
-			&hyper_th_id,
-			params->t_id_string) != 0) {
-		printf("Command failed\n");
-		return;
-	}
-
-	status = app_pipeline_disable(app,
-			socket_id,
-			core_id,
-			hyper_th_id,
-			params->pipeline_id);
-
-	if (status != 0)
-		printf("Command failed\n");
-}
-
-static cmdline_parse_token_string_t cmd_pipeline_disable_t_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_pipeline_disable_result, t_string, "t");
-
-static cmdline_parse_token_string_t cmd_pipeline_disable_t_id_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_pipeline_disable_result, t_id_string,
-		NULL);
-
-static cmdline_parse_token_string_t cmd_pipeline_disable_pipeline_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_pipeline_disable_result,
-		pipeline_string, "pipeline");
-
-static cmdline_parse_token_num_t cmd_pipeline_disable_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_pipeline_disable_result, pipeline_id,
-		UINT32);
-
-static cmdline_parse_token_string_t cmd_pipeline_disable_disable_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_pipeline_disable_result, disable_string,
-		"disable");
-
-static cmdline_parse_inst_t cmd_pipeline_disable = {
-	.f = cmd_pipeline_disable_parsed,
-	.data = NULL,
-	.help_str = "Disable pipeline on specified core",
-	.tokens = {
-		(void *)&cmd_pipeline_disable_t_string,
-		(void *)&cmd_pipeline_disable_t_id_string,
-		(void *)&cmd_pipeline_disable_pipeline_string,
-		(void *)&cmd_pipeline_disable_pipeline_id,
-		(void *)&cmd_pipeline_disable_disable_string,
-		NULL,
-	},
-};
-
-
-/*
- * thread headroom
- */
-
-struct cmd_thread_headroom_result {
-	cmdline_fixed_string_t t_string;
-	cmdline_fixed_string_t t_id_string;
-	cmdline_fixed_string_t headroom_string;
-};
-
-static void
-cmd_thread_headroom_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	 void *data)
-{
-	struct cmd_thread_headroom_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
-	uint32_t core_id, socket_id, hyper_th_id;
-
-	if (parse_pipeline_core(&socket_id,
-			&core_id,
-			&hyper_th_id,
-			params->t_id_string) != 0) {
-		printf("Command failed\n");
-		return;
-	}
-
-	status = app_thread_headroom(app,
-			socket_id,
-			core_id,
-			hyper_th_id);
-
-	if (status != 0)
-		printf("Command failed\n");
-}
-
-static cmdline_parse_token_string_t cmd_thread_headroom_t_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_thread_headroom_result,
-	t_string, "t");
-
-static cmdline_parse_token_string_t cmd_thread_headroom_t_id_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_thread_headroom_result,
-	t_id_string, NULL);
-
-static cmdline_parse_token_string_t cmd_thread_headroom_headroom_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_thread_headroom_result,
-		headroom_string, "headroom");
-
-static cmdline_parse_inst_t cmd_thread_headroom = {
-	.f = cmd_thread_headroom_parsed,
-	.data = NULL,
-	.help_str = "Display thread headroom",
-	.tokens = {
-		(void *)&cmd_thread_headroom_t_string,
-		(void *)&cmd_thread_headroom_t_id_string,
-		(void *)&cmd_thread_headroom_headroom_string,
-		NULL,
-	},
-};
-
-
-static cmdline_parse_ctx_t thread_cmds[] = {
-	(cmdline_parse_inst_t *) &cmd_pipeline_enable,
-	(cmdline_parse_inst_t *) &cmd_pipeline_disable,
-	(cmdline_parse_inst_t *) &cmd_thread_headroom,
-	NULL,
-};
-
-int
-app_pipeline_thread_cmd_push(struct app_params *app)
-{
-	uint32_t n_cmds, i;
-
-	/* Check for available slots in the application commands array */
-	n_cmds = RTE_DIM(thread_cmds) - 1;
-	if (n_cmds > APP_MAX_CMDS - app->n_cmds)
-		return -ENOMEM;
-
-	/* Push thread commands into the application */
-	memcpy(&app->cmds[app->n_cmds], thread_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;
-}
diff --git a/examples/ip_pipeline/thread_fe.h b/examples/ip_pipeline/thread_fe.h
deleted file mode 100644
index 056a5e8..0000000
--- a/examples/ip_pipeline/thread_fe.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#ifndef THREAD_FE_H_
-#define THREAD_FE_H_
-
-static inline struct rte_ring *
-app_thread_msgq_in_get(struct app_params *app,
-		uint32_t socket_id, uint32_t core_id, uint32_t ht_id)
-{
-	char msgq_name[32];
-	ssize_t param_idx;
-
-	snprintf(msgq_name, sizeof(msgq_name),
-		"MSGQ-REQ-CORE-s%" PRIu32 "c%" PRIu32 "%s",
-		socket_id,
-		core_id,
-		(ht_id) ? "h" : "");
-	param_idx = APP_PARAM_FIND(app->msgq_params, msgq_name);
-
-	if (param_idx < 0)
-		return NULL;
-
-	return app->msgq[param_idx];
-}
-
-static inline struct rte_ring *
-app_thread_msgq_out_get(struct app_params *app,
-		uint32_t socket_id, uint32_t core_id, uint32_t ht_id)
-{
-	char msgq_name[32];
-	ssize_t param_idx;
-
-	snprintf(msgq_name, sizeof(msgq_name),
-		"MSGQ-RSP-CORE-s%" PRIu32 "c%" PRIu32 "%s",
-		socket_id,
-		core_id,
-		(ht_id) ? "h" : "");
-	param_idx = APP_PARAM_FIND(app->msgq_params, msgq_name);
-
-	if (param_idx < 0)
-		return NULL;
-
-	return app->msgq[param_idx];
-
-}
-
-int
-app_pipeline_thread_cmd_push(struct app_params *app);
-
-int
-app_pipeline_enable(struct app_params *app,
-		uint32_t core_id,
-		uint32_t socket_id,
-		uint32_t hyper_th_id,
-		uint32_t pipeline_id);
-
-int
-app_pipeline_disable(struct app_params *app,
-		uint32_t core_id,
-		uint32_t socket_id,
-		uint32_t hyper_th_id,
-		uint32_t pipeline_id);
-
-int
-app_thread_headroom(struct app_params *app,
-		uint32_t core_id,
-		uint32_t socket_id,
-		uint32_t hyper_th_id);
-
-#endif /* THREAD_FE_H_ */
-- 
2.9.3

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

* [dpdk-dev] [PATCH v3 16/44] ip_pipeline: remove config
  2018-03-16 17:58       ` [dpdk-dev] [PATCH v3 00/44] ip_pipeline: refactoring Jasvinder Singh
                           ` (14 preceding siblings ...)
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 15/44] ip_pipeline: remove master pipeline Jasvinder Singh
@ 2018-03-16 17:58         ` Jasvinder Singh
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 17/44] ip_pipeline: rework and improvements Jasvinder Singh
                           ` (27 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-16 17:58 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Remove application configuration and script files.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/config/action.cfg             |  68 --
 examples/ip_pipeline/config/action.sh              | 119 ---
 examples/ip_pipeline/config/action.txt             |   8 -
 examples/ip_pipeline/config/diagram-generator.py   | 317 -------
 .../ip_pipeline/config/edge_router_downstream.cfg  |  97 ---
 .../ip_pipeline/config/edge_router_downstream.sh   |  13 -
 .../ip_pipeline/config/edge_router_upstream.cfg    | 124 ---
 .../ip_pipeline/config/edge_router_upstream.sh     |  33 -
 examples/ip_pipeline/config/firewall.cfg           |  68 --
 examples/ip_pipeline/config/firewall.sh            |  13 -
 examples/ip_pipeline/config/firewall.txt           |   9 -
 examples/ip_pipeline/config/flow.cfg               |  72 --
 examples/ip_pipeline/config/flow.sh                |  25 -
 examples/ip_pipeline/config/flow.txt               |  17 -
 examples/ip_pipeline/config/ip_pipeline.cfg        |   9 -
 examples/ip_pipeline/config/ip_pipeline.sh         |   5 -
 examples/ip_pipeline/config/kni.cfg                |  67 --
 examples/ip_pipeline/config/l2fwd.cfg              |  58 --
 examples/ip_pipeline/config/l3fwd.cfg              |  68 --
 examples/ip_pipeline/config/l3fwd.sh               |  33 -
 examples/ip_pipeline/config/l3fwd_arp.cfg          |  70 --
 examples/ip_pipeline/config/l3fwd_arp.sh           |  43 -
 examples/ip_pipeline/config/network_layers.cfg     | 227 ------
 examples/ip_pipeline/config/network_layers.sh      |  79 --
 .../ip_pipeline/config/pipeline-to-core-mapping.py | 906 ---------------------
 examples/ip_pipeline/config/tap.cfg                |  64 --
 examples/ip_pipeline/config/tm_profile.cfg         | 105 ---
 27 files changed, 2717 deletions(-)
 delete mode 100644 examples/ip_pipeline/config/action.cfg
 delete mode 100644 examples/ip_pipeline/config/action.sh
 delete mode 100644 examples/ip_pipeline/config/action.txt
 delete mode 100755 examples/ip_pipeline/config/diagram-generator.py
 delete mode 100644 examples/ip_pipeline/config/edge_router_downstream.cfg
 delete mode 100644 examples/ip_pipeline/config/edge_router_downstream.sh
 delete mode 100644 examples/ip_pipeline/config/edge_router_upstream.cfg
 delete mode 100644 examples/ip_pipeline/config/edge_router_upstream.sh
 delete mode 100644 examples/ip_pipeline/config/firewall.cfg
 delete mode 100644 examples/ip_pipeline/config/firewall.sh
 delete mode 100644 examples/ip_pipeline/config/firewall.txt
 delete mode 100644 examples/ip_pipeline/config/flow.cfg
 delete mode 100644 examples/ip_pipeline/config/flow.sh
 delete mode 100644 examples/ip_pipeline/config/flow.txt
 delete mode 100644 examples/ip_pipeline/config/ip_pipeline.cfg
 delete mode 100644 examples/ip_pipeline/config/ip_pipeline.sh
 delete mode 100644 examples/ip_pipeline/config/kni.cfg
 delete mode 100644 examples/ip_pipeline/config/l2fwd.cfg
 delete mode 100644 examples/ip_pipeline/config/l3fwd.cfg
 delete mode 100644 examples/ip_pipeline/config/l3fwd.sh
 delete mode 100644 examples/ip_pipeline/config/l3fwd_arp.cfg
 delete mode 100644 examples/ip_pipeline/config/l3fwd_arp.sh
 delete mode 100644 examples/ip_pipeline/config/network_layers.cfg
 delete mode 100644 examples/ip_pipeline/config/network_layers.sh
 delete mode 100755 examples/ip_pipeline/config/pipeline-to-core-mapping.py
 delete mode 100644 examples/ip_pipeline/config/tap.cfg
 delete mode 100644 examples/ip_pipeline/config/tm_profile.cfg

diff --git a/examples/ip_pipeline/config/action.cfg b/examples/ip_pipeline/config/action.cfg
deleted file mode 100644
index 994ae94..0000000
--- a/examples/ip_pipeline/config/action.cfg
+++ /dev/null
@@ -1,68 +0,0 @@
-;   BSD LICENSE
-;
-;   Copyright(c) 2016 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.
-
-;             ________________
-; RXQ0.0 --->|                |---> TXQ0.0
-;            |                |
-; RXQ1.0 --->|                |---> TXQ1.0
-;            |      Flow      |
-; RXQ2.0 --->|     Actions    |---> TXQ2.0
-;            |                |
-; RXQ3.0 --->|                |---> TXQ3.0
-;            |________________|
-;
-;
-; Input packet: Ethernet/IPv4
-;
-; Packet buffer layout:
-; #	Field Name		Offset (Bytes)	Size (Bytes)
-; 0	Mbuf			0 		128
-; 1	Headroom		128 		128
-; 2	Ethernet header		256 		14
-; 3	IPv4 header		270 		20
-
-[EAL]
-log_level = 0
-
-[PIPELINE0]
-type = MASTER
-core = 0
-
-[PIPELINE1]
-type = FLOW_ACTIONS
-core = 1
-pktq_in = RXQ0.0 RXQ1.0 RXQ2.0 RXQ3.0
-pktq_out = TXQ0.0 TXQ1.0 TXQ2.0 TXQ3.0
-n_flows = 65536
-n_meters_per_flow = 4
-flow_id_offset = 286; ipdaddr
-ip_hdr_offset = 270
-color_offset = 128
diff --git a/examples/ip_pipeline/config/action.sh b/examples/ip_pipeline/config/action.sh
deleted file mode 100644
index 2986ae6..0000000
--- a/examples/ip_pipeline/config/action.sh
+++ /dev/null
@@ -1,119 +0,0 @@
-#
-# run ./config/action.sh
-#
-
-p 1 action flow 0 meter 0 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 0 policer 0 g G y Y r R
-p 1 action flow 0 meter 1 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 0 policer 1 g G y Y r R
-p 1 action flow 0 meter 2 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 0 policer 2 g G y Y r R
-p 1 action flow 0 meter 3 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 0 policer 3 g G y Y r R
-p 1 action flow 0 port 0
-
-p 1 action flow 1 meter 0 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 1 policer 0 g G y Y r R
-p 1 action flow 1 meter 1 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 1 policer 1 g G y Y r R
-p 1 action flow 1 meter 2 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 1 policer 2 g G y Y r R
-p 1 action flow 1 meter 3 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 1 policer 3 g G y Y r R
-p 1 action flow 1 port 1
-
-p 1 action flow 2 meter 0 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 2 policer 0 g G y Y r R
-p 1 action flow 2 meter 1 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 2 policer 1 g G y Y r R
-p 1 action flow 2 meter 2 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 2 policer 2 g G y Y r R
-p 1 action flow 2 meter 3 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 2 policer 3 g G y Y r R
-p 1 action flow 2 port 2
-
-p 1 action flow 3 meter 0 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 3 policer 0 g G y Y r R
-p 1 action flow 3 meter 1 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 3 policer 1 g G y Y r R
-p 1 action flow 3 meter 2 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 3 policer 2 g G y Y r R
-p 1 action flow 3 meter 3 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 3 policer 3 g G y Y r R
-p 1 action flow 3 port 3
-
-#p 1 action flow bulk ./config/action.txt
-
-#p 1 action flow ls
-
-p 1 action flow 0 stats
-p 1 action flow 1 stats
-p 1 action flow 2 stats
-p 1 action flow 3 stats
-
-p 1 action dscp 0 class 0 color G
-p 1 action dscp 1 class 1 color G
-p 1 action dscp 2 class 2 color G
-p 1 action dscp 3 class 3 color G
-p 1 action dscp 4 class 0 color G
-p 1 action dscp 5 class 1 color G
-p 1 action dscp 6 class 2 color G
-p 1 action dscp 7 class 3 color G
-p 1 action dscp 8 class 0 color G
-p 1 action dscp 9 class 1 color G
-p 1 action dscp 10 class 2 color G
-p 1 action dscp 11 class 3 color G
-p 1 action dscp 12 class 0 color G
-p 1 action dscp 13 class 1 color G
-p 1 action dscp 14 class 2 color G
-p 1 action dscp 15 class 3 color G
-p 1 action dscp 16 class 0 color G
-p 1 action dscp 17 class 1 color G
-p 1 action dscp 18 class 2 color G
-p 1 action dscp 19 class 3 color G
-p 1 action dscp 20 class 0 color G
-p 1 action dscp 21 class 1 color G
-p 1 action dscp 22 class 2 color G
-p 1 action dscp 23 class 3 color G
-p 1 action dscp 24 class 0 color G
-p 1 action dscp 25 class 1 color G
-p 1 action dscp 26 class 2 color G
-p 1 action dscp 27 class 3 color G
-p 1 action dscp 27 class 0 color G
-p 1 action dscp 29 class 1 color G
-p 1 action dscp 30 class 2 color G
-p 1 action dscp 31 class 3 color G
-p 1 action dscp 32 class 0 color G
-p 1 action dscp 33 class 1 color G
-p 1 action dscp 34 class 2 color G
-p 1 action dscp 35 class 3 color G
-p 1 action dscp 36 class 0 color G
-p 1 action dscp 37 class 1 color G
-p 1 action dscp 38 class 2 color G
-p 1 action dscp 39 class 3 color G
-p 1 action dscp 40 class 0 color G
-p 1 action dscp 41 class 1 color G
-p 1 action dscp 42 class 2 color G
-p 1 action dscp 43 class 3 color G
-p 1 action dscp 44 class 0 color G
-p 1 action dscp 45 class 1 color G
-p 1 action dscp 46 class 2 color G
-p 1 action dscp 47 class 3 color G
-p 1 action dscp 48 class 0 color G
-p 1 action dscp 49 class 1 color G
-p 1 action dscp 50 class 2 color G
-p 1 action dscp 51 class 3 color G
-p 1 action dscp 52 class 0 color G
-p 1 action dscp 53 class 1 color G
-p 1 action dscp 54 class 2 color G
-p 1 action dscp 55 class 3 color G
-p 1 action dscp 56 class 0 color G
-p 1 action dscp 57 class 1 color G
-p 1 action dscp 58 class 2 color G
-p 1 action dscp 59 class 3 color G
-p 1 action dscp 60 class 0 color G
-p 1 action dscp 61 class 1 color G
-p 1 action dscp 62 class 2 color G
-p 1 action dscp 63 class 3 color G
-
-p 1 action dscp ls
diff --git a/examples/ip_pipeline/config/action.txt b/examples/ip_pipeline/config/action.txt
deleted file mode 100644
index f14207b..0000000
--- a/examples/ip_pipeline/config/action.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-# p <pipelineid> action flow bulk ./config/action.txt
-#
-
-flow 0 meter 0 trtcm 1250000000 1250000000 1000000 1000000 policer 0 g G y Y r R meter 1 trtcm 1250000000 1250000000 1000000 1000000 policer 1 g G y Y r R meter 2 trtcm 1250000000 1250000000 1000000 1000000 policer 2 g G y Y r R meter 3 trtcm 1250000000 1250000000 1000000 1000000 policer 3 g G y Y r R port 0
-flow 1 meter 0 trtcm 1250000000 1250000000 1000000 1000000 policer 0 g G y Y r R meter 1 trtcm 1250000000 1250000000 1000000 1000000 policer 1 g G y Y r R meter 2 trtcm 1250000000 1250000000 1000000 1000000 policer 2 g G y Y r R meter 3 trtcm 1250000000 1250000000 1000000 1000000 policer 3 g G y Y r R port 1
-flow 2 meter 0 trtcm 1250000000 1250000000 1000000 1000000 policer 0 g G y Y r R meter 1 trtcm 1250000000 1250000000 1000000 1000000 policer 1 g G y Y r R meter 2 trtcm 1250000000 1250000000 1000000 1000000 policer 2 g G y Y r R meter 3 trtcm 1250000000 1250000000 1000000 1000000 policer 3 g G y Y r R port 2
-flow 3 meter 0 trtcm 1250000000 1250000000 1000000 1000000 policer 0 g G y Y r R meter 1 trtcm 1250000000 1250000000 1000000 1000000 policer 1 g G y Y r R meter 2 trtcm 1250000000 1250000000 1000000 1000000 policer 2 g G y Y r R meter 3 trtcm 1250000000 1250000000 1000000 1000000 policer 3 g G y Y r R port 3
diff --git a/examples/ip_pipeline/config/diagram-generator.py b/examples/ip_pipeline/config/diagram-generator.py
deleted file mode 100755
index d9efc75..0000000
--- a/examples/ip_pipeline/config/diagram-generator.py
+++ /dev/null
@@ -1,317 +0,0 @@
-#!/usr/bin/env python
-# SPDX-License-Identifier: BSD-3-Clause
-# Copyright(c) 2016 Intel Corporation
-
-#
-# This script creates a visual representation for a configuration file used by
-# the DPDK ip_pipeline application.
-#
-# The input configuration file is translated to an output file in DOT syntax,
-# which is then used to create the image file using graphviz
-# (www.graphviz.org).
-#
-
-from __future__ import print_function
-import argparse
-import re
-import os
-
-#
-# Command to generate the image file
-#
-DOT_COMMAND = 'dot -Gsize=20,30 -Tpng %s > %s'
-
-#
-# Layout of generated DOT file
-#
-DOT_INTRO = \
-    '#\n# Command to generate image file:\n# \t%s\n#\n\n'
-DOT_GRAPH_BEGIN = \
-    'digraph g {\n  graph [ splines = true rankdir = "LR" ]\n'
-DOT_NODE_LINK_RX = \
-    '  "%s RX" [ shape = box style = filled fillcolor = yellowgreen ]\n'
-DOT_NODE_LINK_TX = \
-    '  "%s TX" [ shape = box style = filled fillcolor = yellowgreen ]\n'
-DOT_NODE_KNI_RX = \
-    '  "%s RX" [ shape = box style = filled fillcolor = orange ]\n'
-DOT_NODE_KNI_TX = \
-    '  "%s TX" [ shape = box style = filled fillcolor = orange ]\n'
-DOT_NODE_TAP_RX = \
-    '  "%s RX" [ shape = box style = filled fillcolor = gold ]\n'
-DOT_NODE_TAP_TX = \
-    '  "%s TX" [ shape = box style = filled fillcolor = gold ]\n'
-DOT_NODE_SOURCE = \
-    '  "%s" [ shape = box style = filled fillcolor = darkgreen ]\n'
-DOT_NODE_SINK = \
-    '  "%s" [ shape = box style = filled fillcolor = peachpuff ]\n'
-DOT_NODE_PIPELINE = \
-    '  "%s" [ shape = box style = filled fillcolor = royalblue ]\n'
-DOT_EDGE_PKTQ = \
-    '  "%s" -> "%s" [ label = "%s" color = gray ]\n'
-DOT_GRAPH_END = \
-    '}\n'
-
-# Relationships between the graph nodes and the graph edges:
-#
-# Edge ID | Edge Label | Writer Node | Reader Node   | Dependencies
-# --------+------------+-------------+---------------+--------------
-# RXQx.y  | RXQx.y     | LINKx       | PIPELINEz     | LINKx
-# TXQx.y  | TXQx.y     | PIPELINEz   | LINKx         | LINKx
-# SWQx    | SWQx       | PIPELINEy   | PIPELINEz     | -
-# TMx     | TMx        | PIPELINEy   | PIPELINEz     | LINKx
-# KNIx RX | KNIx       | KNIx RX     | PIPELINEy     | KNIx, LINKx
-# KNIx TX | KNIx       | PIPELINEy   | KNIx TX       | KNIx, LINKx
-# TAPx RX | TAPx       | TAPx RX     | PIPELINEy     | TAPx
-# TAPx TX | TAPx       | PIPELINEy   | TAPx TX       | TAPx
-# SOURCEx | SOURCEx    | SOURCEx     | PIPELINEy     | SOURCEx
-# SINKx   | SINKx      | PIPELINEy   | SINKx         | SINKx
-
-
-#
-# Parse the input configuration file to detect the graph nodes and edges
-#
-def process_config_file(cfgfile):
-    edges = {}
-    links = set()
-    knis = set()
-    taps = set()
-    sources = set()
-    sinks = set()
-    pipelines = set()
-    pipeline = ''
-
-    dotfile = cfgfile + '.txt'
-    imgfile = cfgfile + '.png'
-
-    #
-    # Read configuration file
-    #
-    lines = open(cfgfile, 'r')
-    for line in lines:
-        # Remove any leading and trailing white space characters
-        line = line.strip()
-
-        # Remove any comment at end of line
-        line, sep, tail = line.partition(';')
-
-        # Look for next "PIPELINE" section
-        match = re.search(r'\[(PIPELINE\d+)\]', line)
-        if match:
-            pipeline = match.group(1)
-            continue
-
-        # Look for next "pktq_in" section entry
-        match = re.search(r'pktq_in\s*=\s*(.+)', line)
-        if match:
-            pipelines.add(pipeline)
-            for q in re.findall('\S+', match.group(1)):
-                match_rxq = re.search(r'^RXQ(\d+)\.\d+$', q)
-                match_swq = re.search(r'^SWQ\d+$', q)
-                match_tm = re.search(r'^TM(\d+)$', q)
-                match_kni = re.search(r'^KNI(\d+)$', q)
-                match_tap = re.search(r'^TAP\d+$', q)
-                match_source = re.search(r'^SOURCE\d+$', q)
-
-                # Set ID for the current packet queue (graph edge)
-                q_id = ''
-                if match_rxq or match_swq or match_tm or match_source:
-                    q_id = q
-                elif match_kni or match_tap:
-                    q_id = q + ' RX'
-                else:
-                    print('Error: Unrecognized pktq_in element "%s"' % q)
-                    return
-
-                # Add current packet queue to the set of graph edges
-                if q_id not in edges:
-                    edges[q_id] = {}
-                if 'label' not in edges[q_id]:
-                    edges[q_id]['label'] = q
-                if 'readers' not in edges[q_id]:
-                    edges[q_id]['readers'] = []
-                if 'writers' not in edges[q_id]:
-                    edges[q_id]['writers'] = []
-
-                # Add reader for the new edge
-                edges[q_id]['readers'].append(pipeline)
-
-                # Check for RXQ
-                if match_rxq:
-                    link = 'LINK' + str(match_rxq.group(1))
-                    edges[q_id]['writers'].append(link + ' RX')
-                    links.add(link)
-                    continue
-
-                # Check for SWQ
-                if match_swq:
-                    continue
-
-                # Check for TM
-                if match_tm:
-                    link = 'LINK' + str(match_tm.group(1))
-                    links.add(link)
-                    continue
-
-                # Check for KNI
-                if match_kni:
-                    link = 'LINK' + str(match_kni.group(1))
-                    edges[q_id]['writers'].append(q_id)
-                    knis.add(q)
-                    links.add(link)
-                    continue
-
-                # Check for TAP
-                if match_tap:
-                    edges[q_id]['writers'].append(q_id)
-                    taps.add(q)
-                    continue
-
-                # Check for SOURCE
-                if match_source:
-                    edges[q_id]['writers'].append(q)
-                    sources.add(q)
-                    continue
-
-                continue
-
-        # Look for next "pktq_out" section entry
-        match = re.search(r'pktq_out\s*=\s*(.+)', line)
-        if match:
-            for q in re.findall('\S+', match.group(1)):
-                match_txq = re.search(r'^TXQ(\d+)\.\d+$', q)
-                match_swq = re.search(r'^SWQ\d+$', q)
-                match_tm = re.search(r'^TM(\d+)$', q)
-                match_kni = re.search(r'^KNI(\d+)$', q)
-                match_tap = re.search(r'^TAP(\d+)$', q)
-                match_sink = re.search(r'^SINK(\d+)$', q)
-
-                # Set ID for the current packet queue (graph edge)
-                q_id = ''
-                if match_txq or match_swq or match_tm or match_sink:
-                    q_id = q
-                elif match_kni or match_tap:
-                    q_id = q + ' TX'
-                else:
-                    print('Error: Unrecognized pktq_out element "%s"' % q)
-                    return
-
-                # Add current packet queue to the set of graph edges
-                if q_id not in edges:
-                    edges[q_id] = {}
-                if 'label' not in edges[q_id]:
-                    edges[q_id]['label'] = q
-                if 'readers' not in edges[q_id]:
-                    edges[q_id]['readers'] = []
-                if 'writers' not in edges[q_id]:
-                    edges[q_id]['writers'] = []
-
-                # Add writer for the new edge
-                edges[q_id]['writers'].append(pipeline)
-
-                # Check for TXQ
-                if match_txq:
-                    link = 'LINK' + str(match_txq.group(1))
-                    edges[q_id]['readers'].append(link + ' TX')
-                    links.add(link)
-                    continue
-
-                # Check for SWQ
-                if match_swq:
-                    continue
-
-                # Check for TM
-                if match_tm:
-                    link = 'LINK' + str(match_tm.group(1))
-                    links.add(link)
-                    continue
-
-                # Check for KNI
-                if match_kni:
-                    link = 'LINK' + str(match_kni.group(1))
-                    edges[q_id]['readers'].append(q_id)
-                    knis.add(q)
-                    links.add(link)
-                    continue
-
-                # Check for TAP
-                if match_tap:
-                    edges[q_id]['readers'].append(q_id)
-                    taps.add(q)
-                    continue
-
-                # Check for SINK
-                if match_sink:
-                    edges[q_id]['readers'].append(q)
-                    sinks.add(q)
-                    continue
-
-                continue
-
-    #
-    # Write DOT file
-    #
-    print('Creating DOT file "%s" ...' % dotfile)
-    dot_cmd = DOT_COMMAND % (dotfile, imgfile)
-    file = open(dotfile, 'w')
-    file.write(DOT_INTRO % dot_cmd)
-    file.write(DOT_GRAPH_BEGIN)
-
-    # Write the graph nodes to the DOT file
-    for l in sorted(links):
-        file.write(DOT_NODE_LINK_RX % l)
-        file.write(DOT_NODE_LINK_TX % l)
-    for k in sorted(knis):
-        file.write(DOT_NODE_KNI_RX % k)
-        file.write(DOT_NODE_KNI_TX % k)
-    for t in sorted(taps):
-        file.write(DOT_NODE_TAP_RX % t)
-        file.write(DOT_NODE_TAP_TX % t)
-    for s in sorted(sources):
-        file.write(DOT_NODE_SOURCE % s)
-    for s in sorted(sinks):
-        file.write(DOT_NODE_SINK % s)
-    for p in sorted(pipelines):
-        file.write(DOT_NODE_PIPELINE % p)
-
-    # Write the graph edges to the DOT file
-    for q in sorted(edges.keys()):
-        rw = edges[q]
-        if 'writers' not in rw:
-            print('Error: "%s" has no writer' % q)
-            return
-        if 'readers' not in rw:
-            print('Error: "%s" has no reader' % q)
-            return
-        for w in rw['writers']:
-            for r in rw['readers']:
-                file.write(DOT_EDGE_PKTQ % (w, r, rw['label']))
-
-    file.write(DOT_GRAPH_END)
-    file.close()
-
-    #
-    # Execute the DOT command to create the image file
-    #
-    print('Creating image file "%s" ...' % imgfile)
-    if os.system('which dot > /dev/null'):
-        print('Error: Unable to locate "dot" executable.'
-              'Please install the "graphviz" package (www.graphviz.org).')
-        return
-
-    os.system(dot_cmd)
-
-
-if __name__ == '__main__':
-    parser = argparse.ArgumentParser(description='Create diagram for IP '
-                                                 'pipeline configuration '
-                                                 'file.')
-
-    parser.add_argument(
-        '-f',
-        '--file',
-        help='input configuration file (e.g. "ip_pipeline.cfg")',
-        required=True)
-
-    args = parser.parse_args()
-
-    process_config_file(args.file)
diff --git a/examples/ip_pipeline/config/edge_router_downstream.cfg b/examples/ip_pipeline/config/edge_router_downstream.cfg
deleted file mode 100644
index c6b4e1f..0000000
--- a/examples/ip_pipeline/config/edge_router_downstream.cfg
+++ /dev/null
@@ -1,97 +0,0 @@
-;   BSD LICENSE
-;
-;   Copyright(c) 2015-2016 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.
-
-
-;   An edge router typically sits between two networks such as the provider
-;   core network and the provider access network. A typical packet processing
-;   pipeline for the downstream traffic (i.e. traffic from core to access
-;   network) contains the following functional blocks: Packet RX & Routing,
-;   Traffic management and Packet TX. The input packets are assumed to be
-;   IPv4, while the output packets are Q-in-Q IPv4.
-;
-;  A simple implementation for this functional pipeline is presented below.
-;
-;                  Packet Rx &                Traffic Management               Packet Tx
-;                   Routing                    (Pass-Through)                (Pass-Through)
-;             _____________________  SWQ0  ______________________  SWQ4  _____________________
-; RXQ0.0 --->|                     |----->|                      |----->|                     |---> TXQ0.0
-;            |                     | SWQ1 |                      | SWQ5 |                     |
-; RXQ1.0 --->|                     |----->|                      |----->|                     |---> TXQ1.0
-;            |        (P1)         | SWQ2 |         (P2)         | SWQ6 |        (P3)         |
-; RXQ2.0 --->|                     |----->|                      |----->|                     |---> TXQ2.0
-;            |                     | SWQ3 |                      | SWQ7 |                     |
-; RXQ3.0 --->|                     |----->|                      |----->|                     |---> TXQ3.0
-;            |_____________________|      |______________________|      |_____________________|
-;                       |                  |  ^  |  ^  |  ^  |  ^
-;                       |                  |__|  |__|  |__|  |__|
-;                       +--> SINK0          TM0   TM1   TM2   TM3
-;                      (Default)
-;
-; Input packet: Ethernet/IPv4
-; Output packet: Ethernet/QinQ/IPv4
-;
-; Packet buffer layout:
-; #	Field Name		Offset (Bytes)	Size (Bytes)
-; 0	Mbuf			0 		128
-; 1	Headroom		128 		128
-; 2	Ethernet header		256 		14
-; 3	IPv4 header		270 		20
-
-[EAL]
-log_level = 0
-
-[PIPELINE0]
-type = MASTER
-core = 0
-
-[PIPELINE1]
-type = ROUTING
-core = 1
-pktq_in = RXQ0.0 RXQ1.0 RXQ2.0 RXQ3.0
-pktq_out = SWQ0 SWQ1 SWQ2 SWQ3 SINK0
-encap = ethernet_qinq
-qinq_sched = test
-ip_hdr_offset = 270
-
-[PIPELINE2]
-type = PASS-THROUGH
-core = 2
-pktq_in = SWQ0 SWQ1 SWQ2 SWQ3 TM0 TM1 TM2 TM3
-pktq_out = TM0 TM1 TM2 TM3 SWQ4 SWQ5 SWQ6 SWQ7
-
-[PIPELINE3]
-type = PASS-THROUGH
-core = 3
-pktq_in = SWQ4 SWQ5 SWQ6 SWQ7
-pktq_out = TXQ0.0 TXQ1.0 TXQ2.0 TXQ3.0
-
-[MEMPOOL0]
-pool_size = 2M
diff --git a/examples/ip_pipeline/config/edge_router_downstream.sh b/examples/ip_pipeline/config/edge_router_downstream.sh
deleted file mode 100644
index 67c3a0d..0000000
--- a/examples/ip_pipeline/config/edge_router_downstream.sh
+++ /dev/null
@@ -1,13 +0,0 @@
-#
-# run ./config/edge_router_downstream.sh
-#
-
-################################################################################
-# Routing: Ether QinQ, ARP off
-################################################################################
-p 1 route add default 4 #SINK0
-p 1 route add 0.0.0.0 10 port 0 ether a0:b0:c0:d0:e0:f0 qinq 256 257
-p 1 route add 0.64.0.0 10 port 1 ether a1:b1:c1:d1:e1:f1 qinq 258 259
-p 1 route add 0.128.0.0 10 port 2 ether a2:b2:c2:d2:e2:f2 qinq 260 261
-p 1 route add 0.192.0.0 10 port 3 ether a3:b3:c3:d3:e3:f3 qinq 262 263
-#p 1 route ls
diff --git a/examples/ip_pipeline/config/edge_router_upstream.cfg b/examples/ip_pipeline/config/edge_router_upstream.cfg
deleted file mode 100644
index dea42b9..0000000
--- a/examples/ip_pipeline/config/edge_router_upstream.cfg
+++ /dev/null
@@ -1,124 +0,0 @@
-;   BSD LICENSE
-;
-;   Copyright(c) 2015-2016 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.
-
-
-;   An edge router typically sits between two networks such as the provider
-;   core network and the provider access network. A typical packet processing
-;   pipeline for the upstream traffic (i.e. traffic from access to core
-;   network) contains the following functional blocks: Packet RX & Firewall,
-;   Flow classification, Metering, Routing and Packet TX. The input packets
-;   are assumed to be Q-in-Q IPv4, while the output packets are MPLS IPv4
-;  (with variable number of labels per route).
-;
-;   A simple implementation for this functional pipeline is presented below.
-;
-;             Packet RX &       Pass-Through    Flow Classification   Flow Actions         Routing
-:              Firewall
-;             __________  SWQ0   __________  SWQ4   __________  SWQ8   __________  SWQ12  __________
-; RXQ0.0 --->|          |------>|          |------>|          |------>|          |------>|          |------> TXQ0.0
-;            |          | SWQ1  |          | SWQ5  |          | SWQ9  |          | SWQ13 |          |
-; RXQ1.0 --->|          |------>|          |------>|          |------>|          |------>|          |------> TXQ1.0
-;            |   (P1)   | SWQ2  |  (P2)    | SWQ6  |   (P3)   | SWQ10 |   (P4)   | SWQ14 |   (P5)   |
-; RXQ2.0 --->|          |------>|          |------>|          |------>|          |------>|          |------> TXQ2.0
-;            |          | SWQ3  |          | SWQ7  |          | SWQ11 |          | SWQ15 |          |
-; RXQ3.0 --->|          |------>|          |------>|          |------>|          |------>|          |------> TXQ3.0
-;            |__________|       |__________|       |__________|       |__________|       |__________|
-;                 |                                     |                                     |
-;                 +--> SINK0 (Default)                  +--> SINK1 (Default)                  +--> SINK2 (Default)
-;
-; Input packet: Ethernet/QinQ/IPv4
-; Output packet: Ethernet/MPLS/IPv4
-;
-; Packet buffer layout:
-; #	Field Name		Offset (Bytes)	Size (Bytes)
-; 0	Mbuf			0 		128
-; 1	Headroom		128 		128
-; 2	Ethernet header		256 		14
-; 3     QinQ header             270             8
-; 4	IPv4 header		278 		20
-
-[EAL]
-log_level = 0
-
-[PIPELINE0]
-type = MASTER
-core = 0
-
-[PIPELINE1]
-type = FIREWALL
-core = 1
-pktq_in = RXQ0.0 RXQ1.0 RXQ2.0 RXQ3.0
-pktq_out = SWQ0 SWQ1 SWQ2 SWQ3 SINK0
-n_rules = 4096
-pkt_type = qinq_ipv4
-
-[PIPELINE2]
-type = PASS-THROUGH
-core = 2
-pktq_in = SWQ0 SWQ1 SWQ2 SWQ3
-pktq_out = SWQ4 SWQ5 SWQ6 SWQ7
-dma_size = 8
-dma_dst_offset = 128
-dma_src_offset = 268; 1st Ethertype offset
-dma_src_mask = 00000FFF00000FFF; qinq
-dma_hash_offset = 136; dma_dst_offset + dma_size
-
-[PIPELINE3]
-type = FLOW_CLASSIFICATION
-core = 2
-pktq_in = SWQ4 SWQ5 SWQ6 SWQ7
-pktq_out = SWQ8 SWQ9 SWQ10 SWQ11 SINK1
-n_flows = 65536
-key_size = 8; dma_size
-key_offset = 128; dma_dst_offset
-hash_offset = 136; dma_hash_offset
-flowid_offset = 192
-
-[PIPELINE4]
-type = FLOW_ACTIONS
-core = 3
-pktq_in = SWQ8 SWQ9 SWQ10 SWQ11
-pktq_out = SWQ12 SWQ13 SWQ14 SWQ15
-n_flows = 65536
-n_meters_per_flow = 1
-flow_id_offset = 192; flowid_offset
-ip_hdr_offset = 278
-color_offset = 196; flowid_offset + sizeof(flow_id)
-
-[PIPELINE5]
-type = ROUTING
-core = 4
-pktq_in = SWQ12 SWQ13 SWQ14 SWQ15
-pktq_out = TXQ0.0 TXQ1.0 TXQ2.0 TXQ3.0 SINK2
-encap = ethernet_mpls
-mpls_color_mark = yes
-ip_hdr_offset = 278
-color_offset = 196; flowid_offset + sizeof(flow_id)
diff --git a/examples/ip_pipeline/config/edge_router_upstream.sh b/examples/ip_pipeline/config/edge_router_upstream.sh
deleted file mode 100644
index 5d574c1..0000000
--- a/examples/ip_pipeline/config/edge_router_upstream.sh
+++ /dev/null
@@ -1,33 +0,0 @@
-#
-# run ./config/edge_router_upstream.sh
-#
-
-################################################################################
-# Firewall
-################################################################################
-p 1 firewall add default 4 #SINK0
-p 1 firewall add bulk ./config/edge_router_upstream_firewall.txt
-#p 1 firewall ls
-
-################################################################################
-# Flow Classification
-################################################################################
-p 3 flow add default 4 #SINK1
-p 3 flow add qinq bulk ./config/edge_router_upstream_flow.txt
-#p 3 flow ls
-
-################################################################################
-# Flow Actions - Metering and Policing
-################################################################################
-p 4 action flow bulk ./config/edge_router_upstream_action.txt
-#p 4 action flow ls
-
-################################################################################
-# Routing: Ether MPLS, ARP off
-################################################################################
-p 5 route add default 4 #SINK2
-p 5 route add 0.0.0.0 10 port 0 ether a0:b0:c0:d0:e0:f0 mpls 0:1
-p 5 route add 0.64.0.0 10 port 1 ether a1:b1:c1:d1:e1:f1 mpls 10:11
-p 5 route add 0.128.0.0 10 port 2 ether a2:b2:c2:d2:e2:f2 mpls 20:21
-p 5 route add 0.192.0.0 10 port 3 ether a3:b3:c3:d3:e3:f3 mpls 30:31
-#p 5 route ls
diff --git a/examples/ip_pipeline/config/firewall.cfg b/examples/ip_pipeline/config/firewall.cfg
deleted file mode 100644
index 2f5dd9f..0000000
--- a/examples/ip_pipeline/config/firewall.cfg
+++ /dev/null
@@ -1,68 +0,0 @@
-;   BSD LICENSE
-;
-;   Copyright(c) 2015-2016 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.
-
-;             _______________
-; RXQ0.0 --->|               |---> TXQ0.0
-;            |               |
-; RXQ1.0 --->|               |---> TXQ1.0
-;            |   Firewall    |
-; RXQ2.0 --->|               |---> TXQ2.0
-;            |               |
-; RXQ3.0 --->|               |---> TXQ3.0
-;            |_______________|
-;                    |
-;                    +-----------> SINK0 (default rule)
-;
-; Input packet: Ethernet/IPv4
-;
-; Packet buffer layout:
-; #	Field Name		Offset (Bytes)	Size (Bytes)
-; 0	Mbuf			0 		128
-; 1	Headroom		128 		128
-; 2	Ethernet header		256 		14
-; 3	IPv4 header		270 		20
-
-[EAL]
-log_level = 0
-
-[PIPELINE0]
-type = MASTER
-core = 0
-
-[PIPELINE1]
-type = FIREWALL
-core = 1
-pktq_in = RXQ0.0 RXQ1.0 RXQ2.0 RXQ3.0
-pktq_out = TXQ0.0 TXQ1.0 TXQ2.0 TXQ3.0 SINK0
-n_rules = 4096
-pkt_type = ipv4
-;pkt_type = vlan_ipv4
-;pkt_type = qinq_ipv4
diff --git a/examples/ip_pipeline/config/firewall.sh b/examples/ip_pipeline/config/firewall.sh
deleted file mode 100644
index c83857e..0000000
--- a/examples/ip_pipeline/config/firewall.sh
+++ /dev/null
@@ -1,13 +0,0 @@
-#
-# run ./config/firewall.sh
-#
-
-p 1 firewall add default 4 #SINK0
-p 1 firewall add priority 1 ipv4 0.0.0.0 0 100.0.0.0 10 0 65535 0 65535 6 0xF port 0
-p 1 firewall add priority 1 ipv4 0.0.0.0 0 100.64.0.0 10 0 65535 0 65535 6 0xF port 1
-p 1 firewall add priority 1 ipv4 0.0.0.0 0 100.128.0.0 10 0 65535 0 65535 6 0xF port 2
-p 1 firewall add priority 1 ipv4 0.0.0.0 0 100.192.0.0 10 0 65535 0 65535 6 0xF port 3
-
-#p 1 firewall add bulk ./config/firewall.txt
-
-p 1 firewall ls
diff --git a/examples/ip_pipeline/config/firewall.txt b/examples/ip_pipeline/config/firewall.txt
deleted file mode 100644
index 54cfffd..0000000
--- a/examples/ip_pipeline/config/firewall.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# p <pipelineid> firewall add bulk ./config/firewall.txt
-# p <pipelineid> firewall del bulk ./config/firewall.txt
-#
-
-priority 1 ipv4 0.0.0.0 0 100.0.0.0 10 0 65535 0 65535 6 0xF port 0
-priority 1 ipv4 0.0.0.0 0 100.64.0.0 10 0 65535 0 65535 6 0xF port 1
-priority 1 ipv4 0.0.0.0 0 100.128.0.0 10 0 65535 0 65535 6 0xF port 2
-priority 1 ipv4 0.0.0.0 0 100.192.0.0 10 0 65535 0 65535 6 0xF port 3
diff --git a/examples/ip_pipeline/config/flow.cfg b/examples/ip_pipeline/config/flow.cfg
deleted file mode 100644
index cec990a..0000000
--- a/examples/ip_pipeline/config/flow.cfg
+++ /dev/null
@@ -1,72 +0,0 @@
-;   BSD LICENSE
-;
-;   Copyright(c) 2015-2016 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.
-
-;             ________________
-; RXQ0.0 --->|                |---> TXQ0.0
-;            |                |
-; RXQ1.0 --->|                |---> TXQ1.0
-;            |      Flow      |
-; RXQ2.0 --->| Classification |---> TXQ2.0
-;            |                |
-; RXQ3.0 --->|                |---> TXQ3.0
-;            |________________|
-;                    |
-;                    +-----------> SINK0 (flow lookup miss)
-;
-; Input packet: Ethernet/IPv4
-;
-; Packet buffer layout:
-; #	Field Name		Offset (Bytes)	Size (Bytes)
-; 0	Mbuf			0		128
-; 1	Headroom		128 		128
-; 2	Ethernet header		256 		14
-; 3	QinQ/IPv4/IPv6 header	270 		8/20/40
-
-[EAL]
-log_level = 0
-
-[PIPELINE0]
-type = MASTER
-core = 0
-
-[PIPELINE1]
-type = FLOW_CLASSIFICATION
-core = 1
-pktq_in = RXQ0.0 RXQ1.0 RXQ2.0 RXQ3.0
-pktq_out = TXQ0.0 TXQ1.0 TXQ2.0 TXQ3.0 SINK0
-n_flows = 65536
-;key_size = 8                ; QinQ key size
-;key_offset = 268            ; QinQ key offset
-;key_mask = 00000FFF00000FFF ; QinQ key mask
-key_size = 16                               ; IPv4 5-tuple key size
-key_offset = 278                            ; IPv4 5-tuple key offset
-key_mask = 00FF0000FFFFFFFFFFFFFFFFFFFFFFFF ; IPv4 5-tuple key mask
-flowid_offset = 128
diff --git a/examples/ip_pipeline/config/flow.sh b/examples/ip_pipeline/config/flow.sh
deleted file mode 100644
index 489c707..0000000
--- a/examples/ip_pipeline/config/flow.sh
+++ /dev/null
@@ -1,25 +0,0 @@
-#
-# run ./config/flow.sh
-#
-
-################################################################################
-# Flow classification (QinQ)
-################################################################################
-#p 1 flow add default 4 #SINK0
-#p 1 flow add qinq 100 200 port 0 id 0
-#p 1 flow add qinq 101 201 port 1 id 1
-#p 1 flow add qinq 102 202 port 2 id 2
-#p 1 flow add qinq 103 203 port 3 id 3
-
-#p 1 flow add qinq bulk ./config/flow.txt
-
-################################################################################
-# Flow classification (IPv4 5-tuple)
-################################################################################
-p 1 flow add default 4 #SINK0
-p 1 flow add ipv4 100.0.0.10 200.0.0.10 100 200 6 port 0 id 0
-p 1 flow add ipv4 100.0.0.11 200.0.0.11 101 201 6 port 1 id 1
-p 1 flow add ipv4 100.0.0.12 200.0.0.12 102 202 6 port 2 id 2
-p 1 flow add ipv4 100.0.0.13 200.0.0.13 103 203 6 port 3 id 3
-
-#p 1 flow add ipv4 bulk ./config/flow.txt
diff --git a/examples/ip_pipeline/config/flow.txt b/examples/ip_pipeline/config/flow.txt
deleted file mode 100644
index c1a141d..0000000
--- a/examples/ip_pipeline/config/flow.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-#
-# p <pipelineid> flow add qinq bulk ./config/flow.txt
-#
-
-#qinq 100 200 port 0 id 0
-#qinq 101 201 port 1 id 1
-#qinq 102 202 port 2 id 2
-#qinq 103 203 port 3 id 3
-
-#
-# p <pipelineid> flow add ipv4 bulk ./config/flow.txt
-#
-
-ipv4 100.0.0.10 200.0.0.10 100 200 6 port 0 id 0
-ipv4 100.0.0.11 200.0.0.11 101 201 6 port 1 id 1
-ipv4 100.0.0.12 200.0.0.12 102 202 6 port 2 id 2
-ipv4 100.0.0.13 200.0.0.13 103 203 6 port 3 id 3
diff --git a/examples/ip_pipeline/config/ip_pipeline.cfg b/examples/ip_pipeline/config/ip_pipeline.cfg
deleted file mode 100644
index 095ed25..0000000
--- a/examples/ip_pipeline/config/ip_pipeline.cfg
+++ /dev/null
@@ -1,9 +0,0 @@
-[PIPELINE0]
-type = MASTER
-core = 0
-
-[PIPELINE1]
-type = PASS-THROUGH
-core = 1
-pktq_in = RXQ0.0 RXQ1.0 RXQ2.0 RXQ3.0
-pktq_out = TXQ0.0 TXQ1.0 TXQ2.0 TXQ3.0
diff --git a/examples/ip_pipeline/config/ip_pipeline.sh b/examples/ip_pipeline/config/ip_pipeline.sh
deleted file mode 100644
index 4fca259..0000000
--- a/examples/ip_pipeline/config/ip_pipeline.sh
+++ /dev/null
@@ -1,5 +0,0 @@
-#
-#run config/ip_pipeline.sh
-#
-
-p 1 ping
diff --git a/examples/ip_pipeline/config/kni.cfg b/examples/ip_pipeline/config/kni.cfg
deleted file mode 100644
index cea208b..0000000
--- a/examples/ip_pipeline/config/kni.cfg
+++ /dev/null
@@ -1,67 +0,0 @@
-;   BSD LICENSE
-;
-;   Copyright(c) 2016 Intel Corporation.
-;   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.
-;
-;             ______________          ______________________
-;            |              |  KNI0  |                      |
-; RXQ0.0 --->|              |------->|--+                   |
-;            |              |  KNI1  |  | br0               |
-; TXQ1.0 <---|              |<-------|<-+                   |
-;            | Pass-through |        |     Linux Kernel     |
-;            |     (P1)     |        |     Network Stack    |
-;            |              |  KNI1  |                      |
-; RXQ1.0 --->|              |------->|--+                   |
-;            |              |  KNI0  |  | br0               |
-; TXQ0.0 <---|              |<-------|<-+                   |
-;            |______________|        |______________________|
-;
-; Insert Linux kernel KNI module:
-;    [Linux]$ insmod rte_kni.ko
-;
-; Configure Linux kernel bridge between KNI0 and KNI1 interfaces:
-;    [Linux]$ ifconfig KNI0 up
-;    [Linux]$ ifconfig KNI1 up
-;    [Linux]$ brctl addbr "br0"
-;    [Linux]$ brctl addif br0 KNI0
-;    [Linux]$ brctl addif br0 KNI1
-;    [Linux]$ ifconfig br0 up
-
-[EAL]
-log_level = 0
-
-[PIPELINE0]
-type = MASTER
-core = 0
-
-[PIPELINE1]
-type = PASS-THROUGH
-core = 1
-pktq_in = RXQ0.0 KNI1 RXQ1.0 KNI0
-pktq_out = KNI0 TXQ1.0 KNI1 TXQ0.0
diff --git a/examples/ip_pipeline/config/l2fwd.cfg b/examples/ip_pipeline/config/l2fwd.cfg
deleted file mode 100644
index a1df9e6..0000000
--- a/examples/ip_pipeline/config/l2fwd.cfg
+++ /dev/null
@@ -1,58 +0,0 @@
-;   BSD LICENSE
-;
-;   Copyright(c) 2015-2016 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.
-
-;
-; The pass-through pipeline below connects the input ports to the output ports
-; as follows: RXQ0.0 -> TXQ1.0, RXQ1.0 -> TXQ0.0, RXQ2.0 -> TXQ3.0 and
-; RXQ3.0 -> TXQ2.0.
-;             ________________
-; RXQ0.0 --->|................|---> TXQ1.0
-;            |                |
-; RXQ1.0 --->|................|---> TXQ0.0
-;            |  Pass-through  |
-; RXQ2.0 --->|................|---> TXQ3.0
-;            |                |
-; RXQ3.0 --->|................|---> TXQ2.0
-;            |________________|
-;
-
-[EAL]
-log_level = 0
-
-[PIPELINE0]
-type = MASTER
-core = 0
-
-[PIPELINE1]
-type = PASS-THROUGH
-core = 1
-pktq_in = RXQ0.0 RXQ1.0 RXQ2.0 RXQ3.0
-pktq_out = TXQ1.0 TXQ0.0 TXQ3.0 TXQ2.0
diff --git a/examples/ip_pipeline/config/l3fwd.cfg b/examples/ip_pipeline/config/l3fwd.cfg
deleted file mode 100644
index 02c8f36..0000000
--- a/examples/ip_pipeline/config/l3fwd.cfg
+++ /dev/null
@@ -1,68 +0,0 @@
-;   BSD LICENSE
-;
-;   Copyright(c) 2015-2016 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.
-
-;             _______________
-; RXQ0.0 --->|               |---> TXQ0.0
-;            |               |
-; RXQ1.0 --->|               |---> TXQ1.0
-;            |    Routing    |
-; RXQ2.0 --->|               |---> TXQ2.0
-;            |               |
-; RXQ3.0 --->|               |---> TXQ3.0
-;            |_______________|
-;                    |
-;                    +-----------> SINK0 (route miss)
-;
-; Input packet: Ethernet/IPv4
-;
-; Packet buffer layout:
-; #	Field Name		Offset (Bytes)	Size (Bytes)
-; 0	Mbuf			0 		128
-; 1	Headroom		128 		128
-; 2	Ethernet header		256 		14
-; 3	IPv4 header		270 		20
-
-[EAL]
-log_level = 0
-
-[PIPELINE0]
-type = MASTER
-core = 0
-
-[PIPELINE1]
-type = ROUTING
-core = 1
-pktq_in = RXQ0.0 RXQ1.0 RXQ2.0 RXQ3.0
-pktq_out = TXQ0.0 TXQ1.0 TXQ2.0 TXQ3.0 SINK0
-encap = ethernet
-;encap = ethernet_qinq
-;encap = ethernet_mpls
-ip_hdr_offset = 270
diff --git a/examples/ip_pipeline/config/l3fwd.sh b/examples/ip_pipeline/config/l3fwd.sh
deleted file mode 100644
index 47406aa..0000000
--- a/examples/ip_pipeline/config/l3fwd.sh
+++ /dev/null
@@ -1,33 +0,0 @@
-#
-# run ./config/l3fwd.sh
-#
-
-################################################################################
-# Routing: encap = ethernet, arp = off
-################################################################################
-p 1 route add default 4 #SINK0
-p 1 route add 100.0.0.0 10 port 0 ether a0:b0:c0:d0:e0:f0
-p 1 route add 100.64.0.0 10 port 1 ether a1:b1:c1:d1:e1:f1
-p 1 route add 100.128.0.0 10 port 2 ether a2:b2:c2:d2:e2:f2
-p 1 route add 100.192.0.0 10 port 3 ether a3:b3:c3:d3:e3:f3
-p 1 route ls
-
-################################################################################
-# Routing: encap = ethernet_qinq, arp = off
-################################################################################
-#p 1 route add default 4 #SINK0
-#p 1 route add 100.0.0.0 10 port 0 ether a0:b0:c0:d0:e0:f0 qinq 1000 2000
-#p 1 route add 100.64.0.0 10 port 1 ether a1:b1:c1:d1:e1:f1 qinq 1001 2001
-#p 1 route add 100.128.0.0 10 port 2 ether a2:b2:c2:d2:e2:f2 qinq 1002 2002
-#p 1 route add 100.192.0.0 10 port 3 ether a3:b3:c3:d3:e3:f3 qinq 1003 2003
-#p 1 route ls
-
-################################################################################
-# Routing: encap = ethernet_mpls, arp = off
-################################################################################
-#p 1 route add default 4 #SINK0
-#p 1 route add 100.0.0.0 10 port 0 ether a0:b0:c0:d0:e0:f0 mpls 1000:2000
-#p 1 route add 100.64.0.0 10 port 1 ether a1:b1:c1:d1:e1:f1 mpls 1001:2001
-#p 1 route add 100.128.0.0 10 port 2 ether a2:b2:c2:d2:e2:f2 mpls 1002:2002
-#p 1 route add 100.192.0.0 10 port 3 ether a3:b3:c3:d3:e3:f3 mpls 1003:2003
-#p 1 route ls
diff --git a/examples/ip_pipeline/config/l3fwd_arp.cfg b/examples/ip_pipeline/config/l3fwd_arp.cfg
deleted file mode 100644
index 2c63c8f..0000000
--- a/examples/ip_pipeline/config/l3fwd_arp.cfg
+++ /dev/null
@@ -1,70 +0,0 @@
-;   BSD LICENSE
-;
-;   Copyright(c) 2015-2016 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.
-
-;             _______________
-; RXQ0.0 --->|               |---> TXQ0.0
-;            |               |
-; RXQ1.0 --->|               |---> TXQ1.0
-;            |    Routing    |
-; RXQ2.0 --->|               |---> TXQ2.0
-;            |               |
-; RXQ3.0 --->|               |---> TXQ3.0
-;            |_______________|
-;                    |
-;                    +-----------> SINK0 (route miss)
-;
-; Input packet: Ethernet/IPv4
-;
-; Packet buffer layout:
-; #	Field Name		Offset (Bytes)	Size (Bytes)
-; 0	Mbuf			0 		128
-; 1	Headroom		128 		128
-; 2	Ethernet header		256 		14
-; 3	IPv4 header		270 		20
-
-[EAL]
-log_level = 0
-
-[PIPELINE0]
-type = MASTER
-core = 0
-
-[PIPELINE1]
-type = ROUTING
-core = 1
-pktq_in = RXQ0.0 RXQ1.0 RXQ2.0 RXQ3.0
-pktq_out = TXQ0.0 TXQ1.0 TXQ2.0 TXQ3.0 SINK0
-encap = ethernet
-;encap = ethernet_qinq
-;encap = ethernet_mpls
-n_arp_entries = 1024
-ip_hdr_offset = 270
-arp_key_offset = 128
diff --git a/examples/ip_pipeline/config/l3fwd_arp.sh b/examples/ip_pipeline/config/l3fwd_arp.sh
deleted file mode 100644
index 20bea58..0000000
--- a/examples/ip_pipeline/config/l3fwd_arp.sh
+++ /dev/null
@@ -1,43 +0,0 @@
-#
-# run ./config/l3fwd_arp.sh
-#
-
-################################################################################
-# ARP
-################################################################################
-p 1 arp add default 4 #SINK0
-p 1 arp add 0 10.0.0.1 a0:b0:c0:d0:e0:f0
-p 1 arp add 1 11.0.0.1 a1:b1:c1:d1:e1:f1
-p 1 arp add 2 12.0.0.1 a2:b2:c2:d2:e2:f2
-p 1 arp add 3 13.0.0.1 a3:b3:c3:d3:e3:f3
-p 1 arp ls
-
-################################################################################
-# Routing: encap = ethernet, arp = on
-################################################################################
-p 1 route add default 4 #SINK0
-p 1 route add 100.0.0.0 10 port 0 ether 10.0.0.1
-p 1 route add 100.64.0.0 10 port 1 ether 11.0.0.1
-p 1 route add 100.128.0.0 10 port 2 ether 12.0.0.1
-p 1 route add 100.192.0.0 10 port 3 ether 13.0.0.1
-p 1 route ls
-
-################################################################################
-# Routing: encap = ethernet_qinq, arp = on
-################################################################################
-#p 1 route add default 4 #SINK0
-#p 1 route add 100.0.0.0 10 port 0 ether 10.0.0.1 qinq 1000 2000
-#p 1 route add 100.64.0.0 10 port 1 ether 11.0.0.1 qinq 1001 2001
-#p 1 route add 100.128.0.0 10 port 2 ether 12.0.0.1 qinq 1002 2002
-#p 1 route add 100.192.0.0 10 port 3 ether 13.0.0.1 qinq 1003 2003
-#p 1 route ls
-
-################################################################################
-# Routing: encap = ethernet_mpls, arp = on
-################################################################################
-#p 1 route add default 4 #SINK0
-#p 1 route add 100.0.0.0 10 port 0 ether 10.0.0.1 mpls 1000:2000
-#p 1 route add 100.64.0.0 10 port 1 ether 11.0.0.1 mpls 1001:2001
-#p 1 route add 100.128.0.0 10 port 2 ether 12.0.0.1 mpls 1002:2002
-#p 1 route add 100.192.0.0 10 port 3 ether 13.0.0.1 mpls 1003:2003
-#p 1 route ls
diff --git a/examples/ip_pipeline/config/network_layers.cfg b/examples/ip_pipeline/config/network_layers.cfg
deleted file mode 100644
index 397b5d7..0000000
--- a/examples/ip_pipeline/config/network_layers.cfg
+++ /dev/null
@@ -1,227 +0,0 @@
-;   BSD LICENSE
-;
-;   Copyright(c) 2016 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.
-
-; The diagram below shows how additional protocol components can be plugged into
-; the IP layer implemented by the ip_pipeline application. Pick your favorite
-; open source components for dynamic ARP, ICMP, UDP or TCP termination, etc and
-; connect them through SWQs to the IP infrastructure.
-;
-; The input packets with local destination are sent to the UDP/TCP applications
-; while the input packets with remote destination are routed back to the
-; network. Additional features can easily be added to this setup:
-;  * IP Reassembly: add SWQs with IP reassembly enabled (typically required for
-;    the input traffic with local destination);
-;  * IP Fragmentation: add SWQs with IP fragmentation enabled (typically
-;    required to enforce the MTU for the routed output traffic);
-;  * Traffic Metering: add Flow Action pipeline instances (e.g. for metering the
-;    TCP connections or ICMP input traffic);
-;  * Traffic Management: add TMs for the required output LINKs;
-;  * Protocol encapsulations (QinQ, MPLS) for the output packets: part of the
-;    routing pipeline configuration.
-;
-;                     _________                       _________
-;                    |         |                     |         |
-;                    |   UDP   |                     |   TCP   |
-;                    |   App   |                     |   App   |
-;                    |_________|                     |_________|
-;                       ^   |                           ^   |
-;                     __|___V__                       __|___V__
-;                    |         |  SWQ0 (UDP TX)      |         |  SWQ1 (TCP TX)
-;                    |   UDP   |-------+             |   TCP   |------------+
-;                    |         |       |             |         |            |
-;                    |_________|       |             |_________|            |
-;                         ^            |                  ^                 |
-;                         | SWQ2       |                  | SWQ3            |
-;                         | (UDP RX)   |                  | (TCP RX)        |
-;                     ____|____        |              ____|____             |
-;                    |         |       |             |         |            |
-; RXQ<0..3>.1 ------>|Firewall +--->|  |     +------>|  Flow   +--->|       |
-; (UDP local dest)   |  (P2)   | SINK0 |     |       |  (P3)   |  SINK1     |
-;                    |_________| (Deny)|     |       |_________|  (RST)     |
-; RXQ<0..3>.2 -------------------------|-----+                              |
-; (TCP local dest)                     |                                    |
-;                                      |     +------------------------------+
-;                                      |     |
-;                                     _V_____V_
-;                                    |         |
-;                                    | Routing |                   TXQ<0..3>.0
-; RXQ<0..3>.0 ---------------------->|  & ARP  +----------------------------->
-; (IP remote dest)                   |  (P1)   |
-;                                    |_________|
-;                                      |  ^  |
-;                   SWQ4 +-------------+  |  |  SWQ5 (ARP miss)
-;           (Route miss) |                |  +------------+
-;                        |  +-------------+               |
-;                     ___V__|__   SWQ6                ____V____
-;                    |         |  (ICMP TX)          |         |   TXQ<0..3>.1
-; RXQ<0..3>.3 ------>|  ICMP   |             +------>| Dyn ARP +------------->
-; (IP local dest)    |         |             |       |         |
-;                    |_________|             |       |_________|
-; RXQ<0..3>.4 -------------------------------+
-; (ARP)
-;
-; This configuration file implements the diagram presented below, where the
-; dynamic ARP, ICMP, UDP and TCP components have been stubbed out and replaced
-; with loop-back and packet drop devices.
-;
-;                     _________                       _________
-;                    |         |  SWQ0 (UDP TX)      |         |  SWQ1 (TCP TX)
-;                    |Loobpack |-------+             |Loopback |------------+
-;                    |  (P4)   |       |             |  (P5)   |            |
-;                    |_________|       |             |_________|            |
-;                         ^            |                  ^                 |
-;                         | SWQ2       |                  | SWQ3            |
-;                         | (UDP RX)   |                  | (TCP RX)        |
-;                     ____|____        |              ____|____             |
-;                    |         |       |             |         |            |
-; RXQ<0..3>.1 ------>|Firewall +--->|  |     +------>|  Flow   +--->|       |
-; (UDP local dest)   |  (P2)   | SINK0 |     |       |  (P3)   |  SINK1     |
-;                    |_________| (Deny)|     |       |_________|  (RST)     |
-; RXQ<0..3>.2 -------------------------|-----+                              |
-; (TCP local dest)                     |                                    |
-;                                      |     +------------------------------+
-;                                      |     |
-;                                     _V_____V_
-;                                    |         |
-;                                    | Routing |                   TXQ<0..3>.0
-; RXQ<0..3>.0 ---------------------->|  & ARP  +----------------------------->
-; (IP remote dest)                   |  (P1)   |
-;                                    |_________|
-;                                      |     |
-;                           SINK2 |<---+     +--->| SINK3
-;                           (Route miss)            (ARP miss)
-;
-;                     _________                            _________
-;                    |         |                          |         |
-; RXQ<0..3>.3 ------>|  Drop   +--->| SINK<4..7>  +------>|  Drop   +--->| SINK<8..11>
-; (IP local dest)    |  (P6)   | (IP local dest)  |       |  (P7)   |     (ARP)
-;                    |_________|                  |       |_________|
-; RXQ<0..3>.4 ------------------------------------+
-; (ARP)
-;
-;
-; Input packet: Ethernet/IPv4 or Ethernet/ARP
-; Output packet: Ethernet/IPv4 or Ethernet/ARP
-;
-; Packet buffer layout (for input IPv4 packets):
-; #	Field Name			Offset (Bytes)	Size (Bytes)
-; 0	Mbuf				0				128
-; 1	Headroom			128				128
-; 2	Ethernet header		256				14
-; 3	IPv4 header			270				20
-; 4	ICMP/UDP/TCP header	290				8/8/20
-
-[EAL]
-log_level = 0
-
-[LINK0]
-udp_local_q = 1
-tcp_local_q = 2
-ip_local_q = 3
-arp_q = 4
-
-[LINK1]
-udp_local_q = 1
-tcp_local_q = 2
-ip_local_q = 3
-arp_q = 4
-
-[LINK2]
-udp_local_q = 1
-tcp_local_q = 2
-ip_local_q = 3
-arp_q = 4
-
-[LINK3]
-udp_local_q = 1
-tcp_local_q = 2
-ip_local_q = 3
-arp_q = 4
-
-[PIPELINE0]
-type = MASTER
-core = 0
-
-[PIPELINE1]
-type = ROUTING
-core = 1
-pktq_in = RXQ0.0 RXQ1.0 RXQ2.0 RXQ3.0 SWQ0 SWQ1
-pktq_out = TXQ0.0 TXQ1.0 TXQ2.0 TXQ3.0 SINK2 SINK3
-port_local_dest = 4 ; SINK2 (Drop)
-n_arp_entries = 1000
-ip_hdr_offset = 270
-arp_key_offset = 128
-
-[PIPELINE2]
-type = FIREWALL
-core = 1
-pktq_in = RXQ0.1 RXQ1.1 RXQ2.1 RXQ3.1
-pktq_out = SWQ2 SINK0
-n_rules = 4096
-
-[PIPELINE3]
-type = FLOW_CLASSIFICATION
-core = 1
-pktq_in = RXQ0.2 RXQ1.2 RXQ2.2 RXQ3.2
-pktq_out = SWQ3 SINK1
-n_flows = 65536
-key_size = 16                               ; IPv4 5-tuple key size
-key_offset = 278                            ; IPv4 5-tuple key offset
-key_mask = 00FF0000FFFFFFFFFFFFFFFFFFFFFFFF ; IPv4 5-tuple key mask
-flowid_offset = 128 ; Flow ID effectively acts as TCP socket ID
-
-[PIPELINE4]
-type = PASS-THROUGH ; Loop-back (UDP place-holder)
-core = 1
-pktq_in = SWQ2
-pktq_out = SWQ0
-swap = 282 286 ; IPSRC <-> IPDST
-swap = 290 292 ; PORTSRC <-> PORTDST
-
-[PIPELINE5]
-type = PASS-THROUGH ; Loop-back (TCP place-holder)
-core = 1
-pktq_in = SWQ3
-pktq_out = SWQ1
-swap = 282 286 ; IPSRC <-> IPDST
-swap = 290 292 ; PORTSRC <-> PORTDST
-
-[PIPELINE6]
-type = PASS-THROUGH ; Drop (ICMP place-holder)
-core = 1
-pktq_in = RXQ0.3 RXQ1.3 RXQ2.3 RXQ3.3
-pktq_out = SINK4 SINK5 SINK6 SINK7
-
-[PIPELINE7]
-type = PASS-THROUGH ; Drop (Dynamic ARP place-holder)
-core = 1
-pktq_in = RXQ0.4 RXQ1.4 RXQ2.4 RXQ3.4
-pktq_out = SINK8 SINK9 SINK10 SINK11
diff --git a/examples/ip_pipeline/config/network_layers.sh b/examples/ip_pipeline/config/network_layers.sh
deleted file mode 100644
index 449b006..0000000
--- a/examples/ip_pipeline/config/network_layers.sh
+++ /dev/null
@@ -1,79 +0,0 @@
-#
-# run ./config/network_layers.sh
-#
-
-################################################################################
-# Link configuration
-################################################################################
-# Routes added implicitly when links are brought UP:
-# IP Prefix = 10.0.0.1/16 => (Port 0, Local)
-# IP Prefix = 10.0.0.1/32 => (Port 4, Local)
-# IP Prefix = 10.1.0.1/16 => (Port 1, Local)
-# IP Prefix = 10.1.0.1/32 => (Port 4, Local)
-# IP Prefix = 10.2.0.1/16 => (Port 2, Local)
-# IP Prefix = 10.2.0.1/32 => (Port 4, Local)
-# IP Prefix = 10.3.0.1/16 => (Port 3, Local)
-# IP Prefix = 10.3.0.1/32 => (Port 4, Local)
-link 0 down
-link 1 down
-link 2 down
-link 3 down
-link 0 config 10.0.0.1 16
-link 1 config 10.1.0.1 16
-link 2 config 10.2.0.1 16
-link 3 config 10.3.0.1 16
-link 0 up
-link 1 up
-link 2 up
-link 3 up
-#link ls
-
-################################################################################
-# Static ARP
-################################################################################
-p 1 arp add default 5 #SINK3
-p 1 arp add 0 10.0.0.2 a0:b0:c0:d0:e0:f0
-p 1 arp add 1 10.1.0.2 a1:b1:c1:d1:e1:f1
-p 1 arp add 2 10.2.0.2 a2:b2:c2:d2:e2:f2
-p 1 arp add 3 10.3.0.2 a3:b3:c3:d3:e3:f3
-#p 1 arp ls
-
-################################################################################
-# Routes
-################################################################################
-p 1 route add default 4 #SINK2
-p 1 route add 100.0.0.0 16 port 0 ether 10.0.0.2
-p 1 route add 100.1.0.0 16 port 1 ether 10.1.0.2
-p 1 route add 100.2.0.0 16 port 2 ether 10.2.0.2
-p 1 route add 100.3.0.0 16 port 3 ether 10.3.0.2
-#p 1 route ls
-
-################################################################################
-# Local destination UDP traffic
-################################################################################
-# Prio = Lowest: [SA = ANY, DA = ANY, SP = ANY, DP = ANY, PROTO = ANY] => Drop
-# Prio = 1 (High): [SA = ANY, DA = 10.0.0.1, SP = ANY, DP = 1000, PROTO = UDP] => Allow
-# Prio = 1 (High): [SA = ANY, DA = 10.1.0.1, SP = ANY, DP = 1001, PROTO = UDP] => Allow
-# Prio = 1 (High): [SA = ANY, DA = 10.2.0.1, SP = ANY, DP = 1002, PROTO = UDP] => Allow
-# Prio = 1 (High): [SA = ANY, DA = 10.3.0.1, SP = ANY, DP = 1003, PROTO = UDP] => Allow
-p 2 firewall add default 1 #SINK0
-p 2 firewall add priority 1 ipv4 0.0.0.0 0 10.0.0.1 32 0 65535 1000 1000 17 0xF port 0
-p 2 firewall add priority 1 ipv4 0.0.0.0 0 10.1.0.1 32 0 65535 1001 1001 17 0xF port 0
-p 2 firewall add priority 1 ipv4 0.0.0.0 0 10.2.0.1 32 0 65535 1002 1002 17 0xF port 0
-p 2 firewall add priority 1 ipv4 0.0.0.0 0 10.3.0.1 32 0 65535 1003 1003 17 0xF port 0
-#p 2 firewall ls
-
-################################################################################
-# Local destination TCP traffic
-################################################################################
-# Unknown connection => Drop
-# TCP [SA = 100.0.0.10, DA = 10.0.0.1, SP = 1000, DP = 80] => socket ID = 0
-# TCP [SA = 100.1.0.10, DA = 10.1.0.1, SP = 1001, DP = 80] => socket ID = 1
-# TCP [SA = 100.2.0.10, DA = 10.2.0.1, SP = 1002, DP = 80] => socket ID = 2
-# TCP [SA = 100.3.0.10, DA = 10.3.0.1, SP = 1003, DP = 80] => socket ID = 3
-p 3 flow add default 1 #SINK1
-p 3 flow add ipv4 100.0.0.10 10.0.0.1 1000 80 6 port 0 id 0
-p 3 flow add ipv4 100.1.0.10 10.1.0.1 1001 80 6 port 0 id 1
-p 3 flow add ipv4 100.2.0.10 10.2.0.1 1002 80 6 port 0 id 2
-p 3 flow add ipv4 100.3.0.10 10.3.0.1 1003 80 6 port 0 id 3
-#p 3 flow ls
diff --git a/examples/ip_pipeline/config/pipeline-to-core-mapping.py b/examples/ip_pipeline/config/pipeline-to-core-mapping.py
deleted file mode 100755
index fc52b2b..0000000
--- a/examples/ip_pipeline/config/pipeline-to-core-mapping.py
+++ /dev/null
@@ -1,906 +0,0 @@
-#!/usr/bin/env python
-# SPDX-License-Identifier: BSD-3-Clause
-# Copyright(c) 2016 Intel Corporation
-
-#
-# This script maps the set of pipelines identified (MASTER pipelines are
-# ignored) from the input configuration file to the set of cores
-# provided as input argument and creates configuration files for each of
-# the mapping combinations.
-#
-
-from __future__ import print_function
-from collections import namedtuple
-import argparse
-import array
-import errno
-import itertools
-import os
-import re
-import sys
-
-# default values
-enable_stage0_traceout = 1
-enable_stage1_traceout = 1
-enable_stage2_traceout = 1
-
-enable_stage1_fileout = 1
-enable_stage2_fileout = 1
-
-Constants = namedtuple('Constants', ['MAX_CORES', 'MAX_PIPELINES'])
-constants = Constants(16, 64)
-
-# pattern for physical core
-pattern_phycore = '^(s|S)\d(c|C)[1-9][0-9]*$'
-reg_phycore = re.compile(pattern_phycore)
-
-
-def popcount(mask):
-    return bin(mask).count("1")
-
-
-def len2mask(length):
-    if (length == 0):
-        return 0
-
-    if (length > 64):
-        sys.exit('error: len2mask - length %i > 64. exiting' % length)
-
-    return int('1' * length, 2)
-
-
-def bitstring_write(n, n_bits):
-    tmpstr = ""
-    if (n_bits > 64):
-        return
-
-    i = n_bits - 1
-    while (i >= 0):
-        cond = (n & (1 << i))
-        if (cond):
-            print('1', end='')
-            tmpstr += '1'
-        else:
-            print('0', end='')
-            tmpstr += '0'
-        i -= 1
-    return tmpstr
-
-
-class Cores0:
-
-    def __init__(self):
-        self.n_pipelines = 0
-
-
-class Cores1:
-
-    def __init__(self):
-        self.pipelines = 0
-        self.n_pipelines = 0
-
-
-class Cores2:
-
-    def __init__(self):
-        self.pipelines = 0
-        self.n_pipelines = 0
-        self.counter = 0
-        self.counter_max = 0
-        self.bitpos = array.array(
-            "L", itertools.repeat(0, constants.MAX_PIPELINES))
-
-
-class Context0:
-
-    def __init__(self):
-        self.cores = [Cores0() for i in range(0, constants.MAX_CORES)]
-        self.n_cores = 0
-        self.n_pipelines = 0
-        self.n_pipelines0 = 0
-        self.pos = 0
-        self.file_comment = ""
-        self.ctx1 = None
-        self.ctx2 = None
-
-    def stage0_print(self):
-        print('printing Context0 obj')
-        print('c0.cores(n_pipelines) = [ ', end='')
-        for cores_count in range(0, constants.MAX_CORES):
-            print(self.cores[cores_count].n_pipelines, end=' ')
-        print(']')
-        print('c0.n_cores = %d' % self.n_cores)
-        print('c0.n_pipelines = %d' % self.n_pipelines)
-        print('c0.n_pipelines0 = %d' % self.n_pipelines0)
-        print('c0.pos = %d' % self.pos)
-        print('c0.file_comment = %s' % self.file_comment)
-        if (self.ctx1 is not None):
-            print('c0.ctx1 = ', end='')
-            print(repr(self.ctx1))
-        else:
-            print('c0.ctx1 = None')
-
-        if (self.ctx2 is not None):
-            print('c0.ctx2 = ', end='')
-            print(repr(self.ctx2))
-        else:
-            print('c0.ctx2 = None')
-
-    def stage0_init(self, num_cores, num_pipelines, ctx1, ctx2):
-        self.n_cores = num_cores
-        self.n_pipelines = num_pipelines
-        self.ctx1 = ctx1
-        self.ctx2 = ctx2
-
-    def stage0_process(self):
-        # stage0 init
-        self.cores[0].n_pipelines = self.n_pipelines
-        self.n_pipelines0 = 0
-        self.pos = 1
-
-        while True:
-            # go forward
-            while True:
-                if ((self.pos < self.n_cores) and (self.n_pipelines0 > 0)):
-                    self.cores[self.pos].n_pipelines = min(
-                        self.cores[self.pos - 1].n_pipelines,
-                        self.n_pipelines0)
-                    self.n_pipelines0 -= self.cores[self.pos].n_pipelines
-                    self.pos += 1
-                else:
-                    break
-
-            # check solution
-            if (self.n_pipelines0 == 0):
-                self.stage0_log()
-                self.ctx1.stage1_init(self, self.ctx2)  # self is object c0
-                self.ctx1.stage1_process()
-
-            # go backward
-            while True:
-                if (self.pos == 0):
-                    return
-
-                self.pos -= 1
-                if ((self.cores[self.pos].n_pipelines > 1) and
-                        (self.pos != (self.n_cores - 1))):
-                    break
-
-                self.n_pipelines0 += self.cores[self.pos].n_pipelines
-                self.cores[self.pos].n_pipelines = 0
-
-            # rearm
-            self.cores[self.pos].n_pipelines -= 1
-            self.n_pipelines0 += 1
-            self.pos += 1
-
-    def stage0_log(self):
-        tmp_file_comment = ""
-        if(enable_stage0_traceout != 1):
-            return
-
-        print('STAGE0: ', end='')
-        tmp_file_comment += 'STAGE0: '
-        for cores_count in range(0, self.n_cores):
-            print('C%d = %d\t'
-                  % (cores_count,
-                      self.cores[cores_count].n_pipelines), end='')
-            tmp_file_comment += "C{} = {}\t".format(
-                cores_count, self.cores[cores_count].n_pipelines)
-        # end for
-        print('')
-        self.ctx1.stage0_file_comment = tmp_file_comment
-        self.ctx2.stage0_file_comment = tmp_file_comment
-
-
-class Context1:
-    _fileTrace = None
-
-    def __init__(self):
-        self.cores = [Cores1() for i in range(constants.MAX_CORES)]
-        self.n_cores = 0
-        self.n_pipelines = 0
-        self.pos = 0
-        self.stage0_file_comment = ""
-        self.stage1_file_comment = ""
-
-        self.ctx2 = None
-        self.arr_pipelines2cores = []
-
-    def stage1_reset(self):
-        for i in range(constants.MAX_CORES):
-            self.cores[i].pipelines = 0
-            self.cores[i].n_pipelines = 0
-
-        self.n_cores = 0
-        self.n_pipelines = 0
-        self.pos = 0
-        self.ctx2 = None
-        # clear list
-        del self.arr_pipelines2cores[:]
-
-    def stage1_print(self):
-        print('printing Context1 obj')
-        print('ctx1.cores(pipelines,n_pipelines) = [ ', end='')
-        for cores_count in range(0, constants.MAX_CORES):
-            print('(%d,%d)' % (self.cores[cores_count].pipelines,
-                               self.cores[cores_count].n_pipelines), end=' ')
-        print(']')
-        print('ctx1.n_cores = %d' % self.n_cores)
-        print('ctx1.n_pipelines = %d' % self.n_pipelines)
-        print('ctx1.pos = %d' % self.pos)
-        print('ctx1.stage0_file_comment = %s' % self.stage0_file_comment)
-        print('ctx1.stage1_file_comment = %s' % self.stage1_file_comment)
-        if (self.ctx2 is not None):
-            print('ctx1.ctx2 = ', end='')
-            print(self.ctx2)
-        else:
-            print('ctx1.ctx2 = None')
-
-    def stage1_init(self, c0, ctx2):
-        self.stage1_reset()
-        self.n_cores = 0
-        while (c0.cores[self.n_cores].n_pipelines > 0):
-            self.n_cores += 1
-
-        self.n_pipelines = c0.n_pipelines
-        self.ctx2 = ctx2
-
-        self.arr_pipelines2cores = [0] * self.n_pipelines
-
-        i = 0
-        while (i < self.n_cores):
-            self.cores[i].n_pipelines = c0.cores[i].n_pipelines
-            i += 1
-
-    def stage1_process(self):
-        pipelines_max = len2mask(self.n_pipelines)
-        while True:
-            pos = 0
-            overlap = 0
-
-            if (self.cores[self.pos].pipelines == pipelines_max):
-                if (self.pos == 0):
-                    return
-
-                self.cores[self.pos].pipelines = 0
-                self.pos -= 1
-                continue
-
-            self.cores[self.pos].pipelines += 1
-            if (popcount(self.cores[self.pos].pipelines) !=
-                    self.cores[self.pos].n_pipelines):
-                continue
-
-            overlap = 0
-            pos = 0
-            while (pos < self.pos):
-                if ((self.cores[self.pos].pipelines) &
-                        (self.cores[pos].pipelines)):
-                    overlap = 1
-                    break
-                pos += 1
-
-            if (overlap):
-                continue
-
-            if ((self.pos > 0) and
-                ((self.cores[self.pos].n_pipelines) ==
-                    (self.cores[self.pos - 1].n_pipelines)) and
-                    ((self.cores[self.pos].pipelines) <
-                        (self.cores[self.pos - 1].pipelines))):
-                continue
-
-            if (self.pos == self.n_cores - 1):
-                self.stage1_log()
-                self.ctx2.stage2_init(self)
-                self.ctx2.stage2_process()
-
-                if (self.pos == 0):
-                    return
-
-                self.cores[self.pos].pipelines = 0
-                self.pos -= 1
-                continue
-
-            self.pos += 1
-
-    def stage1_log(self):
-        tmp_file_comment = ""
-        if(enable_stage1_traceout == 1):
-            print('STAGE1: ', end='')
-            tmp_file_comment += 'STAGE1: '
-            i = 0
-            while (i < self.n_cores):
-                print('C%d = [' % i, end='')
-                tmp_file_comment += "C{} = [".format(i)
-
-                j = self.n_pipelines - 1
-                while (j >= 0):
-                    cond = ((self.cores[i].pipelines) & (1 << j))
-                    if (cond):
-                        print('1', end='')
-                        tmp_file_comment += '1'
-                    else:
-                        print('0', end='')
-                        tmp_file_comment += '0'
-                    j -= 1
-
-                print(']\t', end='')
-                tmp_file_comment += ']\t'
-                i += 1
-
-            print('\n', end='')
-            self.stage1_file_comment = tmp_file_comment
-            self.ctx2.stage1_file_comment = tmp_file_comment
-
-        # check if file traceing is enabled
-        if(enable_stage1_fileout != 1):
-            return
-
-        # spit out the combination to file
-        self.stage1_process_file()
-
-    def stage1_updateCoresInBuf(self, nPipeline, sCore):
-        rePipeline = self._fileTrace.arr_pipelines[nPipeline]
-        rePipeline = rePipeline.replace("[", "\[").replace("]", "\]")
-        reCore = 'core\s*=\s*((\d*)|(((s|S)\d)?(c|C)[1-9][0-9]*)).*\n'
-        sSubs = 'core = ' + sCore + '\n'
-
-        reg_pipeline = re.compile(rePipeline)
-        search_match = reg_pipeline.search(self._fileTrace.in_buf)
-
-        if(search_match):
-            pos = search_match.start()
-            substr1 = self._fileTrace.in_buf[:pos]
-            substr2 = self._fileTrace.in_buf[pos:]
-            substr2 = re.sub(reCore, sSubs, substr2, 1)
-            self._fileTrace.in_buf = substr1 + substr2
-
-    def stage1_process_file(self):
-        outFileName = os.path.join(self._fileTrace.out_path,
-                                   self._fileTrace.prefix_outfile)
-        outFileName += "_{}CoReS".format(self.n_cores)
-
-        i = 0  # represents core number
-        while (i < self.n_cores):
-            j = self.n_pipelines - 1
-            pipeline_idx = 0
-            while(j >= 0):
-                cond = ((self.cores[i].pipelines) & (1 << j))
-                if (cond):
-                    # update the pipelines array to match the core
-                    # only in case of cond match
-                    self.arr_pipelines2cores[
-                        pipeline_idx] = fileTrace.in_physical_cores[i]
-
-                j -= 1
-                pipeline_idx += 1
-
-            i += 1
-
-        # update the in_buf as per the arr_pipelines2cores
-        for pipeline_idx in range(len(self.arr_pipelines2cores)):
-            outFileName += "_{}".format(self.arr_pipelines2cores[pipeline_idx])
-            self.stage1_updateCoresInBuf(
-                pipeline_idx, self.arr_pipelines2cores[pipeline_idx])
-
-        # by now the in_buf is all set to be written to file
-        outFileName += self._fileTrace.suffix_outfile
-        outputFile = open(outFileName, "w")
-
-        # write out the comments
-        strTruncated = ("", "(Truncated)")[self._fileTrace.ncores_truncated]
-        outputFile.write(
-            "; =============== Pipeline-to-Core Mapping ================\n"
-            "; Generated from file {}\n"
-            "; Input pipelines = {}\n"
-            "; Input cores = {}\n"
-            "; N_PIPELINES = {} N_CORES = {} {} hyper_thread = {}\n"
-            .format(
-                self._fileTrace.in_file_namepath,
-                fileTrace.arr_pipelines,
-                fileTrace.in_physical_cores,
-                self._fileTrace.n_pipelines,
-                self._fileTrace.n_cores,
-                strTruncated,
-                self._fileTrace.hyper_thread))
-
-        outputFile.write(
-            "; {stg0cmt}\n"
-            "; {stg1cmt}\n"
-            "; ========================================================\n"
-            "; \n"
-            .format(
-                stg0cmt=self.stage0_file_comment,
-                stg1cmt=self.stage1_file_comment))
-
-        # write buffer contents
-        outputFile.write(self._fileTrace.in_buf)
-        outputFile.flush()
-        outputFile.close()
-
-
-class Context2:
-    _fileTrace = None
-
-    def __init__(self):
-        self.cores = [Cores2() for i in range(constants.MAX_CORES)]
-        self.n_cores = 0
-        self.n_pipelines = 0
-        self.pos = 0
-        self.stage0_file_comment = ""
-        self.stage1_file_comment = ""
-        self.stage2_file_comment = ""
-
-        # each array entry is a pipeline mapped to core stored as string
-        # pipeline ranging from 1 to n, however stored in zero based array
-        self.arr2_pipelines2cores = []
-
-    def stage2_print(self):
-        print('printing Context2 obj')
-        print('ctx2.cores(pipelines, n_pipelines, counter, counter_max) =')
-        for cores_count in range(0, constants.MAX_CORES):
-            print('core[%d] = (%d,%d,%d,%d)' % (
-                cores_count,
-                self.cores[cores_count].pipelines,
-                self.cores[cores_count].n_pipelines,
-                self.cores[cores_count].counter,
-                self.cores[cores_count].counter_max))
-
-            print('ctx2.n_cores = %d' % self.n_cores, end='')
-            print('ctx2.n_pipelines = %d' % self.n_pipelines, end='')
-            print('ctx2.pos = %d' % self.pos)
-            print('ctx2.stage0_file_comment = %s' %
-                  self.self.stage0_file_comment)
-            print('ctx2.stage1_file_comment = %s' %
-                  self.self.stage1_file_comment)
-            print('ctx2.stage2_file_comment = %s' %
-                  self.self.stage2_file_comment)
-
-    def stage2_reset(self):
-        for i in range(0, constants.MAX_CORES):
-            self.cores[i].pipelines = 0
-            self.cores[i].n_pipelines = 0
-            self.cores[i].counter = 0
-            self.cores[i].counter_max = 0
-
-            for idx in range(0, constants.MAX_PIPELINES):
-                self.cores[i].bitpos[idx] = 0
-
-        self.n_cores = 0
-        self.n_pipelines = 0
-        self.pos = 0
-        # clear list
-        del self.arr2_pipelines2cores[:]
-
-    def bitpos_load(self, coreidx):
-        i = j = 0
-        while (i < self.n_pipelines):
-            if ((self.cores[coreidx].pipelines) &
-                    (1 << i)):
-                self.cores[coreidx].bitpos[j] = i
-                j += 1
-            i += 1
-        self.cores[coreidx].n_pipelines = j
-
-    def bitpos_apply(self, in_buf, pos, n_pos):
-        out = 0
-        for i in range(0, n_pos):
-            out |= (in_buf & (1 << i)) << (pos[i] - i)
-
-        return out
-
-    def stage2_init(self, ctx1):
-        self.stage2_reset()
-        self.n_cores = ctx1.n_cores
-        self.n_pipelines = ctx1.n_pipelines
-
-        self.arr2_pipelines2cores = [''] * self.n_pipelines
-
-        core_idx = 0
-        while (core_idx < self.n_cores):
-            self.cores[core_idx].pipelines = ctx1.cores[core_idx].pipelines
-
-            self.bitpos_load(core_idx)
-            core_idx += 1
-
-    def stage2_log(self):
-        tmp_file_comment = ""
-        if(enable_stage2_traceout == 1):
-            print('STAGE2: ', end='')
-            tmp_file_comment += 'STAGE2: '
-
-            for i in range(0, self.n_cores):
-                mask = len2mask(self.cores[i].n_pipelines)
-                pipelines_ht0 = self.bitpos_apply(
-                    (~self.cores[i].counter) & mask,
-                    self.cores[i].bitpos,
-                    self.cores[i].n_pipelines)
-
-                pipelines_ht1 = self.bitpos_apply(
-                    self.cores[i].counter,
-                    self.cores[i].bitpos,
-                    self.cores[i].n_pipelines)
-
-                print('C%dHT0 = [' % i, end='')
-                tmp_file_comment += "C{}HT0 = [".format(i)
-                tmp_file_comment += bitstring_write(
-                    pipelines_ht0, self.n_pipelines)
-
-                print(']\tC%dHT1 = [' % i, end='')
-                tmp_file_comment += "]\tC{}HT1 = [".format(i)
-                tmp_file_comment += bitstring_write(
-                    pipelines_ht1, self.n_pipelines)
-                print(']\t', end='')
-                tmp_file_comment += ']\t'
-
-            print('')
-            self.stage2_file_comment = tmp_file_comment
-
-        # check if file traceing is enabled
-        if(enable_stage2_fileout != 1):
-            return
-        # spit out the combination to file
-        self.stage2_process_file()
-
-    def stage2_updateCoresInBuf(self, nPipeline, sCore):
-        rePipeline = self._fileTrace.arr_pipelines[nPipeline]
-        rePipeline = rePipeline.replace("[", "\[").replace("]", "\]")
-        reCore = 'core\s*=\s*((\d*)|(((s|S)\d)?(c|C)[1-9][0-9]*)).*\n'
-        sSubs = 'core = ' + sCore + '\n'
-
-        reg_pipeline = re.compile(rePipeline)
-        search_match = reg_pipeline.search(self._fileTrace.in_buf)
-
-        if(search_match):
-            pos = search_match.start()
-            substr1 = self._fileTrace.in_buf[:pos]
-            substr2 = self._fileTrace.in_buf[pos:]
-            substr2 = re.sub(reCore, sSubs, substr2, 1)
-            self._fileTrace.in_buf = substr1 + substr2
-
-    def pipelines2cores(self, n, n_bits, nCore, bHT):
-        if (n_bits > 64):
-            return
-
-        i = n_bits - 1
-        pipeline_idx = 0
-        while (i >= 0):
-            cond = (n & (1 << i))
-            if (cond):
-                # update the pipelines array to match the core
-                # only in case of cond match
-                # PIPELINE0 and core 0 are reserved
-                if(bHT):
-                    tmpCore = fileTrace.in_physical_cores[nCore] + 'h'
-                    self.arr2_pipelines2cores[pipeline_idx] = tmpCore
-                else:
-                    self.arr2_pipelines2cores[pipeline_idx] = \
-                        fileTrace.in_physical_cores[nCore]
-
-            i -= 1
-            pipeline_idx += 1
-
-    def stage2_process_file(self):
-        outFileName = os.path.join(self._fileTrace.out_path,
-                                   self._fileTrace.prefix_outfile)
-        outFileName += "_{}CoReS".format(self.n_cores)
-
-        for i in range(0, self.n_cores):
-            mask = len2mask(self.cores[i].n_pipelines)
-            pipelines_ht0 = self.bitpos_apply((~self.cores[i].counter) & mask,
-                                              self.cores[i].bitpos,
-                                              self.cores[i].n_pipelines)
-
-            pipelines_ht1 = self.bitpos_apply(self.cores[i].counter,
-                                              self.cores[i].bitpos,
-                                              self.cores[i].n_pipelines)
-
-            # update pipelines to core mapping
-            self.pipelines2cores(pipelines_ht0, self.n_pipelines, i, False)
-            self.pipelines2cores(pipelines_ht1, self.n_pipelines, i, True)
-
-        # update the in_buf as per the arr_pipelines2cores
-        for pipeline_idx in range(len(self.arr2_pipelines2cores)):
-            outFileName += "_{}".format(
-                self.arr2_pipelines2cores[pipeline_idx])
-            self.stage2_updateCoresInBuf(
-                pipeline_idx, self.arr2_pipelines2cores[pipeline_idx])
-
-        # by now the in_buf is all set to be written to file
-        outFileName += self._fileTrace.suffix_outfile
-        outputFile = open(outFileName, "w")
-
-        # write the file comments
-        strTruncated = ("", "(Truncated)")[self._fileTrace.ncores_truncated]
-        outputFile.write(
-            "; =============== Pipeline-to-Core Mapping ================\n"
-            "; Generated from file {}\n"
-            "; Input pipelines = {}\n"
-            "; Input cores = {}\n"
-            "; N_PIPELINES = {}  N_CORES = {} {} hyper_thread = {} \n"
-            .format(
-                self._fileTrace.in_file_namepath,
-                fileTrace.arr_pipelines,
-                fileTrace.in_physical_cores,
-                self._fileTrace.n_pipelines,
-                self._fileTrace.n_cores,
-                strTruncated,
-                self._fileTrace.hyper_thread))
-
-        outputFile.write(
-            "; {stg0cmt}\n"
-            "; {stg1cmt}\n"
-            "; {stg2cmt}\n"
-            "; ========================================================\n"
-            "; \n"
-            .format(
-                stg0cmt=self.stage0_file_comment,
-                stg1cmt=self.stage1_file_comment,
-                stg2cmt=self.stage2_file_comment))
-
-        # write the buffer contents
-        outputFile.write(self._fileTrace.in_buf)
-        outputFile.flush()
-        outputFile.close()
-
-    def stage2_process(self):
-        i = 0
-        while(i < self.n_cores):
-            self.cores[i].counter_max = len2mask(
-                self.cores[i].n_pipelines - 1)
-            i += 1
-
-        self.pos = self.n_cores - 1
-        while True:
-            if (self.pos == self.n_cores - 1):
-                self.stage2_log()
-
-            if (self.cores[self.pos].counter ==
-                    self.cores[self.pos].counter_max):
-                if (self.pos == 0):
-                    return
-
-                self.cores[self.pos].counter = 0
-                self.pos -= 1
-                continue
-
-            self.cores[self.pos].counter += 1
-            if(self.pos < self.n_cores - 1):
-                self.pos += 1
-
-
-class FileTrace:
-
-    def __init__(self, filenamepath):
-        self.in_file_namepath = os.path.abspath(filenamepath)
-        self.in_filename = os.path.basename(self.in_file_namepath)
-        self.in_path = os.path.dirname(self.in_file_namepath)
-
-        filenamesplit = self.in_filename.split('.')
-        self.prefix_outfile = filenamesplit[0]
-        self.suffix_outfile = ".cfg"
-
-        # output folder:  in the same folder as input file
-        # create new folder in the name of input file
-        self.out_path = os.path.join(
-            os.path.abspath(os.path.dirname(__file__)),
-            self.prefix_outfile)
-
-        try:
-            os.makedirs(self.out_path)
-        except OSError as excep:
-            if excep.errno == errno.EEXIST and os.path.isdir(self.out_path):
-                pass
-            else:
-                raise
-
-        self.in_buf = None
-        self.arr_pipelines = []  # holds the positions of search
-
-        self.max_cores = 15
-        self.max_pipelines = 15
-
-        self.in_physical_cores = None
-        self.hyper_thread = None
-
-        # save the num of pipelines determined from input file
-        self.n_pipelines = 0
-        # save the num of cores input (or the truncated value)
-        self.n_cores = 0
-        self.ncores_truncated = False
-
-    def print_TraceFile(self):
-        print("self.in_file_namepath = ", self.in_file_namepath)
-        print("self.in_filename = ", self.in_filename)
-        print("self.in_path = ", self.in_path)
-        print("self.out_path = ", self.out_path)
-        print("self.prefix_outfile = ", self.prefix_outfile)
-        print("self.suffix_outfile = ", self.suffix_outfile)
-        print("self.in_buf = ", self.in_buf)
-        print("self.arr_pipelines =", self.arr_pipelines)
-        print("self.in_physical_cores", self.in_physical_cores)
-        print("self.hyper_thread", self.hyper_thread)
-
-
-def process(n_cores, n_pipelines, fileTrace):
-    '''process and map pipelines, cores.'''
-    if (n_cores == 0):
-        sys.exit('N_CORES is 0, exiting')
-
-    if (n_pipelines == 0):
-        sys.exit('N_PIPELINES is 0, exiting')
-
-    if (n_cores > n_pipelines):
-        print('\nToo many cores, truncating N_CORES to N_PIPELINES')
-        n_cores = n_pipelines
-        fileTrace.ncores_truncated = True
-
-    fileTrace.n_pipelines = n_pipelines
-    fileTrace.n_cores = n_cores
-
-    strTruncated = ("", "(Truncated)")[fileTrace.ncores_truncated]
-    print("N_PIPELINES = {}, N_CORES = {} {}"
-          .format(n_pipelines, n_cores, strTruncated))
-    print("---------------------------------------------------------------")
-
-    ctx0_inst = Context0()
-    ctx1_inst = Context1()
-    ctx2_inst = Context2()
-
-    # initialize the class variables
-    ctx1_inst._fileTrace = fileTrace
-    ctx2_inst._fileTrace = fileTrace
-
-    ctx0_inst.stage0_init(n_cores, n_pipelines, ctx1_inst, ctx2_inst)
-    ctx0_inst.stage0_process()
-
-
-def validate_core(core):
-    match = reg_phycore.match(core)
-    if(match):
-        return True
-    else:
-        return False
-
-
-def validate_phycores(phy_cores):
-    '''validate physical cores, check if unique.'''
-    # eat up whitespaces
-    phy_cores = phy_cores.strip().split(',')
-
-    # check if the core list is unique
-    if(len(phy_cores) != len(set(phy_cores))):
-        print('list of physical cores has duplicates')
-        return None
-
-    for core in phy_cores:
-        if not validate_core(core):
-            print('invalid physical core specified.')
-            return None
-    return phy_cores
-
-
-def scanconfigfile(fileTrace):
-    '''scan input file for pipelines, validate then process.'''
-    # open file
-    filetoscan = open(fileTrace.in_file_namepath, 'r')
-    fileTrace.in_buf = filetoscan.read()
-
-    # reset iterator on open file
-    filetoscan.seek(0)
-
-    # scan input file for pipelines
-    # master pipelines to be ignored
-    pattern_pipeline = r'\[PIPELINE\d*\]'
-    pattern_mastertype = r'type\s*=\s*MASTER'
-
-    pending_pipeline = False
-    for line in filetoscan:
-        match_pipeline = re.search(pattern_pipeline, line)
-        match_type = re.search('type\s*=', line)
-        match_mastertype = re.search(pattern_mastertype, line)
-
-        if(match_pipeline):
-            sPipeline = line[match_pipeline.start():match_pipeline.end()]
-            pending_pipeline = True
-        elif(match_type):
-            # found a type definition...
-            if(match_mastertype is None):
-                # and this is not a master pipeline...
-                if(pending_pipeline):
-                    # add it to the list of pipelines to be mapped
-                    fileTrace.arr_pipelines.append(sPipeline)
-                    pending_pipeline = False
-            else:
-                # and this is a master pipeline...
-                # ignore the current and move on to next
-                sPipeline = ""
-                pending_pipeline = False
-    filetoscan.close()
-
-    # validate if pipelines are unique
-    if(len(fileTrace.arr_pipelines) != len(set(fileTrace.arr_pipelines))):
-        sys.exit('Error: duplicate pipelines in input file')
-
-    num_pipelines = len(fileTrace.arr_pipelines)
-    num_cores = len(fileTrace.in_physical_cores)
-
-    print("-------------------Pipeline-to-core mapping--------------------")
-    print("Input pipelines = {}\nInput cores = {}"
-          .format(fileTrace.arr_pipelines, fileTrace.in_physical_cores))
-
-    # input configuration file validations goes here
-    if (num_cores > fileTrace.max_cores):
-        sys.exit('Error: number of cores specified > max_cores (%d)' %
-                 fileTrace.max_cores)
-
-    if (num_pipelines > fileTrace.max_pipelines):
-        sys.exit('Error: number of pipelines in input \
-                cfg file > max_pipelines (%d)' % fileTrace.max_pipelines)
-
-    # call process to generate pipeline-to-core mapping, trace and log
-    process(num_cores, num_pipelines, fileTrace)
-
-
-if __name__ == "__main__":
-    parser = argparse.ArgumentParser(description='mappipelines')
-
-    reqNamedGrp = parser.add_argument_group('required named args')
-    reqNamedGrp.add_argument(
-        '-i',
-        '--input-file',
-        type=argparse.FileType('r'),
-        help='Input config file',
-        required=True)
-
-    reqNamedGrp.add_argument(
-        '-pc',
-        '--physical-cores',
-        type=validate_phycores,
-        help='''Enter available CPU cores in
-                format:\"<core>,<core>,...\"
-                where each core format: \"s<SOCKETID>c<COREID>\"
-                where SOCKETID={0..9}, COREID={1-99}''',
-        required=True)
-
-    # add optional arguments
-    parser.add_argument(
-        '-ht',
-        '--hyper-thread',
-        help='enable/disable hyper threading. default is ON',
-        default='ON',
-        choices=['ON', 'OFF'])
-
-    parser.add_argument(
-        '-nO',
-        '--no-output-file',
-        help='''disable output config file generation.
-                Output file generation is enabled by default''',
-        action="store_true")
-
-    args = parser.parse_args()
-
-    if(args.physical_cores is None):
-        parser.error("invalid physical_cores specified")
-
-    # create object of FileTrace and initialise
-    fileTrace = FileTrace(args.input_file.name)
-    fileTrace.in_physical_cores = args.physical_cores
-    fileTrace.hyper_thread = args.hyper_thread
-
-    if(fileTrace.hyper_thread == 'OFF'):
-        print("!!!!disabling stage2 HT!!!!")
-        enable_stage2_traceout = 0
-        enable_stage2_fileout = 0
-    elif(fileTrace.hyper_thread == 'ON'):
-        print("!!!!HT enabled. disabling stage1 file generation.!!!!")
-        enable_stage1_fileout = 0
-
-    if(args.no_output_file is True):
-        print("!!!!disabling stage1 and stage2 fileout!!!!")
-        enable_stage1_fileout = 0
-        enable_stage2_fileout = 0
-
-    scanconfigfile(fileTrace)
diff --git a/examples/ip_pipeline/config/tap.cfg b/examples/ip_pipeline/config/tap.cfg
deleted file mode 100644
index 10d35eb..0000000
--- a/examples/ip_pipeline/config/tap.cfg
+++ /dev/null
@@ -1,64 +0,0 @@
-;   BSD LICENSE
-;
-;   Copyright(c) 2016 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.
-
-;             ______________          ______________________
-;            |              |  TAP0  |                      |
-; RXQ0.0 --->|              |------->|--+                   |
-;            |              |  TAP1  |  | br0               |
-; TXQ1.0 <---|              |<-------|<-+                   |
-;            | Pass-through |        |     Linux Kernel     |
-;            |     (P1)     |        |     Network Stack    |
-;            |              |  TAP1  |                      |
-; RXQ1.0 --->|              |------->|--+                   |
-;            |              |  TAP0  |  | br0               |
-; TXQ0.0 <---|              |<-------|<-+                   |
-;            |______________|        |______________________|
-;
-; Configure Linux kernel bridge between TAP0 and TAP1 interfaces:
-;    [Linux]$ ifconfig TAP0 up
-;    [Linux]$ ifconfig TAP1 up
-;    [Linux]$ brctl addbr "br0"
-;    [Linux]$ brctl addif br0 TAP0
-;    [Linux]$ brctl addif br0 TAP1
-;    [Linux]$ ifconfig br0 up
-
-[EAL]
-log_level = 0
-
-[PIPELINE0]
-type = MASTER
-core = 0
-
-[PIPELINE1]
-type = PASS-THROUGH
-core = 1
-pktq_in = RXQ0.0 TAP1 RXQ1.0 TAP0
-pktq_out = TAP0 TXQ1.0 TAP1 TXQ0.0
diff --git a/examples/ip_pipeline/config/tm_profile.cfg b/examples/ip_pipeline/config/tm_profile.cfg
deleted file mode 100644
index 2dfb215..0000000
--- a/examples/ip_pipeline/config/tm_profile.cfg
+++ /dev/null
@@ -1,105 +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.
-
-; This file enables the following hierarchical scheduler configuration for each
-; 10GbE output port:
-;	* Single subport (subport 0):
-;		- Subport rate set to 100% of port rate
-;		- Each of the 4 traffic classes has rate set to 100% of port rate
-;	* 4K pipes per subport 0 (pipes 0 .. 4095) with identical configuration:
-;		- Pipe rate set to 1/4K of port rate
-;		- Each of the 4 traffic classes has rate set to 100% of pipe rate
-;		- Within each traffic class, the byte-level WRR weights for the 4 queues
-;         are set to 1:1:1:1
-;
-; For more details, please refer to chapter "Quality of Service (QoS) Framework"
-; of Data Plane Development Kit (DPDK) Programmer's Guide.
-
-; Port configuration
-[port]
-frame overhead = 24 ; frame overhead = Preamble (7) + SFD (1) + FCS (4) + IFG (12)
-mtu = 1522; mtu = Q-in-Q MTU (FCS not included)
-number of subports per port = 1
-number of pipes per subport = 4096
-queue sizes = 64 64 64 64
-
-; Subport configuration
-[subport 0]
-tb rate = 1250000000           ; Bytes per second
-tb size = 1000000              ; Bytes
-
-tc 0 rate = 1250000000         ; Bytes per second
-tc 1 rate = 1250000000         ; Bytes per second
-tc 2 rate = 1250000000         ; Bytes per second
-tc 3 rate = 1250000000         ; Bytes per second
-tc period = 10                 ; Milliseconds
-
-pipe 0-4095 = 0                ; These pipes are configured with pipe profile 0
-
-; Pipe configuration
-[pipe profile 0]
-tb rate = 305175               ; Bytes per second
-tb size = 1000000              ; Bytes
-
-tc 0 rate = 305175             ; Bytes per second
-tc 1 rate = 305175             ; Bytes per second
-tc 2 rate = 305175             ; Bytes per second
-tc 3 rate = 305175             ; Bytes per second
-tc period = 40                 ; Milliseconds
-
-tc 3 oversubscription weight = 1
-
-tc 0 wrr weights = 1 1 1 1
-tc 1 wrr weights = 1 1 1 1
-tc 2 wrr weights = 1 1 1 1
-tc 3 wrr weights = 1 1 1 1
-
-; RED params per traffic class and color (Green / Yellow / Red)
-[red]
-tc 0 wred min = 48 40 32
-tc 0 wred max = 64 64 64
-tc 0 wred inv prob = 10 10 10
-tc 0 wred weight = 9 9 9
-
-tc 1 wred min = 48 40 32
-tc 1 wred max = 64 64 64
-tc 1 wred inv prob = 10 10 10
-tc 1 wred weight = 9 9 9
-
-tc 2 wred min = 48 40 32
-tc 2 wred max = 64 64 64
-tc 2 wred inv prob = 10 10 10
-tc 2 wred weight = 9 9 9
-
-tc 3 wred min = 48 40 32
-tc 3 wred max = 64 64 64
-tc 3 wred inv prob = 10 10 10
-tc 3 wred weight = 9 9 9
-- 
2.9.3

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

* [dpdk-dev] [PATCH v3 17/44] ip_pipeline: rework and improvements
  2018-03-16 17:58       ` [dpdk-dev] [PATCH v3 00/44] ip_pipeline: refactoring Jasvinder Singh
                           ` (15 preceding siblings ...)
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 16/44] ip_pipeline: remove config Jasvinder Singh
@ 2018-03-16 17:58         ` Jasvinder Singh
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 18/44] ip_pipeline: add cli interface Jasvinder Singh
                           ` (26 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-16 17:58 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

All the actions associated with application pipelines
tables and ports are now implemented using the new action
APIs. Therefore, thousands of lines of code are eliminated
from the application. The reduced code size is easier to
maintain and extend.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/Makefile          |   22 +-
 examples/ip_pipeline/app.h             | 1389 -------------
 examples/ip_pipeline/config_check.c    |  488 -----
 examples/ip_pipeline/config_parse.c    | 3395 --------------------------------
 examples/ip_pipeline/config_parse_tm.c |  419 ----
 examples/ip_pipeline/cpu_core_map.c    |  471 -----
 examples/ip_pipeline/cpu_core_map.h    |   40 -
 examples/ip_pipeline/init.c            | 1343 -------------
 examples/ip_pipeline/main.c            |   36 +-
 examples/ip_pipeline/meson.build       |   10 +-
 examples/ip_pipeline/parser.c          |   16 +-
 examples/ip_pipeline/parser.h          |    8 +
 examples/ip_pipeline/pipeline.h        |   73 -
 examples/ip_pipeline/pipeline_be.h     |  322 ---
 examples/ip_pipeline/thread.c          |  240 ---
 examples/ip_pipeline/thread.h          |   69 -
 16 files changed, 37 insertions(+), 8304 deletions(-)
 delete mode 100644 examples/ip_pipeline/app.h
 delete mode 100644 examples/ip_pipeline/config_check.c
 delete mode 100644 examples/ip_pipeline/config_parse.c
 delete mode 100644 examples/ip_pipeline/config_parse_tm.c
 delete mode 100644 examples/ip_pipeline/cpu_core_map.c
 delete mode 100644 examples/ip_pipeline/cpu_core_map.h
 delete mode 100644 examples/ip_pipeline/init.c
 delete mode 100644 examples/ip_pipeline/pipeline.h
 delete mode 100644 examples/ip_pipeline/pipeline_be.h
 delete mode 100644 examples/ip_pipeline/thread.c
 delete mode 100644 examples/ip_pipeline/thread.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index 8ba7887..981c4f7 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -1,18 +1,13 @@
 # SPDX-License-Identifier: BSD-3-Clause
-# Copyright(c) 2010-2014 Intel Corporation
+# Copyright(c) 2010-2018 Intel Corporation
 
 # binary name
 APP = ip_pipeline
 
 # all source are stored in SRCS-y
 SRCS-y := main.c
-SRCS-y += config_parse.c
 SRCS-y += parser.c
-SRCS-y += config_parse_tm.c
-SRCS-y += config_check.c
-SRCS-y += init.c
-SRCS-y += thread.c
-SRCS-y += cpu_core_map.c
+#SRCS-y += thread.c
 
 # Build using pkg-config variables if possible
 $(shell pkg-config --exists libdpdk)
@@ -30,9 +25,7 @@ CFLAGS += -O3 $(shell pkg-config --cflags libdpdk)
 LDFLAGS_SHARED = $(shell pkg-config --libs libdpdk)
 LDFLAGS_STATIC = -Wl,-Bstatic $(shell pkg-config --static --libs libdpdk)
 
-VPATH += pipeline
-CFLAGS += -I. -I./pipeline/
-CFLAGS += -DALLOW_EXPERIMENTAL_API
+CFLAGS += -I.
 
 OBJS := $(patsubst %.c,build/%.o,$(SRCS-y))
 
@@ -59,21 +52,18 @@ ifeq ($(RTE_SDK),)
 $(error "Please define RTE_SDK environment variable")
 endif
 
-VPATH += $(SRCDIR)/pipeline
-
 # Default target, can be overridden by command line or environment
 RTE_TARGET ?= x86_64-native-linuxapp-gcc
 
 include $(RTE_SDK)/mk/rte.vars.mk
 
-INC += $(sort $(wildcard *.h)) $(sort $(wildcard pipeline/*.h))
+INC += $(sort $(wildcard *.h))
 
 SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) := $(SRCS-y)
 
-CFLAGS += -I$(SRCDIR) -I$(SRCDIR)/pipeline
+CFLAGS += -I$(SRCDIR)
 CFLAGS += -O3
-CFLAGS += $(WERROR_FLAGS) -Wno-error=unused-function -Wno-error=unused-variable
-CFLAGS += -DALLOW_EXPERIMENTAL_API
+CFLAGS += $(WERROR_FLAGS)
 
 include $(RTE_SDK)/mk/rte.extapp.mk
 
diff --git a/examples/ip_pipeline/app.h b/examples/ip_pipeline/app.h
deleted file mode 100644
index dadaf2b..0000000
--- a/examples/ip_pipeline/app.h
+++ /dev/null
@@ -1,1389 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2016 Intel Corporation
- */
-
-#ifndef __INCLUDE_APP_H__
-#define __INCLUDE_APP_H__
-
-#include <stdint.h>
-#include <string.h>
-
-#include <rte_common.h>
-#include <rte_mempool.h>
-#include <rte_ring.h>
-#include <rte_sched.h>
-#include <cmdline_parse.h>
-
-#include <rte_ethdev.h>
-#ifdef RTE_LIBRTE_KNI
-#include <rte_kni.h>
-#endif
-
-#include "cpu_core_map.h"
-#include "pipeline.h"
-
-#define APP_PARAM_NAME_SIZE                      PIPELINE_NAME_SIZE
-#define APP_LINK_PCI_BDF_SIZE                    16
-
-#ifndef APP_LINK_MAX_HWQ_IN
-#define APP_LINK_MAX_HWQ_IN                      128
-#endif
-
-#ifndef APP_LINK_MAX_HWQ_OUT
-#define APP_LINK_MAX_HWQ_OUT                     128
-#endif
-
-struct app_mempool_params {
-	char *name;
-	uint32_t parsed;
-	uint32_t buffer_size;
-	uint32_t pool_size;
-	uint32_t cache_size;
-	uint32_t cpu_socket_id;
-};
-
-struct app_link_params {
-	char *name;
-	uint32_t parsed;
-	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_q; /* 0 = Disabled (pkts go to default queue) */
-	uint32_t ip_local_q; /* 0 = Disabled (pkts go to default queue 0) */
-	uint32_t tcp_local_q; /* 0 = Disabled (pkts go to default queue 0) */
-	uint32_t udp_local_q; /* 0 = Disabled (pkts go to default queue 0) */
-	uint32_t sctp_local_q; /* 0 = Disabled (pkts go to default queue 0) */
-	uint32_t rss_qs[APP_LINK_MAX_HWQ_IN];
-	uint32_t n_rss_qs;
-	uint64_t rss_proto_ipv4;
-	uint64_t rss_proto_ipv6;
-	uint64_t rss_proto_l2;
-	uint32_t promisc;
-	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 */
-	char pci_bdf[APP_LINK_PCI_BDF_SIZE];
-
-	struct rte_eth_conf conf;
-};
-
-struct app_pktq_hwq_in_params {
-	char *name;
-	uint32_t parsed;
-	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;
-	uint32_t parsed;
-	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;
-	uint32_t parsed;
-	uint32_t size;
-	uint32_t burst_read;
-	uint32_t burst_write;
-	uint32_t dropless;
-	uint64_t n_retries;
-	uint32_t cpu_socket_id;
-	uint32_t ipv4_frag;
-	uint32_t ipv6_frag;
-	uint32_t ipv4_ras;
-	uint32_t ipv6_ras;
-	uint32_t mtu;
-	uint32_t metadata_size;
-	uint32_t mempool_direct_id;
-	uint32_t mempool_indirect_id;
-};
-
-struct app_pktq_kni_params {
-	char *name;
-	uint32_t parsed;
-
-	uint32_t socket_id;
-	uint32_t core_id;
-	uint32_t hyper_th_id;
-	uint32_t force_bind;
-
-	uint32_t mempool_id; /* Position in the app->mempool_params */
-	uint32_t burst_read;
-	uint32_t burst_write;
-	uint32_t dropless;
-	uint64_t n_retries;
-};
-
-#ifndef APP_FILE_NAME_SIZE
-#define APP_FILE_NAME_SIZE                       256
-#endif
-
-#ifndef APP_MAX_SCHED_SUBPORTS
-#define APP_MAX_SCHED_SUBPORTS                   8
-#endif
-
-#ifndef APP_MAX_SCHED_PIPES
-#define APP_MAX_SCHED_PIPES                      4096
-#endif
-
-struct app_pktq_tm_params {
-	char *name;
-	uint32_t parsed;
-	const char *file_name;
-	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_tap_params {
-	char *name;
-	uint32_t parsed;
-	uint32_t burst_read;
-	uint32_t burst_write;
-	uint32_t dropless;
-	uint64_t n_retries;
-	uint32_t mempool_id; /* Position in the app->mempool_params */
-};
-
-struct app_pktq_source_params {
-	char *name;
-	uint32_t parsed;
-	uint32_t mempool_id; /* Position in the app->mempool_params array */
-	uint32_t burst;
-	const char *file_name; /* Full path of PCAP file to be copied to mbufs */
-	uint32_t n_bytes_per_pkt;
-};
-
-struct app_pktq_sink_params {
-	char *name;
-	uint8_t parsed;
-	const char *file_name; /* Full path of PCAP file to be copied to mbufs */
-	uint32_t n_pkts_to_dump;
-};
-
-struct app_msgq_params {
-	char *name;
-	uint32_t parsed;
-	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_TAP,
-	APP_PKTQ_IN_KNI,
-	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_TAP,
-	APP_PKTQ_OUT_KNI,
-	APP_PKTQ_OUT_SINK,
-};
-
-struct app_pktq_out_params {
-	enum app_pktq_out_type type;
-	uint32_t id; /* Position in the appropriate app array */
-};
-
-#define APP_PIPELINE_TYPE_SIZE                   PIPELINE_TYPE_SIZE
-
-#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
-
-#define APP_MAX_PIPELINE_ARGS                    PIPELINE_MAX_ARGS
-
-struct app_pipeline_params {
-	char *name;
-	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_params;
-
-typedef void (*app_link_op)(struct app_params *app,
-	uint32_t link_id,
-	uint32_t up,
-	void *arg);
-
-#ifndef APP_MAX_PIPELINES
-#define APP_MAX_PIPELINES                        64
-#endif
-
-struct app_link_data {
-	app_link_op f_link[APP_MAX_PIPELINES];
-	void *arg[APP_MAX_PIPELINES];
-};
-
-struct app_pipeline_data {
-	void *be;
-	void *fe;
-	struct pipeline_type *ptype;
-	uint64_t timer_period;
-	uint32_t enabled;
-};
-
-struct app_thread_pipeline_data {
-	uint32_t pipeline_id;
-	void *be;
-	pipeline_be_op_run f_run;
-	pipeline_be_op_timer f_timer;
-	uint64_t timer_period;
-	uint64_t deadline;
-};
-
-#ifndef APP_MAX_THREAD_PIPELINES
-#define APP_MAX_THREAD_PIPELINES                 64
-#endif
-
-#ifndef APP_THREAD_TIMER_PERIOD
-#define APP_THREAD_TIMER_PERIOD                  1
-#endif
-
-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 timer_period;
-	uint64_t thread_req_deadline;
-
-	uint64_t deadline;
-
-	struct rte_ring *msgq_in;
-	struct rte_ring *msgq_out;
-
-	uint64_t headroom_time;
-	uint64_t headroom_cycles;
-	double headroom_ratio;
-} __rte_cache_aligned;
-
-#ifndef APP_MAX_LINKS
-#define APP_MAX_LINKS                            16
-#endif
-
-struct app_eal_params {
-	/* Map lcore set to physical cpu set */
-	char *coremap;
-
-	/* Core ID that is used as master */
-	uint32_t master_lcore_present;
-	uint32_t master_lcore;
-
-	/* Number of memory channels */
-	uint32_t channels_present;
-	uint32_t channels;
-
-	/* Memory to allocate (see also --socket-mem) */
-	uint32_t memory_present;
-	uint32_t memory;
-
-	/* Force number of memory ranks (don't detect) */
-	uint32_t ranks_present;
-	uint32_t ranks;
-
-	/* Add a PCI device in black list. */
-	char *pci_blacklist[APP_MAX_LINKS];
-
-	/* Add a PCI device in white list. */
-	char *pci_whitelist[APP_MAX_LINKS];
-
-	/* Add a virtual device. */
-	char *vdev[APP_MAX_LINKS];
-
-	 /* Use VMware TSC map instead of native RDTSC */
-	uint32_t vmware_tsc_map_present;
-	int vmware_tsc_map;
-
-	 /* Type of this process (primary|secondary|auto) */
-	char *proc_type;
-
-	 /* Set syslog facility */
-	char *syslog;
-
-	/* Set default log level */
-	uint32_t log_level_present;
-	uint32_t log_level;
-
-	/* Display version information on startup */
-	uint32_t version_present;
-	int version;
-
-	/* This help */
-	uint32_t help_present;
-	int help;
-
-	 /* Use malloc instead of hugetlbfs */
-	uint32_t no_huge_present;
-	int no_huge;
-
-	/* Disable PCI */
-	uint32_t no_pci_present;
-	int no_pci;
-
-	/* Disable HPET */
-	uint32_t no_hpet_present;
-	int no_hpet;
-
-	/* No shared config (mmap'd files) */
-	uint32_t no_shconf_present;
-	int no_shconf;
-
-	/* Add driver */
-	char *add_driver;
-
-	/*  Memory to allocate on sockets (comma separated values)*/
-	char *socket_mem;
-
-	/* Directory where hugetlbfs is mounted */
-	char *huge_dir;
-
-	/* Prefix for hugepage filenames */
-	char *file_prefix;
-
-	/* Base virtual address */
-	char *base_virtaddr;
-
-	/* Create /dev/uioX (usually done by hotplug) */
-	uint32_t create_uio_dev_present;
-	int create_uio_dev;
-
-	/* Interrupt mode for VFIO (legacy|msi|msix) */
-	char *vfio_intr;
-
-	uint32_t parsed;
-};
-
-#ifndef APP_APPNAME_SIZE
-#define APP_APPNAME_SIZE                         256
-#endif
-
-#ifndef APP_MAX_MEMPOOLS
-#define APP_MAX_MEMPOOLS                         8
-#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_TAP
-#define APP_MAX_PKTQ_TAP                         APP_MAX_LINKS
-#endif
-
-#define APP_MAX_PKTQ_KNI                         APP_MAX_LINKS
-
-#ifndef APP_MAX_PKTQ_SOURCE
-#define APP_MAX_PKTQ_SOURCE                      64
-#endif
-
-#ifndef APP_MAX_PKTQ_SINK
-#define APP_MAX_PKTQ_SINK                        64
-#endif
-
-#ifndef APP_MAX_MSGQ
-#define APP_MAX_MSGQ                             256
-#endif
-
-#ifndef APP_EAL_ARGC
-#define APP_EAL_ARGC                             64
-#endif
-
-#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
-
-#ifndef APP_THREAD_HEADROOM_STATS_COLLECT
-#define APP_THREAD_HEADROOM_STATS_COLLECT        1
-#endif
-
-#define APP_CORE_MASK_SIZE					\
-	(RTE_MAX_LCORE / 64 + ((RTE_MAX_LCORE % 64) ? 1 : 0))
-
-struct app_params {
-	/* Config */
-	char app_name[APP_APPNAME_SIZE];
-	const char *config_file;
-	const char *script_file;
-	const char *parser_file;
-	const char *output_file;
-	const char *preproc;
-	const char *preproc_args;
-	uint64_t port_mask;
-	uint32_t log_level;
-
-	struct app_eal_params eal_params;
-	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_tap_params tap_params[APP_MAX_PKTQ_TAP];
-	struct app_pktq_kni_params kni_params[APP_MAX_PKTQ_KNI];
-	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_tap;
-	uint32_t n_pktq_kni;
-	uint32_t n_pktq_source;
-	uint32_t n_pktq_sink;
-	uint32_t n_msgq;
-	uint32_t n_pipelines;
-
-	/* Init */
-	char *eal_argv[1 + APP_EAL_ARGC];
-	struct cpu_core_map *core_map;
-	uint64_t core_mask[APP_CORE_MASK_SIZE];
-	struct rte_mempool *mempool[APP_MAX_MEMPOOLS];
-	struct app_link_data link_data[APP_MAX_LINKS];
-	struct rte_ring *swq[APP_MAX_PKTQ_SWQ];
-	struct rte_sched_port *tm[APP_MAX_PKTQ_TM];
-	int tap[APP_MAX_PKTQ_TAP];
-#ifdef RTE_LIBRTE_KNI
-	struct rte_kni *kni[APP_MAX_PKTQ_KNI];
-#endif /* RTE_LIBRTE_KNI */
-	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];
-
-	int eal_argc;
-	uint32_t n_pipeline_types;
-	uint32_t n_cmds;
-};
-
-#define APP_PARAM_VALID(obj) ((obj)->name != NULL)
-
-#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++;					\
-}
-
-#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 "%" PRIu32, 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 "%" SCNu32, &id);				\
-while (0)								\
-
-#define	APP_CHECK(exp, fmt, ...)					\
-do {									\
-	if (!(exp)) {							\
-		fprintf(stderr, fmt "\n", ## __VA_ARGS__);		\
-		abort();						\
-	}								\
-} while (0)
-
-enum app_log_level {
-	APP_LOG_LEVEL_HIGH = 1,
-	APP_LOG_LEVEL_LOW,
-	APP_LOG_LEVELS
-};
-
-#define APP_LOG(app, level, fmt, ...)					\
-do {									\
-	if (app->log_level >= APP_LOG_LEVEL_ ## level)			\
-		fprintf(stdout, "[APP] " fmt "\n", ## __VA_ARGS__);	\
-} while (0)
-
-static inline uint32_t
-app_link_get_n_rxq(struct app_params *app, struct app_link_params *link)
-{
-	uint32_t n_rxq = 0, link_id, i;
-	uint32_t n_pktq_hwq_in = RTE_MIN(app->n_pktq_hwq_in,
-		RTE_DIM(app->hwq_in_params));
-
-	APP_PARAM_GET_ID(link, "LINK", link_id);
-
-	for (i = 0; i < n_pktq_hwq_in; i++) {
-		struct app_pktq_hwq_in_params *p = &app->hwq_in_params[i];
-		uint32_t rxq_link_id, rxq_queue_id;
-
-		sscanf(p->name, "RXQ%" SCNu32 ".%" SCNu32,
-			&rxq_link_id, &rxq_queue_id);
-		if (rxq_link_id == link_id)
-			n_rxq++;
-	}
-
-	return n_rxq;
-}
-
-static inline uint32_t
-app_link_get_n_txq(struct app_params *app, struct app_link_params *link)
-{
-	uint32_t n_txq = 0, link_id, i;
-	uint32_t n_pktq_hwq_out = RTE_MIN(app->n_pktq_hwq_out,
-		RTE_DIM(app->hwq_out_params));
-
-	APP_PARAM_GET_ID(link, "LINK", link_id);
-
-	for (i = 0; i < n_pktq_hwq_out; i++) {
-		struct app_pktq_hwq_out_params *p = &app->hwq_out_params[i];
-		uint32_t txq_link_id, txq_queue_id;
-
-		sscanf(p->name, "TXQ%" SCNu32 ".%" SCNu32,
-			&txq_link_id, &txq_queue_id);
-		if (txq_link_id == link_id)
-			n_txq++;
-	}
-
-	return n_txq;
-}
-
-static inline uint32_t
-app_rxq_get_readers(struct app_params *app, struct app_pktq_hwq_in_params *rxq)
-{
-	uint32_t pos = rxq - app->hwq_in_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_readers = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_in = RTE_MIN(p->n_pktq_in, RTE_DIM(p->pktq_in));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_in; j++) {
-			struct app_pktq_in_params *pktq = &p->pktq_in[j];
-
-			if ((pktq->type == APP_PKTQ_IN_HWQ) &&
-				(pktq->id == pos))
-				n_readers++;
-		}
-	}
-
-	return n_readers;
-}
-
-static inline uint32_t
-app_swq_get_readers(struct app_params *app, struct app_pktq_swq_params *swq)
-{
-	uint32_t pos = swq - app->swq_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_readers = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_in = RTE_MIN(p->n_pktq_in, RTE_DIM(p->pktq_in));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_in; j++) {
-			struct app_pktq_in_params *pktq = &p->pktq_in[j];
-
-			if ((pktq->type == APP_PKTQ_IN_SWQ) &&
-				(pktq->id == pos))
-				n_readers++;
-		}
-	}
-
-	return n_readers;
-}
-
-static inline struct app_pipeline_params *
-app_swq_get_reader(struct app_params *app,
-	struct app_pktq_swq_params *swq,
-	uint32_t *pktq_in_id)
-{
-	struct app_pipeline_params *reader = NULL;
-	uint32_t pos = swq - app->swq_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_readers = 0, id = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_in = RTE_MIN(p->n_pktq_in, RTE_DIM(p->pktq_in));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_in; j++) {
-			struct app_pktq_in_params *pktq = &p->pktq_in[j];
-
-			if ((pktq->type == APP_PKTQ_IN_SWQ) &&
-				(pktq->id == pos)) {
-				n_readers++;
-				reader = p;
-				id = j;
-			}
-		}
-	}
-
-	if (n_readers != 1)
-		return NULL;
-
-	*pktq_in_id = id;
-	return reader;
-}
-
-static inline uint32_t
-app_tm_get_readers(struct app_params *app, struct app_pktq_tm_params *tm)
-{
-	uint32_t pos = tm - app->tm_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_readers = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_in = RTE_MIN(p->n_pktq_in, RTE_DIM(p->pktq_in));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_in; j++) {
-			struct app_pktq_in_params *pktq = &p->pktq_in[j];
-
-			if ((pktq->type == APP_PKTQ_IN_TM) &&
-				(pktq->id == pos))
-				n_readers++;
-		}
-	}
-
-	return n_readers;
-}
-
-static inline struct app_pipeline_params *
-app_tm_get_reader(struct app_params *app,
-	struct app_pktq_tm_params *tm,
-	uint32_t *pktq_in_id)
-{
-	struct app_pipeline_params *reader = NULL;
-	uint32_t pos = tm - app->tm_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_readers = 0, id = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_in = RTE_MIN(p->n_pktq_in, RTE_DIM(p->pktq_in));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_in; j++) {
-			struct app_pktq_in_params *pktq = &p->pktq_in[j];
-
-			if ((pktq->type == APP_PKTQ_IN_TM) &&
-				(pktq->id == pos)) {
-				n_readers++;
-				reader = p;
-				id = j;
-			}
-		}
-	}
-
-	if (n_readers != 1)
-		return NULL;
-
-	*pktq_in_id = id;
-	return reader;
-}
-
-static inline uint32_t
-app_tap_get_readers(struct app_params *app, struct app_pktq_tap_params *tap)
-{
-	uint32_t pos = tap - app->tap_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_readers = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_in = RTE_MIN(p->n_pktq_in, RTE_DIM(p->pktq_in));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_in; j++) {
-			struct app_pktq_in_params *pktq = &p->pktq_in[j];
-
-			if ((pktq->type == APP_PKTQ_IN_TAP) &&
-				(pktq->id == pos))
-				n_readers++;
-		}
-	}
-
-	return n_readers;
-}
-
-static inline struct app_pipeline_params *
-app_tap_get_reader(struct app_params *app,
-	struct app_pktq_tap_params *tap,
-	uint32_t *pktq_in_id)
-{
-	struct app_pipeline_params *reader = NULL;
-	uint32_t pos = tap - app->tap_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_readers = 0, id = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_in = RTE_MIN(p->n_pktq_in, RTE_DIM(p->pktq_in));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_in; j++) {
-			struct app_pktq_in_params *pktq = &p->pktq_in[j];
-
-			if ((pktq->type == APP_PKTQ_IN_TAP) &&
-				(pktq->id == pos)) {
-				n_readers++;
-				reader = p;
-				id = j;
-			}
-		}
-	}
-
-	if (n_readers != 1)
-		return NULL;
-
-	*pktq_in_id = id;
-	return reader;
-}
-
-static inline uint32_t
-app_kni_get_readers(struct app_params *app, struct app_pktq_kni_params *kni)
-{
-	uint32_t pos = kni - app->kni_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_readers = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_in = RTE_MIN(p->n_pktq_in, RTE_DIM(p->pktq_in));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_in; j++) {
-			struct app_pktq_in_params *pktq = &p->pktq_in[j];
-
-			if ((pktq->type == APP_PKTQ_IN_KNI) &&
-				(pktq->id == pos))
-				n_readers++;
-		}
-	}
-
-	return n_readers;
-}
-
-static inline struct app_pipeline_params *
-app_kni_get_reader(struct app_params *app,
-				  struct app_pktq_kni_params *kni,
-				  uint32_t *pktq_in_id)
-{
-	struct app_pipeline_params *reader = NULL;
-	uint32_t pos = kni - app->kni_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_readers = 0, id = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_in = RTE_MIN(p->n_pktq_in, RTE_DIM(p->pktq_in));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_in; j++) {
-			struct app_pktq_in_params *pktq = &p->pktq_in[j];
-
-			if ((pktq->type == APP_PKTQ_IN_KNI) &&
-				(pktq->id == pos)) {
-				n_readers++;
-				reader = p;
-				id = j;
-			}
-		}
-	}
-
-	if (n_readers != 1)
-		return NULL;
-
-	*pktq_in_id = id;
-	return reader;
-}
-
-static inline uint32_t
-app_source_get_readers(struct app_params *app,
-struct app_pktq_source_params *source)
-{
-	uint32_t pos = source - app->source_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_readers = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_in = RTE_MIN(p->n_pktq_in, RTE_DIM(p->pktq_in));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_in; j++) {
-			struct app_pktq_in_params *pktq = &p->pktq_in[j];
-
-			if ((pktq->type == APP_PKTQ_IN_SOURCE) &&
-				(pktq->id == pos))
-				n_readers++;
-		}
-	}
-
-	return n_readers;
-}
-
-static inline uint32_t
-app_msgq_get_readers(struct app_params *app, struct app_msgq_params *msgq)
-{
-	uint32_t pos = msgq - app->msgq_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_readers = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_msgq_in = RTE_MIN(p->n_msgq_in, RTE_DIM(p->msgq_in));
-		uint32_t j;
-
-		for (j = 0; j < n_msgq_in; j++)
-			if (p->msgq_in[j] == pos)
-				n_readers++;
-	}
-
-	return n_readers;
-}
-
-static inline uint32_t
-app_txq_get_writers(struct app_params *app, struct app_pktq_hwq_out_params *txq)
-{
-	uint32_t pos = txq - app->hwq_out_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_writers = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_out = RTE_MIN(p->n_pktq_out,
-			RTE_DIM(p->pktq_out));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_out; j++) {
-			struct app_pktq_out_params *pktq = &p->pktq_out[j];
-
-			if ((pktq->type == APP_PKTQ_OUT_HWQ) &&
-				(pktq->id == pos))
-				n_writers++;
-		}
-	}
-
-	return n_writers;
-}
-
-static inline uint32_t
-app_swq_get_writers(struct app_params *app, struct app_pktq_swq_params *swq)
-{
-	uint32_t pos = swq - app->swq_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_writers = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_out = RTE_MIN(p->n_pktq_out,
-			RTE_DIM(p->pktq_out));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_out; j++) {
-			struct app_pktq_out_params *pktq = &p->pktq_out[j];
-
-			if ((pktq->type == APP_PKTQ_OUT_SWQ) &&
-				(pktq->id == pos))
-				n_writers++;
-		}
-	}
-
-	return n_writers;
-}
-
-static inline struct app_pipeline_params *
-app_swq_get_writer(struct app_params *app,
-	struct app_pktq_swq_params *swq,
-	uint32_t *pktq_out_id)
-{
-	struct app_pipeline_params *writer = NULL;
-	uint32_t pos = swq - app->swq_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_writers = 0, id = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_out = RTE_MIN(p->n_pktq_out,
-			RTE_DIM(p->pktq_out));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_out; j++) {
-			struct app_pktq_out_params *pktq = &p->pktq_out[j];
-
-			if ((pktq->type == APP_PKTQ_OUT_SWQ) &&
-				(pktq->id == pos)) {
-				n_writers++;
-				writer = p;
-				id = j;
-			}
-		}
-	}
-
-	if (n_writers != 1)
-		return NULL;
-
-	*pktq_out_id = id;
-	return writer;
-}
-
-static inline uint32_t
-app_tm_get_writers(struct app_params *app, struct app_pktq_tm_params *tm)
-{
-	uint32_t pos = tm - app->tm_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_writers = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_out = RTE_MIN(p->n_pktq_out,
-			RTE_DIM(p->pktq_out));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_out; j++) {
-			struct app_pktq_out_params *pktq = &p->pktq_out[j];
-
-			if ((pktq->type == APP_PKTQ_OUT_TM) &&
-				(pktq->id == pos))
-				n_writers++;
-		}
-	}
-
-	return n_writers;
-}
-
-static inline struct app_pipeline_params *
-app_tm_get_writer(struct app_params *app,
-	struct app_pktq_tm_params *tm,
-	uint32_t *pktq_out_id)
-{
-	struct app_pipeline_params *writer = NULL;
-	uint32_t pos = tm - app->tm_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_writers = 0, id = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_out = RTE_MIN(p->n_pktq_out,
-			RTE_DIM(p->pktq_out));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_out; j++) {
-			struct app_pktq_out_params *pktq = &p->pktq_out[j];
-
-			if ((pktq->type == APP_PKTQ_OUT_TM) &&
-				(pktq->id == pos)) {
-				n_writers++;
-				writer = p;
-				id = j;
-			}
-		}
-	}
-
-	if (n_writers != 1)
-		return NULL;
-
-	*pktq_out_id = id;
-	return writer;
-}
-
-static inline uint32_t
-app_tap_get_writers(struct app_params *app, struct app_pktq_tap_params *tap)
-{
-	uint32_t pos = tap - app->tap_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_writers = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_out = RTE_MIN(p->n_pktq_out,
-			RTE_DIM(p->pktq_out));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_out; j++) {
-			struct app_pktq_out_params *pktq = &p->pktq_out[j];
-
-		if ((pktq->type == APP_PKTQ_OUT_TAP) &&
-			(pktq->id == pos))
-			n_writers++;
-		}
-	}
-
-	return n_writers;
-}
-
-static inline struct app_pipeline_params *
-app_tap_get_writer(struct app_params *app,
-	struct app_pktq_tap_params *tap,
-	uint32_t *pktq_out_id)
-{
-	struct app_pipeline_params *writer = NULL;
-	uint32_t pos = tap - app->tap_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_writers = 0, id = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_out = RTE_MIN(p->n_pktq_out,
-			RTE_DIM(p->pktq_out));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_out; j++) {
-			struct app_pktq_out_params *pktq = &p->pktq_out[j];
-
-			if ((pktq->type == APP_PKTQ_OUT_TAP) &&
-				(pktq->id == pos)) {
-				n_writers++;
-				writer = p;
-				id = j;
-			}
-		}
-	}
-
-	if (n_writers != 1)
-		return NULL;
-
-	*pktq_out_id = id;
-	return writer;
-}
-
-static inline uint32_t
-app_kni_get_writers(struct app_params *app, struct app_pktq_kni_params *kni)
-{
-	uint32_t pos = kni - app->kni_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_writers = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_out = RTE_MIN(p->n_pktq_out,
-			RTE_DIM(p->pktq_out));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_out; j++) {
-			struct app_pktq_out_params *pktq = &p->pktq_out[j];
-
-			if ((pktq->type == APP_PKTQ_OUT_KNI) &&
-				(pktq->id == pos))
-				n_writers++;
-		}
-	}
-
-	return n_writers;
-}
-
-static inline struct app_pipeline_params *
-app_kni_get_writer(struct app_params *app,
-				  struct app_pktq_kni_params *kni,
-				  uint32_t *pktq_out_id)
-{
-	struct app_pipeline_params *writer = NULL;
-	uint32_t pos = kni - app->kni_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_writers = 0, id = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_out = RTE_MIN(p->n_pktq_out,
-			RTE_DIM(p->pktq_out));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_out; j++) {
-			struct app_pktq_out_params *pktq = &p->pktq_out[j];
-
-			if ((pktq->type == APP_PKTQ_OUT_KNI) &&
-				(pktq->id == pos)) {
-				n_writers++;
-				writer = p;
-				id = j;
-			}
-		}
-	}
-
-	if (n_writers != 1)
-		return NULL;
-
-	*pktq_out_id = id;
-	return writer;
-}
-
-static inline uint32_t
-app_sink_get_writers(struct app_params *app, struct app_pktq_sink_params *sink)
-{
-	uint32_t pos = sink - app->sink_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_writers = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_out = RTE_MIN(p->n_pktq_out,
-			RTE_DIM(p->pktq_out));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_out; j++) {
-			struct app_pktq_out_params *pktq = &p->pktq_out[j];
-
-			if ((pktq->type == APP_PKTQ_OUT_SINK) &&
-				(pktq->id == pos))
-				n_writers++;
-		}
-	}
-
-	return n_writers;
-}
-
-static inline uint32_t
-app_msgq_get_writers(struct app_params *app, struct app_msgq_params *msgq)
-{
-	uint32_t pos = msgq - app->msgq_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_writers = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_msgq_out = RTE_MIN(p->n_msgq_out,
-			RTE_DIM(p->msgq_out));
-		uint32_t j;
-
-		for (j = 0; j < n_msgq_out; j++)
-			if (p->msgq_out[j] == pos)
-				n_writers++;
-	}
-
-	return n_writers;
-}
-
-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%" SCNu32 ".%" SCNu32,
-		&rxq_link_id, &rxq_queue_id);
-	sprintf(link_name, "LINK%" PRIu32, 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%" SCNu32 ".%" SCNu32,
-		&txq_link_id, &txq_queue_id);
-	sprintf(link_name, "LINK%" PRIu32, 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%" PRIu32, &link_id);
-	sprintf(link_name, "LINK%" PRIu32, 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];
-}
-
-static inline struct app_link_params *
-app_get_link_for_kni(struct app_params *app, struct app_pktq_kni_params *p_kni)
-{
-	char link_name[APP_PARAM_NAME_SIZE];
-	uint32_t link_id;
-	ssize_t link_param_idx;
-
-	sscanf(p_kni->name, "KNI%" PRIu32, &link_id);
-	sprintf(link_name, "LINK%" PRIu32, 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_kni->name);
-
-	return &app->link_params[link_param_idx];
-}
-
-static inline uint32_t
-app_core_is_enabled(struct app_params *app, uint32_t lcore_id)
-{
-	return(app->core_mask[lcore_id / 64] &
-		(1LLU << (lcore_id % 64)));
-}
-
-static inline void
-app_core_enable_in_core_mask(struct app_params *app, int lcore_id)
-{
-	app->core_mask[lcore_id / 64] |= 1LLU << (lcore_id % 64);
-
-}
-
-static inline void
-app_core_build_core_mask_string(struct app_params *app, char *mask_buffer)
-{
-	int i;
-
-	mask_buffer[0] = '\0';
-	for (i = (int)RTE_DIM(app->core_mask); i > 0; i--) {
-		/* For Hex representation of bits in uint64_t */
-		char buffer[(64 / 8) * 2 + 1];
-		memset(buffer, 0, sizeof(buffer));
-		snprintf(buffer, sizeof(buffer), "%016" PRIx64,
-			 app->core_mask[i-1]);
-		strcat(mask_buffer, buffer);
-	}
-}
-
-int app_config_init(struct app_params *app);
-
-int app_config_args(struct app_params *app,
-	int argc, char **argv);
-
-int app_config_preproc(struct app_params *app);
-
-int app_config_parse(struct app_params *app,
-	const char *file_name);
-
-int app_config_parse_tm(struct app_params *app);
-
-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);
-
-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_check.c b/examples/ip_pipeline/config_check.c
deleted file mode 100644
index 86d1191..0000000
--- a/examples/ip_pipeline/config_check.c
+++ /dev/null
@@ -1,488 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2016 Intel Corporation
- */
-
-#include <stdio.h>
-
-#include <rte_ip.h>
-
-#include "app.h"
-
-static void
-check_mempools(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_mempools; i++) {
-		struct app_mempool_params *p = &app->mempool_params[i];
-
-		APP_CHECK((p->pool_size > 0),
-			"Mempool %s size is 0\n", p->name);
-
-		APP_CHECK((p->cache_size > 0),
-			"Mempool %s cache size is 0\n", p->name);
-
-		APP_CHECK(rte_is_power_of_2(p->cache_size),
-			"Mempool %s cache size not a power of 2\n", p->name);
-	}
-}
-
-static inline uint32_t
-link_rxq_used(struct app_link_params *link, uint32_t q_id)
-{
-	uint32_t i;
-
-	if ((link->arp_q == q_id) ||
-		(link->tcp_syn_q == q_id) ||
-		(link->ip_local_q == q_id) ||
-		(link->tcp_local_q == q_id) ||
-		(link->udp_local_q == q_id) ||
-		(link->sctp_local_q == q_id))
-		return 1;
-
-	for (i = 0; i < link->n_rss_qs; i++)
-		if (link->rss_qs[i] == q_id)
-			return 1;
-
-	return 0;
-}
-
-static void
-check_links(struct app_params *app)
-{
-	uint32_t i;
-
-	/* Check that number of links matches the port mask */
-	if (app->port_mask) {
-		uint32_t n_links_port_mask =
-			__builtin_popcountll(app->port_mask);
-
-		APP_CHECK((app->n_links == n_links_port_mask),
-			"Not enough links provided in the PORT_MASK\n");
-	}
-
-	for (i = 0; i < app->n_links; i++) {
-		struct app_link_params *link = &app->link_params[i];
-		uint32_t rxq_max, n_rxq, n_txq, link_id, i;
-
-		APP_PARAM_GET_ID(link, "LINK", link_id);
-
-		/* Check that link RXQs are contiguous */
-		rxq_max = 0;
-		if (link->arp_q > rxq_max)
-			rxq_max = link->arp_q;
-		if (link->tcp_syn_q > rxq_max)
-			rxq_max = link->tcp_syn_q;
-		if (link->ip_local_q > rxq_max)
-			rxq_max = link->ip_local_q;
-		if (link->tcp_local_q > rxq_max)
-			rxq_max = link->tcp_local_q;
-		if (link->udp_local_q > rxq_max)
-			rxq_max = link->udp_local_q;
-		if (link->sctp_local_q > rxq_max)
-			rxq_max = link->sctp_local_q;
-		for (i = 0; i < link->n_rss_qs; i++)
-			if (link->rss_qs[i] > rxq_max)
-				rxq_max = link->rss_qs[i];
-
-		for (i = 1; i <= rxq_max; i++)
-			APP_CHECK((link_rxq_used(link, i)),
-				"%s RXQs are not contiguous (A)\n", link->name);
-
-		n_rxq = app_link_get_n_rxq(app, link);
-
-		APP_CHECK((n_rxq), "%s does not have any RXQ\n", link->name);
-
-		APP_CHECK((n_rxq == rxq_max + 1),
-			"%s RXQs are not contiguous (B)\n", link->name);
-
-		for (i = 0; i < n_rxq; i++) {
-			char name[APP_PARAM_NAME_SIZE];
-			int pos;
-
-			sprintf(name, "RXQ%" PRIu32 ".%" PRIu32,
-				link_id, i);
-			pos = APP_PARAM_FIND(app->hwq_in_params, name);
-			APP_CHECK((pos >= 0),
-				"%s RXQs are not contiguous (C)\n", link->name);
-		}
-
-		/* Check that link TXQs are contiguous */
-		n_txq = app_link_get_n_txq(app, link);
-
-		APP_CHECK((n_txq),  "%s does not have any TXQ\n", link->name);
-
-		for (i = 0; i < n_txq; i++) {
-			char name[APP_PARAM_NAME_SIZE];
-			int pos;
-
-			sprintf(name, "TXQ%" PRIu32 ".%" PRIu32,
-				link_id, i);
-			pos = APP_PARAM_FIND(app->hwq_out_params, name);
-			APP_CHECK((pos >= 0),
-				"%s TXQs are not contiguous\n", link->name);
-		}
-	}
-}
-
-static void
-check_rxqs(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_pktq_hwq_in; i++) {
-		struct app_pktq_hwq_in_params *p = &app->hwq_in_params[i];
-		uint32_t n_readers = app_rxq_get_readers(app, p);
-
-		APP_CHECK((p->size > 0),
-			"%s size is 0\n", p->name);
-
-		APP_CHECK((rte_is_power_of_2(p->size)),
-			"%s size is not a power of 2\n", p->name);
-
-		APP_CHECK((p->burst > 0),
-			"%s burst size is 0\n", p->name);
-
-		APP_CHECK((p->burst <= p->size),
-			"%s burst size is bigger than its size\n", p->name);
-
-		APP_CHECK((n_readers != 0),
-			"%s has no reader\n", p->name);
-
-		APP_CHECK((n_readers == 1),
-			"%s has more than one reader\n", p->name);
-	}
-}
-
-static void
-check_txqs(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_pktq_hwq_out; i++) {
-		struct app_pktq_hwq_out_params *p = &app->hwq_out_params[i];
-		uint32_t n_writers = app_txq_get_writers(app, p);
-
-		APP_CHECK((p->size > 0),
-			"%s size is 0\n", p->name);
-
-		APP_CHECK((rte_is_power_of_2(p->size)),
-			"%s size is not a power of 2\n", p->name);
-
-		APP_CHECK((p->burst > 0),
-			"%s burst size is 0\n", p->name);
-
-		APP_CHECK((p->burst <= p->size),
-			"%s burst size is bigger than its size\n", p->name);
-
-		APP_CHECK((n_writers != 0),
-			"%s has no writer\n", p->name);
-
-		APP_CHECK((n_writers == 1),
-			"%s has more than one writer\n", p->name);
-	}
-}
-
-static void
-check_swqs(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_pktq_swq; i++) {
-		struct app_pktq_swq_params *p = &app->swq_params[i];
-		uint32_t n_readers = app_swq_get_readers(app, p);
-		uint32_t n_writers = app_swq_get_writers(app, p);
-		uint32_t n_flags;
-
-		APP_CHECK((p->size > 0),
-			"%s size is 0\n", p->name);
-
-		APP_CHECK((rte_is_power_of_2(p->size)),
-			"%s size is not a power of 2\n", p->name);
-
-		APP_CHECK((p->burst_read > 0),
-			"%s read burst size is 0\n", p->name);
-
-		APP_CHECK((p->burst_read <= p->size),
-			"%s read burst size is bigger than its size\n",
-			p->name);
-
-		APP_CHECK((p->burst_write > 0),
-			"%s write burst size is 0\n", p->name);
-
-		APP_CHECK((p->burst_write <= p->size),
-			"%s write burst size is bigger than its size\n",
-			p->name);
-
-		APP_CHECK((n_readers != 0),
-			"%s has no reader\n", p->name);
-
-		if (n_readers > 1)
-			APP_LOG(app, LOW, "%s has more than one reader", p->name);
-
-		APP_CHECK((n_writers != 0),
-			"%s has no writer\n", p->name);
-
-		if (n_writers > 1)
-			APP_LOG(app, LOW, "%s has more than one writer", p->name);
-
-		n_flags = p->ipv4_frag + p->ipv6_frag + p->ipv4_ras + p->ipv6_ras;
-
-		APP_CHECK((n_flags < 2),
-			"%s has more than one fragmentation or reassembly mode enabled\n",
-			p->name);
-
-		APP_CHECK((!((n_readers > 1) && (n_flags == 1))),
-			"%s has more than one reader when fragmentation or reassembly"
-			" mode enabled\n",
-			p->name);
-
-		APP_CHECK((!((n_writers > 1) && (n_flags == 1))),
-			"%s has more than one writer when fragmentation or reassembly"
-			" mode enabled\n",
-			p->name);
-
-		n_flags = p->ipv4_ras + p->ipv6_ras;
-
-		APP_CHECK((!((p->dropless == 1) && (n_flags == 1))),
-			"%s has dropless when reassembly mode enabled\n", p->name);
-
-		n_flags = p->ipv4_frag + p->ipv6_frag;
-
-		if (n_flags == 1) {
-			uint16_t ip_hdr_size = (p->ipv4_frag) ? sizeof(struct ipv4_hdr) :
-				sizeof(struct ipv6_hdr);
-
-			APP_CHECK((p->mtu > ip_hdr_size),
-				"%s mtu size is smaller than ip header\n", p->name);
-
-			APP_CHECK((!((p->mtu - ip_hdr_size) % 8)),
-				"%s mtu size is incorrect\n", p->name);
-		}
-	}
-}
-
-static void
-check_tms(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_pktq_tm; i++) {
-		struct app_pktq_tm_params *p = &app->tm_params[i];
-		uint32_t n_readers = app_tm_get_readers(app, p);
-		uint32_t n_writers = app_tm_get_writers(app, p);
-
-		APP_CHECK((n_readers != 0),
-			"%s has no reader\n", p->name);
-
-		APP_CHECK((n_readers == 1),
-			"%s has more than one reader\n", p->name);
-
-		APP_CHECK((n_writers != 0),
-			"%s has no writer\n", p->name);
-
-		APP_CHECK((n_writers == 1),
-			"%s has more than one writer\n", p->name);
-	}
-}
-
-static void
-check_taps(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_pktq_tap; i++) {
-		struct app_pktq_tap_params *p = &app->tap_params[i];
-		uint32_t n_readers = app_tap_get_readers(app, p);
-		uint32_t n_writers = app_tap_get_writers(app, p);
-
-		APP_CHECK((n_readers != 0),
-			"%s has no reader\n", p->name);
-
-		APP_CHECK((n_readers == 1),
-			"%s has more than one reader\n", p->name);
-
-		APP_CHECK((n_writers != 0),
-			"%s has no writer\n", p->name);
-
-		APP_CHECK((n_writers == 1),
-			"%s has more than one writer\n", p->name);
-
-		APP_CHECK((p->burst_read > 0),
-			"%s read burst size is 0\n", p->name);
-
-		APP_CHECK((p->burst_write > 0),
-			"%s write burst size is 0\n", p->name);
-	}
-}
-
-static void
-check_knis(struct app_params *app) {
-	uint32_t i;
-
-	for (i = 0; i < app->n_pktq_kni; i++) {
-		struct app_pktq_kni_params *p = &app->kni_params[i];
-		uint32_t n_readers = app_kni_get_readers(app, p);
-		uint32_t n_writers = app_kni_get_writers(app, p);
-
-		APP_CHECK((n_readers != 0),
-			"%s has no reader\n", p->name);
-
-		APP_CHECK((n_readers == 1),
-			"%s has more than one reader\n", p->name);
-
-		APP_CHECK((n_writers != 0),
-			"%s has no writer\n", p->name);
-
-		APP_CHECK((n_writers == 1),
-			"%s has more than one writer\n", p->name);
-	}
-}
-
-static void
-check_sources(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_pktq_source; i++) {
-		struct app_pktq_source_params *p = &app->source_params[i];
-		uint32_t n_readers = app_source_get_readers(app, p);
-
-		APP_CHECK((n_readers != 0),
-			"%s has no reader\n", p->name);
-
-		APP_CHECK((n_readers == 1),
-			"%s has more than one reader\n", p->name);
-	}
-}
-
-static void
-check_sinks(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_pktq_sink; i++) {
-		struct app_pktq_sink_params *p = &app->sink_params[i];
-		uint32_t n_writers = app_sink_get_writers(app, p);
-
-		APP_CHECK((n_writers != 0),
-			"%s has no writer\n", p->name);
-
-		APP_CHECK((n_writers == 1),
-			"%s has more than one writer\n", p->name);
-	}
-}
-
-static void
-check_msgqs(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_msgq; i++) {
-		struct app_msgq_params *p = &app->msgq_params[i];
-		uint32_t n_readers = app_msgq_get_readers(app, p);
-		uint32_t n_writers = app_msgq_get_writers(app, p);
-		uint32_t msgq_req_pipeline, msgq_rsp_pipeline;
-		uint32_t msgq_req_core, msgq_rsp_core;
-
-		APP_CHECK((p->size > 0),
-			"%s size is 0\n", p->name);
-
-		APP_CHECK((rte_is_power_of_2(p->size)),
-			"%s size is not a power of 2\n", p->name);
-
-		msgq_req_pipeline = (strncmp(p->name, "MSGQ-REQ-PIPELINE",
-			strlen("MSGQ-REQ-PIPELINE")) == 0);
-
-		msgq_rsp_pipeline = (strncmp(p->name, "MSGQ-RSP-PIPELINE",
-			strlen("MSGQ-RSP-PIPELINE")) == 0);
-
-		msgq_req_core = (strncmp(p->name, "MSGQ-REQ-CORE",
-			strlen("MSGQ-REQ-CORE")) == 0);
-
-		msgq_rsp_core = (strncmp(p->name, "MSGQ-RSP-CORE",
-			strlen("MSGQ-RSP-CORE")) == 0);
-
-		if ((msgq_req_pipeline == 0) &&
-			(msgq_rsp_pipeline == 0) &&
-			(msgq_req_core == 0) &&
-			(msgq_rsp_core == 0)) {
-			APP_CHECK((n_readers != 0),
-				"%s has no reader\n", p->name);
-
-			APP_CHECK((n_readers == 1),
-				"%s has more than one reader\n", p->name);
-
-			APP_CHECK((n_writers != 0),
-				"%s has no writer\n", p->name);
-
-			APP_CHECK((n_writers == 1),
-				"%s has more than one writer\n", p->name);
-		}
-
-		if (msgq_req_pipeline) {
-			struct app_pipeline_params *pipeline;
-			uint32_t pipeline_id;
-
-			APP_PARAM_GET_ID(p, "MSGQ-REQ-PIPELINE", pipeline_id);
-
-			APP_PARAM_FIND_BY_ID(app->pipeline_params,
-				"PIPELINE",
-				pipeline_id,
-				pipeline);
-
-			APP_CHECK((pipeline != NULL),
-				"%s is not associated with a valid pipeline\n",
-				p->name);
-		}
-
-		if (msgq_rsp_pipeline) {
-			struct app_pipeline_params *pipeline;
-			uint32_t pipeline_id;
-
-			APP_PARAM_GET_ID(p, "MSGQ-RSP-PIPELINE", pipeline_id);
-
-			APP_PARAM_FIND_BY_ID(app->pipeline_params,
-				"PIPELINE",
-				pipeline_id,
-				pipeline);
-
-			APP_CHECK((pipeline != NULL),
-				"%s is not associated with a valid pipeline\n",
-				p->name);
-		}
-	}
-}
-
-static void
-check_pipelines(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-
-		APP_CHECK((p->n_msgq_in == p->n_msgq_out),
-			"%s number of input MSGQs does not match "
-			"the number of output MSGQs\n", p->name);
-	}
-}
-
-int
-app_config_check(struct app_params *app)
-{
-	check_mempools(app);
-	check_links(app);
-	check_rxqs(app);
-	check_txqs(app);
-	check_swqs(app);
-	check_tms(app);
-	check_taps(app);
-	check_knis(app);
-	check_sources(app);
-	check_sinks(app);
-	check_msgqs(app);
-	check_pipelines(app);
-
-	return 0;
-}
diff --git a/examples/ip_pipeline/config_parse.c b/examples/ip_pipeline/config_parse.c
deleted file mode 100644
index e90499e..0000000
--- a/examples/ip_pipeline/config_parse.c
+++ /dev/null
@@ -1,3395 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2016 Intel Corporation
- */
-
-#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 <libgen.h>
-#include <unistd.h>
-#include <sys/wait.h>
-
-#include <rte_errno.h>
-#include <rte_cfgfile.h>
-#include <rte_string_fns.h>
-
-#include "app.h"
-#include "parser.h"
-
-/**
- * Default config values
- **/
-
-static struct app_params app_params_default = {
-	.config_file = "./config/ip_pipeline.cfg",
-	.log_level = APP_LOG_LEVEL_HIGH,
-	.port_mask = 0,
-
-	.eal_params = {
-		.channels = 4,
-	},
-};
-
-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_q = 0,
-	.ip_local_q = 0,
-	.tcp_local_q = 0,
-	.udp_local_q = 0,
-	.sctp_local_q = 0,
-	.rss_qs = {0},
-	.n_rss_qs = 0,
-	.rss_proto_ipv4 = ETH_RSS_IPV4,
-	.rss_proto_ipv6 = ETH_RSS_IPV6,
-	.rss_proto_l2 = 0,
-	.state = 0,
-	.ip = 0,
-	.depth = 0,
-	.mac_addr = 0,
-	.pci_bdf = {0},
-
-	.conf = {
-		.link_speeds = 0,
-		.rxmode = {
-			.mq_mode = ETH_MQ_RX_NONE,
-
-			.ignore_offload_bitfield = 1,
-			.offloads = DEV_RX_OFFLOAD_CRC_STRIP,
-
-			.max_rx_pkt_len = 9000, /* Jumbo frame max packet len */
-			.split_hdr_size = 0, /* Header split buffer size */
-		},
-		.rx_adv_conf = {
-			.rss_conf = {
-				.rss_key = NULL,
-				.rss_key_len = 40,
-				.rss_hf = 0,
-			},
-		},
-		.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_IGNORE,
-		.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,
-	.ipv4_frag = 0,
-	.ipv6_frag = 0,
-	.ipv4_ras = 0,
-	.ipv6_ras = 0,
-	.mtu = 0,
-	.metadata_size = 0,
-	.mempool_direct_id = 0,
-	.mempool_indirect_id = 0,
-};
-
-struct app_pktq_tm_params default_tm_params = {
-	.parsed = 0,
-	.file_name = "./config/tm_profile.cfg",
-	.burst_read = 24,
-	.burst_write = 32,
-};
-
-struct app_pktq_tap_params default_tap_params = {
-	.parsed = 0,
-	.burst_read = 32,
-	.burst_write = 32,
-	.dropless = 0,
-	.n_retries = 0,
-	.mempool_id = 0,
-};
-
-struct app_pktq_kni_params default_kni_params = {
-	.parsed = 0,
-	.socket_id = 0,
-	.core_id = 0,
-	.hyper_th_id = 0,
-	.force_bind = 0,
-
-	.mempool_id = 0,
-	.burst_read = 32,
-	.burst_write = 32,
-	.dropless = 0,
-	.n_retries = 0,
-};
-
-struct app_pktq_source_params default_source_params = {
-	.parsed = 0,
-	.mempool_id = 0,
-	.burst = 32,
-	.file_name = "./config/packets.pcap",
-	.n_bytes_per_pkt = 0,
-};
-
-struct app_pktq_sink_params default_sink_params = {
-	.parsed = 0,
-	.file_name = NULL,
-	.n_pkts_to_dump = 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] "
-	"[-l LOG_LEVEL] [--preproc PREPROCESSOR] [--preproc-args ARGS]\n"
-	"\n"
-	"Arguments:\n"
-	"\t-f CONFIG_FILE: Default config file is %s\n"
-	"\t-p PORT_MASK: Mask of NIC port IDs in hex format (generated from "
-		"config file when not provided)\n"
-	"\t-s SCRIPT_FILE: No CLI script file is run when not specified\n"
-	"\t-l LOG_LEVEL: 0 = NONE, 1 = HIGH PRIO (default), 2 = LOW PRIO\n"
-	"\t--preproc PREPROCESSOR: Configuration file pre-processor\n"
-	"\t--preproc-args ARGS: Arguments to be passed to pre-processor\n"
-	"\n";
-
-static void
-app_print_usage(char *prgname)
-{
-	rte_exit(0, app_usage, prgname, app_params_default.config_file);
-}
-
-#define APP_PARAM_ADD(set, key)						\
-({									\
-	ssize_t pos = APP_PARAM_FIND(set, key);				\
-	ssize_t size = RTE_DIM(set);					\
-									\
-	if (pos < 0) {							\
-		for (pos = 0; pos < size; pos++) {			\
-			if (!APP_PARAM_VALID(&((set)[pos])))		\
-				break;					\
-		}							\
-									\
-		APP_CHECK((pos < size),					\
-			"Parse error: size of %s is limited to %u elements",\
-			#set, (uint32_t) size);				\
-									\
-		(set)[pos].name = strdup(key);				\
-		APP_CHECK(((set)[pos].name),				\
-			"Parse error: no free memory");			\
-	}								\
-	pos;								\
-})
-
-#define APP_PARAM_ADD_LINK_FOR_RXQ(app, rxq_name)			\
-({									\
-	char link_name[APP_PARAM_NAME_SIZE];				\
-	ssize_t link_param_pos;						\
-	uint32_t link_id, queue_id;				\
-									\
-	sscanf((rxq_name), "RXQ%" SCNu32 ".%" SCNu32, &link_id, &queue_id);\
-	sprintf(link_name, "LINK%" PRIu32, link_id);			\
-	link_param_pos = APP_PARAM_ADD((app)->link_params, link_name);	\
-	link_param_pos;							\
-})
-
-#define APP_PARAM_ADD_LINK_FOR_TXQ(app, txq_name)			\
-({									\
-	char link_name[APP_PARAM_NAME_SIZE];				\
-	ssize_t link_param_pos;						\
-	uint32_t link_id, queue_id;					\
-									\
-	sscanf((txq_name), "TXQ%" SCNu32 ".%" SCNu32, &link_id, &queue_id);\
-	sprintf(link_name, "LINK%" PRIu32, link_id);			\
-	link_param_pos = APP_PARAM_ADD((app)->link_params, link_name);	\
-	link_param_pos;							\
-})
-
-#define APP_PARAM_ADD_LINK_FOR_TM(app, tm_name)				\
-({									\
-	char link_name[APP_PARAM_NAME_SIZE];				\
-	ssize_t link_param_pos;						\
-	uint32_t link_id;						\
-									\
-	sscanf((tm_name), "TM%" SCNu32, &link_id);			\
-	sprintf(link_name, "LINK%" PRIu32, link_id);			\
-	link_param_pos = APP_PARAM_ADD((app)->link_params, link_name);	\
-	link_param_pos;							\
-})
-
-#define APP_PARAM_ADD_LINK_FOR_KNI(app, kni_name)			\
-({									\
-	char link_name[APP_PARAM_NAME_SIZE];				\
-	ssize_t link_param_pos;						\
-	uint32_t link_id;						\
-									\
-	sscanf((kni_name), "KNI%" SCNu32, &link_id);		\
-	sprintf(link_name, "LINK%" PRIu32, link_id);			\
-	link_param_pos = APP_PARAM_ADD((app)->link_params, link_name);	\
-	link_param_pos;							\
-})
-
-#define PARSE_CHECK_DUPLICATE_SECTION(obj)				\
-do {									\
-	APP_CHECK(((obj)->parsed == 0),					\
-		"Parse error: duplicate \"%s\" section", (obj)->name);	\
-	(obj)->parsed++;					\
-} while (0)
-
-#define PARSE_CHECK_DUPLICATE_SECTION_EAL(obj)				\
-do {									\
-	APP_CHECK(((obj)->parsed == 0),					\
-		"Parse error: duplicate \"%s\" section", "EAL");	\
-	(obj)->parsed++;					\
-} while (0)
-
-#define PARSE_ERROR(exp, section, entry)				\
-APP_CHECK(exp, "Parse error in section \"%s\": entry \"%s\"", section, entry)
-
-#define PARSE_ERROR_MESSAGE(exp, section, entry, message)		\
-APP_CHECK(exp, "Parse error in section \"%s\", entry \"%s\": %s",	\
-	section, entry, message)
-
-#define PARSE_ERROR_NO_ELEMENTS(exp, section, entry)			\
-APP_CHECK(exp, "Parse error in section \"%s\", entry \"%s\": "		\
-	"no elements detected",						\
-	section, entry)
-
-#define PARSE_ERROR_TOO_MANY_ELEMENTS(exp, section, entry, max)		\
-APP_CHECK(exp, "Parse error in section \"%s\", entry \"%s\": "		\
-	"maximum number of elements allowed is %u",			\
-	section, entry, max)
-
-#define PARSE_ERROR_INVALID_ELEMENT(exp, section, entry, value)		\
-APP_CHECK(exp, "Parse error in section \"%s\", entry \"%s\": "		\
-	"Invalid element value \"%s\"",					\
-	section, entry, value)
-
-#define PARSE_ERROR_MALLOC(exp)						\
-APP_CHECK(exp, "Parse error: no free memory")
-
-#define PARSE_ERROR_SECTION(exp, section)				\
-APP_CHECK(exp, "Parse error in section \"%s\"", section)
-
-#define PARSE_ERROR_SECTION_NO_ENTRIES(exp, section)			\
-APP_CHECK(exp, "Parse error in section \"%s\": no entries", section)
-
-#define PARSE_WARNING_IGNORED(exp, section, entry)			\
-do									\
-if (!(exp))								\
-	fprintf(stderr, "Parse warning in section \"%s\": "		\
-		"entry \"%s\" is ignored", section, entry);		\
-while (0)
-
-#define PARSE_ERROR_INVALID(exp, section, entry)			\
-APP_CHECK(exp, "Parse error in section \"%s\": unrecognized entry \"%s\"",\
-	section, entry)
-
-#define PARSE_ERROR_DUPLICATE(exp, section, entry)			\
-APP_CHECK(exp, "Parse error in section \"%s\": duplicate entry \"%s\"",	\
-	section, entry)
-
-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 void
-parse_eal(struct app_params *app,
-	const char *section_name,
-	struct rte_cfgfile *cfg)
-{
-	struct app_eal_params *p = &app->eal_params;
-	struct rte_cfgfile_entry *entries;
-	int n_entries, i;
-
-	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
-	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
-
-	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
-	PARSE_ERROR_MALLOC(entries != NULL);
-
-	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
-
-	PARSE_CHECK_DUPLICATE_SECTION_EAL(p);
-
-	for (i = 0; i < n_entries; i++) {
-		struct rte_cfgfile_entry *entry = &entries[i];
-
-		/* coremask */
-		if (strcmp(entry->name, "c") == 0) {
-			PARSE_WARNING_IGNORED(0, section_name, entry->name);
-			continue;
-		}
-
-		/* corelist */
-		if (strcmp(entry->name, "l") == 0) {
-			PARSE_WARNING_IGNORED(0, section_name, entry->name);
-			continue;
-		}
-
-		/* coremap */
-		if (strcmp(entry->name, "lcores") == 0) {
-			PARSE_ERROR_DUPLICATE((p->coremap == NULL),
-				section_name,
-				entry->name);
-			p->coremap = strdup(entry->value);
-			continue;
-		}
-
-		/* master_lcore */
-		if (strcmp(entry->name, "master_lcore") == 0) {
-			int status;
-
-			PARSE_ERROR_DUPLICATE((p->master_lcore_present == 0),
-				section_name,
-				entry->name);
-			p->master_lcore_present = 1;
-
-			status = parser_read_uint32(&p->master_lcore,
-				entry->value);
-			PARSE_ERROR((status == 0), section_name, entry->name);
-			continue;
-		}
-
-		/* channels */
-		if (strcmp(entry->name, "n") == 0) {
-			int status;
-
-			PARSE_ERROR_DUPLICATE((p->channels_present == 0),
-				section_name,
-				entry->name);
-			p->channels_present = 1;
-
-			status = parser_read_uint32(&p->channels, entry->value);
-			PARSE_ERROR((status == 0), section_name, entry->name);
-			continue;
-		}
-
-		/* memory */
-		if (strcmp(entry->name, "m") == 0) {
-			int status;
-
-			PARSE_ERROR_DUPLICATE((p->memory_present == 0),
-				section_name,
-				entry->name);
-			p->memory_present = 1;
-
-			status = parser_read_uint32(&p->memory, entry->value);
-			PARSE_ERROR((status == 0), section_name, entry->name);
-			continue;
-		}
-
-		/* ranks */
-		if (strcmp(entry->name, "r") == 0) {
-			int status;
-
-			PARSE_ERROR_DUPLICATE((p->ranks_present == 0),
-				section_name,
-				entry->name);
-			p->ranks_present = 1;
-
-			status = parser_read_uint32(&p->ranks, entry->value);
-			PARSE_ERROR((status == 0), section_name, entry->name);
-			continue;
-		}
-
-		/* pci_blacklist */
-		if ((strcmp(entry->name, "pci_blacklist") == 0) ||
-			(strcmp(entry->name, "b") == 0)) {
-			uint32_t i;
-
-			for (i = 0; i < APP_MAX_LINKS; i++) {
-				if (p->pci_blacklist[i])
-					continue;
-
-				p->pci_blacklist[i] =
-					strdup(entry->value);
-				PARSE_ERROR_MALLOC(p->pci_blacklist[i]);
-
-				break;
-			}
-
-			PARSE_ERROR_MESSAGE((i < APP_MAX_LINKS),
-				section_name, entry->name,
-				"too many elements");
-			continue;
-		}
-
-		/* pci_whitelist */
-		if ((strcmp(entry->name, "pci_whitelist") == 0) ||
-			(strcmp(entry->name, "w") == 0)) {
-			uint32_t i;
-
-			PARSE_ERROR_MESSAGE((app->port_mask != 0),
-				section_name, entry->name, "entry to be "
-				"generated by the application (port_mask "
-				"not provided)");
-
-			for (i = 0; i < APP_MAX_LINKS; i++) {
-				if (p->pci_whitelist[i])
-					continue;
-
-				p->pci_whitelist[i] = strdup(entry->value);
-				PARSE_ERROR_MALLOC(p->pci_whitelist[i]);
-
-				break;
-			}
-
-			PARSE_ERROR_MESSAGE((i < APP_MAX_LINKS),
-				section_name, entry->name,
-				"too many elements");
-			continue;
-		}
-
-		/* vdev */
-		if (strcmp(entry->name, "vdev") == 0) {
-			uint32_t i;
-
-			for (i = 0; i < APP_MAX_LINKS; i++) {
-				if (p->vdev[i])
-					continue;
-
-				p->vdev[i] = strdup(entry->value);
-				PARSE_ERROR_MALLOC(p->vdev[i]);
-
-				break;
-			}
-
-			PARSE_ERROR_MESSAGE((i < APP_MAX_LINKS),
-				section_name, entry->name,
-				"too many elements");
-			continue;
-		}
-
-		/* vmware_tsc_map */
-		if (strcmp(entry->name, "vmware_tsc_map") == 0) {
-			int val;
-
-			PARSE_ERROR_DUPLICATE((p->vmware_tsc_map_present == 0),
-				section_name,
-				entry->name);
-			p->vmware_tsc_map_present = 1;
-
-			val = parser_read_arg_bool(entry->value);
-			PARSE_ERROR((val >= 0), section_name, entry->name);
-			p->vmware_tsc_map = val;
-			continue;
-		}
-
-		/* proc_type */
-		if (strcmp(entry->name, "proc_type") == 0) {
-			PARSE_ERROR_DUPLICATE((p->proc_type == NULL),
-				section_name,
-				entry->name);
-			p->proc_type = strdup(entry->value);
-			continue;
-		}
-
-		/* syslog */
-		if (strcmp(entry->name, "syslog") == 0) {
-			PARSE_ERROR_DUPLICATE((p->syslog == NULL),
-				section_name,
-				entry->name);
-			p->syslog = strdup(entry->value);
-			continue;
-		}
-
-		/* log_level */
-		if (strcmp(entry->name, "log_level") == 0) {
-			int status;
-
-			PARSE_ERROR_DUPLICATE((p->log_level_present == 0),
-				section_name,
-				entry->name);
-			p->log_level_present = 1;
-
-			status = parser_read_uint32(&p->log_level,
-				entry->value);
-			PARSE_ERROR((status == 0), section_name, entry->name);
-			continue;
-		}
-
-		/* version */
-		if (strcmp(entry->name, "v") == 0) {
-			int val;
-
-			PARSE_ERROR_DUPLICATE((p->version_present == 0),
-				section_name,
-				entry->name);
-			p->version_present = 1;
-
-			val = parser_read_arg_bool(entry->value);
-			PARSE_ERROR((val >= 0), section_name, entry->name);
-			p->version = val;
-			continue;
-		}
-
-		/* help */
-		if ((strcmp(entry->name, "help") == 0) ||
-			(strcmp(entry->name, "h") == 0)) {
-			int val;
-
-			PARSE_ERROR_DUPLICATE((p->help_present == 0),
-				section_name,
-				entry->name);
-			p->help_present = 1;
-
-			val = parser_read_arg_bool(entry->value);
-			PARSE_ERROR((val >= 0), section_name, entry->name);
-			p->help = val;
-			continue;
-		}
-
-		/* no_huge */
-		if (strcmp(entry->name, "no_huge") == 0) {
-			int val;
-
-			PARSE_ERROR_DUPLICATE((p->no_huge_present == 0),
-				section_name,
-				entry->name);
-			p->no_huge_present = 1;
-
-			val = parser_read_arg_bool(entry->value);
-			PARSE_ERROR((val >= 0), section_name, entry->name);
-			p->no_huge = val;
-			continue;
-		}
-
-		/* no_pci */
-		if (strcmp(entry->name, "no_pci") == 0) {
-			int val;
-
-			PARSE_ERROR_DUPLICATE((p->no_pci_present == 0),
-				section_name,
-				entry->name);
-			p->no_pci_present = 1;
-
-			val = parser_read_arg_bool(entry->value);
-			PARSE_ERROR((val >= 0), section_name, entry->name);
-			p->no_pci = val;
-			continue;
-		}
-
-		/* no_hpet */
-		if (strcmp(entry->name, "no_hpet") == 0) {
-			int val;
-
-			PARSE_ERROR_DUPLICATE((p->no_hpet_present == 0),
-				section_name,
-				entry->name);
-			p->no_hpet_present = 1;
-
-			val = parser_read_arg_bool(entry->value);
-			PARSE_ERROR((val >= 0), section_name, entry->name);
-			p->no_hpet = val;
-			continue;
-		}
-
-		/* no_shconf */
-		if (strcmp(entry->name, "no_shconf") == 0) {
-			int val;
-
-			PARSE_ERROR_DUPLICATE((p->no_shconf_present == 0),
-				section_name,
-				entry->name);
-			p->no_shconf_present = 1;
-
-			val = parser_read_arg_bool(entry->value);
-			PARSE_ERROR((val >= 0), section_name, entry->name);
-			p->no_shconf = val;
-			continue;
-		}
-
-		/* add_driver */
-		if (strcmp(entry->name, "d") == 0) {
-			PARSE_ERROR_DUPLICATE((p->add_driver == NULL),
-				section_name,
-				entry->name);
-			p->add_driver = strdup(entry->value);
-			continue;
-		}
-
-		/* socket_mem */
-		if (strcmp(entry->name, "socket_mem") == 0) {
-			PARSE_ERROR_DUPLICATE((p->socket_mem == NULL),
-				section_name,
-				entry->name);
-			p->socket_mem = strdup(entry->value);
-			continue;
-		}
-
-		/* huge_dir */
-		if (strcmp(entry->name, "huge_dir") == 0) {
-			PARSE_ERROR_DUPLICATE((p->huge_dir == NULL),
-				section_name,
-				entry->name);
-			p->huge_dir = strdup(entry->value);
-			continue;
-		}
-
-		/* file_prefix */
-		if (strcmp(entry->name, "file_prefix") == 0) {
-			PARSE_ERROR_DUPLICATE((p->file_prefix == NULL),
-				section_name,
-				entry->name);
-			p->file_prefix = strdup(entry->value);
-			continue;
-		}
-
-		/* base_virtaddr */
-		if (strcmp(entry->name, "base_virtaddr") == 0) {
-			PARSE_ERROR_DUPLICATE((p->base_virtaddr == NULL),
-				section_name,
-				entry->name);
-			p->base_virtaddr = strdup(entry->value);
-			continue;
-		}
-
-		/* create_uio_dev */
-		if (strcmp(entry->name, "create_uio_dev") == 0) {
-			int val;
-
-			PARSE_ERROR_DUPLICATE((p->create_uio_dev_present == 0),
-				section_name,
-				entry->name);
-			p->create_uio_dev_present = 1;
-
-			val = parser_read_arg_bool(entry->value);
-			PARSE_ERROR((val >= 0), section_name, entry->name);
-			p->create_uio_dev = val;
-			continue;
-		}
-
-		/* vfio_intr */
-		if (strcmp(entry->name, "vfio_intr") == 0) {
-			PARSE_ERROR_DUPLICATE((p->vfio_intr == NULL),
-				section_name,
-				entry->name);
-			p->vfio_intr = strdup(entry->value);
-			continue;
-		}
-
-		/* unrecognized */
-		PARSE_ERROR_INVALID(0, section_name, entry->name);
-	}
-
-	free(entries);
-}
-
-static void
-parse_pipeline_pktq_in(struct app_params *app,
-	struct app_pipeline_params *p,
-	char *value)
-{
-	p->n_pktq_in = 0;
-
-	while (1) {
-		enum app_pktq_in_type type;
-		int id;
-		char *name = strtok_r(value, PARSE_DELIMITER, &value);
-
-		if (name == NULL)
-			break;
-
-		PARSE_ERROR_TOO_MANY_ELEMENTS(
-			(p->n_pktq_in < RTE_DIM(p->pktq_in)),
-			p->name, "pktq_in", (uint32_t)RTE_DIM(p->pktq_in));
-
-		if (validate_name(name, "RXQ", 2) == 0) {
-			type = APP_PKTQ_IN_HWQ;
-			id = APP_PARAM_ADD(app->hwq_in_params, name);
-			APP_PARAM_ADD_LINK_FOR_RXQ(app, 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);
-			APP_PARAM_ADD_LINK_FOR_TM(app, name);
-		} else if (validate_name(name, "TAP", 1) == 0) {
-			type = APP_PKTQ_IN_TAP;
-			id = APP_PARAM_ADD(app->tap_params, name);
-		} else if (validate_name(name, "KNI", 1) == 0) {
-			type = APP_PKTQ_IN_KNI;
-			id = APP_PARAM_ADD(app->kni_params, name);
-			APP_PARAM_ADD_LINK_FOR_KNI(app, name);
-		} else if (validate_name(name, "SOURCE", 1) == 0) {
-			type = APP_PKTQ_IN_SOURCE;
-			id = APP_PARAM_ADD(app->source_params, name);
-		} else
-			PARSE_ERROR_INVALID_ELEMENT(0,
-				p->name, "pktq_in", name);
-
-		p->pktq_in[p->n_pktq_in].type = type;
-		p->pktq_in[p->n_pktq_in].id = (uint32_t) id;
-		p->n_pktq_in++;
-	}
-
-	PARSE_ERROR_NO_ELEMENTS((p->n_pktq_in > 0), p->name, "pktq_in");
-}
-
-static void
-parse_pipeline_pktq_out(struct app_params *app,
-	struct app_pipeline_params *p,
-	char *value)
-{
-	p->n_pktq_out = 0;
-
-	while (1) {
-		enum app_pktq_out_type type;
-		int id;
-		char *name = strtok_r(value, PARSE_DELIMITER, &value);
-
-		if (name == NULL)
-			break;
-
-		PARSE_ERROR_TOO_MANY_ELEMENTS(
-			(p->n_pktq_out < RTE_DIM(p->pktq_out)),
-			p->name, "pktq_out", (uint32_t)RTE_DIM(p->pktq_out));
-
-		if (validate_name(name, "TXQ", 2) == 0) {
-			type = APP_PKTQ_OUT_HWQ;
-			id = APP_PARAM_ADD(app->hwq_out_params, name);
-			APP_PARAM_ADD_LINK_FOR_TXQ(app, 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);
-			APP_PARAM_ADD_LINK_FOR_TM(app, name);
-		} else if (validate_name(name, "TAP", 1) == 0) {
-			type = APP_PKTQ_OUT_TAP;
-			id = APP_PARAM_ADD(app->tap_params, name);
-		} else if (validate_name(name, "KNI", 1) == 0) {
-			type = APP_PKTQ_OUT_KNI;
-			id = APP_PARAM_ADD(app->kni_params, name);
-			APP_PARAM_ADD_LINK_FOR_KNI(app, name);
-		} else if (validate_name(name, "SINK", 1) == 0) {
-			type = APP_PKTQ_OUT_SINK;
-			id = APP_PARAM_ADD(app->sink_params, name);
-		} else
-			PARSE_ERROR_INVALID_ELEMENT(0,
-				p->name, "pktq_out", name);
-
-		p->pktq_out[p->n_pktq_out].type = type;
-		p->pktq_out[p->n_pktq_out].id = id;
-		p->n_pktq_out++;
-	}
-
-	PARSE_ERROR_NO_ELEMENTS((p->n_pktq_out > 0), p->name, "pktq_out");
-}
-
-static void
-parse_pipeline_msgq_in(struct app_params *app,
-	struct app_pipeline_params *p,
-	char *value)
-{
-	p->n_msgq_in = 0;
-
-	while (1) {
-		int idx;
-		char *name = strtok_r(value, PARSE_DELIMITER, &value);
-
-		if (name == NULL)
-			break;
-
-		PARSE_ERROR_TOO_MANY_ELEMENTS(
-			(p->n_msgq_in < RTE_DIM(p->msgq_in)),
-			p->name, "msgq_in", (uint32_t)(RTE_DIM(p->msgq_in)));
-
-		PARSE_ERROR_INVALID_ELEMENT(
-			(validate_name(name, "MSGQ", 1) == 0),
-			p->name, "msgq_in", name);
-
-		idx = APP_PARAM_ADD(app->msgq_params, name);
-		p->msgq_in[p->n_msgq_in] = idx;
-		p->n_msgq_in++;
-	}
-
-	PARSE_ERROR_NO_ELEMENTS((p->n_msgq_in > 0), p->name, "msgq_in");
-}
-
-static void
-parse_pipeline_msgq_out(struct app_params *app,
-	struct app_pipeline_params *p,
-	char *value)
-{
-	p->n_msgq_out = 0;
-
-	while (1) {
-		int idx;
-		char *name = strtok_r(value, PARSE_DELIMITER, &value);
-
-		if (name == NULL)
-			break;
-
-		PARSE_ERROR_TOO_MANY_ELEMENTS(
-			(p->n_msgq_out < RTE_DIM(p->msgq_out)),
-			p->name, "msgq_out", (uint32_t)RTE_DIM(p->msgq_out));
-
-		PARSE_ERROR_INVALID_ELEMENT(
-			(validate_name(name, "MSGQ", 1) == 0),
-			p->name, "msgq_out", name);
-
-		idx = APP_PARAM_ADD(app->msgq_params, name);
-		p->msgq_out[p->n_msgq_out] = idx;
-		p->n_msgq_out++;
-	}
-
-	PARSE_ERROR_NO_ELEMENTS((p->n_msgq_out > 0), p->name, "msgq_out");
-}
-
-static void
-parse_pipeline(struct app_params *app,
-	const char *section_name,
-	struct rte_cfgfile *cfg)
-{
-	char name[CFG_NAME_LEN];
-	struct app_pipeline_params *param;
-	struct rte_cfgfile_entry *entries;
-	ssize_t param_idx;
-	int n_entries, i;
-
-	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
-	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
-
-	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
-	PARSE_ERROR_MALLOC(entries != NULL);
-
-	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
-
-	param_idx = APP_PARAM_ADD(app->pipeline_params, section_name);
-	param = &app->pipeline_params[param_idx];
-	PARSE_CHECK_DUPLICATE_SECTION(param);
-
-	for (i = 0; i < n_entries; i++) {
-		struct rte_cfgfile_entry *ent = &entries[i];
-
-		if (strcmp(ent->name, "type") == 0) {
-			int w_size = snprintf(param->type, RTE_DIM(param->type),
-					"%s", ent->value);
-
-			PARSE_ERROR(((w_size > 0) &&
-				(w_size < (int)RTE_DIM(param->type))),
-				section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "core") == 0) {
-			int status = parse_pipeline_core(
-				&param->socket_id, &param->core_id,
-				&param->hyper_th_id, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "pktq_in") == 0) {
-			parse_pipeline_pktq_in(app, param, ent->value);
-
-			continue;
-		}
-
-		if (strcmp(ent->name, "pktq_out") == 0) {
-			parse_pipeline_pktq_out(app, param, ent->value);
-
-			continue;
-		}
-
-		if (strcmp(ent->name, "msgq_in") == 0) {
-			parse_pipeline_msgq_in(app, param, ent->value);
-
-			continue;
-		}
-
-		if (strcmp(ent->name, "msgq_out") == 0) {
-			parse_pipeline_msgq_out(app, param, ent->value);
-
-			continue;
-		}
-
-		if (strcmp(ent->name, "timer_period") == 0) {
-			int status = parser_read_uint32(
-				&param->timer_period,
-				ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		/* pipeline type specific items */
-		APP_CHECK((param->n_args < APP_MAX_PIPELINE_ARGS),
-			"Parse error in section \"%s\": too many "
-			"pipeline specified parameters", section_name);
-
-		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),
-			"Parse error: no free memory");
-
-		param->n_args++;
-	}
-
-	snprintf(name, sizeof(name), "MSGQ-REQ-%s", section_name);
-	param_idx = APP_PARAM_ADD(app->msgq_params, 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", section_name);
-	param_idx = APP_PARAM_ADD(app->msgq_params, 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);
-	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);
-	app->msgq_params[param_idx].cpu_socket_id = param->socket_id;
-
-	free(entries);
-}
-
-static void
-parse_mempool(struct app_params *app,
-	const char *section_name,
-	struct rte_cfgfile *cfg)
-{
-	struct app_mempool_params *param;
-	struct rte_cfgfile_entry *entries;
-	ssize_t param_idx;
-	int n_entries, i;
-
-	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
-	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
-
-	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
-	PARSE_ERROR_MALLOC(entries != NULL);
-
-	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
-
-	param_idx = APP_PARAM_ADD(app->mempool_params, section_name);
-	param = &app->mempool_params[param_idx];
-	PARSE_CHECK_DUPLICATE_SECTION(param);
-
-	for (i = 0; i < n_entries; i++) {
-		struct rte_cfgfile_entry *ent = &entries[i];
-
-		if (strcmp(ent->name, "buffer_size") == 0) {
-			int status = parser_read_uint32(
-				&param->buffer_size, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "pool_size") == 0) {
-			int status = parser_read_uint32(
-				&param->pool_size, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "cache_size") == 0) {
-			int status = parser_read_uint32(
-				&param->cache_size, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "cpu") == 0) {
-			int status = parser_read_uint32(
-				&param->cpu_socket_id, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		/* unrecognized */
-		PARSE_ERROR_INVALID(0, section_name, ent->name);
-	}
-
-	free(entries);
-}
-
-static int
-parse_link_rss_qs(struct app_link_params *p,
-	char *value)
-{
-	p->n_rss_qs = 0;
-
-	while (1) {
-		char *token = strtok_r(value, PARSE_DELIMITER, &value);
-
-		if (token == NULL)
-			break;
-
-		if (p->n_rss_qs == RTE_DIM(p->rss_qs))
-			return -ENOMEM;
-
-		if (parser_read_uint32(&p->rss_qs[p->n_rss_qs++], token))
-			return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int
-parse_link_rss_proto_ipv4(struct app_link_params *p,
-	char *value)
-{
-	uint64_t mask = 0;
-
-	while (1) {
-		char *token = strtok_r(value, PARSE_DELIMITER, &value);
-
-		if (token == NULL)
-			break;
-
-		if (strcmp(token, "IP") == 0) {
-			mask |= ETH_RSS_IPV4;
-			continue;
-		}
-		if (strcmp(token, "FRAG") == 0) {
-			mask |= ETH_RSS_FRAG_IPV4;
-			continue;
-		}
-		if (strcmp(token, "TCP") == 0) {
-			mask |= ETH_RSS_NONFRAG_IPV4_TCP;
-			continue;
-		}
-		if (strcmp(token, "UDP") == 0) {
-			mask |= ETH_RSS_NONFRAG_IPV4_UDP;
-			continue;
-		}
-		if (strcmp(token, "SCTP") == 0) {
-			mask |= ETH_RSS_NONFRAG_IPV4_SCTP;
-			continue;
-		}
-		if (strcmp(token, "OTHER") == 0) {
-			mask |= ETH_RSS_NONFRAG_IPV4_OTHER;
-			continue;
-		}
-		return -EINVAL;
-	}
-
-	p->rss_proto_ipv4 = mask;
-	return 0;
-}
-
-static int
-parse_link_rss_proto_ipv6(struct app_link_params *p,
-	char *value)
-{
-	uint64_t mask = 0;
-
-	while (1) {
-		char *token = strtok_r(value, PARSE_DELIMITER, &value);
-
-		if (token == NULL)
-			break;
-
-		if (strcmp(token, "IP") == 0) {
-			mask |= ETH_RSS_IPV6;
-			continue;
-		}
-		if (strcmp(token, "FRAG") == 0) {
-			mask |= ETH_RSS_FRAG_IPV6;
-			continue;
-		}
-		if (strcmp(token, "TCP") == 0) {
-			mask |= ETH_RSS_NONFRAG_IPV6_TCP;
-			continue;
-		}
-		if (strcmp(token, "UDP") == 0) {
-			mask |= ETH_RSS_NONFRAG_IPV6_UDP;
-			continue;
-		}
-		if (strcmp(token, "SCTP") == 0) {
-			mask |= ETH_RSS_NONFRAG_IPV6_SCTP;
-			continue;
-		}
-		if (strcmp(token, "OTHER") == 0) {
-			mask |= ETH_RSS_NONFRAG_IPV6_OTHER;
-			continue;
-		}
-		if (strcmp(token, "IP_EX") == 0) {
-			mask |= ETH_RSS_IPV6_EX;
-			continue;
-		}
-		if (strcmp(token, "TCP_EX") == 0) {
-			mask |= ETH_RSS_IPV6_TCP_EX;
-			continue;
-		}
-		if (strcmp(token, "UDP_EX") == 0) {
-			mask |= ETH_RSS_IPV6_UDP_EX;
-			continue;
-		}
-		return -EINVAL;
-	}
-
-	p->rss_proto_ipv6 = mask;
-	return 0;
-}
-
-static int
-parse_link_rss_proto_l2(struct app_link_params *p,
-	char *value)
-{
-	uint64_t mask = 0;
-
-	while (1) {
-		char *token = strtok_r(value, PARSE_DELIMITER, &value);
-
-		if (token == NULL)
-			break;
-
-		if (strcmp(token, "L2") == 0) {
-			mask |= ETH_RSS_L2_PAYLOAD;
-			continue;
-		}
-		return -EINVAL;
-	}
-
-	p->rss_proto_l2 = mask;
-	return 0;
-}
-
-static void
-parse_link(struct app_params *app,
-	const char *section_name,
-	struct rte_cfgfile *cfg)
-{
-	struct app_link_params *param;
-	struct rte_cfgfile_entry *entries;
-	int n_entries, i;
-	int rss_qs_present = 0;
-	int rss_proto_ipv4_present = 0;
-	int rss_proto_ipv6_present = 0;
-	int rss_proto_l2_present = 0;
-	int pci_bdf_present = 0;
-	ssize_t param_idx;
-
-	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
-	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
-
-	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
-	PARSE_ERROR_MALLOC(entries != NULL);
-
-	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
-
-	param_idx = APP_PARAM_ADD(app->link_params, section_name);
-	param = &app->link_params[param_idx];
-	PARSE_CHECK_DUPLICATE_SECTION(param);
-
-	for (i = 0; i < n_entries; i++) {
-		struct rte_cfgfile_entry *ent = &entries[i];
-
-		if (strcmp(ent->name, "promisc") == 0) {
-			int status = parser_read_arg_bool(ent->value);
-
-			PARSE_ERROR((status != -EINVAL), section_name,
-				ent->name);
-			param->promisc = status;
-			continue;
-		}
-
-		if (strcmp(ent->name, "arp_q") == 0) {
-			int status = parser_read_uint32(&param->arp_q,
-				ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "tcp_syn_q") == 0) {
-			int status = parser_read_uint32(
-				&param->tcp_syn_q, ent->value);
-
-			PARSE_ERROR((status == 0), section_name, ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "ip_local_q") == 0) {
-			int status = parser_read_uint32(
-				&param->ip_local_q, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "tcp_local_q") == 0) {
-			int status = parser_read_uint32(
-				&param->tcp_local_q, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "udp_local_q") == 0) {
-			int status = parser_read_uint32(
-				&param->udp_local_q, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "sctp_local_q") == 0) {
-			int status = parser_read_uint32(
-				&param->sctp_local_q, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "rss_qs") == 0) {
-			int status = parse_link_rss_qs(param, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			rss_qs_present = 1;
-			continue;
-		}
-
-		if (strcmp(ent->name, "rss_proto_ipv4") == 0) {
-			int status =
-				parse_link_rss_proto_ipv4(param, ent->value);
-
-			PARSE_ERROR((status != -EINVAL), section_name,
-				ent->name);
-			rss_proto_ipv4_present = 1;
-			continue;
-		}
-
-		if (strcmp(ent->name, "rss_proto_ipv6") == 0) {
-			int status =
-				parse_link_rss_proto_ipv6(param, ent->value);
-
-			PARSE_ERROR((status != -EINVAL), section_name,
-				ent->name);
-			rss_proto_ipv6_present = 1;
-			continue;
-		}
-
-		if (strcmp(ent->name, "rss_proto_l2") == 0) {
-			int status = parse_link_rss_proto_l2(param, ent->value);
-
-			PARSE_ERROR((status != -EINVAL), section_name,
-				ent->name);
-			rss_proto_l2_present = 1;
-			continue;
-		}
-
-		if (strcmp(ent->name, "pci_bdf") == 0) {
-			PARSE_ERROR_DUPLICATE((pci_bdf_present == 0),
-				section_name, ent->name);
-
-			snprintf(param->pci_bdf, APP_LINK_PCI_BDF_SIZE,
-				"%s", ent->value);
-			pci_bdf_present = 1;
-			continue;
-		}
-
-		/* unrecognized */
-		PARSE_ERROR_INVALID(0, section_name, ent->name);
-	}
-
-	/* Check for mandatory fields */
-	if (app->port_mask)
-		PARSE_ERROR_MESSAGE((pci_bdf_present == 0),
-			section_name, "pci_bdf",
-			"entry not allowed (port_mask is provided)");
-	else
-		PARSE_ERROR_MESSAGE((pci_bdf_present),
-			section_name, "pci_bdf",
-			"this entry is mandatory (port_mask is not "
-			"provided)");
-
-	if (rss_proto_ipv4_present)
-		PARSE_ERROR_MESSAGE((rss_qs_present),
-			section_name, "rss_proto_ipv4",
-			"entry not allowed (rss_qs entry is not provided)");
-	if (rss_proto_ipv6_present)
-		PARSE_ERROR_MESSAGE((rss_qs_present),
-			section_name, "rss_proto_ipv6",
-			"entry not allowed (rss_qs entry is not provided)");
-	if (rss_proto_l2_present)
-		PARSE_ERROR_MESSAGE((rss_qs_present),
-			section_name, "rss_proto_l2",
-			"entry not allowed (rss_qs entry is not provided)");
-	if (rss_proto_ipv4_present |
-		rss_proto_ipv6_present |
-		rss_proto_l2_present){
-		if (rss_proto_ipv4_present == 0)
-			param->rss_proto_ipv4 = 0;
-		if (rss_proto_ipv6_present == 0)
-			param->rss_proto_ipv6 = 0;
-		if (rss_proto_l2_present == 0)
-			param->rss_proto_l2 = 0;
-	}
-
-	free(entries);
-}
-
-static void
-parse_rxq(struct app_params *app,
-	const char *section_name,
-	struct rte_cfgfile *cfg)
-{
-	struct app_pktq_hwq_in_params *param;
-	struct rte_cfgfile_entry *entries;
-	int n_entries, i;
-	ssize_t param_idx;
-
-	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
-	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
-
-	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
-	PARSE_ERROR_MALLOC(entries != NULL);
-
-	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
-
-	param_idx = APP_PARAM_ADD(app->hwq_in_params, section_name);
-	param = &app->hwq_in_params[param_idx];
-	PARSE_CHECK_DUPLICATE_SECTION(param);
-
-	APP_PARAM_ADD_LINK_FOR_RXQ(app, section_name);
-
-	for (i = 0; i < n_entries; i++) {
-		struct rte_cfgfile_entry *ent = &entries[i];
-
-		if (strcmp(ent->name, "mempool") == 0) {
-			int status = validate_name(ent->value,
-				"MEMPOOL", 1);
-			ssize_t idx;
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-
-			idx = APP_PARAM_ADD(app->mempool_params, ent->value);
-			param->mempool_id = idx;
-			continue;
-		}
-
-		if (strcmp(ent->name, "size") == 0) {
-			int status = parser_read_uint32(&param->size,
-				ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "burst") == 0) {
-			int status = parser_read_uint32(&param->burst,
-				ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		/* unrecognized */
-		PARSE_ERROR_INVALID(0, section_name, ent->name);
-	}
-
-	free(entries);
-}
-
-static void
-parse_txq(struct app_params *app,
-	const char *section_name,
-	struct rte_cfgfile *cfg)
-{
-	struct app_pktq_hwq_out_params *param;
-	struct rte_cfgfile_entry *entries;
-	int n_entries, i;
-	ssize_t param_idx;
-
-	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
-	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
-
-	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
-	PARSE_ERROR_MALLOC(entries != NULL);
-
-	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
-
-	param_idx = APP_PARAM_ADD(app->hwq_out_params, section_name);
-	param = &app->hwq_out_params[param_idx];
-	PARSE_CHECK_DUPLICATE_SECTION(param);
-
-	APP_PARAM_ADD_LINK_FOR_TXQ(app, section_name);
-
-	for (i = 0; i < n_entries; i++) {
-		struct rte_cfgfile_entry *ent = &entries[i];
-
-		if (strcmp(ent->name, "size") == 0) {
-			int status = parser_read_uint32(&param->size,
-				ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "burst") == 0) {
-			int status = parser_read_uint32(&param->burst,
-				ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "dropless") == 0) {
-			int status = parser_read_arg_bool(ent->value);
-
-
-			PARSE_ERROR((status != -EINVAL), section_name,
-				ent->name);
-			param->dropless = status;
-			continue;
-		}
-
-		if (strcmp(ent->name, "n_retries") == 0) {
-			int status = parser_read_uint64(&param->n_retries,
-				ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		/* unrecognized */
-		PARSE_ERROR_INVALID(0, section_name, ent->name);
-	}
-
-	free(entries);
-}
-
-static void
-parse_swq(struct app_params *app,
-	const char *section_name,
-	struct rte_cfgfile *cfg)
-{
-	struct app_pktq_swq_params *param;
-	struct rte_cfgfile_entry *entries;
-	int n_entries, i;
-	uint32_t mtu_present = 0;
-	uint32_t metadata_size_present = 0;
-	uint32_t mempool_direct_present = 0;
-	uint32_t mempool_indirect_present = 0;
-
-	ssize_t param_idx;
-
-	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
-	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
-
-	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
-	PARSE_ERROR_MALLOC(entries != NULL);
-
-	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
-
-	param_idx = APP_PARAM_ADD(app->swq_params, section_name);
-	param = &app->swq_params[param_idx];
-	PARSE_CHECK_DUPLICATE_SECTION(param);
-
-	for (i = 0; i < n_entries; i++) {
-		struct rte_cfgfile_entry *ent = &entries[i];
-
-		if (strcmp(ent->name, "size") == 0) {
-			int status = parser_read_uint32(&param->size,
-				ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "burst_read") == 0) {
-			int status = parser_read_uint32(&
-				param->burst_read, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "burst_write") == 0) {
-			int status = parser_read_uint32(
-				&param->burst_write, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "dropless") == 0) {
-			int status = parser_read_arg_bool(ent->value);
-
-			PARSE_ERROR((status != -EINVAL), section_name,
-				ent->name);
-			param->dropless = status;
-			continue;
-		}
-
-		if (strcmp(ent->name, "n_retries") == 0) {
-			int status = parser_read_uint64(&param->n_retries,
-				ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "cpu") == 0) {
-			int status = parser_read_uint32(
-				&param->cpu_socket_id, ent->value);
-
-			PARSE_ERROR((status == 0), section_name, ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "ipv4_frag") == 0) {
-			int status = parser_read_arg_bool(ent->value);
-
-			PARSE_ERROR((status != -EINVAL), section_name,
-				ent->name);
-
-			param->ipv4_frag = status;
-			if (param->mtu == 0)
-				param->mtu = 1500;
-
-			continue;
-		}
-
-		if (strcmp(ent->name, "ipv6_frag") == 0) {
-			int status = parser_read_arg_bool(ent->value);
-
-			PARSE_ERROR((status != -EINVAL), section_name,
-				ent->name);
-			param->ipv6_frag = status;
-			if (param->mtu == 0)
-				param->mtu = 1320;
-			continue;
-		}
-
-		if (strcmp(ent->name, "ipv4_ras") == 0) {
-			int status = parser_read_arg_bool(ent->value);
-
-			PARSE_ERROR((status != -EINVAL), section_name,
-				ent->name);
-			param->ipv4_ras = status;
-			continue;
-		}
-
-		if (strcmp(ent->name, "ipv6_ras") == 0) {
-			int status = parser_read_arg_bool(ent->value);
-
-			PARSE_ERROR((status != -EINVAL), section_name,
-				ent->name);
-			param->ipv6_ras = status;
-			continue;
-		}
-
-		if (strcmp(ent->name, "mtu") == 0) {
-			int status = parser_read_uint32(&param->mtu,
-					ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			mtu_present = 1;
-			continue;
-		}
-
-		if (strcmp(ent->name, "metadata_size") == 0) {
-			int status = parser_read_uint32(
-				&param->metadata_size, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			metadata_size_present = 1;
-			continue;
-		}
-
-		if (strcmp(ent->name, "mempool_direct") == 0) {
-			int status = validate_name(ent->value,
-				"MEMPOOL", 1);
-			ssize_t idx;
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-
-			idx = APP_PARAM_ADD(app->mempool_params, ent->value);
-			param->mempool_direct_id = idx;
-
-			mempool_direct_present = 1;
-			continue;
-		}
-
-		if (strcmp(ent->name, "mempool_indirect") == 0) {
-			int status = validate_name(ent->value,
-				"MEMPOOL", 1);
-			ssize_t idx;
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-
-			idx = APP_PARAM_ADD(app->mempool_params, ent->value);
-			param->mempool_indirect_id = idx;
-
-			mempool_indirect_present = 1;
-			continue;
-		}
-
-		/* unrecognized */
-		PARSE_ERROR_INVALID(0, section_name, ent->name);
-	}
-
-	APP_CHECK(((mtu_present == 0) ||
-		((param->ipv4_frag == 1) || (param->ipv6_frag == 1))),
-		"Parse error in section \"%s\": IPv4/IPv6 fragmentation "
-		"is off, therefore entry \"mtu\" is not allowed",
-		section_name);
-
-	APP_CHECK(((metadata_size_present == 0) ||
-		((param->ipv4_frag == 1) || (param->ipv6_frag == 1))),
-		"Parse error in section \"%s\": IPv4/IPv6 fragmentation "
-		"is off, therefore entry \"metadata_size\" is "
-		"not allowed", section_name);
-
-	APP_CHECK(((mempool_direct_present == 0) ||
-		((param->ipv4_frag == 1) || (param->ipv6_frag == 1))),
-		"Parse error in section \"%s\": IPv4/IPv6 fragmentation "
-		"is off, therefore entry \"mempool_direct\" is "
-		"not allowed", section_name);
-
-	APP_CHECK(((mempool_indirect_present == 0) ||
-		((param->ipv4_frag == 1) || (param->ipv6_frag == 1))),
-		"Parse error in section \"%s\": IPv4/IPv6 fragmentation "
-		"is off, therefore entry \"mempool_indirect\" is "
-		"not allowed", section_name);
-
-	free(entries);
-}
-
-static void
-parse_tm(struct app_params *app,
-	const char *section_name,
-	struct rte_cfgfile *cfg)
-{
-	struct app_pktq_tm_params *param;
-	struct rte_cfgfile_entry *entries;
-	int n_entries, i;
-	ssize_t param_idx;
-
-	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
-	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
-
-	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
-	PARSE_ERROR_MALLOC(entries != NULL);
-
-	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
-
-	param_idx = APP_PARAM_ADD(app->tm_params, section_name);
-	param = &app->tm_params[param_idx];
-	PARSE_CHECK_DUPLICATE_SECTION(param);
-
-	APP_PARAM_ADD_LINK_FOR_TM(app, section_name);
-
-	for (i = 0; i < n_entries; i++) {
-		struct rte_cfgfile_entry *ent = &entries[i];
-
-		if (strcmp(ent->name, "cfg") == 0) {
-			param->file_name = strdup(ent->value);
-			PARSE_ERROR_MALLOC(param->file_name != NULL);
-			continue;
-		}
-
-		if (strcmp(ent->name, "burst_read") == 0) {
-			int status = parser_read_uint32(
-				&param->burst_read, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "burst_write") == 0) {
-			int status = parser_read_uint32(
-				&param->burst_write, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		/* unrecognized */
-		PARSE_ERROR_INVALID(0, section_name, ent->name);
-	}
-
-	free(entries);
-}
-
-static void
-parse_tap(struct app_params *app,
-	const char *section_name,
-	struct rte_cfgfile *cfg)
-{
-	struct app_pktq_tap_params *param;
-	struct rte_cfgfile_entry *entries;
-	int n_entries, i;
-	ssize_t param_idx;
-
-	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
-	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
-
-	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
-	PARSE_ERROR_MALLOC(entries != NULL);
-
-	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
-
-	param_idx = APP_PARAM_ADD(app->tap_params, section_name);
-	param = &app->tap_params[param_idx];
-	PARSE_CHECK_DUPLICATE_SECTION(param);
-
-	for (i = 0; i < n_entries; i++) {
-		struct rte_cfgfile_entry *ent = &entries[i];
-
-		if (strcmp(ent->name, "burst_read") == 0) {
-			int status = parser_read_uint32(
-				&param->burst_read, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "burst_write") == 0) {
-			int status = parser_read_uint32(
-				&param->burst_write, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "dropless") == 0) {
-			int status = parser_read_arg_bool(ent->value);
-
-			PARSE_ERROR((status != -EINVAL), section_name,
-				ent->name);
-			param->dropless = status;
-			continue;
-		}
-
-		if (strcmp(ent->name, "n_retries") == 0) {
-			int status = parser_read_uint64(&param->n_retries,
-				ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "mempool") == 0) {
-			int status = validate_name(ent->value,
-				"MEMPOOL", 1);
-			ssize_t idx;
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-
-			idx = APP_PARAM_ADD(app->mempool_params, ent->value);
-			param->mempool_id = idx;
-
-			continue;
-		}
-
-		/* unrecognized */
-		PARSE_ERROR_INVALID(0, section_name, ent->name);
-	}
-
-	free(entries);
-}
-
-static void
-parse_kni(struct app_params *app,
-		  const char *section_name,
-		  struct rte_cfgfile *cfg)
-{
-	struct app_pktq_kni_params *param;
-	struct rte_cfgfile_entry *entries;
-	int n_entries, i;
-	ssize_t param_idx;
-
-	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
-	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
-
-	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
-	PARSE_ERROR_MALLOC(entries != NULL);
-
-	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
-
-	param_idx = APP_PARAM_ADD(app->kni_params, section_name);
-	param = &app->kni_params[param_idx];
-	PARSE_CHECK_DUPLICATE_SECTION(param);
-
-	APP_PARAM_ADD_LINK_FOR_KNI(app, section_name);
-
-	for (i = 0; i < n_entries; i++) {
-		struct rte_cfgfile_entry *ent = &entries[i];
-
-		if (strcmp(ent->name, "core") == 0) {
-			int status = parse_pipeline_core(
-					&param->socket_id,
-					&param->core_id,
-					&param->hyper_th_id,
-					ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-						ent->name);
-			param->force_bind = 1;
-			continue;
-		}
-
-		if (strcmp(ent->name, "mempool") == 0) {
-			int status = validate_name(ent->value,
-				"MEMPOOL", 1);
-			ssize_t idx;
-
-			PARSE_ERROR((status == 0), section_name,
-						ent->name);
-
-			idx = APP_PARAM_ADD(app->mempool_params, ent->value);
-			param->mempool_id = idx;
-			continue;
-		}
-
-		if (strcmp(ent->name, "burst_read") == 0) {
-			int status = parser_read_uint32(&param->burst_read,
-						ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-						ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "burst_write") == 0) {
-			int status = parser_read_uint32(&param->burst_write,
-						ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-						ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "dropless") == 0) {
-			int status = parser_read_arg_bool(ent->value);
-
-			PARSE_ERROR((status != -EINVAL), section_name,
-						ent->name);
-			param->dropless = status;
-			continue;
-		}
-
-		if (strcmp(ent->name, "n_retries") == 0) {
-			int status = parser_read_uint64(&param->n_retries,
-						ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-						ent->name);
-			continue;
-		}
-
-		/* unrecognized */
-		PARSE_ERROR_INVALID(0, section_name, ent->name);
-	}
-
-	free(entries);
-}
-
-static void
-parse_source(struct app_params *app,
-	const char *section_name,
-	struct rte_cfgfile *cfg)
-{
-	struct app_pktq_source_params *param;
-	struct rte_cfgfile_entry *entries;
-	int n_entries, i;
-	ssize_t param_idx;
-	uint32_t pcap_file_present = 0;
-	uint32_t pcap_size_present = 0;
-
-	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
-	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
-
-	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
-	PARSE_ERROR_MALLOC(entries != NULL);
-
-	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
-
-	param_idx = APP_PARAM_ADD(app->source_params, section_name);
-	param = &app->source_params[param_idx];
-	PARSE_CHECK_DUPLICATE_SECTION(param);
-
-	for (i = 0; i < n_entries; i++) {
-		struct rte_cfgfile_entry *ent = &entries[i];
-
-		if (strcmp(ent->name, "mempool") == 0) {
-			int status = validate_name(ent->value,
-				"MEMPOOL", 1);
-			ssize_t idx;
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-
-			idx = APP_PARAM_ADD(app->mempool_params, ent->value);
-			param->mempool_id = idx;
-			continue;
-		}
-
-		if (strcmp(ent->name, "burst") == 0) {
-			int status = parser_read_uint32(&param->burst,
-				ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "pcap_file_rd") == 0) {
-			PARSE_ERROR_DUPLICATE((pcap_file_present == 0),
-				section_name, ent->name);
-
-			param->file_name = strdup(ent->value);
-
-			PARSE_ERROR_MALLOC(param->file_name != NULL);
-			pcap_file_present = 1;
-
-			continue;
-		}
-
-		if (strcmp(ent->name, "pcap_bytes_rd_per_pkt") == 0) {
-			int status;
-
-			PARSE_ERROR_DUPLICATE((pcap_size_present == 0),
-				section_name, ent->name);
-
-			status = parser_read_uint32(
-				&param->n_bytes_per_pkt, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			pcap_size_present = 1;
-
-			continue;
-		}
-
-		/* unrecognized */
-		PARSE_ERROR_INVALID(0, section_name, ent->name);
-	}
-
-	free(entries);
-}
-
-static void
-parse_sink(struct app_params *app,
-	const char *section_name,
-	struct rte_cfgfile *cfg)
-{
-	struct app_pktq_sink_params *param;
-	struct rte_cfgfile_entry *entries;
-	int n_entries, i;
-	ssize_t param_idx;
-	uint32_t pcap_file_present = 0;
-	uint32_t pcap_n_pkt_present = 0;
-
-	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
-	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
-
-	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
-	PARSE_ERROR_MALLOC(entries != NULL);
-
-	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
-
-	param_idx = APP_PARAM_ADD(app->sink_params, section_name);
-	param = &app->sink_params[param_idx];
-	PARSE_CHECK_DUPLICATE_SECTION(param);
-
-	for (i = 0; i < n_entries; i++) {
-		struct rte_cfgfile_entry *ent = &entries[i];
-
-		if (strcmp(ent->name, "pcap_file_wr") == 0) {
-			PARSE_ERROR_DUPLICATE((pcap_file_present == 0),
-				section_name, ent->name);
-
-			param->file_name = strdup(ent->value);
-
-			PARSE_ERROR_MALLOC((param->file_name != NULL));
-
-			continue;
-		}
-
-		if (strcmp(ent->name, "pcap_n_pkt_wr") == 0) {
-			int status;
-
-			PARSE_ERROR_DUPLICATE((pcap_n_pkt_present == 0),
-				section_name, ent->name);
-
-			status = parser_read_uint32(
-				&param->n_pkts_to_dump, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-
-			continue;
-		}
-
-		/* unrecognized */
-		PARSE_ERROR_INVALID(0, section_name, ent->name);
-	}
-
-	free(entries);
-}
-
-static void
-parse_msgq_req_pipeline(struct app_params *app,
-	const char *section_name,
-	struct rte_cfgfile *cfg)
-{
-	struct app_msgq_params *param;
-	struct rte_cfgfile_entry *entries;
-	int n_entries, i;
-	ssize_t param_idx;
-
-	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
-	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
-
-	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
-	PARSE_ERROR_MALLOC(entries != NULL);
-
-	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
-
-	param_idx = APP_PARAM_ADD(app->msgq_params, section_name);
-	param = &app->msgq_params[param_idx];
-	PARSE_CHECK_DUPLICATE_SECTION(param);
-
-	for (i = 0; i < n_entries; i++) {
-		struct rte_cfgfile_entry *ent = &entries[i];
-
-		if (strcmp(ent->name, "size") == 0) {
-			int status = parser_read_uint32(&param->size,
-				ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		/* unrecognized */
-		PARSE_ERROR_INVALID(0, section_name, ent->name);
-	}
-
-	free(entries);
-}
-
-static void
-parse_msgq_rsp_pipeline(struct app_params *app,
-	const char *section_name,
-	struct rte_cfgfile *cfg)
-{
-	struct app_msgq_params *param;
-	struct rte_cfgfile_entry *entries;
-	int n_entries, i;
-	ssize_t param_idx;
-
-	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
-	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
-
-	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
-	PARSE_ERROR_MALLOC(entries != NULL);
-
-	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
-
-	param_idx = APP_PARAM_ADD(app->msgq_params, section_name);
-	param = &app->msgq_params[param_idx];
-	PARSE_CHECK_DUPLICATE_SECTION(param);
-
-	for (i = 0; i < n_entries; i++) {
-		struct rte_cfgfile_entry *ent = &entries[i];
-
-		if (strcmp(ent->name, "size") == 0) {
-			int status = parser_read_uint32(&param->size,
-				ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		/* unrecognized */
-		PARSE_ERROR_INVALID(0, section_name, ent->name);
-	}
-
-	free(entries);
-}
-
-static void
-parse_msgq(struct app_params *app,
-	const char *section_name,
-	struct rte_cfgfile *cfg)
-{
-	struct app_msgq_params *param;
-	struct rte_cfgfile_entry *entries;
-	int n_entries, i;
-	ssize_t param_idx;
-
-	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
-	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
-
-	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
-	PARSE_ERROR_MALLOC(entries != NULL);
-
-	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
-
-	param_idx = APP_PARAM_ADD(app->msgq_params, section_name);
-	param = &app->msgq_params[param_idx];
-	PARSE_CHECK_DUPLICATE_SECTION(param);
-
-	for (i = 0; i < n_entries; i++) {
-		struct rte_cfgfile_entry *ent = &entries[i];
-
-		if (strcmp(ent->name, "size") == 0) {
-			int status = parser_read_uint32(&param->size,
-				ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "cpu") == 0) {
-			int status = parser_read_uint32(
-				&param->cpu_socket_id, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		/* unrecognized */
-		PARSE_ERROR_INVALID(0, section_name, ent->name);
-	}
-
-	free(entries);
-}
-
-typedef void (*config_section_load)(struct app_params *p,
-	const char *section_name,
-	struct rte_cfgfile *cfg);
-
-struct config_section {
-	const char prefix[CFG_NAME_LEN];
-	int numbers;
-	config_section_load load;
-};
-
-static const struct config_section cfg_file_scheme[] = {
-	{"EAL", 0, parse_eal},
-	{"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},
-	{"TAP", 1, parse_tap},
-	{"KNI", 1, parse_kni},
-	{"SOURCE", 1, parse_source},
-	{"SINK", 1, parse_sink},
-	{"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)
-{
-	APP_PARAM_ADD(app->mempool_params, "MEMPOOL0");
-}
-
-static void
-create_implicit_links_from_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%" PRIu32, link_id);
-		idx = APP_PARAM_ADD(app->link_params, name);
-
-		app->link_params[idx].pmd_id = pmd_id;
-		link_id++;
-	}
-}
-
-static void
-assign_link_pmd_id_from_pci_bdf(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_links; i++) {
-		struct app_link_params *link = &app->link_params[i];
-
-		APP_CHECK((strlen(link->pci_bdf)),
-			"Parse error: %s pci_bdf is not configured "
-			"(port_mask is not provided)",
-			link->name);
-
-		link->pmd_id = i;
-	}
-}
-
-int
-app_config_parse(struct app_params *app, const char *file_name)
-{
-	struct rte_cfgfile *cfg;
-	char **section_names;
-	int i, j, sect_count;
-
-	/* Implicit mempools */
-	create_implicit_mempools(app);
-
-	/* Port mask */
-	if (app->port_mask)
-		create_implicit_links_from_port_mask(app, app->port_mask);
-
-	/* Load application configuration file */
-	cfg = rte_cfgfile_load(file_name, 0);
-	APP_CHECK((cfg != NULL), "Parse error: Unable to load config "
-		"file %s", file_name);
-
-	sect_count = rte_cfgfile_num_sections(cfg, NULL, 0);
-	APP_CHECK((sect_count > 0), "Parse error: number of sections "
-		"in file \"%s\" return %d", file_name,
-		sect_count);
-
-	section_names = malloc(sect_count * sizeof(char *));
-	PARSE_ERROR_MALLOC(section_names != NULL);
-
-	for (i = 0; i < sect_count; i++)
-		section_names[i] = malloc(CFG_NAME_LEN);
-
-	rte_cfgfile_sections(cfg, section_names, sect_count);
-
-	for (i = 0; i < sect_count; i++) {
-		const struct config_section *sch_s;
-		int len, cfg_name_len;
-
-		cfg_name_len = strlen(section_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,
-			 * for example: "ABC" should match section name
-			 * "ABC0.0", but it should not match section_name
-			 * "ABCDEF".
-			 */
-			if ((section_names[i][len] != '\0') &&
-				!isdigit(section_names[i][len]))
-				continue;
-
-			if (strncmp(sch_s->prefix, section_names[i], len) == 0)
-				break;
-		}
-
-		APP_CHECK(j < (int)RTE_DIM(cfg_file_scheme),
-			"Parse error: unknown section %s",
-			section_names[i]);
-
-		APP_CHECK(validate_name(section_names[i],
-			sch_s->prefix,
-			sch_s->numbers) == 0,
-			"Parse error: invalid section name \"%s\"",
-			section_names[i]);
-
-		sch_s->load(app, section_names[i], cfg);
-	}
-
-	for (i = 0; i < sect_count; i++)
-		free(section_names[i]);
-
-	free(section_names);
-
-	rte_cfgfile_close(cfg);
-
-	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->tap_params, app->n_pktq_tap);
-	APP_PARAM_COUNT(app->kni_params, app->n_pktq_kni);
-	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);
-
-	if (app->port_mask == 0)
-		assign_link_pmd_id_from_pci_bdf(app);
-
-	/* Save configuration to output file */
-	app_config_save(app, app->output_file);
-
-	/* Load TM configuration files */
-	app_config_parse_tm(app);
-
-	return 0;
-}
-
-static void
-save_eal_params(struct app_params *app, FILE *f)
-{
-	struct app_eal_params *p = &app->eal_params;
-	uint32_t i;
-
-	fprintf(f, "[EAL]\n");
-
-	if (p->coremap)
-		fprintf(f, "%s = %s\n", "lcores", p->coremap);
-
-	if (p->master_lcore_present)
-		fprintf(f, "%s = %" PRIu32 "\n",
-			"master_lcore", p->master_lcore);
-
-	fprintf(f, "%s = %" PRIu32 "\n", "n", p->channels);
-
-	if (p->memory_present)
-		fprintf(f, "%s = %" PRIu32 "\n", "m", p->memory);
-
-	if (p->ranks_present)
-		fprintf(f, "%s = %" PRIu32 "\n", "r", p->ranks);
-
-	for (i = 0; i < APP_MAX_LINKS; i++) {
-		if (p->pci_blacklist[i] == NULL)
-			break;
-
-		fprintf(f, "%s = %s\n", "pci_blacklist",
-			p->pci_blacklist[i]);
-	}
-
-	for (i = 0; i < APP_MAX_LINKS; i++) {
-		if (p->pci_whitelist[i] == NULL)
-			break;
-
-		fprintf(f, "%s = %s\n", "pci_whitelist",
-			p->pci_whitelist[i]);
-	}
-
-	for (i = 0; i < APP_MAX_LINKS; i++) {
-		if (p->vdev[i] == NULL)
-			break;
-
-		fprintf(f, "%s = %s\n", "vdev",
-			p->vdev[i]);
-	}
-
-	if (p->vmware_tsc_map_present)
-		fprintf(f, "%s = %s\n", "vmware_tsc_map",
-			(p->vmware_tsc_map) ? "yes" : "no");
-
-	if (p->proc_type)
-		fprintf(f, "%s = %s\n", "proc_type", p->proc_type);
-
-	if (p->syslog)
-		fprintf(f, "%s = %s\n", "syslog", p->syslog);
-
-	if (p->log_level_present)
-		fprintf(f, "%s = %" PRIu32 "\n", "log_level", p->log_level);
-
-	if (p->version_present)
-		fprintf(f, "%s = %s\n",	"v", (p->version) ? "yes" : "no");
-
-	if (p->help_present)
-		fprintf(f, "%s = %s\n",	"help", (p->help) ? "yes" : "no");
-
-	if (p->no_huge_present)
-		fprintf(f, "%s = %s\n",	"no_huge", (p->no_huge) ? "yes" : "no");
-
-	if (p->no_pci_present)
-		fprintf(f, "%s = %s\n",	"no_pci", (p->no_pci) ? "yes" : "no");
-
-	if (p->no_hpet_present)
-		fprintf(f, "%s = %s\n",	"no_hpet", (p->no_hpet) ? "yes" : "no");
-
-	if (p->no_shconf_present)
-		fprintf(f, "%s = %s\n", "no_shconf",
-			(p->no_shconf) ? "yes" : "no");
-
-	if (p->add_driver)
-		fprintf(f, "%s = %s\n",	"d", p->add_driver);
-
-	if (p->socket_mem)
-		fprintf(f, "%s = %s\n",	"socket_mem", p->socket_mem);
-
-	if (p->huge_dir)
-		fprintf(f, "%s = %s\n", "huge_dir", p->huge_dir);
-
-	if (p->file_prefix)
-		fprintf(f, "%s = %s\n", "file_prefix", p->file_prefix);
-
-	if (p->base_virtaddr)
-		fprintf(f, "%s = %s\n",	"base_virtaddr", p->base_virtaddr);
-
-	if (p->create_uio_dev_present)
-		fprintf(f, "%s = %s\n", "create_uio_dev",
-			(p->create_uio_dev) ? "yes" : "no");
-
-	if (p->vfio_intr)
-		fprintf(f, "%s = %s\n", "vfio_intr", p->vfio_intr);
-
-	fputc('\n', f);
-}
-
-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 = %s\n", "promisc", p->promisc ? "yes" : "no");
-		fprintf(f, "%s = %" PRIu32 "\n", "arp_q", p->arp_q);
-		fprintf(f, "%s = %" PRIu32 "\n", "tcp_syn_q",
-			p->tcp_syn_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);
-
-		if (p->n_rss_qs) {
-			uint32_t j;
-
-			/* rss_qs */
-			fprintf(f, "rss_qs = ");
-			for (j = 0; j < p->n_rss_qs; j++)
-				fprintf(f, "%" PRIu32 " ",	p->rss_qs[j]);
-			fputc('\n', f);
-
-			/* rss_proto_ipv4 */
-			if (p->rss_proto_ipv4) {
-				fprintf(f, "rss_proto_ipv4 = ");
-				if (p->rss_proto_ipv4 & ETH_RSS_IPV4)
-					fprintf(f, "IP ");
-				if (p->rss_proto_ipv4 & ETH_RSS_FRAG_IPV4)
-					fprintf(f, "FRAG ");
-				if (p->rss_proto_ipv4 &
-					ETH_RSS_NONFRAG_IPV4_TCP)
-					fprintf(f, "TCP ");
-				if (p->rss_proto_ipv4 &
-					ETH_RSS_NONFRAG_IPV4_UDP)
-					fprintf(f, "UDP ");
-				if (p->rss_proto_ipv4 &
-					ETH_RSS_NONFRAG_IPV4_SCTP)
-					fprintf(f, "SCTP ");
-				if (p->rss_proto_ipv4 &
-					ETH_RSS_NONFRAG_IPV4_OTHER)
-					fprintf(f, "OTHER ");
-				fprintf(f, "\n");
-			} else
-				fprintf(f, "; rss_proto_ipv4 = <NONE>\n");
-
-			/* rss_proto_ipv6 */
-			if (p->rss_proto_ipv6) {
-				fprintf(f, "rss_proto_ipv6 = ");
-				if (p->rss_proto_ipv6 & ETH_RSS_IPV6)
-					fprintf(f, "IP ");
-				if (p->rss_proto_ipv6 & ETH_RSS_FRAG_IPV6)
-					fprintf(f, "FRAG ");
-				if (p->rss_proto_ipv6 &
-					ETH_RSS_NONFRAG_IPV6_TCP)
-					fprintf(f, "TCP ");
-				if (p->rss_proto_ipv6 &
-					ETH_RSS_NONFRAG_IPV6_UDP)
-					fprintf(f, "UDP ");
-				if (p->rss_proto_ipv6 &
-					ETH_RSS_NONFRAG_IPV6_SCTP)
-					fprintf(f, "SCTP ");
-				if (p->rss_proto_ipv6 &
-					ETH_RSS_NONFRAG_IPV6_OTHER)
-					fprintf(f, "OTHER ");
-				if (p->rss_proto_ipv6 & ETH_RSS_IPV6_EX)
-					fprintf(f, "IP_EX ");
-				if (p->rss_proto_ipv6 &
-					ETH_RSS_IPV6_TCP_EX)
-					fprintf(f, "TCP_EX ");
-				if (p->rss_proto_ipv6 &
-					ETH_RSS_IPV6_UDP_EX)
-					fprintf(f, "UDP_EX ");
-				fprintf(f, "\n");
-			} else
-				fprintf(f, "; rss_proto_ipv6 = <NONE>\n");
-
-			/* rss_proto_l2 */
-			if (p->rss_proto_l2) {
-				fprintf(f, "rss_proto_l2 = ");
-				if (p->rss_proto_l2 & ETH_RSS_L2_PAYLOAD)
-					fprintf(f, "L2 ");
-				fprintf(f, "\n");
-			} else
-				fprintf(f, "; rss_proto_l2 = <NONE>\n");
-		} else {
-			fprintf(f, "; rss_qs = <NONE>\n");
-			fprintf(f, "; rss_proto_ipv4 = <NONE>\n");
-			fprintf(f, "; rss_proto_ipv6 = <NONE>\n");
-			fprintf(f, "; rss_proto_l2 = <NONE>\n");
-		}
-
-		if (strlen(p->pci_bdf))
-			fprintf(f, "%s = %s\n", "pci_bdf", p->pci_bdf);
-
-		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");
-		fprintf(f, "%s = %" PRIu64 "\n", "n_retries", p->n_retries);
-
-		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);
-		fprintf(f, "%s = %s\n", "ipv4_frag", p->ipv4_frag ? "yes" : "no");
-		fprintf(f, "%s = %s\n", "ipv6_frag", p->ipv6_frag ? "yes" : "no");
-		fprintf(f, "%s = %s\n", "ipv4_ras", p->ipv4_ras ? "yes" : "no");
-		fprintf(f, "%s = %s\n", "ipv6_ras", p->ipv6_ras ? "yes" : "no");
-		if ((p->ipv4_frag == 1) || (p->ipv6_frag == 1)) {
-			fprintf(f, "%s = %" PRIu32 "\n", "mtu", p->mtu);
-			fprintf(f, "%s = %" PRIu32 "\n", "metadata_size", p->metadata_size);
-			fprintf(f, "%s = %s\n",
-				"mempool_direct",
-				app->mempool_params[p->mempool_direct_id].name);
-			fprintf(f, "%s = %s\n",
-				"mempool_indirect",
-				app->mempool_params[p->mempool_indirect_id].name);
-		}
-
-		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 = %" PRIu32 "\n", "burst_read", p->burst_read);
-		fprintf(f, "%s = %" PRIu32 "\n", "burst_write", p->burst_write);
-
-		fputc('\n', f);
-	}
-}
-
-static void
-save_tap_params(struct app_params *app, FILE *f)
-{
-	struct app_pktq_tap_params *p;
-	size_t i, count;
-
-	count = RTE_DIM(app->tap_params);
-	for (i = 0; i < count; i++) {
-		p = &app->tap_params[i];
-		if (!APP_PARAM_VALID(p))
-			continue;
-
-		fprintf(f, "[%s]\n", p->name);
-		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 = %s\n", "mempool",
-			app->mempool_params[p->mempool_id].name);
-
-		fputc('\n', f);
-	}
-}
-
-static void
-save_kni_params(struct app_params *app, FILE *f)
-{
-	struct app_pktq_kni_params *p;
-	size_t i, count;
-
-	count = RTE_DIM(app->kni_params);
-	for (i = 0; i < count; i++) {
-		p = &app->kni_params[i];
-		if (!APP_PARAM_VALID(p))
-			continue;
-
-		/* section name */
-		fprintf(f, "[%s]\n", p->name);
-
-		/* core */
-		if (p->force_bind) {
-			fprintf(f, "; force_bind = 1\n");
-			fprintf(f, "core = s%" PRIu32 "c%" PRIu32 "%s\n",
-					p->socket_id,
-					p->core_id,
-					(p->hyper_th_id) ? "h" : "");
-		} else
-			fprintf(f, "; force_bind = 0\n");
-
-		/* mempool */
-		fprintf(f, "%s = %s\n", "mempool",
-				app->mempool_params[p->mempool_id].name);
-
-		/* burst_read */
-		fprintf(f, "%s = %" PRIu32 "\n", "burst_read", p->burst_read);
-
-		/* burst_write */
-		fprintf(f, "%s = %" PRIu32 "\n", "burst_write", p->burst_write);
-
-		/* dropless */
-		fprintf(f, "%s = %s\n",
-				"dropless",
-				p->dropless ? "yes" : "no");
-
-		/* n_retries */
-		fprintf(f, "%s = %" PRIu64 "\n", "n_retries", p->n_retries);
-
-		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 = %" PRIu32 "\n", "burst", p->burst);
-		fprintf(f, "%s = %s\n", "pcap_file_rd", p->file_name);
-		fprintf(f, "%s = %" PRIu32 "\n", "pcap_bytes_rd_per_pkt",
-			p->n_bytes_per_pkt);
-		fputc('\n', f);
-	}
-}
-
-static void
-save_sink_params(struct app_params *app, FILE *f)
-{
-	struct app_pktq_sink_params *p;
-	size_t i, count;
-
-	count = RTE_DIM(app->sink_params);
-	for (i = 0; i < count; i++) {
-		p = &app->sink_params[i];
-		if (!APP_PARAM_VALID(p))
-			continue;
-
-		fprintf(f, "[%s]\n", p->name);
-		fprintf(f, "%s = %s\n", "pcap_file_wr", p->file_name);
-		fprintf(f, "%s = %" PRIu32 "\n",
-				"pcap_n_pkt_wr", p->n_pkts_to_dump);
-		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%" PRIu32 "c%" PRIu32 "%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_TAP:
-					name = app->tap_params[pp->id].name;
-					break;
-				case APP_PKTQ_IN_KNI:
-					name = app->kni_params[pp->id].name;
-					break;
-				case APP_PKTQ_IN_SOURCE:
-					name = app->source_params[pp->id].name;
-					break;
-				default:
-					APP_CHECK(0, "System error "
-						"occurred while saving "
-						"parameter to file");
-				}
-
-				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_TAP:
-					name = app->tap_params[pp->id].name;
-					break;
-				case APP_PKTQ_OUT_KNI:
-					name = app->kni_params[pp->id].name;
-					break;
-				case APP_PKTQ_OUT_SINK:
-					name = app->sink_params[pp->id].name;
-					break;
-				default:
-					APP_CHECK(0, "System error "
-						"occurred while saving "
-						"parameter to file");
-				}
-
-				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_out) {
-			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 = %" PRIu32 "\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;
-	char *name, *dir_name;
-	int status;
-
-	name = strdup(file_name);
-	dir_name = dirname(name);
-	status = access(dir_name, W_OK);
-	APP_CHECK((status == 0),
-		"Error: need write access privilege to directory "
-		"\"%s\" to save configuration\n", dir_name);
-
-	file = fopen(file_name, "w");
-	APP_CHECK((file != NULL),
-		"Error: failed to save configuration to file \"%s\"",
-		file_name);
-
-	save_eal_params(app, file);
-	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_tap_params(app, file);
-	save_kni_params(app, file);
-	save_source_params(app, file);
-	save_sink_params(app, file);
-	save_msgq_params(app, file);
-
-	fclose(file);
-	free(name);
-}
-
-int
-app_config_init(struct app_params *app)
-{
-	size_t i;
-
-	memcpy(app, &app_params_default, sizeof(struct app_params));
-
-	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->tap_params); i++)
-		memcpy(&app->tap_params[i],
-			&default_tap_params,
-			sizeof(default_tap_params));
-
-	for (i = 0; i < RTE_DIM(app->kni_params); i++)
-		memcpy(&app->kni_params[i],
-			   &default_kni_params,
-			   sizeof(default_kni_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;
-}
-
-static char *
-filenamedup(const char *filename, const char *suffix)
-{
-	char *s = malloc(strlen(filename) + strlen(suffix) + 1);
-
-	if (!s)
-		return NULL;
-
-	sprintf(s, "%s%s", filename, suffix);
-	return s;
-}
-
-int
-app_config_args(struct app_params *app, int argc, char **argv)
-{
-	const char *optname;
-	int opt, option_index;
-	int f_present, s_present, p_present, l_present;
-	int preproc_present, preproc_params_present;
-	int scaned = 0;
-
-	static struct option lgopts[] = {
-		{ "preproc", 1, 0, 0 },
-		{ "preproc-args", 1, 0, 0 },
-		{ NULL,  0, 0, 0 }
-	};
-
-	/* Copy application name */
-	strncpy(app->app_name, argv[0], APP_APPNAME_SIZE - 1);
-
-	f_present = 0;
-	s_present = 0;
-	p_present = 0;
-	l_present = 0;
-	preproc_present = 0;
-	preproc_params_present = 0;
-
-	while ((opt = getopt_long(argc, argv, "f:s:p:l:", lgopts,
-			&option_index)) != EOF)
-		switch (opt) {
-		case 'f':
-			if (f_present)
-				rte_panic("Error: Config file is provided "
-					"more than once\n");
-			f_present = 1;
-
-			if (!strlen(optarg))
-				rte_panic("Error: Config file name is null\n");
-
-			app->config_file = strdup(optarg);
-			if (app->config_file == NULL)
-				rte_panic("Error: Memory allocation failure\n");
-
-			break;
-
-		case 's':
-			if (s_present)
-				rte_panic("Error: Script file is provided "
-					"more than once\n");
-			s_present = 1;
-
-			if (!strlen(optarg))
-				rte_panic("Error: Script file name is null\n");
-
-			app->script_file = strdup(optarg);
-			if (app->script_file == NULL)
-				rte_panic("Error: Memory allocation failure\n");
-
-			break;
-
-		case 'p':
-			if (p_present)
-				rte_panic("Error: PORT_MASK is provided "
-					"more than once\n");
-			p_present = 1;
-
-			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");
-
-			break;
-
-		case 'l':
-			if (l_present)
-				rte_panic("Error: LOG_LEVEL is provided "
-					"more than once\n");
-			l_present = 1;
-
-			if ((sscanf(optarg, "%" SCNu32 "%n", &app->log_level,
-				&scaned) != 1) ||
-				((size_t) scaned != strlen(optarg)) ||
-				(app->log_level >= APP_LOG_LEVELS))
-				rte_panic("Error: LOG_LEVEL invalid value\n");
-
-			break;
-
-		case 0:
-			optname = lgopts[option_index].name;
-
-			if (strcmp(optname, "preproc") == 0) {
-				if (preproc_present)
-					rte_panic("Error: Preprocessor argument "
-						"is provided more than once\n");
-				preproc_present = 1;
-
-				app->preproc = strdup(optarg);
-				break;
-			}
-
-			if (strcmp(optname, "preproc-args") == 0) {
-				if (preproc_params_present)
-					rte_panic("Error: Preprocessor args "
-						"are provided more than once\n");
-				preproc_params_present = 1;
-
-				app->preproc_args = strdup(optarg);
-				break;
-			}
-
-			app_print_usage(argv[0]);
-			break;
-
-		default:
-			app_print_usage(argv[0]);
-		}
-
-	optind = 1; /* reset getopt lib */
-
-	/* Check dependencies between args */
-	if (preproc_params_present && (preproc_present == 0))
-		rte_panic("Error: Preprocessor args specified while "
-			"preprocessor is not defined\n");
-
-	app->parser_file = preproc_present ?
-		filenamedup(app->config_file, ".preproc") :
-		strdup(app->config_file);
-	app->output_file = filenamedup(app->config_file, ".out");
-
-	return 0;
-}
-
-int
-app_config_preproc(struct app_params *app)
-{
-	char buffer[256];
-	int status;
-
-	if (app->preproc == NULL)
-		return 0;
-
-	status = access(app->config_file, F_OK | R_OK);
-	APP_CHECK((status == 0), "Error: Unable to open file %s",
-		app->config_file);
-
-	snprintf(buffer, sizeof(buffer), "%s %s %s > %s",
-		app->preproc,
-		app->preproc_args ? app->preproc_args : "",
-		app->config_file,
-		app->parser_file);
-
-	status = system(buffer);
-	APP_CHECK((WIFEXITED(status) && (WEXITSTATUS(status) == 0)),
-		"Error occurred while pre-processing file \"%s\"\n",
-		app->config_file);
-
-	return status;
-}
diff --git a/examples/ip_pipeline/config_parse_tm.c b/examples/ip_pipeline/config_parse_tm.c
deleted file mode 100644
index 6edd2ca..0000000
--- a/examples/ip_pipeline/config_parse_tm.c
+++ /dev/null
@@ -1,419 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-#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 <libgen.h>
-#include <unistd.h>
-
-#include <rte_errno.h>
-#include <rte_cfgfile.h>
-#include <rte_string_fns.h>
-
-#include "app.h"
-
-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", "mtu");
-	if (entry)
-		port_params->mtu = (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 %" PRId32 " 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 %" PRId32 " 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 %" PRId32 " 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 %" PRId32 " 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 %" PRId32, 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 %" PRId32, 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);
-			struct rte_cfgfile_entry entries[n_entries];
-
-			rte_cfgfile_section_entries(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 + 1];
-
-					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 %" PRId32,
-							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 i;
-
-	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_port_params));
-	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];
-
-	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;
-}
-
-int
-app_config_parse_tm(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < RTE_DIM(app->tm_params); i++) {
-		struct app_pktq_tm_params *p = &app->tm_params[i];
-		int status;
-
-		if (!APP_PARAM_VALID(p))
-			break;
-
-		status = tm_cfgfile_load(p);
-		APP_CHECK(status == 0,
-			"Parse error for %s configuration file \"%s\"\n",
-			p->name,
-			p->file_name);
-	}
-
-	return 0;
-}
diff --git a/examples/ip_pipeline/cpu_core_map.c b/examples/ip_pipeline/cpu_core_map.c
deleted file mode 100644
index 231f38e..0000000
--- a/examples/ip_pipeline/cpu_core_map.c
+++ /dev/null
@@ -1,471 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#include <inttypes.h>
-#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%" PRIu32 "/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%" PRIu32 "/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 !defined(RTE_ARCH_PPC_64)
-			if (lcore_socket_id < 0)
-				return -1;
-#endif
-
-			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 !defined(RTE_ARCH_PPC_64)
-				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;
-#endif
-
-#if !defined(RTE_ARCH_PPC_64)
-				if (((uint32_t) lcore_socket_id == socket_id) &&
-					((uint32_t) lcore_core_id == core_id)) {
-#else
-				if (((uint32_t) lcore_socket_id == socket_id)) {
-#endif
-					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)
-{
-	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 %" PRIu32 ":\n", socket_id);
-
-		for (core_id = 0;
-			core_id < map->n_cores_per_socket;
-			core_id++) {
-			printf("[%" PRIu32 "] = [", 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 =
-					cpu_core_map_get_core_id_linux(
-						lcore_id);
-
-				printf(" %" PRId32 " (%" PRIu32 ") ",
-					lcore_id,
-					core_id_noncontig);
-			}
-
-			printf("]\n");
-		}
-	}
-}
-
-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)
-{
-	free(map);
-}
diff --git a/examples/ip_pipeline/cpu_core_map.h b/examples/ip_pipeline/cpu_core_map.h
deleted file mode 100644
index 5e50f6e..0000000
--- a/examples/ip_pipeline/cpu_core_map.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#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/init.c b/examples/ip_pipeline/init.c
deleted file mode 100644
index 9430809..0000000
--- a/examples/ip_pipeline/init.c
+++ /dev/null
@@ -1,1343 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2016 Intel Corporation
- */
-
-#include <inttypes.h>
-#include <stdio.h>
-#include <string.h>
-#include <netinet/in.h>
-#ifdef RTE_EXEC_ENV_LINUXAPP
-#include <linux/if.h>
-#include <linux/if_tun.h>
-#endif
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <unistd.h>
-
-#include <rte_cycles.h>
-#include <rte_ethdev.h>
-#include <rte_ether.h>
-#include <rte_ip.h>
-#include <rte_eal.h>
-#include <rte_malloc.h>
-#include <rte_bus_pci.h>
-
-#include "app.h"
-#include "pipeline.h"
-
-#define APP_NAME_SIZE	32
-
-#define APP_RETA_SIZE_MAX     (ETH_RSS_RETA_SIZE_512 / RTE_RETA_GROUP_SIZE)
-
-static void
-app_init_core_map(struct app_params *app)
-{
-	APP_LOG(app, HIGH, "Initializing CPU core map ...");
-	app->core_map = cpu_core_map_init(RTE_MAX_NUMA_NODES, RTE_MAX_LCORE,
-				4, 0);
-
-	if (app->core_map == NULL)
-		rte_panic("Cannot create CPU core map\n");
-
-	if (app->log_level >= APP_LOG_LEVEL_LOW)
-		cpu_core_map_print(app->core_map);
-}
-
-/* Core Mask String in Hex Representation */
-#define APP_CORE_MASK_STRING_SIZE ((64 * APP_CORE_MASK_SIZE) / 8 * 2 + 1)
-
-static void
-app_init_core_mask(struct app_params *app)
-{
-	uint32_t i;
-	char core_mask_str[APP_CORE_MASK_STRING_SIZE];
-
-	for (i = 0; i < app->n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		int lcore_id;
-
-		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");
-
-		app_core_enable_in_core_mask(app, lcore_id);
-	}
-
-	app_core_build_core_mask_string(app, core_mask_str);
-	APP_LOG(app, HIGH, "CPU core mask = 0x%s", core_mask_str);
-}
-
-static void
-app_init_eal(struct app_params *app)
-{
-	char buffer[256];
-	char core_mask_str[APP_CORE_MASK_STRING_SIZE];
-	struct app_eal_params *p = &app->eal_params;
-	uint32_t n_args = 0;
-	uint32_t i;
-	int status;
-
-	app->eal_argv[n_args++] = strdup(app->app_name);
-
-	app_core_build_core_mask_string(app, core_mask_str);
-	snprintf(buffer, sizeof(buffer), "-c%s", core_mask_str);
-	app->eal_argv[n_args++] = strdup(buffer);
-
-	if (p->coremap) {
-		snprintf(buffer, sizeof(buffer), "--lcores=%s", p->coremap);
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if (p->master_lcore_present) {
-		snprintf(buffer,
-			sizeof(buffer),
-			"--master-lcore=%" PRIu32,
-			p->master_lcore);
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	snprintf(buffer, sizeof(buffer), "-n%" PRIu32, p->channels);
-	app->eal_argv[n_args++] = strdup(buffer);
-
-	if (p->memory_present) {
-		snprintf(buffer, sizeof(buffer), "-m%" PRIu32, p->memory);
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if (p->ranks_present) {
-		snprintf(buffer, sizeof(buffer), "-r%" PRIu32, p->ranks);
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	for (i = 0; i < APP_MAX_LINKS; i++) {
-		if (p->pci_blacklist[i] == NULL)
-			break;
-
-		snprintf(buffer,
-			sizeof(buffer),
-			"--pci-blacklist=%s",
-			p->pci_blacklist[i]);
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if (app->port_mask != 0)
-		for (i = 0; i < APP_MAX_LINKS; i++) {
-			if (p->pci_whitelist[i] == NULL)
-				break;
-
-			snprintf(buffer,
-				sizeof(buffer),
-				"--pci-whitelist=%s",
-				p->pci_whitelist[i]);
-			app->eal_argv[n_args++] = strdup(buffer);
-		}
-	else
-		for (i = 0; i < app->n_links; i++) {
-			char *pci_bdf = app->link_params[i].pci_bdf;
-
-			snprintf(buffer,
-				sizeof(buffer),
-				"--pci-whitelist=%s",
-				pci_bdf);
-			app->eal_argv[n_args++] = strdup(buffer);
-		}
-
-	for (i = 0; i < APP_MAX_LINKS; i++) {
-		if (p->vdev[i] == NULL)
-			break;
-
-		snprintf(buffer,
-			sizeof(buffer),
-			"--vdev=%s",
-			p->vdev[i]);
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if ((p->vmware_tsc_map_present) && p->vmware_tsc_map) {
-		snprintf(buffer, sizeof(buffer), "--vmware-tsc-map");
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if (p->proc_type) {
-		snprintf(buffer,
-			sizeof(buffer),
-			"--proc-type=%s",
-			p->proc_type);
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if (p->syslog) {
-		snprintf(buffer, sizeof(buffer), "--syslog=%s", p->syslog);
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if (p->log_level_present) {
-		snprintf(buffer,
-			sizeof(buffer),
-			"--log-level=%" PRIu32,
-			p->log_level);
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if ((p->version_present) && p->version) {
-		snprintf(buffer, sizeof(buffer), "-v");
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if ((p->help_present) && p->help) {
-		snprintf(buffer, sizeof(buffer), "--help");
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if ((p->no_huge_present) && p->no_huge) {
-		snprintf(buffer, sizeof(buffer), "--no-huge");
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if ((p->no_pci_present) && p->no_pci) {
-		snprintf(buffer, sizeof(buffer), "--no-pci");
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if ((p->no_hpet_present) && p->no_hpet) {
-		snprintf(buffer, sizeof(buffer), "--no-hpet");
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if ((p->no_shconf_present) && p->no_shconf) {
-		snprintf(buffer, sizeof(buffer), "--no-shconf");
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if (p->add_driver) {
-		snprintf(buffer, sizeof(buffer), "-d%s", p->add_driver);
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if (p->socket_mem) {
-		snprintf(buffer,
-			sizeof(buffer),
-			"--socket-mem=%s",
-			p->socket_mem);
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if (p->huge_dir) {
-		snprintf(buffer, sizeof(buffer), "--huge-dir=%s", p->huge_dir);
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if (p->file_prefix) {
-		snprintf(buffer,
-			sizeof(buffer),
-			"--file-prefix=%s",
-			p->file_prefix);
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if (p->base_virtaddr) {
-		snprintf(buffer,
-			sizeof(buffer),
-			"--base-virtaddr=%s",
-			p->base_virtaddr);
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if ((p->create_uio_dev_present) && p->create_uio_dev) {
-		snprintf(buffer, sizeof(buffer), "--create-uio-dev");
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if (p->vfio_intr) {
-		snprintf(buffer,
-			sizeof(buffer),
-			"--vfio-intr=%s",
-			p->vfio_intr);
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	snprintf(buffer, sizeof(buffer), "--");
-	app->eal_argv[n_args++] = strdup(buffer);
-
-	app->eal_argc = n_args;
-
-	APP_LOG(app, HIGH, "Initializing EAL ...");
-	if (app->log_level >= APP_LOG_LEVEL_LOW) {
-		int i;
-
-		fprintf(stdout, "[APP] EAL arguments: \"");
-		for (i = 1; i < app->eal_argc; i++)
-			fprintf(stdout, "%s ", app->eal_argv[i]);
-		fprintf(stdout, "\"\n");
-	}
-
-	status = rte_eal_init(app->eal_argc, app->eal_argv);
-	if (status < 0)
-		rte_panic("EAL init error\n");
-}
-
-static void
-app_init_mempool(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_mempools; i++) {
-		struct app_mempool_params *p = &app->mempool_params[i];
-
-		APP_LOG(app, HIGH, "Initializing %s ...", p->name);
-		app->mempool[i] = rte_pktmbuf_pool_create(
-			p->name,
-			p->pool_size,
-			p->cache_size,
-			0, /* priv_size */
-			p->buffer_size -
-				sizeof(struct rte_mbuf), /* mbuf data size */
-			p->cpu_socket_id);
-
-		if (app->mempool[i] == NULL)
-			rte_panic("%s init error\n", p->name);
-	}
-}
-
-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 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_q,
-	};
-
-	return rte_eth_dev_filter_ctrl(link->pmd_id,
-		RTE_ETH_FILTER_SYN,
-		RTE_ETH_FILTER_ADD,
-		&filter);
-}
-
-static inline int
-app_link_filter_ip_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 = UINT32_MAX, /* Enable */
-		.src_ip = 0,
-		.src_ip_mask = 0, /* Disable */
-		.dst_port = 0,
-		.dst_port_mask = 0, /* Disable */
-		.src_port = 0,
-		.src_port_mask = 0, /* Disable */
-		.proto = 0,
-		.proto_mask = 0, /* 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);
-}
-
-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 = UINT32_MAX, /* Enable */
-		.src_ip = 0,
-		.src_ip_mask = 0, /* Disable */
-		.dst_port = 0,
-		.dst_port_mask = 0, /* Disable */
-		.src_port = 0,
-		.src_port_mask = 0, /* Disable */
-		.proto = 0,
-		.proto_mask = 0, /* 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);
-}
-
-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 = UINT32_MAX, /* Enable */
-		.src_ip = 0,
-		.src_ip_mask = 0, /* Disable */
-		.dst_port = 0,
-		.dst_port_mask = 0, /* Disable */
-		.src_port = 0,
-		.src_port_mask = 0, /* Disable */
-		.proto = IPPROTO_TCP,
-		.proto_mask = UINT8_MAX, /* 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);
-}
-
-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 = UINT32_MAX, /* Enable */
-		.src_ip = 0,
-		.src_ip_mask = 0, /* Disable */
-		.dst_port = 0,
-		.dst_port_mask = 0, /* Disable */
-		.src_port = 0,
-		.src_port_mask = 0, /* Disable */
-		.proto = IPPROTO_TCP,
-		.proto_mask = UINT8_MAX, /* 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);
-}
-
-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 = UINT32_MAX, /* Enable */
-		.src_ip = 0,
-		.src_ip_mask = 0, /* Disable */
-		.dst_port = 0,
-		.dst_port_mask = 0, /* Disable */
-		.src_port = 0,
-		.src_port_mask = 0, /* Disable */
-		.proto = IPPROTO_UDP,
-		.proto_mask = UINT8_MAX, /* 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 = UINT32_MAX, /* Enable */
-		.src_ip = 0,
-		.src_ip_mask = 0, /* Disable */
-		.dst_port = 0,
-		.dst_port_mask = 0, /* Disable */
-		.src_port = 0,
-		.src_port_mask = 0, /* Disable */
-		.proto = IPPROTO_UDP,
-		.proto_mask = UINT8_MAX, /* 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 = UINT32_MAX, /* Enable */
-		.src_ip = 0,
-		.src_ip_mask = 0, /* Disable */
-		.dst_port = 0,
-		.dst_port_mask = 0, /* Disable */
-		.src_port = 0,
-		.src_port_mask = 0, /* Disable */
-		.proto = IPPROTO_SCTP,
-		.proto_mask = UINT8_MAX, /* 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 = UINT32_MAX, /* Enable */
-		.src_ip = 0,
-		.src_ip_mask = 0, /* Disable */
-		.dst_port = 0,
-		.dst_port_mask = 0, /* Disable */
-		.src_port = 0,
-		.src_port_mask = 0, /* Disable */
-		.proto = IPPROTO_SCTP,
-		.proto_mask = UINT8_MAX, /* 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);
-}
-
-static void
-app_link_set_arp_filter(struct app_params *app, struct app_link_params *cp)
-{
-	if (cp->arp_q != 0) {
-		int status = app_link_filter_arp_add(cp);
-
-		APP_LOG(app, LOW, "%s (%" PRIu32 "): "
-			"Adding ARP filter (queue = %" PRIu32 ")",
-			cp->name, cp->pmd_id, cp->arp_q);
-
-		if (status)
-			rte_panic("%s (%" PRIu32 "): "
-				"Error adding ARP filter "
-				"(queue = %" PRIu32 ") (%" PRId32 ")\n",
-				cp->name, cp->pmd_id, cp->arp_q, status);
-	}
-}
-
-static void
-app_link_set_tcp_syn_filter(struct app_params *app, struct app_link_params *cp)
-{
-	if (cp->tcp_syn_q != 0) {
-		int status = app_link_filter_tcp_syn_add(cp);
-
-		APP_LOG(app, LOW, "%s (%" PRIu32 "): "
-			"Adding TCP SYN filter (queue = %" PRIu32 ")",
-			cp->name, cp->pmd_id, cp->tcp_syn_q);
-
-		if (status)
-			rte_panic("%s (%" PRIu32 "): "
-				"Error adding TCP SYN filter "
-				"(queue = %" PRIu32 ") (%" PRId32 ")\n",
-				cp->name, cp->pmd_id, cp->tcp_syn_q,
-				status);
-	}
-}
-
-void
-app_link_up_internal(struct app_params *app, struct app_link_params *cp)
-{
-	uint32_t i;
-	int status;
-
-	/* For each link, add filters for IP of current link */
-	if (cp->ip != 0) {
-		for (i = 0; i < app->n_links; i++) {
-			struct app_link_params *p = &app->link_params[i];
-
-			/* IP */
-			if (p->ip_local_q != 0) {
-				int status = app_link_filter_ip_add(p, cp);
-
-				APP_LOG(app, LOW, "%s (%" PRIu32 "): "
-					"Adding IP filter (queue= %" PRIu32
-					", IP = 0x%08" PRIx32 ")",
-					p->name, p->pmd_id, p->ip_local_q,
-					cp->ip);
-
-				if (status)
-					rte_panic("%s (%" PRIu32 "): "
-						"Error adding IP "
-						"filter (queue= %" PRIu32 ", "
-						"IP = 0x%08" PRIx32
-						") (%" PRId32 ")\n",
-						p->name, p->pmd_id,
-						p->ip_local_q, cp->ip, status);
-			}
-
-			/* TCP */
-			if (p->tcp_local_q != 0) {
-				int status = app_link_filter_tcp_add(p, cp);
-
-				APP_LOG(app, LOW, "%s (%" PRIu32 "): "
-					"Adding TCP filter "
-					"(queue = %" PRIu32
-					", IP = 0x%08" PRIx32 ")",
-					p->name, p->pmd_id, p->tcp_local_q,
-					cp->ip);
-
-				if (status)
-					rte_panic("%s (%" PRIu32 "): "
-						"Error adding TCP "
-						"filter (queue = %" PRIu32 ", "
-						"IP = 0x%08" PRIx32
-						") (%" PRId32 ")\n",
-						p->name, p->pmd_id,
-						p->tcp_local_q, cp->ip, status);
-			}
-
-			/* UDP */
-			if (p->udp_local_q != 0) {
-				int status = app_link_filter_udp_add(p, cp);
-
-				APP_LOG(app, LOW, "%s (%" PRIu32 "): "
-					"Adding UDP filter "
-					"(queue = %" PRIu32
-					", IP = 0x%08" PRIx32 ")",
-					p->name, p->pmd_id, p->udp_local_q,
-					cp->ip);
-
-				if (status)
-					rte_panic("%s (%" PRIu32 "): "
-						"Error adding UDP "
-						"filter (queue = %" PRIu32 ", "
-						"IP = 0x%08" PRIx32
-						") (%" PRId32 ")\n",
-						p->name, p->pmd_id,
-						p->udp_local_q, cp->ip, status);
-			}
-
-			/* SCTP */
-			if (p->sctp_local_q != 0) {
-				int status = app_link_filter_sctp_add(p, cp);
-
-				APP_LOG(app, LOW, "%s (%" PRIu32
-					"): Adding SCTP filter "
-					"(queue = %" PRIu32
-					", IP = 0x%08" PRIx32 ")",
-					p->name, p->pmd_id, p->sctp_local_q,
-					cp->ip);
-
-				if (status)
-					rte_panic("%s (%" PRIu32 "): "
-						"Error adding SCTP "
-						"filter (queue = %" PRIu32 ", "
-						"IP = 0x%08" PRIx32
-						") (%" PRId32 ")\n",
-						p->name, p->pmd_id,
-						p->sctp_local_q, cp->ip,
-						status);
-			}
-		}
-	}
-
-	/* PMD link up */
-	status = rte_eth_dev_set_link_up(cp->pmd_id);
-	/* Do not panic if PMD does not provide link up functionality */
-	if (status < 0 && status != -ENOTSUP)
-		rte_panic("%s (%" PRIu32 "): PMD set link up error %"
-			PRId32 "\n", cp->name, cp->pmd_id, status);
-
-	/* Mark link as UP */
-	cp->state = 1;
-}
-
-void
-app_link_down_internal(struct app_params *app, struct app_link_params *cp)
-{
-	uint32_t i;
-	int status;
-
-	/* PMD link down */
-	status = rte_eth_dev_set_link_down(cp->pmd_id);
-	/* Do not panic if PMD does not provide link down functionality */
-	if (status < 0 && status != -ENOTSUP)
-		rte_panic("%s (%" PRIu32 "): PMD set link down error %"
-			PRId32 "\n", cp->name, cp->pmd_id, status);
-
-	/* Mark link as DOWN */
-	cp->state = 0;
-
-	/* Return if current link IP is not valid */
-	if (cp->ip == 0)
-		return;
-
-	/* For each link, remove filters for IP of current link */
-	for (i = 0; i < app->n_links; i++) {
-		struct app_link_params *p = &app->link_params[i];
-
-		/* IP */
-		if (p->ip_local_q != 0) {
-			int status = app_link_filter_ip_del(p, cp);
-
-			APP_LOG(app, LOW, "%s (%" PRIu32
-				"): Deleting IP filter "
-				"(queue = %" PRIu32 ", IP = 0x%" PRIx32 ")",
-				p->name, p->pmd_id, p->ip_local_q, cp->ip);
-
-			if (status)
-				rte_panic("%s (%" PRIu32
-					"): Error deleting IP filter "
-					"(queue = %" PRIu32
-					", IP = 0x%" PRIx32
-					") (%" PRId32 ")\n",
-					p->name, p->pmd_id, p->ip_local_q,
-					cp->ip, status);
-		}
-
-		/* TCP */
-		if (p->tcp_local_q != 0) {
-			int status = app_link_filter_tcp_del(p, cp);
-
-			APP_LOG(app, LOW, "%s (%" PRIu32
-				"): Deleting TCP filter "
-				"(queue = %" PRIu32
-				", IP = 0x%" PRIx32 ")",
-				p->name, p->pmd_id, p->tcp_local_q, cp->ip);
-
-			if (status)
-				rte_panic("%s (%" PRIu32
-					"): Error deleting TCP filter "
-					"(queue = %" PRIu32
-					", IP = 0x%" PRIx32
-					") (%" PRId32 ")\n",
-					p->name, p->pmd_id, p->tcp_local_q,
-					cp->ip, status);
-		}
-
-		/* UDP */
-		if (p->udp_local_q != 0) {
-			int status = app_link_filter_udp_del(p, cp);
-
-			APP_LOG(app, LOW, "%s (%" PRIu32
-				"): Deleting UDP filter "
-				"(queue = %" PRIu32 ", IP = 0x%" PRIx32 ")",
-				p->name, p->pmd_id, p->udp_local_q, cp->ip);
-
-			if (status)
-				rte_panic("%s (%" PRIu32
-					"): Error deleting UDP filter "
-					"(queue = %" PRIu32
-					", IP = 0x%" PRIx32
-					") (%" PRId32 ")\n",
-					p->name, p->pmd_id, p->udp_local_q,
-					cp->ip, status);
-		}
-
-		/* SCTP */
-		if (p->sctp_local_q != 0) {
-			int status = app_link_filter_sctp_del(p, cp);
-
-			APP_LOG(app, LOW, "%s (%" PRIu32
-				"): Deleting SCTP filter "
-				"(queue = %" PRIu32
-				", IP = 0x%" PRIx32 ")",
-				p->name, p->pmd_id, p->sctp_local_q, cp->ip);
-
-			if (status)
-				rte_panic("%s (%" PRIu32
-					"): Error deleting SCTP filter "
-					"(queue = %" PRIu32
-					", IP = 0x%" PRIx32
-					") (%" PRId32 ")\n",
-					p->name, p->pmd_id, p->sctp_local_q,
-					cp->ip, status);
-		}
-	}
-}
-
-static void
-app_check_link(struct app_params *app)
-{
-	uint32_t all_links_up, i;
-
-	all_links_up = 1;
-
-	for (i = 0; i < app->n_links; i++) {
-		struct app_link_params *p = &app->link_params[i];
-		struct rte_eth_link link_params;
-
-		memset(&link_params, 0, sizeof(link_params));
-		rte_eth_link_get(p->pmd_id, &link_params);
-
-		APP_LOG(app, HIGH, "%s (%" PRIu32 ") (%" PRIu32 " Gbps) %s",
-			p->name,
-			p->pmd_id,
-			link_params.link_speed / 1000,
-			link_params.link_status ? "UP" : "DOWN");
-
-		if (link_params.link_status == ETH_LINK_DOWN)
-			all_links_up = 0;
-	}
-
-	if (all_links_up == 0)
-		rte_panic("Some links are DOWN\n");
-}
-
-static uint32_t
-is_any_swq_frag_or_ras(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_pktq_swq; i++) {
-		struct app_pktq_swq_params *p = &app->swq_params[i];
-
-		if ((p->ipv4_frag == 1) || (p->ipv6_frag == 1) ||
-			(p->ipv4_ras == 1) || (p->ipv6_ras == 1))
-			return 1;
-	}
-
-	return 0;
-}
-
-static void
-app_init_link_frag_ras(struct app_params *app)
-{
-	uint32_t i;
-
-	if (is_any_swq_frag_or_ras(app)) {
-		for (i = 0; i < app->n_links; i++) {
-			struct app_link_params *p_link = &app->link_params[i];
-				p_link->conf.txmode.offloads |=
-						DEV_TX_OFFLOAD_MULTI_SEGS;
-		}
-	}
-}
-
-static inline int
-app_get_cpu_socket_id(uint32_t pmd_id)
-{
-	int status = rte_eth_dev_socket_id(pmd_id);
-
-	return (status != SOCKET_ID_ANY) ? status : 0;
-}
-
-static inline int
-app_link_rss_enabled(struct app_link_params *cp)
-{
-	return (cp->n_rss_qs) ? 1 : 0;
-}
-
-static void
-app_link_rss_setup(struct app_link_params *cp)
-{
-	struct rte_eth_dev_info dev_info;
-	struct rte_eth_rss_reta_entry64 reta_conf[APP_RETA_SIZE_MAX];
-	uint32_t i;
-	int status;
-
-    /* Get RETA size */
-	memset(&dev_info, 0, sizeof(dev_info));
-	rte_eth_dev_info_get(cp->pmd_id, &dev_info);
-
-	if (dev_info.reta_size == 0)
-		rte_panic("%s (%u): RSS setup error (null RETA size)\n",
-			cp->name, cp->pmd_id);
-
-	if (dev_info.reta_size > ETH_RSS_RETA_SIZE_512)
-		rte_panic("%s (%u): RSS setup error (RETA size too big)\n",
-			cp->name, cp->pmd_id);
-
-	/* Setup RETA contents */
-	memset(reta_conf, 0, sizeof(reta_conf));
-
-	for (i = 0; i < dev_info.reta_size; i++)
-		reta_conf[i / RTE_RETA_GROUP_SIZE].mask = UINT64_MAX;
-
-	for (i = 0; i < dev_info.reta_size; i++) {
-		uint32_t reta_id = i / RTE_RETA_GROUP_SIZE;
-		uint32_t reta_pos = i % RTE_RETA_GROUP_SIZE;
-		uint32_t rss_qs_pos = i % cp->n_rss_qs;
-
-		reta_conf[reta_id].reta[reta_pos] =
-			(uint16_t) cp->rss_qs[rss_qs_pos];
-	}
-
-	/* RETA update */
-	status = rte_eth_dev_rss_reta_update(cp->pmd_id,
-		reta_conf,
-		dev_info.reta_size);
-	if (status != 0)
-		rte_panic("%s (%u): RSS setup error (RETA update failed)\n",
-			cp->name, cp->pmd_id);
-}
-
-static void
-app_init_link_set_config(struct app_link_params *p)
-{
-	if (p->n_rss_qs) {
-		p->conf.rxmode.mq_mode = ETH_MQ_RX_RSS;
-		p->conf.rx_adv_conf.rss_conf.rss_hf = p->rss_proto_ipv4 |
-			p->rss_proto_ipv6 |
-			p->rss_proto_l2;
-	}
-}
-
-static void
-app_init_link(struct app_params *app)
-{
-	uint32_t i;
-
-	app_init_link_frag_ras(app);
-
-	for (i = 0; i < app->n_links; i++) {
-		struct app_link_params *p_link = &app->link_params[i];
-		struct rte_eth_dev_info dev_info;
-		uint32_t link_id, n_hwq_in, n_hwq_out, j;
-		int status;
-
-		sscanf(p_link->name, "LINK%" PRIu32, &link_id);
-		n_hwq_in = app_link_get_n_rxq(app, p_link);
-		n_hwq_out = app_link_get_n_txq(app, p_link);
-		app_init_link_set_config(p_link);
-
-		APP_LOG(app, HIGH, "Initializing %s (%" PRIu32") "
-			"(%" PRIu32 " RXQ, %" PRIu32 " TXQ) ...",
-			p_link->name,
-			p_link->pmd_id,
-			n_hwq_in,
-			n_hwq_out);
-
-		/* LINK */
-		rte_eth_dev_info_get(p_link->pmd_id, &dev_info);
-		if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE)
-			p_link->conf.txmode.offloads |=
-				DEV_TX_OFFLOAD_MBUF_FAST_FREE;
-		status = rte_eth_dev_configure(
-			p_link->pmd_id,
-			n_hwq_in,
-			n_hwq_out,
-			&p_link->conf);
-		if (status < 0)
-			rte_panic("%s (%" PRId32 "): "
-				"init error (%" PRId32 ")\n",
-				p_link->name, p_link->pmd_id, status);
-
-		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->n_pktq_hwq_in; j++) {
-			struct app_pktq_hwq_in_params *p_rxq =
-				&app->hwq_in_params[j];
-			uint32_t rxq_link_id, rxq_queue_id;
-			uint16_t nb_rxd = p_rxq->size;
-
-			sscanf(p_rxq->name, "RXQ%" PRIu32 ".%" PRIu32,
-				&rxq_link_id, &rxq_queue_id);
-			if (rxq_link_id != link_id)
-				continue;
-
-			status = rte_eth_dev_adjust_nb_rx_tx_desc(
-				p_link->pmd_id,
-				&nb_rxd,
-				NULL);
-			if (status < 0)
-				rte_panic("%s (%" PRIu32 "): "
-					"%s adjust number of Rx descriptors "
-					"error (%" PRId32 ")\n",
-					p_link->name,
-					p_link->pmd_id,
-					p_rxq->name,
-					status);
-
-			p_rxq->conf.offloads = p_link->conf.rxmode.offloads;
-			status = rte_eth_rx_queue_setup(
-				p_link->pmd_id,
-				rxq_queue_id,
-				nb_rxd,
-				app_get_cpu_socket_id(p_link->pmd_id),
-				&p_rxq->conf,
-				app->mempool[p_rxq->mempool_id]);
-			if (status < 0)
-				rte_panic("%s (%" PRIu32 "): "
-					"%s init error (%" PRId32 ")\n",
-					p_link->name,
-					p_link->pmd_id,
-					p_rxq->name,
-					status);
-		}
-
-		/* TXQ */
-		for (j = 0; j < app->n_pktq_hwq_out; j++) {
-			struct app_pktq_hwq_out_params *p_txq =
-				&app->hwq_out_params[j];
-			uint32_t txq_link_id, txq_queue_id;
-			uint16_t nb_txd = p_txq->size;
-
-			sscanf(p_txq->name, "TXQ%" PRIu32 ".%" PRIu32,
-				&txq_link_id, &txq_queue_id);
-			if (txq_link_id != link_id)
-				continue;
-
-			status = rte_eth_dev_adjust_nb_rx_tx_desc(
-				p_link->pmd_id,
-				NULL,
-				&nb_txd);
-			if (status < 0)
-				rte_panic("%s (%" PRIu32 "): "
-					"%s adjust number of Tx descriptors "
-					"error (%" PRId32 ")\n",
-					p_link->name,
-					p_link->pmd_id,
-					p_txq->name,
-					status);
-
-			p_txq->conf.offloads = p_link->conf.txmode.offloads;
-			status = rte_eth_tx_queue_setup(
-				p_link->pmd_id,
-				txq_queue_id,
-				nb_txd,
-				app_get_cpu_socket_id(p_link->pmd_id),
-				&p_txq->conf);
-			if (status < 0)
-				rte_panic("%s (%" PRIu32 "): "
-					"%s init error (%" PRId32 ")\n",
-					p_link->name,
-					p_link->pmd_id,
-					p_txq->name,
-					status);
-		}
-
-		/* LINK START */
-		status = rte_eth_dev_start(p_link->pmd_id);
-		if (status < 0)
-			rte_panic("Cannot start %s (error %" PRId32 ")\n",
-				p_link->name, status);
-
-		/* LINK FILTERS */
-		app_link_set_arp_filter(app, p_link);
-		app_link_set_tcp_syn_filter(app, p_link);
-		if (app_link_rss_enabled(p_link))
-			app_link_rss_setup(p_link);
-
-		/* LINK UP */
-		app_link_up_internal(app, p_link);
-	}
-
-	app_check_link(app);
-}
-
-static void
-app_init_swq(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_pktq_swq; i++) {
-		struct app_pktq_swq_params *p = &app->swq_params[i];
-		unsigned flags = 0;
-
-		if (app_swq_get_readers(app, p) == 1)
-			flags |= RING_F_SC_DEQ;
-		if (app_swq_get_writers(app, p) == 1)
-			flags |= RING_F_SP_ENQ;
-
-		APP_LOG(app, HIGH, "Initializing %s...", p->name);
-		app->swq[i] = rte_ring_create(
-				p->name,
-				p->size,
-				p->cpu_socket_id,
-				flags);
-
-		if (app->swq[i] == NULL)
-			rte_panic("%s init error\n", p->name);
-	}
-}
-
-static void
-app_init_tm(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_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;
-
-		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 =
-			app_get_cpu_socket_id(p_link->pmd_id);
-		p_tm->sched_port_params.rate =
-			(uint64_t) link_eth_params.link_speed * 1000 * 1000 / 8;
-
-		APP_LOG(app, HIGH, "Initializing %s ...", p_tm->name);
-		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 %" PRIu32
-					" init error (%" PRId32 ")\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 %" PRIu32
-						" pipe %" PRIu32
-						" (profile %" PRId32 ") "
-						"init error (% " PRId32 ")\n",
-						p_tm->name, subport_id, pipe_id,
-						profile_id, status);
-			}
-		}
-	}
-}
-
-#ifndef RTE_EXEC_ENV_LINUXAPP
-static void
-app_init_tap(struct app_params *app) {
-	if (app->n_pktq_tap == 0)
-		return;
-
-	rte_panic("TAP device not supported.\n");
-}
-#else
-static void
-app_init_tap(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_pktq_tap; i++) {
-		struct app_pktq_tap_params *p_tap = &app->tap_params[i];
-		struct ifreq ifr;
-		int fd, status;
-
-		APP_LOG(app, HIGH, "Initializing %s ...", p_tap->name);
-
-		fd = open("/dev/net/tun", O_RDWR | O_NONBLOCK);
-		if (fd < 0)
-			rte_panic("Cannot open file /dev/net/tun\n");
-
-		memset(&ifr, 0, sizeof(ifr));
-		ifr.ifr_flags = IFF_TAP | IFF_NO_PI; /* No packet information */
-		snprintf(ifr.ifr_name, IFNAMSIZ, "%s", p_tap->name);
-
-		status = ioctl(fd, TUNSETIFF, (void *) &ifr);
-		if (status < 0)
-			rte_panic("TAP setup error\n");
-
-		app->tap[i] = fd;
-	}
-}
-#endif
-
-#ifdef RTE_LIBRTE_KNI
-static int
-kni_config_network_interface(uint16_t port_id, uint8_t if_up) {
-	int ret = 0;
-
-	if (port_id >= rte_eth_dev_count())
-		return -EINVAL;
-
-	ret = (if_up) ?
-		rte_eth_dev_set_link_up(port_id) :
-		rte_eth_dev_set_link_down(port_id);
-
-	return ret;
-}
-
-static int
-kni_change_mtu(uint16_t port_id, unsigned int new_mtu) {
-	int ret;
-
-	if (port_id >= rte_eth_dev_count())
-		return -EINVAL;
-
-	if (new_mtu > ETHER_MAX_LEN)
-		return -EINVAL;
-
-	/* Set new MTU */
-	ret = rte_eth_dev_set_mtu(port_id, new_mtu);
-	if (ret < 0)
-		return ret;
-
-	return 0;
-}
-#endif /* RTE_LIBRTE_KNI */
-
-#ifndef RTE_LIBRTE_KNI
-static void
-app_init_kni(struct app_params *app) {
-	if (app->n_pktq_kni == 0)
-		return;
-
-	rte_panic("Can not init KNI without librte_kni support.\n");
-}
-#else
-static void
-app_init_kni(struct app_params *app) {
-	uint32_t i;
-
-	if (app->n_pktq_kni == 0)
-		return;
-
-	rte_kni_init(app->n_pktq_kni);
-
-	for (i = 0; i < app->n_pktq_kni; i++) {
-		struct app_pktq_kni_params *p_kni = &app->kni_params[i];
-		struct app_link_params *p_link;
-		struct rte_eth_dev_info dev_info;
-		struct app_mempool_params *mempool_params;
-		struct rte_mempool *mempool;
-		struct rte_kni_conf conf;
-		struct rte_kni_ops ops;
-
-		/* LINK */
-		p_link = app_get_link_for_kni(app, p_kni);
-		memset(&dev_info, 0, sizeof(dev_info));
-		rte_eth_dev_info_get(p_link->pmd_id, &dev_info);
-
-		/* MEMPOOL */
-		mempool_params = &app->mempool_params[p_kni->mempool_id];
-		mempool = app->mempool[p_kni->mempool_id];
-
-		/* KNI */
-		memset(&conf, 0, sizeof(conf));
-		snprintf(conf.name, RTE_KNI_NAMESIZE, "%s", p_kni->name);
-		conf.force_bind = p_kni->force_bind;
-		if (conf.force_bind) {
-			int lcore_id;
-
-			lcore_id = cpu_core_map_get_lcore_id(app->core_map,
-				p_kni->socket_id,
-				p_kni->core_id,
-				p_kni->hyper_th_id);
-
-			if (lcore_id < 0)
-				rte_panic("%s invalid CPU core\n", p_kni->name);
-
-			conf.core_id = (uint32_t) lcore_id;
-		}
-		conf.group_id = p_link->pmd_id;
-		conf.mbuf_size = mempool_params->buffer_size;
-		conf.addr = dev_info.pci_dev->addr;
-		conf.id = dev_info.pci_dev->id;
-
-		memset(&ops, 0, sizeof(ops));
-		ops.port_id = (uint8_t) p_link->pmd_id;
-		ops.change_mtu = kni_change_mtu;
-		ops.config_network_if = kni_config_network_interface;
-
-		APP_LOG(app, HIGH, "Initializing %s ...", p_kni->name);
-		app->kni[i] = rte_kni_alloc(mempool, &conf, &ops);
-		if (!app->kni[i])
-			rte_panic("%s init error\n", p_kni->name);
-	}
-}
-#endif /* RTE_LIBRTE_KNI */
-
-static void
-app_init_msgq(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_msgq; i++) {
-		struct app_msgq_params *p = &app->msgq_params[i];
-
-		APP_LOG(app, HIGH, "Initializing %s ...", 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);
-	}
-}
-
-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_tap(app);
-	app_init_kni(app);
-	app_init_msgq(app);
-
-	return 0;
-}
diff --git a/examples/ip_pipeline/main.c b/examples/ip_pipeline/main.c
index a44cf9a..1696e36 100644
--- a/examples/ip_pipeline/main.c
+++ b/examples/ip_pipeline/main.c
@@ -2,34 +2,24 @@
  * Copyright(c) 2010-2015 Intel Corporation
  */
 
-#include "app.h"
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <getopt.h>
 
-static struct app_params app;
+#include <rte_eal.h>
 
 int
 main(int argc, char **argv)
 {
-	rte_openlog_stream(stderr);
+	int status;
 
-	/* Config */
-	app_config_init(&app);
+	/* EAL */
+	status = rte_eal_init(argc, argv);
+	if (status < 0) {
+		printf("Error: EAL initialization failed (%d)\n", status);
+		return status;
+	};
 
-	app_config_args(&app, argc, argv);
-
-	app_config_preproc(&app);
-
-	app_config_parse(&app, app.parser_file);
-
-	app_config_check(&app);
-
-	/* 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/meson.build b/examples/ip_pipeline/meson.build
index be3f3e5..063865c 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -1,19 +1,13 @@
 # SPDX-License-Identifier: BSD-3-Clause
-# Copyright(c) 2017 Intel Corporation
+# Copyright(c) 2017-2018 Intel Corporation
 
 # meson file, for building this example as part of a main DPDK build.
 #
 # To build this example as a standalone application with an already-installed
 # DPDK instance, use 'make'
 
-deps += ['cfgfile', 'bus_pci']
+deps += ['pipeline', 'bus_pci']
 sources = files(
-	'config_check.c',
-	'config_parse.c',
-	'config_parse_tm.c',
-	'cpu_core_map.c',
-	'init.c',
 	'main.c',
 	'parser.c',
-	'thread.c',
 )
diff --git a/examples/ip_pipeline/parser.c b/examples/ip_pipeline/parser.c
index 0901e9c..0ae3d1d 100644
--- a/examples/ip_pipeline/parser.c
+++ b/examples/ip_pipeline/parser.c
@@ -39,7 +39,6 @@
 #include <rte_cfgfile.h>
 #include <rte_string_fns.h>
 
-#include "app.h"
 #include "parser.h"
 
 static uint32_t
@@ -596,10 +595,8 @@ parse_mac_addr(const char *token, struct ether_addr *addr)
 }
 
 int
-parse_pipeline_core(uint32_t *socket,
-	uint32_t *core,
-	uint32_t *ht,
-	const char *entry)
+parse_cpu_core(const char *entry,
+	struct cpu_core_params *p)
 {
 	size_t num_len;
 	char num[8];
@@ -609,6 +606,9 @@ parse_pipeline_core(uint32_t *socket,
 	const char *next = skip_white_spaces(entry);
 	char type;
 
+	if (p == NULL)
+		return -EINVAL;
+
 	/* Expect <CORE> or [sX][cY][h]. At least one parameter is required. */
 	while (*next != '\0') {
 		/* If everything parsed nothing should left */
@@ -682,8 +682,8 @@ parse_pipeline_core(uint32_t *socket,
 		}
 	}
 
-	*socket = s;
-	*core = c;
-	*ht = h;
+	p->socket_id = s;
+	p->core_id = c;
+	p->thread_id = h;
 	return 0;
 }
diff --git a/examples/ip_pipeline/parser.h b/examples/ip_pipeline/parser.h
index 5c421d2..261a8c8 100644
--- a/examples/ip_pipeline/parser.h
+++ b/examples/ip_pipeline/parser.h
@@ -50,6 +50,14 @@ int parse_ipv6_addr(const char *token, struct in6_addr *ipv6);
 int parse_mac_addr(const char *token, struct ether_addr *addr);
 int parse_mpls_labels(char *string, uint32_t *labels, uint32_t *n_labels);
 
+struct cpu_core_params {
+	uint32_t socket_id;
+	uint32_t core_id;
+	uint32_t thread_id;
+};
+
+int parse_cpu_core(const char *entry, struct cpu_core_params *p);
+
 int parse_tokenize_string(char *string, char *tokens[], uint32_t *n_tokens);
 
 #endif
diff --git a/examples/ip_pipeline/pipeline.h b/examples/ip_pipeline/pipeline.h
deleted file mode 100644
index 7ca9cad..0000000
--- a/examples/ip_pipeline/pipeline.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#ifndef __INCLUDE_PIPELINE_H__
-#define __INCLUDE_PIPELINE_H__
-
-#include <cmdline_parse.h>
-
-#include "pipeline_be.h"
-
-/*
- * Pipeline type front-end operations
- */
-
-typedef void* (*pipeline_fe_op_init)(struct pipeline_params *params,
-	void *arg);
-
-typedef int (*pipeline_fe_op_post_init)(void *pipeline);
-
-typedef int (*pipeline_fe_op_free)(void *pipeline);
-
-typedef int (*pipeline_fe_op_track)(struct pipeline_params *params,
-	uint32_t port_in,
-	uint32_t *port_out);
-
-struct pipeline_fe_ops {
-	pipeline_fe_op_init f_init;
-	pipeline_fe_op_post_init f_post_init;
-	pipeline_fe_op_free f_free;
-	pipeline_fe_op_track f_track;
-	cmdline_parse_ctx_t *cmds;
-};
-
-/*
- * Pipeline type
- */
-
-struct pipeline_type {
-	const char *name;
-
-	/* pipeline back-end */
-	struct pipeline_be_ops *be_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;
-}
-
-int
-parse_pipeline_core(uint32_t *socket,
-	uint32_t *core,
-	uint32_t *ht,
-	const char *entry);
-
-#endif
diff --git a/examples/ip_pipeline/pipeline_be.h b/examples/ip_pipeline/pipeline_be.h
deleted file mode 100644
index 6c0c97a..0000000
--- a/examples/ip_pipeline/pipeline_be.h
+++ /dev/null
@@ -1,322 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2016 Intel Corporation
- */
-
-#ifndef __INCLUDE_PIPELINE_BE_H__
-#define __INCLUDE_PIPELINE_BE_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_fd.h>
-#include <rte_port_source_sink.h>
-#ifdef RTE_LIBRTE_KNI
-#include <rte_port_kni.h>
-#endif
-#include <rte_pipeline.h>
-
-enum pipeline_port_in_type {
-	PIPELINE_PORT_IN_ETHDEV_READER,
-	PIPELINE_PORT_IN_RING_READER,
-	PIPELINE_PORT_IN_RING_MULTI_READER,
-	PIPELINE_PORT_IN_RING_READER_IPV4_FRAG,
-	PIPELINE_PORT_IN_RING_READER_IPV6_FRAG,
-	PIPELINE_PORT_IN_SCHED_READER,
-	PIPELINE_PORT_IN_FD_READER,
-	PIPELINE_PORT_IN_KNI_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_multi_reader_params ring_multi;
-		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_fd_reader_params fd;
-#ifdef RTE_LIBRTE_KNI
-		struct rte_port_kni_reader_params kni;
-#endif
-		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_MULTI_READER:
-		return (void *) &p->params.ring_multi;
-	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_FD_READER:
-		return (void *) &p->params.fd;
-#ifdef RTE_LIBRTE_KNI
-	case PIPELINE_PORT_IN_KNI_READER:
-		return (void *) &p->params.kni;
-#endif
-	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_MULTI_READER:
-		return &rte_port_ring_multi_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_FD_READER:
-		return &rte_port_fd_reader_ops;
-#ifdef RTE_LIBRTE_KNI
-	case PIPELINE_PORT_IN_KNI_READER:
-		return &rte_port_kni_reader_ops;
-#endif
-	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_MULTI_WRITER,
-	PIPELINE_PORT_OUT_RING_WRITER_NODROP,
-	PIPELINE_PORT_OUT_RING_MULTI_WRITER_NODROP,
-	PIPELINE_PORT_OUT_RING_WRITER_IPV4_RAS,
-	PIPELINE_PORT_OUT_RING_WRITER_IPV6_RAS,
-	PIPELINE_PORT_OUT_SCHED_WRITER,
-	PIPELINE_PORT_OUT_FD_WRITER,
-	PIPELINE_PORT_OUT_KNI_WRITER,
-	PIPELINE_PORT_OUT_KNI_WRITER_NODROP,
-	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_multi_writer_params ring_multi;
-		struct rte_port_ring_writer_nodrop_params ring_nodrop;
-		struct rte_port_ring_multi_writer_nodrop_params ring_multi_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;
-		struct rte_port_fd_writer_params fd;
-#ifdef RTE_LIBRTE_KNI
-		struct rte_port_kni_writer_params kni;
-		struct rte_port_kni_writer_nodrop_params kni_nodrop;
-#endif
-		struct rte_port_sink_params sink;
-	} 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_MULTI_WRITER:
-		return (void *) &p->params.ring_multi;
-	case PIPELINE_PORT_OUT_RING_WRITER_NODROP:
-		return (void *) &p->params.ring_nodrop;
-	case PIPELINE_PORT_OUT_RING_MULTI_WRITER_NODROP:
-		return (void *) &p->params.ring_multi_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_FD_WRITER:
-		return (void *) &p->params.fd;
-#ifdef RTE_LIBRTE_KNI
-	case PIPELINE_PORT_OUT_KNI_WRITER:
-		return (void *) &p->params.kni;
-	case PIPELINE_PORT_OUT_KNI_WRITER_NODROP:
-		return (void *) &p->params.kni_nodrop;
-#endif
-	case PIPELINE_PORT_OUT_SINK:
-		return (void *) &p->params.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_MULTI_WRITER:
-		return &rte_port_ring_multi_writer_ops;
-	case PIPELINE_PORT_OUT_RING_WRITER_NODROP:
-		return &rte_port_ring_writer_nodrop_ops;
-	case PIPELINE_PORT_OUT_RING_MULTI_WRITER_NODROP:
-		return &rte_port_ring_multi_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_FD_WRITER:
-		return &rte_port_fd_writer_ops;
-#ifdef RTE_LIBRTE_KNI
-	case PIPELINE_PORT_OUT_KNI_WRITER:
-		return &rte_port_kni_writer_ops;
-	case PIPELINE_PORT_OUT_KNI_WRITER_NODROP:
-		return &rte_port_kni_writer_nodrop_ops;
-#endif
-	case PIPELINE_PORT_OUT_SINK:
-		return &rte_port_sink_ops;
-	default:
-		return NULL;
-	}
-}
-
-#ifndef PIPELINE_NAME_SIZE
-#define PIPELINE_NAME_SIZE                       64
-#endif
-
-#ifndef PIPELINE_TYPE_SIZE
-#define PIPELINE_TYPE_SIZE                       64
-#endif
-
-#ifndef PIPELINE_MAX_PORT_IN
-#define PIPELINE_MAX_PORT_IN                     64
-#endif
-
-#ifndef PIPELINE_MAX_PORT_OUT
-#define PIPELINE_MAX_PORT_OUT                    64
-#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                        64
-#endif
-
-struct pipeline_params {
-	char name[PIPELINE_NAME_SIZE];
-	char type[PIPELINE_TYPE_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;
-
-	uint32_t log_level;
-};
-
-/*
- * Pipeline type back-end operations
- */
-
-typedef void* (*pipeline_be_op_init)(struct pipeline_params *params,
-	void *arg);
-
-typedef int (*pipeline_be_op_free)(void *pipeline);
-
-typedef int (*pipeline_be_op_run)(void *pipeline);
-
-typedef int (*pipeline_be_op_timer)(void *pipeline);
-
-struct pipeline_be_ops {
-	pipeline_be_op_init f_init;
-	pipeline_be_op_free f_free;
-	pipeline_be_op_run f_run;
-	pipeline_be_op_timer f_timer;
-};
-
-/* Pipeline specific config parse error messages */
-#define PIPELINE_ARG_CHECK(exp, fmt, ...)				\
-do {									\
-	if (!(exp)) {							\
-		fprintf(stderr, fmt "\n", ## __VA_ARGS__);		\
-		return -1;						\
-	}								\
-} while (0)
-
-#define PIPELINE_PARSE_ERR_INV_VAL(exp, section, entry, val)		\
-PIPELINE_ARG_CHECK(exp, "Parse error in section \"%s\": entry \"%s\" "	\
-	"has invalid value (\"%s\")", section, entry, val)
-
-#define PIPELINE_PARSE_ERR_OUT_RNG(exp, section, entry, val)		\
-PIPELINE_ARG_CHECK(exp, "Parse error in section \"%s\": entry \"%s\" "	\
-	"value is out of range (\"%s\")", section, entry, val)
-
-#define PIPELINE_PARSE_ERR_DUPLICATE(exp, section, entry)		\
-PIPELINE_ARG_CHECK(exp, "Parse error in section \"%s\": duplicated "	\
-	"entry \"%s\"", section, entry)
-
-#define PIPELINE_PARSE_ERR_INV_ENT(exp, section, entry)			\
-PIPELINE_ARG_CHECK(exp, "Parse error in section \"%s\": invalid entry "	\
-	"\"%s\"", section, entry)
-
-#define PIPELINE_PARSE_ERR_MANDATORY(exp, section, entry)		\
-PIPELINE_ARG_CHECK(exp, "Parse error in section \"%s\": mandatory "	\
-	"entry \"%s\" is missing", section, entry)
-
-#endif
diff --git a/examples/ip_pipeline/thread.c b/examples/ip_pipeline/thread.c
deleted file mode 100644
index a36bf92..0000000
--- a/examples/ip_pipeline/thread.c
+++ /dev/null
@@ -1,240 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#include <rte_common.h>
-#include <rte_cycles.h>
-#include <rte_pipeline.h>
-
-#include "app.h"
-#include "thread.h"
-
-static inline void *
-thread_msg_recv(struct rte_ring *r)
-{
-	void *msg;
-	int status = rte_ring_sc_dequeue(r, &msg);
-
-	if (status != 0)
-		return NULL;
-
-	return msg;
-}
-
-static inline void
-thread_msg_send(struct rte_ring *r,
-	void *msg)
-{
-	int status;
-
-	do {
-		status = rte_ring_sp_enqueue(r, msg);
-	} while (status == -ENOBUFS);
-}
-
-static int
-thread_pipeline_enable(struct app_thread_data *t,
-		struct thread_pipeline_enable_msg_req *req)
-{
-	struct app_thread_pipeline_data *p;
-
-	if (req->f_run == NULL) {
-		if (t->n_regular >= APP_MAX_THREAD_PIPELINES)
-			return -1;
-	} else {
-		if (t->n_custom >= APP_MAX_THREAD_PIPELINES)
-			return -1;
-	}
-
-	p = (req->f_run == NULL) ?
-		&t->regular[t->n_regular] :
-		&t->custom[t->n_custom];
-
-	p->pipeline_id = req->pipeline_id;
-	p->be = req->be;
-	p->f_run = req->f_run;
-	p->f_timer = req->f_timer;
-	p->timer_period = req->timer_period;
-	p->deadline = 0;
-
-	if (req->f_run == NULL)
-		t->n_regular++;
-	else
-		t->n_custom++;
-
-	return 0;
-}
-
-static int
-thread_pipeline_disable(struct app_thread_data *t,
-		struct thread_pipeline_disable_msg_req *req)
-{
-	uint32_t n_regular = RTE_MIN(t->n_regular, RTE_DIM(t->regular));
-	uint32_t n_custom = RTE_MIN(t->n_custom, RTE_DIM(t->custom));
-	uint32_t i;
-
-	/* search regular pipelines of current thread */
-	for (i = 0; i < n_regular; i++) {
-		if (t->regular[i].pipeline_id != req->pipeline_id)
-			continue;
-
-		if (i < n_regular - 1)
-			memcpy(&t->regular[i],
-			  &t->regular[i+1],
-			  (n_regular - 1 - i) * sizeof(struct app_thread_pipeline_data));
-
-		n_regular--;
-		t->n_regular = n_regular;
-
-		return 0;
-	}
-
-	/* search custom pipelines of current thread */
-	for (i = 0; i < n_custom; i++) {
-		if (t->custom[i].pipeline_id != req->pipeline_id)
-			continue;
-
-		if (i < n_custom - 1)
-			memcpy(&t->custom[i],
-			  &t->custom[i+1],
-			  (n_custom - 1 - i) * sizeof(struct app_thread_pipeline_data));
-
-		n_custom--;
-		t->n_custom = n_custom;
-
-		return 0;
-	}
-
-	/* return if pipeline not found */
-	return -1;
-}
-
-static int
-thread_msg_req_handle(struct app_thread_data *t)
-{
-	void *msg_ptr;
-	struct thread_msg_req *req;
-	struct thread_msg_rsp *rsp;
-
-	msg_ptr = thread_msg_recv(t->msgq_in);
-	req = msg_ptr;
-	rsp = msg_ptr;
-
-	if (req != NULL)
-		switch (req->type) {
-		case THREAD_MSG_REQ_PIPELINE_ENABLE: {
-			rsp->status = thread_pipeline_enable(t,
-					(struct thread_pipeline_enable_msg_req *) req);
-			thread_msg_send(t->msgq_out, rsp);
-			break;
-		}
-
-		case THREAD_MSG_REQ_PIPELINE_DISABLE: {
-			rsp->status = thread_pipeline_disable(t,
-					(struct thread_pipeline_disable_msg_req *) req);
-			thread_msg_send(t->msgq_out, rsp);
-			break;
-		}
-
-		case THREAD_MSG_REQ_HEADROOM_READ: {
-			struct thread_headroom_read_msg_rsp *rsp =
-				(struct thread_headroom_read_msg_rsp *)
-				req;
-
-			rsp->headroom_ratio = t->headroom_ratio;
-			rsp->status = 0;
-			thread_msg_send(t->msgq_out, rsp);
-			break;
-		}
-		default:
-			break;
-		}
-
-	return 0;
-}
-
-static void
-thread_headroom_update(struct app_thread_data *t, uint64_t time)
-{
-	uint64_t time_diff = time - t->headroom_time;
-
-	t->headroom_ratio =
-		((double) t->headroom_cycles) / ((double) time_diff);
-
-	t->headroom_cycles = 0;
-	t->headroom_time = rte_rdtsc_precise();
-}
-
-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++) {
-		uint32_t n_regular = RTE_MIN(t->n_regular, RTE_DIM(t->regular));
-		uint32_t n_custom = RTE_MIN(t->n_custom, RTE_DIM(t->custom));
-
-		/* 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 < 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 < 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;
-			}
-
-			/* Timer for thread message request */
-			{
-				uint64_t deadline = t->thread_req_deadline;
-
-				if (deadline <= time) {
-					thread_msg_req_handle(t);
-					thread_headroom_update(t, time);
-					deadline = time + t->timer_period;
-					t->thread_req_deadline = deadline;
-				}
-
-				if (deadline < t_deadline)
-					t_deadline = deadline;
-			}
-
-
-			t->deadline = t_deadline;
-		}
-	}
-
-	return 0;
-}
diff --git a/examples/ip_pipeline/thread.h b/examples/ip_pipeline/thread.h
deleted file mode 100644
index 2c4fb6a..0000000
--- a/examples/ip_pipeline/thread.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#ifndef THREAD_H_
-#define THREAD_H_
-
-#include "app.h"
-#include "pipeline_be.h"
-
-enum thread_msg_req_type {
-	THREAD_MSG_REQ_PIPELINE_ENABLE = 0,
-	THREAD_MSG_REQ_PIPELINE_DISABLE,
-	THREAD_MSG_REQ_HEADROOM_READ,
-	THREAD_MSG_REQS
-};
-
-struct thread_msg_req {
-	enum thread_msg_req_type type;
-};
-
-struct thread_msg_rsp {
-	int status;
-};
-
-/*
- * PIPELINE ENABLE
- */
-struct thread_pipeline_enable_msg_req {
-	enum thread_msg_req_type type;
-
-	uint32_t pipeline_id;
-	void *be;
-	pipeline_be_op_run f_run;
-	pipeline_be_op_timer f_timer;
-	uint64_t timer_period;
-};
-
-struct thread_pipeline_enable_msg_rsp {
-	int status;
-};
-
-/*
- * PIPELINE DISABLE
- */
-struct thread_pipeline_disable_msg_req {
-	enum thread_msg_req_type type;
-
-	uint32_t pipeline_id;
-};
-
-struct thread_pipeline_disable_msg_rsp {
-	int status;
-};
-
-/*
- * THREAD HEADROOM
- */
-struct thread_headroom_read_msg_req {
-	enum thread_msg_req_type type;
-};
-
-struct thread_headroom_read_msg_rsp {
-	int status;
-
-	double headroom_ratio;
-};
-
-#endif /* THREAD_H_ */
-- 
2.9.3

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

* [dpdk-dev] [PATCH v3 18/44] ip_pipeline: add cli interface
  2018-03-16 17:58       ` [dpdk-dev] [PATCH v3 00/44] ip_pipeline: refactoring Jasvinder Singh
                           ` (16 preceding siblings ...)
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 17/44] ip_pipeline: rework and improvements Jasvinder Singh
@ 2018-03-16 17:58         ` Jasvinder Singh
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 19/44] ip_pipeline: add mempool object for pipeline Jasvinder Singh
                           ` (25 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-16 17:58 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

CLI interface allowing connectivity with external agent(e.g. telnet,
netcat, Python script, etc) is added to the application.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/Makefile    |   4 +-
 examples/ip_pipeline/cli.c       |  85 ++++++++++
 examples/ip_pipeline/cli.h       |  18 +++
 examples/ip_pipeline/conn.c      | 326 +++++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/conn.h      |  47 ++++++
 examples/ip_pipeline/main.c      | 151 +++++++++++++++++-
 examples/ip_pipeline/meson.build |   2 +
 7 files changed, 631 insertions(+), 2 deletions(-)
 create mode 100644 examples/ip_pipeline/cli.c
 create mode 100644 examples/ip_pipeline/cli.h
 create mode 100644 examples/ip_pipeline/conn.c
 create mode 100644 examples/ip_pipeline/conn.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index 981c4f7..0c5b6b1 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -5,7 +5,9 @@
 APP = ip_pipeline
 
 # all source are stored in SRCS-y
-SRCS-y := main.c
+SRCS-y := cli.c
+SRCS-y += conn.c
+SRCS-y += main.c
 SRCS-y += parser.c
 #SRCS-y += thread.c
 
diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
new file mode 100644
index 0000000..3e97b29
--- /dev/null
+++ b/examples/ip_pipeline/cli.c
@@ -0,0 +1,85 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <rte_common.h>
+
+#include "cli.h"
+
+static int
+is_comment(char *in)
+{
+	if ((strlen(in) && index("!#%;", in[0])) ||
+		(strncmp(in, "//", 2) == 0) ||
+		(strncmp(in, "--", 2) == 0))
+		return 1;
+
+	return 0;
+}
+
+void
+cli_process(char *in, char *out __rte_unused, size_t out_size __rte_unused)
+{
+	if (is_comment(in))
+		return;
+
+}
+
+int
+cli_script_process(const char *file_name,
+	size_t msg_in_len_max,
+	size_t msg_out_len_max)
+{
+	char *msg_in = NULL, *msg_out = NULL;
+	FILE *f = NULL;
+
+	/* Check input arguments */
+	if ((file_name == NULL) ||
+		(strlen(file_name) == 0) ||
+		(msg_in_len_max == 0) ||
+		(msg_out_len_max == 0))
+		return -EINVAL;
+
+	msg_in = malloc(msg_in_len_max + 1);
+	msg_out = malloc(msg_out_len_max + 1);
+	if ((msg_in == NULL) ||
+		(msg_out == NULL)) {
+		free(msg_out);
+		free(msg_in);
+		return -ENOMEM;
+	}
+
+	/* Open input file */
+	f = fopen(file_name, "r");
+	if (f == NULL) {
+		free(msg_out);
+		free(msg_in);
+		return -EIO;
+	}
+
+	/* Read file */
+	for ( ; ; ) {
+		if (fgets(msg_in, msg_in_len_max + 1, f) == NULL)
+			break;
+
+		printf("%s", msg_in);
+
+		cli_process(msg_in,
+			msg_out,
+			msg_out_len_max);
+
+		if (strlen(msg_out))
+			printf("%s", msg_out);
+	}
+
+	/* Close file */
+	fclose(f);
+	free(msg_out);
+	free(msg_in);
+	return 0;
+}
diff --git a/examples/ip_pipeline/cli.h b/examples/ip_pipeline/cli.h
new file mode 100644
index 0000000..992e4c3
--- /dev/null
+++ b/examples/ip_pipeline/cli.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#ifndef __INCLUDE_CLI_H__
+#define __INCLUDE_CLI_H__
+
+#include <stddef.h>
+
+void
+cli_process(char *in, char *out, size_t out_size);
+
+int
+cli_script_process(const char *file_name,
+	size_t msg_in_len_max,
+	size_t msg_out_len_max);
+
+#endif
diff --git a/examples/ip_pipeline/conn.c b/examples/ip_pipeline/conn.c
new file mode 100644
index 0000000..2a9fa15
--- /dev/null
+++ b/examples/ip_pipeline/conn.c
@@ -0,0 +1,326 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+#define __USE_GNU
+#include <sys/socket.h>
+
+#include <sys/epoll.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <errno.h>
+
+#include "conn.h"
+
+#define MSG_CMD_TOO_LONG "Command too long."
+
+struct conn {
+	char *welcome;
+	char *prompt;
+	char *buf;
+	char *msg_in;
+	char *msg_out;
+	size_t buf_size;
+	size_t msg_in_len_max;
+	size_t msg_out_len_max;
+	size_t msg_in_len;
+	int fd_server;
+	int fd_client_group;
+	conn_msg_handle_t msg_handle;
+};
+
+struct conn *
+conn_init(struct conn_params *p)
+{
+	struct sockaddr_in server_address;
+	struct conn *conn;
+	int fd_server, fd_client_group, status;
+
+	memset(&server_address, 0, sizeof(server_address));
+
+	/* Check input arguments */
+	if ((p == NULL) ||
+		(p->welcome == NULL) ||
+		(p->prompt == NULL) ||
+		(p->addr == NULL) ||
+		(p->buf_size == 0) ||
+		(p->msg_in_len_max == 0) ||
+		(p->msg_out_len_max == 0) ||
+		(p->msg_handle == NULL))
+		return NULL;
+
+	status = inet_aton(p->addr, &server_address.sin_addr);
+	if (status == 0)
+		return NULL;
+
+	/* Memory allocation */
+	conn = calloc(1, sizeof(struct conn));
+	if (conn == NULL)
+		return NULL;
+
+	conn->welcome = calloc(1, CONN_WELCOME_LEN_MAX + 1);
+	conn->prompt = calloc(1, CONN_PROMPT_LEN_MAX + 1);
+	conn->buf = calloc(1, p->buf_size);
+	conn->msg_in = calloc(1, p->msg_in_len_max + 1);
+	conn->msg_out = calloc(1, p->msg_out_len_max + 1);
+
+	if ((conn->welcome == NULL) ||
+		(conn->prompt == NULL) ||
+		(conn->buf == NULL) ||
+		(conn->msg_in == NULL) ||
+		(conn->msg_out == NULL)) {
+		conn_free(conn);
+		return NULL;
+	}
+
+	/* Server socket */
+	server_address.sin_family = AF_INET;
+	server_address.sin_port = htons(p->port);
+
+	fd_server = socket(AF_INET,
+		SOCK_STREAM | SOCK_NONBLOCK,
+		0);
+	if (fd_server == -1) {
+		conn_free(conn);
+		return NULL;
+	}
+
+	status = bind(fd_server,
+		(struct sockaddr *) &server_address,
+		sizeof(server_address));
+	if (status == -1) {
+		conn_free(conn);
+		return NULL;
+	}
+
+	status = listen(fd_server, 16);
+	if (status == -1) {
+		conn_free(conn);
+		return NULL;
+	}
+
+	/* Client group */
+	fd_client_group = epoll_create(1);
+	if (fd_client_group == -1) {
+		conn_free(conn);
+		return NULL;
+	}
+
+	/* Fill in */
+	strncpy(conn->welcome, p->welcome, CONN_WELCOME_LEN_MAX);
+	strncpy(conn->prompt, p->prompt, CONN_PROMPT_LEN_MAX);
+	conn->buf_size = p->buf_size;
+	conn->msg_in_len_max = p->msg_in_len_max;
+	conn->msg_out_len_max = p->msg_out_len_max;
+	conn->msg_in_len = 0;
+	conn->fd_server = fd_server;
+	conn->fd_client_group = fd_client_group;
+	conn->msg_handle = p->msg_handle;
+
+	return conn;
+}
+
+void
+conn_free(struct conn *conn)
+{
+	if (conn == NULL)
+		return;
+
+	if (conn->fd_client_group)
+		close(conn->fd_client_group);
+
+	if (conn->fd_server)
+		close(conn->fd_server);
+
+	free(conn->msg_out);
+	free(conn->msg_in);
+	free(conn->prompt);
+	free(conn->welcome);
+	free(conn);
+}
+
+int
+conn_poll_for_conn(struct conn *conn)
+{
+	struct sockaddr_in client_address;
+	struct epoll_event event;
+	socklen_t client_address_length;
+	int fd_client, status;
+
+	/* Check input arguments */
+	if (conn == NULL)
+		return -1;
+
+	/* Server socket */
+	client_address_length = sizeof(client_address);
+	fd_client = accept4(conn->fd_server,
+		(struct sockaddr *) &client_address,
+		&client_address_length,
+		SOCK_NONBLOCK);
+	if (fd_client == -1) {
+		if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
+			return 0;
+
+		return -1;
+	}
+
+	/* Client group */
+	event.events = EPOLLIN | EPOLLRDHUP | EPOLLHUP;
+	event.data.fd = fd_client;
+
+	status = epoll_ctl(conn->fd_client_group,
+		EPOLL_CTL_ADD,
+		fd_client,
+		&event);
+	if (status == -1) {
+		close(fd_client);
+		return -1;
+	}
+
+	/* Client */
+	status = write(fd_client,
+		conn->welcome,
+		strlen(conn->welcome));
+	if (status == -1) {
+		close(fd_client);
+		return -1;
+	}
+
+	status = write(fd_client,
+		conn->prompt,
+		strlen(conn->prompt));
+	if (status == -1) {
+		close(fd_client);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+data_event_handle(struct conn *conn,
+	int fd_client)
+{
+	ssize_t len, i, status;
+
+	/* Read input message */
+
+	len = read(fd_client,
+		conn->buf,
+		conn->buf_size);
+	if (len == -1) {
+		if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
+			return 0;
+
+		return -1;
+	}
+	if (len == 0)
+		return 0;
+
+	/* Handle input messages */
+	for (i = 0; i < len; i++) {
+		if (conn->buf[i] == '\n') {
+			size_t n;
+
+			conn->msg_in[conn->msg_in_len] = 0;
+			conn->msg_out[0] = 0;
+
+			conn->msg_handle(conn->msg_in,
+				conn->msg_out,
+				conn->msg_out_len_max);
+
+			n = strlen(conn->msg_out);
+			if (n) {
+				status = write(fd_client,
+					conn->msg_out,
+					n);
+				if (status == -1)
+					return status;
+			}
+
+			conn->msg_in_len = 0;
+		} else if (conn->msg_in_len < conn->msg_in_len_max) {
+			conn->msg_in[conn->msg_in_len] = conn->buf[i];
+			conn->msg_in_len++;
+		} else {
+			status = write(fd_client,
+				MSG_CMD_TOO_LONG,
+				strlen(MSG_CMD_TOO_LONG));
+			if (status == -1)
+				return status;
+
+			conn->msg_in_len = 0;
+		}
+	}
+
+	/* Write prompt */
+	status = write(fd_client,
+		conn->prompt,
+		strlen(conn->prompt));
+	if (status == -1)
+		return status;
+
+	return 0;
+}
+
+static int
+control_event_handle(struct conn *conn,
+	int fd_client)
+{
+	int status;
+
+	status = epoll_ctl(conn->fd_client_group,
+		EPOLL_CTL_DEL,
+		fd_client,
+		NULL);
+	if (status == -1)
+		return -1;
+
+	status = close(fd_client);
+	if (status == -1)
+		return -1;
+
+	return 0;
+}
+
+int
+conn_poll_for_msg(struct conn *conn)
+{
+	struct epoll_event event;
+	int fd_client, status, status_data, status_control;
+
+	/* Check input arguments */
+	if (conn == NULL)
+		return -1;
+
+	/* Client group */
+	status = epoll_wait(conn->fd_client_group,
+		&event,
+		1,
+		0);
+	if (status == -1)
+		return -1;
+	if (status == 0)
+		return 0;
+
+	fd_client = event.data.fd;
+
+	/* Data available */
+	if (event.events & EPOLLIN)
+		status_data = data_event_handle(conn, fd_client);
+
+	/* Control events */
+	if (event.events & (EPOLLRDHUP | EPOLLERR | EPOLLHUP))
+		status_control = control_event_handle(conn, fd_client);
+
+	if (status_data || status_control)
+		return -1;
+
+	return 0;
+}
diff --git a/examples/ip_pipeline/conn.h b/examples/ip_pipeline/conn.h
new file mode 100644
index 0000000..46f9f95
--- /dev/null
+++ b/examples/ip_pipeline/conn.h
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#ifndef __INCLUDE_CONN_H__
+#define __INCLUDE_CONN_H__
+
+#include <stdint.h>
+
+struct conn;
+
+#ifndef CONN_WELCOME_LEN_MAX
+#define CONN_WELCOME_LEN_MAX                               1024
+#endif
+
+#ifndef CONN_PROMPT_LEN_MAX
+#define CONN_PROMPT_LEN_MAX                                16
+#endif
+
+typedef void (*conn_msg_handle_t)(char *msg_in,
+	char *msg_out,
+	size_t msg_out_len_max);
+
+struct conn_params {
+	const char *welcome;
+	const char *prompt;
+	const char *addr;
+	uint16_t port;
+	size_t buf_size;
+	size_t msg_in_len_max;
+	size_t msg_out_len_max;
+	conn_msg_handle_t msg_handle;
+};
+
+struct conn *
+conn_init(struct conn_params *p);
+
+void
+conn_free(struct conn *conn);
+
+int
+conn_poll_for_conn(struct conn *conn);
+
+int
+conn_poll_for_msg(struct conn *conn);
+
+#endif
diff --git a/examples/ip_pipeline/main.c b/examples/ip_pipeline/main.c
index 1696e36..60936f4 100644
--- a/examples/ip_pipeline/main.c
+++ b/examples/ip_pipeline/main.c
@@ -1,5 +1,5 @@
 /* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
+ * Copyright(c) 2010-2018 Intel Corporation
  */
 
 #include <stdio.h>
@@ -10,11 +10,140 @@
 
 #include <rte_eal.h>
 
+#include "cli.h"
+#include "conn.h"
+
+static const char usage[] =
+	"%s EAL_ARGS -- [-h HOST] [-p PORT] [-s SCRIPT]\n";
+
+static const char welcome[] =
+	"\n"
+	"Welcome to IP Pipeline!\n"
+	"\n";
+
+static const char prompt[] = "pipeline> ";
+
+static struct app_params {
+	struct conn_params conn;
+	char *script_name;
+} app = {
+	.conn = {
+		.welcome = welcome,
+		.prompt = prompt,
+		.addr = "0.0.0.0",
+		.port = 8086,
+		.buf_size = 1024 * 1024,
+		.msg_in_len_max = 1024,
+		.msg_out_len_max = 1024 * 1024,
+		.msg_handle = cli_process,
+	},
+	.script_name = NULL,
+};
+
+static int
+parse_args(int argc, char **argv)
+{
+	char *app_name = argv[0];
+	struct option lgopts[] = {
+		{ NULL,  0, 0, 0 }
+	};
+	int opt, option_index;
+	int h_present, p_present, s_present, n_args, i;
+
+	/* Skip EAL input args */
+	n_args = argc;
+	for (i = 0; i < n_args; i++)
+		if (strcmp(argv[i], "--") == 0) {
+			argc -= i;
+			argv += i;
+			break;
+		}
+
+	if (i == n_args)
+		return 0;
+
+	/* Parse args */
+	h_present = 0;
+	p_present = 0;
+	s_present = 0;
+
+	while ((opt = getopt_long(argc, argv, "h:p:s:", lgopts, &option_index))
+			!= EOF)
+		switch (opt) {
+		case 'h':
+			if (h_present) {
+				printf("Error: Multiple -h arguments\n");
+				return -1;
+			}
+			h_present = 1;
+
+			if (!strlen(optarg)) {
+				printf("Error: Argument for -h not provided\n");
+				return -1;
+			}
+
+			app.conn.addr = strdup(optarg);
+			if (app.conn.addr == NULL) {
+				printf("Error: Not enough memory\n");
+				return -1;
+			}
+			break;
+
+		case 'p':
+			if (p_present) {
+				printf("Error: Multiple -p arguments\n");
+				return -1;
+			}
+			p_present = 1;
+
+			if (!strlen(optarg)) {
+				printf("Error: Argument for -p not provided\n");
+				return -1;
+			}
+
+			app.conn.port = (uint16_t) atoi(optarg);
+			break;
+
+		case 's':
+			if (s_present) {
+				printf("Error: Multiple -s arguments\n");
+				return -1;
+			}
+			s_present = 1;
+
+			if (!strlen(optarg)) {
+				printf("Error: Argument for -s not provided\n");
+				return -1;
+			}
+
+			app.script_name = strdup(optarg);
+			if (app.script_name == NULL) {
+				printf("Error: Not enough memory\n");
+				return -1;
+			}
+			break;
+
+		default:
+			printf(usage, app_name);
+			return -1;
+		}
+
+	optind = 1; /* reset getopt lib */
+
+	return 0;
+}
+
 int
 main(int argc, char **argv)
 {
+	struct conn *conn;
 	int status;
 
+	/* Parse application arguments */
+	status = parse_args(argc, argv);
+	if (status < 0)
+		return status;
+
 	/* EAL */
 	status = rte_eal_init(argc, argv);
 	if (status < 0) {
@@ -22,4 +151,24 @@ main(int argc, char **argv)
 		return status;
 	};
 
+	/* Connectivity */
+	conn = conn_init(&app.conn);
+	if (conn == NULL) {
+		printf("Error: Connectivity initialization failed (%d)\n",
+			status);
+		return status;
+	};
+
+	/* Script */
+	if (app.script_name)
+		cli_script_process(app.script_name,
+			app.conn.msg_in_len_max,
+			app.conn.msg_out_len_max);
+
+	/* Dispatch loop */
+	for ( ; ; ) {
+		conn_poll_for_conn(conn);
+
+		conn_poll_for_msg(conn);
+	}
 }
diff --git a/examples/ip_pipeline/meson.build b/examples/ip_pipeline/meson.build
index 063865c..a89cb30 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -8,6 +8,8 @@
 
 deps += ['pipeline', 'bus_pci']
 sources = files(
+	'cli.c',
+	'conn.c',
 	'main.c',
 	'parser.c',
 )
-- 
2.9.3

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

* [dpdk-dev] [PATCH v3 19/44] ip_pipeline: add mempool object for pipeline
  2018-03-16 17:58       ` [dpdk-dev] [PATCH v3 00/44] ip_pipeline: refactoring Jasvinder Singh
                           ` (17 preceding siblings ...)
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 18/44] ip_pipeline: add cli interface Jasvinder Singh
@ 2018-03-16 17:58         ` Jasvinder Singh
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 20/44] ip_pipeline: add link object Jasvinder Singh
                           ` (24 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-16 17:58 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Fan Zhang

Add mempool object implementation to the application.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Fan Zhang <roy.fan.zhang@intel.com>
---
 examples/ip_pipeline/Makefile    |   1 +
 examples/ip_pipeline/cli.c       | 109 ++++++++++++++++++++++++++++++++++++++-
 examples/ip_pipeline/common.h    |  12 +++++
 examples/ip_pipeline/main.c      |   8 +++
 examples/ip_pipeline/mempool.c   |  81 +++++++++++++++++++++++++++++
 examples/ip_pipeline/mempool.h   |  40 ++++++++++++++
 examples/ip_pipeline/meson.build |   1 +
 7 files changed, 251 insertions(+), 1 deletion(-)
 create mode 100644 examples/ip_pipeline/common.h
 create mode 100644 examples/ip_pipeline/mempool.c
 create mode 100644 examples/ip_pipeline/mempool.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index 0c5b6b1..fca28c5 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -8,6 +8,7 @@ APP = ip_pipeline
 SRCS-y := cli.c
 SRCS-y += conn.c
 SRCS-y += main.c
+SRCS-y += mempool.c
 SRCS-y += parser.c
 #SRCS-y += thread.c
 
diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index 3e97b29..6fe3725 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -10,6 +10,23 @@
 #include <rte_common.h>
 
 #include "cli.h"
+#include "mempool.h"
+#include "parser.h"
+
+#ifndef CMD_MAX_TOKENS
+#define CMD_MAX_TOKENS     256
+#endif
+
+#define MSG_OUT_OF_MEMORY  "Not enough memory.\n"
+#define MSG_CMD_UNKNOWN    "Unknown command \"%s\".\n"
+#define MSG_CMD_UNIMPLEM   "Command \"%s\" not implemented.\n"
+#define MSG_ARG_NOT_ENOUGH "Not enough arguments for command \"%s\".\n"
+#define MSG_ARG_TOO_MANY   "Too many arguments for command \"%s\".\n"
+#define MSG_ARG_MISMATCH   "Wrong number of arguments for command \"%s\".\n"
+#define MSG_ARG_NOT_FOUND  "Argument \"%s\" not found.\n"
+#define MSG_ARG_INVALID    "Invalid value for argument \"%s\".\n"
+#define MSG_FILE_ERR       "Error in file \"%s\" at line %u.\n"
+#define MSG_CMD_FAIL       "Command \"%s\" failed.\n"
 
 static int
 is_comment(char *in)
@@ -22,12 +39,102 @@ is_comment(char *in)
 	return 0;
 }
 
+/**
+ * mempool <mempool_name>
+ *  buffer <buffer_size>
+ *  pool <pool_size>
+ *  cache <cache_size>
+ *  cpu <cpu_id>
+ */
+static void
+cmd_mempool(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct mempool_params p;
+	char *name;
+	struct mempool *mempool;
+
+	if (n_tokens != 10) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	name = tokens[1];
+
+	if (strcmp(tokens[2], "buffer") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "buffer");
+		return;
+	}
+
+	if (parser_read_uint32(&p.buffer_size, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "buffer_size");
+		return;
+	}
+
+	if (strcmp(tokens[4], "pool") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pool");
+		return;
+	}
+
+	if (parser_read_uint32(&p.pool_size, tokens[5]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "pool_size");
+		return;
+	}
+
+	if (strcmp(tokens[6], "cache") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cache");
+		return;
+	}
+
+	if (parser_read_uint32(&p.cache_size, tokens[7]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "cache_size");
+		return;
+	}
+
+	if (strcmp(tokens[8], "cpu") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu");
+		return;
+	}
+
+	if (parser_read_uint32(&p.cpu_id, tokens[9]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id");
+		return;
+	}
+
+	mempool = mempool_create(name, &p);
+	if (mempool == NULL) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
 void
-cli_process(char *in, char *out __rte_unused, size_t out_size __rte_unused)
+cli_process(char *in, char *out, size_t out_size)
 {
+	char *tokens[CMD_MAX_TOKENS];
+	uint32_t n_tokens = RTE_DIM(tokens);
+	int status;
+
 	if (is_comment(in))
 		return;
 
+	status = parse_tokenize_string(in, tokens, &n_tokens);
+	if (status) {
+		snprintf(out, out_size, MSG_ARG_TOO_MANY, "");
+		return;
+	}
+
+	if (n_tokens == 0)
+		return;
+
+	if (strcmp(tokens[0], "mempool") == 0) {
+		cmd_mempool(tokens, n_tokens, out, out_size);
+		return;
+	}
+
+	snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
 }
 
 int
diff --git a/examples/ip_pipeline/common.h b/examples/ip_pipeline/common.h
new file mode 100644
index 0000000..0886dfb
--- /dev/null
+++ b/examples/ip_pipeline/common.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#ifndef _INCLUDE_COMMON_H_
+#define _INCLUDE_COMMON_H_
+
+#ifndef NAME_SIZE
+#define NAME_SIZE                                            64
+#endif
+
+#endif /* _INCLUDE_COMMON_H_ */
diff --git a/examples/ip_pipeline/main.c b/examples/ip_pipeline/main.c
index 60936f4..b53f623 100644
--- a/examples/ip_pipeline/main.c
+++ b/examples/ip_pipeline/main.c
@@ -12,6 +12,7 @@
 
 #include "cli.h"
 #include "conn.h"
+#include "mempool.h"
 
 static const char usage[] =
 	"%s EAL_ARGS -- [-h HOST] [-p PORT] [-s SCRIPT]\n";
@@ -159,6 +160,13 @@ main(int argc, char **argv)
 		return status;
 	};
 
+	/* Mempool */
+	status = mempool_init();
+	if (status) {
+		printf("Error: Mempool initialization failed (%d)\n", status);
+		return status;
+	}
+
 	/* Script */
 	if (app.script_name)
 		cli_script_process(app.script_name,
diff --git a/examples/ip_pipeline/mempool.c b/examples/ip_pipeline/mempool.c
new file mode 100644
index 0000000..33b9243
--- /dev/null
+++ b/examples/ip_pipeline/mempool.c
@@ -0,0 +1,81 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <rte_mbuf.h>
+
+#include "mempool.h"
+
+#define BUFFER_SIZE_MIN        (sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM)
+
+static struct mempool_list mempool_list;
+
+int
+mempool_init(void)
+{
+	TAILQ_INIT(&mempool_list);
+
+	return 0;
+}
+
+struct mempool *
+mempool_find(const char *name)
+{
+	struct mempool *mempool;
+
+	if (name == NULL)
+		return NULL;
+
+	TAILQ_FOREACH(mempool, &mempool_list, node)
+		if (strcmp(mempool->name, name) == 0)
+			return mempool;
+
+	return NULL;
+}
+
+struct mempool *
+mempool_create(const char *name, struct mempool_params *params)
+{
+	struct mempool *mempool;
+	struct rte_mempool *m;
+
+	/* Check input params */
+	if ((name == NULL) ||
+		mempool_find(name) ||
+		(params == NULL) ||
+		(params->buffer_size < BUFFER_SIZE_MIN) ||
+		(params->pool_size == 0))
+		return NULL;
+
+	/* Resource create */
+	m = rte_pktmbuf_pool_create(
+		name,
+		params->pool_size,
+		params->cache_size,
+		0,
+		params->buffer_size - sizeof(struct rte_mbuf),
+		params->cpu_id);
+
+	if (m == NULL)
+		return NULL;
+
+	/* Node allocation */
+	mempool = calloc(1, sizeof(struct mempool));
+	if (mempool == NULL) {
+		rte_mempool_free(m);
+		return NULL;
+	}
+
+	/* Node fill in */
+	strncpy(mempool->name, name, sizeof(mempool->name));
+	mempool->m = m;
+	mempool->buffer_size = params->buffer_size;
+
+	/* Node add to list */
+	TAILQ_INSERT_TAIL(&mempool_list, mempool, node);
+
+	return mempool;
+}
diff --git a/examples/ip_pipeline/mempool.h b/examples/ip_pipeline/mempool.h
new file mode 100644
index 0000000..bd46a11
--- /dev/null
+++ b/examples/ip_pipeline/mempool.h
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#ifndef _INCLUDE_MEMPOOL_H_
+#define _INCLUDE_MEMPOOL_H_
+
+#include <stdint.h>
+#include <sys/queue.h>
+
+#include <rte_mempool.h>
+
+#include "common.h"
+
+struct mempool {
+	TAILQ_ENTRY(mempool) node;
+	char name[NAME_SIZE];
+	struct rte_mempool *m;
+	uint32_t buffer_size;
+};
+
+TAILQ_HEAD(mempool_list, mempool);
+
+int
+mempool_init(void);
+
+struct mempool *
+mempool_find(const char *name);
+
+struct mempool_params {
+	uint32_t buffer_size;
+	uint32_t pool_size;
+	uint32_t cache_size;
+	uint32_t cpu_id;
+};
+
+struct mempool *
+mempool_create(const char *name, struct mempool_params *params);
+
+#endif /* _INCLUDE_MEMPOOL_H_ */
diff --git a/examples/ip_pipeline/meson.build b/examples/ip_pipeline/meson.build
index a89cb30..f8a450f 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -11,5 +11,6 @@ sources = files(
 	'cli.c',
 	'conn.c',
 	'main.c',
+	'mempool.c',
 	'parser.c',
 )
-- 
2.9.3

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

* [dpdk-dev] [PATCH v3 20/44] ip_pipeline: add link object
  2018-03-16 17:58       ` [dpdk-dev] [PATCH v3 00/44] ip_pipeline: refactoring Jasvinder Singh
                           ` (18 preceding siblings ...)
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 19/44] ip_pipeline: add mempool object for pipeline Jasvinder Singh
@ 2018-03-16 17:58         ` Jasvinder Singh
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 21/44] ip_pipeline: add software queue object Jasvinder Singh
                           ` (23 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-16 17:58 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Fan Zhang

Add link object implementation to the application.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Fan Zhang <roy.fan.zhang@intel.com>
---
 examples/ip_pipeline/Makefile    |   1 +
 examples/ip_pipeline/cli.c       | 122 ++++++++++++++++++
 examples/ip_pipeline/link.c      | 268 +++++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/link.h      |  63 +++++++++
 examples/ip_pipeline/main.c      |   8 ++
 examples/ip_pipeline/meson.build |   1 +
 6 files changed, 463 insertions(+)
 create mode 100644 examples/ip_pipeline/link.c
 create mode 100644 examples/ip_pipeline/link.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index fca28c5..3dab932 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -7,6 +7,7 @@ APP = ip_pipeline
 # all source are stored in SRCS-y
 SRCS-y := cli.c
 SRCS-y += conn.c
+SRCS-y += link.c
 SRCS-y += main.c
 SRCS-y += mempool.c
 SRCS-y += parser.c
diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index 6fe3725..aa87824 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -10,6 +10,7 @@
 #include <rte_common.h>
 
 #include "cli.h"
+#include "link.h"
 #include "mempool.h"
 #include "parser.h"
 
@@ -110,6 +111,122 @@ cmd_mempool(char **tokens,
 	}
 }
 
+/**
+ * link <link_name>
+ *  dev <device_name> | port <port_id>
+ *  rxq <n_queues> <queue_size> <mempool_name>
+ *  txq <n_queues> <queue_size>
+ *  promiscuous on | off
+ *  [rss <qid_0> ... <qid_n>]
+ */
+static void
+cmd_link(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct link_params p;
+	struct link_params_rss rss;
+	struct link *link;
+	char *name;
+
+	if ((n_tokens < 13) || (n_tokens > 14 + LINK_RXQ_RSS_MAX)) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+	name = tokens[1];
+
+	if (strcmp(tokens[2], "dev") == 0)
+		p.dev_name = tokens[3];
+	else if (strcmp(tokens[2], "port") == 0) {
+		p.dev_name = NULL;
+
+		if (parser_read_uint16(&p.port_id, tokens[3]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
+			return;
+		}
+	} else {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "dev or port");
+		return;
+	}
+
+	if (strcmp(tokens[4], "rxq") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rxq");
+	return;
+	}
+
+	if (parser_read_uint32(&p.rx.n_queues, tokens[5]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "n_queues");
+		return;
+	}
+	if (parser_read_uint32(&p.rx.queue_size, tokens[6]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "queue_size");
+		return;
+}
+
+	p.rx.mempool_name = tokens[7];
+
+	if (strcmp(tokens[8], "txq") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "txq");
+		return;
+	}
+
+	if (parser_read_uint32(&p.tx.n_queues, tokens[9]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "n_queues");
+		return;
+	}
+
+	if (parser_read_uint32(&p.tx.queue_size, tokens[10]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "queue_size");
+		return;
+	}
+
+	if (strcmp(tokens[11], "promiscuous") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "promiscuous");
+		return;
+	}
+
+	if (strcmp(tokens[12], "on") == 0)
+		p.promiscuous = 1;
+	else if (strcmp(tokens[12], "off") == 0)
+		p.promiscuous = 0;
+	else {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "on or off");
+		return;
+	}
+
+	/* RSS */
+	p.rx.rss = NULL;
+	if (n_tokens > 13) {
+		uint32_t queue_id, i;
+
+		if (strcmp(tokens[13], "rss") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rss");
+			return;
+		}
+
+		p.rx.rss = &rss;
+
+		rss.n_queues = 0;
+		for (i = 14; i < n_tokens; i++) {
+			if (parser_read_uint32(&queue_id, tokens[i]) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID,
+					"queue_id");
+				return;
+			}
+
+			rss.queue_id[rss.n_queues] = queue_id;
+			rss.n_queues++;
+		}
+	}
+
+	link = link_create(name, &p);
+	if (link == NULL) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
 void
 cli_process(char *in, char *out, size_t out_size)
 {
@@ -134,6 +251,11 @@ cli_process(char *in, char *out, size_t out_size)
 		return;
 	}
 
+	if (strcmp(tokens[0], "link") == 0) {
+		cmd_link(tokens, n_tokens, out, out_size);
+		return;
+	}
+
 	snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
 }
 
diff --git a/examples/ip_pipeline/link.c b/examples/ip_pipeline/link.c
new file mode 100644
index 0000000..26ff41b
--- /dev/null
+++ b/examples/ip_pipeline/link.c
@@ -0,0 +1,268 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <rte_ethdev.h>
+
+#include "link.h"
+#include "mempool.h"
+
+static struct link_list link_list;
+
+int
+link_init(void)
+{
+	TAILQ_INIT(&link_list);
+
+	return 0;
+}
+
+struct link *
+link_find(const char *name)
+{
+	struct link *link;
+
+	if (name == NULL)
+		return NULL;
+
+	TAILQ_FOREACH(link, &link_list, node)
+		if (strcmp(link->name, name) == 0)
+			return link;
+
+	return NULL;
+}
+
+static struct rte_eth_conf port_conf_default = {
+	.link_speeds = 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   = 1, /* CRC strip by HW */
+		.enable_scatter = 0, /* Scattered packets RX handler */
+
+		.max_rx_pkt_len = 9000, /* Jumbo frame max packet len */
+		.split_hdr_size = 0, /* Header split buffer size */
+	},
+	.rx_adv_conf = {
+		.rss_conf = {
+			.rss_key = NULL,
+			.rss_key_len = 40,
+			.rss_hf = 0,
+		},
+	},
+	.txmode = {
+		.mq_mode = ETH_MQ_TX_NONE,
+	},
+	.lpbk_mode = 0,
+};
+
+#define RETA_CONF_SIZE     (ETH_RSS_RETA_SIZE_512 / RTE_RETA_GROUP_SIZE)
+
+static int
+rss_setup(uint16_t port_id,
+	uint16_t reta_size,
+	struct link_params_rss *rss)
+{
+	struct rte_eth_rss_reta_entry64 reta_conf[RETA_CONF_SIZE];
+	uint32_t i;
+	int status;
+
+	/* RETA setting */
+	memset(reta_conf, 0, sizeof(reta_conf));
+
+	for (i = 0; i < reta_size; i++)
+		reta_conf[i / RTE_RETA_GROUP_SIZE].mask = UINT64_MAX;
+
+	for (i = 0; i < reta_size; i++) {
+		uint32_t reta_id = i / RTE_RETA_GROUP_SIZE;
+		uint32_t reta_pos = i % RTE_RETA_GROUP_SIZE;
+		uint32_t rss_qs_pos = i % rss->n_queues;
+
+		reta_conf[reta_id].reta[reta_pos] =
+			(uint16_t) rss->queue_id[rss_qs_pos];
+	}
+
+	/* RETA update */
+	status = rte_eth_dev_rss_reta_update(port_id,
+		reta_conf,
+		reta_size);
+
+	return status;
+}
+
+struct link *
+link_create(const char *name, struct link_params *params)
+{
+	struct rte_eth_dev_info port_info;
+	struct rte_eth_conf port_conf;
+	struct link *link;
+	struct link_params_rss *rss;
+	struct mempool *mempool;
+	uint32_t cpu_id, i;
+	int status;
+	uint16_t port_id;
+
+	/* Check input params */
+	if ((name == NULL) ||
+		link_find(name) ||
+		(params == NULL) ||
+		(params->rx.n_queues == 0) ||
+		(params->rx.queue_size == 0) ||
+		(params->tx.n_queues == 0) ||
+		(params->tx.queue_size == 0))
+		return NULL;
+
+	port_id = params->port_id;
+	if (params->dev_name) {
+		status = rte_eth_dev_get_port_by_name(params->dev_name,
+			&port_id);
+
+		if (status)
+			return NULL;
+	} else
+		if (!rte_eth_dev_is_valid_port(port_id))
+			return NULL;
+
+	rte_eth_dev_info_get(port_id, &port_info);
+
+	mempool = mempool_find(params->rx.mempool_name);
+	if (mempool == NULL)
+		return NULL;
+
+	rss = params->rx.rss;
+	if (rss) {
+		if ((port_info.reta_size == 0) ||
+			(port_info.reta_size > ETH_RSS_RETA_SIZE_512))
+			return NULL;
+
+		if ((rss->n_queues == 0) ||
+			(rss->n_queues >= LINK_RXQ_RSS_MAX))
+			return NULL;
+
+		for (i = 0; i < rss->n_queues; i++)
+			if (rss->queue_id[i] >= port_info.max_rx_queues)
+				return NULL;
+	}
+
+	/**
+	 * Resource create
+	 */
+	/* Port */
+	memcpy(&port_conf, &port_conf_default, sizeof(port_conf));
+	if (rss) {
+		port_conf.rxmode.mq_mode = ETH_MQ_RX_RSS;
+		port_conf.rx_adv_conf.rss_conf.rss_hf =
+			ETH_RSS_IPV4 | ETH_RSS_IPV6;
+	}
+
+	cpu_id = (uint32_t) rte_eth_dev_socket_id(port_id);
+	if (cpu_id == (uint32_t) SOCKET_ID_ANY)
+		cpu_id = 0;
+
+	status = rte_eth_dev_configure(
+		port_id,
+		params->rx.n_queues,
+		params->tx.n_queues,
+		&port_conf);
+
+	if (status < 0)
+		return NULL;
+
+	if (params->promiscuous)
+		rte_eth_promiscuous_enable(port_id);
+
+	/* Port RX */
+	for (i = 0; i < params->rx.n_queues; i++) {
+		status = rte_eth_rx_queue_setup(
+			port_id,
+			i,
+			params->rx.queue_size,
+			cpu_id,
+			NULL,
+			mempool->m);
+
+		if (status < 0)
+			return NULL;
+	}
+
+	/* Port TX */
+	for (i = 0; i < params->tx.n_queues; i++) {
+		status = rte_eth_tx_queue_setup(
+			port_id,
+			i,
+			params->tx.queue_size,
+			cpu_id,
+			NULL);
+
+		if (status < 0)
+			return NULL;
+	}
+
+	/* Port start */
+	status = rte_eth_dev_start(port_id);
+	if (status < 0)
+		return NULL;
+
+	if (rss) {
+		status = rss_setup(port_id, port_info.reta_size, rss);
+
+		if (status) {
+			rte_eth_dev_stop(port_id);
+			return NULL;
+		}
+	}
+
+	/* Port link up */
+	status = rte_eth_dev_set_link_up(port_id);
+	if ((status < 0) && (status != -ENOTSUP)) {
+		rte_eth_dev_stop(port_id);
+		return NULL;
+	}
+
+	/* Node allocation */
+	link = calloc(1, sizeof(struct link));
+	if (link == NULL) {
+		rte_eth_dev_stop(port_id);
+		return NULL;
+	}
+
+	/* Node fill in */
+	strncpy(link->name, name, sizeof(link->name));
+	link->port_id = port_id;
+	link->n_rxq = params->rx.n_queues;
+	link->n_txq = params->tx.n_queues;
+
+	/* Node add to list */
+	TAILQ_INSERT_TAIL(&link_list, link, node);
+
+	return link;
+}
+
+int
+link_is_up(const char *name)
+{
+	struct rte_eth_link link_params;
+	struct link *link;
+
+	/* Check input params */
+	if (name == NULL)
+		return 0;
+
+	link = link_find(name);
+	if (link == NULL)
+		return 0;
+
+	/* Resource */
+	rte_eth_link_get(link->port_id, &link_params);
+
+	return (link_params.link_status == ETH_LINK_DOWN) ? 0 : 1;
+}
diff --git a/examples/ip_pipeline/link.h b/examples/ip_pipeline/link.h
new file mode 100644
index 0000000..37d3dc4
--- /dev/null
+++ b/examples/ip_pipeline/link.h
@@ -0,0 +1,63 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#ifndef _INCLUDE_LINK_H_
+#define _INCLUDE_LINK_H_
+
+#include <stdint.h>
+#include <sys/queue.h>
+
+#include "common.h"
+
+#ifndef LINK_RXQ_RSS_MAX
+#define LINK_RXQ_RSS_MAX                                   16
+#endif
+
+struct link {
+	TAILQ_ENTRY(link) node;
+	char name[NAME_SIZE];
+	uint16_t port_id;
+	uint32_t n_rxq;
+	uint32_t n_txq;
+};
+
+TAILQ_HEAD(link_list, link);
+
+int
+link_init(void);
+
+struct link *
+link_find(const char *name);
+
+struct link_params_rss {
+	uint32_t queue_id[LINK_RXQ_RSS_MAX];
+	uint32_t n_queues;
+};
+
+struct link_params {
+	const char *dev_name;
+	uint16_t port_id; /**< Valid only when *dev_name* is NULL. */
+
+	struct {
+		uint32_t n_queues;
+		uint32_t queue_size;
+		const char *mempool_name;
+		struct link_params_rss *rss;
+	} rx;
+
+	struct {
+		uint32_t n_queues;
+		uint32_t queue_size;
+	} tx;
+
+	int promiscuous;
+};
+
+struct link *
+link_create(const char *name, struct link_params *params);
+
+int
+link_is_up(const char *name);
+
+#endif /* _INCLUDE_LINK_H_ */
diff --git a/examples/ip_pipeline/main.c b/examples/ip_pipeline/main.c
index b53f623..edfb523 100644
--- a/examples/ip_pipeline/main.c
+++ b/examples/ip_pipeline/main.c
@@ -12,6 +12,7 @@
 
 #include "cli.h"
 #include "conn.h"
+#include "link.h"
 #include "mempool.h"
 
 static const char usage[] =
@@ -167,6 +168,13 @@ main(int argc, char **argv)
 		return status;
 	}
 
+	/* Link */
+	status = link_init();
+	if (status) {
+		printf("Error: Link initialization failed (%d)\n", status);
+		return status;
+	}
+
 	/* Script */
 	if (app.script_name)
 		cli_script_process(app.script_name,
diff --git a/examples/ip_pipeline/meson.build b/examples/ip_pipeline/meson.build
index f8a450f..a2f9bb6 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -10,6 +10,7 @@ deps += ['pipeline', 'bus_pci']
 sources = files(
 	'cli.c',
 	'conn.c',
+	'link.c',
 	'main.c',
 	'mempool.c',
 	'parser.c',
-- 
2.9.3

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

* [dpdk-dev] [PATCH v3 21/44] ip_pipeline: add software queue object
  2018-03-16 17:58       ` [dpdk-dev] [PATCH v3 00/44] ip_pipeline: refactoring Jasvinder Singh
                           ` (19 preceding siblings ...)
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 20/44] ip_pipeline: add link object Jasvinder Singh
@ 2018-03-16 17:58         ` Jasvinder Singh
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 22/44] ip_pipeline: add traffic manager object Jasvinder Singh
                           ` (22 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-16 17:58 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Kevin Laatz

Add swq object implementation to the application.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
---
 examples/ip_pipeline/Makefile    |  1 +
 examples/ip_pipeline/cli.c       | 55 +++++++++++++++++++++++++++++
 examples/ip_pipeline/main.c      |  8 +++++
 examples/ip_pipeline/meson.build |  1 +
 examples/ip_pipeline/swq.c       | 74 ++++++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/swq.h       | 37 ++++++++++++++++++++
 6 files changed, 176 insertions(+)
 create mode 100644 examples/ip_pipeline/swq.c
 create mode 100644 examples/ip_pipeline/swq.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index 3dab932..0dc8442 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -11,6 +11,7 @@ SRCS-y += link.c
 SRCS-y += main.c
 SRCS-y += mempool.c
 SRCS-y += parser.c
+SRCS-y += swq.c
 #SRCS-y += thread.c
 
 # Build using pkg-config variables if possible
diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index aa87824..622d206 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -13,6 +13,7 @@
 #include "link.h"
 #include "mempool.h"
 #include "parser.h"
+#include "swq.h"
 
 #ifndef CMD_MAX_TOKENS
 #define CMD_MAX_TOKENS     256
@@ -227,6 +228,55 @@ cmd_link(char **tokens,
 	}
 }
 
+/**
+ * swq <swq_name>
+ *  size <size>
+ *  cpu <cpu_id>
+ */
+static void
+cmd_swq(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct swq_params p;
+	char *name;
+	struct swq *swq;
+
+	if (n_tokens != 6) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	name = tokens[1];
+
+	if (strcmp(tokens[2], "size") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
+		return;
+	}
+
+	if (parser_read_uint32(&p.size, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "size");
+		return;
+	}
+
+	if (strcmp(tokens[4], "cpu") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu");
+		return;
+	}
+
+	if (parser_read_uint32(&p.cpu_id, tokens[5]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id");
+		return;
+	}
+
+	swq = swq_create(name, &p);
+	if (swq == NULL) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
 void
 cli_process(char *in, char *out, size_t out_size)
 {
@@ -256,6 +306,11 @@ cli_process(char *in, char *out, size_t out_size)
 		return;
 	}
 
+	if (strcmp(tokens[0], "swq") == 0) {
+		cmd_swq(tokens, n_tokens, out, out_size);
+		return;
+	}
+
 	snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
 }
 
diff --git a/examples/ip_pipeline/main.c b/examples/ip_pipeline/main.c
index edfb523..456f016 100644
--- a/examples/ip_pipeline/main.c
+++ b/examples/ip_pipeline/main.c
@@ -14,6 +14,7 @@
 #include "conn.h"
 #include "link.h"
 #include "mempool.h"
+#include "swq.h"
 
 static const char usage[] =
 	"%s EAL_ARGS -- [-h HOST] [-p PORT] [-s SCRIPT]\n";
@@ -175,6 +176,13 @@ main(int argc, char **argv)
 		return status;
 	}
 
+	/* SWQ */
+	status = swq_init();
+	if (status) {
+		printf("Error: SWQ initialization failed (%d)\n", status);
+		return status;
+	}
+
 	/* Script */
 	if (app.script_name)
 		cli_script_process(app.script_name,
diff --git a/examples/ip_pipeline/meson.build b/examples/ip_pipeline/meson.build
index a2f9bb6..442f3e3 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -14,4 +14,5 @@ sources = files(
 	'main.c',
 	'mempool.c',
 	'parser.c',
+	'swq.c',
 )
diff --git a/examples/ip_pipeline/swq.c b/examples/ip_pipeline/swq.c
new file mode 100644
index 0000000..c11bbf2
--- /dev/null
+++ b/examples/ip_pipeline/swq.c
@@ -0,0 +1,74 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "swq.h"
+
+static struct swq_list swq_list;
+
+int
+swq_init(void)
+{
+	TAILQ_INIT(&swq_list);
+
+	return 0;
+}
+
+struct swq *
+swq_find(const char *name)
+{
+	struct swq *swq;
+
+	if (name == NULL)
+		return NULL;
+
+	TAILQ_FOREACH(swq, &swq_list, node)
+		if (strcmp(swq->name, name) == 0)
+			return swq;
+
+	return NULL;
+}
+
+struct swq *
+swq_create(const char *name, struct swq_params *params)
+{
+	struct swq *swq;
+	struct rte_ring *r;
+	unsigned int flags = RING_F_SP_ENQ | RING_F_SC_DEQ;
+
+	/* Check input params */
+	if ((name == NULL) ||
+		swq_find(name) ||
+		(params == NULL) ||
+		(params->size == 0))
+		return NULL;
+
+	/* Resource create */
+	r = rte_ring_create(
+		name,
+		params->size,
+		params->cpu_id,
+		flags);
+
+	if (r == NULL)
+		return NULL;
+
+	/* Node allocation */
+	swq = calloc(1, sizeof(struct swq));
+	if (swq == NULL) {
+		rte_ring_free(r);
+		return NULL;
+	}
+
+	/* Node fill in */
+	strncpy(swq->name, name, sizeof(swq->name));
+	swq->r = r;
+
+	/* Node add to list */
+	TAILQ_INSERT_TAIL(&swq_list, swq, node);
+
+	return swq;
+}
diff --git a/examples/ip_pipeline/swq.h b/examples/ip_pipeline/swq.h
new file mode 100644
index 0000000..c8440ee
--- /dev/null
+++ b/examples/ip_pipeline/swq.h
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#ifndef _INCLUDE_SWQ_H_
+#define _INCLUDE_SWQ_H_
+
+#include <stdint.h>
+#include <sys/queue.h>
+
+#include <rte_ring.h>
+
+#include "common.h"
+
+struct swq {
+	TAILQ_ENTRY(swq) node;
+	char name[NAME_SIZE];
+	struct rte_ring *r;
+};
+
+TAILQ_HEAD(swq_list, swq);
+
+int
+swq_init(void);
+
+struct swq *
+swq_find(const char *name);
+
+struct swq_params {
+	uint32_t size;
+	uint32_t cpu_id;
+};
+
+struct swq *
+swq_create(const char *name, struct swq_params *params);
+
+#endif /* _INCLUDE_SWQ_H_ */
-- 
2.9.3

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

* [dpdk-dev] [PATCH v3 22/44] ip_pipeline: add traffic manager object
  2018-03-16 17:58       ` [dpdk-dev] [PATCH v3 00/44] ip_pipeline: refactoring Jasvinder Singh
                           ` (20 preceding siblings ...)
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 21/44] ip_pipeline: add software queue object Jasvinder Singh
@ 2018-03-16 17:58         ` Jasvinder Singh
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 23/44] ip_pipeline: add tap object Jasvinder Singh
                           ` (21 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-16 17:58 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add traffic manager object implementation to the application.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/Makefile    |   1 +
 examples/ip_pipeline/cli.c       | 360 +++++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/main.c      |   8 +
 examples/ip_pipeline/meson.build |   1 +
 examples/ip_pipeline/tmgr.c      | 227 ++++++++++++++++++++++++
 examples/ip_pipeline/tmgr.h      |  70 ++++++++
 6 files changed, 667 insertions(+)
 create mode 100644 examples/ip_pipeline/tmgr.c
 create mode 100644 examples/ip_pipeline/tmgr.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index 0dc8442..35e4302 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -12,6 +12,7 @@ SRCS-y += main.c
 SRCS-y += mempool.c
 SRCS-y += parser.c
 SRCS-y += swq.c
+SRCS-y += tmgr.c
 #SRCS-y += thread.c
 
 # Build using pkg-config variables if possible
diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index 622d206..b895d60 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -14,6 +14,7 @@
 #include "mempool.h"
 #include "parser.h"
 #include "swq.h"
+#include "tmgr.h"
 
 #ifndef CMD_MAX_TOKENS
 #define CMD_MAX_TOKENS     256
@@ -277,6 +278,331 @@ cmd_swq(char **tokens,
 	}
 }
 
+/**
+ * tmgr subport profile
+ *  <tb_rate> <tb_size>
+ *  <tc0_rate> <tc1_rate> <tc2_rate> <tc3_rate>
+ *  <tc_period>
+ */
+static void
+cmd_tmgr_subport_profile(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct rte_sched_subport_params p;
+	int status, i;
+
+	if (n_tokens != 10) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	if (parser_read_uint32(&p.tb_rate, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "tb_rate");
+		return;
+	}
+
+	if (parser_read_uint32(&p.tb_size, tokens[4]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "tb_size");
+		return;
+	}
+
+	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
+		if (parser_read_uint32(&p.tc_rate[i], tokens[5 + i]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "tc_rate");
+			return;
+		}
+
+	if (parser_read_uint32(&p.tc_period, tokens[9]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "tc_period");
+		return;
+	}
+
+	status = tmgr_subport_profile_add(&p);
+	if (status != 0) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
+ * tmgr pipe profile
+ *  <tb_rate> <tb_size>
+ *  <tc0_rate> <tc1_rate> <tc2_rate> <tc3_rate>
+ *  <tc_period>
+ *  <tc_ov_weight>
+ *  <wrr_weight0..15>
+ */
+static void
+cmd_tmgr_pipe_profile(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct rte_sched_pipe_params p;
+	int status, i;
+
+	if (n_tokens != 27) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	if (parser_read_uint32(&p.tb_rate, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "tb_rate");
+		return;
+	}
+
+	if (parser_read_uint32(&p.tb_size, tokens[4]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "tb_size");
+		return;
+	}
+
+	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
+		if (parser_read_uint32(&p.tc_rate[i], tokens[5 + i]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "tc_rate");
+			return;
+		}
+
+	if (parser_read_uint32(&p.tc_period, tokens[9]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "tc_period");
+		return;
+	}
+
+#ifdef RTE_SCHED_SUBPORT_TC_OV
+	if (parser_read_uint32(&p.tc_ov_weight, tokens[10]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "tc_ov_weight");
+		return;
+	}
+#endif
+
+	for (i = 0; i < RTE_SCHED_QUEUES_PER_PIPE; i++)
+		if (parser_read_uint8(&p.wrr_weights[i], tokens[11 + i]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "wrr_weights");
+			return;
+		}
+
+	status = tmgr_pipe_profile_add(&p);
+	if (status != 0) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
+ * tmgr <tmgr_name>
+ *  rate <rate>
+ *  spp <n_subports_per_port>
+ *  pps <n_pipes_per_subport>
+ *  qsize <qsize_tc0> <qsize_tc1> <qsize_tc2> <qsize_tc3>
+ *  fo <frame_overhead>
+ *  mtu <mtu>
+ *  cpu <cpu_id>
+ */
+static void
+cmd_tmgr(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct tmgr_port_params p;
+	char *name;
+	struct tmgr_port *tmgr_port;
+	int i;
+
+	if (n_tokens != 19) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	name = tokens[1];
+
+	if (strcmp(tokens[2], "rate") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rate");
+		return;
+	}
+
+	if (parser_read_uint32(&p.rate, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "rate");
+		return;
+	}
+
+	if (strcmp(tokens[4], "spp") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "spp");
+		return;
+	}
+
+	if (parser_read_uint32(&p.n_subports_per_port, tokens[5]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "n_subports_per_port");
+		return;
+	}
+
+	if (strcmp(tokens[6], "pps") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pps");
+		return;
+	}
+
+	if (parser_read_uint32(&p.n_pipes_per_subport, tokens[7]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "n_pipes_per_subport");
+		return;
+	}
+
+	if (strcmp(tokens[8], "qsize") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "qsize");
+		return;
+	}
+
+	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
+		if (parser_read_uint16(&p.qsize[i], tokens[9 + i]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "qsize");
+			return;
+		}
+
+	if (strcmp(tokens[13], "fo") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "fo");
+		return;
+	}
+
+	if (parser_read_uint32(&p.frame_overhead, tokens[14]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "frame_overhead");
+		return;
+	}
+
+	if (strcmp(tokens[15], "mtu") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mtu");
+		return;
+	}
+
+	if (parser_read_uint32(&p.mtu, tokens[16]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "mtu");
+		return;
+	}
+
+	if (strcmp(tokens[17], "cpu") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu");
+		return;
+	}
+
+	if (parser_read_uint32(&p.cpu_id, tokens[18]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id");
+		return;
+	}
+
+	tmgr_port = tmgr_port_create(name, &p);
+	if (tmgr_port == NULL) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
+ * tmgr <tmgr_name> subport <subport_id>
+ *  profile <subport_profile_id>
+ */
+static void
+cmd_tmgr_subport(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	uint32_t subport_id, subport_profile_id;
+	int status;
+	char *name;
+
+	if (n_tokens != 6) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	name = tokens[1];
+
+	if (parser_read_uint32(&subport_id, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "subport_id");
+		return;
+	}
+
+	if (parser_read_uint32(&subport_profile_id, tokens[5]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "subport_profile_id");
+		return;
+	}
+
+	status = tmgr_subport_config(name, subport_id, subport_profile_id);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
+ * tmgr <tmgr_name> subport <subport_id> pipe
+ *  from <pipe_id_first> to <pipe_id_last>
+ *  profile <pipe_profile_id>
+ */
+static void
+cmd_tmgr_subport_pipe(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	uint32_t subport_id, pipe_id_first, pipe_id_last, pipe_profile_id;
+	int status;
+	char *name;
+
+	if (n_tokens != 11) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	name = tokens[1];
+
+	if (parser_read_uint32(&subport_id, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "subport_id");
+		return;
+	}
+
+	if (strcmp(tokens[4], "pipe") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipe");
+		return;
+	}
+
+	if (strcmp(tokens[5], "from") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "from");
+		return;
+	}
+
+	if (parser_read_uint32(&pipe_id_first, tokens[6]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "pipe_id_first");
+		return;
+	}
+
+	if (strcmp(tokens[7], "to") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "to");
+		return;
+	}
+
+	if (parser_read_uint32(&pipe_id_last, tokens[8]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "pipe_id_last");
+		return;
+	}
+
+	if (strcmp(tokens[9], "profile") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
+		return;
+	}
+
+	if (parser_read_uint32(&pipe_profile_id, tokens[10]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "pipe_profile_id");
+		return;
+	}
+
+	status = tmgr_pipe_config(name, subport_id, pipe_id_first,
+			pipe_id_last, pipe_profile_id);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
 void
 cli_process(char *in, char *out, size_t out_size)
 {
@@ -311,6 +637,40 @@ cli_process(char *in, char *out, size_t out_size)
 		return;
 	}
 
+	if (strcmp(tokens[0], "tmgr") == 0) {
+		if ((n_tokens >= 3) &&
+			(strcmp(tokens[1], "subport") == 0) &&
+			(strcmp(tokens[2], "profile") == 0)) {
+			cmd_tmgr_subport_profile(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
+
+		if ((n_tokens >= 3) &&
+			(strcmp(tokens[1], "pipe") == 0) &&
+			(strcmp(tokens[2], "profile") == 0)) {
+			cmd_tmgr_pipe_profile(tokens, n_tokens, out, out_size);
+			return;
+		}
+
+		if ((n_tokens >= 5) &&
+			(strcmp(tokens[2], "subport") == 0) &&
+			(strcmp(tokens[4], "profile") == 0)) {
+			cmd_tmgr_subport(tokens, n_tokens, out, out_size);
+			return;
+		}
+
+		if ((n_tokens >= 5) &&
+			(strcmp(tokens[2], "subport") == 0) &&
+			(strcmp(tokens[4], "pipe") == 0)) {
+			cmd_tmgr_subport_pipe(tokens, n_tokens, out, out_size);
+			return;
+		}
+
+		cmd_tmgr(tokens, n_tokens, out, out_size);
+		return;
+	}
+
 	snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
 }
 
diff --git a/examples/ip_pipeline/main.c b/examples/ip_pipeline/main.c
index 456f016..490991f 100644
--- a/examples/ip_pipeline/main.c
+++ b/examples/ip_pipeline/main.c
@@ -15,6 +15,7 @@
 #include "link.h"
 #include "mempool.h"
 #include "swq.h"
+#include "tmgr.h"
 
 static const char usage[] =
 	"%s EAL_ARGS -- [-h HOST] [-p PORT] [-s SCRIPT]\n";
@@ -183,6 +184,13 @@ main(int argc, char **argv)
 		return status;
 	}
 
+	/* Traffic Manager */
+	status = tmgr_init();
+	if (status) {
+		printf("Error: TMGR initialization failed (%d)\n", status);
+		return status;
+	}
+
 	/* Script */
 	if (app.script_name)
 		cli_script_process(app.script_name,
diff --git a/examples/ip_pipeline/meson.build b/examples/ip_pipeline/meson.build
index 442f3e3..cb2154c 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -15,4 +15,5 @@ sources = files(
 	'mempool.c',
 	'parser.c',
 	'swq.c',
+	'tmgr.c'
 )
diff --git a/examples/ip_pipeline/tmgr.c b/examples/ip_pipeline/tmgr.c
new file mode 100644
index 0000000..b46ca96
--- /dev/null
+++ b/examples/ip_pipeline/tmgr.c
@@ -0,0 +1,227 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#include <stdlib.h>
+
+#include "tmgr.h"
+
+static struct rte_sched_subport_params
+	subport_profile[TMGR_SUBPORT_PROFILE_MAX];
+
+static uint32_t n_subport_profiles;
+
+static struct rte_sched_pipe_params
+	pipe_profile[TMGR_PIPE_PROFILE_MAX];
+
+static uint32_t n_pipe_profiles;
+
+static struct tmgr_port_list tmgr_port_list;
+
+int
+tmgr_init(void)
+{
+	TAILQ_INIT(&tmgr_port_list);
+
+	return 0;
+}
+
+struct tmgr_port *
+tmgr_port_find(const char *name)
+{
+	struct tmgr_port *tmgr_port;
+
+	if (name == NULL)
+		return NULL;
+
+	TAILQ_FOREACH(tmgr_port, &tmgr_port_list, node)
+		if (strcmp(tmgr_port->name, name) == 0)
+			return tmgr_port;
+
+	return NULL;
+}
+
+int
+tmgr_subport_profile_add(struct rte_sched_subport_params *p)
+{
+	/* Check input params */
+	if (p == NULL)
+		return -1;
+
+	/* Save profile */
+	memcpy(&subport_profile[n_subport_profiles],
+		p,
+		sizeof(*p));
+
+	n_subport_profiles++;
+
+	return 0;
+}
+
+int
+tmgr_pipe_profile_add(struct rte_sched_pipe_params *p)
+{
+	/* Check input params */
+	if (p == NULL)
+		return -1;
+
+	/* Save profile */
+	memcpy(&pipe_profile[n_pipe_profiles],
+		p,
+		sizeof(*p));
+
+	n_pipe_profiles++;
+
+	return 0;
+}
+
+struct tmgr_port *
+tmgr_port_create(const char *name, struct tmgr_port_params *params)
+{
+	struct rte_sched_port_params p;
+	struct tmgr_port *tmgr_port;
+	struct rte_sched_port *s;
+	uint32_t i, j;
+
+	/* Check input params */
+	if ((name == NULL) ||
+		tmgr_port_find(name) ||
+		(params == NULL) ||
+		(params->n_subports_per_port == 0) ||
+		(params->n_pipes_per_subport == 0) ||
+		(params->cpu_id >= RTE_MAX_NUMA_NODES) ||
+		(n_subport_profiles == 0) ||
+		(n_pipe_profiles == 0))
+		return NULL;
+
+	/* Resource create */
+	p.name = name;
+	p.socket = (int) params->cpu_id;
+	p.rate = params->rate;
+	p.mtu = params->mtu;
+	p.frame_overhead = params->frame_overhead;
+	p.n_subports_per_port = params->n_subports_per_port;
+	p.n_pipes_per_subport = params->n_pipes_per_subport;
+
+	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
+		p.qsize[i] = params->qsize[i];
+
+	p.pipe_profiles = pipe_profile;
+	p.n_pipe_profiles = n_pipe_profiles;
+
+	s = rte_sched_port_config(&p);
+	if (s == NULL)
+		return NULL;
+
+	for (i = 0; i < params->n_subports_per_port; i++) {
+		int status;
+
+		status = rte_sched_subport_config(
+			s,
+			i,
+			&subport_profile[0]);
+
+		if (status) {
+			rte_sched_port_free(s);
+			return NULL;
+		}
+
+		for (j = 0; j < params->n_pipes_per_subport; j++) {
+			status = rte_sched_pipe_config(
+				s,
+				i,
+				j,
+				0);
+
+			if (status) {
+				rte_sched_port_free(s);
+				return NULL;
+			}
+		}
+	}
+
+	/* Node allocation */
+	tmgr_port = calloc(1, sizeof(struct tmgr_port));
+	if (tmgr_port == NULL) {
+		rte_sched_port_free(s);
+		return NULL;
+	}
+
+	/* Node fill in */
+	strncpy(tmgr_port->name, name, sizeof(tmgr_port->name));
+	tmgr_port->s = s;
+	tmgr_port->n_subports_per_port = params->n_subports_per_port;
+	tmgr_port->n_pipes_per_subport = params->n_pipes_per_subport;
+
+	/* Node add to list */
+	TAILQ_INSERT_TAIL(&tmgr_port_list, tmgr_port, node);
+
+	return tmgr_port;
+}
+
+int
+tmgr_subport_config(const char *port_name,
+	uint32_t subport_id,
+	uint32_t subport_profile_id)
+{
+	struct tmgr_port *port;
+	int status;
+
+	/* Check input params */
+	if (port_name == NULL)
+		return -1;
+
+	port = tmgr_port_find(port_name);
+	if ((port == NULL) ||
+		(subport_id >= port->n_subports_per_port) ||
+		(subport_profile_id >= n_subport_profiles))
+		return -1;
+
+	/* Resource config */
+	status = rte_sched_subport_config(
+		port->s,
+		subport_id,
+		&subport_profile[subport_profile_id]);
+
+	return status;
+}
+
+int
+tmgr_pipe_config(const char *port_name,
+	uint32_t subport_id,
+	uint32_t pipe_id_first,
+	uint32_t pipe_id_last,
+	uint32_t pipe_profile_id)
+{
+	struct tmgr_port *port;
+	uint32_t i;
+
+	/* Check input params */
+	if (port_name == NULL)
+		return -1;
+
+	port = tmgr_port_find(port_name);
+	if ((port == NULL) ||
+		(subport_id >= port->n_subports_per_port) ||
+		(pipe_id_first >= port->n_pipes_per_subport) ||
+		(pipe_id_last >= port->n_pipes_per_subport) ||
+		(pipe_id_first > pipe_id_last) ||
+		(pipe_profile_id >= n_pipe_profiles))
+		return -1;
+
+	/* Resource config */
+	for (i = pipe_id_first; i <= pipe_id_last; i++) {
+		int status;
+
+		status = rte_sched_pipe_config(
+			port->s,
+			subport_id,
+			i,
+			(int) pipe_profile_id);
+
+		if (status)
+			return status;
+	}
+
+	return 0;
+}
diff --git a/examples/ip_pipeline/tmgr.h b/examples/ip_pipeline/tmgr.h
new file mode 100644
index 0000000..0b497e7
--- /dev/null
+++ b/examples/ip_pipeline/tmgr.h
@@ -0,0 +1,70 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#ifndef _INCLUDE_TMGR_H_
+#define _INCLUDE_TMGR_H_
+
+#include <stdint.h>
+#include <sys/queue.h>
+
+#include <rte_sched.h>
+
+#include "common.h"
+
+#ifndef TMGR_SUBPORT_PROFILE_MAX
+#define TMGR_SUBPORT_PROFILE_MAX                           256
+#endif
+
+#ifndef TMGR_PIPE_PROFILE_MAX
+#define TMGR_PIPE_PROFILE_MAX                              256
+#endif
+
+struct tmgr_port {
+	TAILQ_ENTRY(tmgr_port) node;
+	char name[NAME_SIZE];
+	struct rte_sched_port *s;
+	uint32_t n_subports_per_port;
+	uint32_t n_pipes_per_subport;
+};
+
+TAILQ_HEAD(tmgr_port_list, tmgr_port);
+
+int
+tmgr_init(void);
+
+struct tmgr_port *
+tmgr_port_find(const char *name);
+
+struct tmgr_port_params {
+	uint32_t rate;
+	uint32_t n_subports_per_port;
+	uint32_t n_pipes_per_subport;
+	uint16_t qsize[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
+	uint32_t frame_overhead;
+	uint32_t mtu;
+	uint32_t cpu_id;
+};
+
+int
+tmgr_subport_profile_add(struct rte_sched_subport_params *p);
+
+int
+tmgr_pipe_profile_add(struct rte_sched_pipe_params *p);
+
+struct tmgr_port *
+tmgr_port_create(const char *name, struct tmgr_port_params *params);
+
+int
+tmgr_subport_config(const char *port_name,
+	uint32_t subport_id,
+	uint32_t subport_profile_id);
+
+int
+tmgr_pipe_config(const char *port_name,
+	uint32_t subport_id,
+	uint32_t pipe_id_first,
+	uint32_t pipe_id_last,
+	uint32_t pipe_profile_id);
+
+#endif /* _INCLUDE_TMGR_H_ */
-- 
2.9.3

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

* [dpdk-dev] [PATCH v3 23/44] ip_pipeline: add tap object
  2018-03-16 17:58       ` [dpdk-dev] [PATCH v3 00/44] ip_pipeline: refactoring Jasvinder Singh
                           ` (21 preceding siblings ...)
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 22/44] ip_pipeline: add traffic manager object Jasvinder Singh
@ 2018-03-16 17:58         ` Jasvinder Singh
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 24/44] ip_pipeline: add kni object Jasvinder Singh
                           ` (20 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-16 17:58 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Kevin Laatz

Add tap object implementation to the application

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
---
 examples/ip_pipeline/Makefile    |  1 +
 examples/ip_pipeline/cli.c       | 32 +++++++++++++
 examples/ip_pipeline/main.c      |  8 ++++
 examples/ip_pipeline/meson.build |  1 +
 examples/ip_pipeline/tap.c       | 97 ++++++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/tap.h       | 29 ++++++++++++
 6 files changed, 168 insertions(+)
 create mode 100644 examples/ip_pipeline/tap.c
 create mode 100644 examples/ip_pipeline/tap.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index 35e4302..0f6bb78 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -12,6 +12,7 @@ SRCS-y += main.c
 SRCS-y += mempool.c
 SRCS-y += parser.c
 SRCS-y += swq.c
+SRCS-y += tap.c
 SRCS-y += tmgr.c
 #SRCS-y += thread.c
 
diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index b895d60..a3b1ffd 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -14,6 +14,7 @@
 #include "mempool.h"
 #include "parser.h"
 #include "swq.h"
+#include "tap.h"
 #include "tmgr.h"
 
 #ifndef CMD_MAX_TOKENS
@@ -603,6 +604,32 @@ cmd_tmgr_subport_pipe(char **tokens,
 	}
 }
 
+/**
+ * tap <tap_name>
+ */
+static void
+cmd_tap(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	char *name;
+	struct tap *tap;
+
+	if (n_tokens != 2) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	name = tokens[1];
+
+	tap = tap_create(name);
+	if (tap == NULL) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
 void
 cli_process(char *in, char *out, size_t out_size)
 {
@@ -671,6 +698,11 @@ cli_process(char *in, char *out, size_t out_size)
 		return;
 	}
 
+	if (strcmp(tokens[0], "tap") == 0) {
+		cmd_tap(tokens, n_tokens, out, out_size);
+		return;
+	}
+
 	snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
 }
 
diff --git a/examples/ip_pipeline/main.c b/examples/ip_pipeline/main.c
index 490991f..33c3354 100644
--- a/examples/ip_pipeline/main.c
+++ b/examples/ip_pipeline/main.c
@@ -15,6 +15,7 @@
 #include "link.h"
 #include "mempool.h"
 #include "swq.h"
+#include "tap.h"
 #include "tmgr.h"
 
 static const char usage[] =
@@ -191,6 +192,13 @@ main(int argc, char **argv)
 		return status;
 	}
 
+	/* TAP */
+	status = tap_init();
+	if (status) {
+		printf("Error: TAP initialization failed (%d)\n", status);
+		return status;
+	}
+
 	/* Script */
 	if (app.script_name)
 		cli_script_process(app.script_name,
diff --git a/examples/ip_pipeline/meson.build b/examples/ip_pipeline/meson.build
index cb2154c..e875811 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -15,5 +15,6 @@ sources = files(
 	'mempool.c',
 	'parser.c',
 	'swq.c',
+	'tap.c',
 	'tmgr.c'
 )
diff --git a/examples/ip_pipeline/tap.c b/examples/ip_pipeline/tap.c
new file mode 100644
index 0000000..5b34032
--- /dev/null
+++ b/examples/ip_pipeline/tap.c
@@ -0,0 +1,97 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#include <netinet/in.h>
+#ifdef RTE_EXEC_ENV_LINUXAPP
+#include <linux/if.h>
+#include <linux/if_tun.h>
+#endif
+#include <sys/ioctl.h>
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "tap.h"
+
+#define TAP_DEV                                            "/dev/net/tun"
+
+static struct tap_list tap_list;
+
+int
+tap_init(void)
+{
+	TAILQ_INIT(&tap_list);
+
+	return 0;
+}
+
+struct tap *
+tap_find(const char *name)
+{
+	struct tap *tap;
+
+	if (name == NULL)
+		return NULL;
+
+	TAILQ_FOREACH(tap, &tap_list, node)
+		if (strcmp(tap->name, name) == 0)
+			return tap;
+
+	return NULL;
+}
+
+#ifndef RTE_EXEC_ENV_LINUXAPP
+
+struct tap *
+tap_create(const char *name __rte_unused)
+{
+	return NULL;
+}
+
+#else
+
+struct tap *
+tap_create(const char *name)
+{
+	struct tap *tap;
+	struct ifreq ifr;
+	int fd, status;
+
+	/* Check input params */
+	if ((name == NULL) ||
+		tap_find(name))
+		return NULL;
+
+	/* Resource create */
+	fd = open(TAP_DEV, O_RDWR | O_NONBLOCK);
+	if (fd < 0)
+		return NULL;
+
+	memset(&ifr, 0, sizeof(ifr));
+	ifr.ifr_flags = IFF_TAP | IFF_NO_PI; /* No packet information */
+	snprintf(ifr.ifr_name, IFNAMSIZ, "%s", name);
+
+	status = ioctl(fd, TUNSETIFF, (void *) &ifr);
+	if (status < 0)
+		return NULL;
+
+	/* Node allocation */
+	tap = calloc(1, sizeof(struct tap));
+	if (tap == NULL)
+		return NULL;
+
+	/* Node fill in */
+	strncpy(tap->name, name, sizeof(tap->name));
+	tap->fd = fd;
+
+	/* Node add to list */
+	TAILQ_INSERT_TAIL(&tap_list, tap, node);
+
+	return tap;
+}
+
+#endif
diff --git a/examples/ip_pipeline/tap.h b/examples/ip_pipeline/tap.h
new file mode 100644
index 0000000..0dce72f
--- /dev/null
+++ b/examples/ip_pipeline/tap.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#ifndef _INCLUDE_TAP_H_
+#define _INCLUDE_TAP_H_
+
+#include <sys/queue.h>
+
+#include "common.h"
+
+struct tap {
+	TAILQ_ENTRY(tap) node;
+	char name[NAME_SIZE];
+	int fd;
+};
+
+TAILQ_HEAD(tap_list, tap);
+
+int
+tap_init(void);
+
+struct tap *
+tap_find(const char *name);
+
+struct tap *
+tap_create(const char *name);
+
+#endif /* _INCLUDE_TAP_H_ */
-- 
2.9.3

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

* [dpdk-dev] [PATCH v3 24/44] ip_pipeline: add kni object
  2018-03-16 17:58       ` [dpdk-dev] [PATCH v3 00/44] ip_pipeline: refactoring Jasvinder Singh
                           ` (22 preceding siblings ...)
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 23/44] ip_pipeline: add tap object Jasvinder Singh
@ 2018-03-16 17:58         ` Jasvinder Singh
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 25/44] ip_pipeline: add action profile object Jasvinder Singh
                           ` (19 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-16 17:58 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Kevin Laatz

Add kni object implementation to the application.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
---
 examples/ip_pipeline/Makefile    |   1 +
 examples/ip_pipeline/cli.c       |  65 +++++++++++++++
 examples/ip_pipeline/kni.c       | 167 +++++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/kni.h       |  44 +++++++++++
 examples/ip_pipeline/main.c      |  10 +++
 examples/ip_pipeline/meson.build |   1 +
 6 files changed, 288 insertions(+)
 create mode 100644 examples/ip_pipeline/kni.c
 create mode 100644 examples/ip_pipeline/kni.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index 0f6bb78..dc56ebf 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -7,6 +7,7 @@ APP = ip_pipeline
 # all source are stored in SRCS-y
 SRCS-y := cli.c
 SRCS-y += conn.c
+SRCS-y += kni.c
 SRCS-y += link.c
 SRCS-y += main.c
 SRCS-y += mempool.c
diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index a3b1ffd..ab57c33 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -10,6 +10,7 @@
 #include <rte_common.h>
 
 #include "cli.h"
+#include "kni.h"
 #include "link.h"
 #include "mempool.h"
 #include "parser.h"
@@ -630,6 +631,65 @@ cmd_tap(char **tokens,
 	}
 }
 
+/**
+ * kni <kni_name>
+ *  link <link_name>
+ *  mempool <mempool_name>
+ *  [thread <thread_id>]
+ */
+static void
+cmd_kni(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct kni_params p;
+	char *name;
+	struct kni *kni;
+
+	if ((n_tokens != 6) && (n_tokens != 8)) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	name = tokens[1];
+
+	if (strcmp(tokens[2], "link") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "link");
+		return;
+	}
+
+	p.link_name = tokens[3];
+
+	if (strcmp(tokens[4], "mempool") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mempool");
+		return;
+	}
+
+	p.mempool_name = tokens[5];
+
+	if (n_tokens == 8) {
+		if (strcmp(tokens[6], "thread") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "thread");
+			return;
+		}
+
+		if (parser_read_uint32(&p.thread_id, tokens[7]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
+			return;
+		}
+
+		p.force_bind = 1;
+	} else
+		p.force_bind = 0;
+
+	kni = kni_create(name, &p);
+	if (kni == NULL) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
 void
 cli_process(char *in, char *out, size_t out_size)
 {
@@ -703,6 +763,11 @@ cli_process(char *in, char *out, size_t out_size)
 		return;
 	}
 
+	if (strcmp(tokens[0], "kni") == 0) {
+		cmd_kni(tokens, n_tokens, out, out_size);
+		return;
+	}
+
 	snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
 }
 
diff --git a/examples/ip_pipeline/kni.c b/examples/ip_pipeline/kni.c
new file mode 100644
index 0000000..c8a9fbe
--- /dev/null
+++ b/examples/ip_pipeline/kni.c
@@ -0,0 +1,167 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <rte_ethdev.h>
+#include <rte_bus_pci.h>
+
+#include "kni.h"
+#include "mempool.h"
+#include "link.h"
+
+static struct kni_list kni_list;
+
+#ifndef KNI_MAX
+#define KNI_MAX                                            16
+#endif
+
+int
+kni_init(void)
+{
+	TAILQ_INIT(&kni_list);
+
+#ifdef RTE_LIBRTE_KNI
+	rte_kni_init(KNI_MAX);
+#endif
+
+	return 0;
+}
+
+struct kni *
+kni_find(const char *name)
+{
+	struct kni *kni;
+
+	if (name == NULL)
+		return NULL;
+
+	TAILQ_FOREACH(kni, &kni_list, node)
+		if (strcmp(kni->name, name) == 0)
+			return kni;
+
+	return NULL;
+}
+
+#ifndef RTE_LIBRTE_KNI
+
+struct kni *
+kni_create(const char *name __rte_unused,
+	struct kni_params *params __rte_unused)
+{
+	return NULL;
+}
+
+void
+kni_handle_request(void)
+{
+	return 0;
+}
+
+#else
+
+static int
+kni_config_network_interface(uint16_t port_id, uint8_t if_up)
+{
+	int ret = 0;
+
+	if (port_id >= rte_eth_dev_count())
+		return -EINVAL;
+
+	ret = (if_up) ?
+		rte_eth_dev_set_link_up(port_id) :
+		rte_eth_dev_set_link_down(port_id);
+
+	return ret;
+}
+
+static int
+kni_change_mtu(uint16_t port_id, unsigned int new_mtu)
+{
+	int ret;
+
+	if (port_id >= rte_eth_dev_count())
+		return -EINVAL;
+
+	if (new_mtu > ETHER_MAX_LEN)
+		return -EINVAL;
+
+	/* Set new MTU */
+	ret = rte_eth_dev_set_mtu(port_id, new_mtu);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+struct kni *
+kni_create(const char *name, struct kni_params *params)
+{
+	struct rte_eth_dev_info dev_info;
+	struct rte_kni_conf kni_conf;
+	struct rte_kni_ops kni_ops;
+	struct kni *kni;
+	struct mempool *mempool;
+	struct link *link;
+	struct rte_kni *k;
+
+	/* Check input params */
+	if ((name == NULL) ||
+		kni_find(name) ||
+		(params == NULL))
+		return NULL;
+
+	mempool = mempool_find(params->mempool_name);
+	link = link_find(params->link_name);
+	if ((mempool == NULL) ||
+		(link == NULL))
+		return NULL;
+
+	/* Resource create */
+	rte_eth_dev_info_get(link->port_id, &dev_info);
+
+	memset(&kni_conf, 0, sizeof(kni_conf));
+	snprintf(kni_conf.name, RTE_KNI_NAMESIZE, "%s", name);
+	kni_conf.force_bind = params->force_bind;
+	kni_conf.core_id = params->thread_id;
+	kni_conf.group_id = link->port_id;
+	kni_conf.mbuf_size = mempool->buffer_size;
+	kni_conf.addr = dev_info.pci_dev->addr;
+	kni_conf.id = dev_info.pci_dev->id;
+
+	memset(&kni_ops, 0, sizeof(kni_ops));
+	kni_ops.port_id = link->port_id;
+	kni_ops.config_network_if = kni_config_network_interface;
+	kni_ops.change_mtu = kni_change_mtu;
+
+	k = rte_kni_alloc(mempool->m, &kni_conf, &kni_ops);
+	if (k == NULL)
+		return NULL;
+
+	/* Node allocation */
+	kni = calloc(1, sizeof(struct kni));
+	if (kni == NULL)
+		return NULL;
+
+	/* Node fill in */
+	strncpy(kni->name, name, sizeof(kni->name));
+	kni->k = k;
+
+	/* Node add to list */
+	TAILQ_INSERT_TAIL(&kni_list, kni, node);
+
+	return kni;
+}
+
+void
+kni_handle_request(void)
+{
+	struct kni *kni;
+
+	TAILQ_FOREACH(kni, &kni_list, node)
+		rte_kni_handle_request(kni->k);
+}
+
+#endif
diff --git a/examples/ip_pipeline/kni.h b/examples/ip_pipeline/kni.h
new file mode 100644
index 0000000..e53de12
--- /dev/null
+++ b/examples/ip_pipeline/kni.h
@@ -0,0 +1,44 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#ifndef _INCLUDE_KNI_H_
+#define _INCLUDE_KNI_H_
+
+#include <stdint.h>
+#include <sys/queue.h>
+
+#ifdef RTE_LIBRTE_KNI
+#include <rte_kni.h>
+#endif
+
+#include "common.h"
+
+struct kni {
+	TAILQ_ENTRY(kni) node;
+	char name[NAME_SIZE];
+	struct rte_kni *k;
+};
+
+TAILQ_HEAD(kni_list, kni);
+
+int
+kni_init(void);
+
+struct kni *
+kni_find(const char *name);
+
+struct kni_params {
+	const char *link_name;
+	const char *mempool_name;
+	int force_bind;
+	uint32_t thread_id;
+};
+
+struct kni *
+kni_create(const char *name, struct kni_params *params);
+
+void
+kni_handle_request(void);
+
+#endif /* _INCLUDE_KNI_H_ */
diff --git a/examples/ip_pipeline/main.c b/examples/ip_pipeline/main.c
index 33c3354..b65762e 100644
--- a/examples/ip_pipeline/main.c
+++ b/examples/ip_pipeline/main.c
@@ -12,6 +12,7 @@
 
 #include "cli.h"
 #include "conn.h"
+#include "kni.h"
 #include "link.h"
 #include "mempool.h"
 #include "swq.h"
@@ -199,6 +200,13 @@ main(int argc, char **argv)
 		return status;
 	}
 
+	/* KNI */
+	status = kni_init();
+	if (status) {
+		printf("Error: KNI initialization failed (%d)\n", status);
+		return status;
+	}
+
 	/* Script */
 	if (app.script_name)
 		cli_script_process(app.script_name,
@@ -210,5 +218,7 @@ main(int argc, char **argv)
 		conn_poll_for_conn(conn);
 
 		conn_poll_for_msg(conn);
+
+		kni_handle_request();
 	}
 }
diff --git a/examples/ip_pipeline/meson.build b/examples/ip_pipeline/meson.build
index e875811..5ad79b2 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -10,6 +10,7 @@ deps += ['pipeline', 'bus_pci']
 sources = files(
 	'cli.c',
 	'conn.c',
+	'kni.c',
 	'link.c',
 	'main.c',
 	'mempool.c',
-- 
2.9.3

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

* [dpdk-dev] [PATCH v3 25/44] ip_pipeline: add action profile object
  2018-03-16 17:58       ` [dpdk-dev] [PATCH v3 00/44] ip_pipeline: refactoring Jasvinder Singh
                           ` (23 preceding siblings ...)
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 24/44] ip_pipeline: add kni object Jasvinder Singh
@ 2018-03-16 17:58         ` Jasvinder Singh
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 26/44] ip_pipeline: add pipeline object Jasvinder Singh
                           ` (18 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-16 17:58 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Fan Zhang

Add action profile object implementation to the application.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Fan Zhang <roy.fan.zhang@intel.com>
---
 examples/ip_pipeline/Makefile    |   4 +-
 examples/ip_pipeline/action.c    | 165 +++++++++++++++++++++
 examples/ip_pipeline/action.h    |  44 ++++++
 examples/ip_pipeline/cli.c       | 309 +++++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/cli.h       |   2 +
 examples/ip_pipeline/main.c      |   8 +
 examples/ip_pipeline/meson.build |   2 +
 7 files changed, 533 insertions(+), 1 deletion(-)
 create mode 100644 examples/ip_pipeline/action.c
 create mode 100644 examples/ip_pipeline/action.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index dc56ebf..d9c8d86 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -5,7 +5,8 @@
 APP = ip_pipeline
 
 # all source are stored in SRCS-y
-SRCS-y := cli.c
+SRCS-y := action.c
+SRCS-y += cli.c
 SRCS-y += conn.c
 SRCS-y += kni.c
 SRCS-y += link.c
@@ -69,6 +70,7 @@ INC += $(sort $(wildcard *.h))
 
 SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) := $(SRCS-y)
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -I$(SRCDIR)
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
diff --git a/examples/ip_pipeline/action.c b/examples/ip_pipeline/action.c
new file mode 100644
index 0000000..c70dd4a
--- /dev/null
+++ b/examples/ip_pipeline/action.c
@@ -0,0 +1,165 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "action.h"
+
+static struct table_action_profile_list table_action_profile_list;
+
+int
+table_action_profile_init(void)
+{
+	TAILQ_INIT(&table_action_profile_list);
+
+	return 0;
+}
+
+struct table_action_profile *
+table_action_profile_find(const char *name)
+{
+	struct table_action_profile *profile;
+
+	if (name == NULL)
+		return NULL;
+
+	TAILQ_FOREACH(profile, &table_action_profile_list, node)
+		if (strcmp(profile->name, name) == 0)
+			return profile;
+
+	return NULL;
+}
+
+struct table_action_profile *
+table_action_profile_create(const char *name,
+	struct table_action_profile_params *params)
+{
+	struct table_action_profile *profile;
+	struct rte_table_action_profile *ap;
+	int status;
+
+	/* Check input params */
+	if ((name == NULL) ||
+		table_action_profile_find(name) ||
+		(params == NULL) ||
+		((params->action_mask & (1LLU << RTE_TABLE_ACTION_FWD)) == 0))
+		return NULL;
+
+	/* Resource */
+	ap = rte_table_action_profile_create(&params->common);
+	if (ap == NULL)
+		return NULL;
+
+	if (params->action_mask & (1LLU << RTE_TABLE_ACTION_FWD)) {
+		status = rte_table_action_profile_action_register(ap,
+			RTE_TABLE_ACTION_FWD,
+			NULL);
+
+		if (status) {
+			rte_table_action_profile_free(ap);
+			return NULL;
+		}
+	}
+
+	if (params->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) {
+		status = rte_table_action_profile_action_register(ap,
+			RTE_TABLE_ACTION_MTR,
+			&params->mtr);
+
+		if (status) {
+			rte_table_action_profile_free(ap);
+			return NULL;
+		}
+	}
+
+	if (params->action_mask & (1LLU << RTE_TABLE_ACTION_TM)) {
+		status = rte_table_action_profile_action_register(ap,
+			RTE_TABLE_ACTION_TM,
+			&params->tm);
+
+		if (status) {
+			rte_table_action_profile_free(ap);
+			return NULL;
+		}
+	}
+
+	if (params->action_mask & (1LLU << RTE_TABLE_ACTION_ENCAP)) {
+		status = rte_table_action_profile_action_register(ap,
+			RTE_TABLE_ACTION_ENCAP,
+			&params->encap);
+
+		if (status) {
+			rte_table_action_profile_free(ap);
+			return NULL;
+		}
+	}
+
+	if (params->action_mask & (1LLU << RTE_TABLE_ACTION_NAT)) {
+		status = rte_table_action_profile_action_register(ap,
+			RTE_TABLE_ACTION_NAT,
+			&params->nat);
+
+		if (status) {
+			rte_table_action_profile_free(ap);
+			return NULL;
+		}
+	}
+
+	if (params->action_mask & (1LLU << RTE_TABLE_ACTION_TTL)) {
+		status = rte_table_action_profile_action_register(ap,
+			RTE_TABLE_ACTION_TTL,
+			&params->ttl);
+
+		if (status) {
+			rte_table_action_profile_free(ap);
+			return NULL;
+		}
+	}
+
+	if (params->action_mask & (1LLU << RTE_TABLE_ACTION_STATS)) {
+		status = rte_table_action_profile_action_register(ap,
+			RTE_TABLE_ACTION_STATS,
+			&params->stats);
+
+		if (status) {
+			rte_table_action_profile_free(ap);
+			return NULL;
+		}
+	}
+	if (params->action_mask & (1LLU << RTE_TABLE_ACTION_TIME)) {
+		status = rte_table_action_profile_action_register(ap,
+			RTE_TABLE_ACTION_TIME,
+			NULL);
+
+		if (status) {
+			rte_table_action_profile_free(ap);
+			return NULL;
+		}
+	}
+
+	status = rte_table_action_profile_freeze(ap);
+	if (status) {
+		rte_table_action_profile_free(ap);
+		return NULL;
+	}
+
+	/* Node allocation */
+	profile = calloc(1, sizeof(struct table_action_profile));
+	if (profile == NULL) {
+		rte_table_action_profile_free(ap);
+		return NULL;
+	}
+
+	/* Node fill in */
+	strncpy(profile->name, name, sizeof(profile->name));
+	memcpy(&profile->params, params, sizeof(*params));
+	profile->ap = ap;
+
+	/* Node add to list */
+	TAILQ_INSERT_TAIL(&table_action_profile_list, profile, node);
+
+	return profile;
+}
diff --git a/examples/ip_pipeline/action.h b/examples/ip_pipeline/action.h
new file mode 100644
index 0000000..5720b3e
--- /dev/null
+++ b/examples/ip_pipeline/action.h
@@ -0,0 +1,44 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#ifndef _INCLUDE_ACTION_H_
+#define _INCLUDE_ACTION_H_
+
+#include <sys/queue.h>
+
+#include <rte_table_action.h>
+
+#include "common.h"
+
+struct table_action_profile_params {
+	uint64_t action_mask;
+	struct rte_table_action_common_config common;
+	struct rte_table_action_mtr_config mtr;
+	struct rte_table_action_tm_config tm;
+	struct rte_table_action_encap_config encap;
+	struct rte_table_action_nat_config nat;
+	struct rte_table_action_ttl_config ttl;
+	struct rte_table_action_stats_config stats;
+};
+
+struct table_action_profile {
+	TAILQ_ENTRY(table_action_profile) node;
+	char name[NAME_SIZE];
+	struct table_action_profile_params params;
+	struct rte_table_action_profile *ap;
+};
+
+TAILQ_HEAD(table_action_profile_list, table_action_profile);
+
+int
+table_action_profile_init(void);
+
+struct table_action_profile *
+table_action_profile_find(const char *name);
+
+struct table_action_profile *
+table_action_profile_create(const char *name,
+	struct table_action_profile_params *params);
+
+#endif /* _INCLUDE_ACTION_H_ */
diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index ab57c33..b01177b 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -690,6 +690,310 @@ cmd_kni(char **tokens,
 	}
 }
 
+/**
+ * table action profile <profile_name>
+ *  ipv4 | ipv6
+ *  offset <ip_offset>
+ *      fwd
+ *  [meter srtcm | trtcm
+ *      tc <n_tc>
+ *      stats none | pkts | bytes | both]
+ *      [tm spp <n_subports_per_port> pps <n_pipes_per_subport>]
+ *  [encap ether | vlan | qinq | mpls | pppoe | esp | gre | gtpu]
+ *  [nat src | dst
+ *      proto udp | tcp]
+ *  [ttl drop | fwd
+ *              stats none | pkts]
+ *  [stats pkts | bytes | both]
+ *      [time]
+ */
+static void
+cmd_table_action_profile(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct table_action_profile_params p;
+	struct table_action_profile *ap;
+	char *name;
+	uint32_t t0;
+
+	memset(&p, 0, sizeof(p));
+
+	if (n_tokens < 8) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	if (strcmp(tokens[1], "action") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "action");
+		return;
+	}
+
+	if (strcmp(tokens[2], "profile") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
+		return;
+	}
+
+	name = tokens[3];
+
+	if (strcmp(tokens[4], "ipv4") == 0)
+		p.common.ip_version = 1;
+	else if (strcmp(tokens[4], "ipv6") == 0)
+		p.common.ip_version = 0;
+	else {
+		snprintf(out, out_size, MSG_ARG_INVALID, "ipv4 or ipv6");
+		return;
+	}
+
+	if (strcmp(tokens[5], "offset") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
+		return;
+	}
+
+	if (parser_read_uint32(&p.common.ip_offset, tokens[6]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "ip_offset");
+		return;
+	}
+
+	if (strcmp(tokens[7], "fwd") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "fwd");
+		return;
+	}
+
+	p.action_mask |= 1LLU << RTE_TABLE_ACTION_FWD;
+
+	t0 = 8;
+	if ((t0 < n_tokens) && (strcmp(tokens[t0], "meter") == 0)) {
+		if (n_tokens < t0 + 6) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"table action profile meter");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 1], "srtcm") == 0)
+			p.mtr.alg = RTE_TABLE_ACTION_METER_SRTCM;
+		else if (strcmp(tokens[t0 + 1], "trtcm") == 0)
+			p.mtr.alg = RTE_TABLE_ACTION_METER_TRTCM;
+		else {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+				"srtcm or trtcm");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 2], "tc") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc");
+			return;
+		}
+
+		if (parser_read_uint32(&p.mtr.n_tc, tokens[t0 + 3]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "n_tc");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 4], "stats") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 5], "none") == 0) {
+			p.mtr.n_packets_enabled = 0;
+			p.mtr.n_bytes_enabled = 0;
+		} else if (strcmp(tokens[t0 + 5], "pkts") == 0) {
+			p.mtr.n_packets_enabled = 1;
+			p.mtr.n_bytes_enabled = 0;
+		} else if (strcmp(tokens[t0 + 5], "bytes") == 0) {
+			p.mtr.n_packets_enabled = 0;
+			p.mtr.n_bytes_enabled = 1;
+		} else if (strcmp(tokens[t0 + 5], "both") == 0) {
+			p.mtr.n_packets_enabled = 1;
+			p.mtr.n_bytes_enabled = 1;
+		} else {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+				"none or pkts or bytes or both");
+			return;
+		}
+
+		p.action_mask |= 1LLU << RTE_TABLE_ACTION_MTR;
+		t0 += 6;
+	} /* meter */
+
+	if ((t0 < n_tokens) && (strcmp(tokens[t0], "tm") == 0)) {
+		if (n_tokens < t0 + 5) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"table action profile tm");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 1], "spp") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "spp");
+			return;
+		}
+
+		if (parser_read_uint32(&p.tm.n_subports_per_port,
+			tokens[t0 + 2]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID,
+				"n_subports_per_port");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 3], "pps") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pps");
+			return;
+		}
+
+		if (parser_read_uint32(&p.tm.n_pipes_per_subport,
+			tokens[t0 + 4]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID,
+				"n_pipes_per_subport");
+			return;
+		}
+
+		p.action_mask |= 1LLU << RTE_TABLE_ACTION_TM;
+		t0 += 5;
+	} /* tm */
+
+	if ((t0 < n_tokens) && (strcmp(tokens[t0], "encap") == 0)) {
+		if (n_tokens < t0 + 2) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"action profile encap");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 1], "ether") == 0)
+			p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_ETHER;
+		else if (strcmp(tokens[t0 + 1], "vlan") == 0)
+			p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_VLAN;
+		else if (strcmp(tokens[t0 + 1], "qinq") == 0)
+			p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_QINQ;
+		else if (strcmp(tokens[t0 + 1], "mpls") == 0)
+			p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_MPLS;
+		else if (strcmp(tokens[t0 + 1], "pppoe") == 0)
+			p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_PPPOE;
+		else {
+			snprintf(out, out_size, MSG_ARG_MISMATCH, "encap");
+			return;
+		}
+
+		p.action_mask |= 1LLU << RTE_TABLE_ACTION_ENCAP;
+		t0 += 2;
+	} /* encap */
+
+	if ((t0 < n_tokens) && (strcmp(tokens[t0], "nat") == 0)) {
+		if (n_tokens < t0 + 4) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"table action profile nat");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 1], "src") == 0)
+			p.nat.source_nat = 1;
+		else if (strcmp(tokens[t0 + 1], "dst") == 0)
+			p.nat.source_nat = 0;
+		else {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+				"src or dst");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 2], "proto") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "proto");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 3], "tcp") == 0)
+			p.nat.proto = 0x06;
+		else if (strcmp(tokens[t0 + 3], "udp") == 0)
+			p.nat.proto = 0x11;
+		else {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+				"tcp or udp");
+			return;
+		}
+
+		p.action_mask |= 1LLU << RTE_TABLE_ACTION_NAT;
+		t0 += 4;
+	} /* nat */
+
+	if ((t0 < n_tokens) && (strcmp(tokens[t0], "ttl") == 0)) {
+		if (n_tokens < t0 + 4) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"table action profile ttl");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 1], "drop") == 0)
+			p.ttl.drop = 1;
+		else if (strcmp(tokens[t0 + 1], "fwd") == 0)
+			p.ttl.drop = 0;
+		else {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+				"drop or fwd");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 2], "stats") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 3], "none") == 0)
+			p.ttl.n_packets_enabled = 0;
+		else if (strcmp(tokens[t0 + 3], "pkts") == 0)
+			p.ttl.n_packets_enabled = 1;
+		else {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+				"none or pkts");
+			return;
+		}
+
+		p.action_mask |= 1LLU << RTE_TABLE_ACTION_TTL;
+		t0 += 4;
+	} /* ttl */
+
+	if ((t0 < n_tokens) && (strcmp(tokens[t0], "stats") == 0)) {
+		if (n_tokens < t0 + 2) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"table action profile stats");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 1], "pkts") == 0) {
+			p.stats.n_packets_enabled = 1;
+			p.stats.n_bytes_enabled = 0;
+		} else if (strcmp(tokens[t0 + 1], "bytes") == 0) {
+			p.stats.n_packets_enabled = 0;
+			p.stats.n_bytes_enabled = 1;
+		} else if (strcmp(tokens[t0 + 1], "both") == 0) {
+			p.stats.n_packets_enabled = 1;
+			p.stats.n_bytes_enabled = 1;
+		} else {
+			snprintf(out, out_size,	MSG_ARG_NOT_FOUND,
+				"pkts or bytes or both");
+			return;
+		}
+
+		p.action_mask |= 1LLU << RTE_TABLE_ACTION_STATS;
+		t0 += 2;
+	} /* stats */
+
+	if ((t0 < n_tokens) && (strcmp(tokens[t0], "time") == 0)) {
+		p.action_mask |= 1LLU << RTE_TABLE_ACTION_TIME;
+		t0 += 1;
+	} /* time */
+
+	if (t0 < n_tokens) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	ap = table_action_profile_create(name, &p);
+	if (ap == NULL) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
 void
 cli_process(char *in, char *out, size_t out_size)
 {
@@ -768,6 +1072,11 @@ cli_process(char *in, char *out, size_t out_size)
 		return;
 	}
 
+	if (strcmp(tokens[0], "action") == 0) {
+		cmd_table_action_profile(tokens, n_tokens, out, out_size);
+		return;
+	}
+
 	snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
 }
 
diff --git a/examples/ip_pipeline/cli.h b/examples/ip_pipeline/cli.h
index 992e4c3..02564a6 100644
--- a/examples/ip_pipeline/cli.h
+++ b/examples/ip_pipeline/cli.h
@@ -7,6 +7,8 @@
 
 #include <stddef.h>
 
+#include "action.h"
+
 void
 cli_process(char *in, char *out, size_t out_size);
 
diff --git a/examples/ip_pipeline/main.c b/examples/ip_pipeline/main.c
index b65762e..24b74cf 100644
--- a/examples/ip_pipeline/main.c
+++ b/examples/ip_pipeline/main.c
@@ -207,6 +207,14 @@ main(int argc, char **argv)
 		return status;
 	}
 
+	/* Action profile */
+	status = table_action_profile_init();
+	if (status) {
+		printf("Error: Action profile initialization failed (%d)\n",
+			status);
+		return status;
+	}
+
 	/* Script */
 	if (app.script_name)
 		cli_script_process(app.script_name,
diff --git a/examples/ip_pipeline/meson.build b/examples/ip_pipeline/meson.build
index 5ad79b2..fb1b61d 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -7,7 +7,9 @@
 # DPDK instance, use 'make'
 
 deps += ['pipeline', 'bus_pci']
+allow_experimental_apis = true
 sources = files(
+	'action.c',
 	'cli.c',
 	'conn.c',
 	'kni.c',
-- 
2.9.3

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

* [dpdk-dev] [PATCH v3 26/44] ip_pipeline: add pipeline object
  2018-03-16 17:58       ` [dpdk-dev] [PATCH v3 00/44] ip_pipeline: refactoring Jasvinder Singh
                           ` (24 preceding siblings ...)
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 25/44] ip_pipeline: add action profile object Jasvinder Singh
@ 2018-03-16 17:58         ` Jasvinder Singh
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 27/44] ip_pipeline: add threads Jasvinder Singh
                           ` (17 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-16 17:58 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add pipeline object implementation to the application.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/Makefile    |   1 +
 examples/ip_pipeline/cli.c       | 786 +++++++++++++++++++++++++++++++++
 examples/ip_pipeline/cli.h       |   2 -
 examples/ip_pipeline/main.c      |   8 +
 examples/ip_pipeline/meson.build |   1 +
 examples/ip_pipeline/pipeline.c  | 930 +++++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/pipeline.h  | 265 +++++++++++
 7 files changed, 1991 insertions(+), 2 deletions(-)
 create mode 100644 examples/ip_pipeline/pipeline.c
 create mode 100644 examples/ip_pipeline/pipeline.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index d9c8d86..033319d 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -13,6 +13,7 @@ SRCS-y += link.c
 SRCS-y += main.c
 SRCS-y += mempool.c
 SRCS-y += parser.c
+SRCS-y += pipeline.c
 SRCS-y += swq.c
 SRCS-y += tap.c
 SRCS-y += tmgr.c
diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index b01177b..c82bbc3 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -14,6 +14,7 @@
 #include "link.h"
 #include "mempool.h"
 #include "parser.h"
+#include "pipeline.h"
 #include "swq.h"
 #include "tap.h"
 #include "tmgr.h"
@@ -994,6 +995,751 @@ cmd_table_action_profile(char **tokens,
 	}
 }
 
+/**
+ * pipeline <pipeline_name>
+ *  period <timer_period_ms>
+ *  offset_port_id <offset_port_id>
+ *  cpu <cpu_id>
+ */
+static void
+cmd_pipeline(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct pipeline_params p;
+	char *name;
+	struct pipeline *pipeline;
+
+	if (n_tokens != 8) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	name = tokens[1];
+
+	if (strcmp(tokens[2], "period") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "period");
+		return;
+	}
+
+	if (parser_read_uint32(&p.timer_period_ms, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "timer_period_ms");
+		return;
+	}
+
+	if (strcmp(tokens[4], "offset_port_id") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset_port_id");
+		return;
+	}
+
+	if (parser_read_uint32(&p.offset_port_id, tokens[5]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "offset_port_id");
+		return;
+	}
+
+	if (strcmp(tokens[6], "cpu") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu");
+		return;
+	}
+
+	if (parser_read_uint32(&p.cpu_id, tokens[7]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id");
+		return;
+	}
+
+	pipeline = pipeline_create(name, &p);
+	if (pipeline == NULL) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
+ * pipeline <pipeline_name> port in
+ *  bsz <burst_size>
+ *  link <link_name> rxq <queue_id>
+ *  | swq <swq_name>
+ *  | tmgr <tmgr_name>
+ *  | tap <tap_name> mempool <mempool_name> mtu <mtu>
+ *  | kni <kni_name>
+ *  | source <source_name> mempool <mempool_name> file <file_name>
+ *      [disabled]
+ */
+static void
+cmd_pipeline_port_in(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct port_in_params p;
+	char *pipeline_name;
+	uint32_t t0;
+	int enabled, status;
+
+	if (n_tokens < 7) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "port") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
+		return;
+	}
+
+	if (strcmp(tokens[3], "in") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
+		return;
+	}
+
+	if (strcmp(tokens[4], "bsz") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
+		return;
+	}
+
+	if (parser_read_uint32(&p.burst_size, tokens[5]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "burst_size");
+		return;
+	}
+
+	t0 = 6;
+
+	if (strcmp(tokens[t0], "link") == 0) {
+		if (n_tokens < t0 + 4) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline port in link");
+			return;
+		}
+
+		p.type = PORT_IN_RXQ;
+
+		p.dev_name = tokens[t0 + 1];
+
+		if (strcmp(tokens[t0 + 2], "rxq") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rxq");
+			return;
+		}
+
+		if (parser_read_uint16(&p.rxq.queue_id, tokens[t0 + 3]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID,
+				"queue_id");
+			return;
+		}
+		t0 += 4;
+	} else if (strcmp(tokens[t0], "swq") == 0) {
+		if (n_tokens < t0 + 2) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline port in swq");
+			return;
+		}
+
+		p.type = PORT_IN_SWQ;
+
+		p.dev_name = tokens[t0 + 1];
+
+		t0 += 2;
+	} else if (strcmp(tokens[t0], "tmgr") == 0) {
+		if (n_tokens < t0 + 2) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline port in tmgr");
+			return;
+		}
+
+		p.type = PORT_IN_TMGR;
+
+		p.dev_name = tokens[t0 + 1];
+
+		t0 += 2;
+	} else if (strcmp(tokens[t0], "tap") == 0) {
+		if (n_tokens < t0 + 6) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline port in tap");
+			return;
+		}
+
+		p.type = PORT_IN_TAP;
+
+		p.dev_name = tokens[t0 + 1];
+
+		if (strcmp(tokens[t0 + 2], "mempool") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+				"mempool");
+			return;
+		}
+
+		p.tap.mempool_name = tokens[t0 + 3];
+
+		if (strcmp(tokens[t0 + 4], "mtu") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+				"mtu");
+			return;
+		}
+
+		if (parser_read_uint32(&p.tap.mtu, tokens[t0 + 5]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "mtu");
+			return;
+		}
+
+		t0 += 6;
+	} else if (strcmp(tokens[t0], "kni") == 0) {
+		if (n_tokens < t0 + 2) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline port in kni");
+			return;
+		}
+
+		p.type = PORT_IN_KNI;
+
+		p.dev_name = tokens[t0 + 1];
+
+		t0 += 2;
+	} else if (strcmp(tokens[t0], "source") == 0) {
+		if (n_tokens < t0 + 6) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline port in source");
+			return;
+		}
+
+		p.type = PORT_IN_SOURCE;
+
+		p.dev_name = tokens[t0 + 1];
+
+		if (strcmp(tokens[t0 + 2], "mempool") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+				"mempool");
+			return;
+		}
+
+		p.source.mempool_name = tokens[t0 + 3];
+
+		if (strcmp(tokens[t0 + 4], "file") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+				"file");
+			return;
+		}
+
+		p.source.file_name = tokens[t0 + 5];
+
+		p.source.n_bytes_per_pkt = 0;
+
+		t0 += 6;
+	} else {
+		snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
+		return;
+	}
+
+	enabled = 1;
+	if ((n_tokens > t0) &&
+		(strcmp(tokens[t0], "disabled") == 0)) {
+		enabled = 0;
+
+		t0 += 1;
+	}
+
+	if (n_tokens != t0) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	status = pipeline_port_in_create(pipeline_name,
+		&p, enabled);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
+ * pipeline <pipeline_name> port out
+ *  bsz <burst_size>
+ *  link <link_name> txq <txq_id>
+ *  | swq <swq_name>
+ *  | tmgr <tmgr_name>
+ *  | tap <tap_name>
+ *  | kni <kni_name>
+ *  | sink <sink_name> [file <file_name>]
+ */
+static void
+cmd_pipeline_port_out(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct port_out_params p;
+	char *pipeline_name;
+	int status;
+
+	memset(&p, 0, sizeof(p));
+
+	if (n_tokens < 7) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "port") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
+		return;
+	}
+
+	if (strcmp(tokens[3], "out") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "out");
+		return;
+	}
+
+	if (strcmp(tokens[4], "bsz") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
+		return;
+	}
+
+	if (parser_read_uint32(&p.burst_size, tokens[5]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "burst_size");
+		return;
+	}
+
+	if (strcmp(tokens[6], "link") == 0) {
+		if (n_tokens != 10) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline port out link");
+			return;
+		}
+
+		p.type = PORT_OUT_TXQ;
+
+		p.dev_name = tokens[7];
+
+		if (strcmp(tokens[8], "txq") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "txq");
+			return;
+		}
+
+		if (parser_read_uint16(&p.txq.queue_id, tokens[9]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "queue_id");
+			return;
+		}
+	} else if (strcmp(tokens[6], "swq") == 0) {
+		if (n_tokens != 8) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline port out swq");
+			return;
+		}
+
+		p.type = PORT_OUT_SWQ;
+
+		p.dev_name = tokens[7];
+	} else if (strcmp(tokens[6], "tmgr") == 0) {
+		if (n_tokens != 8) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline port out tmgr");
+			return;
+		}
+
+		p.type = PORT_OUT_TMGR;
+
+		p.dev_name = tokens[7];
+	} else if (strcmp(tokens[6], "tap") == 0) {
+		if (n_tokens != 8) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline port out tap");
+			return;
+		}
+
+		p.type = PORT_OUT_TAP;
+
+		p.dev_name = tokens[7];
+	} else if (strcmp(tokens[6], "kni") == 0) {
+		if (n_tokens != 8) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline port out kni");
+			return;
+		}
+
+		p.type = PORT_OUT_KNI;
+
+		p.dev_name = tokens[7];
+	} else if (strcmp(tokens[6], "sink") == 0) {
+		if ((n_tokens != 8) && (n_tokens != 10)) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline port out sink");
+			return;
+		}
+
+		p.type = PORT_OUT_SINK;
+
+		p.dev_name = tokens[7];
+
+		if (n_tokens == 8)
+			p.sink.file_name = NULL;
+		else {
+			if (strcmp(tokens[8], "file") != 0) {
+				snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+					"file");
+				return;
+			}
+
+			p.sink.file_name = tokens[9];
+		}
+
+		p.sink.max_n_pkts = 0;
+	} else {
+		snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
+		return;
+	}
+
+	status = pipeline_port_out_create(pipeline_name, &p);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
+ * pipeline <pipeline_name> table
+ *      match
+ *      acl
+ *          ipv4 | ipv6
+ *          offset <ip_header_offset>
+ *          size <n_rules>
+ *      | array
+ *          offset <key_offset>
+ *          size <n_keys>
+ *      | hash
+ *          ext | lru
+ *          key <key_size>
+ *          mask <key_mask>
+ *          offset <key_offset>
+ *          buckets <n_buckets>
+ *          size <n_keys>
+ *      | lpm
+ *          ipv4 | ipv6
+ *          offset <ip_header_offset>
+ *          size <n_rules>
+ *      | stub
+ *  action <action_profile_name>
+ */
+static void
+cmd_pipeline_table(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	uint8_t key_mask[TABLE_RULE_MATCH_SIZE_MAX];
+	struct table_params p;
+	char *pipeline_name;
+	uint32_t t0;
+	int status;
+
+	if (n_tokens < 5) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "table") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
+		return;
+	}
+
+	if (strcmp(tokens[3], "match") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match");
+		return;
+	}
+
+	t0 = 4;
+	if (strcmp(tokens[t0], "acl") == 0) {
+		if (n_tokens < t0 + 6) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline table acl");
+			return;
+		}
+
+		p.match_type = TABLE_ACL;
+
+		if (strcmp(tokens[t0 + 1], "ipv4") == 0)
+			p.match.acl.ip_version = 1;
+		else if (strcmp(tokens[t0 + 1], "ipv6") == 0)
+			p.match.acl.ip_version = 0;
+		else {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+				"ipv4 or ipv6");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 2], "offset") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
+			return;
+		}
+
+		if (parser_read_uint32(&p.match.acl.ip_header_offset,
+			tokens[t0 + 3]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID,
+				"ip_header_offset");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 4], "size") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
+			return;
+		}
+
+		if (parser_read_uint32(&p.match.acl.n_rules,
+			tokens[t0 + 5]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "n_rules");
+			return;
+		}
+
+		t0 += 6;
+	} else if (strcmp(tokens[t0], "array") == 0) {
+		if (n_tokens < t0 + 5) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline table array");
+			return;
+		}
+
+		p.match_type = TABLE_ARRAY;
+
+		if (strcmp(tokens[t0 + 1], "offset") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
+			return;
+		}
+
+		if (parser_read_uint32(&p.match.array.key_offset,
+			tokens[t0 + 2]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 3], "size") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
+			return;
+		}
+
+		if (parser_read_uint32(&p.match.array.n_keys,
+			tokens[t0 + 4]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "n_keys");
+			return;
+		}
+
+		t0 += 5;
+	} else if (strcmp(tokens[t0], "hash") == 0) {
+		uint32_t key_mask_size = TABLE_RULE_MATCH_SIZE_MAX;
+
+		if (n_tokens < t0 + 12) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline table hash");
+			return;
+		}
+
+		p.match_type = TABLE_HASH;
+
+		if (strcmp(tokens[t0 + 1], "ext") == 0)
+			p.match.hash.extendable_bucket = 1;
+		else if (strcmp(tokens[t0 + 1], "lru") == 0)
+			p.match.hash.extendable_bucket = 0;
+		else {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+				"ext or lru");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 2], "key") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "key");
+			return;
+		}
+
+		if ((parser_read_uint32(&p.match.hash.key_size,
+			tokens[t0 + 3]) != 0) ||
+			(p.match.hash.key_size == 0) ||
+			(p.match.hash.key_size > TABLE_RULE_MATCH_SIZE_MAX)) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "key_size");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 4], "mask") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask");
+			return;
+		}
+
+		if ((parse_hex_string(tokens[t0 + 5],
+			key_mask, &key_mask_size) != 0) ||
+			(key_mask_size != p.match.hash.key_size)) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "key_mask");
+			return;
+		}
+		p.match.hash.key_mask = key_mask;
+
+		if (strcmp(tokens[t0 + 6], "offset") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
+			return;
+		}
+
+		if (parser_read_uint32(&p.match.hash.key_offset,
+			tokens[t0 + 7]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 8], "buckets") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "buckets");
+			return;
+		}
+
+		if (parser_read_uint32(&p.match.hash.n_buckets,
+			tokens[t0 + 9]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "n_buckets");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 10], "size") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
+			return;
+		}
+
+		if (parser_read_uint32(&p.match.hash.n_keys,
+			tokens[t0 + 11]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "n_keys");
+			return;
+		}
+
+		t0 += 12;
+	} else if (strcmp(tokens[t0], "lpm") == 0) {
+		if (n_tokens < t0 + 6) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline table lpm");
+			return;
+		}
+
+		p.match_type = TABLE_LPM;
+
+		if (strcmp(tokens[t0 + 1], "ipv4") == 0)
+			p.match.lpm.key_size = 4;
+		else if (strcmp(tokens[t0 + 1], "ipv6") == 0)
+			p.match.lpm.key_size = 16;
+		else {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+				"ipv4 or ipv6");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 2], "offset") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
+			return;
+		}
+
+		if (parser_read_uint32(&p.match.lpm.key_offset,
+			tokens[t0 + 3]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 4], "size") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
+			return;
+		}
+
+		if (parser_read_uint32(&p.match.lpm.n_rules,
+			tokens[t0 + 5]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "n_rules");
+			return;
+		}
+
+		t0 += 6;
+	} else if (strcmp(tokens[t0], "stub") == 0) {
+		if (n_tokens < t0 + 1) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline table stub");
+			return;
+		}
+
+		p.match_type = TABLE_STUB;
+
+		t0 += 1;
+	} else {
+		snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
+		return;
+	}
+
+	if (n_tokens >= t0 + 2) {
+		if (strcmp(tokens[t0], "action") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "action");
+			return;
+		}
+
+		p.action_profile_name = tokens[t0 + 1];
+
+		t0 += 2;
+	}
+
+	if (n_tokens > t0) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	status = pipeline_table_create(pipeline_name, &p);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
+ * pipeline <pipeline_name> port in <port_id> table <table_id>
+ */
+static void
+cmd_pipeline_port_in_table(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	char *pipeline_name;
+	uint32_t port_id, table_id;
+	int status;
+
+	if (n_tokens != 7) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "port") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
+		return;
+	}
+
+	if (strcmp(tokens[3], "in") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
+		return;
+	}
+
+	if (parser_read_uint32(&port_id, tokens[4]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
+		return;
+	}
+
+	if (strcmp(tokens[5], "table") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
+		return;
+	}
+
+	if (parser_read_uint32(&table_id, tokens[6]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
+		return;
+	}
+
+	status = pipeline_port_in_connect_to_table(pipeline_name,
+		port_id,
+		table_id);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
 void
 cli_process(char *in, char *out, size_t out_size)
 {
@@ -1077,6 +1823,46 @@ cli_process(char *in, char *out, size_t out_size)
 		return;
 	}
 
+	if (strcmp(tokens[0], "pipeline") == 0) {
+		if ((n_tokens >= 3) &&
+			(strcmp(tokens[2], "period") == 0)) {
+			cmd_pipeline(tokens, n_tokens, out, out_size);
+			return;
+		}
+
+		if ((n_tokens >= 5) &&
+			(strcmp(tokens[2], "port") == 0) &&
+			(strcmp(tokens[3], "in") == 0) &&
+			(strcmp(tokens[4], "bsz") == 0)) {
+			cmd_pipeline_port_in(tokens, n_tokens, out, out_size);
+			return;
+		}
+
+		if ((n_tokens >= 5) &&
+			(strcmp(tokens[2], "port") == 0) &&
+			(strcmp(tokens[3], "out") == 0) &&
+			(strcmp(tokens[4], "bsz") == 0)) {
+			cmd_pipeline_port_out(tokens, n_tokens, out, out_size);
+			return;
+		}
+
+		if ((n_tokens >= 4) &&
+			(strcmp(tokens[2], "table") == 0) &&
+			(strcmp(tokens[3], "match") == 0)) {
+			cmd_pipeline_table(tokens, n_tokens, out, out_size);
+			return;
+		}
+
+		if ((n_tokens >= 6) &&
+			(strcmp(tokens[2], "port") == 0) &&
+			(strcmp(tokens[3], "in") == 0) &&
+			(strcmp(tokens[5], "table") == 0)) {
+			cmd_pipeline_port_in_table(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
+	}
+
 	snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
 }
 
diff --git a/examples/ip_pipeline/cli.h b/examples/ip_pipeline/cli.h
index 02564a6..992e4c3 100644
--- a/examples/ip_pipeline/cli.h
+++ b/examples/ip_pipeline/cli.h
@@ -7,8 +7,6 @@
 
 #include <stddef.h>
 
-#include "action.h"
-
 void
 cli_process(char *in, char *out, size_t out_size);
 
diff --git a/examples/ip_pipeline/main.c b/examples/ip_pipeline/main.c
index 24b74cf..a7f4486 100644
--- a/examples/ip_pipeline/main.c
+++ b/examples/ip_pipeline/main.c
@@ -15,6 +15,7 @@
 #include "kni.h"
 #include "link.h"
 #include "mempool.h"
+#include "pipeline.h"
 #include "swq.h"
 #include "tap.h"
 #include "tmgr.h"
@@ -215,6 +216,13 @@ main(int argc, char **argv)
 		return status;
 	}
 
+	/* Pipeline */
+	status = pipeline_init();
+	if (status) {
+		printf("Error: Pipeline initialization failed (%d)\n", status);
+		return status;
+	}
+
 	/* Script */
 	if (app.script_name)
 		cli_script_process(app.script_name,
diff --git a/examples/ip_pipeline/meson.build b/examples/ip_pipeline/meson.build
index fb1b61d..2366242 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -17,6 +17,7 @@ sources = files(
 	'main.c',
 	'mempool.c',
 	'parser.c',
+	'pipeline.c',
 	'swq.c',
 	'tap.c',
 	'tmgr.c'
diff --git a/examples/ip_pipeline/pipeline.c b/examples/ip_pipeline/pipeline.c
new file mode 100644
index 0000000..8efc70d
--- /dev/null
+++ b/examples/ip_pipeline/pipeline.c
@@ -0,0 +1,930 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <rte_common.h>
+#include <rte_ip.h>
+#include <rte_tcp.h>
+
+#include <rte_port_ethdev.h>
+#include <rte_port_kni.h>
+#include <rte_port_ring.h>
+#include <rte_port_source_sink.h>
+#include <rte_port_fd.h>
+#include <rte_port_sched.h>
+
+#include <rte_table_acl.h>
+#include <rte_table_array.h>
+#include <rte_table_hash.h>
+#include <rte_table_lpm.h>
+#include <rte_table_lpm_ipv6.h>
+#include <rte_table_stub.h>
+
+#include "kni.h"
+#include "link.h"
+#include "mempool.h"
+#include "pipeline.h"
+#include "tap.h"
+#include "tmgr.h"
+#include "swq.h"
+
+#include "hash_func.h"
+
+#ifndef PIPELINE_MSGQ_SIZE
+#define PIPELINE_MSGQ_SIZE                                 64
+#endif
+
+#ifndef TABLE_LPM_NUMBER_TBL8
+#define TABLE_LPM_NUMBER_TBL8                              256
+#endif
+
+static struct pipeline_list pipeline_list;
+
+int
+pipeline_init(void)
+{
+	TAILQ_INIT(&pipeline_list);
+
+	return 0;
+}
+
+struct pipeline *
+pipeline_find(const char *name)
+{
+	struct pipeline *pipeline;
+
+	if (name == NULL)
+		return NULL;
+
+	TAILQ_FOREACH(pipeline, &pipeline_list, node)
+		if (strcmp(name, pipeline->name) == 0)
+			return pipeline;
+
+	return NULL;
+}
+
+struct pipeline *
+pipeline_create(const char *name, struct pipeline_params *params)
+{
+	char msgq_name[NAME_MAX];
+	struct rte_pipeline_params pp;
+	struct pipeline *pipeline;
+	struct rte_pipeline *p;
+	struct rte_ring *msgq_req;
+	struct rte_ring *msgq_rsp;
+
+	/* Check input params */
+	if ((name == NULL) ||
+		pipeline_find(name) ||
+		(params == NULL) ||
+		(params->timer_period_ms == 0))
+		return NULL;
+
+	/* Resource create */
+	snprintf(msgq_name, sizeof(msgq_name), "%s-MSGQ-REQ", name);
+
+	msgq_req = rte_ring_create(msgq_name,
+		PIPELINE_MSGQ_SIZE,
+		params->cpu_id,
+		RING_F_SP_ENQ | RING_F_SC_DEQ);
+	if (msgq_req == NULL)
+		return NULL;
+
+	snprintf(msgq_name, sizeof(msgq_name), "%s-MSGQ-RSP", name);
+
+	msgq_rsp = rte_ring_create(msgq_name,
+		PIPELINE_MSGQ_SIZE,
+		params->cpu_id,
+		RING_F_SP_ENQ | RING_F_SC_DEQ);
+	if (msgq_rsp == NULL) {
+		rte_ring_free(msgq_req);
+		return NULL;
+	}
+
+	pp.name = name;
+	pp.socket_id = (int) params->cpu_id;
+	pp.offset_port_id = params->offset_port_id;
+
+	p = rte_pipeline_create(&pp);
+	if (p == NULL) {
+		rte_ring_free(msgq_rsp);
+		rte_ring_free(msgq_req);
+		return NULL;
+	}
+
+	/* Node allocation */
+	pipeline = calloc(1, sizeof(struct pipeline));
+	if (pipeline == NULL) {
+		rte_pipeline_free(p);
+		rte_ring_free(msgq_rsp);
+		rte_ring_free(msgq_req);
+		return NULL;
+	}
+
+	/* Node fill in */
+	strncpy(pipeline->name, name, sizeof(pipeline->name));
+	pipeline->p = p;
+	pipeline->n_ports_in = 0;
+	pipeline->n_ports_out = 0;
+	pipeline->n_tables = 0;
+	pipeline->msgq_req = msgq_req;
+	pipeline->msgq_rsp = msgq_rsp;
+	pipeline->timer_period_ms = params->timer_period_ms;
+	pipeline->enabled = 0;
+	pipeline->cpu_id = params->cpu_id;
+
+	/* Node add to list */
+	TAILQ_INSERT_TAIL(&pipeline_list, pipeline, node);
+
+	return pipeline;
+}
+
+int
+pipeline_port_in_create(const char *pipeline_name,
+	struct port_in_params *params,
+	int enabled)
+{
+	struct rte_pipeline_port_in_params p;
+
+	union {
+		struct rte_port_ethdev_reader_params ethdev;
+		struct rte_port_ring_reader_params ring;
+		struct rte_port_sched_reader_params sched;
+		struct rte_port_fd_reader_params fd;
+		struct rte_port_kni_reader_params kni;
+		struct rte_port_source_params source;
+	} pp;
+
+	struct pipeline *pipeline;
+	uint32_t port_id;
+	int status;
+
+	memset(&pp, 0, sizeof(pp));
+
+	/* Check input params */
+	if ((pipeline_name == NULL) ||
+		(params == NULL) ||
+		(params->burst_size == 0) ||
+		(params->burst_size > RTE_PORT_IN_BURST_SIZE_MAX))
+		return -1;
+
+	pipeline = pipeline_find(pipeline_name);
+	if (pipeline == NULL)
+		return -1;
+
+	switch (params->type) {
+	case PORT_IN_RXQ:
+	{
+		struct link *link;
+
+		link = link_find(params->dev_name);
+		if (link == NULL)
+			return -1;
+
+		if (params->rxq.queue_id >= link->n_rxq)
+			return -1;
+
+		pp.ethdev.port_id = link->port_id;
+		pp.ethdev.queue_id = params->rxq.queue_id;
+
+		p.ops = &rte_port_ethdev_reader_ops;
+		p.arg_create = &pp.ethdev;
+		break;
+	}
+
+	case PORT_IN_SWQ:
+	{
+		struct swq *swq;
+
+		swq = swq_find(params->dev_name);
+		if (swq == NULL)
+			return -1;
+
+		pp.ring.ring = swq->r;
+
+		p.ops = &rte_port_ring_reader_ops;
+		p.arg_create = &pp.ring;
+		break;
+	}
+
+	case PORT_IN_TMGR:
+	{
+		struct tmgr_port *tmgr_port;
+
+		tmgr_port = tmgr_port_find(params->dev_name);
+		if (tmgr_port == NULL)
+			return -1;
+
+		pp.sched.sched = tmgr_port->s;
+
+		p.ops = &rte_port_sched_reader_ops;
+		p.arg_create = &pp.sched;
+		break;
+	}
+
+	case PORT_IN_TAP:
+	{
+		struct tap *tap;
+		struct mempool *mempool;
+
+		tap = tap_find(params->dev_name);
+		mempool = mempool_find(params->tap.mempool_name);
+		if ((tap == NULL) || (mempool == NULL))
+			return -1;
+
+		pp.fd.fd = tap->fd;
+		pp.fd.mempool = mempool->m;
+		pp.fd.mtu = params->tap.mtu;
+
+		p.ops = &rte_port_fd_reader_ops;
+		p.arg_create = &pp.fd;
+		break;
+	}
+
+	case PORT_IN_KNI:
+	{
+		struct kni *kni;
+
+		kni = kni_find(params->dev_name);
+		if (kni == NULL)
+			return -1;
+
+		pp.kni.kni = kni->k;
+
+		p.ops = &rte_port_kni_reader_ops;
+		p.arg_create = &pp.kni;
+		break;
+	}
+
+	case PORT_IN_SOURCE:
+	{
+		struct mempool *mempool;
+
+		mempool = mempool_find(params->source.mempool_name);
+		if (mempool == NULL)
+			return -1;
+
+		pp.source.mempool = mempool->m;
+		pp.source.file_name = params->source.file_name;
+		pp.source.n_bytes_per_pkt = params->source.n_bytes_per_pkt;
+
+		p.ops = &rte_port_source_ops;
+		p.arg_create = &pp.source;
+		break;
+	}
+
+	default:
+		return -1;
+	}
+
+	p.f_action = NULL;
+	p.arg_ah = NULL;
+	p.burst_size = params->burst_size;
+
+	/* Resource create */
+	status = rte_pipeline_port_in_create(pipeline->p,
+		&p,
+		&port_id);
+
+	if (status)
+		return -1;
+
+	if (enabled)
+		rte_pipeline_port_in_enable(pipeline->p, port_id);
+
+	/* Pipeline */
+	pipeline->n_ports_in++;
+
+	return 0;
+}
+
+int
+pipeline_port_in_connect_to_table(const char *pipeline_name,
+	uint32_t port_id,
+	uint32_t table_id)
+{
+	struct pipeline *pipeline;
+	int status;
+
+	/* Check input params */
+	if (pipeline_name == NULL)
+		return -1;
+
+	pipeline = pipeline_find(pipeline_name);
+	if ((pipeline == NULL) ||
+		(port_id >= pipeline->n_ports_in) ||
+		(table_id >= pipeline->n_tables))
+		return -1;
+
+	/* Resource */
+	status = rte_pipeline_port_in_connect_to_table(pipeline->p,
+		port_id,
+		table_id);
+
+	return status;
+
+}
+
+int
+pipeline_port_out_create(const char *pipeline_name,
+	struct port_out_params *params)
+{
+	struct rte_pipeline_port_out_params p;
+
+	union {
+		struct rte_port_ethdev_writer_params ethdev;
+		struct rte_port_ring_writer_params ring;
+		struct rte_port_sched_writer_params sched;
+		struct rte_port_fd_writer_params fd;
+		struct rte_port_kni_writer_params kni;
+		struct rte_port_sink_params sink;
+	} pp;
+
+	union {
+		struct rte_port_ethdev_writer_nodrop_params ethdev;
+		struct rte_port_ring_writer_nodrop_params ring;
+		struct rte_port_fd_writer_nodrop_params fd;
+		struct rte_port_kni_writer_nodrop_params kni;
+	} pp_nodrop;
+
+	struct pipeline *pipeline;
+	uint32_t port_id;
+	int status;
+
+	memset(&pp, 0, sizeof(pp));
+	memset(&pp_nodrop, 0, sizeof(pp_nodrop));
+
+	/* Check input params */
+	if ((pipeline_name == NULL) ||
+		(params == NULL) ||
+		(params->burst_size == 0) ||
+		(params->burst_size > RTE_PORT_IN_BURST_SIZE_MAX))
+		return -1;
+
+	pipeline = pipeline_find(pipeline_name);
+	if (pipeline == NULL)
+		return -1;
+
+	switch (params->type) {
+	case PORT_OUT_TXQ:
+	{
+		struct link *link;
+
+		link = link_find(params->dev_name);
+		if (link == NULL)
+			return -1;
+
+		if (params->txq.queue_id >= link->n_txq)
+			return -1;
+
+		pp.ethdev.port_id = link->port_id;
+		pp.ethdev.queue_id = params->txq.queue_id;
+		pp.ethdev.tx_burst_sz = params->burst_size;
+
+		pp_nodrop.ethdev.port_id = link->port_id;
+		pp_nodrop.ethdev.queue_id = params->txq.queue_id;
+		pp_nodrop.ethdev.tx_burst_sz = params->burst_size;
+		pp_nodrop.ethdev.n_retries = params->n_retries;
+
+		if (params->retry == 0) {
+			p.ops = &rte_port_ethdev_writer_ops;
+			p.arg_create = &pp.ethdev;
+		} else {
+			p.ops = &rte_port_ethdev_writer_nodrop_ops;
+			p.arg_create = &pp_nodrop.ethdev;
+		}
+		break;
+	}
+
+	case PORT_OUT_SWQ:
+	{
+		struct swq *swq;
+
+		swq = swq_find(params->dev_name);
+		if (swq == NULL)
+			return -1;
+
+		pp.ring.ring = swq->r;
+		pp.ring.tx_burst_sz = params->burst_size;
+
+		pp_nodrop.ring.ring = swq->r;
+		pp_nodrop.ring.tx_burst_sz = params->burst_size;
+		pp_nodrop.ring.n_retries = params->n_retries;
+
+		if (params->retry == 0) {
+			p.ops = &rte_port_ring_writer_ops;
+			p.arg_create = &pp.ring;
+		} else {
+			p.ops = &rte_port_ring_writer_nodrop_ops;
+			p.arg_create = &pp_nodrop.ring;
+		}
+		break;
+	}
+
+	case PORT_OUT_TMGR:
+	{
+		struct tmgr_port *tmgr_port;
+
+		tmgr_port = tmgr_port_find(params->dev_name);
+		if (tmgr_port == NULL)
+			return -1;
+
+		pp.sched.sched = tmgr_port->s;
+		pp.sched.tx_burst_sz = params->burst_size;
+
+		p.ops = &rte_port_sched_writer_ops;
+		p.arg_create = &pp.sched;
+		break;
+	}
+
+	case PORT_OUT_TAP:
+	{
+		struct tap *tap;
+
+		tap = tap_find(params->dev_name);
+		if (tap == NULL)
+			return -1;
+
+		pp.fd.fd = tap->fd;
+		pp.fd.tx_burst_sz = params->burst_size;
+
+		pp_nodrop.fd.fd = tap->fd;
+		pp_nodrop.fd.tx_burst_sz = params->burst_size;
+		pp_nodrop.fd.n_retries = params->n_retries;
+
+		if (params->retry == 0) {
+			p.ops = &rte_port_fd_writer_ops;
+			p.arg_create = &pp.fd;
+		} else {
+			p.ops = &rte_port_fd_writer_nodrop_ops;
+			p.arg_create = &pp_nodrop.fd;
+		}
+		break;
+	}
+
+	case PORT_OUT_KNI:
+	{
+		struct kni *kni;
+
+		kni = kni_find(params->dev_name);
+		if (kni == NULL)
+			return -1;
+
+		pp.kni.kni = kni->k;
+		pp.kni.tx_burst_sz = params->burst_size;
+
+		pp_nodrop.kni.kni = kni->k;
+		pp_nodrop.kni.tx_burst_sz = params->burst_size;
+		pp_nodrop.kni.n_retries = params->n_retries;
+
+		if (params->retry == 0) {
+			p.ops = &rte_port_kni_writer_ops;
+			p.arg_create = &pp.kni;
+		} else {
+			p.ops = &rte_port_kni_writer_nodrop_ops;
+			p.arg_create = &pp_nodrop.kni;
+		}
+		break;
+	}
+
+	case PORT_OUT_SINK:
+	{
+		pp.sink.file_name = params->sink.file_name;
+		pp.sink.max_n_pkts = params->sink.max_n_pkts;
+
+		p.ops = &rte_port_sink_ops;
+		p.arg_create = &pp.sink;
+		break;
+	}
+
+	default:
+		return -1;
+	}
+
+	p.f_action = NULL;
+	p.arg_ah = NULL;
+
+	/* Resource create */
+	status = rte_pipeline_port_out_create(pipeline->p,
+		&p,
+		&port_id);
+
+	if (status)
+		return -1;
+
+	/* Pipeline */
+	pipeline->n_ports_out++;
+
+	return 0;
+}
+
+static const struct rte_acl_field_def table_acl_field_format_ipv4[] = {
+	/* Protocol */
+	[0] = {
+		.type = RTE_ACL_FIELD_TYPE_BITMASK,
+		.size = sizeof(uint8_t),
+		.field_index = 0,
+		.input_index = 0,
+		.offset = offsetof(struct ipv4_hdr, next_proto_id),
+	},
+
+	/* Source IP address (IPv4) */
+	[1] = {
+		.type = RTE_ACL_FIELD_TYPE_MASK,
+		.size = sizeof(uint32_t),
+		.field_index = 1,
+		.input_index = 1,
+		.offset = offsetof(struct ipv4_hdr, src_addr),
+	},
+
+	/* Destination IP address (IPv4) */
+	[2] = {
+		.type = RTE_ACL_FIELD_TYPE_MASK,
+		.size = sizeof(uint32_t),
+		.field_index = 2,
+		.input_index = 2,
+		.offset = offsetof(struct ipv4_hdr, dst_addr),
+	},
+
+	/* Source Port */
+	[3] = {
+		.type = RTE_ACL_FIELD_TYPE_RANGE,
+		.size = sizeof(uint16_t),
+		.field_index = 3,
+		.input_index = 3,
+		.offset = sizeof(struct ipv4_hdr) +
+			offsetof(struct tcp_hdr, src_port),
+	},
+
+	/* Destination Port */
+	[4] = {
+		.type = RTE_ACL_FIELD_TYPE_RANGE,
+		.size = sizeof(uint16_t),
+		.field_index = 4,
+		.input_index = 3,
+		.offset = sizeof(struct ipv4_hdr) +
+			offsetof(struct tcp_hdr, dst_port),
+	},
+};
+
+static const struct rte_acl_field_def table_acl_field_format_ipv6[] = {
+	/* Protocol */
+	[0] = {
+		.type = RTE_ACL_FIELD_TYPE_BITMASK,
+		.size = sizeof(uint8_t),
+		.field_index = 0,
+		.input_index = 0,
+		.offset = offsetof(struct ipv6_hdr, proto),
+	},
+
+	/* Source IP address (IPv6) */
+	[1] = {
+		.type = RTE_ACL_FIELD_TYPE_MASK,
+		.size = sizeof(uint32_t),
+		.field_index = 1,
+		.input_index = 1,
+		.offset = offsetof(struct ipv6_hdr, src_addr[0]),
+	},
+
+	[2] = {
+		.type = RTE_ACL_FIELD_TYPE_MASK,
+		.size = sizeof(uint32_t),
+		.field_index = 2,
+		.input_index = 2,
+		.offset = offsetof(struct ipv6_hdr, src_addr[4]),
+	},
+
+	[3] = {
+		.type = RTE_ACL_FIELD_TYPE_MASK,
+		.size = sizeof(uint32_t),
+		.field_index = 3,
+		.input_index = 3,
+		.offset = offsetof(struct ipv6_hdr, src_addr[8]),
+	},
+
+	[4] = {
+		.type = RTE_ACL_FIELD_TYPE_MASK,
+		.size = sizeof(uint32_t),
+		.field_index = 4,
+		.input_index = 4,
+		.offset = offsetof(struct ipv6_hdr, src_addr[12]),
+	},
+
+	/* Destination IP address (IPv6) */
+	[5] = {
+		.type = RTE_ACL_FIELD_TYPE_MASK,
+		.size = sizeof(uint32_t),
+		.field_index = 5,
+		.input_index = 5,
+		.offset = offsetof(struct ipv6_hdr, dst_addr[0]),
+	},
+
+	[6] = {
+		.type = RTE_ACL_FIELD_TYPE_MASK,
+		.size = sizeof(uint32_t),
+		.field_index = 6,
+		.input_index = 6,
+		.offset = offsetof(struct ipv6_hdr, dst_addr[4]),
+	},
+
+	[7] = {
+		.type = RTE_ACL_FIELD_TYPE_MASK,
+		.size = sizeof(uint32_t),
+		.field_index = 7,
+		.input_index = 7,
+		.offset = offsetof(struct ipv6_hdr, dst_addr[8]),
+	},
+
+	[8] = {
+		.type = RTE_ACL_FIELD_TYPE_MASK,
+		.size = sizeof(uint32_t),
+		.field_index = 8,
+		.input_index = 8,
+		.offset = offsetof(struct ipv6_hdr, dst_addr[12]),
+	},
+
+	/* Source Port */
+	[9] = {
+		.type = RTE_ACL_FIELD_TYPE_RANGE,
+		.size = sizeof(uint16_t),
+		.field_index = 9,
+		.input_index = 9,
+		.offset = sizeof(struct ipv6_hdr) +
+			offsetof(struct tcp_hdr, src_port),
+	},
+
+	/* Destination Port */
+	[10] = {
+		.type = RTE_ACL_FIELD_TYPE_RANGE,
+		.size = sizeof(uint16_t),
+		.field_index = 10,
+		.input_index = 9,
+		.offset = sizeof(struct ipv6_hdr) +
+			offsetof(struct tcp_hdr, dst_port),
+	},
+};
+
+int
+pipeline_table_create(const char *pipeline_name,
+	struct table_params *params)
+{
+	char name[NAME_MAX];
+	struct rte_pipeline_table_params p;
+
+	union {
+		struct rte_table_acl_params acl;
+		struct rte_table_array_params array;
+		struct rte_table_hash_params hash;
+		struct rte_table_lpm_params lpm;
+		struct rte_table_lpm_ipv6_params lpm_ipv6;
+	} pp;
+
+	struct pipeline *pipeline;
+	struct table *table;
+	struct table_action_profile *ap;
+	struct rte_table_action *action;
+	uint32_t table_id;
+	int status;
+
+	memset(&p, 0, sizeof(p));
+	memset(&pp, 0, sizeof(pp));
+
+	/* Check input params */
+	if ((pipeline_name == NULL) ||
+		(params == NULL) ||
+		(params->action_profile_name == NULL))
+		return -1;
+
+	pipeline = pipeline_find(pipeline_name);
+	if ((pipeline == NULL) ||
+		(pipeline->n_tables >= PIPELINE_TABLE_MAX))
+		return -1;
+
+	ap = table_action_profile_find(params->action_profile_name);
+	if (ap == NULL)
+		return -1;
+
+	snprintf(name, NAME_MAX, "%s_table%u",
+		pipeline_name, pipeline->n_tables);
+
+	switch (params->match_type) {
+	case TABLE_ACL:
+	{
+		uint32_t ip_header_offset = params->match.acl.ip_header_offset -
+			(sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM);
+		uint32_t i;
+
+		if (params->match.acl.n_rules == 0)
+			return -1;
+
+		pp.acl.name = name;
+		pp.acl.n_rules = params->match.acl.n_rules;
+		if (params->match.acl.ip_version) {
+			memcpy(&pp.acl.field_format,
+				&table_acl_field_format_ipv4,
+				sizeof(table_acl_field_format_ipv4));
+			pp.acl.n_rule_fields =
+				RTE_DIM(table_acl_field_format_ipv4);
+		} else {
+			memcpy(&pp.acl.field_format,
+				&table_acl_field_format_ipv6,
+				sizeof(table_acl_field_format_ipv6));
+			pp.acl.n_rule_fields =
+				RTE_DIM(table_acl_field_format_ipv6);
+		}
+
+		for (i = 0; i < pp.acl.n_rule_fields; i++)
+			pp.acl.field_format[i].offset += ip_header_offset;
+
+		p.ops = &rte_table_acl_ops;
+		p.arg_create = &pp.acl;
+		break;
+	}
+
+	case TABLE_ARRAY:
+	{
+		if (params->match.array.n_keys == 0)
+			return -1;
+
+		pp.array.n_entries = params->match.array.n_keys;
+		pp.array.offset = params->match.array.key_offset;
+
+		p.ops = &rte_table_array_ops;
+		p.arg_create = &pp.array;
+		break;
+	}
+
+	case TABLE_HASH:
+	{
+		struct rte_table_ops *ops;
+		rte_table_hash_op_hash f_hash;
+
+		if (params->match.hash.n_keys == 0)
+			return -1;
+
+		switch (params->match.hash.key_size) {
+		case  8:
+			f_hash = hash_default_key8;
+			break;
+		case 16:
+			f_hash = hash_default_key16;
+			break;
+		case 24:
+			f_hash = hash_default_key24;
+			break;
+		case 32:
+			f_hash = hash_default_key32;
+			break;
+		case 40:
+			f_hash = hash_default_key40;
+			break;
+		case 48:
+			f_hash = hash_default_key48;
+			break;
+		case 56:
+			f_hash = hash_default_key56;
+			break;
+		case 64:
+			f_hash = hash_default_key64;
+			break;
+		default:
+			return -1;
+		}
+
+		pp.hash.name = name;
+		pp.hash.key_size = params->match.hash.key_size;
+		pp.hash.key_offset = params->match.hash.key_offset;
+		pp.hash.key_mask = params->match.hash.key_mask;
+		pp.hash.n_keys = params->match.hash.n_keys;
+		pp.hash.n_buckets = params->match.hash.n_buckets;
+		pp.hash.f_hash = f_hash;
+		pp.hash.seed = 0;
+
+		if (params->match.hash.extendable_bucket)
+			switch (params->match.hash.key_size) {
+			case  8:
+				ops = &rte_table_hash_key8_ext_ops;
+				break;
+			case 16:
+				ops = &rte_table_hash_key16_ext_ops;
+				break;
+			default:
+				ops = &rte_table_hash_ext_ops;
+			}
+		else
+			switch (params->match.hash.key_size) {
+			case  8:
+				ops = &rte_table_hash_key8_lru_ops;
+				break;
+			case 16:
+				ops = &rte_table_hash_key16_lru_ops;
+				break;
+			default:
+				ops = &rte_table_hash_lru_ops;
+			}
+
+		p.ops = ops;
+		p.arg_create = &pp.hash;
+		break;
+	}
+
+	case TABLE_LPM:
+	{
+		if (params->match.lpm.n_rules == 0)
+			return -1;
+
+		switch (params->match.lpm.key_size) {
+		case 4:
+		{
+			pp.lpm.name = name;
+			pp.lpm.n_rules = params->match.lpm.n_rules;
+			pp.lpm.number_tbl8s = TABLE_LPM_NUMBER_TBL8;
+			pp.lpm.flags = 0;
+			pp.lpm.entry_unique_size = p.action_data_size +
+				sizeof(struct rte_pipeline_table_entry);
+			pp.lpm.offset = params->match.lpm.key_offset;
+
+			p.ops = &rte_table_lpm_ops;
+			p.arg_create = &pp.lpm;
+			break;
+		}
+
+		case 16:
+		{
+			pp.lpm_ipv6.name = name;
+			pp.lpm_ipv6.n_rules = params->match.lpm.n_rules;
+			pp.lpm_ipv6.number_tbl8s = TABLE_LPM_NUMBER_TBL8;
+			pp.lpm_ipv6.entry_unique_size = p.action_data_size +
+				sizeof(struct rte_pipeline_table_entry);
+			pp.lpm_ipv6.offset = params->match.lpm.key_offset;
+
+			p.ops = &rte_table_lpm_ipv6_ops;
+			p.arg_create = &pp.lpm_ipv6;
+			break;
+		}
+
+		default:
+			return -1;
+		}
+
+		break;
+	}
+
+	case TABLE_STUB:
+	{
+		p.ops = &rte_table_stub_ops;
+		p.arg_create = NULL;
+		break;
+	}
+
+	default:
+		return -1;
+	}
+
+	/* Resource create */
+	action = rte_table_action_create(ap->ap,
+		pipeline->cpu_id);
+	if (action == NULL)
+		return -1;
+
+	status = rte_table_action_table_params_get(
+		action,
+		&p);
+	if (status ||
+		((p.action_data_size +
+		sizeof(struct rte_pipeline_table_entry)) >
+		TABLE_RULE_ACTION_SIZE_MAX)) {
+		rte_table_action_free(action);
+		return -1;
+	}
+
+	if (params->match_type == TABLE_LPM) {
+		if (params->match.lpm.key_size == 4)
+			pp.lpm.entry_unique_size = p.action_data_size +
+				sizeof(struct rte_pipeline_table_entry);
+
+		if (params->match.lpm.key_size == 16)
+			pp.lpm_ipv6.entry_unique_size = p.action_data_size +
+				sizeof(struct rte_pipeline_table_entry);
+	}
+
+	status = rte_pipeline_table_create(pipeline->p,
+		&p,
+		&table_id);
+	if (status) {
+		rte_table_action_free(action);
+		return -1;
+	}
+
+	/* Pipeline */
+	table = &pipeline->table[pipeline->n_tables];
+	memcpy(&table->params, params, sizeof(*params));
+	table->ap = ap;
+	table->a = action;
+	pipeline->n_tables++;
+
+	return 0;
+}
diff --git a/examples/ip_pipeline/pipeline.h b/examples/ip_pipeline/pipeline.h
new file mode 100644
index 0000000..dbc6f77
--- /dev/null
+++ b/examples/ip_pipeline/pipeline.h
@@ -0,0 +1,265 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#ifndef _INCLUDE_PIPELINE_H_
+#define _INCLUDE_PIPELINE_H_
+
+#include <stdint.h>
+#include <sys/queue.h>
+
+#include <rte_pipeline.h>
+#include <rte_table_action.h>
+
+#include "common.h"
+#include "action.h"
+
+struct pipeline_params {
+	uint32_t timer_period_ms;
+	uint32_t offset_port_id;
+	uint32_t cpu_id;
+};
+
+enum port_in_type {
+	PORT_IN_RXQ,
+	PORT_IN_SWQ,
+	PORT_IN_TMGR,
+	PORT_IN_TAP,
+	PORT_IN_KNI,
+	PORT_IN_SOURCE,
+};
+
+struct port_in_params {
+	enum port_in_type type;
+	const char *dev_name;
+	union {
+		struct {
+			uint16_t queue_id;
+		} rxq;
+
+		struct {
+			const char *mempool_name;
+			uint32_t mtu;
+		} tap;
+
+		struct {
+			const char *mempool_name;
+			const char *file_name;
+			uint32_t n_bytes_per_pkt;
+		} source;
+	};
+	uint32_t burst_size;
+};
+
+enum port_out_type {
+	PORT_OUT_TXQ,
+	PORT_OUT_SWQ,
+	PORT_OUT_TMGR,
+	PORT_OUT_TAP,
+	PORT_OUT_KNI,
+	PORT_OUT_SINK,
+};
+
+struct port_out_params {
+	enum port_out_type type;
+	const char *dev_name;
+	union {
+		struct {
+			uint16_t queue_id;
+		} txq;
+
+		struct {
+			const char *file_name;
+			uint32_t max_n_pkts;
+		} sink;
+	};
+	uint32_t burst_size;
+	int retry;
+	uint32_t n_retries;
+};
+
+enum table_type {
+	TABLE_ACL,
+	TABLE_ARRAY,
+	TABLE_HASH,
+	TABLE_LPM,
+	TABLE_STUB,
+};
+
+struct table_acl_params {
+	uint32_t n_rules;
+	uint32_t ip_header_offset;
+	int ip_version;
+};
+
+struct table_array_params {
+	uint32_t n_keys;
+	uint32_t key_offset;
+};
+
+struct table_hash_params {
+	uint32_t n_keys;
+	uint32_t key_offset;
+	uint32_t key_size;
+	uint8_t *key_mask;
+	uint32_t n_buckets;
+	int extendable_bucket;
+};
+
+struct table_lpm_params {
+	uint32_t n_rules;
+	uint32_t key_offset;
+	uint32_t key_size;
+};
+
+struct table_params {
+	/* Match */
+	enum table_type match_type;
+	union {
+		struct table_acl_params acl;
+		struct table_array_params array;
+		struct table_hash_params hash;
+		struct table_lpm_params lpm;
+	} match;
+
+	/* Action */
+	const char *action_profile_name;
+};
+
+struct table {
+	struct table_params params;
+	struct table_action_profile *ap;
+	struct rte_table_action *a;
+};
+
+#ifndef PIPELINE_TABLE_MAX
+#define PIPELINE_TABLE_MAX                                 256
+#endif
+
+struct pipeline {
+	TAILQ_ENTRY(pipeline) node;
+	char name[NAME_SIZE];
+
+	struct rte_pipeline *p;
+	struct table table[PIPELINE_TABLE_MAX];
+	uint32_t n_ports_in;
+	uint32_t n_ports_out;
+	uint32_t n_tables;
+
+	struct rte_ring *msgq_req;
+	struct rte_ring *msgq_rsp;
+	uint32_t timer_period_ms;
+
+	int enabled;
+	uint32_t thread_id;
+	uint32_t cpu_id;
+};
+
+TAILQ_HEAD(pipeline_list, pipeline);
+
+int
+pipeline_init(void);
+
+struct pipeline *
+pipeline_find(const char *name);
+
+struct pipeline *
+pipeline_create(const char *name, struct pipeline_params *params);
+
+int
+pipeline_port_in_create(const char *pipeline_name,
+	struct port_in_params *params,
+	int enabled);
+
+int
+pipeline_port_in_connect_to_table(const char *pipeline_name,
+	uint32_t port_id,
+	uint32_t table_id);
+
+int
+pipeline_port_out_create(const char *pipeline_name,
+	struct port_out_params *params);
+
+int
+pipeline_table_create(const char *pipeline_name,
+	struct table_params *params);
+
+struct table_rule_match_acl {
+	int ip_version;
+
+	RTE_STD_C11
+	union {
+		struct {
+			uint32_t sa;
+			uint32_t da;
+		} ipv4;
+
+		struct {
+			uint8_t sa[16];
+			uint8_t da[16];
+		} ipv6;
+	};
+
+	uint32_t sa_depth;
+	uint32_t da_depth;
+	uint16_t sp0;
+	uint16_t sp1;
+	uint16_t dp0;
+	uint16_t dp1;
+	uint8_t proto;
+	uint8_t proto_mask;
+	uint32_t priority;
+};
+
+struct table_rule_match_array {
+	uint32_t pos;
+};
+
+#ifndef TABLE_RULE_MATCH_SIZE_MAX
+#define TABLE_RULE_MATCH_SIZE_MAX                          256
+#endif
+
+#ifndef TABLE_RULE_ACTION_SIZE_MAX
+#define TABLE_RULE_ACTION_SIZE_MAX                         2048
+#endif
+
+struct table_rule_match_hash {
+	uint8_t key[TABLE_RULE_MATCH_SIZE_MAX];
+};
+
+struct table_rule_match_lpm {
+	int ip_version;
+
+	RTE_STD_C11
+	union {
+		uint32_t ipv4;
+		uint8_t ipv6[16];
+	};
+
+	uint8_t depth;
+};
+
+struct table_rule_match {
+	enum table_type match_type;
+
+	union {
+		struct table_rule_match_acl acl;
+		struct table_rule_match_array array;
+		struct table_rule_match_hash hash;
+		struct table_rule_match_lpm lpm;
+	} match;
+};
+
+struct table_rule_action {
+	uint64_t action_mask;
+	struct rte_table_action_fwd_params fwd;
+	struct rte_table_action_mtr_params mtr;
+	struct rte_table_action_tm_params tm;
+	struct rte_table_action_encap_params encap;
+	struct rte_table_action_nat_params nat;
+	struct rte_table_action_ttl_params ttl;
+	struct rte_table_action_stats_params stats;
+	struct rte_table_action_time_params time;
+};
+
+#endif /* _INCLUDE_PIPELINE_H_ */
-- 
2.9.3

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

* [dpdk-dev] [PATCH v3 27/44] ip_pipeline: add threads
  2018-03-16 17:58       ` [dpdk-dev] [PATCH v3 00/44] ip_pipeline: refactoring Jasvinder Singh
                           ` (25 preceding siblings ...)
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 26/44] ip_pipeline: add pipeline object Jasvinder Singh
@ 2018-03-16 17:58         ` Jasvinder Singh
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 28/44] ip_pipeline: add thread runtime Jasvinder Singh
                           ` (16 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-16 17:58 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add threads data structure and initialisation functions to run
the pipeline.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/Makefile    |   2 +-
 examples/ip_pipeline/main.c      |   8 ++
 examples/ip_pipeline/meson.build |   1 +
 examples/ip_pipeline/thread.c    | 159 +++++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/thread.h    |  13 ++++
 5 files changed, 182 insertions(+), 1 deletion(-)
 create mode 100644 examples/ip_pipeline/thread.c
 create mode 100644 examples/ip_pipeline/thread.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index 033319d..c936d1e 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -16,8 +16,8 @@ SRCS-y += parser.c
 SRCS-y += pipeline.c
 SRCS-y += swq.c
 SRCS-y += tap.c
+SRCS-y += thread.c
 SRCS-y += tmgr.c
-#SRCS-y += thread.c
 
 # Build using pkg-config variables if possible
 $(shell pkg-config --exists libdpdk)
diff --git a/examples/ip_pipeline/main.c b/examples/ip_pipeline/main.c
index a7f4486..d139290 100644
--- a/examples/ip_pipeline/main.c
+++ b/examples/ip_pipeline/main.c
@@ -18,6 +18,7 @@
 #include "pipeline.h"
 #include "swq.h"
 #include "tap.h"
+#include "thread.h"
 #include "tmgr.h"
 
 static const char usage[] =
@@ -223,6 +224,13 @@ main(int argc, char **argv)
 		return status;
 	}
 
+	/* Thread */
+	status = thread_init();
+	if (status) {
+		printf("Error: Thread initialization failed (%d)\n", status);
+		return status;
+	}
+
 	/* Script */
 	if (app.script_name)
 		cli_script_process(app.script_name,
diff --git a/examples/ip_pipeline/meson.build b/examples/ip_pipeline/meson.build
index 2366242..a9f2ea4 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -20,5 +20,6 @@ sources = files(
 	'pipeline.c',
 	'swq.c',
 	'tap.c',
+	'thread.c',
 	'tmgr.c'
 )
diff --git a/examples/ip_pipeline/thread.c b/examples/ip_pipeline/thread.c
new file mode 100644
index 0000000..4da8db9
--- /dev/null
+++ b/examples/ip_pipeline/thread.c
@@ -0,0 +1,159 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#include <stdlib.h>
+
+#include <rte_common.h>
+#include <rte_cycles.h>
+#include <rte_lcore.h>
+#include <rte_ring.h>
+
+#include <rte_table_acl.h>
+#include <rte_table_array.h>
+#include <rte_table_hash.h>
+#include <rte_table_lpm.h>
+#include <rte_table_lpm_ipv6.h>
+
+#include "common.h"
+#include "thread.h"
+#include "pipeline.h"
+
+#ifndef THREAD_PIPELINES_MAX
+#define THREAD_PIPELINES_MAX                               256
+#endif
+
+#ifndef THREAD_MSGQ_SIZE
+#define THREAD_MSGQ_SIZE                                   64
+#endif
+
+#ifndef THREAD_TIMER_PERIOD_MS
+#define THREAD_TIMER_PERIOD_MS                             100
+#endif
+
+/**
+ * Master thead: data plane thread context
+ */
+struct thread {
+	struct rte_ring *msgq_req;
+	struct rte_ring *msgq_rsp;
+
+	uint32_t enabled;
+};
+
+static struct thread thread[RTE_MAX_LCORE];
+
+/**
+ * Data plane threads: context
+ */
+struct table_data {
+	void *ap_instance;
+};
+
+struct pipeline_data {
+	struct rte_pipeline *p;
+	struct table_data table_data[PIPELINE_TABLE_MAX];
+	uint32_t n_tables;
+
+	struct rte_ring *msgq_req;
+	struct rte_ring *msgq_rsp;
+	uint64_t timer_period; /* Measured in CPU cycles. */
+	uint64_t time_next;
+
+	uint8_t buffer[TABLE_RULE_ACTION_SIZE_MAX];
+};
+
+struct thread_data {
+	struct rte_pipeline *p[THREAD_PIPELINES_MAX];
+	uint32_t n_pipelines;
+
+	struct pipeline_data pipeline_data[THREAD_PIPELINES_MAX];
+	struct rte_ring *msgq_req;
+	struct rte_ring *msgq_rsp;
+	uint64_t timer_period; /* Measured in CPU cycles. */
+	uint64_t time_next;
+	uint64_t time_next_min;
+} __rte_cache_aligned;
+
+static struct thread_data thread_data[RTE_MAX_LCORE];
+
+/**
+ * Master thread: data plane thread init
+ */
+static void
+thread_free(void)
+{
+	uint32_t i;
+
+	for (i = 0; i < RTE_MAX_LCORE; i++) {
+		struct thread *t = &thread[i];
+
+		if (!rte_lcore_is_enabled(i))
+			continue;
+
+		/* MSGQs */
+		if (t->msgq_req)
+			rte_ring_free(t->msgq_req);
+
+		if (t->msgq_rsp)
+			rte_ring_free(t->msgq_rsp);
+	}
+}
+
+int
+thread_init(void)
+{
+	uint32_t i;
+
+	for (i = 0; i < RTE_MAX_LCORE; i++) {
+		char name[NAME_MAX];
+		struct rte_ring *msgq_req, *msgq_rsp;
+		struct thread *t = &thread[i];
+		struct thread_data *t_data = &thread_data[i];
+		uint32_t cpu_id = rte_lcore_to_socket_id(i);
+
+		if (!rte_lcore_is_enabled(i))
+			continue;
+
+		/* MSGQs */
+		snprintf(name, sizeof(name), "THREAD-%04x-MSGQ-REQ", i);
+
+		msgq_req = rte_ring_create(name,
+			THREAD_MSGQ_SIZE,
+			cpu_id,
+			RING_F_SP_ENQ | RING_F_SC_DEQ);
+
+		if (msgq_req == NULL) {
+			thread_free();
+			return -1;
+		}
+
+		snprintf(name, sizeof(name), "THREAD-%04x-MSGQ-RSP", i);
+
+		msgq_rsp = rte_ring_create(name,
+			THREAD_MSGQ_SIZE,
+			cpu_id,
+			RING_F_SP_ENQ | RING_F_SC_DEQ);
+
+		if (msgq_rsp == NULL) {
+			thread_free();
+			return -1;
+		}
+
+		/* Master thread records */
+		t->msgq_req = msgq_req;
+		t->msgq_rsp = msgq_rsp;
+		t->enabled = 1;
+
+		/* Data plane thread records */
+		t_data->n_pipelines = 0;
+		t_data->msgq_req = msgq_req;
+		t_data->msgq_rsp = msgq_rsp;
+		t_data->timer_period =
+			(rte_get_tsc_hz() * THREAD_TIMER_PERIOD_MS) / 1000;
+		t_data->time_next = rte_get_tsc_cycles() + t_data->timer_period;
+		t_data->time_next_min = t_data->time_next;
+	}
+
+	return 0;
+}
diff --git a/examples/ip_pipeline/thread.h b/examples/ip_pipeline/thread.h
new file mode 100644
index 0000000..39c0d89
--- /dev/null
+++ b/examples/ip_pipeline/thread.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#ifndef _INCLUDE_THREAD_H_
+#define _INCLUDE_THREAD_H_
+
+#include <stdint.h>
+
+int
+thread_init(void);
+
+#endif /* _INCLUDE_THREAD_H_ */
-- 
2.9.3

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

* [dpdk-dev] [PATCH v3 28/44] ip_pipeline: add thread runtime
  2018-03-16 17:58       ` [dpdk-dev] [PATCH v3 00/44] ip_pipeline: refactoring Jasvinder Singh
                           ` (26 preceding siblings ...)
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 27/44] ip_pipeline: add threads Jasvinder Singh
@ 2018-03-16 17:58         ` Jasvinder Singh
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 29/44] ip_pipeline: add cli to enable and disable pipeline Jasvinder Singh
                           ` (15 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-16 17:58 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add runtime thread functions for the pipeline.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/main.c   |   6 ++
 examples/ip_pipeline/thread.c | 193 ++++++++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/thread.h |   3 +
 3 files changed, 202 insertions(+)

diff --git a/examples/ip_pipeline/main.c b/examples/ip_pipeline/main.c
index d139290..36da679 100644
--- a/examples/ip_pipeline/main.c
+++ b/examples/ip_pipeline/main.c
@@ -8,6 +8,7 @@
 #include <unistd.h>
 #include <getopt.h>
 
+#include <rte_launch.h>
 #include <rte_eal.h>
 
 #include "cli.h"
@@ -231,6 +232,11 @@ main(int argc, char **argv)
 		return status;
 	}
 
+	rte_eal_mp_remote_launch(
+		thread_main,
+		NULL,
+		SKIP_MASTER);
+
 	/* Script */
 	if (app.script_name)
 		cli_script_process(app.script_name,
diff --git a/examples/ip_pipeline/thread.c b/examples/ip_pipeline/thread.c
index 4da8db9..387e9bc 100644
--- a/examples/ip_pipeline/thread.c
+++ b/examples/ip_pipeline/thread.c
@@ -157,3 +157,196 @@ thread_init(void)
 
 	return 0;
 }
+
+/**
+ * Master thread & data plane threads: message passing
+ */
+enum thread_req_type {
+	THREAD_REQ_MAX
+};
+
+struct thread_msg_req {
+	enum thread_req_type type;
+};
+
+struct thread_msg_rsp {
+	int status;
+};
+
+/**
+ * Data plane threads: message handling
+ */
+static inline struct thread_msg_req *
+thread_msg_recv(struct rte_ring *msgq_req)
+{
+	struct thread_msg_req *req;
+
+	int status = rte_ring_sc_dequeue(msgq_req, (void **) &req);
+
+	if (status != 0)
+		return NULL;
+
+	return req;
+}
+
+static inline void
+thread_msg_send(struct rte_ring *msgq_rsp,
+	struct thread_msg_rsp *rsp)
+{
+	int status;
+
+	do {
+		status = rte_ring_sp_enqueue(msgq_rsp, rsp);
+	} while (status == -ENOBUFS);
+}
+
+static void
+thread_msg_handle(struct thread_data *t)
+{
+	for ( ; ; ) {
+		struct thread_msg_req *req;
+		struct thread_msg_rsp *rsp;
+
+		req = thread_msg_recv(t->msgq_req);
+		if (req == NULL)
+			break;
+
+		switch (req->type) {
+		default:
+			rsp = (struct thread_msg_rsp *) req;
+			rsp->status = -1;
+		}
+
+		thread_msg_send(t->msgq_rsp, rsp);
+	}
+}
+
+/**
+ * Master thread & data plane threads: message passing
+ */
+
+enum pipeline_req_type {
+	PIPELINE_REQ_MAX
+};
+
+struct pipeline_msg_req {
+	enum pipeline_req_type type;
+};
+
+struct pipeline_msg_rsp {
+	int status;
+};
+
+/**
+ * Data plane threads: message handling
+ */
+static inline struct pipeline_msg_req *
+pipeline_msg_recv(struct rte_ring *msgq_req)
+{
+	struct pipeline_msg_req *req;
+
+	int status = rte_ring_sc_dequeue(msgq_req, (void **) &req);
+
+	if (status != 0)
+		return NULL;
+
+	return req;
+}
+
+static inline void
+pipeline_msg_send(struct rte_ring *msgq_rsp,
+	struct pipeline_msg_rsp *rsp)
+{
+	int status;
+
+	do {
+		status = rte_ring_sp_enqueue(msgq_rsp, rsp);
+	} while (status == -ENOBUFS);
+}
+
+static void
+pipeline_msg_handle(struct pipeline_data *p)
+{
+	for ( ; ; ) {
+		struct pipeline_msg_req *req;
+		struct pipeline_msg_rsp *rsp;
+
+		req = pipeline_msg_recv(p->msgq_req);
+		if (req == NULL)
+			break;
+
+		switch (req->type) {
+		default:
+			rsp = (struct pipeline_msg_rsp *) req;
+			rsp->status = -1;
+		}
+
+		pipeline_msg_send(p->msgq_rsp, rsp);
+	}
+}
+
+/**
+ * Data plane threads: main
+ */
+int
+thread_main(void *arg __rte_unused)
+{
+	struct thread_data *t;
+	uint32_t thread_id, i;
+
+	thread_id = rte_lcore_id();
+	t = &thread_data[thread_id];
+
+	/* Dispatch loop */
+	for (i = 0; ; i++) {
+		uint32_t j;
+
+		/* Data Plane */
+		for (j = 0; j < t->n_pipelines; j++)
+			rte_pipeline_run(t->p[j]);
+
+		/* Control Plane */
+		if ((i & 0xF) == 0) {
+			uint64_t time = rte_get_tsc_cycles();
+			uint64_t time_next_min = UINT64_MAX;
+
+			if (time < t->time_next_min)
+				continue;
+
+			/* Pipeline message queues */
+			for (j = 0; j < t->n_pipelines; j++) {
+				struct pipeline_data *p =
+					&t->pipeline_data[j];
+				uint64_t time_next = p->time_next;
+
+				if (time_next <= time) {
+					pipeline_msg_handle(p);
+					rte_pipeline_flush(p->p);
+					time_next = time + p->timer_period;
+					p->time_next = time_next;
+				}
+
+				if (time_next < time_next_min)
+					time_next_min = time_next;
+			}
+
+			/* Thread message queues */
+			{
+				uint64_t time_next = t->time_next;
+
+				if (time_next <= time) {
+					thread_msg_handle(t);
+					time_next = time + t->timer_period;
+					t->time_next = time_next;
+				}
+
+				if (time_next < time_next_min)
+					time_next_min = time_next;
+			}
+
+			t->time_next_min = time_next_min;
+		}
+	}
+
+	return 0;
+}
diff --git a/examples/ip_pipeline/thread.h b/examples/ip_pipeline/thread.h
index 39c0d89..47db428 100644
--- a/examples/ip_pipeline/thread.h
+++ b/examples/ip_pipeline/thread.h
@@ -10,4 +10,7 @@
 int
 thread_init(void);
 
+int
+thread_main(void *arg);
+
 #endif /* _INCLUDE_THREAD_H_ */
-- 
2.9.3

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

* [dpdk-dev] [PATCH v3 29/44] ip_pipeline: add cli to enable and disable pipeline
  2018-03-16 17:58       ` [dpdk-dev] [PATCH v3 00/44] ip_pipeline: refactoring Jasvinder Singh
                           ` (27 preceding siblings ...)
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 28/44] ip_pipeline: add thread runtime Jasvinder Singh
@ 2018-03-16 17:58         ` Jasvinder Singh
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 30/44] ip_pipeline: add cli to enable and disable pipeline port Jasvinder Singh
                           ` (14 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-16 17:58 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Fan Zhang

Add commands to enable and disable the pipeline on the thread.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Fan Zhang <roy.fan.zhang@intel.com>
---
 examples/ip_pipeline/cli.c    | 102 +++++++++++++++++
 examples/ip_pipeline/thread.c | 260 +++++++++++++++++++++++++++++++++++++++++-
 examples/ip_pipeline/thread.h |   8 ++
 3 files changed, 369 insertions(+), 1 deletion(-)

diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index c82bbc3..a3642b4 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -17,6 +17,7 @@
 #include "pipeline.h"
 #include "swq.h"
 #include "tap.h"
+#include "thread.h"
 #include "tmgr.h"
 
 #ifndef CMD_MAX_TOKENS
@@ -1740,6 +1741,91 @@ cmd_pipeline_port_in_table(char **tokens,
 	}
 }
 
+/**
+ * thread <thread_id> pipeline <pipeline_name> enable
+ */
+static void
+cmd_thread_pipeline_enable(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	char *pipeline_name;
+	uint32_t thread_id;
+	int status;
+
+	if (n_tokens != 5) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	if (parser_read_uint32(&thread_id, tokens[1]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
+		return;
+	}
+
+	if (strcmp(tokens[2], "pipeline") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
+		return;
+	}
+
+	pipeline_name = tokens[3];
+
+	if (strcmp(tokens[4], "enable") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable");
+		return;
+	}
+
+	status = thread_pipeline_enable(thread_id, pipeline_name);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, "thread pipeline enable");
+		return;
+	}
+}
+
+/**
+ * thread <thread_id> pipeline <pipeline_name> disable
+ */
+static void
+cmd_thread_pipeline_disable(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	char *pipeline_name;
+	uint32_t thread_id;
+	int status;
+
+	if (n_tokens != 5) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	if (parser_read_uint32(&thread_id, tokens[1]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
+		return;
+	}
+
+	if (strcmp(tokens[2], "pipeline") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
+		return;
+	}
+
+	pipeline_name = tokens[3];
+
+	if (strcmp(tokens[4], "disable") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable");
+		return;
+	}
+
+	status = thread_pipeline_disable(thread_id, pipeline_name);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL,
+			"thread pipeline disable");
+		return;
+	}
+}
+
 void
 cli_process(char *in, char *out, size_t out_size)
 {
@@ -1863,6 +1949,22 @@ cli_process(char *in, char *out, size_t out_size)
 		}
 	}
 
+	if (strcmp(tokens[0], "thread") == 0) {
+		if ((n_tokens >= 5) &&
+			(strcmp(tokens[4], "enable") == 0)) {
+			cmd_thread_pipeline_enable(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
+
+		if ((n_tokens >= 5) &&
+			(strcmp(tokens[4], "disable") == 0)) {
+			cmd_thread_pipeline_disable(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
+	}
+
 	snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
 }
 
diff --git a/examples/ip_pipeline/thread.c b/examples/ip_pipeline/thread.c
index 387e9bc..d707ad7 100644
--- a/examples/ip_pipeline/thread.c
+++ b/examples/ip_pipeline/thread.c
@@ -47,7 +47,7 @@ static struct thread thread[RTE_MAX_LCORE];
  * Data plane threads: context
  */
 struct table_data {
-	void *ap_instance;
+	struct rte_table_action *a;
 };
 
 struct pipeline_data {
@@ -162,11 +162,30 @@ thread_init(void)
  * Master thread & data plane threads: message passing
  */
 enum thread_req_type {
+	THREAD_REQ_PIPELINE_ENABLE = 0,
+	THREAD_REQ_PIPELINE_DISABLE,
 	THREAD_REQ_MAX
 };
 
 struct thread_msg_req {
 	enum thread_req_type type;
+
+	union {
+		struct {
+			struct rte_pipeline *p;
+			struct {
+				struct rte_table_action *a;
+			} table[PIPELINE_TABLE_MAX];
+			struct rte_ring *msgq_req;
+			struct rte_ring *msgq_rsp;
+			uint32_t timer_period_ms;
+			uint32_t n_tables;
+		} pipeline_enable;
+
+		struct {
+			struct rte_pipeline *p;
+		} pipeline_disable;
+	};
 };
 
 struct thread_msg_rsp {
@@ -174,6 +193,164 @@ struct thread_msg_rsp {
 };
 
 /**
+ * Master thread
+ */
+static struct thread_msg_req *
+thread_msg_alloc(void)
+{
+	size_t size = RTE_MAX(sizeof(struct thread_msg_req),
+		sizeof(struct thread_msg_rsp));
+
+	return calloc(1, size);
+}
+
+static void
+thread_msg_free(struct thread_msg_rsp *rsp)
+{
+	free(rsp);
+}
+
+static struct thread_msg_rsp *
+thread_msg_send_recv(uint32_t thread_id,
+	struct thread_msg_req *req)
+{
+	struct thread *t = &thread[thread_id];
+	struct rte_ring *msgq_req = t->msgq_req;
+	struct rte_ring *msgq_rsp = t->msgq_rsp;
+	struct thread_msg_rsp *rsp;
+	int status;
+
+	/* send */
+	do {
+		status = rte_ring_sp_enqueue(msgq_req, req);
+	} while (status == -ENOBUFS);
+
+	/* recv */
+	do {
+		status = rte_ring_sc_dequeue(msgq_rsp, (void **) &rsp);
+	} while (status != 0);
+
+	return rsp;
+}
+
+int
+thread_pipeline_enable(uint32_t thread_id,
+	const char *pipeline_name)
+{
+	struct pipeline *p = pipeline_find(pipeline_name);
+	struct thread *t;
+	struct thread_msg_req *req;
+	struct thread_msg_rsp *rsp;
+	uint32_t i;
+	int status;
+
+	/* Check input params */
+	if ((thread_id >= RTE_MAX_LCORE) ||
+		(p == NULL) ||
+		(p->n_ports_in == 0) ||
+		(p->n_ports_out == 0) ||
+		(p->n_tables == 0))
+		return -1;
+
+	t = &thread[thread_id];
+	if (t->enabled == 0)
+		return -1;
+
+	if (p->enabled && (p->thread_id == thread_id))
+		return 0;
+
+	/* Allocate request */
+	req = thread_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = THREAD_REQ_PIPELINE_ENABLE;
+	req->pipeline_enable.p = p->p;
+	for (i = 0; i < p->n_tables; i++)
+		req->pipeline_enable.table[i].a =
+			p->table[i].a;
+	req->pipeline_enable.msgq_req = p->msgq_req;
+	req->pipeline_enable.msgq_rsp = p->msgq_rsp;
+	req->pipeline_enable.timer_period_ms = p->timer_period_ms;
+	req->pipeline_enable.n_tables = p->n_tables;
+
+	/* Send request and wait for response */
+	rsp = thread_msg_send_recv(thread_id, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+
+	/* Free response */
+	thread_msg_free(rsp);
+
+	/* Request completion */
+	if (status)
+		return status;
+
+	p->thread_id = thread_id;
+	p->enabled = 1;
+
+	return 0;
+}
+
+int
+thread_pipeline_disable(uint32_t thread_id,
+	const char *pipeline_name)
+{
+	struct pipeline *p = pipeline_find(pipeline_name);
+	struct thread *t;
+	struct thread_msg_req *req;
+	struct thread_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if ((thread_id >= RTE_MAX_LCORE) ||
+		(p == NULL))
+		return -1;
+
+	t = &thread[thread_id];
+	if (t->enabled == 0)
+		return -1;
+
+	if (p->enabled == 0)
+		return 0;
+
+	if (p->thread_id != thread_id)
+		return -1;
+
+	/* Allocate request */
+	req = thread_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = THREAD_REQ_PIPELINE_DISABLE;
+	req->pipeline_disable.p = p->p;
+
+	/* Send request and wait for response */
+	rsp = thread_msg_send_recv(thread_id, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+
+	/* Free response */
+	thread_msg_free(rsp);
+
+	/* Request completion */
+	if (status)
+		return status;
+
+	p->enabled = 0;
+
+	return 0;
+}
+
+/**
  * Data plane threads: message handling
  */
 static inline struct thread_msg_req *
@@ -200,6 +377,79 @@ thread_msg_send(struct rte_ring *msgq_rsp,
 	} while (status == -ENOBUFS);
 }
 
+static struct thread_msg_rsp *
+thread_msg_handle_pipeline_enable(struct thread_data *t,
+	struct thread_msg_req *req)
+{
+	struct thread_msg_rsp *rsp = (struct thread_msg_rsp *) req;
+	struct pipeline_data *p = &t->pipeline_data[t->n_pipelines];
+	uint32_t i;
+
+	/* Request */
+	if (t->n_pipelines >= THREAD_PIPELINES_MAX) {
+		rsp->status = -1;
+		return rsp;
+	}
+
+	t->p[t->n_pipelines] = req->pipeline_enable.p;
+
+	p->p = req->pipeline_enable.p;
+	for (i = 0; i < req->pipeline_enable.n_tables; i++)
+		p->table_data[i].a =
+			req->pipeline_enable.table[i].a;
+
+	p->n_tables = req->pipeline_enable.n_tables;
+
+	p->msgq_req = req->pipeline_enable.msgq_req;
+	p->msgq_rsp = req->pipeline_enable.msgq_rsp;
+	p->timer_period =
+		(rte_get_tsc_hz() * req->pipeline_enable.timer_period_ms) / 1000;
+	p->time_next = rte_get_tsc_cycles() + p->timer_period;
+
+	t->n_pipelines++;
+
+	/* Response */
+	rsp->status = 0;
+	return rsp;
+}
+
+static struct thread_msg_rsp *
+thread_msg_handle_pipeline_disable(struct thread_data *t,
+	struct thread_msg_req *req)
+{
+	struct thread_msg_rsp *rsp = (struct thread_msg_rsp *) req;
+	uint32_t n_pipelines = t->n_pipelines;
+	struct rte_pipeline *pipeline = req->pipeline_disable.p;
+	uint32_t i;
+
+	/* find pipeline */
+	for (i = 0; i < n_pipelines; i++) {
+		struct pipeline_data *p = &t->pipeline_data[i];
+
+		if (p->p != pipeline)
+			continue;
+
+		if (i < n_pipelines - 1) {
+			struct rte_pipeline *pipeline_last =
+				t->p[n_pipelines - 1];
+			struct pipeline_data *p_last =
+				&t->pipeline_data[n_pipelines - 1];
+
+			t->p[i] = pipeline_last;
+			memcpy(p, p_last, sizeof(*p));
+		}
+
+		t->n_pipelines--;
+
+		rsp->status = 0;
+		return rsp;
+	}
+
+	/* should not get here */
+	rsp->status = 0;
+	return rsp;
+}
+
 static void
 thread_msg_handle(struct thread_data *t)
 {
@@ -212,6 +462,14 @@ thread_msg_handle(struct thread_data *t)
 			break;
 
 		switch (req->type) {
+		case THREAD_REQ_PIPELINE_ENABLE:
+			rsp = thread_msg_handle_pipeline_enable(t, req);
+			break;
+
+		case THREAD_REQ_PIPELINE_DISABLE:
+			rsp = thread_msg_handle_pipeline_disable(t, req);
+			break;
+
 		default:
 			rsp = (struct thread_msg_rsp *) req;
 			rsp->status = -1;
diff --git a/examples/ip_pipeline/thread.h b/examples/ip_pipeline/thread.h
index 47db428..facdf00 100644
--- a/examples/ip_pipeline/thread.h
+++ b/examples/ip_pipeline/thread.h
@@ -8,6 +8,14 @@
 #include <stdint.h>
 
 int
+thread_pipeline_enable(uint32_t thread_id,
+	const char *pipeline_name);
+
+int
+thread_pipeline_disable(uint32_t thread_id,
+	const char *pipeline_name);
+
+int
 thread_init(void);
 
 int
-- 
2.9.3

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

* [dpdk-dev] [PATCH v3 30/44] ip_pipeline: add cli to enable and disable pipeline port
  2018-03-16 17:58       ` [dpdk-dev] [PATCH v3 00/44] ip_pipeline: refactoring Jasvinder Singh
                           ` (28 preceding siblings ...)
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 29/44] ip_pipeline: add cli to enable and disable pipeline Jasvinder Singh
@ 2018-03-16 17:58         ` Jasvinder Singh
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 31/44] ip_pipeline: add cli to read pipeline port and table stats Jasvinder Singh
                           ` (13 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-16 17:58 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Fan Zhang

Add commands to enable and disable the pipeline ports.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Fan Zhang <roy.fan.zhang@intel.com>
---
 examples/ip_pipeline/cli.c      | 112 +++++++++++++++++++++++++++
 examples/ip_pipeline/pipeline.h |   8 ++
 examples/ip_pipeline/thread.c   | 163 +++++++++++++++++++++++++++++++++++++++-
 3 files changed, 282 insertions(+), 1 deletion(-)

diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index a3642b4..b9b2138 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -1742,6 +1742,100 @@ cmd_pipeline_port_in_table(char **tokens,
 }
 
 /**
+ * pipeline <pipeline_name> port in <port_id> enable
+ */
+static void
+cmd_pipeline_port_in_enable(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	char *pipeline_name;
+	uint32_t port_id;
+	int status;
+
+	if (n_tokens != 6) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "port") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
+		return;
+	}
+
+	if (strcmp(tokens[3], "in") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
+		return;
+	}
+
+	if (parser_read_uint32(&port_id, tokens[4]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
+		return;
+	}
+
+	if (strcmp(tokens[5], "enable") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable");
+		return;
+	}
+
+	status = pipeline_port_in_enable(pipeline_name, port_id);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
+ * pipeline <pipeline_name> port in <port_id> disable
+ */
+static void
+cmd_pipeline_port_in_disable(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	char *pipeline_name;
+	uint32_t port_id;
+	int status;
+
+	if (n_tokens != 6) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "port") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
+		return;
+	}
+
+	if (strcmp(tokens[3], "in") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
+		return;
+	}
+
+	if (parser_read_uint32(&port_id, tokens[4]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
+		return;
+	}
+
+	if (strcmp(tokens[5], "disable") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable");
+		return;
+	}
+
+	status = pipeline_port_in_disable(pipeline_name, port_id);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
  * thread <thread_id> pipeline <pipeline_name> enable
  */
 static void
@@ -1947,6 +2041,24 @@ cli_process(char *in, char *out, size_t out_size)
 				out, out_size);
 			return;
 		}
+
+		if ((n_tokens >= 6) &&
+			(strcmp(tokens[2], "port") == 0) &&
+			(strcmp(tokens[3], "in") == 0) &&
+			(strcmp(tokens[5], "enable") == 0)) {
+			cmd_pipeline_port_in_enable(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
+
+		if ((n_tokens >= 6) &&
+			(strcmp(tokens[2], "port") == 0) &&
+			(strcmp(tokens[3], "in") == 0) &&
+			(strcmp(tokens[5], "disable") == 0)) {
+			cmd_pipeline_port_in_disable(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
 	}
 
 	if (strcmp(tokens[0], "thread") == 0) {
diff --git a/examples/ip_pipeline/pipeline.h b/examples/ip_pipeline/pipeline.h
index dbc6f77..9b79b67 100644
--- a/examples/ip_pipeline/pipeline.h
+++ b/examples/ip_pipeline/pipeline.h
@@ -262,4 +262,12 @@ struct table_rule_action {
 	struct rte_table_action_time_params time;
 };
 
+int
+pipeline_port_in_enable(const char *pipeline_name,
+	uint32_t port_id);
+
+int
+pipeline_port_in_disable(const char *pipeline_name,
+	uint32_t port_id);
+
 #endif /* _INCLUDE_PIPELINE_H_ */
diff --git a/examples/ip_pipeline/thread.c b/examples/ip_pipeline/thread.c
index d707ad7..a47b645 100644
--- a/examples/ip_pipeline/thread.c
+++ b/examples/ip_pipeline/thread.c
@@ -482,13 +482,17 @@ thread_msg_handle(struct thread_data *t)
 /**
  * Master thread & data plane threads: message passing
  */
-
 enum pipeline_req_type {
+	/* Port IN */
+	PIPELINE_REQ_PORT_IN_ENABLE,
+	PIPELINE_REQ_PORT_IN_DISABLE,
+
 	PIPELINE_REQ_MAX
 };
 
 struct pipeline_msg_req {
 	enum pipeline_req_type type;
+	uint32_t id; /* Port IN, port OUT or table ID */
 };
 
 struct pipeline_msg_rsp {
@@ -496,6 +500,129 @@ struct pipeline_msg_rsp {
 };
 
 /**
+ * Master thread
+ */
+static struct pipeline_msg_req *
+pipeline_msg_alloc(void)
+{
+	size_t size = RTE_MAX(sizeof(struct pipeline_msg_req),
+		sizeof(struct pipeline_msg_rsp));
+
+	return calloc(1, size);
+}
+
+static void
+pipeline_msg_free(struct pipeline_msg_rsp *rsp)
+{
+	free(rsp);
+}
+
+static struct pipeline_msg_rsp *
+pipeline_msg_send_recv(struct pipeline *p,
+	struct pipeline_msg_req *req)
+{
+	struct rte_ring *msgq_req = p->msgq_req;
+	struct rte_ring *msgq_rsp = p->msgq_rsp;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* send */
+	do {
+		status = rte_ring_sp_enqueue(msgq_req, req);
+	} while (status == -ENOBUFS);
+
+	/* recv */
+	do {
+		status = rte_ring_sc_dequeue(msgq_rsp, (void **) &rsp);
+	} while (status != 0);
+
+	return rsp;
+}
+
+int
+pipeline_port_in_enable(const char *pipeline_name,
+	uint32_t port_id)
+{
+	struct pipeline *p;
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if (pipeline_name == NULL)
+		return -1;
+
+	p = pipeline_find(pipeline_name);
+	if ((p == NULL) ||
+		(port_id >= p->n_ports_in))
+		return -1;
+
+	/* Allocate request */
+	req = pipeline_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = PIPELINE_REQ_PORT_IN_ENABLE;
+	req->id = port_id;
+
+	/* Send request and wait for response */
+	rsp = pipeline_msg_send_recv(p, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+
+	/* Free response */
+	pipeline_msg_free(rsp);
+
+	return status;
+}
+
+int
+pipeline_port_in_disable(const char *pipeline_name,
+	uint32_t port_id)
+{
+	struct pipeline *p;
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if (pipeline_name == NULL)
+		return -1;
+
+	p = pipeline_find(pipeline_name);
+	if ((p == NULL) ||
+		(port_id >= p->n_ports_in))
+		return -1;
+
+	/* Allocate request */
+	req = pipeline_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = PIPELINE_REQ_PORT_IN_DISABLE;
+	req->id = port_id;
+
+	/* Send request and wait for response */
+	rsp = pipeline_msg_send_recv(p, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+
+	/* Free response */
+	pipeline_msg_free(rsp);
+
+	return status;
+}
+
+
+/**
  * Data plane threads: message handling
  */
 static inline struct pipeline_msg_req *
@@ -522,6 +649,32 @@ pipeline_msg_send(struct rte_ring *msgq_rsp,
 	} while (status == -ENOBUFS);
 }
 
+static struct pipeline_msg_rsp *
+pipeline_msg_handle_port_in_enable(struct pipeline_data *p,
+	struct pipeline_msg_req *req)
+{
+	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+	uint32_t port_id = req->id;
+
+	rsp->status = rte_pipeline_port_in_enable(p->p,
+		port_id);
+
+	return rsp;
+}
+
+static struct pipeline_msg_rsp *
+pipeline_msg_handle_port_in_disable(struct pipeline_data *p,
+	struct pipeline_msg_req *req)
+{
+	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+	uint32_t port_id = req->id;
+
+	rsp->status = rte_pipeline_port_in_disable(p->p,
+		port_id);
+
+	return rsp;
+}
+
 static void
 pipeline_msg_handle(struct pipeline_data *p)
 {
@@ -534,6 +687,14 @@ pipeline_msg_handle(struct pipeline_data *p)
 			break;
 
 		switch (req->type) {
+		case PIPELINE_REQ_PORT_IN_ENABLE:
+			rsp = pipeline_msg_handle_port_in_enable(p, req);
+			break;
+
+		case PIPELINE_REQ_PORT_IN_DISABLE:
+			rsp = pipeline_msg_handle_port_in_disable(p, req);
+			break;
+
 		default:
 			rsp = (struct pipeline_msg_rsp *) req;
 			rsp->status = -1;
-- 
2.9.3

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

* [dpdk-dev] [PATCH v3 31/44] ip_pipeline: add cli to read pipeline port and table stats
  2018-03-16 17:58       ` [dpdk-dev] [PATCH v3 00/44] ip_pipeline: refactoring Jasvinder Singh
                           ` (29 preceding siblings ...)
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 30/44] ip_pipeline: add cli to enable and disable pipeline port Jasvinder Singh
@ 2018-03-16 17:58         ` Jasvinder Singh
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 32/44] ip_pipeline: add cli for pipeline table entries Jasvinder Singh
                           ` (12 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-16 17:58 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Fan Zhang

Add commands to read the pipeline  port in, port out
and table stats.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Fan Zhang <roy.fan.zhang@intel.com>
---
 examples/ip_pipeline/cli.c      | 256 ++++++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/pipeline.h |  18 +++
 examples/ip_pipeline/thread.c   | 246 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 520 insertions(+)

diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index b9b2138..bbf98aa 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -1742,6 +1742,83 @@ cmd_pipeline_port_in_table(char **tokens,
 }
 
 /**
+ * pipeline <pipeline_name> port in <port_id> stats read [clear]
+ */
+
+#define MSG_PIPELINE_PORT_IN_STATS                         \
+	"Pkts in: %" PRIu64 "\n"                           \
+	"Pkts dropped by AH: %" PRIu64 "\n"                \
+	"Pkts dropped by other: %" PRIu64 "\n"
+
+static void
+cmd_pipeline_port_in_stats(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct rte_pipeline_port_in_stats stats;
+	char *pipeline_name;
+	uint32_t port_id;
+	int clear, status;
+
+	if ((n_tokens != 7) && (n_tokens != 8)) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "port") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
+		return;
+	}
+
+	if (strcmp(tokens[3], "in") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
+		return;
+	}
+
+	if (parser_read_uint32(&port_id, tokens[4]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
+		return;
+	}
+
+	if (strcmp(tokens[5], "stats") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
+		return;
+	}
+
+	if (strcmp(tokens[6], "read") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read");
+		return;
+	}
+
+	clear = 0;
+	if (n_tokens == 8) {
+		if (strcmp(tokens[7], "clear") != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "clear");
+			return;
+		}
+
+		clear = 1;
+	}
+
+	status = pipeline_port_in_stats_read(pipeline_name,
+		port_id,
+		&stats,
+		clear);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+
+	snprintf(out, out_size, MSG_PIPELINE_PORT_IN_STATS,
+		stats.stats.n_pkts_in,
+		stats.n_pkts_dropped_by_ah,
+		stats.stats.n_pkts_drop);
+}
+
+/**
  * pipeline <pipeline_name> port in <port_id> enable
  */
 static void
@@ -1836,6 +1913,159 @@ cmd_pipeline_port_in_disable(char **tokens,
 }
 
 /**
+ * pipeline <pipeline_name> port out <port_id> stats read [clear]
+ */
+#define MSG_PIPELINE_PORT_OUT_STATS                        \
+	"Pkts in: %" PRIu64 "\n"                           \
+	"Pkts dropped by AH: %" PRIu64 "\n"                \
+	"Pkts dropped by other: %" PRIu64 "\n"
+
+static void
+cmd_pipeline_port_out_stats(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct rte_pipeline_port_out_stats stats;
+	char *pipeline_name;
+	uint32_t port_id;
+	int clear, status;
+
+	if ((n_tokens != 7) && (n_tokens != 8)) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "port") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
+		return;
+	}
+
+	if (strcmp(tokens[3], "out") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "out");
+		return;
+	}
+
+	if (parser_read_uint32(&port_id, tokens[4]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
+		return;
+	}
+
+	if (strcmp(tokens[5], "stats") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
+		return;
+	}
+
+	if (strcmp(tokens[6], "read") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read");
+		return;
+	}
+
+	clear = 0;
+	if (n_tokens == 8) {
+		if (strcmp(tokens[7], "clear") != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "clear");
+			return;
+		}
+
+		clear = 1;
+	}
+
+	status = pipeline_port_out_stats_read(pipeline_name,
+		port_id,
+		&stats,
+		clear);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+
+	snprintf(out, out_size, MSG_PIPELINE_PORT_OUT_STATS,
+		stats.stats.n_pkts_in,
+		stats.n_pkts_dropped_by_ah,
+		stats.stats.n_pkts_drop);
+}
+
+/**
+ * pipeline <pipeline_name> table <table_id> stats read [clear]
+ */
+#define MSG_PIPELINE_TABLE_STATS                                     \
+	"Pkts in: %" PRIu64 "\n"                                     \
+	"Pkts in with lookup miss: %" PRIu64 "\n"                    \
+	"Pkts in with lookup hit dropped by AH: %" PRIu64 "\n"       \
+	"Pkts in with lookup hit dropped by others: %" PRIu64 "\n"   \
+	"Pkts in with lookup miss dropped by AH: %" PRIu64 "\n"      \
+	"Pkts in with lookup miss dropped by others: %" PRIu64 "\n"
+
+static void
+cmd_pipeline_table_stats(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct rte_pipeline_table_stats stats;
+	char *pipeline_name;
+	uint32_t table_id;
+	int clear, status;
+
+	if ((n_tokens != 6) && (n_tokens != 7)) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "table") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
+		return;
+	}
+
+	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
+		return;
+	}
+
+	if (strcmp(tokens[4], "stats") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
+		return;
+	}
+
+	if (strcmp(tokens[5], "read") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read");
+		return;
+	}
+
+	clear = 0;
+	if (n_tokens == 7) {
+		if (strcmp(tokens[6], "clear") != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "clear");
+			return;
+		}
+
+		clear = 1;
+	}
+
+	status = pipeline_table_stats_read(pipeline_name,
+		table_id,
+		&stats,
+		clear);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+
+	snprintf(out, out_size, MSG_PIPELINE_TABLE_STATS,
+		stats.stats.n_pkts_in,
+		stats.stats.n_pkts_lookup_miss,
+		stats.n_pkts_dropped_by_lkp_hit_ah,
+		stats.n_pkts_dropped_lkp_hit,
+		stats.n_pkts_dropped_by_lkp_miss_ah,
+		stats.n_pkts_dropped_lkp_miss);
+}
+
+/**
  * thread <thread_id> pipeline <pipeline_name> enable
  */
 static void
@@ -2045,6 +2275,15 @@ cli_process(char *in, char *out, size_t out_size)
 		if ((n_tokens >= 6) &&
 			(strcmp(tokens[2], "port") == 0) &&
 			(strcmp(tokens[3], "in") == 0) &&
+			(strcmp(tokens[5], "stats") == 0)) {
+			cmd_pipeline_port_in_stats(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
+
+		if ((n_tokens >= 6) &&
+			(strcmp(tokens[2], "port") == 0) &&
+			(strcmp(tokens[3], "in") == 0) &&
 			(strcmp(tokens[5], "enable") == 0)) {
 			cmd_pipeline_port_in_enable(tokens, n_tokens,
 				out, out_size);
@@ -2059,6 +2298,23 @@ cli_process(char *in, char *out, size_t out_size)
 				out, out_size);
 			return;
 		}
+
+		if ((n_tokens >= 6) &&
+			(strcmp(tokens[2], "port") == 0) &&
+			(strcmp(tokens[3], "out") == 0) &&
+			(strcmp(tokens[5], "stats") == 0)) {
+			cmd_pipeline_port_out_stats(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
+
+		if ((n_tokens >= 5) &&
+			(strcmp(tokens[2], "table") == 0) &&
+			(strcmp(tokens[4], "stats") == 0)) {
+			cmd_pipeline_table_stats(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
 	}
 
 	if (strcmp(tokens[0], "thread") == 0) {
diff --git a/examples/ip_pipeline/pipeline.h b/examples/ip_pipeline/pipeline.h
index 9b79b67..9b2c295 100644
--- a/examples/ip_pipeline/pipeline.h
+++ b/examples/ip_pipeline/pipeline.h
@@ -263,6 +263,12 @@ struct table_rule_action {
 };
 
 int
+pipeline_port_in_stats_read(const char *pipeline_name,
+	uint32_t port_id,
+	struct rte_pipeline_port_in_stats *stats,
+	int clear);
+
+int
 pipeline_port_in_enable(const char *pipeline_name,
 	uint32_t port_id);
 
@@ -270,4 +276,16 @@ int
 pipeline_port_in_disable(const char *pipeline_name,
 	uint32_t port_id);
 
+int
+pipeline_port_out_stats_read(const char *pipeline_name,
+	uint32_t port_id,
+	struct rte_pipeline_port_out_stats *stats,
+	int clear);
+
+int
+pipeline_table_stats_read(const char *pipeline_name,
+	uint32_t table_id,
+	struct rte_pipeline_table_stats *stats,
+	int clear);
+
 #endif /* _INCLUDE_PIPELINE_H_ */
diff --git a/examples/ip_pipeline/thread.c b/examples/ip_pipeline/thread.c
index a47b645..a18a820 100644
--- a/examples/ip_pipeline/thread.c
+++ b/examples/ip_pipeline/thread.c
@@ -484,19 +484,64 @@ thread_msg_handle(struct thread_data *t)
  */
 enum pipeline_req_type {
 	/* Port IN */
+	PIPELINE_REQ_PORT_IN_STATS_READ,
 	PIPELINE_REQ_PORT_IN_ENABLE,
 	PIPELINE_REQ_PORT_IN_DISABLE,
 
+	/* Port OUT */
+	PIPELINE_REQ_PORT_OUT_STATS_READ,
+
+	/* Table */
+	PIPELINE_REQ_TABLE_STATS_READ,
+
 	PIPELINE_REQ_MAX
 };
 
+struct pipeline_msg_req_port_in_stats_read {
+	int clear;
+};
+
+struct pipeline_msg_req_port_out_stats_read {
+	int clear;
+};
+
+struct pipeline_msg_req_table_stats_read {
+	int clear;
+};
+
 struct pipeline_msg_req {
 	enum pipeline_req_type type;
 	uint32_t id; /* Port IN, port OUT or table ID */
+
+	RTE_STD_C11
+	union {
+		struct pipeline_msg_req_port_in_stats_read port_in_stats_read;
+		struct pipeline_msg_req_port_out_stats_read port_out_stats_read;
+		struct pipeline_msg_req_table_stats_read table_stats_read;
+	};
+};
+
+struct pipeline_msg_rsp_port_in_stats_read {
+	struct rte_pipeline_port_in_stats stats;
+};
+
+struct pipeline_msg_rsp_port_out_stats_read {
+	struct rte_pipeline_port_out_stats stats;
+};
+
+struct pipeline_msg_rsp_table_stats_read {
+	struct rte_pipeline_table_stats stats;
 };
 
 struct pipeline_msg_rsp {
 	int status;
+
+	RTE_STD_C11
+	union {
+		struct pipeline_msg_rsp_port_in_stats_read port_in_stats_read;
+		struct pipeline_msg_rsp_port_out_stats_read port_out_stats_read;
+		struct pipeline_msg_rsp_table_stats_read table_stats_read;
+	};
 };
 
 /**
@@ -540,6 +585,53 @@ pipeline_msg_send_recv(struct pipeline *p,
 }
 
 int
+pipeline_port_in_stats_read(const char *pipeline_name,
+	uint32_t port_id,
+	struct rte_pipeline_port_in_stats *stats,
+	int clear)
+{
+	struct pipeline *p;
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if ((pipeline_name == NULL) ||
+		(stats == NULL))
+		return -1;
+
+	p = pipeline_find(pipeline_name);
+	if ((p == NULL) ||
+		(port_id >= p->n_ports_in))
+		return -1;
+
+	/* Allocate request */
+	req = pipeline_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = PIPELINE_REQ_PORT_IN_STATS_READ;
+	req->id = port_id;
+	req->port_in_stats_read.clear = clear;
+
+	/* Send request and wait for response */
+	rsp = pipeline_msg_send_recv(p, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+	if (status)
+		memcpy(stats, &rsp->port_in_stats_read.stats, sizeof(*stats));
+
+	/* Free response */
+	pipeline_msg_free(rsp);
+
+	return status;
+}
+
+int
 pipeline_port_in_enable(const char *pipeline_name,
 	uint32_t port_id)
 {
@@ -621,6 +713,99 @@ pipeline_port_in_disable(const char *pipeline_name,
 	return status;
 }
 
+int
+pipeline_port_out_stats_read(const char *pipeline_name,
+	uint32_t port_id,
+	struct rte_pipeline_port_out_stats *stats,
+	int clear)
+{
+	struct pipeline *p;
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if ((pipeline_name == NULL) ||
+		(stats == NULL))
+		return -1;
+
+	p = pipeline_find(pipeline_name);
+	if ((p == NULL) ||
+		(port_id >= p->n_ports_out))
+		return -1;
+
+	/* Allocate request */
+	req = pipeline_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = PIPELINE_REQ_PORT_OUT_STATS_READ;
+	req->id = port_id;
+	req->port_out_stats_read.clear = clear;
+
+	/* Send request and wait for response */
+	rsp = pipeline_msg_send_recv(p, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+	if (status)
+		memcpy(stats, &rsp->port_out_stats_read.stats, sizeof(*stats));
+
+	/* Free response */
+	pipeline_msg_free(rsp);
+
+	return status;
+}
+
+int
+pipeline_table_stats_read(const char *pipeline_name,
+	uint32_t table_id,
+	struct rte_pipeline_table_stats *stats,
+	int clear)
+{
+	struct pipeline *p;
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if ((pipeline_name == NULL) ||
+		(stats == NULL))
+		return -1;
+
+	p = pipeline_find(pipeline_name);
+	if ((p == NULL) ||
+		(table_id >= p->n_tables))
+		return -1;
+
+	/* Allocate request */
+	req = pipeline_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = PIPELINE_REQ_TABLE_STATS_READ;
+	req->id = table_id;
+	req->table_stats_read.clear = clear;
+
+	/* Send request and wait for response */
+	rsp = pipeline_msg_send_recv(p, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+	if (status)
+		memcpy(stats, &rsp->table_stats_read.stats, sizeof(*stats));
+
+	/* Free response */
+	pipeline_msg_free(rsp);
+
+	return status;
+}
 
 /**
  * Data plane threads: message handling
@@ -650,6 +835,22 @@ pipeline_msg_send(struct rte_ring *msgq_rsp,
 }
 
 static struct pipeline_msg_rsp *
+pipeline_msg_handle_port_in_stats_read(struct pipeline_data *p,
+	struct pipeline_msg_req *req)
+{
+	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+	uint32_t port_id = req->id;
+	int clear = req->port_in_stats_read.clear;
+
+	rsp->status = rte_pipeline_port_in_stats_read(p->p,
+		port_id,
+		&rsp->port_in_stats_read.stats,
+		clear);
+
+	return rsp;
+}
+
+static struct pipeline_msg_rsp *
 pipeline_msg_handle_port_in_enable(struct pipeline_data *p,
 	struct pipeline_msg_req *req)
 {
@@ -675,6 +876,38 @@ pipeline_msg_handle_port_in_disable(struct pipeline_data *p,
 	return rsp;
 }
 
+static struct pipeline_msg_rsp *
+pipeline_msg_handle_port_out_stats_read(struct pipeline_data *p,
+	struct pipeline_msg_req *req)
+{
+	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+	uint32_t port_id = req->id;
+	int clear = req->port_out_stats_read.clear;
+
+	rsp->status = rte_pipeline_port_out_stats_read(p->p,
+		port_id,
+		&rsp->port_out_stats_read.stats,
+		clear);
+
+	return rsp;
+}
+
+static struct pipeline_msg_rsp *
+pipeline_msg_handle_table_stats_read(struct pipeline_data *p,
+	struct pipeline_msg_req *req)
+{
+	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+	uint32_t port_id = req->id;
+	int clear = req->table_stats_read.clear;
+
+	rsp->status = rte_pipeline_table_stats_read(p->p,
+		port_id,
+		&rsp->table_stats_read.stats,
+		clear);
+
+	return rsp;
+}
+
 static void
 pipeline_msg_handle(struct pipeline_data *p)
 {
@@ -687,6 +920,10 @@ pipeline_msg_handle(struct pipeline_data *p)
 			break;
 
 		switch (req->type) {
+		case PIPELINE_REQ_PORT_IN_STATS_READ:
+			rsp = pipeline_msg_handle_port_in_stats_read(p, req);
+			break;
+
 		case PIPELINE_REQ_PORT_IN_ENABLE:
 			rsp = pipeline_msg_handle_port_in_enable(p, req);
 			break;
@@ -695,6 +932,15 @@ pipeline_msg_handle(struct pipeline_data *p)
 			rsp = pipeline_msg_handle_port_in_disable(p, req);
 			break;
 
+		case PIPELINE_REQ_PORT_OUT_STATS_READ:
+			rsp = pipeline_msg_handle_port_out_stats_read(p, req);
+			break;
+
+		case PIPELINE_REQ_TABLE_STATS_READ:
+			rsp = pipeline_msg_handle_table_stats_read(p, req);
+			break;
+
+
 		default:
 			rsp = (struct pipeline_msg_rsp *) req;
 			rsp->status = -1;
-- 
2.9.3

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

* [dpdk-dev] [PATCH v3 32/44] ip_pipeline: add cli for pipeline table entries
  2018-03-16 17:58       ` [dpdk-dev] [PATCH v3 00/44] ip_pipeline: refactoring Jasvinder Singh
                           ` (30 preceding siblings ...)
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 31/44] ip_pipeline: add cli to read pipeline port and table stats Jasvinder Singh
@ 2018-03-16 17:58         ` Jasvinder Singh
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 33/44] ip_pipeline: add cli to delete pipeline table entry Jasvinder Singh
                           ` (11 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-16 17:58 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add commands to add pipeline table entries which contains match and
action part.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/cli.c      | 1273 +++++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/pipeline.h |   13 +
 examples/ip_pipeline/thread.c   |  749 +++++++++++++++++++++++
 3 files changed, 2035 insertions(+)

diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index bbf98aa..b353b99 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -8,6 +8,7 @@
 #include <string.h>
 
 #include <rte_common.h>
+#include <rte_cycles.h>
 
 #include "cli.h"
 #include "kni.h"
@@ -2066,6 +2067,1261 @@ cmd_pipeline_table_stats(char **tokens,
 }
 
 /**
+ * <match> ::=
+ *
+ * match
+ *    acl
+ *       priority <priority>
+ *       ipv4 | ipv6 <sa> <sa_depth> <da> <da_depth>
+ *       <sp0> <sp1> <dp0> <dp1> <proto>
+ *    | array
+ *       pos
+ *    | hash
+ *       raw <key>
+ *       | ipv4_5tuple <sa> <da> <sp> <dp> <proto>
+ *       | ipv6_5tuple <sa> <da> <sp> <dp> <proto>
+ *       | ipv4_addr <addr>
+ *       | ipv6_addr <addr>
+ *       | qinq <svlan> <cvlan>
+ *    | lpm
+ *       ipv4 | ipv6 <addr> <depth>
+ */
+struct pkt_key_qinq {
+	uint16_t ethertype_svlan;
+	uint16_t svlan;
+	uint16_t ethertype_cvlan;
+	uint16_t cvlan;
+} __attribute__((__packed__));
+
+struct pkt_key_ipv4_5tuple {
+	uint8_t time_to_live;
+	uint8_t proto;
+	uint16_t hdr_checksum;
+	uint32_t sa;
+	uint32_t da;
+	uint16_t sp;
+	uint16_t dp;
+} __attribute__((__packed__));
+
+struct pkt_key_ipv6_5tuple {
+	uint16_t payload_length;
+	uint8_t proto;
+	uint8_t hop_limit;
+	uint8_t sa[16];
+	uint8_t da[16];
+	uint16_t sp;
+	uint16_t dp;
+} __attribute__((__packed__));
+
+struct pkt_key_ipv4_addr {
+	uint32_t addr;
+} __attribute__((__packed__));
+
+struct pkt_key_ipv6_addr {
+	uint8_t addr[16];
+} __attribute__((__packed__));
+
+static uint32_t
+parse_match(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size,
+	struct table_rule_match *m)
+{
+	memset(m, 0, sizeof(*m));
+
+	if (n_tokens < 2)
+		return 0;
+
+	if (strcmp(tokens[0], "match") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match");
+		return 0;
+	}
+
+	if (strcmp(tokens[1], "acl") == 0) {
+		if (n_tokens < 14) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+			return 0;
+		}
+
+		m->match_type = TABLE_ACL;
+
+		if (strcmp(tokens[2], "priority") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "priority");
+			return 0;
+		}
+
+		if (parser_read_uint32(&m->match.acl.priority,
+			tokens[3]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "priority");
+			return 0;
+		}
+
+		if (strcmp(tokens[4], "ipv4") == 0) {
+			struct in_addr saddr, daddr;
+
+			m->match.acl.ip_version = 1;
+
+			if (parse_ipv4_addr(tokens[5], &saddr) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID, "sa");
+				return 0;
+			}
+			m->match.acl.ipv4.sa = rte_be_to_cpu_32(saddr.s_addr);
+
+			if (parse_ipv4_addr(tokens[7], &daddr) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID, "da");
+				return 0;
+			}
+			m->match.acl.ipv4.da = rte_be_to_cpu_32(daddr.s_addr);
+		} else if (strcmp(tokens[4], "ipv6") == 0) {
+			struct in6_addr saddr, daddr;
+
+			m->match.acl.ip_version = 0;
+
+			if (parse_ipv6_addr(tokens[5], &saddr) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID, "sa");
+				return 0;
+			}
+			memcpy(m->match.acl.ipv6.sa, saddr.s6_addr, 16);
+
+			if (parse_ipv6_addr(tokens[7], &daddr) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID, "da");
+				return 0;
+			}
+			memcpy(m->match.acl.ipv6.da, daddr.s6_addr, 16);
+		} else {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+				"ipv4 or ipv6");
+			return 0;
+		}
+
+		if (parser_read_uint32(&m->match.acl.sa_depth,
+			tokens[6]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "sa_depth");
+			return 0;
+		}
+
+		if (parser_read_uint32(&m->match.acl.da_depth,
+			tokens[8]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "da_depth");
+			return 0;
+		}
+
+		if (parser_read_uint16(&m->match.acl.sp0, tokens[9]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "sp0");
+			return 0;
+		}
+
+		if (parser_read_uint16(&m->match.acl.sp1, tokens[10]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "sp1");
+			return 0;
+		}
+
+		if (parser_read_uint16(&m->match.acl.dp0, tokens[11]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "dp0");
+			return 0;
+		}
+
+		if (parser_read_uint16(&m->match.acl.dp1, tokens[12]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "dp1");
+			return 0;
+		}
+
+		if (parser_read_uint8(&m->match.acl.proto, tokens[13]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "proto");
+			return 0;
+		}
+
+		m->match.acl.proto_mask = 0xff;
+
+		return 14;
+	} /* acl */
+
+	if (strcmp(tokens[1], "array") == 0) {
+		if (n_tokens < 3) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+			return 0;
+		}
+
+		m->match_type = TABLE_ARRAY;
+
+		if (parser_read_uint32(&m->match.array.pos, tokens[2]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "pos");
+			return 0;
+		}
+
+		return 3;
+	} /* array */
+
+	if (strcmp(tokens[1], "hash") == 0) {
+		if (n_tokens < 3) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+			return 0;
+		}
+
+		m->match_type = TABLE_HASH;
+
+		if (strcmp(tokens[2], "raw") == 0) {
+			uint32_t key_size = TABLE_RULE_MATCH_SIZE_MAX;
+
+			if (n_tokens < 4) {
+				snprintf(out, out_size, MSG_ARG_MISMATCH,
+					tokens[0]);
+				return 0;
+			}
+
+			if (parse_hex_string(tokens[3],
+				m->match.hash.key, &key_size) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID, "key");
+				return 0;
+			}
+
+			return 4;
+		} /* hash raw */
+
+		if (strcmp(tokens[2], "ipv4_5tuple") == 0) {
+			struct pkt_key_ipv4_5tuple *ipv4 =
+				(struct pkt_key_ipv4_5tuple *) m->match.hash.key;
+			struct in_addr saddr, daddr;
+			uint16_t sp, dp;
+			uint8_t proto;
+
+			if (n_tokens < 8) {
+				snprintf(out, out_size, MSG_ARG_MISMATCH,
+					tokens[0]);
+				return 0;
+			}
+
+			if (parse_ipv4_addr(tokens[3], &saddr) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID, "sa");
+				return 0;
+			}
+
+			if (parse_ipv4_addr(tokens[4], &daddr) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID, "da");
+				return 0;
+			}
+
+			if (parser_read_uint16(&sp, tokens[5]) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID, "sp");
+				return 0;
+			}
+
+			if (parser_read_uint16(&dp, tokens[6]) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID, "dp");
+				return 0;
+			}
+
+			if (parser_read_uint8(&proto, tokens[7]) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID,
+					"proto");
+				return 0;
+			}
+
+			ipv4->sa = saddr.s_addr;
+			ipv4->da = daddr.s_addr;
+			ipv4->sp = rte_cpu_to_be_16(sp);
+			ipv4->dp = rte_cpu_to_be_16(dp);
+			ipv4->proto = proto;
+
+			return 8;
+		} /* hash ipv4_5tuple */
+
+		if (strcmp(tokens[2], "ipv6_5tuple") == 0) {
+			struct pkt_key_ipv6_5tuple *ipv6 =
+				(struct pkt_key_ipv6_5tuple *) m->match.hash.key;
+			struct in6_addr saddr, daddr;
+			uint16_t sp, dp;
+			uint8_t proto;
+
+			if (n_tokens < 8) {
+				snprintf(out, out_size, MSG_ARG_MISMATCH,
+					tokens[0]);
+				return 0;
+			}
+
+			if (parse_ipv6_addr(tokens[3], &saddr) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID, "sa");
+				return 0;
+			}
+
+			if (parse_ipv6_addr(tokens[4], &daddr) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID, "da");
+				return 0;
+			}
+
+			if (parser_read_uint16(&sp, tokens[5]) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID, "sp");
+				return 0;
+			}
+
+			if (parser_read_uint16(&dp, tokens[6]) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID, "dp");
+				return 0;
+			}
+
+			if (parser_read_uint8(&proto, tokens[7]) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID,
+					"proto");
+				return 0;
+			}
+
+			memcpy(ipv6->sa, saddr.s6_addr, 16);
+			memcpy(ipv6->da, daddr.s6_addr, 16);
+			ipv6->sp = rte_cpu_to_be_16(sp);
+			ipv6->dp = rte_cpu_to_be_16(dp);
+			ipv6->proto = proto;
+
+			return 8;
+		} /* hash ipv6_5tuple */
+
+		if (strcmp(tokens[2], "ipv4_addr") == 0) {
+			struct pkt_key_ipv4_addr *ipv4_addr =
+				(struct pkt_key_ipv4_addr *) m->match.hash.key;
+			struct in_addr addr;
+
+			if (n_tokens < 4) {
+				snprintf(out, out_size, MSG_ARG_MISMATCH,
+					tokens[0]);
+				return 0;
+			}
+
+			if (parse_ipv4_addr(tokens[3], &addr) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID,
+					"addr");
+				return 0;
+			}
+
+			ipv4_addr->addr = addr.s_addr;
+
+			return 4;
+		} /* hash ipv4_addr */
+
+		if (strcmp(tokens[2], "ipv6_addr") == 0) {
+			struct pkt_key_ipv6_addr *ipv6_addr =
+				(struct pkt_key_ipv6_addr *) m->match.hash.key;
+			struct in6_addr addr;
+
+			if (n_tokens < 4) {
+				snprintf(out, out_size, MSG_ARG_MISMATCH,
+					tokens[0]);
+				return 0;
+			}
+
+			if (parse_ipv6_addr(tokens[3], &addr) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID,
+					"addr");
+				return 0;
+			}
+
+			memcpy(ipv6_addr->addr, addr.s6_addr, 16);
+
+			return 4;
+		} /* hash ipv6_5tuple */
+
+		if (strcmp(tokens[2], "qinq") == 0) {
+			struct pkt_key_qinq *qinq =
+				(struct pkt_key_qinq *) m->match.hash.key;
+			uint16_t svlan, cvlan;
+
+			if (n_tokens < 5) {
+				snprintf(out, out_size, MSG_ARG_MISMATCH,
+					tokens[0]);
+				return 0;
+			}
+
+			if ((parser_read_uint16(&svlan, tokens[3]) != 0) ||
+				(svlan > 0xFFF)) {
+				snprintf(out, out_size, MSG_ARG_INVALID,
+					"svlan");
+				return 0;
+			}
+
+			if ((parser_read_uint16(&cvlan, tokens[4]) != 0) ||
+				(cvlan > 0xFFF)) {
+				snprintf(out, out_size, MSG_ARG_INVALID,
+					"cvlan");
+				return 0;
+			}
+
+			qinq->svlan = rte_cpu_to_be_16(svlan);
+			qinq->cvlan = rte_cpu_to_be_16(cvlan);
+
+			return 5;
+		} /* hash qinq */
+
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return 0;
+	} /* hash */
+
+	if (strcmp(tokens[1], "lpm") == 0) {
+		if (n_tokens < 5) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+			return 0;
+		}
+
+		m->match_type = TABLE_LPM;
+
+		if (strcmp(tokens[2], "ipv4") == 0) {
+			struct in_addr addr;
+
+			m->match.lpm.ip_version = 1;
+
+			if (parse_ipv4_addr(tokens[3], &addr) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID,
+					"addr");
+				return 0;
+			}
+
+			m->match.lpm.ipv4 = rte_be_to_cpu_32(addr.s_addr);
+		} else if (strcmp(tokens[2], "ipv6") == 0) {
+			struct in6_addr addr;
+
+			m->match.lpm.ip_version = 0;
+
+			if (parse_ipv6_addr(tokens[3], &addr) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID,
+					"addr");
+				return 0;
+			}
+
+			memcpy(m->match.lpm.ipv6, addr.s6_addr, 16);
+		} else {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"ipv4 or ipv6");
+			return 0;
+		}
+
+		if (parser_read_uint8(&m->match.lpm.depth, tokens[4]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "depth");
+			return 0;
+		}
+
+		return 5;
+	} /* lpm */
+
+	snprintf(out, out_size, MSG_ARG_MISMATCH,
+		"acl or array or hash or lpm");
+	return 0;
+}
+
+/**
+ * table_action ::=
+ *
+ * action
+ *    fwd drop | port <port_id> | table <table_id>
+ *    [meter
+ *       tc0 meter <meter_profile_id> policer g <pa> y <pa> r <pa>
+ *       [tc1 meter <meter_profile_id> policer g <pa> y <pa> r <pa>
+ *        tc2 meter <meter_profile_id> policer g <pa> y <pa> r <pa>
+ *        tc3 meter <meter_profile_id> policer g <pa> y <pa> r <pa>]]
+ *    [tm subport <subport_id> pipe <pipe_id>]
+ *    [encap
+ *       ether <da> <sa>
+ *       | vlan <da> <sa> <pcp> <dei> <vid>
+ *       | qinq <da> <sa> <pcp> <dei> <vid> <pcp> <dei> <vid>
+ *       | mpls unicast | multicast
+ *          <da> <sa>
+ *          label0 <label> <tc> <ttl>
+ *          [label1 <label> <tc> <ttl>
+ *          [label2 <label> <tc> <ttl>
+ *          [label3 <label> <tc> <ttl>]]]
+ *       | pppoe <da> <sa> <session_id>]
+ *    [nat ipv4 | ipv6 <addr> <port>]
+ *    [ttl dec | keep]
+ *    [stats]
+ *    [time]
+ *
+ * where:
+ *    <pa> ::= g | y | r | drop
+ */
+static uint32_t
+parse_table_action_fwd(char **tokens,
+	uint32_t n_tokens,
+	struct table_rule_action *a)
+{
+	if ((n_tokens == 0) || (strcmp(tokens[0], "fwd") != 0))
+		return 0;
+
+	tokens++;
+	n_tokens--;
+
+	if (n_tokens && (strcmp(tokens[0], "drop") == 0)) {
+		a->fwd.action = RTE_PIPELINE_ACTION_DROP;
+		a->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
+		return 1 + 1;
+	}
+
+	if (n_tokens && (strcmp(tokens[0], "port") == 0)) {
+		uint32_t id;
+
+		if ((n_tokens < 2) ||
+			parser_read_uint32(&id, tokens[1]))
+			return 0;
+
+		a->fwd.action = RTE_PIPELINE_ACTION_PORT;
+		a->fwd.id = id;
+		a->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
+		return 1 + 2;
+	}
+
+	if (n_tokens && (strcmp(tokens[0], "table") == 0)) {
+		uint32_t id;
+
+		if ((n_tokens < 2) ||
+			parser_read_uint32(&id, tokens[1]))
+			return 0;
+
+		a->fwd.action = RTE_PIPELINE_ACTION_TABLE;
+		a->fwd.id = id;
+		a->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
+		return 1 + 2;
+	}
+
+	return 0;
+}
+
+static int
+parse_policer_action(char *token, enum rte_table_action_policer *a)
+{
+	if (strcmp(token, "g") == 0) {
+		*a = RTE_TABLE_ACTION_POLICER_COLOR_GREEN;
+		return 0;
+	}
+
+	if (strcmp(token, "y") == 0) {
+		*a = RTE_TABLE_ACTION_POLICER_COLOR_YELLOW;
+		return 0;
+	}
+
+	if (strcmp(token, "r") == 0) {
+		*a = RTE_TABLE_ACTION_POLICER_COLOR_RED;
+		return 0;
+	}
+
+	if (strcmp(token, "drop") == 0) {
+		*a = RTE_TABLE_ACTION_POLICER_DROP;
+		return 0;
+	}
+
+	return -1;
+}
+
+static uint32_t
+parse_table_action_meter_tc(char **tokens,
+	uint32_t n_tokens,
+	struct rte_table_action_mtr_tc_params *mtr)
+{
+	if ((n_tokens < 9) ||
+		strcmp(tokens[0], "meter") ||
+		parser_read_uint32(&mtr->meter_profile_id, tokens[1]) ||
+		strcmp(tokens[2], "policer") ||
+		strcmp(tokens[3], "g") ||
+		parse_policer_action(tokens[4], &mtr->policer[e_RTE_METER_GREEN]) ||
+		strcmp(tokens[5], "y") ||
+		parse_policer_action(tokens[6], &mtr->policer[e_RTE_METER_YELLOW]) ||
+		strcmp(tokens[7], "r") ||
+		parse_policer_action(tokens[8], &mtr->policer[e_RTE_METER_RED]))
+		return 0;
+
+	return 9;
+}
+
+static uint32_t
+parse_table_action_meter(char **tokens,
+	uint32_t n_tokens,
+	struct table_rule_action *a)
+{
+	if ((n_tokens == 0) || strcmp(tokens[0], "meter"))
+		return 0;
+
+	tokens++;
+	n_tokens--;
+
+	if ((n_tokens < 10) ||
+		strcmp(tokens[0], "tc0") ||
+		(parse_table_action_meter_tc(tokens + 1,
+			n_tokens - 1,
+			&a->mtr.mtr[0]) == 0))
+		return 0;
+
+	tokens += 10;
+	n_tokens -= 10;
+
+	if ((n_tokens == 0) || strcmp(tokens[0], "tc1")) {
+		a->mtr.tc_mask = 1;
+		a->action_mask |= 1 << RTE_TABLE_ACTION_MTR;
+		return 1 + 10;
+	}
+
+	if ((n_tokens < 30) ||
+		(parse_table_action_meter_tc(tokens + 1,
+			n_tokens - 1, &a->mtr.mtr[1]) == 0) ||
+		strcmp(tokens[10], "tc2") ||
+		(parse_table_action_meter_tc(tokens + 11,
+			n_tokens - 11, &a->mtr.mtr[2]) == 0) ||
+		strcmp(tokens[20], "tc3") ||
+		(parse_table_action_meter_tc(tokens + 21,
+			n_tokens - 21, &a->mtr.mtr[3]) == 0))
+		return 0;
+
+	a->mtr.tc_mask = 0xF;
+	a->action_mask |= 1 << RTE_TABLE_ACTION_MTR;
+	return 1 + 10 + 3 * 10;
+}
+
+static uint32_t
+parse_table_action_tm(char **tokens,
+	uint32_t n_tokens,
+	struct table_rule_action *a)
+{
+	uint32_t subport_id, pipe_id;
+
+	if ((n_tokens < 5) ||
+		strcmp(tokens[0], "tm") ||
+		strcmp(tokens[1], "subport") ||
+		parser_read_uint32(&subport_id, tokens[2]) ||
+		strcmp(tokens[3], "pipe") ||
+		parser_read_uint32(&pipe_id, tokens[4]))
+		return 0;
+
+	a->tm.subport_id = subport_id;
+	a->tm.pipe_id = pipe_id;
+	a->action_mask |= 1 << RTE_TABLE_ACTION_TM;
+	return 5;
+}
+
+static uint32_t
+parse_table_action_encap(char **tokens,
+	uint32_t n_tokens,
+	struct table_rule_action *a)
+{
+	if ((n_tokens == 0) || strcmp(tokens[0], "encap"))
+		return 0;
+
+	tokens++;
+	n_tokens--;
+
+	/* ether */
+	if (n_tokens && (strcmp(tokens[0], "ether") == 0)) {
+		if ((n_tokens < 3) ||
+			parse_mac_addr(tokens[1], &a->encap.ether.ether.da) ||
+			parse_mac_addr(tokens[2], &a->encap.ether.ether.sa))
+			return 0;
+
+		a->encap.type = RTE_TABLE_ACTION_ENCAP_ETHER;
+		a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
+		return 1 + 3;
+	}
+
+	/* vlan */
+	if (n_tokens && (strcmp(tokens[0], "vlan") == 0)) {
+		uint32_t pcp, dei, vid;
+
+		if ((n_tokens < 6) ||
+			parse_mac_addr(tokens[1], &a->encap.vlan.ether.da) ||
+			parse_mac_addr(tokens[2], &a->encap.vlan.ether.sa) ||
+			parser_read_uint32(&pcp, tokens[3]) ||
+			(pcp > 0x7) ||
+			parser_read_uint32(&dei, tokens[4]) ||
+			(dei > 0x1) ||
+			parser_read_uint32(&vid, tokens[5]) ||
+			(vid > 0xFFF))
+			return 0;
+
+		a->encap.vlan.vlan.pcp = pcp & 0x7;
+		a->encap.vlan.vlan.dei = dei & 0x1;
+		a->encap.vlan.vlan.vid = vid & 0xFFF;
+		a->encap.type = RTE_TABLE_ACTION_ENCAP_VLAN;
+		a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
+		return 1 + 6;
+	}
+
+	/* qinq */
+	if (n_tokens && (strcmp(tokens[0], "qinq") == 0)) {
+		uint32_t svlan_pcp, svlan_dei, svlan_vid;
+		uint32_t cvlan_pcp, cvlan_dei, cvlan_vid;
+
+		if ((n_tokens < 9) ||
+			parse_mac_addr(tokens[1], &a->encap.qinq.ether.da) ||
+			parse_mac_addr(tokens[2], &a->encap.qinq.ether.sa) ||
+			parser_read_uint32(&svlan_pcp, tokens[3]) ||
+			(svlan_pcp > 0x7) ||
+			parser_read_uint32(&svlan_dei, tokens[4]) ||
+			(svlan_dei > 0x1) ||
+			parser_read_uint32(&svlan_vid, tokens[5]) ||
+			(svlan_vid > 0xFFF) ||
+			parser_read_uint32(&cvlan_pcp, tokens[6]) ||
+			(cvlan_pcp > 0x7) ||
+			parser_read_uint32(&cvlan_dei, tokens[7]) ||
+			(cvlan_dei > 0x1) ||
+			parser_read_uint32(&cvlan_vid, tokens[8]) ||
+			(cvlan_vid > 0xFFF))
+			return 0;
+
+		a->encap.qinq.svlan.pcp = svlan_pcp & 0x7;
+		a->encap.qinq.svlan.dei = svlan_dei & 0x1;
+		a->encap.qinq.svlan.vid = svlan_vid & 0xFFF;
+		a->encap.qinq.cvlan.pcp = cvlan_pcp & 0x7;
+		a->encap.qinq.cvlan.dei = cvlan_dei & 0x1;
+		a->encap.qinq.cvlan.vid = cvlan_vid & 0xFFF;
+		a->encap.type = RTE_TABLE_ACTION_ENCAP_QINQ;
+		a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
+		return 1 + 9;
+	}
+
+	/* mpls */
+	if (n_tokens && (strcmp(tokens[0], "mpls") == 0)) {
+		uint32_t label, tc, ttl;
+
+		if (n_tokens < 8)
+			return 0;
+
+		if (strcmp(tokens[1], "unicast") == 0)
+			a->encap.mpls.unicast = 1;
+		else if (strcmp(tokens[1], "multicast") == 0)
+			a->encap.mpls.unicast = 0;
+		else
+			return 0;
+
+		if (parse_mac_addr(tokens[2], &a->encap.mpls.ether.da) ||
+			parse_mac_addr(tokens[3], &a->encap.mpls.ether.sa) ||
+			strcmp(tokens[4], "label0") ||
+			parser_read_uint32(&label, tokens[5]) ||
+			(label > 0xFFFFF) ||
+			parser_read_uint32(&tc, tokens[6]) ||
+			(tc > 0x7) ||
+			parser_read_uint32(&ttl, tokens[7]) ||
+			(ttl > 0x3F))
+			return 0;
+
+		a->encap.mpls.mpls[0].label = label;
+		a->encap.mpls.mpls[0].tc = tc;
+		a->encap.mpls.mpls[0].ttl = ttl;
+
+		tokens += 8;
+		n_tokens -= 8;
+
+		if ((n_tokens == 0) || strcmp(tokens[0], "label1")) {
+			a->encap.mpls.mpls_count = 1;
+			a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS;
+			a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
+			return 1 + 8;
+		}
+
+		if ((n_tokens < 4) ||
+			parser_read_uint32(&label, tokens[1]) ||
+			(label > 0xFFFFF) ||
+			parser_read_uint32(&tc, tokens[2]) ||
+			(tc > 0x7) ||
+			parser_read_uint32(&ttl, tokens[3]) ||
+			(ttl > 0x3F))
+			return 0;
+
+		a->encap.mpls.mpls[1].label = label;
+		a->encap.mpls.mpls[1].tc = tc;
+		a->encap.mpls.mpls[1].ttl = ttl;
+
+		tokens += 4;
+		n_tokens -= 4;
+
+		if ((n_tokens == 0) || strcmp(tokens[0], "label2")) {
+			a->encap.mpls.mpls_count = 2;
+			a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS;
+			a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
+			return 1 + 8 + 4;
+		}
+
+		if ((n_tokens < 4) ||
+			parser_read_uint32(&label, tokens[1]) ||
+			(label > 0xFFFFF) ||
+			parser_read_uint32(&tc, tokens[2]) ||
+			(tc > 0x7) ||
+			parser_read_uint32(&ttl, tokens[3]) ||
+			(ttl > 0x3F))
+			return 0;
+
+		a->encap.mpls.mpls[2].label = label;
+		a->encap.mpls.mpls[2].tc = tc;
+		a->encap.mpls.mpls[2].ttl = ttl;
+
+		tokens += 4;
+		n_tokens -= 4;
+
+		if ((n_tokens == 0) || strcmp(tokens[0], "label3")) {
+			a->encap.mpls.mpls_count = 3;
+			a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS;
+			a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
+			return 1 + 8 + 4 + 4;
+		}
+
+		if ((n_tokens < 4) ||
+			parser_read_uint32(&label, tokens[1]) ||
+			(label > 0xFFFFF) ||
+			parser_read_uint32(&tc, tokens[2]) ||
+			(tc > 0x7) ||
+			parser_read_uint32(&ttl, tokens[3]) ||
+			(ttl > 0x3F))
+			return 0;
+
+		a->encap.mpls.mpls[3].label = label;
+		a->encap.mpls.mpls[3].tc = tc;
+		a->encap.mpls.mpls[3].ttl = ttl;
+
+		a->encap.mpls.mpls_count = 4;
+		a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS;
+		a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
+		return 1 + 8 + 4 + 4 + 4;
+	}
+
+	/* pppoe */
+	if (n_tokens && (strcmp(tokens[0], "pppoe") == 0)) {
+		if ((n_tokens < 4) ||
+			parse_mac_addr(tokens[1], &a->encap.pppoe.ether.da) ||
+			parse_mac_addr(tokens[2], &a->encap.pppoe.ether.sa) ||
+			parser_read_uint16(&a->encap.pppoe.pppoe.session_id,
+				tokens[3]))
+			return 0;
+
+		a->encap.type = RTE_TABLE_ACTION_ENCAP_PPPOE;
+		a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
+		return 1 + 4;
+	}
+
+	return 0;
+}
+
+static uint32_t
+parse_table_action_nat(char **tokens,
+	uint32_t n_tokens,
+	struct table_rule_action *a)
+{
+	if ((n_tokens < 4) ||
+		strcmp(tokens[0], "nat"))
+		return 0;
+
+	if (strcmp(tokens[1], "ipv4") == 0) {
+		struct in_addr addr;
+		uint16_t port;
+
+		if (parse_ipv4_addr(tokens[2], &addr) ||
+			parser_read_uint16(&port, tokens[3]))
+			return 0;
+
+		a->nat.ip_version = 1;
+		a->nat.addr.ipv4 = rte_be_to_cpu_32(addr.s_addr);
+		a->nat.port = port;
+		a->action_mask |= 1 << RTE_TABLE_ACTION_NAT;
+		return 4;
+	}
+
+	if (strcmp(tokens[1], "ipv6") == 0) {
+		struct in6_addr addr;
+		uint16_t port;
+
+		if (parse_ipv6_addr(tokens[2], &addr) ||
+			parser_read_uint16(&port, tokens[3]))
+			return 0;
+
+		a->nat.ip_version = 0;
+		memcpy(a->nat.addr.ipv6, addr.s6_addr, 16);
+		a->nat.port = port;
+		a->action_mask |= 1 << RTE_TABLE_ACTION_NAT;
+		return 4;
+	}
+
+	return 0;
+}
+
+static uint32_t
+parse_table_action_ttl(char **tokens,
+	uint32_t n_tokens,
+	struct table_rule_action *a)
+{
+	if ((n_tokens < 2) ||
+		strcmp(tokens[0], "ttl"))
+		return 0;
+
+	if (strcmp(tokens[1], "dec") == 0)
+		a->ttl.decrement = 1;
+	else if (strcmp(tokens[1], "keep") == 0)
+		a->ttl.decrement = 0;
+	else
+		return 0;
+
+	a->action_mask |= 1 << RTE_TABLE_ACTION_TTL;
+	return 2;
+}
+
+static uint32_t
+parse_table_action_stats(char **tokens,
+	uint32_t n_tokens,
+	struct table_rule_action *a)
+{
+	if ((n_tokens < 1) ||
+		strcmp(tokens[0], "stats"))
+		return 0;
+
+	a->stats.n_packets = 0;
+	a->stats.n_bytes = 0;
+	a->action_mask |= 1 << RTE_TABLE_ACTION_STATS;
+	return 1;
+}
+
+static uint32_t
+parse_table_action_time(char **tokens,
+	uint32_t n_tokens,
+	struct table_rule_action *a)
+{
+	if ((n_tokens < 1) ||
+		strcmp(tokens[0], "time"))
+		return 0;
+
+	a->time.time = rte_rdtsc();
+	a->action_mask |= 1 << RTE_TABLE_ACTION_TIME;
+	return 1;
+}
+
+static uint32_t
+parse_table_action(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size,
+	struct table_rule_action *a)
+{
+	uint32_t n_tokens0 = n_tokens;
+
+	memset(a, 0, sizeof(*a));
+
+	if ((n_tokens < 2) ||
+		strcmp(tokens[0], "action"))
+		return 0;
+
+	tokens++;
+	n_tokens--;
+
+	if (n_tokens && (strcmp(tokens[0], "fwd") == 0)) {
+		uint32_t n;
+
+		n = parse_table_action_fwd(tokens, n_tokens, a);
+		if (n == 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID,
+				"action fwd");
+			return 0;
+		}
+
+		tokens += n;
+		n_tokens -= n;
+	}
+
+	if (n_tokens && (strcmp(tokens[0], "meter") == 0)) {
+		uint32_t n;
+
+		n = parse_table_action_meter(tokens, n_tokens, a);
+		if (n == 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID,
+				"action meter");
+			return 0;
+		}
+
+		tokens += n;
+		n_tokens -= n;
+	}
+
+	if (n_tokens && (strcmp(tokens[0], "tm") == 0)) {
+		uint32_t n;
+
+		n = parse_table_action_tm(tokens, n_tokens, a);
+		if (n == 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID,
+				"action tm");
+			return 0;
+		}
+
+		tokens += n;
+		n_tokens -= n;
+	}
+
+	if (n_tokens && (strcmp(tokens[0], "encap") == 0)) {
+		uint32_t n;
+
+		n = parse_table_action_encap(tokens, n_tokens, a);
+		if (n == 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID,
+				"action encap");
+			return 0;
+		}
+
+		tokens += n;
+		n_tokens -= n;
+	}
+
+	if (n_tokens && (strcmp(tokens[0], "nat") == 0)) {
+		uint32_t n;
+
+		n = parse_table_action_nat(tokens, n_tokens, a);
+		if (n == 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID,
+				"action nat");
+			return 0;
+		}
+
+		tokens += n;
+		n_tokens -= n;
+	}
+
+	if (n_tokens && (strcmp(tokens[0], "ttl") == 0)) {
+		uint32_t n;
+
+		n = parse_table_action_ttl(tokens, n_tokens, a);
+		if (n == 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID,
+				"action ttl");
+			return 0;
+		}
+
+		tokens += n;
+		n_tokens -= n;
+	}
+
+	if (n_tokens && (strcmp(tokens[0], "stats") == 0)) {
+		uint32_t n;
+
+		n = parse_table_action_stats(tokens, n_tokens, a);
+		if (n == 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID,
+				"action stats");
+			return 0;
+		}
+
+		tokens += n;
+		n_tokens -= n;
+	}
+
+	if (n_tokens && (strcmp(tokens[0], "time") == 0)) {
+		uint32_t n;
+
+		n = parse_table_action_time(tokens, n_tokens, a);
+		if (n == 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID,
+				"action time");
+			return 0;
+		}
+
+		tokens += n;
+		n_tokens -= n;
+	}
+
+	if (n_tokens0 - n_tokens == 1) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "action");
+		return 0;
+	}
+
+	return n_tokens0 - n_tokens;
+}
+
+/**
+ * pipeline <pipeline_name> table <table_id> rule add
+ *    match <match>
+ *    action <table_action>
+ */
+static void
+cmd_pipeline_table_rule_add(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct table_rule_match m;
+	struct table_rule_action a;
+	char *pipeline_name;
+	void *data;
+	uint32_t table_id, t0, n_tokens_parsed;
+	int status;
+
+	if (n_tokens < 8) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "table") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
+		return;
+	}
+
+	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
+		return;
+	}
+
+	if (strcmp(tokens[4], "rule") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
+		return;
+	}
+
+	if (strcmp(tokens[5], "add") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
+		return;
+	}
+
+	t0 = 6;
+
+	/* match */
+	n_tokens_parsed = parse_match(tokens + t0,
+		n_tokens - t0,
+		out,
+		out_size,
+		&m);
+	if (n_tokens_parsed == 0)
+		return;
+	t0 += n_tokens_parsed;
+
+	/* action */
+	n_tokens_parsed = parse_table_action(tokens + t0,
+		n_tokens - t0,
+		out,
+		out_size,
+		&a);
+	if (n_tokens_parsed == 0)
+		return;
+	t0 += n_tokens_parsed;
+
+	if (t0 != n_tokens) {
+		snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
+		return;
+	}
+
+	status = pipeline_table_rule_add(pipeline_name, table_id,
+		&m, &a, &data);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
+ * pipeline <pipeline_name> table <table_id> rule add
+ *    match
+ *       default
+ *    action
+ *       fwd drop | port <port_id> | table <table_id>
+ */
+static void
+cmd_pipeline_table_rule_add_default(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct table_rule_action action;
+	void *data;
+	char *pipeline_name;
+	uint32_t table_id;
+	int status;
+
+	if ((n_tokens != 11) && (n_tokens != 12)) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "table") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
+		return;
+	}
+
+	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
+		return;
+	}
+
+	if (strcmp(tokens[4], "rule") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
+		return;
+	}
+
+	if (strcmp(tokens[5], "add") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
+		return;
+	}
+
+	if (strcmp(tokens[6], "match") != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "match");
+		return;
+	}
+
+	if (strcmp(tokens[7], "default") != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "default");
+		return;
+	}
+
+	if (strcmp(tokens[8], "action") != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "action");
+		return;
+	}
+
+	if (strcmp(tokens[9], "fwd") != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "fwd");
+		return;
+	}
+
+	action.action_mask = 1 << RTE_TABLE_ACTION_FWD;
+
+	if (strcmp(tokens[10], "drop") == 0) {
+		if (n_tokens != 11) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+			return;
+		}
+
+		action.fwd.action = RTE_PIPELINE_ACTION_DROP;
+	} else if (strcmp(tokens[10], "port") == 0) {
+		uint32_t id;
+
+		if (n_tokens != 12) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+			return;
+		}
+
+		if (parser_read_uint32(&id, tokens[11]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
+			return;
+		}
+
+		action.fwd.action = RTE_PIPELINE_ACTION_PORT;
+		action.fwd.id = id;
+	} else if (strcmp(tokens[10], "table") == 0) {
+		uint32_t id;
+
+		if (n_tokens != 12) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+			return;
+		}
+
+		if (parser_read_uint32(&id, tokens[11]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
+			return;
+		}
+
+		action.fwd.action = RTE_PIPELINE_ACTION_TABLE;
+		action.fwd.id = id;
+	} else {
+		snprintf(out, out_size, MSG_ARG_INVALID,
+			"drop or port or table");
+		return;
+	}
+
+	status = pipeline_table_rule_add_default(pipeline_name,
+		table_id,
+		&action,
+		&data);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
  * thread <thread_id> pipeline <pipeline_name> enable
  */
 static void
@@ -2315,6 +3571,23 @@ cli_process(char *in, char *out, size_t out_size)
 				out, out_size);
 			return;
 		}
+
+		if ((n_tokens >= 7) &&
+			(strcmp(tokens[2], "table") == 0) &&
+			(strcmp(tokens[4], "rule") == 0) &&
+			(strcmp(tokens[5], "add") == 0) &&
+			(strcmp(tokens[6], "match") == 0)) {
+			if ((n_tokens >= 8) &&
+				(strcmp(tokens[7], "default") == 0)) {
+				cmd_pipeline_table_rule_add_default(tokens,
+					n_tokens, out, out_size);
+				return;
+			}
+
+			cmd_pipeline_table_rule_add(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
 	}
 
 	if (strcmp(tokens[0], "thread") == 0) {
diff --git a/examples/ip_pipeline/pipeline.h b/examples/ip_pipeline/pipeline.h
index 9b2c295..9351024 100644
--- a/examples/ip_pipeline/pipeline.h
+++ b/examples/ip_pipeline/pipeline.h
@@ -288,4 +288,17 @@ pipeline_table_stats_read(const char *pipeline_name,
 	struct rte_pipeline_table_stats *stats,
 	int clear);
 
+int
+pipeline_table_rule_add(const char *pipeline_name,
+	uint32_t table_id,
+	struct table_rule_match *match,
+	struct table_rule_action *action,
+	void **data);
+
+int
+pipeline_table_rule_add_default(const char *pipeline_name,
+	uint32_t table_id,
+	struct table_rule_action *action,
+	void **data);
+
 #endif /* _INCLUDE_PIPELINE_H_ */
diff --git a/examples/ip_pipeline/thread.c b/examples/ip_pipeline/thread.c
index a18a820..be12d20 100644
--- a/examples/ip_pipeline/thread.c
+++ b/examples/ip_pipeline/thread.c
@@ -493,6 +493,8 @@ enum pipeline_req_type {
 
 	/* Table */
 	PIPELINE_REQ_TABLE_STATS_READ,
+	PIPELINE_REQ_TABLE_RULE_ADD,
+	PIPELINE_REQ_TABLE_RULE_ADD_DEFAULT,
 
 	PIPELINE_REQ_MAX
 };
@@ -509,6 +511,15 @@ struct pipeline_msg_req_table_stats_read {
 	int clear;
 };
 
+struct pipeline_msg_req_table_rule_add {
+	struct table_rule_match match;
+	struct table_rule_action action;
+};
+
+struct pipeline_msg_req_table_rule_add_default {
+	struct table_rule_action action;
+};
+
 struct pipeline_msg_req {
 	enum pipeline_req_type type;
 	uint32_t id; /* Port IN, port OUT or table ID */
@@ -518,6 +529,8 @@ struct pipeline_msg_req {
 		struct pipeline_msg_req_port_in_stats_read port_in_stats_read;
 		struct pipeline_msg_req_port_out_stats_read port_out_stats_read;
 		struct pipeline_msg_req_table_stats_read table_stats_read;
+		struct pipeline_msg_req_table_rule_add table_rule_add;
+		struct pipeline_msg_req_table_rule_add_default table_rule_add_default;
 	};
 };
 
@@ -533,6 +546,14 @@ struct pipeline_msg_rsp_table_stats_read {
 	struct rte_pipeline_table_stats stats;
 };
 
+struct pipeline_msg_rsp_table_rule_add {
+	void *data;
+};
+
+struct pipeline_msg_rsp_table_rule_add_default {
+	void *data;
+};
+
 struct pipeline_msg_rsp {
 	int status;
 
@@ -541,6 +562,8 @@ struct pipeline_msg_rsp {
 		struct pipeline_msg_rsp_port_in_stats_read port_in_stats_read;
 		struct pipeline_msg_rsp_port_out_stats_read port_out_stats_read;
 		struct pipeline_msg_rsp_table_stats_read table_stats_read;
+		struct pipeline_msg_rsp_table_rule_add table_rule_add;
+		struct pipeline_msg_rsp_table_rule_add_default table_rule_add_default;
 	};
 };
 
@@ -807,6 +830,270 @@ pipeline_table_stats_read(const char *pipeline_name,
 	return status;
 }
 
+static int
+match_check(struct table_rule_match *match,
+	struct pipeline *p,
+	uint32_t table_id)
+{
+	struct table *table;
+
+	if ((match == NULL) ||
+		(p == NULL) ||
+		(table_id >= p->n_tables))
+		return -1;
+
+	table = &p->table[table_id];
+	if (match->match_type != table->params.match_type)
+		return -1;
+
+	switch (match->match_type) {
+	case TABLE_ACL:
+	{
+		struct table_acl_params *t = &table->params.match.acl;
+		struct table_rule_match_acl *r = &match->match.acl;
+
+		if ((r->ip_version && (t->ip_version == 0)) ||
+			((r->ip_version == 0) && t->ip_version))
+			return -1;
+
+		if (r->ip_version) {
+			if ((r->sa_depth > 32) ||
+				(r->da_depth > 32))
+				return -1;
+		} else {
+			if ((r->sa_depth > 128) ||
+				(r->da_depth > 128))
+				return -1;
+		}
+		return 0;
+	}
+
+	case TABLE_ARRAY:
+		return 0;
+
+	case TABLE_HASH:
+		return 0;
+
+	case TABLE_LPM:
+	{
+		struct table_lpm_params *t = &table->params.match.lpm;
+		struct table_rule_match_lpm *r = &match->match.lpm;
+
+		if ((r->ip_version && (t->key_size != 4)) ||
+			((r->ip_version == 0) && (t->key_size != 16)))
+			return -1;
+
+		if (r->ip_version) {
+			if (r->depth > 32)
+				return -1;
+		} else {
+			if (r->depth > 128)
+				return -1;
+		}
+		return 0;
+	}
+
+	case TABLE_STUB:
+		return -1;
+
+	default:
+		return -1;
+	}
+}
+
+static int
+action_check(struct table_rule_action *action,
+	struct pipeline *p,
+	uint32_t table_id)
+{
+	struct table_action_profile *ap;
+
+	if ((action == NULL) ||
+		(p == NULL) ||
+		(table_id >= p->n_tables))
+		return -1;
+
+	ap = p->table[table_id].ap;
+	if (action->action_mask != ap->params.action_mask)
+		return -1;
+
+	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_FWD)) {
+		if ((action->fwd.action == RTE_PIPELINE_ACTION_PORT) &&
+			(action->fwd.id >= p->n_ports_out))
+			return -1;
+
+		if ((action->fwd.action == RTE_PIPELINE_ACTION_TABLE) &&
+			(action->fwd.id >= p->n_tables))
+			return -1;
+	}
+
+	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) {
+		uint32_t tc_mask0 = (1 << ap->params.mtr.n_tc) - 1;
+		uint32_t tc_mask1 = action->mtr.tc_mask;
+
+		if (tc_mask1 != tc_mask0)
+			return -1;
+	}
+
+	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_TM)) {
+		uint32_t n_subports_per_port =
+			ap->params.tm.n_subports_per_port;
+		uint32_t n_pipes_per_subport =
+			ap->params.tm.n_pipes_per_subport;
+		uint32_t subport_id = action->tm.subport_id;
+		uint32_t pipe_id = action->tm.pipe_id;
+
+		if ((subport_id >= n_subports_per_port) ||
+			(pipe_id >= n_pipes_per_subport))
+			return -1;
+	}
+
+	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_ENCAP)) {
+		uint64_t encap_mask = ap->params.encap.encap_mask;
+		enum rte_table_action_encap_type type = action->encap.type;
+
+		if ((encap_mask & (1LLU << type)) == 0)
+			return -1;
+	}
+
+	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_NAT)) {
+		int ip_version0 = ap->params.common.ip_version;
+		int ip_version1 = action->nat.ip_version;
+
+		if ((ip_version1 && (ip_version0 == 0)) ||
+			((ip_version1 == 0) && ip_version0))
+			return -1;
+	}
+
+	return 0;
+}
+
+static int
+action_default_check(struct table_rule_action *action,
+	struct pipeline *p,
+	uint32_t table_id)
+{
+	if ((action == NULL) ||
+		(action->action_mask != (1LLU << RTE_TABLE_ACTION_FWD)) ||
+		(p == NULL) ||
+		(table_id >= p->n_tables))
+		return -1;
+
+	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_FWD)) {
+		if ((action->fwd.action == RTE_PIPELINE_ACTION_PORT) &&
+			(action->fwd.id >= p->n_ports_out))
+			return -1;
+
+		if ((action->fwd.action == RTE_PIPELINE_ACTION_TABLE) &&
+			(action->fwd.id >= p->n_tables))
+			return -1;
+	}
+
+	return 0;
+}
+
+int
+pipeline_table_rule_add(const char *pipeline_name,
+	uint32_t table_id,
+	struct table_rule_match *match,
+	struct table_rule_action *action,
+	void **data)
+{
+	struct pipeline *p;
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if ((pipeline_name == NULL) ||
+		(match == NULL) ||
+		(action == NULL) ||
+		(data == NULL))
+		return -1;
+
+	p = pipeline_find(pipeline_name);
+	if ((p == NULL) ||
+		(table_id >= p->n_tables) ||
+		match_check(match, p, table_id) ||
+		action_check(action, p, table_id))
+		return -1;
+
+	/* Allocate request */
+	req = pipeline_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = PIPELINE_REQ_TABLE_RULE_ADD;
+	req->id = table_id;
+	memcpy(&req->table_rule_add.match, match, sizeof(*match));
+	memcpy(&req->table_rule_add.action, action, sizeof(*action));
+
+	/* Send request and wait for response */
+	rsp = pipeline_msg_send_recv(p, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+	if (status == 0)
+		*data = rsp->table_rule_add.data;
+
+	/* Free response */
+	pipeline_msg_free(rsp);
+
+	return status;
+}
+
+int
+pipeline_table_rule_add_default(const char *pipeline_name,
+	uint32_t table_id,
+	struct table_rule_action *action,
+	void **data)
+{
+	struct pipeline *p;
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if ((pipeline_name == NULL) ||
+		(action == NULL) ||
+		(data == NULL))
+		return -1;
+
+	p = pipeline_find(pipeline_name);
+	if ((p == NULL) ||
+		(table_id >= p->n_tables) ||
+		action_default_check(action, p, table_id))
+		return -1;
+
+	/* Allocate request */
+	req = pipeline_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = PIPELINE_REQ_TABLE_RULE_ADD_DEFAULT;
+	req->id = table_id;
+	memcpy(&req->table_rule_add_default.action, action, sizeof(*action));
+
+	/* Send request and wait for response */
+	rsp = pipeline_msg_send_recv(p, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+	if (status == 0)
+		*data = rsp->table_rule_add_default.data;
+
+	/* Free response */
+	pipeline_msg_free(rsp);
+
+	return status;
+}
+
 /**
  * Data plane threads: message handling
  */
@@ -908,6 +1195,461 @@ pipeline_msg_handle_table_stats_read(struct pipeline_data *p,
 	return rsp;
 }
 
+union table_rule_match_low_level {
+	struct rte_table_acl_rule_add_params acl_add;
+	struct rte_table_acl_rule_delete_params acl_delete;
+	struct rte_table_array_key array;
+	uint8_t hash[TABLE_RULE_MATCH_SIZE_MAX];
+	struct rte_table_lpm_key lpm_ipv4;
+	struct rte_table_lpm_ipv6_key lpm_ipv6;
+};
+
+static int
+match_convert_ipv6_depth(uint32_t depth, uint32_t *depth32)
+{
+	if (depth > 128)
+		return -1;
+
+	switch (depth / 32) {
+	case 0:
+		depth32[0] = depth;
+		depth32[1] = 0;
+		depth32[2] = 0;
+		depth32[3] = 0;
+		return 0;
+
+	case 1:
+		depth32[0] = 32;
+		depth32[1] = depth - 32;
+		depth32[2] = 0;
+		depth32[3] = 0;
+		return 0;
+
+	case 2:
+		depth32[0] = 32;
+		depth32[1] = 32;
+		depth32[2] = depth - 64;
+		depth32[3] = 0;
+		return 0;
+
+	case 3:
+		depth32[0] = 32;
+		depth32[1] = 32;
+		depth32[2] = 32;
+		depth32[3] = depth - 96;
+		return 0;
+
+	case 4:
+		depth32[0] = 32;
+		depth32[1] = 32;
+		depth32[2] = 32;
+		depth32[3] = 32;
+		return 0;
+
+	default:
+		return -1;
+	}
+}
+
+static int
+match_convert(struct table_rule_match *mh,
+	union table_rule_match_low_level *ml,
+	int add)
+{
+	memset(ml, 0, sizeof(*ml));
+
+	switch (mh->match_type) {
+	case TABLE_ACL:
+		if (mh->match.acl.ip_version)
+			if (add) {
+				ml->acl_add.field_value[0].value.u8 =
+					mh->match.acl.proto;
+				ml->acl_add.field_value[0].mask_range.u8 =
+					mh->match.acl.proto_mask;
+
+				ml->acl_add.field_value[1].value.u32 =
+					mh->match.acl.ipv4.sa;
+				ml->acl_add.field_value[1].mask_range.u32 =
+					mh->match.acl.sa_depth;
+
+				ml->acl_add.field_value[2].value.u32 =
+					mh->match.acl.ipv4.da;
+				ml->acl_add.field_value[2].mask_range.u32 =
+					mh->match.acl.da_depth;
+
+				ml->acl_add.field_value[3].value.u16 =
+					mh->match.acl.sp0;
+				ml->acl_add.field_value[3].mask_range.u16 =
+					mh->match.acl.sp1;
+
+				ml->acl_add.field_value[4].value.u16 =
+					mh->match.acl.dp0;
+				ml->acl_add.field_value[4].mask_range.u16 =
+					mh->match.acl.dp1;
+
+				ml->acl_add.priority =
+					(int32_t) mh->match.acl.priority;
+			} else {
+				ml->acl_delete.field_value[0].value.u8 =
+					mh->match.acl.proto;
+				ml->acl_delete.field_value[0].mask_range.u8 =
+					mh->match.acl.proto_mask;
+
+				ml->acl_delete.field_value[1].value.u32 =
+					mh->match.acl.ipv4.sa;
+				ml->acl_delete.field_value[1].mask_range.u32 =
+					mh->match.acl.sa_depth;
+
+				ml->acl_delete.field_value[2].value.u32 =
+					mh->match.acl.ipv4.da;
+				ml->acl_delete.field_value[2].mask_range.u32 =
+					mh->match.acl.da_depth;
+
+				ml->acl_delete.field_value[3].value.u16 =
+					mh->match.acl.sp0;
+				ml->acl_delete.field_value[3].mask_range.u16 =
+					mh->match.acl.sp1;
+
+				ml->acl_delete.field_value[4].value.u16 =
+					mh->match.acl.dp0;
+				ml->acl_delete.field_value[4].mask_range.u16 =
+					mh->match.acl.dp1;
+			}
+		else
+			if (add) {
+				uint32_t *sa32 =
+					(uint32_t *) mh->match.acl.ipv6.sa;
+				uint32_t *da32 =
+					(uint32_t *) mh->match.acl.ipv6.da;
+				uint32_t sa32_depth[4], da32_depth[4];
+				int status;
+
+				status = match_convert_ipv6_depth(
+					mh->match.acl.sa_depth,
+					sa32_depth);
+				if (status)
+					return status;
+
+				status = match_convert_ipv6_depth(
+					mh->match.acl.da_depth,
+					da32_depth);
+				if (status)
+					return status;
+
+				ml->acl_add.field_value[0].value.u8 =
+					mh->match.acl.proto;
+				ml->acl_add.field_value[0].mask_range.u8 =
+					mh->match.acl.proto_mask;
+
+				ml->acl_add.field_value[1].value.u32 = sa32[0];
+				ml->acl_add.field_value[1].mask_range.u32 =
+					sa32_depth[0];
+				ml->acl_add.field_value[2].value.u32 = sa32[1];
+				ml->acl_add.field_value[2].mask_range.u32 =
+					sa32_depth[1];
+				ml->acl_add.field_value[3].value.u32 = sa32[2];
+				ml->acl_add.field_value[3].mask_range.u32 =
+					sa32_depth[2];
+				ml->acl_add.field_value[4].value.u32 = sa32[3];
+				ml->acl_add.field_value[4].mask_range.u32 =
+					sa32_depth[3];
+
+				ml->acl_add.field_value[5].value.u32 = da32[0];
+				ml->acl_add.field_value[5].mask_range.u32 =
+					da32_depth[0];
+				ml->acl_add.field_value[6].value.u32 = da32[1];
+				ml->acl_add.field_value[6].mask_range.u32 =
+					da32_depth[1];
+				ml->acl_add.field_value[7].value.u32 = da32[2];
+				ml->acl_add.field_value[7].mask_range.u32 =
+					da32_depth[2];
+				ml->acl_add.field_value[8].value.u32 = da32[3];
+				ml->acl_add.field_value[8].mask_range.u32 =
+					da32_depth[3];
+
+				ml->acl_add.field_value[9].value.u16 =
+					mh->match.acl.sp0;
+				ml->acl_add.field_value[9].mask_range.u16 =
+					mh->match.acl.sp1;
+
+				ml->acl_add.field_value[10].value.u16 =
+					mh->match.acl.dp0;
+				ml->acl_add.field_value[10].mask_range.u16 =
+					mh->match.acl.dp1;
+
+				ml->acl_add.priority =
+					(int32_t) mh->match.acl.priority;
+			} else {
+				uint32_t *sa32 =
+					(uint32_t *) mh->match.acl.ipv6.sa;
+				uint32_t *da32 =
+					(uint32_t *) mh->match.acl.ipv6.da;
+				uint32_t sa32_depth[4], da32_depth[4];
+				int status;
+
+				status = match_convert_ipv6_depth(
+					mh->match.acl.sa_depth,
+					sa32_depth);
+				if (status)
+					return status;
+
+				status = match_convert_ipv6_depth(
+					mh->match.acl.da_depth,
+					da32_depth);
+				if (status)
+					return status;
+
+				ml->acl_delete.field_value[0].value.u8 =
+					mh->match.acl.proto;
+				ml->acl_delete.field_value[0].mask_range.u8 =
+					mh->match.acl.proto_mask;
+
+				ml->acl_delete.field_value[1].value.u32 =
+					sa32[0];
+				ml->acl_delete.field_value[1].mask_range.u32 =
+					sa32_depth[0];
+				ml->acl_delete.field_value[2].value.u32 =
+					sa32[1];
+				ml->acl_delete.field_value[2].mask_range.u32 =
+					sa32_depth[1];
+				ml->acl_delete.field_value[3].value.u32 =
+					sa32[2];
+				ml->acl_delete.field_value[3].mask_range.u32 =
+					sa32_depth[2];
+				ml->acl_delete.field_value[4].value.u32 =
+					sa32[3];
+				ml->acl_delete.field_value[4].mask_range.u32 =
+					sa32_depth[3];
+
+				ml->acl_delete.field_value[5].value.u32 =
+					da32[0];
+				ml->acl_delete.field_value[5].mask_range.u32 =
+					da32_depth[0];
+				ml->acl_delete.field_value[6].value.u32 =
+					da32[1];
+				ml->acl_delete.field_value[6].mask_range.u32 =
+					da32_depth[1];
+				ml->acl_delete.field_value[7].value.u32 =
+					da32[2];
+				ml->acl_delete.field_value[7].mask_range.u32 =
+					da32_depth[2];
+				ml->acl_delete.field_value[8].value.u32 =
+					da32[3];
+				ml->acl_delete.field_value[8].mask_range.u32 =
+					da32_depth[3];
+
+				ml->acl_delete.field_value[9].value.u16 =
+					mh->match.acl.sp0;
+				ml->acl_delete.field_value[9].mask_range.u16 =
+					mh->match.acl.sp1;
+
+				ml->acl_delete.field_value[10].value.u16 =
+					mh->match.acl.dp0;
+				ml->acl_delete.field_value[10].mask_range.u16 =
+					mh->match.acl.dp1;
+			}
+		return 0;
+
+	case TABLE_ARRAY:
+		ml->array.pos = mh->match.array.pos;
+		return 0;
+
+	case TABLE_HASH:
+		memcpy(ml->hash, mh->match.hash.key, sizeof(ml->hash));
+		return 0;
+
+	case TABLE_LPM:
+		if (mh->match.lpm.ip_version) {
+			ml->lpm_ipv4.ip = mh->match.lpm.ipv4;
+			ml->lpm_ipv4.depth = mh->match.lpm.depth;
+		} else {
+			memcpy(ml->lpm_ipv6.ip,
+				mh->match.lpm.ipv6, sizeof(ml->lpm_ipv6.ip));
+			ml->lpm_ipv6.depth = mh->match.lpm.depth;
+		}
+
+		return 0;
+
+	default:
+		return -1;
+	}
+}
+
+static struct pipeline_msg_rsp *
+pipeline_msg_handle_table_rule_add(struct pipeline_data *p,
+	struct pipeline_msg_req *req)
+{
+	union table_rule_match_low_level match_ll;
+	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+	struct table_rule_match *match = &req->table_rule_add.match;
+	struct table_rule_action *action = &req->table_rule_add.action;
+	struct rte_pipeline_table_entry *data_in, *data_out;
+	uint32_t table_id = req->id;
+	int key_found, status;
+	struct rte_table_action *a = p->table_data[table_id].a;
+
+	/* Apply actions */
+	memset(p->buffer, 0, sizeof(p->buffer));
+	data_in = (struct rte_pipeline_table_entry *) p->buffer;
+
+	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_FWD)) {
+		status = rte_table_action_apply(a,
+			data_in,
+			RTE_TABLE_ACTION_FWD,
+			&action->fwd);
+
+		if (status) {
+			rsp->status = -1;
+			return rsp;
+		}
+	}
+
+	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) {
+		status = rte_table_action_apply(a,
+			data_in,
+			RTE_TABLE_ACTION_MTR,
+			&action->mtr);
+
+		if (status) {
+			rsp->status = -1;
+			return rsp;
+		}
+	}
+
+	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_TM)) {
+		status = rte_table_action_apply(a,
+			data_in,
+			RTE_TABLE_ACTION_TM,
+			&action->tm);
+
+		if (status) {
+			rsp->status = -1;
+			return rsp;
+		}
+	}
+
+	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_ENCAP)) {
+		status = rte_table_action_apply(a,
+			data_in,
+			RTE_TABLE_ACTION_ENCAP,
+			&action->encap);
+
+		if (status) {
+			rsp->status = -1;
+			return rsp;
+		}
+	}
+
+	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_NAT)) {
+		status = rte_table_action_apply(a,
+			data_in,
+			RTE_TABLE_ACTION_NAT,
+			&action->nat);
+
+		if (status) {
+			rsp->status = -1;
+			return rsp;
+		}
+	}
+
+	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_TTL)) {
+		status = rte_table_action_apply(a,
+			data_in,
+			RTE_TABLE_ACTION_TTL,
+			&action->ttl);
+
+		if (status) {
+			rsp->status = -1;
+			return rsp;
+		}
+	}
+
+	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_STATS)) {
+		status = rte_table_action_apply(a,
+			data_in,
+			RTE_TABLE_ACTION_STATS,
+			&action->stats);
+
+		if (status) {
+			rsp->status = -1;
+			return rsp;
+		}
+	}
+
+	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_TIME)) {
+		status = rte_table_action_apply(a,
+			data_in,
+			RTE_TABLE_ACTION_TIME,
+			&action->time);
+
+		if (status) {
+			rsp->status = -1;
+			return rsp;
+		}
+	}
+
+	/* Add rule (match, action) to table */
+	status = match_convert(match, &match_ll, 1);
+	if (status) {
+		rsp->status = -1;
+		return rsp;
+	}
+
+	status = rte_pipeline_table_entry_add(p->p,
+		table_id,
+		&match_ll,
+		data_in,
+		&key_found,
+		&data_out);
+	if (status) {
+		rsp->status = -1;
+		return rsp;
+	}
+
+	/* Write response */
+	rsp->status = 0;
+	rsp->table_rule_add.data = data_out;
+
+	return rsp;
+}
+
+static struct pipeline_msg_rsp *
+pipeline_msg_handle_table_rule_add_default(struct pipeline_data *p,
+	struct pipeline_msg_req *req)
+{
+	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+	struct table_rule_action *action = &req->table_rule_add_default.action;
+	struct rte_pipeline_table_entry *data_in, *data_out;
+	uint32_t table_id = req->id;
+	int status;
+
+	/* Apply actions */
+	memset(p->buffer, 0, sizeof(p->buffer));
+	data_in = (struct rte_pipeline_table_entry *) p->buffer;
+
+	data_in->action = action->fwd.action;
+	if (action->fwd.action == RTE_PIPELINE_ACTION_PORT)
+		data_in->port_id = action->fwd.id;
+	if (action->fwd.action == RTE_PIPELINE_ACTION_TABLE)
+		data_in->table_id = action->fwd.id;
+
+	/* Add default rule to table */
+	status = rte_pipeline_table_default_entry_add(p->p,
+		table_id,
+		data_in,
+		&data_out);
+	if (status) {
+		rsp->status = -1;
+		return rsp;
+	}
+
+	/* Write response */
+	rsp->status = 0;
+	rsp->table_rule_add_default.data = data_out;
+
+	return rsp;
+}
+
 static void
 pipeline_msg_handle(struct pipeline_data *p)
 {
@@ -940,6 +1682,13 @@ pipeline_msg_handle(struct pipeline_data *p)
 			rsp = pipeline_msg_handle_table_stats_read(p, req);
 			break;
 
+		case PIPELINE_REQ_TABLE_RULE_ADD:
+			rsp = pipeline_msg_handle_table_rule_add(p, req);
+			break;
+
+		case PIPELINE_REQ_TABLE_RULE_ADD_DEFAULT:
+			rsp = pipeline_msg_handle_table_rule_add_default(p,	req);
+			break;
 
 		default:
 			rsp = (struct pipeline_msg_rsp *) req;
-- 
2.9.3

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

* [dpdk-dev] [PATCH v3 33/44] ip_pipeline: add cli to delete pipeline table entry
  2018-03-16 17:58       ` [dpdk-dev] [PATCH v3 00/44] ip_pipeline: refactoring Jasvinder Singh
                           ` (31 preceding siblings ...)
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 32/44] ip_pipeline: add cli for pipeline table entries Jasvinder Singh
@ 2018-03-16 17:58         ` Jasvinder Singh
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 34/44] ip_pipeline: add cli to read pipeline table entry stats Jasvinder Singh
                           ` (10 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-16 17:58 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add command to delete the pipeline table entry.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/cli.c      | 145 ++++++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/pipeline.h |   9 +++
 examples/ip_pipeline/thread.c   | 140 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 294 insertions(+)

diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index b353b99..88df168 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -3322,6 +3322,134 @@ cmd_pipeline_table_rule_add_default(char **tokens,
 }
 
 /**
+ * pipeline <pipeline_name> table <table_id> rule delete
+ *    match <match>
+ */
+static void
+cmd_pipeline_table_rule_delete(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct table_rule_match m;
+	char *pipeline_name;
+	uint32_t table_id, n_tokens_parsed, t0;
+	int status;
+
+	if (n_tokens < 8) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "table") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
+		return;
+	}
+
+	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
+		return;
+	}
+
+	if (strcmp(tokens[4], "rule") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
+		return;
+	}
+
+	if (strcmp(tokens[5], "delete") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete");
+		return;
+	}
+
+	t0 = 6;
+
+	/* match */
+	n_tokens_parsed = parse_match(tokens + t0,
+		n_tokens - t0,
+		out,
+		out_size,
+		&m);
+	if (n_tokens_parsed == 0)
+		return;
+	t0 += n_tokens_parsed;
+
+	if (n_tokens != t0) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	status = pipeline_table_rule_delete(pipeline_name,
+		table_id,
+		&m);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
+ * pipeline <pipeline_name> table <table_id> rule delete
+ *    match
+ *       default
+ */
+static void
+cmd_pipeline_table_rule_delete_default(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	char *pipeline_name;
+	uint32_t table_id;
+	int status;
+
+	if (n_tokens != 8) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "table") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
+		return;
+	}
+
+	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
+		return;
+	}
+
+	if (strcmp(tokens[4], "rule") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
+		return;
+	}
+
+	if (strcmp(tokens[5], "delete") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete");
+		return;
+	}
+
+	if (strcmp(tokens[6], "match") != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "match");
+		return;
+	}
+
+	if (strcmp(tokens[7], "default") != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "default");
+		return;
+	}
+
+	status = pipeline_table_rule_delete_default(pipeline_name,
+		table_id);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
  * thread <thread_id> pipeline <pipeline_name> enable
  */
 static void
@@ -3588,6 +3716,23 @@ cli_process(char *in, char *out, size_t out_size)
 				out, out_size);
 			return;
 		}
+
+		if ((n_tokens >= 7) &&
+			(strcmp(tokens[2], "table") == 0) &&
+			(strcmp(tokens[4], "rule") == 0) &&
+			(strcmp(tokens[5], "delete") == 0) &&
+			(strcmp(tokens[6], "match") == 0)) {
+			if ((n_tokens >= 8) &&
+				(strcmp(tokens[7], "default") == 0)) {
+				cmd_pipeline_table_rule_delete_default(tokens,
+					n_tokens, out, out_size);
+				return;
+				}
+
+			cmd_pipeline_table_rule_delete(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
 	}
 
 	if (strcmp(tokens[0], "thread") == 0) {
diff --git a/examples/ip_pipeline/pipeline.h b/examples/ip_pipeline/pipeline.h
index 9351024..2bf6360 100644
--- a/examples/ip_pipeline/pipeline.h
+++ b/examples/ip_pipeline/pipeline.h
@@ -301,4 +301,13 @@ pipeline_table_rule_add_default(const char *pipeline_name,
 	struct table_rule_action *action,
 	void **data);
 
+int
+pipeline_table_rule_delete(const char *pipeline_name,
+	uint32_t table_id,
+	struct table_rule_match *match);
+
+int
+pipeline_table_rule_delete_default(const char *pipeline_name,
+	uint32_t table_id);
+
 #endif /* _INCLUDE_PIPELINE_H_ */
diff --git a/examples/ip_pipeline/thread.c b/examples/ip_pipeline/thread.c
index be12d20..7f29f2d 100644
--- a/examples/ip_pipeline/thread.c
+++ b/examples/ip_pipeline/thread.c
@@ -495,6 +495,8 @@ enum pipeline_req_type {
 	PIPELINE_REQ_TABLE_STATS_READ,
 	PIPELINE_REQ_TABLE_RULE_ADD,
 	PIPELINE_REQ_TABLE_RULE_ADD_DEFAULT,
+	PIPELINE_REQ_TABLE_RULE_DELETE,
+	PIPELINE_REQ_TABLE_RULE_DELETE_DEFAULT,
 
 	PIPELINE_REQ_MAX
 };
@@ -520,6 +522,10 @@ struct pipeline_msg_req_table_rule_add_default {
 	struct table_rule_action action;
 };
 
+struct pipeline_msg_req_table_rule_delete {
+	struct table_rule_match match;
+};
+
 struct pipeline_msg_req {
 	enum pipeline_req_type type;
 	uint32_t id; /* Port IN, port OUT or table ID */
@@ -531,6 +537,7 @@ struct pipeline_msg_req {
 		struct pipeline_msg_req_table_stats_read table_stats_read;
 		struct pipeline_msg_req_table_rule_add table_rule_add;
 		struct pipeline_msg_req_table_rule_add_default table_rule_add_default;
+		struct pipeline_msg_req_table_rule_delete table_rule_delete;
 	};
 };
 
@@ -1094,6 +1101,92 @@ pipeline_table_rule_add_default(const char *pipeline_name,
 	return status;
 }
 
+int
+pipeline_table_rule_delete(const char *pipeline_name,
+	uint32_t table_id,
+	struct table_rule_match *match)
+{
+	struct pipeline *p;
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if ((pipeline_name == NULL) ||
+		(match == NULL))
+		return -1;
+
+	p = pipeline_find(pipeline_name);
+	if ((p == NULL) ||
+		(table_id >= p->n_tables) ||
+		match_check(match, p, table_id))
+		return -1;
+
+	/* Allocate request */
+	req = pipeline_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = PIPELINE_REQ_TABLE_RULE_DELETE;
+	req->id = table_id;
+	memcpy(&req->table_rule_delete.match, match, sizeof(*match));
+
+	/* Send request and wait for response */
+	rsp = pipeline_msg_send_recv(p, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+
+	/* Free response */
+	pipeline_msg_free(rsp);
+
+	return status;
+}
+
+int
+pipeline_table_rule_delete_default(const char *pipeline_name,
+	uint32_t table_id)
+{
+	struct pipeline *p;
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if (pipeline_name == NULL)
+		return -1;
+
+	p = pipeline_find(pipeline_name);
+	if ((p == NULL) ||
+		(table_id >= p->n_tables))
+		return -1;
+
+	/* Allocate request */
+	req = pipeline_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = PIPELINE_REQ_TABLE_RULE_DELETE_DEFAULT;
+	req->id = table_id;
+
+	/* Send request and wait for response */
+	rsp = pipeline_msg_send_recv(p, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+
+	/* Free response */
+	pipeline_msg_free(rsp);
+
+	return status;
+}
+
 /**
  * Data plane threads: message handling
  */
@@ -1650,6 +1743,45 @@ pipeline_msg_handle_table_rule_add_default(struct pipeline_data *p,
 	return rsp;
 }
 
+static struct pipeline_msg_rsp *
+pipeline_msg_handle_table_rule_delete(struct pipeline_data *p,
+	struct pipeline_msg_req *req)
+{
+	union table_rule_match_low_level match_ll;
+	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+	struct table_rule_match *match = &req->table_rule_delete.match;
+	uint32_t table_id = req->id;
+	int key_found, status;
+
+	status = match_convert(match, &match_ll, 0);
+	if (status) {
+		rsp->status = -1;
+		return rsp;
+	}
+
+	rsp->status = rte_pipeline_table_entry_delete(p->p,
+		table_id,
+		&match_ll,
+		&key_found,
+		NULL);
+
+	return rsp;
+}
+
+static struct pipeline_msg_rsp *
+pipeline_msg_handle_table_rule_delete_default(struct pipeline_data *p,
+	struct pipeline_msg_req *req)
+{
+	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+	uint32_t table_id = req->id;
+
+	rsp->status = rte_pipeline_table_default_entry_delete(p->p,
+		table_id,
+		NULL);
+
+	return rsp;
+}
+
 static void
 pipeline_msg_handle(struct pipeline_data *p)
 {
@@ -1690,6 +1822,14 @@ pipeline_msg_handle(struct pipeline_data *p)
 			rsp = pipeline_msg_handle_table_rule_add_default(p,	req);
 			break;
 
+		case PIPELINE_REQ_TABLE_RULE_DELETE:
+			rsp = pipeline_msg_handle_table_rule_delete(p, req);
+			break;
+
+		case PIPELINE_REQ_TABLE_RULE_DELETE_DEFAULT:
+			rsp = pipeline_msg_handle_table_rule_delete_default(p, req);
+			break;
+
 		default:
 			rsp = (struct pipeline_msg_rsp *) req;
 			rsp->status = -1;
-- 
2.9.3

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

* [dpdk-dev] [PATCH v3 34/44] ip_pipeline: add cli to read pipeline table entry stats
  2018-03-16 17:58       ` [dpdk-dev] [PATCH v3 00/44] ip_pipeline: refactoring Jasvinder Singh
                           ` (32 preceding siblings ...)
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 33/44] ip_pipeline: add cli to delete pipeline table entry Jasvinder Singh
@ 2018-03-16 17:58         ` Jasvinder Singh
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 35/44] ip_pipeline: add cli to configure meter profile Jasvinder Singh
                           ` (9 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-16 17:58 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Fan Zhang

Add command to read the pipeline table entry stats.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Fan Zhang <roy.fan.zhang@intel.com>
---
 examples/ip_pipeline/cli.c      | 22 +++++++++++
 examples/ip_pipeline/pipeline.h |  7 ++++
 examples/ip_pipeline/thread.c   | 84 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 113 insertions(+)

diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index 88df168..ee2c78d 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -3450,6 +3450,18 @@ cmd_pipeline_table_rule_delete_default(char **tokens,
 }
 
 /**
+ * pipeline <pipeline_name> table <table_id> rule read stats [clear]
+ */
+static void
+cmd_pipeline_table_rule_stats_read(char **tokens,
+	uint32_t n_tokens __rte_unused,
+	char *out,
+	size_t out_size)
+{
+	snprintf(out, out_size, MSG_CMD_UNIMPLEM, tokens[0]);
+}
+
+/**
  * thread <thread_id> pipeline <pipeline_name> enable
  */
 static void
@@ -3733,6 +3745,16 @@ cli_process(char *in, char *out, size_t out_size)
 				out, out_size);
 			return;
 		}
+
+		if ((n_tokens >= 7) &&
+			(strcmp(tokens[2], "table") == 0) &&
+			(strcmp(tokens[4], "rule") == 0) &&
+			(strcmp(tokens[5], "read") == 0) &&
+			(strcmp(tokens[6], "stats") == 0)) {
+			cmd_pipeline_table_rule_stats_read(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
 	}
 
 	if (strcmp(tokens[0], "thread") == 0) {
diff --git a/examples/ip_pipeline/pipeline.h b/examples/ip_pipeline/pipeline.h
index 2bf6360..296e4da 100644
--- a/examples/ip_pipeline/pipeline.h
+++ b/examples/ip_pipeline/pipeline.h
@@ -310,4 +310,11 @@ int
 pipeline_table_rule_delete_default(const char *pipeline_name,
 	uint32_t table_id);
 
+int
+pipeline_table_rule_stats_read(const char *pipeline_name,
+	uint32_t table_id,
+	void *data,
+	struct rte_table_action_stats_counters *stats,
+	int clear);
+
 #endif /* _INCLUDE_PIPELINE_H_ */
diff --git a/examples/ip_pipeline/thread.c b/examples/ip_pipeline/thread.c
index 7f29f2d..21f36ca 100644
--- a/examples/ip_pipeline/thread.c
+++ b/examples/ip_pipeline/thread.c
@@ -497,6 +497,7 @@ enum pipeline_req_type {
 	PIPELINE_REQ_TABLE_RULE_ADD_DEFAULT,
 	PIPELINE_REQ_TABLE_RULE_DELETE,
 	PIPELINE_REQ_TABLE_RULE_DELETE_DEFAULT,
+	PIPELINE_REQ_TABLE_RULE_STATS_READ,
 
 	PIPELINE_REQ_MAX
 };
@@ -526,6 +527,11 @@ struct pipeline_msg_req_table_rule_delete {
 	struct table_rule_match match;
 };
 
+struct pipeline_msg_req_table_rule_stats_read {
+	void *data;
+	int clear;
+};
+
 struct pipeline_msg_req {
 	enum pipeline_req_type type;
 	uint32_t id; /* Port IN, port OUT or table ID */
@@ -538,6 +544,7 @@ struct pipeline_msg_req {
 		struct pipeline_msg_req_table_rule_add table_rule_add;
 		struct pipeline_msg_req_table_rule_add_default table_rule_add_default;
 		struct pipeline_msg_req_table_rule_delete table_rule_delete;
+		struct pipeline_msg_req_table_rule_stats_read table_rule_stats_read;
 	};
 };
 
@@ -561,6 +568,10 @@ struct pipeline_msg_rsp_table_rule_add_default {
 	void *data;
 };
 
+struct pipeline_msg_rsp_table_rule_stats_read {
+	struct rte_table_action_stats_counters stats;
+};
+
 struct pipeline_msg_rsp {
 	int status;
 
@@ -571,6 +582,7 @@ struct pipeline_msg_rsp {
 		struct pipeline_msg_rsp_table_stats_read table_stats_read;
 		struct pipeline_msg_rsp_table_rule_add table_rule_add;
 		struct pipeline_msg_rsp_table_rule_add_default table_rule_add_default;
+		struct pipeline_msg_rsp_table_rule_stats_read table_rule_stats_read;
 	};
 };
 
@@ -1187,6 +1199,56 @@ pipeline_table_rule_delete_default(const char *pipeline_name,
 	return status;
 }
 
+int
+pipeline_table_rule_stats_read(const char *pipeline_name,
+	uint32_t table_id,
+	void *data,
+	struct rte_table_action_stats_counters *stats,
+	int clear)
+{
+	struct pipeline *p;
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if ((pipeline_name == NULL) ||
+		(data == NULL) ||
+		(stats == NULL))
+		return -1;
+
+	p = pipeline_find(pipeline_name);
+	if ((p == NULL) ||
+		(table_id >= p->n_tables))
+		return -1;
+
+	/* Allocate request */
+	req = pipeline_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = PIPELINE_REQ_TABLE_RULE_STATS_READ;
+	req->id = table_id;
+	req->table_rule_stats_read.data = data;
+	req->table_rule_stats_read.clear = clear;
+
+	/* Send request and wait for response */
+	rsp = pipeline_msg_send_recv(p, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+	if (status)
+		memcpy(stats, &rsp->table_rule_stats_read.stats, sizeof(*stats));
+
+	/* Free response */
+	pipeline_msg_free(rsp);
+
+	return status;
+}
+
 /**
  * Data plane threads: message handling
  */
@@ -1782,6 +1844,24 @@ pipeline_msg_handle_table_rule_delete_default(struct pipeline_data *p,
 	return rsp;
 }
 
+static struct pipeline_msg_rsp *
+pipeline_msg_handle_table_rule_stats_read(struct pipeline_data *p,
+	struct pipeline_msg_req *req)
+{
+	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+	uint32_t table_id = req->id;
+	void *data = req->table_rule_stats_read.data;
+	int clear = req->table_rule_stats_read.clear;
+	struct rte_table_action *a = p->table_data[table_id].a;
+
+	rsp->status = rte_table_action_stats_read(a,
+		data,
+		&rsp->table_rule_stats_read.stats,
+		clear);
+
+	return rsp;
+}
+
 static void
 pipeline_msg_handle(struct pipeline_data *p)
 {
@@ -1830,6 +1910,10 @@ pipeline_msg_handle(struct pipeline_data *p)
 			rsp = pipeline_msg_handle_table_rule_delete_default(p, req);
 			break;
 
+		case PIPELINE_REQ_TABLE_RULE_STATS_READ:
+			rsp = pipeline_msg_handle_table_rule_stats_read(p, req);
+			break;
+
 		default:
 			rsp = (struct pipeline_msg_rsp *) req;
 			rsp->status = -1;
-- 
2.9.3

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

* [dpdk-dev] [PATCH v3 35/44] ip_pipeline: add cli to configure meter profile
  2018-03-16 17:58       ` [dpdk-dev] [PATCH v3 00/44] ip_pipeline: refactoring Jasvinder Singh
                           ` (33 preceding siblings ...)
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 34/44] ip_pipeline: add cli to read pipeline table entry stats Jasvinder Singh
@ 2018-03-16 17:58         ` Jasvinder Singh
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 36/44] ip_pipeline: add cli to read meter stats Jasvinder Singh
                           ` (8 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-16 17:58 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add commands to configure the traffic meter profile.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/cli.c      | 232 ++++++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/pipeline.h |  11 ++
 examples/ip_pipeline/thread.c   | 145 ++++++++++++++++++++++++-
 3 files changed, 387 insertions(+), 1 deletion(-)

diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index ee2c78d..fabf2db 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -3462,6 +3462,218 @@ cmd_pipeline_table_rule_stats_read(char **tokens,
 }
 
 /**
+ * pipeline <pipeline_name> table <table_id> meter profile <meter_profile_id>
+ *  add srtcm cir <cir> cbs <cbs> ebs <ebs>
+ *  | trtcm cir <cir> pir <pir> cbs <cbs> pbs <pbs>
+ */
+static void
+cmd_pipeline_table_meter_profile_add(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct rte_table_action_meter_profile p;
+	char *pipeline_name;
+	uint32_t table_id, meter_profile_id;
+	int status;
+
+	if (n_tokens < 9) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "table") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
+		return;
+	}
+
+	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
+		return;
+	}
+
+	if (strcmp(tokens[4], "meter") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
+		return;
+	}
+
+	if (strcmp(tokens[5], "profile") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
+		return;
+	}
+
+	if (parser_read_uint32(&meter_profile_id, tokens[6]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "meter_profile_id");
+		return;
+	}
+
+	if (strcmp(tokens[7], "add") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
+		return;
+	}
+
+	if (strcmp(tokens[8], "srtcm") == 0) {
+		if (n_tokens != 15) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				tokens[0]);
+			return;
+		}
+
+		p.alg = RTE_TABLE_ACTION_METER_SRTCM;
+
+		if (strcmp(tokens[9], "cir") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cir");
+			return;
+		}
+
+		if (parser_read_uint64(&p.srtcm.cir, tokens[10]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "cir");
+			return;
+		}
+
+		if (strcmp(tokens[11], "cbs") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cbs");
+			return;
+		}
+
+		if (parser_read_uint64(&p.srtcm.cbs, tokens[12]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "cbs");
+			return;
+		}
+
+		if (strcmp(tokens[13], "ebs") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "ebs");
+			return;
+		}
+
+		if (parser_read_uint64(&p.srtcm.ebs, tokens[14]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "ebs");
+			return;
+		}
+	} else if (strcmp(tokens[8], "trtcm") == 0) {
+		if (n_tokens != 17) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+			return;
+		}
+
+		p.alg = RTE_TABLE_ACTION_METER_TRTCM;
+
+		if (strcmp(tokens[9], "cir") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cir");
+			return;
+		}
+
+		if (parser_read_uint64(&p.trtcm.cir, tokens[10]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "cir");
+			return;
+		}
+
+		if (strcmp(tokens[11], "pir") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pir");
+			return;
+		}
+
+		if (parser_read_uint64(&p.trtcm.pir, tokens[12]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "pir");
+			return;
+		}
+		if (strcmp(tokens[13], "cbs") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cbs");
+			return;
+		}
+
+		if (parser_read_uint64(&p.trtcm.cbs, tokens[14]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "cbs");
+			return;
+		}
+
+		if (strcmp(tokens[15], "pbs") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pbs");
+			return;
+		}
+
+		if (parser_read_uint64(&p.trtcm.pbs, tokens[16]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "pbs");
+			return;
+		}
+	} else {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	status = pipeline_table_mtr_profile_add(pipeline_name,
+		table_id,
+		meter_profile_id,
+		&p);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
+ * pipeline <pipeline_name> table <table_id>
+ *  meter profile <meter_profile_id> delete
+ */
+static void
+cmd_pipeline_table_meter_profile_delete(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	char *pipeline_name;
+	uint32_t table_id, meter_profile_id;
+	int status;
+
+	if (n_tokens != 8) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "table") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
+		return;
+	}
+
+	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
+		return;
+	}
+
+	if (strcmp(tokens[4], "meter") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
+		return;
+	}
+
+	if (strcmp(tokens[5], "profile") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
+		return;
+	}
+
+	if (parser_read_uint32(&meter_profile_id, tokens[6]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "meter_profile_id");
+		return;
+	}
+
+	if (strcmp(tokens[7], "delete") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete");
+		return;
+	}
+
+	status = pipeline_table_mtr_profile_delete(pipeline_name,
+		table_id,
+		meter_profile_id);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
  * thread <thread_id> pipeline <pipeline_name> enable
  */
 static void
@@ -3755,6 +3967,26 @@ cli_process(char *in, char *out, size_t out_size)
 				out, out_size);
 			return;
 		}
+
+		if ((n_tokens >= 8) &&
+			(strcmp(tokens[2], "table") == 0) &&
+			(strcmp(tokens[4], "meter") == 0) &&
+			(strcmp(tokens[5], "profile") == 0) &&
+			(strcmp(tokens[7], "add") == 0)) {
+			cmd_pipeline_table_meter_profile_add(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
+
+		if ((n_tokens >= 8) &&
+			(strcmp(tokens[2], "table") == 0) &&
+			(strcmp(tokens[4], "meter") == 0) &&
+			(strcmp(tokens[5], "profile") == 0) &&
+			(strcmp(tokens[7], "delete") == 0)) {
+			cmd_pipeline_table_meter_profile_delete(tokens,
+				n_tokens, out, out_size);
+			return;
+		}
 	}
 
 	if (strcmp(tokens[0], "thread") == 0) {
diff --git a/examples/ip_pipeline/pipeline.h b/examples/ip_pipeline/pipeline.h
index 296e4da..d524145 100644
--- a/examples/ip_pipeline/pipeline.h
+++ b/examples/ip_pipeline/pipeline.h
@@ -317,4 +317,15 @@ pipeline_table_rule_stats_read(const char *pipeline_name,
 	struct rte_table_action_stats_counters *stats,
 	int clear);
 
+int
+pipeline_table_mtr_profile_add(const char *pipeline_name,
+	uint32_t table_id,
+	uint32_t meter_profile_id,
+	struct rte_table_action_meter_profile *profile);
+
+int
+pipeline_table_mtr_profile_delete(const char *pipeline_name,
+	uint32_t table_id,
+	uint32_t meter_profile_id);
+
 #endif /* _INCLUDE_PIPELINE_H_ */
diff --git a/examples/ip_pipeline/thread.c b/examples/ip_pipeline/thread.c
index 21f36ca..97fce1a 100644
--- a/examples/ip_pipeline/thread.c
+++ b/examples/ip_pipeline/thread.c
@@ -498,7 +498,8 @@ enum pipeline_req_type {
 	PIPELINE_REQ_TABLE_RULE_DELETE,
 	PIPELINE_REQ_TABLE_RULE_DELETE_DEFAULT,
 	PIPELINE_REQ_TABLE_RULE_STATS_READ,
-
+	PIPELINE_REQ_TABLE_MTR_PROFILE_ADD,
+	PIPELINE_REQ_TABLE_MTR_PROFILE_DELETE,
 	PIPELINE_REQ_MAX
 };
 
@@ -532,6 +533,15 @@ struct pipeline_msg_req_table_rule_stats_read {
 	int clear;
 };
 
+struct pipeline_msg_req_table_mtr_profile_add {
+	uint32_t meter_profile_id;
+	struct rte_table_action_meter_profile profile;
+};
+
+struct pipeline_msg_req_table_mtr_profile_delete {
+	uint32_t meter_profile_id;
+};
+
 struct pipeline_msg_req {
 	enum pipeline_req_type type;
 	uint32_t id; /* Port IN, port OUT or table ID */
@@ -545,6 +555,8 @@ struct pipeline_msg_req {
 		struct pipeline_msg_req_table_rule_add_default table_rule_add_default;
 		struct pipeline_msg_req_table_rule_delete table_rule_delete;
 		struct pipeline_msg_req_table_rule_stats_read table_rule_stats_read;
+		struct pipeline_msg_req_table_mtr_profile_add table_mtr_profile_add;
+		struct pipeline_msg_req_table_mtr_profile_delete table_mtr_profile_delete;
 	};
 };
 
@@ -1249,6 +1261,95 @@ pipeline_table_rule_stats_read(const char *pipeline_name,
 	return status;
 }
 
+int
+pipeline_table_mtr_profile_add(const char *pipeline_name,
+	uint32_t table_id,
+	uint32_t meter_profile_id,
+	struct rte_table_action_meter_profile *profile)
+{
+	struct pipeline *p;
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if ((pipeline_name == NULL) ||
+		(profile == NULL))
+		return -1;
+
+	p = pipeline_find(pipeline_name);
+	if ((p == NULL) ||
+		(table_id >= p->n_tables))
+		return -1;
+
+	/* Allocate request */
+	req = pipeline_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = PIPELINE_REQ_TABLE_MTR_PROFILE_ADD;
+	req->id = table_id;
+	req->table_mtr_profile_add.meter_profile_id = meter_profile_id;
+	memcpy(&req->table_mtr_profile_add.profile, profile, sizeof(*profile));
+
+	/* Send request and wait for response */
+	rsp = pipeline_msg_send_recv(p, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+
+	/* Free response */
+	pipeline_msg_free(rsp);
+
+	return status;
+}
+
+int
+pipeline_table_mtr_profile_delete(const char *pipeline_name,
+	uint32_t table_id,
+	uint32_t meter_profile_id)
+{
+	struct pipeline *p;
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if (pipeline_name == NULL)
+		return -1;
+
+	p = pipeline_find(pipeline_name);
+	if ((p == NULL) ||
+		(table_id >= p->n_tables))
+		return -1;
+
+	/* Allocate request */
+	req = pipeline_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = PIPELINE_REQ_TABLE_MTR_PROFILE_DELETE;
+	req->id = table_id;
+	req->table_mtr_profile_delete.meter_profile_id = meter_profile_id;
+
+	/* Send request and wait for response */
+	rsp = pipeline_msg_send_recv(p, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+
+	/* Free response */
+	pipeline_msg_free(rsp);
+
+	return status;
+}
+
 /**
  * Data plane threads: message handling
  */
@@ -1862,6 +1963,40 @@ pipeline_msg_handle_table_rule_stats_read(struct pipeline_data *p,
 	return rsp;
 }
 
+static struct pipeline_msg_rsp *
+pipeline_msg_handle_table_mtr_profile_add(struct pipeline_data *p,
+	struct pipeline_msg_req *req)
+{
+	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+	uint32_t table_id = req->id;
+	uint32_t meter_profile_id = req->table_mtr_profile_add.meter_profile_id;
+	struct rte_table_action_meter_profile *profile =
+		&req->table_mtr_profile_add.profile;
+	struct rte_table_action *a = p->table_data[table_id].a;
+
+	rsp->status = rte_table_action_meter_profile_add(a,
+		meter_profile_id,
+		profile);
+
+	return rsp;
+}
+
+static struct pipeline_msg_rsp *
+pipeline_msg_handle_table_mtr_profile_delete(struct pipeline_data *p,
+	struct pipeline_msg_req *req)
+{
+	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+	uint32_t table_id = req->id;
+	uint32_t meter_profile_id =
+		req->table_mtr_profile_delete.meter_profile_id;
+	struct rte_table_action *a = p->table_data[table_id].a;
+
+	rsp->status = rte_table_action_meter_profile_delete(a,
+		meter_profile_id);
+
+	return rsp;
+}
+
 static void
 pipeline_msg_handle(struct pipeline_data *p)
 {
@@ -1914,6 +2049,14 @@ pipeline_msg_handle(struct pipeline_data *p)
 			rsp = pipeline_msg_handle_table_rule_stats_read(p, req);
 			break;
 
+		case PIPELINE_REQ_TABLE_MTR_PROFILE_ADD:
+			rsp = pipeline_msg_handle_table_mtr_profile_add(p, req);
+			break;
+
+		case PIPELINE_REQ_TABLE_MTR_PROFILE_DELETE:
+			rsp = pipeline_msg_handle_table_mtr_profile_delete(p, req);
+			break;
+
 		default:
 			rsp = (struct pipeline_msg_rsp *) req;
 			rsp->status = -1;
-- 
2.9.3

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

* [dpdk-dev] [PATCH v3 36/44] ip_pipeline: add cli to read meter stats
  2018-03-16 17:58       ` [dpdk-dev] [PATCH v3 00/44] ip_pipeline: refactoring Jasvinder Singh
                           ` (34 preceding siblings ...)
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 35/44] ip_pipeline: add cli to configure meter profile Jasvinder Singh
@ 2018-03-16 17:58         ` Jasvinder Singh
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 37/44] ip_pipeline: add cli to update dscp table Jasvinder Singh
                           ` (7 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-16 17:58 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add command to read traffic meter stats.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/cli.c      | 22 +++++++++++
 examples/ip_pipeline/pipeline.h |  8 ++++
 examples/ip_pipeline/thread.c   | 88 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 118 insertions(+)

diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index fabf2db..e01806a 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -3674,6 +3674,18 @@ cmd_pipeline_table_meter_profile_delete(char **tokens,
 }
 
 /**
+ * pipeline <pipeline_name> table <table_id> rule read meter [clear]
+ */
+static void
+cmd_pipeline_table_rule_meter_read(char **tokens,
+	uint32_t n_tokens __rte_unused,
+	char *out,
+	size_t out_size)
+{
+	snprintf(out, out_size, MSG_CMD_UNIMPLEM, tokens[0]);
+}
+
+/**
  * thread <thread_id> pipeline <pipeline_name> enable
  */
 static void
@@ -3987,6 +3999,16 @@ cli_process(char *in, char *out, size_t out_size)
 				n_tokens, out, out_size);
 			return;
 		}
+
+		if ((n_tokens >= 7) &&
+			(strcmp(tokens[2], "table") == 0) &&
+			(strcmp(tokens[4], "rule") == 0) &&
+			(strcmp(tokens[5], "read") == 0) &&
+			(strcmp(tokens[6], "meter") == 0)) {
+			cmd_pipeline_table_rule_meter_read(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
 	}
 
 	if (strcmp(tokens[0], "thread") == 0) {
diff --git a/examples/ip_pipeline/pipeline.h b/examples/ip_pipeline/pipeline.h
index d524145..4978555 100644
--- a/examples/ip_pipeline/pipeline.h
+++ b/examples/ip_pipeline/pipeline.h
@@ -328,4 +328,12 @@ pipeline_table_mtr_profile_delete(const char *pipeline_name,
 	uint32_t table_id,
 	uint32_t meter_profile_id);
 
+int
+pipeline_table_rule_mtr_read(const char *pipeline_name,
+	uint32_t table_id,
+	void *data,
+	uint32_t tc_mask,
+	struct rte_table_action_mtr_counters *stats,
+	int clear);
+
 #endif /* _INCLUDE_PIPELINE_H_ */
diff --git a/examples/ip_pipeline/thread.c b/examples/ip_pipeline/thread.c
index 97fce1a..de89190 100644
--- a/examples/ip_pipeline/thread.c
+++ b/examples/ip_pipeline/thread.c
@@ -500,6 +500,7 @@ enum pipeline_req_type {
 	PIPELINE_REQ_TABLE_RULE_STATS_READ,
 	PIPELINE_REQ_TABLE_MTR_PROFILE_ADD,
 	PIPELINE_REQ_TABLE_MTR_PROFILE_DELETE,
+	PIPELINE_REQ_TABLE_RULE_MTR_READ,
 	PIPELINE_REQ_MAX
 };
 
@@ -542,6 +543,11 @@ struct pipeline_msg_req_table_mtr_profile_delete {
 	uint32_t meter_profile_id;
 };
 
+struct pipeline_msg_req_table_rule_mtr_read {
+	void *data;
+	uint32_t tc_mask;
+	int clear;
+};
 struct pipeline_msg_req {
 	enum pipeline_req_type type;
 	uint32_t id; /* Port IN, port OUT or table ID */
@@ -557,6 +563,7 @@ struct pipeline_msg_req {
 		struct pipeline_msg_req_table_rule_stats_read table_rule_stats_read;
 		struct pipeline_msg_req_table_mtr_profile_add table_mtr_profile_add;
 		struct pipeline_msg_req_table_mtr_profile_delete table_mtr_profile_delete;
+		struct pipeline_msg_req_table_rule_mtr_read table_rule_mtr_read;
 	};
 };
 
@@ -584,6 +591,10 @@ struct pipeline_msg_rsp_table_rule_stats_read {
 	struct rte_table_action_stats_counters stats;
 };
 
+struct pipeline_msg_rsp_table_rule_mtr_read {
+	struct rte_table_action_mtr_counters stats;
+};
+
 struct pipeline_msg_rsp {
 	int status;
 
@@ -595,6 +606,7 @@ struct pipeline_msg_rsp {
 		struct pipeline_msg_rsp_table_rule_add table_rule_add;
 		struct pipeline_msg_rsp_table_rule_add_default table_rule_add_default;
 		struct pipeline_msg_rsp_table_rule_stats_read table_rule_stats_read;
+		struct pipeline_msg_rsp_table_rule_mtr_read table_rule_mtr_read;
 	};
 };
 
@@ -1350,6 +1362,58 @@ pipeline_table_mtr_profile_delete(const char *pipeline_name,
 	return status;
 }
 
+int
+pipeline_table_rule_mtr_read(const char *pipeline_name,
+	uint32_t table_id,
+	void *data,
+	uint32_t tc_mask,
+	struct rte_table_action_mtr_counters *stats,
+	int clear)
+{
+	struct pipeline *p;
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if ((pipeline_name == NULL) ||
+		(data == NULL) ||
+		(stats == NULL))
+		return -1;
+
+	p = pipeline_find(pipeline_name);
+	if ((p == NULL) ||
+		(table_id >= p->n_tables))
+		return -1;
+
+	/* Allocate request */
+	req = pipeline_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = PIPELINE_REQ_TABLE_RULE_MTR_READ;
+	req->id = table_id;
+	req->table_rule_mtr_read.data = data;
+	req->table_rule_mtr_read.tc_mask = tc_mask;
+	req->table_rule_mtr_read.clear = clear;
+
+	/* Send request and wait for response */
+	rsp = pipeline_msg_send_recv(p, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+	if (status)
+		memcpy(stats, &rsp->table_rule_mtr_read.stats, sizeof(*stats));
+
+	/* Free response */
+	pipeline_msg_free(rsp);
+
+	return status;
+}
+
 /**
  * Data plane threads: message handling
  */
@@ -1997,6 +2061,26 @@ pipeline_msg_handle_table_mtr_profile_delete(struct pipeline_data *p,
 	return rsp;
 }
 
+static struct pipeline_msg_rsp *
+pipeline_msg_handle_table_rule_mtr_read(struct pipeline_data *p,
+	struct pipeline_msg_req *req)
+{
+	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+	uint32_t table_id = req->id;
+	void *data = req->table_rule_mtr_read.data;
+	uint32_t tc_mask = req->table_rule_mtr_read.tc_mask;
+	int clear = req->table_rule_mtr_read.clear;
+	struct rte_table_action *a = p->table_data[table_id].a;
+
+	rsp->status = rte_table_action_meter_read(a,
+		data,
+		tc_mask,
+		&rsp->table_rule_mtr_read.stats,
+		clear);
+
+	return rsp;
+}
+
 static void
 pipeline_msg_handle(struct pipeline_data *p)
 {
@@ -2057,6 +2141,10 @@ pipeline_msg_handle(struct pipeline_data *p)
 			rsp = pipeline_msg_handle_table_mtr_profile_delete(p, req);
 			break;
 
+		case PIPELINE_REQ_TABLE_RULE_MTR_READ:
+			rsp = pipeline_msg_handle_table_rule_mtr_read(p, req);
+			break;
+
 		default:
 			rsp = (struct pipeline_msg_rsp *) req;
 			rsp->status = -1;
-- 
2.9.3

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

* [dpdk-dev] [PATCH v3 37/44] ip_pipeline: add cli to update dscp table
  2018-03-16 17:58       ` [dpdk-dev] [PATCH v3 00/44] ip_pipeline: refactoring Jasvinder Singh
                           ` (35 preceding siblings ...)
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 36/44] ip_pipeline: add cli to read meter stats Jasvinder Singh
@ 2018-03-16 17:58         ` Jasvinder Singh
  2018-03-16 17:59         ` [dpdk-dev] [PATCH v3 38/44] ip_pipeline: add cli to read ttl stats Jasvinder Singh
                           ` (6 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-16 17:58 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add command to update the dscp table for traffic meter and traffic
manager.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/cli.c      | 154 ++++++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/pipeline.h |   6 ++
 examples/ip_pipeline/thread.c   |  77 ++++++++++++++++++++
 3 files changed, 237 insertions(+)

diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index e01806a..1f51eaf 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -3686,6 +3686,152 @@ cmd_pipeline_table_rule_meter_read(char **tokens,
 }
 
 /**
+ * pipeline <pipeline_name> table <table_id> dscp <file_name>
+ *
+ * File <file_name>:
+ *  - exactly 64 lines
+ *  - line format: <tc_id> <tc_queue_id> <color>, with <color> as: g | y | r
+ */
+static int
+load_dscp_table(struct rte_table_action_dscp_table *dscp_table,
+	const char *file_name,
+	uint32_t *line_number)
+{
+	FILE *f = NULL;
+	uint32_t dscp, l;
+
+	/* Check input arguments */
+	if ((dscp_table == NULL) ||
+		(file_name == NULL) ||
+		(line_number == NULL)) {
+		if (line_number)
+			*line_number = 0;
+		return -EINVAL;
+	}
+
+	/* Open input file */
+	f = fopen(file_name, "r");
+	if (f == NULL) {
+		*line_number = 0;
+		return -EINVAL;
+	}
+
+	/* Read file */
+	for (dscp = 0, l = 1; ; l++) {
+		char line[64];
+		char *tokens[3];
+		enum rte_meter_color color;
+		uint32_t tc_id, tc_queue_id, n_tokens = RTE_DIM(tokens);
+
+		if (fgets(line, sizeof(line), f) == NULL)
+			break;
+
+		if (is_comment(line))
+			continue;
+
+		if (parse_tokenize_string(line, tokens, &n_tokens)) {
+			*line_number = l;
+			return -EINVAL;
+		}
+
+		if (n_tokens == 0)
+			continue;
+
+		if ((dscp >= RTE_DIM(dscp_table->entry)) ||
+			(n_tokens != RTE_DIM(tokens)) ||
+			parser_read_uint32(&tc_id, tokens[0]) ||
+			(tc_id >= RTE_TABLE_ACTION_TC_MAX) ||
+			parser_read_uint32(&tc_queue_id, tokens[1]) ||
+			(tc_queue_id >= RTE_TABLE_ACTION_TC_QUEUE_MAX) ||
+			(strlen(tokens[2]) != 1)) {
+			*line_number = l;
+			return -EINVAL;
+		}
+
+		switch (tokens[2][0]) {
+		case 'g':
+		case 'G':
+			color = e_RTE_METER_GREEN;
+			break;
+
+		case 'y':
+		case 'Y':
+			color = e_RTE_METER_YELLOW;
+			break;
+
+		case 'r':
+		case 'R':
+			color = e_RTE_METER_RED;
+			break;
+
+		default:
+			*line_number = l;
+			return -EINVAL;
+		}
+
+		dscp_table->entry[dscp].tc_id = tc_id;
+		dscp_table->entry[dscp].tc_queue_id = tc_queue_id;
+		dscp_table->entry[dscp].color = color;
+		dscp++;
+	}
+
+	/* Close file */
+	fclose(f);
+	return 0;
+}
+
+static void
+cmd_pipeline_table_dscp(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct rte_table_action_dscp_table dscp_table;
+	char *pipeline_name, *file_name;
+	uint32_t table_id, line_number;
+	int status;
+
+	if (n_tokens != 6) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "table") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
+		return;
+	}
+
+	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
+		return;
+	}
+
+	if (strcmp(tokens[4], "dscp") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "dscp");
+		return;
+	}
+
+	file_name = tokens[5];
+
+	status = load_dscp_table(&dscp_table, file_name, &line_number);
+	if (status) {
+		snprintf(out, out_size, MSG_FILE_ERR, file_name, line_number);
+		return;
+	}
+
+	status = pipeline_table_dscp_table_update(pipeline_name,
+		table_id,
+		UINT64_MAX,
+		&dscp_table);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
  * thread <thread_id> pipeline <pipeline_name> enable
  */
 static void
@@ -4009,6 +4155,14 @@ cli_process(char *in, char *out, size_t out_size)
 				out, out_size);
 			return;
 		}
+
+		if ((n_tokens >= 5) &&
+			(strcmp(tokens[2], "table") == 0) &&
+			(strcmp(tokens[4], "dscp") == 0)) {
+			cmd_pipeline_table_dscp(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
 	}
 
 	if (strcmp(tokens[0], "thread") == 0) {
diff --git a/examples/ip_pipeline/pipeline.h b/examples/ip_pipeline/pipeline.h
index 4978555..598bed0 100644
--- a/examples/ip_pipeline/pipeline.h
+++ b/examples/ip_pipeline/pipeline.h
@@ -336,4 +336,10 @@ pipeline_table_rule_mtr_read(const char *pipeline_name,
 	struct rte_table_action_mtr_counters *stats,
 	int clear);
 
+int
+pipeline_table_dscp_table_update(const char *pipeline_name,
+	uint32_t table_id,
+	uint64_t dscp_mask,
+	struct rte_table_action_dscp_table *dscp_table);
+
 #endif /* _INCLUDE_PIPELINE_H_ */
diff --git a/examples/ip_pipeline/thread.c b/examples/ip_pipeline/thread.c
index de89190..3c1318d 100644
--- a/examples/ip_pipeline/thread.c
+++ b/examples/ip_pipeline/thread.c
@@ -501,6 +501,7 @@ enum pipeline_req_type {
 	PIPELINE_REQ_TABLE_MTR_PROFILE_ADD,
 	PIPELINE_REQ_TABLE_MTR_PROFILE_DELETE,
 	PIPELINE_REQ_TABLE_RULE_MTR_READ,
+	PIPELINE_REQ_TABLE_DSCP_TABLE_UPDATE,
 	PIPELINE_REQ_MAX
 };
 
@@ -548,6 +549,12 @@ struct pipeline_msg_req_table_rule_mtr_read {
 	uint32_t tc_mask;
 	int clear;
 };
+
+struct pipeline_msg_req_table_dscp_table_update {
+	uint64_t dscp_mask;
+	struct rte_table_action_dscp_table dscp_table;
+};
+
 struct pipeline_msg_req {
 	enum pipeline_req_type type;
 	uint32_t id; /* Port IN, port OUT or table ID */
@@ -564,6 +571,7 @@ struct pipeline_msg_req {
 		struct pipeline_msg_req_table_mtr_profile_add table_mtr_profile_add;
 		struct pipeline_msg_req_table_mtr_profile_delete table_mtr_profile_delete;
 		struct pipeline_msg_req_table_rule_mtr_read table_rule_mtr_read;
+		struct pipeline_msg_req_table_dscp_table_update table_dscp_table_update;
 	};
 };
 
@@ -1414,6 +1422,53 @@ pipeline_table_rule_mtr_read(const char *pipeline_name,
 	return status;
 }
 
+int
+pipeline_table_dscp_table_update(const char *pipeline_name,
+	uint32_t table_id,
+	uint64_t dscp_mask,
+	struct rte_table_action_dscp_table *dscp_table)
+{
+	struct pipeline *p;
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if ((pipeline_name == NULL) ||
+		(dscp_table == NULL))
+		return -1;
+
+	p = pipeline_find(pipeline_name);
+	if ((p == NULL) ||
+		(table_id >= p->n_tables))
+		return -1;
+
+	/* Allocate request */
+	req = pipeline_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = PIPELINE_REQ_TABLE_DSCP_TABLE_UPDATE;
+	req->id = table_id;
+	req->table_dscp_table_update.dscp_mask = dscp_mask;
+	memcpy(&req->table_dscp_table_update.dscp_table,
+		dscp_table, sizeof(*dscp_table));
+
+	/* Send request and wait for response */
+	rsp = pipeline_msg_send_recv(p, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+
+	/* Free response */
+	pipeline_msg_free(rsp);
+
+	return status;
+}
+
 /**
  * Data plane threads: message handling
  */
@@ -2081,6 +2136,24 @@ pipeline_msg_handle_table_rule_mtr_read(struct pipeline_data *p,
 	return rsp;
 }
 
+static struct pipeline_msg_rsp *
+pipeline_msg_handle_table_dscp_table_update(struct pipeline_data *p,
+	struct pipeline_msg_req *req)
+{
+	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+	uint32_t table_id = req->id;
+	uint64_t dscp_mask = req->table_dscp_table_update.dscp_mask;
+	struct rte_table_action_dscp_table *dscp_table =
+		&req->table_dscp_table_update.dscp_table;
+	struct rte_table_action *a = p->table_data[table_id].a;
+
+	rsp->status = rte_table_action_dscp_table_update(a,
+		dscp_mask,
+		dscp_table);
+
+	return rsp;
+}
+
 static void
 pipeline_msg_handle(struct pipeline_data *p)
 {
@@ -2145,6 +2218,10 @@ pipeline_msg_handle(struct pipeline_data *p)
 			rsp = pipeline_msg_handle_table_rule_mtr_read(p, req);
 			break;
 
+		case PIPELINE_REQ_TABLE_DSCP_TABLE_UPDATE:
+			rsp = pipeline_msg_handle_table_dscp_table_update(p, req);
+			break;
+
 		default:
 			rsp = (struct pipeline_msg_rsp *) req;
 			rsp->status = -1;
-- 
2.9.3

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

* [dpdk-dev] [PATCH v3 38/44] ip_pipeline: add cli to read ttl stats
  2018-03-16 17:58       ` [dpdk-dev] [PATCH v3 00/44] ip_pipeline: refactoring Jasvinder Singh
                           ` (36 preceding siblings ...)
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 37/44] ip_pipeline: add cli to update dscp table Jasvinder Singh
@ 2018-03-16 17:59         ` Jasvinder Singh
  2018-03-16 17:59         ` [dpdk-dev] [PATCH v3 39/44] ip_pipeline: add l2fwd example Jasvinder Singh
                           ` (5 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-16 17:59 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add command to read the ttl stats.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/cli.c      | 22 +++++++++++
 examples/ip_pipeline/pipeline.h |  7 ++++
 examples/ip_pipeline/thread.c   | 84 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 113 insertions(+)

diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index 1f51eaf..6757d32 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -3832,6 +3832,18 @@ cmd_pipeline_table_dscp(char **tokens,
 }
 
 /**
+ * pipeline <pipeline_name> table <table_id> rule read ttl [clear]
+ */
+static void
+cmd_pipeline_table_rule_ttl_read(char **tokens,
+	uint32_t n_tokens __rte_unused,
+	char *out,
+	size_t out_size)
+{
+	snprintf(out, out_size, MSG_CMD_UNIMPLEM, tokens[0]);
+}
+
+/**
  * thread <thread_id> pipeline <pipeline_name> enable
  */
 static void
@@ -4163,6 +4175,16 @@ cli_process(char *in, char *out, size_t out_size)
 				out, out_size);
 			return;
 		}
+
+		if ((n_tokens >= 7) &&
+			(strcmp(tokens[2], "table") == 0) &&
+			(strcmp(tokens[4], "rule") == 0) &&
+			(strcmp(tokens[5], "read") == 0) &&
+			(strcmp(tokens[6], "ttl") == 0)) {
+			cmd_pipeline_table_rule_ttl_read(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
 	}
 
 	if (strcmp(tokens[0], "thread") == 0) {
diff --git a/examples/ip_pipeline/pipeline.h b/examples/ip_pipeline/pipeline.h
index 598bed0..208e407 100644
--- a/examples/ip_pipeline/pipeline.h
+++ b/examples/ip_pipeline/pipeline.h
@@ -342,4 +342,11 @@ pipeline_table_dscp_table_update(const char *pipeline_name,
 	uint64_t dscp_mask,
 	struct rte_table_action_dscp_table *dscp_table);
 
+int
+pipeline_table_rule_ttl_read(const char *pipeline_name,
+	uint32_t table_id,
+	void *data,
+	struct rte_table_action_ttl_counters *stats,
+	int clear);
+
 #endif /* _INCLUDE_PIPELINE_H_ */
diff --git a/examples/ip_pipeline/thread.c b/examples/ip_pipeline/thread.c
index 3c1318d..065435d 100644
--- a/examples/ip_pipeline/thread.c
+++ b/examples/ip_pipeline/thread.c
@@ -502,6 +502,7 @@ enum pipeline_req_type {
 	PIPELINE_REQ_TABLE_MTR_PROFILE_DELETE,
 	PIPELINE_REQ_TABLE_RULE_MTR_READ,
 	PIPELINE_REQ_TABLE_DSCP_TABLE_UPDATE,
+	PIPELINE_REQ_TABLE_RULE_TTL_READ,
 	PIPELINE_REQ_MAX
 };
 
@@ -555,6 +556,11 @@ struct pipeline_msg_req_table_dscp_table_update {
 	struct rte_table_action_dscp_table dscp_table;
 };
 
+struct pipeline_msg_req_table_rule_ttl_read {
+	void *data;
+	int clear;
+};
+
 struct pipeline_msg_req {
 	enum pipeline_req_type type;
 	uint32_t id; /* Port IN, port OUT or table ID */
@@ -572,6 +578,7 @@ struct pipeline_msg_req {
 		struct pipeline_msg_req_table_mtr_profile_delete table_mtr_profile_delete;
 		struct pipeline_msg_req_table_rule_mtr_read table_rule_mtr_read;
 		struct pipeline_msg_req_table_dscp_table_update table_dscp_table_update;
+		struct pipeline_msg_req_table_rule_ttl_read table_rule_ttl_read;
 	};
 };
 
@@ -603,6 +610,10 @@ struct pipeline_msg_rsp_table_rule_mtr_read {
 	struct rte_table_action_mtr_counters stats;
 };
 
+struct pipeline_msg_rsp_table_rule_ttl_read {
+	struct rte_table_action_ttl_counters stats;
+};
+
 struct pipeline_msg_rsp {
 	int status;
 
@@ -615,6 +626,7 @@ struct pipeline_msg_rsp {
 		struct pipeline_msg_rsp_table_rule_add_default table_rule_add_default;
 		struct pipeline_msg_rsp_table_rule_stats_read table_rule_stats_read;
 		struct pipeline_msg_rsp_table_rule_mtr_read table_rule_mtr_read;
+		struct pipeline_msg_rsp_table_rule_ttl_read table_rule_ttl_read;
 	};
 };
 
@@ -1469,6 +1481,56 @@ pipeline_table_dscp_table_update(const char *pipeline_name,
 	return status;
 }
 
+int
+pipeline_table_rule_ttl_read(const char *pipeline_name,
+	uint32_t table_id,
+	void *data,
+	struct rte_table_action_ttl_counters *stats,
+	int clear)
+{
+	struct pipeline *p;
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if ((pipeline_name == NULL) ||
+		(data == NULL) ||
+		(stats == NULL))
+		return -1;
+
+	p = pipeline_find(pipeline_name);
+	if ((p == NULL) ||
+		(table_id >= p->n_tables))
+		return -1;
+
+	/* Allocate request */
+	req = pipeline_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = PIPELINE_REQ_TABLE_RULE_TTL_READ;
+	req->id = table_id;
+	req->table_rule_ttl_read.data = data;
+	req->table_rule_ttl_read.clear = clear;
+
+	/* Send request and wait for response */
+	rsp = pipeline_msg_send_recv(p, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+	if (status)
+		memcpy(stats, &rsp->table_rule_ttl_read.stats, sizeof(*stats));
+
+	/* Free response */
+	pipeline_msg_free(rsp);
+
+	return status;
+}
+
 /**
  * Data plane threads: message handling
  */
@@ -2154,6 +2216,24 @@ pipeline_msg_handle_table_dscp_table_update(struct pipeline_data *p,
 	return rsp;
 }
 
+static struct pipeline_msg_rsp *
+pipeline_msg_handle_table_rule_ttl_read(struct pipeline_data *p,
+	struct pipeline_msg_req *req)
+{
+	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+	uint32_t table_id = req->id;
+	void *data = req->table_rule_ttl_read.data;
+	int clear = req->table_rule_ttl_read.clear;
+	struct rte_table_action *a = p->table_data[table_id].a;
+
+	rsp->status = rte_table_action_ttl_read(a,
+		data,
+		&rsp->table_rule_ttl_read.stats,
+		clear);
+
+	return rsp;
+}
+
 static void
 pipeline_msg_handle(struct pipeline_data *p)
 {
@@ -2222,6 +2302,10 @@ pipeline_msg_handle(struct pipeline_data *p)
 			rsp = pipeline_msg_handle_table_dscp_table_update(p, req);
 			break;
 
+		case PIPELINE_REQ_TABLE_RULE_TTL_READ:
+			rsp = pipeline_msg_handle_table_rule_ttl_read(p, req);
+			break;
+
 		default:
 			rsp = (struct pipeline_msg_rsp *) req;
 			rsp->status = -1;
-- 
2.9.3

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

* [dpdk-dev] [PATCH v3 39/44] ip_pipeline: add l2fwd example
  2018-03-16 17:58       ` [dpdk-dev] [PATCH v3 00/44] ip_pipeline: refactoring Jasvinder Singh
                           ` (37 preceding siblings ...)
  2018-03-16 17:59         ` [dpdk-dev] [PATCH v3 38/44] ip_pipeline: add cli to read ttl stats Jasvinder Singh
@ 2018-03-16 17:59         ` Jasvinder Singh
  2018-03-16 17:59         ` [dpdk-dev] [PATCH v3 40/44] ip_pipeline: add KNI port example Jasvinder Singh
                           ` (4 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-16 17:59 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Kevin Laatz

This patch add the configuration file for l2fwd example. It
includes commands to build the packet processing stage (pipeline),
defining action, add rules to its table, etc.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
---
 examples/ip_pipeline/examples/l2fwd.cli | 53 +++++++++++++++++++++++++++++++++
 1 file changed, 53 insertions(+)
 create mode 100644 examples/ip_pipeline/examples/l2fwd.cli

diff --git a/examples/ip_pipeline/examples/l2fwd.cli b/examples/ip_pipeline/examples/l2fwd.cli
new file mode 100644
index 0000000..5b9d529
--- /dev/null
+++ b/examples/ip_pipeline/examples/l2fwd.cli
@@ -0,0 +1,53 @@
+; SPDX-License-Identifier: BSD-3-Clause
+; Copyright(c) 2010-2018 Intel Corporation
+
+; The pipeline below implements a simple pass-through connection between the
+; input ports to the output ports, as in this diagram:
+;                 ________________
+; LINK0 RXQ0 --->|................|---> LINK1 TXQ0
+;                |                |
+; LINK1 RXQ0 --->|................|---> LINK0 TXQ0
+;                |    PIPELINE0   |
+; LINK2 RXQ0 --->|................|---> LINK3 TXQ0
+;                |                |
+; LINK3 RXQ0 --->|................|---> LINK2 TXQ0
+;                |________________|
+;
+
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+
+link LINK0 dev 0000:02:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+link LINK1 dev 0000:02:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+link LINK2 dev 0000:06:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+link LINK3 dev 0000:06:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+
+table action profile AP0 ipv4 offset 270 fwd
+
+pipeline PIPELINE0 period 10 offset_port_id 0 cpu 0
+
+pipeline PIPELINE0 port in bsz 32 link LINK0 rxq 0
+pipeline PIPELINE0 port in bsz 32 link LINK1 rxq 0
+pipeline PIPELINE0 port in bsz 32 link LINK2 rxq 0
+pipeline PIPELINE0 port in bsz 32 link LINK3 rxq 0
+
+pipeline PIPELINE0 port out bsz 32 link LINK0 txq 0
+pipeline PIPELINE0 port out bsz 32 link LINK1 txq 0
+pipeline PIPELINE0 port out bsz 32 link LINK2 txq 0
+pipeline PIPELINE0 port out bsz 32 link LINK3 txq 0
+
+pipeline PIPELINE0 table match stub action AP0
+pipeline PIPELINE0 table match stub action AP0
+pipeline PIPELINE0 table match stub action AP0
+pipeline PIPELINE0 table match stub action AP0
+
+pipeline PIPELINE0 port in 0 table 0
+pipeline PIPELINE0 port in 1 table 1
+pipeline PIPELINE0 port in 2 table 2
+pipeline PIPELINE0 port in 3 table 3
+
+thread 1 pipeline PIPELINE0 enable
+
+pipeline PIPELINE0 table 0 rule add match default action fwd port 1
+pipeline PIPELINE0 table 1 rule add match default action fwd port 0
+pipeline PIPELINE0 table 2 rule add match default action fwd port 3
+pipeline PIPELINE0 table 3 rule add match default action fwd port 2
-- 
2.9.3

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

* [dpdk-dev] [PATCH v3 40/44] ip_pipeline: add KNI port example
  2018-03-16 17:58       ` [dpdk-dev] [PATCH v3 00/44] ip_pipeline: refactoring Jasvinder Singh
                           ` (38 preceding siblings ...)
  2018-03-16 17:59         ` [dpdk-dev] [PATCH v3 39/44] ip_pipeline: add l2fwd example Jasvinder Singh
@ 2018-03-16 17:59         ` Jasvinder Singh
  2018-03-16 17:59         ` [dpdk-dev] [PATCH v3 41/44] ip_pipeline: add TAP " Jasvinder Singh
                           ` (3 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-16 17:59 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Kevin Laatz

Add example to illustrate the pipeline functioning with KNI
interface.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
---
 examples/ip_pipeline/examples/kni.cli | 69 +++++++++++++++++++++++++++++++++++
 1 file changed, 69 insertions(+)
 create mode 100644 examples/ip_pipeline/examples/kni.cli

diff --git a/examples/ip_pipeline/examples/kni.cli b/examples/ip_pipeline/examples/kni.cli
new file mode 100644
index 0000000..1438340
--- /dev/null
+++ b/examples/ip_pipeline/examples/kni.cli
@@ -0,0 +1,69 @@
+; SPDX-License-Identifier: BSD-3-Clause
+; Copyright(c) 2010-2018 Intel Corporation
+
+;                 _______________          ______________________
+;                |               |  KNI0  |                      |
+; LINK0 RXQ0 --->|...............|------->|--+                   |
+;                |               |  KNI1  |  | br0               |
+; LINK1 TXQ0 <---|...............|<-------|<-+                   |
+;                |               |        |     Linux Kernel     |
+;                |   PIPELINE0   |        |     Network Stack    |
+;                |               |  KNI1  |                      |
+; LINK1 RXQ0 --->|...............|------->|--+                   |
+;                |               |  KNI0  |  | br0               |
+; LINK0 TXQ0 <---|...............|<-------|<-+                   |
+;                |_______________|        |______________________|
+;
+; Insert Linux kernel KNI module:
+;    [Linux]$ insmod rte_kni.ko
+;
+; Configure Linux kernel bridge between KNI0 and KNI1 interfaces:
+;    [Linux]$ brctl addbr br0
+;    [Linux]$ brctl addif br0 KNI0
+;    [Linux]$ brctl addif br0 KNI1
+;    [Linux]$ ifconfig br0 up
+;    [Linux]$ ifconfig KNI0 up
+;    [Linux]$ ifconfig KNI1 up
+;
+; Monitor packet forwarding performed by Linux kernel between KNI0 and KNI1:
+;    [Linux]$ tcpdump -i KNI0
+;    [Linux]$ tcpdump -i KNI1
+
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+
+link LINK0 dev 0000:02:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+link LINK1 dev 0000:02:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+
+kni KNI0 link LINK0 mempool MEMPOOL0
+kni KNI1 link LINK1 mempool MEMPOOL0
+
+table action profile AP0 ipv4 offset 270 fwd
+
+pipeline PIPELINE0 period 10 offset_port_id 0 cpu 0
+
+pipeline PIPELINE0 port in bsz 32 link LINK0 rxq 0
+pipeline PIPELINE0 port in bsz 32 kni KNI1
+pipeline PIPELINE0 port in bsz 32 link LINK1 rxq 0
+pipeline PIPELINE0 port in bsz 32 kni KNI0
+
+pipeline PIPELINE0 port out bsz 32 kni KNI0
+pipeline PIPELINE0 port out bsz 32 link LINK1 txq 0
+pipeline PIPELINE0 port out bsz 32 kni KNI1
+pipeline PIPELINE0 port out bsz 32 link LINK0 txq 0
+
+pipeline PIPELINE0 table match stub action AP0
+pipeline PIPELINE0 table match stub action AP0
+pipeline PIPELINE0 table match stub action AP0
+pipeline PIPELINE0 table match stub action AP0
+
+pipeline PIPELINE0 port in 0 table 0
+pipeline PIPELINE0 port in 1 table 1
+pipeline PIPELINE0 port in 2 table 2
+pipeline PIPELINE0 port in 3 table 3
+
+thread 1 pipeline PIPELINE0 enable
+
+pipeline PIPELINE0 table 0 rule add match default action fwd port 0
+pipeline PIPELINE0 table 1 rule add match default action fwd port 1
+pipeline PIPELINE0 table 2 rule add match default action fwd port 2
+pipeline PIPELINE0 table 3 rule add match default action fwd port 3
-- 
2.9.3

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

* [dpdk-dev] [PATCH v3 41/44] ip_pipeline: add TAP port example
  2018-03-16 17:58       ` [dpdk-dev] [PATCH v3 00/44] ip_pipeline: refactoring Jasvinder Singh
                           ` (39 preceding siblings ...)
  2018-03-16 17:59         ` [dpdk-dev] [PATCH v3 40/44] ip_pipeline: add KNI port example Jasvinder Singh
@ 2018-03-16 17:59         ` Jasvinder Singh
  2018-03-16 17:59         ` [dpdk-dev] [PATCH v3 42/44] ip_pipeline: add route example Jasvinder Singh
                           ` (2 subsequent siblings)
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-16 17:59 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Kevin Laatz

Add example to illustrate the pipeline functioning with TAP
interface.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
---
 examples/ip_pipeline/examples/tap.cli | 66 +++++++++++++++++++++++++++++++++++
 1 file changed, 66 insertions(+)
 create mode 100644 examples/ip_pipeline/examples/tap.cli

diff --git a/examples/ip_pipeline/examples/tap.cli b/examples/ip_pipeline/examples/tap.cli
new file mode 100644
index 0000000..600cea2
--- /dev/null
+++ b/examples/ip_pipeline/examples/tap.cli
@@ -0,0 +1,66 @@
+; SPDX-License-Identifier: BSD-3-Clause
+; Copyright(c) 2010-2018 Intel Corporation
+
+;                 _______________          ______________________
+;                |               |  TAP0  |                      |
+; LINK0 RXQ0 --->|...............|------->|--+                   |
+;                |               |  TAP1  |  | br0               |
+; LINK1 TXQ0 <---|...............|<-------|<-+                   |
+;                |               |        |     Linux Kernel     |
+;                |   PIPELINE0   |        |     Network Stack    |
+;                |               |  TAP1  |                      |
+; LINK1 RXQ0 --->|...............|------->|--+                   |
+;                |               |  TAP0  |  | br0               |
+; LINK0 TXQ0 <---|...............|<-------|<-+                   |
+;                |_______________|        |______________________|
+;
+; Configure Linux kernel bridge between TAP0 and TAP1 interfaces:
+;    [Linux]$ brctl addbr br0
+;    [Linux]$ brctl addif br0 TAP0
+;    [Linux]$ brctl addif br0 TAP1
+;    [Linux]$ ifconfig TAP0 up
+;    [Linux]$ ifconfig TAP1 up
+;    [Linux]$ ifconfig br0 up
+;
+; Monitor packet forwarding performed by Linux kernel between TAP0 and TAP1:
+;    [Linux]$ tcpdump -i TAP0
+;    [Linux]$ tcpdump -i TAP1
+
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+
+link LINK0 dev 0000:02:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+link LINK1 dev 0000:02:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+
+tap TAP0
+tap TAP1
+
+table action profile AP0 ipv4 offset 270 fwd
+
+pipeline PIPELINE0 period 10 offset_port_id 0 cpu 0
+
+pipeline PIPELINE0 port in bsz 32 link LINK0 rxq 0
+pipeline PIPELINE0 port in bsz 32 tap TAP1 mempool MEMPOOL0 mtu 1500
+pipeline PIPELINE0 port in bsz 32 link LINK1 rxq 0
+pipeline PIPELINE0 port in bsz 32 tap TAP0 mempool MEMPOOL0 mtu 1500
+
+pipeline PIPELINE0 port out bsz 32 tap TAP0
+pipeline PIPELINE0 port out bsz 32 link LINK1 txq 0
+pipeline PIPELINE0 port out bsz 32 tap TAP1
+pipeline PIPELINE0 port out bsz 32 link LINK0 txq 0
+
+pipeline PIPELINE0 table match stub action AP0
+pipeline PIPELINE0 table match stub action AP0
+pipeline PIPELINE0 table match stub action AP0
+pipeline PIPELINE0 table match stub action AP0
+
+pipeline PIPELINE0 port in 0 table 0
+pipeline PIPELINE0 port in 1 table 1
+pipeline PIPELINE0 port in 2 table 2
+pipeline PIPELINE0 port in 3 table 3
+
+thread 1 pipeline PIPELINE0 enable
+
+pipeline PIPELINE0 table 0 rule add match default action fwd port 0
+pipeline PIPELINE0 table 1 rule add match default action fwd port 1
+pipeline PIPELINE0 table 2 rule add match default action fwd port 2
+pipeline PIPELINE0 table 3 rule add match default action fwd port 3
-- 
2.9.3

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

* [dpdk-dev] [PATCH v3 42/44] ip_pipeline: add route example
  2018-03-16 17:58       ` [dpdk-dev] [PATCH v3 00/44] ip_pipeline: refactoring Jasvinder Singh
                           ` (40 preceding siblings ...)
  2018-03-16 17:59         ` [dpdk-dev] [PATCH v3 41/44] ip_pipeline: add TAP " Jasvinder Singh
@ 2018-03-16 17:59         ` Jasvinder Singh
  2018-03-16 17:59         ` [dpdk-dev] [PATCH v3 43/44] ip_pipeline: add firewall example Jasvinder Singh
  2018-03-16 17:59         ` [dpdk-dev] [PATCH v3 44/44] ip_pipeline: add flow classification example Jasvinder Singh
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-16 17:59 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Reshma Pattan

Add example to built pipeline with LPM table to demonstrate layer 3
routing.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Reshma Pattan <reshma.pattan@intel.com>
---
 examples/ip_pipeline/examples/route.cli | 60 +++++++++++++++++++++++++++++++++
 1 file changed, 60 insertions(+)
 create mode 100644 examples/ip_pipeline/examples/route.cli

diff --git a/examples/ip_pipeline/examples/route.cli b/examples/ip_pipeline/examples/route.cli
new file mode 100644
index 0000000..50f0a10
--- /dev/null
+++ b/examples/ip_pipeline/examples/route.cli
@@ -0,0 +1,60 @@
+; SPDX-License-Identifier: BSD-3-Clause
+; Copyright(c) 2010-2018 Intel Corporation
+
+;                 _______________
+; LINK0 RXQ0 --->|               |---> LINK0 TXQ0
+;                |               |
+; LINK1 RXQ0 --->|               |---> LINK1 TXQ0
+;                |    Routing    |
+; LINK2 RXQ0 --->|               |---> LINK2 TXQ0
+;                |               |
+; LINK3 RXQ0 --->|               |---> LINK3 TXQ0
+;                |_______________|
+;                        |
+;                        +-----------> SINK0 (route miss)
+;
+; Input packet: Ethernet/IPv4
+;
+; Packet buffer layout:
+; #   Field Name       Offset (Bytes)   Size (Bytes)
+; 0   Mbuf             0                128
+; 1   Headroom         128              128
+; 2   Ethernet header  256              14
+; 3   IPv4 header      270              20
+
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+
+link LINK0 dev 0000:02:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+link LINK1 dev 0000:02:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+link LINK2 dev 0000:06:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+link LINK3 dev 0000:06:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+
+table action profile AP0 ipv4 offset 270 fwd encap ether
+
+pipeline PIPELINE0 period 10 offset_port_id 0 cpu 0
+
+pipeline PIPELINE0 port in bsz 32 link LINK0 rxq 0
+pipeline PIPELINE0 port in bsz 32 link LINK1 rxq 0
+pipeline PIPELINE0 port in bsz 32 link LINK2 rxq 0
+pipeline PIPELINE0 port in bsz 32 link LINK3 rxq 0
+
+pipeline PIPELINE0 port out bsz 32 link LINK0 txq 0
+pipeline PIPELINE0 port out bsz 32 link LINK1 txq 0
+pipeline PIPELINE0 port out bsz 32 link LINK2 txq 0
+pipeline PIPELINE0 port out bsz 32 link LINK3 txq 0
+pipeline PIPELINE0 port out bsz 32 sink SINK0
+
+pipeline PIPELINE0 table match lpm ipv4 offset 286 size 4K action AP0
+
+pipeline PIPELINE0 port in 0 table 0
+pipeline PIPELINE0 port in 1 table 0
+pipeline PIPELINE0 port in 2 table 0
+pipeline PIPELINE0 port in 3 table 0
+
+thread 1 pipeline PIPELINE0 enable
+
+pipeline PIPELINE0 table 0 rule add match default action fwd port 4
+pipeline PIPELINE0 table 0 rule add match lpm ipv4 100.0.0.0 10 action fwd port 0 encap ether a0:a1:a2:a3:a4:a5 00:01:02:03:04:05
+pipeline PIPELINE0 table 0 rule add match lpm ipv4 100.64.0.0 10 action fwd port 1 encap ether b0:b1:b2:b3:b4:b5 10:11:12:13:14:15
+pipeline PIPELINE0 table 0 rule add match lpm ipv4 100.128.0.0 10 action fwd port 2 encap ether c0:c1:c2:c3:c4:c5 20:21:22:23:24:25
+pipeline PIPELINE0 table 0 rule add match lpm ipv4 100.192.0.0 10 action fwd port 3 encap ether d0:d1:d2:d3:d4:d5 30:31:32:33:34:35
-- 
2.9.3

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

* [dpdk-dev] [PATCH v3 43/44] ip_pipeline: add firewall example
  2018-03-16 17:58       ` [dpdk-dev] [PATCH v3 00/44] ip_pipeline: refactoring Jasvinder Singh
                           ` (41 preceding siblings ...)
  2018-03-16 17:59         ` [dpdk-dev] [PATCH v3 42/44] ip_pipeline: add route example Jasvinder Singh
@ 2018-03-16 17:59         ` Jasvinder Singh
  2018-03-16 17:59         ` [dpdk-dev] [PATCH v3 44/44] ip_pipeline: add flow classification example Jasvinder Singh
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-16 17:59 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add example to built pipeline with ACL table to demonstrate
the firewall operation.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/examples/firewall.cli | 59 ++++++++++++++++++++++++++++++
 1 file changed, 59 insertions(+)
 create mode 100644 examples/ip_pipeline/examples/firewall.cli

diff --git a/examples/ip_pipeline/examples/firewall.cli b/examples/ip_pipeline/examples/firewall.cli
new file mode 100644
index 0000000..269256c
--- /dev/null
+++ b/examples/ip_pipeline/examples/firewall.cli
@@ -0,0 +1,59 @@
+; SPDX-License-Identifier: BSD-3-Clause
+; Copyright(c) 2010-2018 Intel Corporation
+
+;                 _______________
+; LINK0 RXQ0 --->|               |---> LINK0 TXQ0
+;                |               |
+; LINK1 RXQ0 --->|               |---> LINK1 TXQ0
+;                |   Firewall    |
+; LINK2 RXQ0 --->|               |---> LINK2 TXQ0
+;                |               |
+; LINK3 RXQ0 --->|               |---> LINK3 TXQ0
+;                |_______________|
+;                        |
+;                       -+-
+;
+; Input packet: Ethernet/IPv4
+;
+; Packet buffer layout:
+; #   Field Name            Offset (Bytes)      Size (Bytes)
+; 0   Mbuf                  0                   128
+; 1   Headroom              128                 128
+; 2   Ethernet header       256                 14
+; 3   IPv4 header           270                 20
+
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+
+link LINK0 dev 0000:02:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+link LINK1 dev 0000:02:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+link LINK2 dev 0000:06:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+link LINK3 dev 0000:06:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+
+table action profile AP0 ipv4 offset 270 fwd
+
+pipeline PIPELINE0 period 10 offset_port_id 0 cpu 0
+
+pipeline PIPELINE0 port in bsz 32 link LINK0 rxq 0
+pipeline PIPELINE0 port in bsz 32 link LINK1 rxq 0
+pipeline PIPELINE0 port in bsz 32 link LINK2 rxq 0
+pipeline PIPELINE0 port in bsz 32 link LINK3 rxq 0
+
+pipeline PIPELINE0 port out bsz 32 link LINK0 txq 0
+pipeline PIPELINE0 port out bsz 32 link LINK1 txq 0
+pipeline PIPELINE0 port out bsz 32 link LINK2 txq 0
+pipeline PIPELINE0 port out bsz 32 link LINK3 txq 0
+
+pipeline PIPELINE0 table match acl ipv4 offset 270 size 4K action AP0
+
+pipeline PIPELINE0 port in 0 table 0
+pipeline PIPELINE0 port in 1 table 0
+pipeline PIPELINE0 port in 2 table 0
+pipeline PIPELINE0 port in 3 table 0
+
+thread 1 pipeline PIPELINE0 enable
+
+pipeline PIPELINE0 table 0 rule add match default action fwd drop
+pipeline PIPELINE0 table 0 rule add match acl priority 0 ipv4 0.0.0.0 0 100.0.0.0 10 0 65535 0 65535 6 action fwd port 0
+pipeline PIPELINE0 table 0 rule add match acl priority 0 ipv4 0.0.0.0 0 100.64.0.0 10 0 65535 0 65535 6 action fwd port 1
+pipeline PIPELINE0 table 0 rule add match acl priority 0 ipv4 0.0.0.0 0 100.128.0.0 10 0 65535 0 65535 6 action fwd port 2
+pipeline PIPELINE0 table 0 rule add match acl priority 0 ipv4 0.0.0.0 0 100.192.0.0 10 0 65535 0 65535 6 action fwd port 3
-- 
2.9.3

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

* [dpdk-dev] [PATCH v3 44/44] ip_pipeline: add flow classification example
  2018-03-16 17:58       ` [dpdk-dev] [PATCH v3 00/44] ip_pipeline: refactoring Jasvinder Singh
                           ` (42 preceding siblings ...)
  2018-03-16 17:59         ` [dpdk-dev] [PATCH v3 43/44] ip_pipeline: add firewall example Jasvinder Singh
@ 2018-03-16 17:59         ` Jasvinder Singh
  43 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-16 17:59 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Fan Zhang

Add example to build pipeline with hash table to classify the
ingress traffic.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Fan Zhang <roy.fan.zhang@intel.com>
---
 examples/ip_pipeline/examples/flow.cli | 60 ++++++++++++++++++++++++++++++++++
 1 file changed, 60 insertions(+)
 create mode 100644 examples/ip_pipeline/examples/flow.cli

diff --git a/examples/ip_pipeline/examples/flow.cli b/examples/ip_pipeline/examples/flow.cli
new file mode 100644
index 0000000..60b8445
--- /dev/null
+++ b/examples/ip_pipeline/examples/flow.cli
@@ -0,0 +1,60 @@
+; SPDX-License-Identifier: BSD-3-Clause
+; Copyright(c) 2010-2018 Intel Corporation
+
+;                 ________________
+; LINK0 RXQ0 --->|                |---> LINK0 TXQ0
+;                |                |
+; LINK1 RXQ0 --->|                |---> LINK1 TXQ0
+;                |      Flow      |
+; LINK2 RXQ0 --->| Classification |---> LINK2 TXQ0
+;                |                |
+; LINK3 RXQ0 --->|                |---> LINK3 TXQ0
+;                |________________|
+;                        |
+;                        +-----------> SINK0 (flow lookup miss)
+;
+; Input packet: Ethernet/IPv4
+;
+; Packet buffer layout:
+; #   Field Name       Offset (Bytes)   Size (Bytes)
+; 0   Mbuf             0                128
+; 1   Headroom         128              128
+; 2   Ethernet header  256              14
+; 3   IPv4 header      270              20
+
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+
+link LINK0 dev 0000:02:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+link LINK1 dev 0000:02:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+link LINK2 dev 0000:06:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+link LINK3 dev 0000:06:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+
+table action profile AP0 ipv4 offset 270 fwd
+
+pipeline PIPELINE0 period 10 offset_port_id 0 cpu 0
+
+pipeline PIPELINE0 port in bsz 32 link LINK0 rxq 0
+pipeline PIPELINE0 port in bsz 32 link LINK1 rxq 0
+pipeline PIPELINE0 port in bsz 32 link LINK2 rxq 0
+pipeline PIPELINE0 port in bsz 32 link LINK3 rxq 0
+
+pipeline PIPELINE0 port out bsz 32 link LINK0 txq 0
+pipeline PIPELINE0 port out bsz 32 link LINK1 txq 0
+pipeline PIPELINE0 port out bsz 32 link LINK2 txq 0
+pipeline PIPELINE0 port out bsz 32 link LINK3 txq 0
+pipeline PIPELINE0 port out bsz 32 sink SINK0
+
+pipeline PIPELINE0 table match hash ext key 16 mask 00FF0000FFFFFFFFFFFFFFFFFFFFFFFF offset 278 buckets 16K size 65K action AP0
+
+pipeline PIPELINE0 port in 0 table 0
+pipeline PIPELINE0 port in 1 table 0
+pipeline PIPELINE0 port in 2 table 0
+pipeline PIPELINE0 port in 3 table 0
+
+thread 1 pipeline PIPELINE0 enable
+
+pipeline PIPELINE0 table 0 rule add match default action fwd port 4
+pipeline PIPELINE0 table 0 rule add match hash ipv4_5tuple 100.0.0.10 200.0.0.10 100 200 6 action fwd port 0
+pipeline PIPELINE0 table 0 rule add match hash ipv4_5tuple 100.0.0.11 200.0.0.11 101 201 6 action fwd port 1
+pipeline PIPELINE0 table 0 rule add match hash ipv4_5tuple 100.0.0.12 200.0.0.12 102 202 6 action fwd port 2
+pipeline PIPELINE0 table 0 rule add match hash ipv4_5tuple 100.0.0.13 200.0.0.13 103 203 6 action fwd port 3
-- 
2.9.3

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

* [dpdk-dev] [PATCH v4 00/49] ip_pipeline: refactoring
  2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 01/44] pipeline: add pipeline table action APIs Jasvinder Singh
@ 2018-03-29 18:31           ` Jasvinder Singh
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 01/49] pipeline: add pipeline table action APIs Jasvinder Singh
                               ` (49 more replies)
  0 siblings, 50 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-29 18:31 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Refactored the IP pipeline application. As result, the code base
size (lines of code) reduces by ~60%.

1. Moved table actions into the librte_pipeline library. As result,
   the pre-fabricated pipelines from the application pipeline folder
   were removed. The flexibility is greatly improved, as now any
   action can be combined with any match (i.e. table type), which
   was not possible before.

2. Removed configuration file as the initialization method. Now
   all the pipelines are set up and assigned to threads through
   CLI commands for improved flexibility.

3. Replaced the local CLI with remote CLI. Any standard TCP
   client (e.g. telnet, netcat) can now connect to the app,
   send request as command string through the network and wait
   for the response string before pushing the next command.
   Results in better flexibility and automation.

v4:
- add pipeline port action APIs.
- add load balance pipeline table action.
- add cli for adding bulk entries to pipeline table.
- add check to return error when pipeline is not enabled on the thread.
- add source and sink port params to cli

v3:
- add checksum update for TTL and NAT action
- fix build warning

v2:
- split the patch that removes the existing pipeline components
  into multiple patches.
- fix checkpatch errors.

Jasvinder Singh (49):
  pipeline: add pipeline table action APIs
  pipeline: get pipeline table action params
  pipeline: add traffic metering action
  pipeline: add traffic manager action
  pipeline: add packet encapsulation action
  pipeline: add nat action
  pipeline: add ttl update action
  pipeline: add statistics read action
  pipeline: add timestamp action
  pipeline: add load balance action
  pipeline: add pipeline port in action APIs
  librte_table/acl: remove incorrect check
  ip_pipeline: remove passthrough pipeline
  ip_pipeline: remove routing pipeline
  ip_pipeline: remove flow classification pipeline
  ip_pipeline: remove flow actions pipeline
  ip_pipeline: remove firewall pipeline
  ip_pipeline: remove master pipeline
  ip_pipeline: remove config
  ip_pipeline: rework and improvements
  ip_pipeline: add cli interface
  ip_pipeline: add mempool object for pipeline
  ip_pipeline: add link object
  ip_pipeline: add software queue object
  ip_pipeline: add traffic manager object
  ip_pipeline: add tap object
  ip_pipeline: add kni object
  ip_pipeline: add action profile object
  ip_pipeline: add pipeline object
  ip_pipeline: add threads
  ip_pipeline: add thread runtime
  ip_pipeline: add cli to enable and disable pipeline
  ip_pipeline: add cli to enable and disable pipeline port
  ip_pipeline: add cli to read pipeline port and table stats
  ip_pipeline: add cli for pipeline table entry
  ip_pipeline: add cli to delete pipeline table entry
  ip_pipeline: add cli for bulk entries to pipeline table
  ip_pipeline: add cli to read pipeline table entry stats
  ip_pipeline: add cli to configure meter profile
  ip_pipeline: add cli to read meter stats
  ip_pipeline: add cli to update dscp table
  ip_pipeline: add cli to read ttl stats
  ip_pipeline: add cli for load balance action
  ip_pipeline: add l2fwd example
  ip_pipeline: add KNI port example
  ip_pipeline: add TAP port example
  ip_pipeline: add route example
  ip_pipeline: add firewall example
  ip_pipeline: add flow classification example

 doc/api/doxy-api-index.md                          |    1 +
 examples/ip_pipeline/Makefile                      |   49 +-
 examples/ip_pipeline/action.c                      |  289 ++
 examples/ip_pipeline/action.h                      |   77 +
 examples/ip_pipeline/app.h                         | 1401 ------
 examples/ip_pipeline/cli.c                         | 4814 ++++++++++++++++++++
 examples/ip_pipeline/cli.h                         |   18 +
 examples/ip_pipeline/common.h                      |   12 +
 examples/ip_pipeline/config/action.cfg             |   68 -
 examples/ip_pipeline/config/action.sh              |  119 -
 examples/ip_pipeline/config/action.txt             |    8 -
 examples/ip_pipeline/config/diagram-generator.py   |  317 --
 .../ip_pipeline/config/edge_router_downstream.cfg  |   97 -
 .../ip_pipeline/config/edge_router_downstream.sh   |   13 -
 .../ip_pipeline/config/edge_router_upstream.cfg    |  124 -
 .../ip_pipeline/config/edge_router_upstream.sh     |   33 -
 examples/ip_pipeline/config/firewall.cfg           |   68 -
 examples/ip_pipeline/config/firewall.sh            |   13 -
 examples/ip_pipeline/config/firewall.txt           |    9 -
 examples/ip_pipeline/config/flow.cfg               |   72 -
 examples/ip_pipeline/config/flow.sh                |   25 -
 examples/ip_pipeline/config/flow.txt               |   17 -
 examples/ip_pipeline/config/ip_pipeline.cfg        |    9 -
 examples/ip_pipeline/config/ip_pipeline.sh         |    5 -
 examples/ip_pipeline/config/kni.cfg                |   67 -
 examples/ip_pipeline/config/l2fwd.cfg              |   58 -
 examples/ip_pipeline/config/l3fwd.cfg              |   68 -
 examples/ip_pipeline/config/l3fwd.sh               |   33 -
 examples/ip_pipeline/config/l3fwd_arp.cfg          |   70 -
 examples/ip_pipeline/config/l3fwd_arp.sh           |   43 -
 examples/ip_pipeline/config/network_layers.cfg     |  227 -
 examples/ip_pipeline/config/network_layers.sh      |   79 -
 .../ip_pipeline/config/pipeline-to-core-mapping.py |  906 ----
 examples/ip_pipeline/config/tap.cfg                |   64 -
 examples/ip_pipeline/config/tm_profile.cfg         |  105 -
 examples/ip_pipeline/config_check.c                |  488 --
 examples/ip_pipeline/config_parse.c                | 3395 --------------
 examples/ip_pipeline/config_parse_tm.c             |  419 --
 examples/ip_pipeline/conn.c                        |  326 ++
 examples/ip_pipeline/conn.h                        |   47 +
 examples/ip_pipeline/cpu_core_map.c                |  471 --
 examples/ip_pipeline/cpu_core_map.h                |   40 -
 examples/ip_pipeline/examples/firewall.cli         |   59 +
 examples/ip_pipeline/examples/flow.cli             |   60 +
 examples/ip_pipeline/examples/kni.cli              |   69 +
 examples/ip_pipeline/examples/l2fwd.cli            |   51 +
 examples/ip_pipeline/examples/route.cli            |   60 +
 examples/ip_pipeline/examples/tap.cli              |   66 +
 examples/ip_pipeline/{pipeline => }/hash_func.h    |    3 +-
 .../ip_pipeline/{pipeline => }/hash_func_arm64.h   |    0
 examples/ip_pipeline/init.c                        | 1927 --------
 examples/ip_pipeline/kni.c                         |  167 +
 examples/ip_pipeline/kni.h                         |   44 +
 examples/ip_pipeline/link.c                        |  268 ++
 examples/ip_pipeline/link.h                        |   63 +
 examples/ip_pipeline/main.c                        |  259 +-
 examples/ip_pipeline/mempool.c                     |   81 +
 examples/ip_pipeline/mempool.h                     |   40 +
 examples/ip_pipeline/meson.build                   |   35 +-
 examples/ip_pipeline/parser.c                      |   16 +-
 examples/ip_pipeline/parser.h                      |    8 +
 examples/ip_pipeline/pipeline.c                    |  973 ++++
 examples/ip_pipeline/pipeline.h                    |  389 +-
 .../ip_pipeline/pipeline/pipeline_actions_common.h |  202 -
 examples/ip_pipeline/pipeline/pipeline_common_be.c |  176 -
 examples/ip_pipeline/pipeline/pipeline_common_be.h |  134 -
 examples/ip_pipeline/pipeline/pipeline_common_fe.c | 1455 ------
 examples/ip_pipeline/pipeline/pipeline_common_fe.h |  231 -
 examples/ip_pipeline/pipeline/pipeline_firewall.c  | 1421 ------
 examples/ip_pipeline/pipeline/pipeline_firewall.h  |   60 -
 .../ip_pipeline/pipeline/pipeline_firewall_be.c    |  856 ----
 .../ip_pipeline/pipeline/pipeline_firewall_be.h    |  147 -
 .../ip_pipeline/pipeline/pipeline_flow_actions.c   | 1286 ------
 .../ip_pipeline/pipeline/pipeline_flow_actions.h   |   60 -
 .../pipeline/pipeline_flow_actions_be.c            |  983 ----
 .../pipeline/pipeline_flow_actions_be.h            |  139 -
 .../pipeline/pipeline_flow_classification.c        | 1878 --------
 .../pipeline/pipeline_flow_classification.h        |  106 -
 .../pipeline/pipeline_flow_classification_be.c     |  723 ---
 .../pipeline/pipeline_flow_classification_be.h     |  113 -
 examples/ip_pipeline/pipeline/pipeline_master.c    |   20 -
 examples/ip_pipeline/pipeline/pipeline_master.h    |   12 -
 examples/ip_pipeline/pipeline/pipeline_master_be.c |  141 -
 examples/ip_pipeline/pipeline/pipeline_master_be.h |   12 -
 .../ip_pipeline/pipeline/pipeline_passthrough.c    |   45 -
 .../ip_pipeline/pipeline/pipeline_passthrough.h    |   12 -
 .../ip_pipeline/pipeline/pipeline_passthrough_be.c |  929 ----
 .../ip_pipeline/pipeline/pipeline_passthrough_be.h |   44 -
 examples/ip_pipeline/pipeline/pipeline_routing.c   | 1613 -------
 examples/ip_pipeline/pipeline/pipeline_routing.h   |   71 -
 .../ip_pipeline/pipeline/pipeline_routing_be.c     | 1966 --------
 .../ip_pipeline/pipeline/pipeline_routing_be.h     |  283 --
 examples/ip_pipeline/pipeline_be.h                 |  322 --
 examples/ip_pipeline/swq.c                         |   74 +
 examples/ip_pipeline/swq.h                         |   37 +
 examples/ip_pipeline/tap.c                         |   97 +
 examples/ip_pipeline/tap.h                         |   29 +
 examples/ip_pipeline/thread.c                      | 2796 +++++++++++-
 examples/ip_pipeline/thread.h                      |   75 +-
 examples/ip_pipeline/thread_fe.c                   |  457 --
 examples/ip_pipeline/thread_fe.h                   |   72 -
 examples/ip_pipeline/tmgr.c                        |  227 +
 examples/ip_pipeline/tmgr.h                        |   70 +
 lib/librte_pipeline/Makefile                       |    7 +-
 lib/librte_pipeline/meson.build                    |    7 +-
 lib/librte_pipeline/rte_pipeline_version.map       |   29 +
 lib/librte_pipeline/rte_port_in_action.c           |  531 +++
 lib/librte_pipeline/rte_port_in_action.h           |  301 ++
 lib/librte_pipeline/rte_table_action.c             | 2386 ++++++++++
 lib/librte_pipeline/rte_table_action.h             |  905 ++++
 lib/librte_table/rte_table_acl.c                   |    6 -
 111 files changed, 15520 insertions(+), 27228 deletions(-)
 create mode 100644 examples/ip_pipeline/action.c
 create mode 100644 examples/ip_pipeline/action.h
 delete mode 100644 examples/ip_pipeline/app.h
 create mode 100644 examples/ip_pipeline/cli.c
 create mode 100644 examples/ip_pipeline/cli.h
 create mode 100644 examples/ip_pipeline/common.h
 delete mode 100644 examples/ip_pipeline/config/action.cfg
 delete mode 100644 examples/ip_pipeline/config/action.sh
 delete mode 100644 examples/ip_pipeline/config/action.txt
 delete mode 100755 examples/ip_pipeline/config/diagram-generator.py
 delete mode 100644 examples/ip_pipeline/config/edge_router_downstream.cfg
 delete mode 100644 examples/ip_pipeline/config/edge_router_downstream.sh
 delete mode 100644 examples/ip_pipeline/config/edge_router_upstream.cfg
 delete mode 100644 examples/ip_pipeline/config/edge_router_upstream.sh
 delete mode 100644 examples/ip_pipeline/config/firewall.cfg
 delete mode 100644 examples/ip_pipeline/config/firewall.sh
 delete mode 100644 examples/ip_pipeline/config/firewall.txt
 delete mode 100644 examples/ip_pipeline/config/flow.cfg
 delete mode 100644 examples/ip_pipeline/config/flow.sh
 delete mode 100644 examples/ip_pipeline/config/flow.txt
 delete mode 100644 examples/ip_pipeline/config/ip_pipeline.cfg
 delete mode 100644 examples/ip_pipeline/config/ip_pipeline.sh
 delete mode 100644 examples/ip_pipeline/config/kni.cfg
 delete mode 100644 examples/ip_pipeline/config/l2fwd.cfg
 delete mode 100644 examples/ip_pipeline/config/l3fwd.cfg
 delete mode 100644 examples/ip_pipeline/config/l3fwd.sh
 delete mode 100644 examples/ip_pipeline/config/l3fwd_arp.cfg
 delete mode 100644 examples/ip_pipeline/config/l3fwd_arp.sh
 delete mode 100644 examples/ip_pipeline/config/network_layers.cfg
 delete mode 100644 examples/ip_pipeline/config/network_layers.sh
 delete mode 100755 examples/ip_pipeline/config/pipeline-to-core-mapping.py
 delete mode 100644 examples/ip_pipeline/config/tap.cfg
 delete mode 100644 examples/ip_pipeline/config/tm_profile.cfg
 delete mode 100644 examples/ip_pipeline/config_check.c
 delete mode 100644 examples/ip_pipeline/config_parse.c
 delete mode 100644 examples/ip_pipeline/config_parse_tm.c
 create mode 100644 examples/ip_pipeline/conn.c
 create mode 100644 examples/ip_pipeline/conn.h
 delete mode 100644 examples/ip_pipeline/cpu_core_map.c
 delete mode 100644 examples/ip_pipeline/cpu_core_map.h
 create mode 100644 examples/ip_pipeline/examples/firewall.cli
 create mode 100644 examples/ip_pipeline/examples/flow.cli
 create mode 100644 examples/ip_pipeline/examples/kni.cli
 create mode 100644 examples/ip_pipeline/examples/l2fwd.cli
 create mode 100644 examples/ip_pipeline/examples/route.cli
 create mode 100644 examples/ip_pipeline/examples/tap.cli
 rename examples/ip_pipeline/{pipeline => }/hash_func.h (99%)
 rename examples/ip_pipeline/{pipeline => }/hash_func_arm64.h (100%)
 delete mode 100644 examples/ip_pipeline/init.c
 create mode 100644 examples/ip_pipeline/kni.c
 create mode 100644 examples/ip_pipeline/kni.h
 create mode 100644 examples/ip_pipeline/link.c
 create mode 100644 examples/ip_pipeline/link.h
 create mode 100644 examples/ip_pipeline/mempool.c
 create mode 100644 examples/ip_pipeline/mempool.h
 create mode 100644 examples/ip_pipeline/pipeline.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_actions_common.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_common_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_common_be.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_common_fe.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_common_fe.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_firewall.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_firewall.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_firewall_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_firewall_be.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_actions.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_actions.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_actions_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_actions_be.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_classification.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_classification.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_classification_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_classification_be.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_master.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_master.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_master_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_master_be.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_passthrough.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_passthrough.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_passthrough_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_passthrough_be.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_routing.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_routing.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_routing_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_routing_be.h
 delete mode 100644 examples/ip_pipeline/pipeline_be.h
 create mode 100644 examples/ip_pipeline/swq.c
 create mode 100644 examples/ip_pipeline/swq.h
 create mode 100644 examples/ip_pipeline/tap.c
 create mode 100644 examples/ip_pipeline/tap.h
 delete mode 100644 examples/ip_pipeline/thread_fe.c
 delete mode 100644 examples/ip_pipeline/thread_fe.h
 create mode 100644 examples/ip_pipeline/tmgr.c
 create mode 100644 examples/ip_pipeline/tmgr.h
 create mode 100644 lib/librte_pipeline/rte_port_in_action.c
 create mode 100644 lib/librte_pipeline/rte_port_in_action.h
 create mode 100644 lib/librte_pipeline/rte_table_action.c
 create mode 100644 lib/librte_pipeline/rte_table_action.h

-- 
2.9.3

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

* [dpdk-dev] [PATCH v4 01/49] pipeline: add pipeline table action APIs
  2018-03-29 18:31           ` [dpdk-dev] [PATCH v4 00/49] ip_pipeline: refactoring Jasvinder Singh
@ 2018-03-29 18:31             ` Jasvinder Singh
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 02/49] pipeline: get pipeline table action params Jasvinder Singh
                               ` (48 subsequent siblings)
  49 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-29 18:31 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

This API provides a common set of actions for pipeline tables to speed up
application development.

Each match-action rule added to a pipeline table has associated data
that stores the action context. This data is input to the table
action handler called for every input packet that hits the rule as
part of the table lookup during the pipeline execution.

The pipeline library allows the user to define his own table
actions by providing customized table action handlers (table
lookup) and complete freedom of setting the rules and their data
(table rule add/delete). While the user can still follow this
process, this API is intended to provide a quicker development
alternative for a set of predefined actions.

The typical steps to use this API are:
* Define a table action profile.
* Instantiate the table action profile to create table action objects.
* Use the table action object to generate the pipeline table action
  handlers (invoked by the pipeline table lookup operation).
* Use the table action object to generate the rule data (for the
  pipeline table rule add operation) based on given action parameters.
* Use the table action object to read action data (e.g. stats counters)
  for any given rule.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 doc/api/doxy-api-index.md                    |   1 +
 lib/librte_pipeline/Makefile                 |   3 +-
 lib/librte_pipeline/meson.build              |   5 +-
 lib/librte_pipeline/rte_pipeline_version.map |  13 ++
 lib/librte_pipeline/rte_table_action.c       | 279 +++++++++++++++++++++++++++
 lib/librte_pipeline/rte_table_action.h       | 224 +++++++++++++++++++++
 6 files changed, 522 insertions(+), 3 deletions(-)
 create mode 100644 lib/librte_pipeline/rte_table_action.c
 create mode 100644 lib/librte_pipeline/rte_table_action.h

diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md
index d77f205..e24b70e 100644
--- a/doc/api/doxy-api-index.md
+++ b/doc/api/doxy-api-index.md
@@ -159,6 +159,7 @@ The public API headers are grouped by topics:
     [array]            (@ref rte_table_array.h),
     [stub]             (@ref rte_table_stub.h)
   * [pipeline]         (@ref rte_pipeline.h)
+    [table_action].....(@ref rte_table_action.h)
 
 - **basic**:
   [approx fraction]    (@ref rte_approx.h),
diff --git a/lib/librte_pipeline/Makefile b/lib/librte_pipeline/Makefile
index e94fbc0..e8c43c7 100644
--- a/lib/librte_pipeline/Makefile
+++ b/lib/librte_pipeline/Makefile
@@ -21,8 +21,9 @@ LIBABIVER := 3
 # all source are stored in SRCS-y
 #
 SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) := rte_pipeline.c
+SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += rte_table_action.c
 
 # install includes
-SYMLINK-$(CONFIG_RTE_LIBRTE_PIPELINE)-include += rte_pipeline.h
+SYMLINK-$(CONFIG_RTE_LIBRTE_PIPELINE)-include += rte_pipeline.h rte_table_action.h
 
 include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_pipeline/meson.build b/lib/librte_pipeline/meson.build
index a35b622..4dda560 100644
--- a/lib/librte_pipeline/meson.build
+++ b/lib/librte_pipeline/meson.build
@@ -2,6 +2,7 @@
 # Copyright(c) 2017 Intel Corporation
 
 version = 3
-sources = files('rte_pipeline.c')
-headers = files('rte_pipeline.h')
+allow_experimental_apis = true
+sources = files('rte_pipeline.c', 'rte_table_action.c')
+headers = files('rte_pipeline.h', 'rte_table_action.h')
 deps += ['port', 'table']
diff --git a/lib/librte_pipeline/rte_pipeline_version.map b/lib/librte_pipeline/rte_pipeline_version.map
index e4ee154..4bc414c 100644
--- a/lib/librte_pipeline/rte_pipeline_version.map
+++ b/lib/librte_pipeline/rte_pipeline_version.map
@@ -45,3 +45,16 @@ DPDK_16.04 {
 	rte_pipeline_ah_packet_drop;
 
 } DPDK_2.2;
+
+EXPERIMENTAL {
+	global:
+
+	rte_table_action_apply;
+	rte_table_action_create;
+	rte_table_action_free;
+	rte_table_action_profile_action_register;
+	rte_table_action_profile_create;
+	rte_table_action_profile_free;
+	rte_table_action_profile_freeze;
+
+} DPDK_16.04;
diff --git a/lib/librte_pipeline/rte_table_action.c b/lib/librte_pipeline/rte_table_action.c
new file mode 100644
index 0000000..f15847c
--- /dev/null
+++ b/lib/librte_pipeline/rte_table_action.c
@@ -0,0 +1,279 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <rte_malloc.h>
+
+#include <rte_common.h>
+#include <rte_malloc.h>
+
+#include "rte_table_action.h"
+
+/**
+ * RTE_TABLE_ACTION_FWD
+ */
+#define fwd_data rte_pipeline_table_entry
+
+static int
+fwd_apply(struct fwd_data *data,
+	struct rte_table_action_fwd_params *p)
+{
+	data->action = p->action;
+
+	if (p->action == RTE_PIPELINE_ACTION_PORT)
+		data->port_id = p->id;
+
+	if (p->action == RTE_PIPELINE_ACTION_TABLE)
+		data->table_id = p->id;
+
+	return 0;
+}
+
+/**
+ * Action profile
+ */
+static int
+action_valid(enum rte_table_action_type action)
+{
+	switch (action) {
+	case RTE_TABLE_ACTION_FWD:
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+
+#define RTE_TABLE_ACTION_MAX                      64
+
+struct ap_config {
+	uint64_t action_mask;
+	struct rte_table_action_common_config common;
+};
+
+static size_t
+action_cfg_size(enum rte_table_action_type action)
+{
+	switch (action) {
+	default:
+		return 0;
+	}
+}
+
+static void*
+action_cfg_get(struct ap_config *ap_config __rte_unused,
+	enum rte_table_action_type type)
+{
+	switch (type) {
+	default:
+		return NULL;
+	}
+}
+
+static void
+action_cfg_set(struct ap_config *ap_config,
+	enum rte_table_action_type type,
+	void *action_cfg)
+{
+	void *dst = action_cfg_get(ap_config, type);
+
+	if (dst)
+		memcpy(dst, action_cfg, action_cfg_size(type));
+
+	ap_config->action_mask |= 1LLU << type;
+}
+
+struct ap_data {
+	size_t offset[RTE_TABLE_ACTION_MAX];
+	size_t total_size;
+};
+
+static size_t
+action_data_size(enum rte_table_action_type action,
+	struct ap_config *ap_config __rte_unused)
+{
+	switch (action) {
+	case RTE_TABLE_ACTION_FWD:
+		return sizeof(struct fwd_data);
+
+	default:
+		return 0;
+	}
+}
+
+
+static void
+action_data_offset_set(struct ap_data *ap_data,
+	struct ap_config *ap_config)
+{
+	uint64_t action_mask = ap_config->action_mask;
+	size_t offset;
+	uint32_t action;
+
+	memset(ap_data->offset, 0, sizeof(ap_data->offset));
+
+	offset = 0;
+	for (action = 0; action < RTE_TABLE_ACTION_MAX; action++)
+		if (action_mask & (1LLU << action)) {
+			ap_data->offset[action] = offset;
+			offset += action_data_size((enum rte_table_action_type)action,
+				ap_config);
+		}
+
+	ap_data->total_size = offset;
+}
+
+struct rte_table_action_profile {
+	struct ap_config cfg;
+	struct ap_data data;
+	int frozen;
+};
+
+struct rte_table_action_profile *
+rte_table_action_profile_create(struct rte_table_action_common_config *common)
+{
+	struct rte_table_action_profile *ap;
+
+	/* Check input arguments */
+	if (common == NULL)
+		return NULL;
+
+	/* Memory allocation */
+	ap = calloc(1, sizeof(struct rte_table_action_profile));
+	if (ap == NULL)
+		return NULL;
+
+	/* Initialization */
+	memcpy(&ap->cfg.common, common, sizeof(*common));
+
+	return ap;
+}
+
+
+int
+rte_table_action_profile_action_register(struct rte_table_action_profile *profile,
+	enum rte_table_action_type type,
+	void *action_config)
+{
+	/* Check input arguments */
+	if ((profile == NULL) ||
+		profile->frozen ||
+		(action_valid(type) == 0) ||
+		(profile->cfg.action_mask & (1LLU << type)) ||
+		((action_cfg_size(type) == 0) && action_config) ||
+		(action_cfg_size(type) && (action_config == NULL)))
+		return -EINVAL;
+
+	/* Action enable */
+	action_cfg_set(&profile->cfg, type, action_config);
+
+	return 0;
+}
+
+int
+rte_table_action_profile_freeze(struct rte_table_action_profile *profile)
+{
+	if (profile->frozen)
+		return -EBUSY;
+
+	profile->cfg.action_mask |= 1LLU << RTE_TABLE_ACTION_FWD;
+	action_data_offset_set(&profile->data, &profile->cfg);
+	profile->frozen = 1;
+
+	return 0;
+}
+
+int
+rte_table_action_profile_free(struct rte_table_action_profile *profile)
+{
+	if (profile == NULL)
+		return 0;
+
+	free(profile);
+	return 0;
+}
+
+struct rte_table_action {
+	struct ap_config cfg;
+	struct ap_data data;
+};
+
+struct rte_table_action *
+rte_table_action_create(struct rte_table_action_profile *profile,
+	uint32_t socket_id)
+{
+	struct rte_table_action *action;
+
+	/* Check input arguments */
+	if ((profile == NULL) ||
+		(profile->frozen == 0))
+		return NULL;
+
+	/* Memory allocation */
+	action = rte_zmalloc_socket(NULL,
+		sizeof(struct rte_table_action),
+		RTE_CACHE_LINE_SIZE,
+		socket_id);
+	if (action == NULL)
+		return NULL;
+
+	/* Initialization */
+	memcpy(&action->cfg, &profile->cfg, sizeof(profile->cfg));
+	memcpy(&action->data, &profile->data, sizeof(profile->data));
+
+	return action;
+}
+
+static __rte_always_inline void *
+action_data_get(void *data,
+	struct rte_table_action *action,
+	enum rte_table_action_type type)
+{
+	size_t offset = action->data.offset[type];
+	uint8_t *data_bytes = data;
+
+	return &data_bytes[offset];
+}
+
+int
+rte_table_action_apply(struct rte_table_action *action,
+	void *data,
+	enum rte_table_action_type type,
+	void *action_params)
+{
+	void *action_data;
+
+	/* Check input arguments */
+	if ((action == NULL) ||
+		(data == NULL) ||
+		(action_valid(type) == 0) ||
+		((action->cfg.action_mask & (1LLU << type)) == 0) ||
+		(action_params == NULL))
+		return -EINVAL;
+
+	/* Data update */
+	action_data = action_data_get(data, action, type);
+
+	switch (type) {
+	case RTE_TABLE_ACTION_FWD:
+		return fwd_apply(action_data,
+			action_params);
+
+	default:
+		return -EINVAL;
+	}
+}
+
+int
+rte_table_action_free(struct rte_table_action *action)
+{
+	if (action == NULL)
+		return 0;
+
+	rte_free(action);
+
+	return 0;
+}
diff --git a/lib/librte_pipeline/rte_table_action.h b/lib/librte_pipeline/rte_table_action.h
new file mode 100644
index 0000000..da7f12c
--- /dev/null
+++ b/lib/librte_pipeline/rte_table_action.h
@@ -0,0 +1,224 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation
+ */
+
+#ifndef __INCLUDE_RTE_TABLE_ACTION_H__
+#define __INCLUDE_RTE_TABLE_ACTION_H__
+
+/**
+ * @file
+ * RTE Pipeline Table Actions
+ *
+ * This API provides a common set of actions for pipeline tables to speed up
+ * application development.
+ *
+ * Each match-action rule added to a pipeline table has associated data that
+ * stores the action context. This data is input to the table action handler
+ * called for every input packet that hits the rule as part of the table lookup
+ * during the pipeline execution. The pipeline library allows the user to define
+ * his own table actions by providing customized table action handlers (table
+ * lookup) and complete freedom of setting the rules and their data (table rule
+ * add/delete). While the user can still follow this process, this API is
+ * intended to provide a quicker development alternative for a set of predefined
+ * actions.
+ *
+ * The typical steps to use this API are:
+ *  - Define a table action profile. This is a configuration template that can
+ *    potentially be shared by multiple tables from the same or different
+ *    pipelines, with different tables from the same pipeline likely to use
+ *    different action profiles. For every table using a given action profile,
+ *    the profile defines the set of actions and the action configuration to be
+ *    implemented for all the table rules. API functions:
+ *    rte_table_action_profile_create(),
+ *    rte_table_action_profile_action_register(),
+ *    rte_table_action_profile_freeze().
+ *
+ *  - Instantiate the table action profile to create table action objects. Each
+ *    pipeline table has its own table action object. API functions:
+ *    rte_table_action_create().
+ *
+ *  - Use the table action object to generate the pipeline table action handlers
+ *    (invoked by the pipeline table lookup operation). API functions:
+ *    rte_table_action_table_params_get().
+ *
+ *  - Use the table action object to generate the rule data (for the pipeline
+ *    table rule add operation) based on given action parameters. API functions:
+ *    rte_table_action_apply().
+ *
+ *  - Use the table action object to read action data (e.g. stats counters) for
+ *    any given rule. API functions: rte_table_action_XYZ_read().
+ *
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+
+#include <rte_compat.h>
+
+#include "rte_pipeline.h"
+
+/** Table actions. */
+enum rte_table_action_type {
+	/** Forward to next pipeline table, output port or drop. */
+	RTE_TABLE_ACTION_FWD = 0,
+};
+
+/** Common action configuration (per table action profile). */
+struct rte_table_action_common_config {
+	/** Input packet Internet Protocol (IP) version. Non-zero for IPv4, zero
+	 * for IPv6.
+	 */
+	int ip_version;
+
+	/** IP header offset within the input packet buffer. Offset 0 points to
+	 * the first byte of the MBUF structure.
+	 */
+	uint32_t ip_offset;
+};
+
+/**
+ * RTE_TABLE_ACTION_FWD
+ */
+/** Forward action parameters (per table rule). */
+struct rte_table_action_fwd_params {
+	/** Forward action. */
+	enum rte_pipeline_action action;
+
+	/** Pipeline table ID or output port ID. */
+	uint32_t id;
+};
+
+/**
+ * Table action profile.
+ */
+struct rte_table_action_profile;
+
+/**
+ * Table action profile create.
+ *
+ * @param[in] common
+ *   Common action configuration.
+ * @return
+ *   Table action profile handle on success, NULL otherwise.
+ */
+struct rte_table_action_profile * __rte_experimental
+rte_table_action_profile_create(struct rte_table_action_common_config *common);
+
+/**
+ * Table action profile free.
+ *
+ * @param[in] profile
+ *   Table profile action handle (needs to be valid).
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_table_action_profile_free(struct rte_table_action_profile *profile);
+
+/**
+ * Table action profile action register.
+ *
+ * @param[in] profile
+ *   Table profile action handle (needs to be valid and not in frozen state).
+ * @param[in] type
+ *   Specific table action to be registered for *profile*.
+ * @param[in] action_config
+ *   Configuration for the *type* action.
+ *   If struct rte_table_action_*type*_config is defined by the Table Action
+ *   API, it needs to point to a valid instance of this structure, otherwise it
+ *   needs to be set to NULL.
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_table_action_profile_action_register(struct rte_table_action_profile *profile,
+	enum rte_table_action_type type,
+	void *action_config);
+
+/**
+ * Table action profile freeze.
+ *
+ * Once this function is called successfully, the given profile enters the
+ * frozen state with the following immediate effects: no more actions can be
+ * registered for this profile, so the profile can be instantiated to create
+ * table action objects.
+ *
+ * @param[in] profile
+ *   Table profile action handle (needs to be valid and not in frozen state).
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ *
+ * @see rte_table_action_create()
+ */
+int __rte_experimental
+rte_table_action_profile_freeze(struct rte_table_action_profile *profile);
+
+/**
+ * Table action.
+ */
+struct rte_table_action;
+
+/**
+ * Table action create.
+ *
+ * Instantiates the given table action profile to create a table action object.
+ *
+ * @param[in] profile
+ *   Table profile action handle (needs to be valid and in frozen state).
+ * @param[in] socket_id
+ *   CPU socket ID where the internal data structures required by the new table
+ *   action object should be allocated.
+ * @return
+ *   Handle to table action object on success, NULL on error.
+ *
+ * @see rte_table_action_create()
+ */
+struct rte_table_action * __rte_experimental
+rte_table_action_create(struct rte_table_action_profile *profile,
+	uint32_t socket_id);
+
+/**
+ * Table action free.
+ *
+ * @param[in] action
+ *   Handle to table action object (needs to be valid).
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_table_action_free(struct rte_table_action *action);
+
+/**
+ * Table action apply.
+ *
+ * @param[in] action
+ *   Handle to table action object (needs to be valid).
+ * @param[in] data
+ *   Data byte array (typically table rule data) to apply action *type* on.
+ * @param[in] type
+ *   Specific table action previously registered for the table action profile of
+ *   the *action* object.
+ * @param[in] action_params
+ *   Parameters for the *type* action.
+ *   If struct rte_table_action_*type*_params is defined by the Table Action
+ *   API, it needs to point to a valid instance of this structure, otherwise it
+ *   needs to be set to NULL.
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_table_action_apply(struct rte_table_action *action,
+	void *data,
+	enum rte_table_action_type type,
+	void *action_params);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __INCLUDE_RTE_TABLE_ACTION_H__ */
-- 
2.9.3

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

* [dpdk-dev] [PATCH v4 02/49] pipeline: get pipeline table action params
  2018-03-29 18:31           ` [dpdk-dev] [PATCH v4 00/49] ip_pipeline: refactoring Jasvinder Singh
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 01/49] pipeline: add pipeline table action APIs Jasvinder Singh
@ 2018-03-29 18:31             ` Jasvinder Singh
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 03/49] pipeline: add traffic metering action Jasvinder Singh
                               ` (47 subsequent siblings)
  49 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-29 18:31 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add API to specify action related parameters such as action
handler, table entry data size, etc. for the pipeline table.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 lib/librte_pipeline/rte_pipeline_version.map |   1 +
 lib/librte_pipeline/rte_table_action.c       | 130 +++++++++++++++++++++++++++
 lib/librte_pipeline/rte_table_action.h       |  14 +++
 3 files changed, 145 insertions(+)

diff --git a/lib/librte_pipeline/rte_pipeline_version.map b/lib/librte_pipeline/rte_pipeline_version.map
index 4bc414c..13337de 100644
--- a/lib/librte_pipeline/rte_pipeline_version.map
+++ b/lib/librte_pipeline/rte_pipeline_version.map
@@ -56,5 +56,6 @@ EXPERIMENTAL {
 	rte_table_action_profile_create;
 	rte_table_action_profile_free;
 	rte_table_action_profile_freeze;
+	rte_table_action_table_params_get;
 
 } DPDK_16.04;
diff --git a/lib/librte_pipeline/rte_table_action.c b/lib/librte_pipeline/rte_table_action.c
index f15847c..09f26f5 100644
--- a/lib/librte_pipeline/rte_table_action.c
+++ b/lib/librte_pipeline/rte_table_action.c
@@ -267,6 +267,136 @@ rte_table_action_apply(struct rte_table_action *action,
 	}
 }
 
+static __rte_always_inline uint64_t
+pkt_work(struct rte_mbuf *mbuf __rte_unused,
+	struct rte_pipeline_table_entry *table_entry __rte_unused,
+	uint64_t time __rte_unused,
+	struct rte_table_action *action __rte_unused,
+	struct ap_config *cfg __rte_unused)
+{
+	return 0;
+}
+
+static __rte_always_inline uint64_t
+pkt4_work(struct rte_mbuf **mbufs __rte_unused,
+	struct rte_pipeline_table_entry **table_entries __rte_unused,
+	uint64_t time __rte_unused,
+	struct rte_table_action *action __rte_unused,
+	struct ap_config *cfg __rte_unused)
+{
+	return 0;
+}
+
+static __rte_always_inline int
+ah(struct rte_pipeline *p,
+	struct rte_mbuf **pkts,
+	uint64_t pkts_mask,
+	struct rte_pipeline_table_entry **entries,
+	struct rte_table_action *action,
+	struct ap_config *cfg)
+{
+	uint64_t pkts_drop_mask = 0;
+	uint64_t time = 0;
+
+	if ((pkts_mask & (pkts_mask + 1)) == 0) {
+		uint64_t n_pkts = __builtin_popcountll(pkts_mask);
+		uint32_t i;
+
+		for (i = 0; i < (n_pkts & (~0x3LLU)); i += 4) {
+			uint64_t drop_mask;
+
+			drop_mask = pkt4_work(&pkts[i],
+				&entries[i],
+				time,
+				action,
+				cfg);
+
+			pkts_drop_mask |= drop_mask << i;
+		}
+
+		for ( ; i < n_pkts; i++) {
+			uint64_t drop_mask;
+
+			drop_mask = pkt_work(pkts[i],
+				entries[i],
+				time,
+				action,
+				cfg);
+
+			pkts_drop_mask |= drop_mask << i;
+		}
+	} else
+		for ( ; pkts_mask; ) {
+			uint32_t pos = __builtin_ctzll(pkts_mask);
+			uint64_t pkt_mask = 1LLU << pos;
+			uint64_t drop_mask;
+
+			drop_mask = pkt_work(pkts[pos],
+				entries[pos],
+				time,
+				action,
+				cfg);
+
+			pkts_mask &= ~pkt_mask;
+			pkts_drop_mask |= drop_mask << pos;
+		}
+
+	rte_pipeline_ah_packet_drop(p, pkts_drop_mask);
+
+	return 0;
+}
+
+static int
+ah_default(struct rte_pipeline *p,
+	struct rte_mbuf **pkts,
+	uint64_t pkts_mask,
+	struct rte_pipeline_table_entry **entries,
+	void *arg)
+{
+	struct rte_table_action *action = arg;
+
+	return ah(p,
+		pkts,
+		pkts_mask,
+		entries,
+		action,
+		&action->cfg);
+}
+
+static rte_pipeline_table_action_handler_hit
+ah_selector(struct rte_table_action *action)
+{
+	if (action->cfg.action_mask == (1LLU << RTE_TABLE_ACTION_FWD))
+		return NULL;
+
+	return ah_default;
+}
+
+int
+rte_table_action_table_params_get(struct rte_table_action *action,
+	struct rte_pipeline_table_params *params)
+{
+	rte_pipeline_table_action_handler_hit f_action_hit;
+	uint32_t total_size;
+
+	/* Check input arguments */
+	if ((action == NULL) ||
+		(params == NULL))
+		return -EINVAL;
+
+	f_action_hit = ah_selector(action);
+	total_size = rte_align32pow2(action->data.total_size);
+
+	/* Fill in params */
+	params->f_action_hit = f_action_hit;
+	params->f_action_miss = NULL;
+	params->arg_ah = (f_action_hit) ? action : NULL;
+	params->action_data_size = total_size -
+		sizeof(struct rte_pipeline_table_entry);
+
+	return 0;
+}
+
 int
 rte_table_action_free(struct rte_table_action *action)
 {
diff --git a/lib/librte_pipeline/rte_table_action.h b/lib/librte_pipeline/rte_table_action.h
index da7f12c..03b77ca 100644
--- a/lib/librte_pipeline/rte_table_action.h
+++ b/lib/librte_pipeline/rte_table_action.h
@@ -194,6 +194,20 @@ int __rte_experimental
 rte_table_action_free(struct rte_table_action *action);
 
 /**
+ * Table action table params get.
+ *
+ * @param[in] action
+ *   Handle to table action object (needs to be valid).
+ * @param[inout] params
+ *   Pipeline table parameters (needs to be pre-allocated).
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_table_action_table_params_get(struct rte_table_action *action,
+	struct rte_pipeline_table_params *params);
+
+/**
  * Table action apply.
  *
  * @param[in] action
-- 
2.9.3

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

* [dpdk-dev] [PATCH v4 03/49] pipeline: add traffic metering action
  2018-03-29 18:31           ` [dpdk-dev] [PATCH v4 00/49] ip_pipeline: refactoring Jasvinder Singh
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 01/49] pipeline: add pipeline table action APIs Jasvinder Singh
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 02/49] pipeline: get pipeline table action params Jasvinder Singh
@ 2018-03-29 18:31             ` Jasvinder Singh
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 04/49] pipeline: add traffic manager action Jasvinder Singh
                               ` (46 subsequent siblings)
  49 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-29 18:31 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add traffic metering action implementation.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 lib/librte_pipeline/Makefile                 |   3 +-
 lib/librte_pipeline/meson.build              |   2 +-
 lib/librte_pipeline/rte_pipeline_version.map |   4 +
 lib/librte_pipeline/rte_table_action.c       | 640 ++++++++++++++++++++++++++-
 lib/librte_pipeline/rte_table_action.h       | 248 +++++++++++
 5 files changed, 879 insertions(+), 18 deletions(-)

diff --git a/lib/librte_pipeline/Makefile b/lib/librte_pipeline/Makefile
index e8c43c7..72e4c7c 100644
--- a/lib/librte_pipeline/Makefile
+++ b/lib/librte_pipeline/Makefile
@@ -8,10 +8,11 @@ include $(RTE_SDK)/mk/rte.vars.mk
 #
 LIB = librte_pipeline.a
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
 LDLIBS += -lrte_eal -lrte_mempool -lrte_mbuf -lrte_table
-LDLIBS += -lrte_port
+LDLIBS += -lrte_port -lrte_meter
 
 EXPORT_MAP := rte_pipeline_version.map
 
diff --git a/lib/librte_pipeline/meson.build b/lib/librte_pipeline/meson.build
index 4dda560..71da295 100644
--- a/lib/librte_pipeline/meson.build
+++ b/lib/librte_pipeline/meson.build
@@ -5,4 +5,4 @@ version = 3
 allow_experimental_apis = true
 sources = files('rte_pipeline.c', 'rte_table_action.c')
 headers = files('rte_pipeline.h', 'rte_table_action.h')
-deps += ['port', 'table']
+deps += ['port', 'table', 'meter']
diff --git a/lib/librte_pipeline/rte_pipeline_version.map b/lib/librte_pipeline/rte_pipeline_version.map
index 13337de..c7106dc 100644
--- a/lib/librte_pipeline/rte_pipeline_version.map
+++ b/lib/librte_pipeline/rte_pipeline_version.map
@@ -51,7 +51,11 @@ EXPERIMENTAL {
 
 	rte_table_action_apply;
 	rte_table_action_create;
+	rte_table_action_dscp_table_update;
 	rte_table_action_free;
+	rte_table_action_meter_profile_add;
+	rte_table_action_meter_profile_delete;
+	rte_table_action_meter_read;
 	rte_table_action_profile_action_register;
 	rte_table_action_profile_create;
 	rte_table_action_profile_free;
diff --git a/lib/librte_pipeline/rte_table_action.c b/lib/librte_pipeline/rte_table_action.c
index 09f26f5..f3be28a 100644
--- a/lib/librte_pipeline/rte_table_action.c
+++ b/lib/librte_pipeline/rte_table_action.c
@@ -5,13 +5,21 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include <rte_malloc.h>
-
 #include <rte_common.h>
+#include <rte_byteorder.h>
+#include <rte_cycles.h>
 #include <rte_malloc.h>
+#include <rte_ip.h>
+
 
 #include "rte_table_action.h"
 
+#define rte_htons rte_cpu_to_be_16
+#define rte_htonl rte_cpu_to_be_32
+
+#define rte_ntohs rte_be_to_cpu_16
+#define rte_ntohl rte_be_to_cpu_32
+
 /**
  * RTE_TABLE_ACTION_FWD
  */
@@ -33,6 +41,264 @@ fwd_apply(struct fwd_data *data,
 }
 
 /**
+ * RTE_TABLE_ACTION_MTR
+ */
+static int
+mtr_cfg_check(struct rte_table_action_mtr_config *mtr)
+{
+	if ((mtr->alg == RTE_TABLE_ACTION_METER_SRTCM) ||
+		((mtr->n_tc != 1) && (mtr->n_tc != 4)) ||
+		(mtr->n_bytes_enabled != 0))
+		return -ENOTSUP;
+	return 0;
+}
+
+#define MBUF_SCHED_QUEUE_TC_COLOR(queue, tc, color)        \
+	((uint16_t)((((uint64_t)(queue)) & 0x3) |          \
+	((((uint64_t)(tc)) & 0x3) << 2) |                  \
+	((((uint64_t)(color)) & 0x3) << 4)))
+
+#define MBUF_SCHED_COLOR(sched, color)                     \
+	(((sched) & (~0x30LLU)) | ((color) << 4))
+
+struct mtr_trtcm_data {
+	struct rte_meter_trtcm trtcm;
+	uint64_t stats[e_RTE_METER_COLORS];
+} __attribute__((__packed__));
+
+#define MTR_TRTCM_DATA_METER_PROFILE_ID_GET(data)          \
+	(((data)->stats[e_RTE_METER_GREEN] & 0xF8LLU) >> 3)
+
+static void
+mtr_trtcm_data_meter_profile_id_set(struct mtr_trtcm_data *data,
+	uint32_t profile_id)
+{
+	data->stats[e_RTE_METER_GREEN] &= ~0xF8LLU;
+	data->stats[e_RTE_METER_GREEN] |= (profile_id % 32) << 3;
+}
+
+#define MTR_TRTCM_DATA_POLICER_ACTION_DROP_GET(data, color)\
+	(((data)->stats[(color)] & 4LLU) >> 2)
+
+#define MTR_TRTCM_DATA_POLICER_ACTION_COLOR_GET(data, color)\
+	((enum rte_meter_color)((data)->stats[(color)] & 3LLU))
+
+static void
+mtr_trtcm_data_policer_action_set(struct mtr_trtcm_data *data,
+	enum rte_meter_color color,
+	enum rte_table_action_policer action)
+{
+	if (action == RTE_TABLE_ACTION_POLICER_DROP) {
+		data->stats[color] |= 4LLU;
+	} else {
+		data->stats[color] &= ~7LLU;
+		data->stats[color] |= color & 3LLU;
+	}
+}
+
+static uint64_t
+mtr_trtcm_data_stats_get(struct mtr_trtcm_data *data,
+	enum rte_meter_color color)
+{
+	return data->stats[color] >> 8;
+}
+
+static void
+mtr_trtcm_data_stats_reset(struct mtr_trtcm_data *data,
+	enum rte_meter_color color)
+{
+	data->stats[color] &= 0xFFLU;
+}
+
+#define MTR_TRTCM_DATA_STATS_INC(data, color)              \
+	((data)->stats[(color)] += (1LLU << 8))
+
+static size_t
+mtr_data_size(struct rte_table_action_mtr_config *mtr)
+{
+	return mtr->n_tc * sizeof(struct mtr_trtcm_data);
+}
+
+struct dscp_table_entry_data {
+	enum rte_meter_color color;
+	uint16_t tc;
+	uint16_t queue_tc_color;
+};
+
+struct dscp_table_data {
+	struct dscp_table_entry_data entry[64];
+};
+
+struct meter_profile_data {
+	struct rte_meter_trtcm_profile profile;
+	uint32_t profile_id;
+	int valid;
+};
+
+static struct meter_profile_data *
+meter_profile_data_find(struct meter_profile_data *mp,
+	uint32_t mp_size,
+	uint32_t profile_id)
+{
+	uint32_t i;
+
+	for (i = 0; i < mp_size; i++) {
+		struct meter_profile_data *mp_data = &mp[i];
+
+		if (mp_data->valid && (mp_data->profile_id == profile_id))
+			return mp_data;
+	}
+
+	return NULL;
+}
+
+static struct meter_profile_data *
+meter_profile_data_find_unused(struct meter_profile_data *mp,
+	uint32_t mp_size)
+{
+	uint32_t i;
+
+	for (i = 0; i < mp_size; i++) {
+		struct meter_profile_data *mp_data = &mp[i];
+
+		if (!mp_data->valid)
+			return mp_data;
+	}
+
+	return NULL;
+}
+
+static int
+mtr_apply_check(struct rte_table_action_mtr_params *p,
+	struct rte_table_action_mtr_config *cfg,
+	struct meter_profile_data *mp,
+	uint32_t mp_size)
+{
+	uint32_t i;
+
+	if (p->tc_mask > RTE_LEN2MASK(cfg->n_tc, uint32_t))
+		return -EINVAL;
+
+	for (i = 0; i < RTE_TABLE_ACTION_TC_MAX; i++) {
+		struct rte_table_action_mtr_tc_params *p_tc = &p->mtr[i];
+		struct meter_profile_data *mp_data;
+
+		if ((p->tc_mask & (1LLU << i)) == 0)
+			continue;
+
+		mp_data = meter_profile_data_find(mp,
+			mp_size,
+			p_tc->meter_profile_id);
+		if (!mp_data)
+			return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int
+mtr_apply(struct mtr_trtcm_data *data,
+	struct rte_table_action_mtr_params *p,
+	struct rte_table_action_mtr_config *cfg,
+	struct meter_profile_data *mp,
+	uint32_t mp_size)
+{
+	uint32_t i;
+	int status;
+
+	/* Check input arguments */
+	status = mtr_apply_check(p, cfg, mp, mp_size);
+	if (status)
+		return status;
+
+	/* Apply */
+	for (i = 0; i < RTE_TABLE_ACTION_TC_MAX; i++) {
+		struct rte_table_action_mtr_tc_params *p_tc = &p->mtr[i];
+		struct mtr_trtcm_data *data_tc = &data[i];
+		struct meter_profile_data *mp_data;
+
+		if ((p->tc_mask & (1LLU << i)) == 0)
+			continue;
+
+		/* Find profile */
+		mp_data = meter_profile_data_find(mp,
+			mp_size,
+			p_tc->meter_profile_id);
+		if (!mp_data)
+			return -EINVAL;
+
+		memset(data_tc, 0, sizeof(*data_tc));
+
+		/* Meter object */
+		status = rte_meter_trtcm_config(&data_tc->trtcm,
+			&mp_data->profile);
+		if (status)
+			return status;
+
+		/* Meter profile */
+		mtr_trtcm_data_meter_profile_id_set(data_tc,
+			mp_data - mp);
+
+		/* Policer actions */
+		mtr_trtcm_data_policer_action_set(data_tc,
+			e_RTE_METER_GREEN,
+			p_tc->policer[e_RTE_METER_GREEN]);
+
+		mtr_trtcm_data_policer_action_set(data_tc,
+			e_RTE_METER_YELLOW,
+			p_tc->policer[e_RTE_METER_YELLOW]);
+
+		mtr_trtcm_data_policer_action_set(data_tc,
+			e_RTE_METER_RED,
+			p_tc->policer[e_RTE_METER_RED]);
+	}
+
+	return 0;
+}
+
+static __rte_always_inline uint64_t
+pkt_work_mtr(struct rte_mbuf *mbuf,
+	struct mtr_trtcm_data *data,
+	struct dscp_table_data *dscp_table,
+	struct meter_profile_data *mp,
+	uint64_t time,
+	uint32_t dscp,
+	uint16_t total_length)
+{
+	uint64_t drop_mask, sched;
+	uint64_t *sched_ptr = (uint64_t *) &mbuf->hash.sched;
+	struct dscp_table_entry_data *dscp_entry = &dscp_table->entry[dscp];
+	enum rte_meter_color color_in, color_meter, color_policer;
+	uint32_t tc, mp_id;
+
+	tc = dscp_entry->tc;
+	color_in = dscp_entry->color;
+	data += tc;
+	mp_id = MTR_TRTCM_DATA_METER_PROFILE_ID_GET(data);
+	sched = *sched_ptr;
+
+	/* Meter */
+	color_meter = rte_meter_trtcm_color_aware_check(
+		&data->trtcm,
+		&mp[mp_id].profile,
+		time,
+		total_length,
+		color_in);
+
+	/* Stats */
+	MTR_TRTCM_DATA_STATS_INC(data, color_meter);
+
+	/* Police */
+	drop_mask = MTR_TRTCM_DATA_POLICER_ACTION_DROP_GET(data, color_meter);
+	color_policer =
+		MTR_TRTCM_DATA_POLICER_ACTION_COLOR_GET(data, color_meter);
+	*sched_ptr = MBUF_SCHED_COLOR(sched, color_policer);
+
+	return drop_mask;
+}
+
+
+/**
  * Action profile
  */
 static int
@@ -40,6 +306,7 @@ action_valid(enum rte_table_action_type action)
 {
 	switch (action) {
 	case RTE_TABLE_ACTION_FWD:
+	case RTE_TABLE_ACTION_MTR:
 		return 1;
 	default:
 		return 0;
@@ -52,22 +319,28 @@ action_valid(enum rte_table_action_type action)
 struct ap_config {
 	uint64_t action_mask;
 	struct rte_table_action_common_config common;
+	struct rte_table_action_mtr_config mtr;
 };
 
 static size_t
 action_cfg_size(enum rte_table_action_type action)
 {
 	switch (action) {
+	case RTE_TABLE_ACTION_MTR:
+		return sizeof(struct rte_table_action_mtr_config);
 	default:
 		return 0;
 	}
 }
 
 static void*
-action_cfg_get(struct ap_config *ap_config __rte_unused,
+action_cfg_get(struct ap_config *ap_config,
 	enum rte_table_action_type type)
 {
 	switch (type) {
+	case RTE_TABLE_ACTION_MTR:
+		return &ap_config->mtr;
+
 	default:
 		return NULL;
 	}
@@ -93,12 +366,15 @@ struct ap_data {
 
 static size_t
 action_data_size(enum rte_table_action_type action,
-	struct ap_config *ap_config __rte_unused)
+	struct ap_config *ap_config)
 {
 	switch (action) {
 	case RTE_TABLE_ACTION_FWD:
 		return sizeof(struct fwd_data);
 
+	case RTE_TABLE_ACTION_MTR:
+		return mtr_data_size(&ap_config->mtr);
+
 	default:
 		return 0;
 	}
@@ -158,6 +434,8 @@ rte_table_action_profile_action_register(struct rte_table_action_profile *profil
 	enum rte_table_action_type type,
 	void *action_config)
 {
+	int status;
+
 	/* Check input arguments */
 	if ((profile == NULL) ||
 		profile->frozen ||
@@ -167,6 +445,19 @@ rte_table_action_profile_action_register(struct rte_table_action_profile *profil
 		(action_cfg_size(type) && (action_config == NULL)))
 		return -EINVAL;
 
+	switch (type) {
+	case RTE_TABLE_ACTION_MTR:
+		status = mtr_cfg_check(action_config);
+		break;
+
+	default:
+		status = 0;
+		break;
+	}
+
+	if (status)
+		return status;
+
 	/* Action enable */
 	action_cfg_set(&profile->cfg, type, action_config);
 
@@ -196,9 +487,16 @@ rte_table_action_profile_free(struct rte_table_action_profile *profile)
 	return 0;
 }
 
+/**
+ * Action
+ */
+#define METER_PROFILES_MAX                                 32
+
 struct rte_table_action {
 	struct ap_config cfg;
 	struct ap_data data;
+	struct dscp_table_data dscp_table;
+	struct meter_profile_data mp[METER_PROFILES_MAX];
 };
 
 struct rte_table_action *
@@ -262,31 +560,338 @@ rte_table_action_apply(struct rte_table_action *action,
 		return fwd_apply(action_data,
 			action_params);
 
+	case RTE_TABLE_ACTION_MTR:
+		return mtr_apply(action_data,
+			action_params,
+			&action->cfg.mtr,
+			action->mp,
+			RTE_DIM(action->mp));
+
 	default:
 		return -EINVAL;
 	}
 }
 
-static __rte_always_inline uint64_t
-pkt_work(struct rte_mbuf *mbuf __rte_unused,
-	struct rte_pipeline_table_entry *table_entry __rte_unused,
-	uint64_t time __rte_unused,
-	struct rte_table_action *action __rte_unused,
-	struct ap_config *cfg __rte_unused)
+int
+rte_table_action_dscp_table_update(struct rte_table_action *action,
+	uint64_t dscp_mask,
+	struct rte_table_action_dscp_table *table)
 {
+	uint32_t i;
+
+	/* Check input arguments */
+	if ((action == NULL) ||
+		(action->cfg.action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) ||
+		(dscp_mask == 0) ||
+		(table == NULL))
+		return -EINVAL;
+
+	for (i = 0; i < RTE_DIM(table->entry); i++) {
+		struct dscp_table_entry_data *data =
+			&action->dscp_table.entry[i];
+		struct rte_table_action_dscp_table_entry *entry =
+			&table->entry[i];
+		uint16_t queue_tc_color =
+			MBUF_SCHED_QUEUE_TC_COLOR(entry->tc_queue_id,
+				entry->tc_id,
+				entry->color);
+
+		if ((dscp_mask & (1LLU << i)) == 0)
+			continue;
+
+		data->color = entry->color;
+		data->tc = entry->tc_id;
+		data->queue_tc_color = queue_tc_color;
+	}
+
 	return 0;
 }
 
-static __rte_always_inline uint64_t
-pkt4_work(struct rte_mbuf **mbufs __rte_unused,
-	struct rte_pipeline_table_entry **table_entries __rte_unused,
-	uint64_t time __rte_unused,
-	struct rte_table_action *action __rte_unused,
-	struct ap_config *cfg __rte_unused)
+int
+rte_table_action_meter_profile_add(struct rte_table_action *action,
+	uint32_t meter_profile_id,
+	struct rte_table_action_meter_profile *profile)
 {
+	struct meter_profile_data *mp_data;
+	uint32_t status;
+
+	/* Check input arguments */
+	if ((action == NULL) ||
+		((action->cfg.action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) == 0) ||
+		(profile == NULL))
+		return -EINVAL;
+
+	if (profile->alg != RTE_TABLE_ACTION_METER_TRTCM)
+		return -ENOTSUP;
+
+	mp_data = meter_profile_data_find(action->mp,
+		RTE_DIM(action->mp),
+		meter_profile_id);
+	if (mp_data)
+		return -EEXIST;
+
+	mp_data = meter_profile_data_find_unused(action->mp,
+		RTE_DIM(action->mp));
+	if (!mp_data)
+		return -ENOSPC;
+
+	/* Install new profile */
+	status = rte_meter_trtcm_profile_config(&mp_data->profile,
+		&profile->trtcm);
+	if (status)
+		return status;
+
+	mp_data->profile_id = meter_profile_id;
+	mp_data->valid = 1;
+
 	return 0;
 }
 
+int
+rte_table_action_meter_profile_delete(struct rte_table_action *action,
+	uint32_t meter_profile_id)
+{
+	struct meter_profile_data *mp_data;
+
+	/* Check input arguments */
+	if ((action == NULL) ||
+		((action->cfg.action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) == 0))
+		return -EINVAL;
+
+	mp_data = meter_profile_data_find(action->mp,
+		RTE_DIM(action->mp),
+		meter_profile_id);
+	if (!mp_data)
+		return 0;
+
+	/* Uninstall profile */
+	mp_data->valid = 0;
+
+	return 0;
+}
+
+int
+rte_table_action_meter_read(struct rte_table_action *action,
+	void *data,
+	uint32_t tc_mask,
+	struct rte_table_action_mtr_counters *stats,
+	int clear)
+{
+	struct mtr_trtcm_data *mtr_data;
+	uint32_t i;
+
+	/* Check input arguments */
+	if ((action == NULL) ||
+		((action->cfg.action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) == 0) ||
+		(data == NULL) ||
+		(tc_mask > RTE_LEN2MASK(action->cfg.mtr.n_tc, uint32_t)))
+		return -EINVAL;
+
+	mtr_data = action_data_get(data, action, RTE_TABLE_ACTION_MTR);
+
+	/* Read */
+	if (stats) {
+		for (i = 0; i < RTE_TABLE_ACTION_TC_MAX; i++) {
+			struct rte_table_action_mtr_counters_tc *dst =
+				&stats->stats[i];
+			struct mtr_trtcm_data *src = &mtr_data[i];
+
+			if ((tc_mask & (1 << i)) == 0)
+				continue;
+
+			dst->n_packets[e_RTE_METER_GREEN] =
+				mtr_trtcm_data_stats_get(src, e_RTE_METER_GREEN);
+
+			dst->n_packets[e_RTE_METER_YELLOW] =
+				mtr_trtcm_data_stats_get(src, e_RTE_METER_YELLOW);
+
+			dst->n_packets[e_RTE_METER_RED] =
+				mtr_trtcm_data_stats_get(src, e_RTE_METER_RED);
+
+			dst->n_packets_valid = 1;
+			dst->n_bytes_valid = 0;
+		}
+
+		stats->tc_mask = tc_mask;
+	}
+
+	/* Clear */
+	if (clear)
+		for (i = 0; i < RTE_TABLE_ACTION_TC_MAX; i++) {
+			struct mtr_trtcm_data *src = &mtr_data[i];
+
+			if ((tc_mask & (1 << i)) == 0)
+				continue;
+
+			mtr_trtcm_data_stats_reset(src, e_RTE_METER_GREEN);
+			mtr_trtcm_data_stats_reset(src, e_RTE_METER_YELLOW);
+			mtr_trtcm_data_stats_reset(src, e_RTE_METER_RED);
+		}
+
+
+	return 0;
+}
+
+static __rte_always_inline uint64_t
+pkt_work(struct rte_mbuf *mbuf,
+	struct rte_pipeline_table_entry *table_entry,
+	uint64_t time,
+	struct rte_table_action *action,
+	struct ap_config *cfg)
+{
+	uint64_t drop_mask = 0;
+
+	uint32_t ip_offset = action->cfg.common.ip_offset;
+	void *ip = RTE_MBUF_METADATA_UINT32_PTR(mbuf, ip_offset);
+
+	uint32_t dscp;
+	uint16_t total_length;
+
+	if (cfg->common.ip_version) {
+		struct ipv4_hdr *hdr = ip;
+
+		dscp = hdr->type_of_service >> 2;
+		total_length = rte_ntohs(hdr->total_length);
+	} else {
+		struct ipv6_hdr *hdr = ip;
+
+		dscp = (rte_ntohl(hdr->vtc_flow) & 0x0F600000) >> 18;
+		total_length =
+			rte_ntohs(hdr->payload_len) + sizeof(struct ipv6_hdr);
+	}
+
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) {
+		void *data =
+			action_data_get(table_entry, action, RTE_TABLE_ACTION_MTR);
+
+		drop_mask |= pkt_work_mtr(mbuf,
+			data,
+			&action->dscp_table,
+			action->mp,
+			time,
+			dscp,
+			total_length);
+	}
+
+	return drop_mask;
+}
+
+static __rte_always_inline uint64_t
+pkt4_work(struct rte_mbuf **mbufs,
+	struct rte_pipeline_table_entry **table_entries,
+	uint64_t time,
+	struct rte_table_action *action,
+	struct ap_config *cfg)
+{
+	uint64_t drop_mask0 = 0;
+	uint64_t drop_mask1 = 0;
+	uint64_t drop_mask2 = 0;
+	uint64_t drop_mask3 = 0;
+
+	struct rte_mbuf *mbuf0 = mbufs[0];
+	struct rte_mbuf *mbuf1 = mbufs[1];
+	struct rte_mbuf *mbuf2 = mbufs[2];
+	struct rte_mbuf *mbuf3 = mbufs[3];
+
+	struct rte_pipeline_table_entry *table_entry0 = table_entries[0];
+	struct rte_pipeline_table_entry *table_entry1 = table_entries[1];
+	struct rte_pipeline_table_entry *table_entry2 = table_entries[2];
+	struct rte_pipeline_table_entry *table_entry3 = table_entries[3];
+
+	uint32_t ip_offset = action->cfg.common.ip_offset;
+	void *ip0 = RTE_MBUF_METADATA_UINT32_PTR(mbuf0, ip_offset);
+	void *ip1 = RTE_MBUF_METADATA_UINT32_PTR(mbuf1, ip_offset);
+	void *ip2 = RTE_MBUF_METADATA_UINT32_PTR(mbuf2, ip_offset);
+	void *ip3 = RTE_MBUF_METADATA_UINT32_PTR(mbuf3, ip_offset);
+
+	uint32_t dscp0, dscp1, dscp2, dscp3;
+	uint16_t total_length0, total_length1, total_length2, total_length3;
+
+	if (cfg->common.ip_version) {
+		struct ipv4_hdr *hdr0 = ip0;
+		struct ipv4_hdr *hdr1 = ip1;
+		struct ipv4_hdr *hdr2 = ip2;
+		struct ipv4_hdr *hdr3 = ip3;
+
+		dscp0 = hdr0->type_of_service >> 2;
+		dscp1 = hdr1->type_of_service >> 2;
+		dscp2 = hdr2->type_of_service >> 2;
+		dscp3 = hdr3->type_of_service >> 2;
+
+		total_length0 = rte_ntohs(hdr0->total_length);
+		total_length1 = rte_ntohs(hdr1->total_length);
+		total_length2 = rte_ntohs(hdr2->total_length);
+		total_length3 = rte_ntohs(hdr3->total_length);
+	} else {
+		struct ipv6_hdr *hdr0 = ip0;
+		struct ipv6_hdr *hdr1 = ip1;
+		struct ipv6_hdr *hdr2 = ip2;
+		struct ipv6_hdr *hdr3 = ip3;
+
+		dscp0 = (rte_ntohl(hdr0->vtc_flow) & 0x0F600000) >> 18;
+		dscp1 = (rte_ntohl(hdr1->vtc_flow) & 0x0F600000) >> 18;
+		dscp2 = (rte_ntohl(hdr2->vtc_flow) & 0x0F600000) >> 18;
+		dscp3 = (rte_ntohl(hdr3->vtc_flow) & 0x0F600000) >> 18;
+
+		total_length0 =
+			rte_ntohs(hdr0->payload_len) + sizeof(struct ipv6_hdr);
+		total_length1 =
+			rte_ntohs(hdr1->payload_len) + sizeof(struct ipv6_hdr);
+		total_length2 =
+			rte_ntohs(hdr2->payload_len) + sizeof(struct ipv6_hdr);
+		total_length3 =
+			rte_ntohs(hdr3->payload_len) + sizeof(struct ipv6_hdr);
+	}
+
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) {
+		void *data0 =
+			action_data_get(table_entry0, action, RTE_TABLE_ACTION_MTR);
+		void *data1 =
+			action_data_get(table_entry1, action, RTE_TABLE_ACTION_MTR);
+		void *data2 =
+			action_data_get(table_entry2, action, RTE_TABLE_ACTION_MTR);
+		void *data3 =
+			action_data_get(table_entry3, action, RTE_TABLE_ACTION_MTR);
+
+		drop_mask0 |= pkt_work_mtr(mbuf0,
+			data0,
+			&action->dscp_table,
+			action->mp,
+			time,
+			dscp0,
+			total_length0);
+
+		drop_mask1 |= pkt_work_mtr(mbuf1,
+			data1,
+			&action->dscp_table,
+			action->mp,
+			time,
+			dscp1,
+			total_length1);
+
+		drop_mask2 |= pkt_work_mtr(mbuf2,
+			data2,
+			&action->dscp_table,
+			action->mp,
+			time,
+			dscp2,
+			total_length2);
+
+		drop_mask3 |= pkt_work_mtr(mbuf3,
+			data3,
+			&action->dscp_table,
+			action->mp,
+			time,
+			dscp3,
+			total_length3);
+	}
+
+	return drop_mask0 |
+		(drop_mask1 << 1) |
+		(drop_mask2 << 2) |
+		(drop_mask3 << 3);
+}
+
 static __rte_always_inline int
 ah(struct rte_pipeline *p,
 	struct rte_mbuf **pkts,
@@ -298,6 +903,9 @@ ah(struct rte_pipeline *p,
 	uint64_t pkts_drop_mask = 0;
 	uint64_t time = 0;
 
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_MTR))
+		time = rte_rdtsc();
+
 	if ((pkts_mask & (pkts_mask + 1)) == 0) {
 		uint64_t n_pkts = __builtin_popcountll(pkts_mask);
 		uint32_t i;
diff --git a/lib/librte_pipeline/rte_table_action.h b/lib/librte_pipeline/rte_table_action.h
index 03b77ca..c2f4a55 100644
--- a/lib/librte_pipeline/rte_table_action.h
+++ b/lib/librte_pipeline/rte_table_action.h
@@ -59,6 +59,7 @@ extern "C" {
 #include <stdint.h>
 
 #include <rte_compat.h>
+#include <rte_meter.h>
 
 #include "rte_pipeline.h"
 
@@ -66,6 +67,9 @@ extern "C" {
 enum rte_table_action_type {
 	/** Forward to next pipeline table, output port or drop. */
 	RTE_TABLE_ACTION_FWD = 0,
+
+	/**  Traffic Metering and Policing. */
+	RTE_TABLE_ACTION_MTR,
 };
 
 /** Common action configuration (per table action profile). */
@@ -94,6 +98,164 @@ struct rte_table_action_fwd_params {
 };
 
 /**
+ * RTE_TABLE_ACTION_MTR
+ */
+/** Max number of traffic classes (TCs). */
+#define RTE_TABLE_ACTION_TC_MAX                                  4
+
+/** Max number of queues per traffic class. */
+#define RTE_TABLE_ACTION_TC_QUEUE_MAX                            4
+
+/** Differentiated Services Code Point (DSCP) translation table entry. */
+struct rte_table_action_dscp_table_entry {
+	/** Traffic class. Used by the meter or the traffic management actions.
+	 * Has to be strictly smaller than *RTE_TABLE_ACTION_TC_MAX*. Traffic
+	 * class 0 is the highest priority.
+	 */
+	uint32_t tc_id;
+
+	/** Traffic class queue. Used by the traffic management action. Has to
+	 * be strictly smaller than *RTE_TABLE_ACTION_TC_QUEUE_MAX*.
+	 */
+	uint32_t tc_queue_id;
+
+	/** Packet color. Used by the meter action as the packet input color
+	 * for the color aware mode of the traffic metering algorithm.
+	 */
+	enum rte_meter_color color;
+};
+
+/** DSCP translation table. */
+struct rte_table_action_dscp_table {
+	/** Array of DSCP table entries */
+	struct rte_table_action_dscp_table_entry entry[64];
+};
+
+/** Supported traffic metering algorithms. */
+enum rte_table_action_meter_algorithm {
+	/** Single Rate Three Color Marker (srTCM) - IETF RFC 2697. */
+	RTE_TABLE_ACTION_METER_SRTCM,
+
+	/** Two Rate Three Color Marker (trTCM) - IETF RFC 2698. */
+	RTE_TABLE_ACTION_METER_TRTCM,
+};
+
+/** Traffic metering profile (configuration template). */
+struct rte_table_action_meter_profile {
+	/** Traffic metering algorithm. */
+	enum rte_table_action_meter_algorithm alg;
+
+	RTE_STD_C11
+	union {
+		/** Only valid when *alg* is set to srTCM - IETF RFC 2697. */
+		struct rte_meter_srtcm_params srtcm;
+
+		/** Only valid when *alg* is set to trTCM - IETF RFC 2698. */
+		struct rte_meter_trtcm_params trtcm;
+	};
+};
+
+/** Policer actions. */
+enum rte_table_action_policer {
+	/** Recolor the packet as green. */
+	RTE_TABLE_ACTION_POLICER_COLOR_GREEN = 0,
+
+	/** Recolor the packet as yellow. */
+	RTE_TABLE_ACTION_POLICER_COLOR_YELLOW,
+
+	/** Recolor the packet as red. */
+	RTE_TABLE_ACTION_POLICER_COLOR_RED,
+
+	/** Drop the packet. */
+	RTE_TABLE_ACTION_POLICER_DROP,
+
+	/** Number of policer actions. */
+	RTE_TABLE_ACTION_POLICER_MAX
+};
+
+/** Meter action configuration per traffic class. */
+struct rte_table_action_mtr_tc_params {
+	/** Meter profile ID. */
+	uint32_t meter_profile_id;
+
+	/** Policer actions. */
+	enum rte_table_action_policer policer[e_RTE_METER_COLORS];
+};
+
+/** Meter action statistics counters per traffic class. */
+struct rte_table_action_mtr_counters_tc {
+	/** Number of packets per color at the output of the traffic metering
+	 * and before the policer actions are executed. Only valid when
+	 * *n_packets_valid* is non-zero.
+	 */
+	uint64_t n_packets[e_RTE_METER_COLORS];
+
+	/** Number of packet bytes per color at the output of the traffic
+	 * metering and before the policer actions are executed. Only valid when
+	 * *n_bytes_valid* is non-zero.
+	 */
+	uint64_t n_bytes[e_RTE_METER_COLORS];
+
+	/** When non-zero, the *n_packets* field is valid. */
+	int n_packets_valid;
+
+	/** When non-zero, the *n_bytes* field is valid. */
+	int n_bytes_valid;
+};
+
+/** Meter action configuration (per table action profile). */
+struct rte_table_action_mtr_config {
+	/** Meter algorithm. */
+	enum rte_table_action_meter_algorithm alg;
+
+	/** Number of traffic classes. Each traffic class has its own traffic
+	 * meter and policer instances. Needs to be equal to either 1 or to
+	 * *RTE_TABLE_ACTION_TC_MAX*.
+	 */
+	uint32_t n_tc;
+
+	/** When non-zero, the *n_packets* meter stats counter is enabled,
+	 * otherwise it is disabled.
+	 *
+	 * @see struct rte_table_action_mtr_counters_tc
+	 */
+	int n_packets_enabled;
+
+	/** When non-zero, the *n_bytes* meter stats counter is enabled,
+	 * otherwise it is disabled.
+	 *
+	 * @see struct rte_table_action_mtr_counters_tc
+	 */
+	int n_bytes_enabled;
+};
+
+/** Meter action parameters (per table rule). */
+struct rte_table_action_mtr_params {
+	/** Traffic meter and policer parameters for each of the *tc_mask*
+	 * traffic classes.
+	 */
+	struct rte_table_action_mtr_tc_params mtr[RTE_TABLE_ACTION_TC_MAX];
+
+	/** Bit mask defining which traffic class parameters are valid in *mtr*.
+	 * If bit N is set in *tc_mask*, then parameters for traffic class N are
+	 * valid in *mtr*.
+	 */
+	uint32_t tc_mask;
+};
+
+/** Meter action statistics counters (per table rule). */
+struct rte_table_action_mtr_counters {
+	/** Stats counters for each of the *tc_mask* traffic classes. */
+	struct rte_table_action_mtr_counters_tc stats[RTE_TABLE_ACTION_TC_MAX];
+
+	/** Bit mask defining which traffic class parameters are valid in *mtr*.
+	 * If bit N is set in *tc_mask*, then parameters for traffic class N are
+	 * valid in *mtr*.
+	 */
+	uint32_t tc_mask;
+};
+
+/**
  * Table action profile.
  */
 struct rte_table_action_profile;
@@ -231,6 +393,92 @@ rte_table_action_apply(struct rte_table_action *action,
 	enum rte_table_action_type type,
 	void *action_params);
 
+/**
+ * Table action DSCP table update.
+ *
+ * @param[in] action
+ *   Handle to table action object (needs to be valid).
+ * @param[in] dscp_mask
+ *   64-bit mask defining the DSCP table entries to be updated. If bit N is set
+ *   in this bit mask, then DSCP table entry N is to be updated, otherwise not.
+ * @param[in] table
+ *   DSCP table.
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_table_action_dscp_table_update(struct rte_table_action *action,
+	uint64_t dscp_mask,
+	struct rte_table_action_dscp_table *table);
+
+/**
+ * Table action meter profile add.
+ *
+ * @param[in] action
+ *   Handle to table action object (needs to be valid).
+ * @param[in] meter_profile_id
+ *   Meter profile ID to be used for the *profile* once it is successfully added
+ *   to the *action* object (needs to be unused by the set of meter profiles
+ *   currently registered for the *action* object).
+ * @param[in] profile
+ *   Meter profile to be added.
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_table_action_meter_profile_add(struct rte_table_action *action,
+	uint32_t meter_profile_id,
+	struct rte_table_action_meter_profile *profile);
+
+/**
+ * Table action meter profile delete.
+ *
+ * @param[in] action
+ *   Handle to table action object (needs to be valid).
+ * @param[in] meter_profile_id
+ *   Meter profile ID of the meter profile to be deleted from the *action*
+ *   object (needs to be valid for the *action* object).
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_table_action_meter_profile_delete(struct rte_table_action *action,
+	uint32_t meter_profile_id);
+
+/**
+ * Table action meter read.
+ *
+ * @param[in] action
+ *   Handle to table action object (needs to be valid).
+ * @param[in] data
+ *   Data byte array (typically table rule data) with meter action previously
+ *   applied on it.
+ * @param[in] tc_mask
+ *   Bit mask defining which traffic classes should have the meter stats
+ *   counters read from *data* and stored into *stats*. If bit N is set in this
+ *   bit mask, then traffic class N is part of this operation, otherwise it is
+ *   not. If bit N is set in this bit mask, then traffic class N must be one of
+ *   the traffic classes that are enabled for the meter action in the table
+ *   action profile used by the *action* object.
+ * @param[inout] stats
+ *   When non-NULL, it points to the area where the meter stats counters read
+ *   from *data* are saved. Only the meter stats counters for the *tc_mask*
+ *   traffic classes are read and stored to *stats*.
+ * @param[in] clear
+ *   When non-zero, the meter stats counters are cleared (i.e. set to zero),
+ *   otherwise the counters are not modified. When the read operation is enabled
+ *   (*stats* is non-NULL), the clear operation is performed after the read
+ *   operation is completed.
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_table_action_meter_read(struct rte_table_action *action,
+	void *data,
+	uint32_t tc_mask,
+	struct rte_table_action_mtr_counters *stats,
+	int clear);
+
 #ifdef __cplusplus
 }
 #endif
-- 
2.9.3

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

* [dpdk-dev] [PATCH v4 04/49] pipeline: add traffic manager action
  2018-03-29 18:31           ` [dpdk-dev] [PATCH v4 00/49] ip_pipeline: refactoring Jasvinder Singh
                               ` (2 preceding siblings ...)
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 03/49] pipeline: add traffic metering action Jasvinder Singh
@ 2018-03-29 18:31             ` Jasvinder Singh
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 05/49] pipeline: add packet encapsulation action Jasvinder Singh
                               ` (45 subsequent siblings)
  49 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-29 18:31 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add implementation of traffic manager action.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 lib/librte_pipeline/Makefile           |   2 +-
 lib/librte_pipeline/meson.build        |   2 +-
 lib/librte_pipeline/rte_table_action.c | 130 ++++++++++++++++++++++++++++++++-
 lib/librte_pipeline/rte_table_action.h |  24 ++++++
 4 files changed, 155 insertions(+), 3 deletions(-)

diff --git a/lib/librte_pipeline/Makefile b/lib/librte_pipeline/Makefile
index 72e4c7c..c0eaa09 100644
--- a/lib/librte_pipeline/Makefile
+++ b/lib/librte_pipeline/Makefile
@@ -12,7 +12,7 @@ CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
 LDLIBS += -lrte_eal -lrte_mempool -lrte_mbuf -lrte_table
-LDLIBS += -lrte_port -lrte_meter
+LDLIBS += -lrte_port -lrte_meter -lrte_sched
 
 EXPORT_MAP := rte_pipeline_version.map
 
diff --git a/lib/librte_pipeline/meson.build b/lib/librte_pipeline/meson.build
index 71da295..1ee276f 100644
--- a/lib/librte_pipeline/meson.build
+++ b/lib/librte_pipeline/meson.build
@@ -5,4 +5,4 @@ version = 3
 allow_experimental_apis = true
 sources = files('rte_pipeline.c', 'rte_table_action.c')
 headers = files('rte_pipeline.h', 'rte_table_action.h')
-deps += ['port', 'table', 'meter']
+deps += ['port', 'table', 'meter', 'sched']
diff --git a/lib/librte_pipeline/rte_table_action.c b/lib/librte_pipeline/rte_table_action.c
index f3be28a..791fc20 100644
--- a/lib/librte_pipeline/rte_table_action.c
+++ b/lib/librte_pipeline/rte_table_action.c
@@ -297,6 +297,73 @@ pkt_work_mtr(struct rte_mbuf *mbuf,
 	return drop_mask;
 }
 
+/**
+ * RTE_TABLE_ACTION_TM
+ */
+static int
+tm_cfg_check(struct rte_table_action_tm_config *tm)
+{
+	if ((tm->n_subports_per_port == 0) ||
+		(rte_is_power_of_2(tm->n_subports_per_port) == 0) ||
+		(tm->n_subports_per_port > UINT16_MAX) ||
+		(tm->n_pipes_per_subport == 0) ||
+		(rte_is_power_of_2(tm->n_pipes_per_subport) == 0))
+		return -ENOTSUP;
+
+	return 0;
+}
+
+struct tm_data {
+	uint16_t queue_tc_color;
+	uint16_t subport;
+	uint32_t pipe;
+} __attribute__((__packed__));
+
+static int
+tm_apply_check(struct rte_table_action_tm_params *p,
+	struct rte_table_action_tm_config *cfg)
+{
+	if ((p->subport_id >= cfg->n_subports_per_port) ||
+		(p->pipe_id >= cfg->n_pipes_per_subport))
+		return -EINVAL;
+
+	return 0;
+}
+
+static int
+tm_apply(struct tm_data *data,
+	struct rte_table_action_tm_params *p,
+	struct rte_table_action_tm_config *cfg)
+{
+	int status;
+
+	/* Check input arguments */
+	status = tm_apply_check(p, cfg);
+	if (status)
+		return status;
+
+	/* Apply */
+	data->queue_tc_color = 0;
+	data->subport = (uint16_t) p->subport_id;
+	data->pipe = p->pipe_id;
+
+	return 0;
+}
+
+static __rte_always_inline void
+pkt_work_tm(struct rte_mbuf *mbuf,
+	struct tm_data *data,
+	struct dscp_table_data *dscp_table,
+	uint32_t dscp)
+{
+	struct dscp_table_entry_data *dscp_entry = &dscp_table->entry[dscp];
+	struct tm_data *sched_ptr = (struct tm_data *) &mbuf->hash.sched;
+	struct tm_data sched;
+
+	sched = *data;
+	sched.queue_tc_color = dscp_entry->queue_tc_color;
+	*sched_ptr = sched;
+}
 
 /**
  * Action profile
@@ -307,6 +374,7 @@ action_valid(enum rte_table_action_type action)
 	switch (action) {
 	case RTE_TABLE_ACTION_FWD:
 	case RTE_TABLE_ACTION_MTR:
+	case RTE_TABLE_ACTION_TM:
 		return 1;
 	default:
 		return 0;
@@ -320,6 +388,7 @@ struct ap_config {
 	uint64_t action_mask;
 	struct rte_table_action_common_config common;
 	struct rte_table_action_mtr_config mtr;
+	struct rte_table_action_tm_config tm;
 };
 
 static size_t
@@ -328,6 +397,8 @@ action_cfg_size(enum rte_table_action_type action)
 	switch (action) {
 	case RTE_TABLE_ACTION_MTR:
 		return sizeof(struct rte_table_action_mtr_config);
+	case RTE_TABLE_ACTION_TM:
+		return sizeof(struct rte_table_action_tm_config);
 	default:
 		return 0;
 	}
@@ -341,6 +412,9 @@ action_cfg_get(struct ap_config *ap_config,
 	case RTE_TABLE_ACTION_MTR:
 		return &ap_config->mtr;
 
+	case RTE_TABLE_ACTION_TM:
+		return &ap_config->tm;
+
 	default:
 		return NULL;
 	}
@@ -375,6 +449,9 @@ action_data_size(enum rte_table_action_type action,
 	case RTE_TABLE_ACTION_MTR:
 		return mtr_data_size(&ap_config->mtr);
 
+	case RTE_TABLE_ACTION_TM:
+		return sizeof(struct tm_data);
+
 	default:
 		return 0;
 	}
@@ -450,6 +527,10 @@ rte_table_action_profile_action_register(struct rte_table_action_profile *profil
 		status = mtr_cfg_check(action_config);
 		break;
 
+	case RTE_TABLE_ACTION_TM:
+		status = tm_cfg_check(action_config);
+		break;
+
 	default:
 		status = 0;
 		break;
@@ -567,6 +648,11 @@ rte_table_action_apply(struct rte_table_action *action,
 			action->mp,
 			RTE_DIM(action->mp));
 
+	case RTE_TABLE_ACTION_TM:
+		return tm_apply(action_data,
+			action_params,
+			&action->cfg.tm);
+
 	default:
 		return -EINVAL;
 	}
@@ -581,7 +667,8 @@ rte_table_action_dscp_table_update(struct rte_table_action *action,
 
 	/* Check input arguments */
 	if ((action == NULL) ||
-		(action->cfg.action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) ||
+		((action->cfg.action_mask & ((1LLU << RTE_TABLE_ACTION_MTR) |
+		(1LLU << RTE_TABLE_ACTION_TM))) == 0) ||
 		(dscp_mask == 0) ||
 		(table == NULL))
 		return -EINVAL;
@@ -773,6 +860,16 @@ pkt_work(struct rte_mbuf *mbuf,
 			total_length);
 	}
 
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_TM)) {
+		void *data =
+			action_data_get(table_entry, action, RTE_TABLE_ACTION_TM);
+
+		pkt_work_tm(mbuf,
+			data,
+			&action->dscp_table,
+			dscp);
+	}
+
 	return drop_mask;
 }
 
@@ -886,6 +983,37 @@ pkt4_work(struct rte_mbuf **mbufs,
 			total_length3);
 	}
 
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_TM)) {
+		void *data0 =
+			action_data_get(table_entry0, action, RTE_TABLE_ACTION_TM);
+		void *data1 =
+			action_data_get(table_entry1, action, RTE_TABLE_ACTION_TM);
+		void *data2 =
+			action_data_get(table_entry2, action, RTE_TABLE_ACTION_TM);
+		void *data3 =
+			action_data_get(table_entry3, action, RTE_TABLE_ACTION_TM);
+
+		pkt_work_tm(mbuf0,
+			data0,
+			&action->dscp_table,
+			dscp0);
+
+		pkt_work_tm(mbuf1,
+			data1,
+			&action->dscp_table,
+			dscp1);
+
+		pkt_work_tm(mbuf2,
+			data2,
+			&action->dscp_table,
+			dscp2);
+
+		pkt_work_tm(mbuf3,
+			data3,
+			&action->dscp_table,
+			dscp3);
+	}
+
 	return drop_mask0 |
 		(drop_mask1 << 1) |
 		(drop_mask2 << 2) |
diff --git a/lib/librte_pipeline/rte_table_action.h b/lib/librte_pipeline/rte_table_action.h
index c2f4a55..98babc5 100644
--- a/lib/librte_pipeline/rte_table_action.h
+++ b/lib/librte_pipeline/rte_table_action.h
@@ -70,6 +70,9 @@ enum rte_table_action_type {
 
 	/**  Traffic Metering and Policing. */
 	RTE_TABLE_ACTION_MTR,
+
+	/**  Traffic Management. */
+	RTE_TABLE_ACTION_TM,
 };
 
 /** Common action configuration (per table action profile). */
@@ -256,6 +259,27 @@ struct rte_table_action_mtr_counters {
 };
 
 /**
+ * RTE_TABLE_ACTION_TM
+ */
+/** Traffic management action configuration (per table action profile). */
+struct rte_table_action_tm_config {
+	/** Number of subports per port. */
+	uint32_t n_subports_per_port;
+
+	/** Number of pipes per subport. */
+	uint32_t n_pipes_per_subport;
+};
+
+/** Traffic management action parameters (per table rule). */
+struct rte_table_action_tm_params {
+	/** Subport ID. */
+	uint32_t subport_id;
+
+	/** Pipe ID. */
+	uint32_t pipe_id;
+};
+
+/**
  * Table action profile.
  */
 struct rte_table_action_profile;
-- 
2.9.3

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

* [dpdk-dev] [PATCH v4 05/49] pipeline: add packet encapsulation action
  2018-03-29 18:31           ` [dpdk-dev] [PATCH v4 00/49] ip_pipeline: refactoring Jasvinder Singh
                               ` (3 preceding siblings ...)
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 04/49] pipeline: add traffic manager action Jasvinder Singh
@ 2018-03-29 18:31             ` Jasvinder Singh
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 06/49] pipeline: add nat action Jasvinder Singh
                               ` (44 subsequent siblings)
  49 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-29 18:31 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add implementation of different type of packet encap
such as vlan, qinq, mpls, pppoe, etc.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 lib/librte_pipeline/rte_table_action.c | 440 ++++++++++++++++++++++++++++++++-
 lib/librte_pipeline/rte_table_action.h | 129 ++++++++++
 2 files changed, 568 insertions(+), 1 deletion(-)

diff --git a/lib/librte_pipeline/rte_table_action.c b/lib/librte_pipeline/rte_table_action.c
index 791fc20..fa528d8 100644
--- a/lib/librte_pipeline/rte_table_action.c
+++ b/lib/librte_pipeline/rte_table_action.c
@@ -9,8 +9,12 @@
 #include <rte_byteorder.h>
 #include <rte_cycles.h>
 #include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_ether.h>
 #include <rte_ip.h>
-
+#include <rte_esp.h>
+#include <rte_tcp.h>
+#include <rte_udp.h>
 
 #include "rte_table_action.h"
 
@@ -366,6 +370,369 @@ pkt_work_tm(struct rte_mbuf *mbuf,
 }
 
 /**
+ * RTE_TABLE_ACTION_ENCAP
+ */
+static int
+encap_valid(enum rte_table_action_encap_type encap)
+{
+	switch (encap) {
+	case RTE_TABLE_ACTION_ENCAP_ETHER:
+	case RTE_TABLE_ACTION_ENCAP_VLAN:
+	case RTE_TABLE_ACTION_ENCAP_QINQ:
+	case RTE_TABLE_ACTION_ENCAP_MPLS:
+	case RTE_TABLE_ACTION_ENCAP_PPPOE:
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+static int
+encap_cfg_check(struct rte_table_action_encap_config *encap)
+{
+	if ((encap->encap_mask == 0) ||
+		(__builtin_popcountll(encap->encap_mask) != 1))
+		return -ENOTSUP;
+
+	return 0;
+}
+
+struct encap_ether_data {
+	struct ether_hdr ether;
+} __attribute__((__packed__));
+
+#define VLAN(pcp, dei, vid)                                \
+	((uint16_t)((((uint64_t)(pcp)) & 0x7LLU) << 13) |  \
+	((((uint64_t)(dei)) & 0x1LLU) << 12) |             \
+	(((uint64_t)(vid)) & 0xFFFLLU))                    \
+
+struct encap_vlan_data {
+	struct ether_hdr ether;
+	struct vlan_hdr vlan;
+} __attribute__((__packed__));
+
+struct encap_qinq_data {
+	struct ether_hdr ether;
+	struct vlan_hdr svlan;
+	struct vlan_hdr cvlan;
+} __attribute__((__packed__));
+
+#define ETHER_TYPE_MPLS_UNICAST                            0x8847
+
+#define ETHER_TYPE_MPLS_MULTICAST                          0x8848
+
+#define MPLS(label, tc, s, ttl)                            \
+	((uint32_t)(((((uint64_t)(label)) & 0xFFFFFLLU) << 12) |\
+	((((uint64_t)(tc)) & 0x7LLU) << 9) |               \
+	((((uint64_t)(s)) & 0x1LLU) << 8) |                \
+	(((uint64_t)(ttl)) & 0xFFLLU)))
+
+struct encap_mpls_data {
+	struct ether_hdr ether;
+	uint32_t mpls[RTE_TABLE_ACTION_MPLS_LABELS_MAX];
+	uint32_t mpls_count;
+} __attribute__((__packed__));
+
+#define ETHER_TYPE_PPPOE_SESSION                           0x8864
+
+#define PPP_PROTOCOL_IP                                    0x0021
+
+struct pppoe_ppp_hdr {
+	uint16_t ver_type_code;
+	uint16_t session_id;
+	uint16_t length;
+	uint16_t protocol;
+} __attribute__((__packed__));
+
+struct encap_pppoe_data {
+	struct ether_hdr ether;
+	struct pppoe_ppp_hdr pppoe_ppp;
+} __attribute__((__packed__));
+
+static size_t
+encap_data_size(struct rte_table_action_encap_config *encap)
+{
+	switch (encap->encap_mask) {
+	case 1LLU << RTE_TABLE_ACTION_ENCAP_ETHER:
+		return sizeof(struct encap_ether_data);
+
+	case 1LLU << RTE_TABLE_ACTION_ENCAP_VLAN:
+		return sizeof(struct encap_vlan_data);
+
+	case 1LLU << RTE_TABLE_ACTION_ENCAP_QINQ:
+		return sizeof(struct encap_qinq_data);
+
+	case 1LLU << RTE_TABLE_ACTION_ENCAP_MPLS:
+		return sizeof(struct encap_mpls_data);
+
+	case 1LLU << RTE_TABLE_ACTION_ENCAP_PPPOE:
+		return sizeof(struct encap_pppoe_data);
+
+	default:
+		return 0;
+	}
+}
+
+static int
+encap_apply_check(struct rte_table_action_encap_params *p,
+	struct rte_table_action_encap_config *cfg)
+{
+	if ((encap_valid(p->type) == 0) ||
+		((cfg->encap_mask & (1LLU << p->type)) == 0))
+		return -EINVAL;
+
+	switch (p->type) {
+	case RTE_TABLE_ACTION_ENCAP_ETHER:
+		return 0;
+
+	case RTE_TABLE_ACTION_ENCAP_VLAN:
+		return 0;
+
+	case RTE_TABLE_ACTION_ENCAP_QINQ:
+		return 0;
+
+	case RTE_TABLE_ACTION_ENCAP_MPLS:
+		if ((p->mpls.mpls_count == 0) ||
+			(p->mpls.mpls_count > RTE_TABLE_ACTION_MPLS_LABELS_MAX))
+			return -EINVAL;
+
+		return 0;
+
+	case RTE_TABLE_ACTION_ENCAP_PPPOE:
+		return 0;
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static int
+encap_ether_apply(void *data,
+	struct rte_table_action_encap_params *p,
+	struct rte_table_action_common_config *common_cfg)
+{
+	struct encap_ether_data *d = data;
+	uint16_t ethertype = (common_cfg->ip_version) ?
+		ETHER_TYPE_IPv4 :
+		ETHER_TYPE_IPv6;
+
+	/* Ethernet */
+	ether_addr_copy(&p->ether.ether.da, &d->ether.d_addr);
+	ether_addr_copy(&p->ether.ether.sa, &d->ether.s_addr);
+	d->ether.ether_type = rte_htons(ethertype);
+
+	return 0;
+}
+
+static int
+encap_vlan_apply(void *data,
+	struct rte_table_action_encap_params *p,
+	struct rte_table_action_common_config *common_cfg)
+{
+	struct encap_vlan_data *d = data;
+	uint16_t ethertype = (common_cfg->ip_version) ?
+		ETHER_TYPE_IPv4 :
+		ETHER_TYPE_IPv6;
+
+	/* Ethernet */
+	ether_addr_copy(&p->vlan.ether.da, &d->ether.d_addr);
+	ether_addr_copy(&p->vlan.ether.sa, &d->ether.s_addr);
+	d->ether.ether_type = rte_htons(ETHER_TYPE_VLAN);
+
+	/* VLAN */
+	d->vlan.vlan_tci = rte_htons(VLAN(p->vlan.vlan.pcp,
+		p->vlan.vlan.dei,
+		p->vlan.vlan.vid));
+	d->vlan.eth_proto = rte_htons(ethertype);
+
+	return 0;
+}
+
+static int
+encap_qinq_apply(void *data,
+	struct rte_table_action_encap_params *p,
+	struct rte_table_action_common_config *common_cfg)
+{
+	struct encap_qinq_data *d = data;
+	uint16_t ethertype = (common_cfg->ip_version) ?
+		ETHER_TYPE_IPv4 :
+		ETHER_TYPE_IPv6;
+
+	/* Ethernet */
+	ether_addr_copy(&p->qinq.ether.da, &d->ether.d_addr);
+	ether_addr_copy(&p->qinq.ether.sa, &d->ether.s_addr);
+	d->ether.ether_type = rte_htons(ETHER_TYPE_QINQ);
+
+	/* SVLAN */
+	d->svlan.vlan_tci = rte_htons(VLAN(p->qinq.svlan.pcp,
+		p->qinq.svlan.dei,
+		p->qinq.svlan.vid));
+	d->svlan.eth_proto = rte_htons(ETHER_TYPE_VLAN);
+
+	/* CVLAN */
+	d->cvlan.vlan_tci = rte_htons(VLAN(p->qinq.cvlan.pcp,
+		p->qinq.cvlan.dei,
+		p->qinq.cvlan.vid));
+	d->cvlan.eth_proto = rte_htons(ethertype);
+
+	return 0;
+}
+
+static int
+encap_mpls_apply(void *data,
+	struct rte_table_action_encap_params *p)
+{
+	struct encap_mpls_data *d = data;
+	uint16_t ethertype = (p->mpls.unicast) ?
+		ETHER_TYPE_MPLS_UNICAST :
+		ETHER_TYPE_MPLS_MULTICAST;
+	uint32_t i;
+
+	/* Ethernet */
+	ether_addr_copy(&p->mpls.ether.da, &d->ether.d_addr);
+	ether_addr_copy(&p->mpls.ether.sa, &d->ether.s_addr);
+	d->ether.ether_type = rte_htons(ethertype);
+
+	/* MPLS */
+	for (i = 0; i < p->mpls.mpls_count - 1; i++)
+		d->mpls[i] = rte_htonl(MPLS(p->mpls.mpls[i].label,
+			p->mpls.mpls[i].tc,
+			0,
+			p->mpls.mpls[i].ttl));
+
+	d->mpls[i] = rte_htonl(MPLS(p->mpls.mpls[i].label,
+		p->mpls.mpls[i].tc,
+		1,
+		p->mpls.mpls[i].ttl));
+
+	d->mpls_count = p->mpls.mpls_count;
+	return 0;
+}
+
+static int
+encap_pppoe_apply(void *data,
+	struct rte_table_action_encap_params *p)
+{
+	struct encap_pppoe_data *d = data;
+
+	/* Ethernet */
+	ether_addr_copy(&p->pppoe.ether.da, &d->ether.d_addr);
+	ether_addr_copy(&p->pppoe.ether.sa, &d->ether.s_addr);
+	d->ether.ether_type = rte_htons(ETHER_TYPE_PPPOE_SESSION);
+
+	/* PPPoE and PPP*/
+	d->pppoe_ppp.ver_type_code = rte_htons(0x1100);
+	d->pppoe_ppp.session_id = rte_htons(p->pppoe.pppoe.session_id);
+	d->pppoe_ppp.length = 0; /* not pre-computed */
+	d->pppoe_ppp.protocol = rte_htons(PPP_PROTOCOL_IP);
+
+	return 0;
+}
+
+static int
+encap_apply(void *data,
+	struct rte_table_action_encap_params *p,
+	struct rte_table_action_encap_config *cfg,
+	struct rte_table_action_common_config *common_cfg)
+{
+	int status;
+
+	/* Check input arguments */
+	status = encap_apply_check(p, cfg);
+	if (status)
+		return status;
+
+	switch (p->type) {
+	case RTE_TABLE_ACTION_ENCAP_ETHER:
+		return encap_ether_apply(data, p, common_cfg);
+
+	case RTE_TABLE_ACTION_ENCAP_VLAN:
+		return encap_vlan_apply(data, p, common_cfg);
+
+	case RTE_TABLE_ACTION_ENCAP_QINQ:
+		return encap_qinq_apply(data, p, common_cfg);
+
+	case RTE_TABLE_ACTION_ENCAP_MPLS:
+		return encap_mpls_apply(data, p);
+
+	case RTE_TABLE_ACTION_ENCAP_PPPOE:
+		return encap_pppoe_apply(data, p);
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static __rte_always_inline void *
+encap(void *dst, const void *src, size_t n)
+{
+	dst = ((uint8_t *) dst) - n;
+	return rte_memcpy(dst, src, n);
+}
+
+static __rte_always_inline void
+pkt_work_encap(struct rte_mbuf *mbuf,
+	void *data,
+	struct rte_table_action_encap_config *cfg,
+	void *ip,
+	uint16_t total_length,
+	uint32_t ip_offset)
+{
+	switch (cfg->encap_mask) {
+	case 1LLU << RTE_TABLE_ACTION_ENCAP_ETHER:
+		encap(ip, data, sizeof(struct encap_ether_data));
+		mbuf->data_off = ip_offset - (sizeof(struct rte_mbuf) +
+			sizeof(struct encap_ether_data));
+		mbuf->pkt_len = mbuf->data_len = total_length +
+			sizeof(struct encap_ether_data);
+		break;
+
+	case 1LLU << RTE_TABLE_ACTION_ENCAP_VLAN:
+		encap(ip, data, sizeof(struct encap_vlan_data));
+		mbuf->data_off = ip_offset - (sizeof(struct rte_mbuf) +
+			sizeof(struct encap_vlan_data));
+		mbuf->pkt_len = mbuf->data_len = total_length +
+			sizeof(struct encap_vlan_data);
+		break;
+
+	case 1LLU << RTE_TABLE_ACTION_ENCAP_QINQ:
+		encap(ip, data, sizeof(struct encap_qinq_data));
+		mbuf->data_off = ip_offset - (sizeof(struct rte_mbuf) +
+			sizeof(struct encap_qinq_data));
+		mbuf->pkt_len = mbuf->data_len = total_length +
+			sizeof(struct encap_qinq_data);
+		break;
+
+	case 1LLU << RTE_TABLE_ACTION_ENCAP_MPLS:
+	{
+		struct encap_mpls_data *mpls = data;
+		size_t size = sizeof(struct ether_hdr) +
+			mpls->mpls_count * 4;
+
+		encap(ip, data, size);
+		mbuf->data_off = ip_offset - (sizeof(struct rte_mbuf) + size);
+		mbuf->pkt_len = mbuf->data_len = total_length + size;
+		break;
+	}
+
+	case 1LLU << RTE_TABLE_ACTION_ENCAP_PPPOE:
+	{
+		struct encap_pppoe_data *pppoe =
+			encap(ip, data, sizeof(struct encap_pppoe_data));
+		pppoe->pppoe_ppp.length = rte_htons(total_length + 2);
+		mbuf->data_off = ip_offset - (sizeof(struct rte_mbuf) +
+			sizeof(struct encap_pppoe_data));
+		mbuf->pkt_len = mbuf->data_len = total_length +
+			sizeof(struct encap_pppoe_data);
+		break;
+	}
+
+	default:
+		break;
+	}
+}
+
+/**
  * Action profile
  */
 static int
@@ -375,6 +742,7 @@ action_valid(enum rte_table_action_type action)
 	case RTE_TABLE_ACTION_FWD:
 	case RTE_TABLE_ACTION_MTR:
 	case RTE_TABLE_ACTION_TM:
+	case RTE_TABLE_ACTION_ENCAP:
 		return 1;
 	default:
 		return 0;
@@ -389,6 +757,7 @@ struct ap_config {
 	struct rte_table_action_common_config common;
 	struct rte_table_action_mtr_config mtr;
 	struct rte_table_action_tm_config tm;
+	struct rte_table_action_encap_config encap;
 };
 
 static size_t
@@ -399,6 +768,8 @@ action_cfg_size(enum rte_table_action_type action)
 		return sizeof(struct rte_table_action_mtr_config);
 	case RTE_TABLE_ACTION_TM:
 		return sizeof(struct rte_table_action_tm_config);
+	case RTE_TABLE_ACTION_ENCAP:
+		return sizeof(struct rte_table_action_encap_config);
 	default:
 		return 0;
 	}
@@ -415,6 +786,9 @@ action_cfg_get(struct ap_config *ap_config,
 	case RTE_TABLE_ACTION_TM:
 		return &ap_config->tm;
 
+	case RTE_TABLE_ACTION_ENCAP:
+		return &ap_config->encap;
+
 	default:
 		return NULL;
 	}
@@ -452,6 +826,9 @@ action_data_size(enum rte_table_action_type action,
 	case RTE_TABLE_ACTION_TM:
 		return sizeof(struct tm_data);
 
+	case RTE_TABLE_ACTION_ENCAP:
+		return encap_data_size(&ap_config->encap);
+
 	default:
 		return 0;
 	}
@@ -531,6 +908,10 @@ rte_table_action_profile_action_register(struct rte_table_action_profile *profil
 		status = tm_cfg_check(action_config);
 		break;
 
+	case RTE_TABLE_ACTION_ENCAP:
+		status = encap_cfg_check(action_config);
+		break;
+
 	default:
 		status = 0;
 		break;
@@ -653,6 +1034,12 @@ rte_table_action_apply(struct rte_table_action *action,
 			action_params,
 			&action->cfg.tm);
 
+	case RTE_TABLE_ACTION_ENCAP:
+		return encap_apply(action_data,
+			action_params,
+			&action->cfg.encap,
+			&action->cfg.common);
+
 	default:
 		return -EINVAL;
 	}
@@ -870,6 +1257,18 @@ pkt_work(struct rte_mbuf *mbuf,
 			dscp);
 	}
 
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_ENCAP)) {
+		void *data =
+			action_data_get(table_entry, action, RTE_TABLE_ACTION_ENCAP);
+
+		pkt_work_encap(mbuf,
+			data,
+			&cfg->encap,
+			ip,
+			total_length,
+			ip_offset);
+	}
+
 	return drop_mask;
 }
 
@@ -1014,6 +1413,45 @@ pkt4_work(struct rte_mbuf **mbufs,
 			dscp3);
 	}
 
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_ENCAP)) {
+		void *data0 =
+			action_data_get(table_entry0, action, RTE_TABLE_ACTION_ENCAP);
+		void *data1 =
+			action_data_get(table_entry1, action, RTE_TABLE_ACTION_ENCAP);
+		void *data2 =
+			action_data_get(table_entry2, action, RTE_TABLE_ACTION_ENCAP);
+		void *data3 =
+			action_data_get(table_entry3, action, RTE_TABLE_ACTION_ENCAP);
+
+		pkt_work_encap(mbuf0,
+			data0,
+			&cfg->encap,
+			ip0,
+			total_length0,
+			ip_offset);
+
+		pkt_work_encap(mbuf1,
+			data1,
+			&cfg->encap,
+			ip1,
+			total_length1,
+			ip_offset);
+
+		pkt_work_encap(mbuf2,
+			data2,
+			&cfg->encap,
+			ip2,
+			total_length2,
+			ip_offset);
+
+		pkt_work_encap(mbuf3,
+			data3,
+			&cfg->encap,
+			ip3,
+			total_length3,
+			ip_offset);
+	}
+
 	return drop_mask0 |
 		(drop_mask1 << 1) |
 		(drop_mask2 << 2) |
diff --git a/lib/librte_pipeline/rte_table_action.h b/lib/librte_pipeline/rte_table_action.h
index 98babc5..c5c987d 100644
--- a/lib/librte_pipeline/rte_table_action.h
+++ b/lib/librte_pipeline/rte_table_action.h
@@ -59,6 +59,7 @@ extern "C" {
 #include <stdint.h>
 
 #include <rte_compat.h>
+#include <rte_ether.h>
 #include <rte_meter.h>
 
 #include "rte_pipeline.h"
@@ -73,6 +74,9 @@ enum rte_table_action_type {
 
 	/**  Traffic Management. */
 	RTE_TABLE_ACTION_TM,
+
+	/** Packet encapsulations. */
+	RTE_TABLE_ACTION_ENCAP,
 };
 
 /** Common action configuration (per table action profile). */
@@ -280,6 +284,131 @@ struct rte_table_action_tm_params {
 };
 
 /**
+ * RTE_TABLE_ACTION_ENCAP
+ */
+/** Supported packet encapsulation types. */
+enum rte_table_action_encap_type {
+	/** IP -> { Ether | IP } */
+	RTE_TABLE_ACTION_ENCAP_ETHER = 0,
+
+	/** IP -> { Ether | VLAN | IP } */
+	RTE_TABLE_ACTION_ENCAP_VLAN,
+
+	/** IP -> { Ether | S-VLAN | C-VLAN | IP } */
+	RTE_TABLE_ACTION_ENCAP_QINQ,
+
+	/** IP -> { Ether | MPLS | IP } */
+	RTE_TABLE_ACTION_ENCAP_MPLS,
+
+	/** IP -> { Ether | PPPoE | PPP | IP } */
+	RTE_TABLE_ACTION_ENCAP_PPPOE,
+};
+
+/** Pre-computed Ethernet header fields for encapsulation action. */
+struct rte_table_action_ether_hdr {
+	struct ether_addr da; /**< Destination address. */
+	struct ether_addr sa; /**< Source address. */
+};
+
+/** Pre-computed VLAN header fields for encapsulation action. */
+struct rte_table_action_vlan_hdr {
+	uint8_t pcp; /**< Priority Code Point (PCP). */
+	uint8_t dei; /**< Drop Eligibility Indicator (DEI). */
+	uint16_t vid; /**< VLAN Identifier (VID). */
+};
+
+/** Pre-computed MPLS header fields for encapsulation action. */
+struct rte_table_action_mpls_hdr {
+	uint32_t label; /**< Label. */
+	uint8_t tc; /**< Traffic Class (TC). */
+	uint8_t ttl; /**< Time to Live (TTL). */
+};
+
+/** Pre-computed PPPoE header fields for encapsulation action. */
+struct rte_table_action_pppoe_hdr {
+	uint16_t session_id; /**< Session ID. */
+};
+
+/** Ether encap parameters. */
+struct rte_table_action_encap_ether_params {
+	struct rte_table_action_ether_hdr ether; /**< Ethernet header. */
+};
+
+/** VLAN encap parameters. */
+struct rte_table_action_encap_vlan_params {
+	struct rte_table_action_ether_hdr ether; /**< Ethernet header. */
+	struct rte_table_action_vlan_hdr vlan; /**< VLAN header. */
+};
+
+/** QinQ encap parameters. */
+struct rte_table_action_encap_qinq_params {
+	struct rte_table_action_ether_hdr ether; /**< Ethernet header. */
+	struct rte_table_action_vlan_hdr svlan; /**< Service VLAN header. */
+	struct rte_table_action_vlan_hdr cvlan; /**< Customer VLAN header. */
+};
+
+/** Max number of MPLS labels per output packet for MPLS encapsulation. */
+#ifndef RTE_TABLE_ACTION_MPLS_LABELS_MAX
+#define RTE_TABLE_ACTION_MPLS_LABELS_MAX                   4
+#endif
+
+/** MPLS encap parameters. */
+struct rte_table_action_encap_mpls_params {
+	/** Ethernet header. */
+	struct rte_table_action_ether_hdr ether;
+
+	/** MPLS header. */
+	struct rte_table_action_mpls_hdr mpls[RTE_TABLE_ACTION_MPLS_LABELS_MAX];
+
+	/** Number of MPLS labels in MPLS header. */
+	uint32_t mpls_count;
+
+	/** Non-zero for MPLS unicast, zero for MPLS multicast. */
+	int unicast;
+};
+
+/** PPPoE encap parameters. */
+struct rte_table_action_encap_pppoe_params {
+	struct rte_table_action_ether_hdr ether; /**< Ethernet header. */
+	struct rte_table_action_pppoe_hdr pppoe; /**< PPPoE/PPP headers. */
+};
+
+/** Encap action configuration (per table action profile). */
+struct rte_table_action_encap_config {
+	/** Bit mask defining the set of packet encapsulations enabled for the
+	 * current table action profile. If bit (1 << N) is set in *encap_mask*,
+	 * then packet encapsulation N is enabled, otherwise it is disabled.
+	 *
+	 * @see enum rte_table_action_encap_type
+	 */
+	uint64_t encap_mask;
+};
+
+/** Encap action parameters (per table rule). */
+struct rte_table_action_encap_params {
+	/** Encapsulation type. */
+	enum rte_table_action_encap_type type;
+
+	RTE_STD_C11
+	union {
+		/** Only valid when *type* is set to Ether. */
+		struct rte_table_action_encap_ether_params ether;
+
+		/** Only valid when *type* is set to VLAN. */
+		struct rte_table_action_encap_vlan_params vlan;
+
+		/** Only valid when *type* is set to QinQ. */
+		struct rte_table_action_encap_qinq_params qinq;
+
+		/** Only valid when *type* is set to MPLS. */
+		struct rte_table_action_encap_mpls_params mpls;
+
+		/** Only valid when *type* is set to PPPoE. */
+		struct rte_table_action_encap_pppoe_params pppoe;
+	};
+};
+
+/**
  * Table action profile.
  */
 struct rte_table_action_profile;
-- 
2.9.3

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

* [dpdk-dev] [PATCH v4 06/49] pipeline: add nat action
  2018-03-29 18:31           ` [dpdk-dev] [PATCH v4 00/49] ip_pipeline: refactoring Jasvinder Singh
                               ` (4 preceding siblings ...)
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 05/49] pipeline: add packet encapsulation action Jasvinder Singh
@ 2018-03-29 18:31             ` Jasvinder Singh
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 07/49] pipeline: add ttl update action Jasvinder Singh
                               ` (43 subsequent siblings)
  49 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-29 18:31 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add implementation of Network Address Translation(NAT) action.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 lib/librte_pipeline/rte_table_action.c | 351 +++++++++++++++++++++++++++++++++
 lib/librte_pipeline/rte_table_action.h |  39 ++++
 2 files changed, 390 insertions(+)

diff --git a/lib/librte_pipeline/rte_table_action.c b/lib/librte_pipeline/rte_table_action.c
index fa528d8..d22493a 100644
--- a/lib/librte_pipeline/rte_table_action.c
+++ b/lib/librte_pipeline/rte_table_action.c
@@ -733,6 +733,304 @@ pkt_work_encap(struct rte_mbuf *mbuf,
 }
 
 /**
+ * RTE_TABLE_ACTION_NAT
+ */
+static int
+nat_cfg_check(struct rte_table_action_nat_config *nat)
+{
+	if ((nat->proto != 0x06) &&
+		(nat->proto != 0x11))
+		return -ENOTSUP;
+
+	return 0;
+}
+
+struct nat_ipv4_data {
+	uint32_t addr;
+	uint16_t port;
+} __attribute__((__packed__));
+
+struct nat_ipv6_data {
+	uint8_t addr[16];
+	uint16_t port;
+} __attribute__((__packed__));
+
+static size_t
+nat_data_size(struct rte_table_action_nat_config *nat __rte_unused,
+	struct rte_table_action_common_config *common)
+{
+	int ip_version = common->ip_version;
+
+	return (ip_version) ?
+		sizeof(struct nat_ipv4_data) :
+		sizeof(struct nat_ipv6_data);
+}
+
+static int
+nat_apply_check(struct rte_table_action_nat_params *p,
+	struct rte_table_action_common_config *cfg)
+{
+	if ((p->ip_version && (cfg->ip_version == 0)) ||
+		((p->ip_version == 0) && cfg->ip_version))
+		return -EINVAL;
+
+	return 0;
+}
+
+static int
+nat_apply(void *data,
+	struct rte_table_action_nat_params *p,
+	struct rte_table_action_common_config *cfg)
+{
+	int status;
+
+	/* Check input arguments */
+	status = nat_apply_check(p, cfg);
+	if (status)
+		return status;
+
+	/* Apply */
+	if (p->ip_version) {
+		struct nat_ipv4_data *d = data;
+
+		d->addr = rte_htonl(p->addr.ipv4);
+		d->port = rte_htons(p->port);
+	} else {
+		struct nat_ipv6_data *d = data;
+
+		memcpy(d->addr, p->addr.ipv6, sizeof(d->addr));
+		d->port = rte_htons(p->port);
+	}
+
+	return 0;
+}
+
+static __rte_always_inline uint16_t
+nat_ipv4_checksum_update(uint16_t cksum0,
+	uint32_t ip0,
+	uint32_t ip1)
+{
+	int32_t cksum1;
+
+	cksum1 = cksum0;
+	cksum1 = ~cksum1 & 0xFFFF;
+
+	/* Subtract ip0 (one's complement logic) */
+	cksum1 -= (ip0 >> 16) + (ip0 & 0xFFFF);
+	cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
+	cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
+
+	/* Add ip1 (one's complement logic) */
+	cksum1 += (ip1 >> 16) + (ip1 & 0xFFFF);
+	cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
+	cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
+
+	return (uint16_t)(~cksum1);
+}
+
+static __rte_always_inline uint16_t
+nat_ipv4_tcp_udp_checksum_update(uint16_t cksum0,
+	uint32_t ip0,
+	uint32_t ip1,
+	uint16_t port0,
+	uint16_t port1)
+{
+	int32_t cksum1;
+
+	cksum1 = cksum0;
+	cksum1 = ~cksum1 & 0xFFFF;
+
+	/* Subtract ip0 and port 0 (one's complement logic) */
+	cksum1 -= (ip0 >> 16) + (ip0 & 0xFFFF) + port0;
+	cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
+	cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
+
+	/* Add ip1 and port1 (one's complement logic) */
+	cksum1 += (ip1 >> 16) + (ip1 & 0xFFFF) + port1;
+	cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
+	cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
+
+	return (uint16_t)(~cksum1);
+}
+
+static __rte_always_inline uint16_t
+nat_ipv6_tcp_udp_checksum_update(uint16_t cksum0,
+	uint16_t *ip0,
+	uint16_t *ip1,
+	uint16_t port0,
+	uint16_t port1)
+{
+	int32_t cksum1;
+
+	cksum1 = cksum0;
+	cksum1 = ~cksum1 & 0xFFFF;
+
+	/* Subtract ip0 and port 0 (one's complement logic) */
+	cksum1 -= ip0[0] + ip0[1] + ip0[2] + ip0[3] +
+		ip0[4] + ip0[5] + ip0[6] + ip0[7] + port0;
+	cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
+	cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
+
+	/* Add ip1 and port1 (one's complement logic) */
+	cksum1 += ip1[0] + ip1[1] + ip1[2] + ip1[3] +
+		ip1[4] + ip1[5] + ip1[6] + ip1[7] + port1;
+	cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
+	cksum1 = (cksum1 & 0xFFFF) + (cksum1 >> 16);
+
+	return (uint16_t)(~cksum1);
+}
+
+static __rte_always_inline void
+pkt_ipv4_work_nat(struct ipv4_hdr *ip,
+	struct nat_ipv4_data *data,
+	struct rte_table_action_nat_config *cfg)
+{
+	if (cfg->source_nat) {
+		if (cfg->proto == 0x6) {
+			struct tcp_hdr *tcp = (struct tcp_hdr *) &ip[1];
+			uint16_t ip_cksum, tcp_cksum;
+
+			ip_cksum = nat_ipv4_checksum_update(ip->hdr_checksum,
+				ip->src_addr,
+				data->addr);
+
+			tcp_cksum = nat_ipv4_tcp_udp_checksum_update(tcp->cksum,
+				ip->src_addr,
+				data->addr,
+				tcp->src_port,
+				data->port);
+
+			ip->src_addr = data->addr;
+			ip->hdr_checksum = ip_cksum;
+			tcp->src_port = data->port;
+			tcp->cksum = tcp_cksum;
+		} else {
+			struct udp_hdr *udp = (struct udp_hdr *) &ip[1];
+			uint16_t ip_cksum, udp_cksum;
+
+			ip_cksum = nat_ipv4_checksum_update(ip->hdr_checksum,
+				ip->src_addr,
+				data->addr);
+
+			udp_cksum = nat_ipv4_tcp_udp_checksum_update(udp->dgram_cksum,
+				ip->src_addr,
+				data->addr,
+				udp->src_port,
+				data->port);
+
+			ip->src_addr = data->addr;
+			ip->hdr_checksum = ip_cksum;
+			udp->src_port = data->port;
+			if (udp->dgram_cksum)
+				udp->dgram_cksum = udp_cksum;
+		}
+	} else {
+		if (cfg->proto == 0x6) {
+			struct tcp_hdr *tcp = (struct tcp_hdr *) &ip[1];
+			uint16_t ip_cksum, tcp_cksum;
+
+			ip_cksum = nat_ipv4_checksum_update(ip->hdr_checksum,
+				ip->dst_addr,
+				data->addr);
+
+			tcp_cksum = nat_ipv4_tcp_udp_checksum_update(tcp->cksum,
+				ip->dst_addr,
+				data->addr,
+				tcp->dst_port,
+				data->port);
+
+			ip->dst_addr = data->addr;
+			ip->hdr_checksum = ip_cksum;
+			tcp->dst_port = data->port;
+			tcp->cksum = tcp_cksum;
+		} else {
+			struct udp_hdr *udp = (struct udp_hdr *) &ip[1];
+			uint16_t ip_cksum, udp_cksum;
+
+			ip_cksum = nat_ipv4_checksum_update(ip->hdr_checksum,
+				ip->dst_addr,
+				data->addr);
+
+			udp_cksum = nat_ipv4_tcp_udp_checksum_update(udp->dgram_cksum,
+				ip->dst_addr,
+				data->addr,
+				udp->dst_port,
+				data->port);
+
+			ip->dst_addr = data->addr;
+			ip->hdr_checksum = ip_cksum;
+			udp->dst_port = data->port;
+			if (udp->dgram_cksum)
+				udp->dgram_cksum = udp_cksum;
+		}
+	}
+}
+
+static __rte_always_inline void
+pkt_ipv6_work_nat(struct ipv6_hdr *ip,
+	struct nat_ipv6_data *data,
+	struct rte_table_action_nat_config *cfg)
+{
+	if (cfg->source_nat) {
+		if (cfg->proto == 0x6) {
+			struct tcp_hdr *tcp = (struct tcp_hdr *) &ip[1];
+			uint16_t tcp_cksum;
+
+			tcp_cksum = nat_ipv6_tcp_udp_checksum_update(tcp->cksum,
+				(uint16_t *)ip->src_addr,
+				(uint16_t *)data->addr,
+				tcp->src_port,
+				data->port);
+
+			rte_memcpy(ip->src_addr, data->addr, 16);
+			tcp->src_port = data->port;
+			tcp->cksum = tcp_cksum;
+		} else {
+			struct udp_hdr *udp = (struct udp_hdr *) &ip[1];
+			uint16_t udp_cksum;
+
+			udp_cksum = nat_ipv6_tcp_udp_checksum_update(udp->dgram_cksum,
+				(uint16_t *)ip->src_addr,
+				(uint16_t *)data->addr,
+				udp->src_port,
+				data->port);
+
+			rte_memcpy(ip->src_addr, data->addr, 16);
+			udp->src_port = data->port;
+			udp->dgram_cksum = udp_cksum;
+		}
+	} else {
+		if (cfg->proto == 0x6) {
+			struct tcp_hdr *tcp = (struct tcp_hdr *) &ip[1];
+			uint16_t tcp_cksum;
+
+			tcp_cksum = nat_ipv6_tcp_udp_checksum_update(tcp->cksum,
+				(uint16_t *)ip->dst_addr,
+				(uint16_t *)data->addr,
+				tcp->dst_port,
+				data->port);
+
+			rte_memcpy(ip->dst_addr, data->addr, 16);
+			tcp->dst_port = data->port;
+			tcp->cksum = tcp_cksum;
+		} else {
+			struct udp_hdr *udp = (struct udp_hdr *) &ip[1];
+			uint16_t udp_cksum;
+
+			udp_cksum = nat_ipv6_tcp_udp_checksum_update(udp->dgram_cksum,
+				(uint16_t *)ip->dst_addr,
+				(uint16_t *)data->addr,
+				udp->dst_port,
+				data->port);
+
+			rte_memcpy(ip->dst_addr, data->addr, 16);
+			udp->dst_port = data->port;
+			udp->dgram_cksum = udp_cksum;
+		}
+	}
+}
+
+/**
  * Action profile
  */
 static int
@@ -743,6 +1041,7 @@ action_valid(enum rte_table_action_type action)
 	case RTE_TABLE_ACTION_MTR:
 	case RTE_TABLE_ACTION_TM:
 	case RTE_TABLE_ACTION_ENCAP:
+	case RTE_TABLE_ACTION_NAT:
 		return 1;
 	default:
 		return 0;
@@ -758,6 +1057,7 @@ struct ap_config {
 	struct rte_table_action_mtr_config mtr;
 	struct rte_table_action_tm_config tm;
 	struct rte_table_action_encap_config encap;
+	struct rte_table_action_nat_config nat;
 };
 
 static size_t
@@ -770,6 +1070,8 @@ action_cfg_size(enum rte_table_action_type action)
 		return sizeof(struct rte_table_action_tm_config);
 	case RTE_TABLE_ACTION_ENCAP:
 		return sizeof(struct rte_table_action_encap_config);
+	case RTE_TABLE_ACTION_NAT:
+		return sizeof(struct rte_table_action_nat_config);
 	default:
 		return 0;
 	}
@@ -789,6 +1091,9 @@ action_cfg_get(struct ap_config *ap_config,
 	case RTE_TABLE_ACTION_ENCAP:
 		return &ap_config->encap;
 
+	case RTE_TABLE_ACTION_NAT:
+		return &ap_config->nat;
+
 	default:
 		return NULL;
 	}
@@ -829,6 +1134,10 @@ action_data_size(enum rte_table_action_type action,
 	case RTE_TABLE_ACTION_ENCAP:
 		return encap_data_size(&ap_config->encap);
 
+	case RTE_TABLE_ACTION_NAT:
+		return nat_data_size(&ap_config->nat,
+			&ap_config->common);
+
 	default:
 		return 0;
 	}
@@ -912,6 +1221,10 @@ rte_table_action_profile_action_register(struct rte_table_action_profile *profil
 		status = encap_cfg_check(action_config);
 		break;
 
+	case RTE_TABLE_ACTION_NAT:
+		status = nat_cfg_check(action_config);
+		break;
+
 	default:
 		status = 0;
 		break;
@@ -1040,6 +1353,11 @@ rte_table_action_apply(struct rte_table_action *action,
 			&action->cfg.encap,
 			&action->cfg.common);
 
+	case RTE_TABLE_ACTION_NAT:
+		return nat_apply(action_data,
+			action_params,
+			&action->cfg.common);
+
 	default:
 		return -EINVAL;
 	}
@@ -1269,6 +1587,16 @@ pkt_work(struct rte_mbuf *mbuf,
 			ip_offset);
 	}
 
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_NAT)) {
+		void *data =
+			action_data_get(table_entry, action, RTE_TABLE_ACTION_NAT);
+
+		if (cfg->common.ip_version)
+			pkt_ipv4_work_nat(ip, data, &cfg->nat);
+		else
+			pkt_ipv6_work_nat(ip, data, &cfg->nat);
+	}
+
 	return drop_mask;
 }
 
@@ -1452,6 +1780,29 @@ pkt4_work(struct rte_mbuf **mbufs,
 			ip_offset);
 	}
 
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_NAT)) {
+		void *data0 =
+			action_data_get(table_entry0, action, RTE_TABLE_ACTION_NAT);
+		void *data1 =
+			action_data_get(table_entry1, action, RTE_TABLE_ACTION_NAT);
+		void *data2 =
+			action_data_get(table_entry2, action, RTE_TABLE_ACTION_NAT);
+		void *data3 =
+			action_data_get(table_entry3, action, RTE_TABLE_ACTION_NAT);
+
+		if (cfg->common.ip_version) {
+			pkt_ipv4_work_nat(ip0, data0, &cfg->nat);
+			pkt_ipv4_work_nat(ip1, data1, &cfg->nat);
+			pkt_ipv4_work_nat(ip2, data2, &cfg->nat);
+			pkt_ipv4_work_nat(ip3, data3, &cfg->nat);
+		} else {
+			pkt_ipv6_work_nat(ip0, data0, &cfg->nat);
+			pkt_ipv6_work_nat(ip1, data1, &cfg->nat);
+			pkt_ipv6_work_nat(ip2, data2, &cfg->nat);
+			pkt_ipv6_work_nat(ip3, data3, &cfg->nat);
+		}
+	}
+
 	return drop_mask0 |
 		(drop_mask1 << 1) |
 		(drop_mask2 << 2) |
diff --git a/lib/librte_pipeline/rte_table_action.h b/lib/librte_pipeline/rte_table_action.h
index c5c987d..5204511 100644
--- a/lib/librte_pipeline/rte_table_action.h
+++ b/lib/librte_pipeline/rte_table_action.h
@@ -77,6 +77,9 @@ enum rte_table_action_type {
 
 	/** Packet encapsulations. */
 	RTE_TABLE_ACTION_ENCAP,
+
+	/** Network Address Translation (NAT). */
+	RTE_TABLE_ACTION_NAT,
 };
 
 /** Common action configuration (per table action profile). */
@@ -409,6 +412,42 @@ struct rte_table_action_encap_params {
 };
 
 /**
+ * RTE_TABLE_ACTION_NAT
+ */
+/** NAT action configuration (per table action profile). */
+struct rte_table_action_nat_config {
+	/** When non-zero, the IP source address and L4 protocol source port are
+	 * translated. When zero, the IP destination address and L4 protocol
+	 * destination port are translated.
+	 */
+	int source_nat;
+
+	/** Layer 4 protocol, for example TCP (0x06) or UDP (0x11). The checksum
+	 * field is computed differently and placed at different header offset
+	 * by each layer 4 protocol.
+	 */
+	uint8_t proto;
+};
+
+/** NAT action parameters (per table rule). */
+struct rte_table_action_nat_params {
+	/** IP version for *addr*: non-zero for IPv4, zero for IPv6. */
+	int ip_version;
+
+	/** IP address. */
+	union {
+		/** IPv4 address; only valid when *ip_version* is non-zero. */
+		uint32_t ipv4;
+
+		/** IPv6 address; only valid when *ip_version* is set to 0. */
+		uint8_t ipv6[16];
+	} addr;
+
+	/** Port. */
+	uint16_t port;
+};
+
+/**
  * Table action profile.
  */
 struct rte_table_action_profile;
-- 
2.9.3

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

* [dpdk-dev] [PATCH v4 07/49] pipeline: add ttl update action
  2018-03-29 18:31           ` [dpdk-dev] [PATCH v4 00/49] ip_pipeline: refactoring Jasvinder Singh
                               ` (5 preceding siblings ...)
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 06/49] pipeline: add nat action Jasvinder Singh
@ 2018-03-29 18:31             ` Jasvinder Singh
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 08/49] pipeline: add statistics read action Jasvinder Singh
                               ` (42 subsequent siblings)
  49 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-29 18:31 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add implementation of ttl update action.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 lib/librte_pipeline/rte_pipeline_version.map |   1 +
 lib/librte_pipeline/rte_table_action.c       | 162 +++++++++++++++++++++++++++
 lib/librte_pipeline/rte_table_action.h       |  66 +++++++++++
 3 files changed, 229 insertions(+)

diff --git a/lib/librte_pipeline/rte_pipeline_version.map b/lib/librte_pipeline/rte_pipeline_version.map
index c7106dc..9388585 100644
--- a/lib/librte_pipeline/rte_pipeline_version.map
+++ b/lib/librte_pipeline/rte_pipeline_version.map
@@ -61,5 +61,6 @@ EXPERIMENTAL {
 	rte_table_action_profile_free;
 	rte_table_action_profile_freeze;
 	rte_table_action_table_params_get;
+	rte_table_action_ttl_read;
 
 } DPDK_16.04;
diff --git a/lib/librte_pipeline/rte_table_action.c b/lib/librte_pipeline/rte_table_action.c
index d22493a..c77bfb7 100644
--- a/lib/librte_pipeline/rte_table_action.c
+++ b/lib/librte_pipeline/rte_table_action.c
@@ -1031,6 +1031,89 @@ pkt_ipv6_work_nat(struct ipv6_hdr *ip,
 }
 
 /**
+ * RTE_TABLE_ACTION_TTL
+ */
+static int
+ttl_cfg_check(struct rte_table_action_ttl_config *ttl)
+{
+	if (ttl->drop == 0)
+		return -ENOTSUP;
+
+	return 0;
+}
+
+struct ttl_data {
+	uint32_t n_packets;
+} __attribute__((__packed__));
+
+#define TTL_INIT(data, decrement)                         \
+	((data)->n_packets = (decrement) ? 1 : 0)
+
+#define TTL_DEC_GET(data)                                  \
+	((uint8_t)((data)->n_packets & 1))
+
+#define TTL_STATS_RESET(data)                             \
+	((data)->n_packets = ((data)->n_packets & 1))
+
+#define TTL_STATS_READ(data)                               \
+	((data)->n_packets >> 1)
+
+#define TTL_STATS_ADD(data, value)                        \
+	((data)->n_packets =                                  \
+		(((((data)->n_packets >> 1) + (value)) << 1) |    \
+		((data)->n_packets & 1)))
+
+static int
+ttl_apply(void *data,
+	struct rte_table_action_ttl_params *p)
+{
+	struct ttl_data *d = data;
+
+	TTL_INIT(d, p->decrement);
+
+	return 0;
+}
+
+static __rte_always_inline uint64_t
+pkt_ipv4_work_ttl(struct ipv4_hdr *ip,
+	struct ttl_data *data)
+{
+	uint32_t drop;
+	uint16_t cksum = ip->hdr_checksum;
+	uint8_t ttl = ip->time_to_live;
+	uint8_t ttl_diff = TTL_DEC_GET(data);
+
+	cksum += ttl_diff;
+	ttl -= ttl_diff;
+
+	ip->hdr_checksum = cksum;
+	ip->time_to_live = ttl;
+
+	drop = (ttl == 0) ? 1 : 0;
+	TTL_STATS_ADD(data, drop);
+
+	return drop;
+}
+
+static __rte_always_inline uint64_t
+pkt_ipv6_work_ttl(struct ipv6_hdr *ip,
+	struct ttl_data *data)
+{
+	uint32_t drop;
+	uint8_t ttl = ip->hop_limits;
+	uint8_t ttl_diff = TTL_DEC_GET(data);
+
+	ttl -= ttl_diff;
+
+	ip->hop_limits = ttl;
+
+	drop = (ttl == 0) ? 1 : 0;
+	TTL_STATS_ADD(data, drop);
+
+	return drop;
+}
+
+/**
  * Action profile
  */
 static int
@@ -1042,6 +1125,7 @@ action_valid(enum rte_table_action_type action)
 	case RTE_TABLE_ACTION_TM:
 	case RTE_TABLE_ACTION_ENCAP:
 	case RTE_TABLE_ACTION_NAT:
+	case RTE_TABLE_ACTION_TTL:
 		return 1;
 	default:
 		return 0;
@@ -1058,6 +1142,7 @@ struct ap_config {
 	struct rte_table_action_tm_config tm;
 	struct rte_table_action_encap_config encap;
 	struct rte_table_action_nat_config nat;
+	struct rte_table_action_ttl_config ttl;
 };
 
 static size_t
@@ -1072,6 +1157,8 @@ action_cfg_size(enum rte_table_action_type action)
 		return sizeof(struct rte_table_action_encap_config);
 	case RTE_TABLE_ACTION_NAT:
 		return sizeof(struct rte_table_action_nat_config);
+	case RTE_TABLE_ACTION_TTL:
+		return sizeof(struct rte_table_action_ttl_config);
 	default:
 		return 0;
 	}
@@ -1094,6 +1181,9 @@ action_cfg_get(struct ap_config *ap_config,
 	case RTE_TABLE_ACTION_NAT:
 		return &ap_config->nat;
 
+	case RTE_TABLE_ACTION_TTL:
+		return &ap_config->ttl;
+
 	default:
 		return NULL;
 	}
@@ -1138,6 +1228,9 @@ action_data_size(enum rte_table_action_type action,
 		return nat_data_size(&ap_config->nat,
 			&ap_config->common);
 
+	case RTE_TABLE_ACTION_TTL:
+		return sizeof(struct ttl_data);
+
 	default:
 		return 0;
 	}
@@ -1225,6 +1318,10 @@ rte_table_action_profile_action_register(struct rte_table_action_profile *profil
 		status = nat_cfg_check(action_config);
 		break;
 
+	case RTE_TABLE_ACTION_TTL:
+		status = ttl_cfg_check(action_config);
+		break;
+
 	default:
 		status = 0;
 		break;
@@ -1358,6 +1455,10 @@ rte_table_action_apply(struct rte_table_action *action,
 			action_params,
 			&action->cfg.common);
 
+	case RTE_TABLE_ACTION_TTL:
+		return ttl_apply(action_data,
+			action_params);
+
 	default:
 		return -EINVAL;
 	}
@@ -1524,6 +1625,34 @@ rte_table_action_meter_read(struct rte_table_action *action,
 	return 0;
 }
 
+int
+rte_table_action_ttl_read(struct rte_table_action *action,
+	void *data,
+	struct rte_table_action_ttl_counters *stats,
+	int clear)
+{
+	struct ttl_data *ttl_data;
+
+	/* Check input arguments */
+	if ((action == NULL) ||
+		((action->cfg.action_mask &
+		(1LLU << RTE_TABLE_ACTION_TTL)) == 0) ||
+		(data == NULL))
+		return -EINVAL;
+
+	ttl_data = action_data_get(data, action, RTE_TABLE_ACTION_TTL);
+
+	/* Read */
+	if (stats)
+		stats->n_packets = TTL_STATS_READ(ttl_data);
+
+	/* Clear */
+	if (clear)
+		TTL_STATS_RESET(ttl_data);
+
+	return 0;
+}
+
 static __rte_always_inline uint64_t
 pkt_work(struct rte_mbuf *mbuf,
 	struct rte_pipeline_table_entry *table_entry,
@@ -1597,6 +1726,16 @@ pkt_work(struct rte_mbuf *mbuf,
 			pkt_ipv6_work_nat(ip, data, &cfg->nat);
 	}
 
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_TTL)) {
+		void *data =
+			action_data_get(table_entry, action, RTE_TABLE_ACTION_TTL);
+
+		if (cfg->common.ip_version)
+			drop_mask |= pkt_ipv4_work_ttl(ip, data);
+		else
+			drop_mask |= pkt_ipv6_work_ttl(ip, data);
+	}
+
 	return drop_mask;
 }
 
@@ -1803,6 +1942,29 @@ pkt4_work(struct rte_mbuf **mbufs,
 		}
 	}
 
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_TTL)) {
+		void *data0 =
+			action_data_get(table_entry0, action, RTE_TABLE_ACTION_TTL);
+		void *data1 =
+			action_data_get(table_entry1, action, RTE_TABLE_ACTION_TTL);
+		void *data2 =
+			action_data_get(table_entry2, action, RTE_TABLE_ACTION_TTL);
+		void *data3 =
+			action_data_get(table_entry3, action, RTE_TABLE_ACTION_TTL);
+
+		if (cfg->common.ip_version) {
+			drop_mask0 |= pkt_ipv4_work_ttl(ip0, data0);
+			drop_mask1 |= pkt_ipv4_work_ttl(ip1, data1);
+			drop_mask2 |= pkt_ipv4_work_ttl(ip2, data2);
+			drop_mask3 |= pkt_ipv4_work_ttl(ip3, data3);
+		} else {
+			drop_mask0 |= pkt_ipv6_work_ttl(ip0, data0);
+			drop_mask1 |= pkt_ipv6_work_ttl(ip1, data1);
+			drop_mask2 |= pkt_ipv6_work_ttl(ip2, data2);
+			drop_mask3 |= pkt_ipv6_work_ttl(ip3, data3);
+		}
+	}
+
 	return drop_mask0 |
 		(drop_mask1 << 1) |
 		(drop_mask2 << 2) |
diff --git a/lib/librte_pipeline/rte_table_action.h b/lib/librte_pipeline/rte_table_action.h
index 5204511..57ac4f9 100644
--- a/lib/librte_pipeline/rte_table_action.h
+++ b/lib/librte_pipeline/rte_table_action.h
@@ -80,6 +80,9 @@ enum rte_table_action_type {
 
 	/** Network Address Translation (NAT). */
 	RTE_TABLE_ACTION_NAT,
+
+	/** Time to Live (TTL) update. */
+	RTE_TABLE_ACTION_TTL,
 };
 
 /** Common action configuration (per table action profile). */
@@ -448,6 +451,44 @@ struct rte_table_action_nat_params {
 };
 
 /**
+ * RTE_TABLE_ACTION_TTL
+ */
+/** TTL action configuration (per table action profile). */
+struct rte_table_action_ttl_config {
+	/** When non-zero, the input packets whose updated IPv4 Time to Live
+	 * (TTL) field or IPv6 Hop Limit (HL) field is zero are dropped.
+	 * When zero, the input packets whose updated IPv4 TTL field or IPv6 HL
+	 * field is zero are forwarded as usual (typically for debugging
+	 * purpose).
+	 */
+	int drop;
+
+	/** When non-zero, the *n_packets* stats counter for TTL action is
+	 * enabled, otherwise disabled.
+	 *
+	 * @see struct rte_table_action_ttl_counters
+	 */
+	int n_packets_enabled;
+};
+
+/** TTL action parameters (per table rule). */
+struct rte_table_action_ttl_params {
+	/** When non-zero, decrement the IPv4 TTL field and update the checksum
+	 * field, or decrement the IPv6 HL field. When zero, the IPv4 TTL field
+	 * or the IPv6 HL field is not changed.
+	 */
+	int decrement;
+};
+
+/** TTL action statistics packets (per table rule). */
+struct rte_table_action_ttl_counters {
+	/** Number of IPv4 packets whose updated TTL field is zero or IPv6
+	 * packets whose updated HL field is zero.
+	 */
+	uint64_t n_packets;
+};
+
+/**
  * Table action profile.
  */
 struct rte_table_action_profile;
@@ -671,6 +712,31 @@ rte_table_action_meter_read(struct rte_table_action *action,
 	struct rte_table_action_mtr_counters *stats,
 	int clear);
 
+/**
+ * Table action TTL read.
+ *
+ * @param[in] action
+ *   Handle to table action object (needs to be valid).
+ * @param[in] data
+ *   Data byte array (typically table rule data) with TTL action previously
+ *   applied on it.
+ * @param[inout] stats
+ *   When non-NULL, it points to the area where the TTL stats counters read from
+ *   *data* are saved.
+ * @param[in] clear
+ *   When non-zero, the TTL stats counters are cleared (i.e. set to zero),
+ *   otherwise the counters are not modified. When the read operation is enabled
+ *   (*stats* is non-NULL), the clear operation is performed after the read
+ *   operation is completed.
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_table_action_ttl_read(struct rte_table_action *action,
+	void *data,
+	struct rte_table_action_ttl_counters *stats,
+	int clear);
+
 #ifdef __cplusplus
 }
 #endif
-- 
2.9.3

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

* [dpdk-dev] [PATCH v4 08/49] pipeline: add statistics read action
  2018-03-29 18:31           ` [dpdk-dev] [PATCH v4 00/49] ip_pipeline: refactoring Jasvinder Singh
                               ` (6 preceding siblings ...)
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 07/49] pipeline: add ttl update action Jasvinder Singh
@ 2018-03-29 18:31             ` Jasvinder Singh
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 09/49] pipeline: add timestamp action Jasvinder Singh
                               ` (41 subsequent siblings)
  49 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-29 18:31 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add implementation of stats read action

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 lib/librte_pipeline/rte_pipeline_version.map |   1 +
 lib/librte_pipeline/rte_table_action.c       | 111 +++++++++++++++++++++++++++
 lib/librte_pipeline/rte_table_action.h       |  78 +++++++++++++++++++
 3 files changed, 190 insertions(+)

diff --git a/lib/librte_pipeline/rte_pipeline_version.map b/lib/librte_pipeline/rte_pipeline_version.map
index 9388585..8241efc 100644
--- a/lib/librte_pipeline/rte_pipeline_version.map
+++ b/lib/librte_pipeline/rte_pipeline_version.map
@@ -61,6 +61,7 @@ EXPERIMENTAL {
 	rte_table_action_profile_free;
 	rte_table_action_profile_freeze;
 	rte_table_action_table_params_get;
+	rte_table_action_stats_read;
 	rte_table_action_ttl_read;
 
 } DPDK_16.04;
diff --git a/lib/librte_pipeline/rte_table_action.c b/lib/librte_pipeline/rte_table_action.c
index c77bfb7..8bcc4eb 100644
--- a/lib/librte_pipeline/rte_table_action.c
+++ b/lib/librte_pipeline/rte_table_action.c
@@ -1114,6 +1114,41 @@ pkt_ipv6_work_ttl(struct ipv6_hdr *ip,
 }
 
 /**
+ * RTE_TABLE_ACTION_STATS
+ */
+static int
+stats_cfg_check(struct rte_table_action_stats_config *stats)
+{
+	if ((stats->n_packets_enabled == 0) && (stats->n_bytes_enabled == 0))
+		return -EINVAL;
+
+	return 0;
+}
+
+struct stats_data {
+	uint64_t n_packets;
+	uint64_t n_bytes;
+} __attribute__((__packed__));
+
+static int
+stats_apply(struct stats_data *data,
+	struct rte_table_action_stats_params *p)
+{
+	data->n_packets = p->n_packets;
+	data->n_bytes = p->n_bytes;
+
+	return 0;
+}
+
+static __rte_always_inline void
+pkt_work_stats(struct stats_data *data,
+	uint16_t total_length)
+{
+	data->n_packets++;
+	data->n_bytes += total_length;
+}
+
+/**
  * Action profile
  */
 static int
@@ -1126,6 +1161,7 @@ action_valid(enum rte_table_action_type action)
 	case RTE_TABLE_ACTION_ENCAP:
 	case RTE_TABLE_ACTION_NAT:
 	case RTE_TABLE_ACTION_TTL:
+	case RTE_TABLE_ACTION_STATS:
 		return 1;
 	default:
 		return 0;
@@ -1143,6 +1179,7 @@ struct ap_config {
 	struct rte_table_action_encap_config encap;
 	struct rte_table_action_nat_config nat;
 	struct rte_table_action_ttl_config ttl;
+	struct rte_table_action_stats_config stats;
 };
 
 static size_t
@@ -1159,6 +1196,8 @@ action_cfg_size(enum rte_table_action_type action)
 		return sizeof(struct rte_table_action_nat_config);
 	case RTE_TABLE_ACTION_TTL:
 		return sizeof(struct rte_table_action_ttl_config);
+	case RTE_TABLE_ACTION_STATS:
+		return sizeof(struct rte_table_action_stats_config);
 	default:
 		return 0;
 	}
@@ -1184,6 +1223,9 @@ action_cfg_get(struct ap_config *ap_config,
 	case RTE_TABLE_ACTION_TTL:
 		return &ap_config->ttl;
 
+	case RTE_TABLE_ACTION_STATS:
+		return &ap_config->stats;
+
 	default:
 		return NULL;
 	}
@@ -1231,6 +1273,9 @@ action_data_size(enum rte_table_action_type action,
 	case RTE_TABLE_ACTION_TTL:
 		return sizeof(struct ttl_data);
 
+	case RTE_TABLE_ACTION_STATS:
+		return sizeof(struct stats_data);
+
 	default:
 		return 0;
 	}
@@ -1322,6 +1367,10 @@ rte_table_action_profile_action_register(struct rte_table_action_profile *profil
 		status = ttl_cfg_check(action_config);
 		break;
 
+	case RTE_TABLE_ACTION_STATS:
+		status = stats_cfg_check(action_config);
+		break;
+
 	default:
 		status = 0;
 		break;
@@ -1459,6 +1508,10 @@ rte_table_action_apply(struct rte_table_action *action,
 		return ttl_apply(action_data,
 			action_params);
 
+	case RTE_TABLE_ACTION_STATS:
+		return stats_apply(action_data,
+			action_params);
+
 	default:
 		return -EINVAL;
 	}
@@ -1653,6 +1706,41 @@ rte_table_action_ttl_read(struct rte_table_action *action,
 	return 0;
 }
 
+int
+rte_table_action_stats_read(struct rte_table_action *action,
+	void *data,
+	struct rte_table_action_stats_counters *stats,
+	int clear)
+{
+	struct stats_data *stats_data;
+
+	/* Check input arguments */
+	if ((action == NULL) ||
+		((action->cfg.action_mask &
+		(1LLU << RTE_TABLE_ACTION_STATS)) == 0) ||
+		(data == NULL))
+		return -EINVAL;
+
+	stats_data = action_data_get(data, action,
+		RTE_TABLE_ACTION_STATS);
+
+	/* Read */
+	if (stats) {
+		stats->n_packets = stats_data->n_packets;
+		stats->n_bytes = stats_data->n_bytes;
+		stats->n_packets_valid = 1;
+		stats->n_bytes_valid = 1;
+	}
+
+	/* Clear */
+	if (clear) {
+		stats_data->n_packets = 0;
+		stats_data->n_bytes = 0;
+	}
+
+	return 0;
+}
+
 static __rte_always_inline uint64_t
 pkt_work(struct rte_mbuf *mbuf,
 	struct rte_pipeline_table_entry *table_entry,
@@ -1736,6 +1824,13 @@ pkt_work(struct rte_mbuf *mbuf,
 			drop_mask |= pkt_ipv6_work_ttl(ip, data);
 	}
 
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_STATS)) {
+		void *data =
+			action_data_get(table_entry, action, RTE_TABLE_ACTION_STATS);
+
+		pkt_work_stats(data, total_length);
+	}
+
 	return drop_mask;
 }
 
@@ -1965,6 +2060,22 @@ pkt4_work(struct rte_mbuf **mbufs,
 		}
 	}
 
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_STATS)) {
+		void *data0 =
+			action_data_get(table_entry0, action, RTE_TABLE_ACTION_STATS);
+		void *data1 =
+			action_data_get(table_entry1, action, RTE_TABLE_ACTION_STATS);
+		void *data2 =
+			action_data_get(table_entry2, action, RTE_TABLE_ACTION_STATS);
+		void *data3 =
+			action_data_get(table_entry3, action, RTE_TABLE_ACTION_STATS);
+
+		pkt_work_stats(data0, total_length0);
+		pkt_work_stats(data1, total_length1);
+		pkt_work_stats(data2, total_length2);
+		pkt_work_stats(data3, total_length3);
+	}
+
 	return drop_mask0 |
 		(drop_mask1 << 1) |
 		(drop_mask2 << 2) |
diff --git a/lib/librte_pipeline/rte_table_action.h b/lib/librte_pipeline/rte_table_action.h
index 57ac4f9..53b9866 100644
--- a/lib/librte_pipeline/rte_table_action.h
+++ b/lib/librte_pipeline/rte_table_action.h
@@ -83,6 +83,9 @@ enum rte_table_action_type {
 
 	/** Time to Live (TTL) update. */
 	RTE_TABLE_ACTION_TTL,
+
+	/** Statistics. */
+	RTE_TABLE_ACTION_STATS,
 };
 
 /** Common action configuration (per table action profile). */
@@ -489,6 +492,56 @@ struct rte_table_action_ttl_counters {
 };
 
 /**
+ * RTE_TABLE_ACTION_STATS
+ */
+/** Stats action configuration (per table action profile). */
+struct rte_table_action_stats_config {
+	/** When non-zero, the *n_packets* stats counter is enabled, otherwise
+	 * disabled.
+	 *
+	 * @see struct rte_table_action_stats_counters
+	 */
+	int n_packets_enabled;
+
+	/** When non-zero, the *n_bytes* stats counter is enabled, otherwise
+	 * disabled.
+	 *
+	 * @see struct rte_table_action_stats_counters
+	 */
+	int n_bytes_enabled;
+};
+
+/** Stats action parameters (per table rule). */
+struct rte_table_action_stats_params {
+	/** Initial value for the *n_packets* stats counter. Typically set to 0.
+	 *
+	 * @see struct rte_table_action_stats_counters
+	 */
+	uint64_t n_packets;
+
+	/** Initial value for the *n_bytes* stats counter. Typically set to 0.
+	 *
+	 * @see struct rte_table_action_stats_counters
+	 */
+	uint64_t n_bytes;
+};
+
+/** Stats action counters (per table rule). */
+struct rte_table_action_stats_counters {
+	/** Number of packets. Valid only when *n_packets_valid* is non-zero. */
+	uint64_t n_packets;
+
+	/** Number of bytes. Valid only when *n_bytes_valid* is non-zero. */
+	uint64_t n_bytes;
+
+	/** When non-zero, the *n_packets* field is valid, otherwise invalid. */
+	int n_packets_valid;
+
+	/** When non-zero, the *n_bytes* field is valid, otherwise invalid. */
+	int n_bytes_valid;
+};
+
+/**
  * Table action profile.
  */
 struct rte_table_action_profile;
@@ -737,6 +790,31 @@ rte_table_action_ttl_read(struct rte_table_action *action,
 	struct rte_table_action_ttl_counters *stats,
 	int clear);
 
+/**
+ * Table action stats read.
+ *
+ * @param[in] action
+ *   Handle to table action object (needs to be valid).
+ * @param[in] data
+ *   Data byte array (typically table rule data) with stats action previously
+ *   applied on it.
+ * @param[inout] stats
+ *   When non-NULL, it points to the area where the stats counters read from
+ *   *data* are saved.
+ * @param[in] clear
+ *   When non-zero, the stats counters are cleared (i.e. set to zero), otherwise
+ *   the counters are not modified. When the read operation is enabled (*stats*
+ *   is non-NULL), the clear operation is performed after the read operation is
+ *   completed.
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_table_action_stats_read(struct rte_table_action *action,
+	void *data,
+	struct rte_table_action_stats_counters *stats,
+	int clear);
+
 #ifdef __cplusplus
 }
 #endif
-- 
2.9.3

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

* [dpdk-dev] [PATCH v4 09/49] pipeline: add timestamp action
  2018-03-29 18:31           ` [dpdk-dev] [PATCH v4 00/49] ip_pipeline: refactoring Jasvinder Singh
                               ` (7 preceding siblings ...)
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 08/49] pipeline: add statistics read action Jasvinder Singh
@ 2018-03-29 18:31             ` Jasvinder Singh
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 10/49] pipeline: add load balance action Jasvinder Singh
                               ` (40 subsequent siblings)
  49 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-29 18:31 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add implementation of timestamp action.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 lib/librte_pipeline/rte_pipeline_version.map |  1 +
 lib/librte_pipeline/rte_table_action.c       | 79 +++++++++++++++++++++++++++-
 lib/librte_pipeline/rte_table_action.h       | 31 +++++++++++
 3 files changed, 110 insertions(+), 1 deletion(-)

diff --git a/lib/librte_pipeline/rte_pipeline_version.map b/lib/librte_pipeline/rte_pipeline_version.map
index 8241efc..4e948b8 100644
--- a/lib/librte_pipeline/rte_pipeline_version.map
+++ b/lib/librte_pipeline/rte_pipeline_version.map
@@ -62,6 +62,7 @@ EXPERIMENTAL {
 	rte_table_action_profile_freeze;
 	rte_table_action_table_params_get;
 	rte_table_action_stats_read;
+	rte_table_action_time_read;
 	rte_table_action_ttl_read;
 
 } DPDK_16.04;
diff --git a/lib/librte_pipeline/rte_table_action.c b/lib/librte_pipeline/rte_table_action.c
index 8bcc4eb..1a32c71 100644
--- a/lib/librte_pipeline/rte_table_action.c
+++ b/lib/librte_pipeline/rte_table_action.c
@@ -1149,6 +1149,28 @@ pkt_work_stats(struct stats_data *data,
 }
 
 /**
+ * RTE_TABLE_ACTION_TIME
+ */
+struct time_data {
+	uint64_t time;
+} __attribute__((__packed__));
+
+static int
+time_apply(struct time_data *data,
+	struct rte_table_action_time_params *p)
+{
+	data->time = p->time;
+	return 0;
+}
+
+static __rte_always_inline void
+pkt_work_time(struct time_data *data,
+	uint64_t time)
+{
+	data->time = time;
+}
+
+/**
  * Action profile
  */
 static int
@@ -1162,6 +1184,7 @@ action_valid(enum rte_table_action_type action)
 	case RTE_TABLE_ACTION_NAT:
 	case RTE_TABLE_ACTION_TTL:
 	case RTE_TABLE_ACTION_STATS:
+	case RTE_TABLE_ACTION_TIME:
 		return 1;
 	default:
 		return 0;
@@ -1276,6 +1299,9 @@ action_data_size(enum rte_table_action_type action,
 	case RTE_TABLE_ACTION_STATS:
 		return sizeof(struct stats_data);
 
+	case RTE_TABLE_ACTION_TIME:
+		return sizeof(struct time_data);
+
 	default:
 		return 0;
 	}
@@ -1512,6 +1538,10 @@ rte_table_action_apply(struct rte_table_action *action,
 		return stats_apply(action_data,
 			action_params);
 
+	case RTE_TABLE_ACTION_TIME:
+		return time_apply(action_data,
+			action_params);
+
 	default:
 		return -EINVAL;
 	}
@@ -1741,6 +1771,29 @@ rte_table_action_stats_read(struct rte_table_action *action,
 	return 0;
 }
 
+int
+rte_table_action_time_read(struct rte_table_action *action,
+	void *data,
+	uint64_t *timestamp)
+{
+	struct time_data *time_data;
+
+	/* Check input arguments */
+	if ((action == NULL) ||
+		((action->cfg.action_mask &
+		(1LLU << RTE_TABLE_ACTION_TIME)) == 0) ||
+		(data == NULL) ||
+		(timestamp == NULL))
+		return -EINVAL;
+
+	time_data = action_data_get(data, action, RTE_TABLE_ACTION_TIME);
+
+	/* Read */
+	*timestamp = time_data->time;
+
+	return 0;
+}
+
 static __rte_always_inline uint64_t
 pkt_work(struct rte_mbuf *mbuf,
 	struct rte_pipeline_table_entry *table_entry,
@@ -1831,6 +1884,13 @@ pkt_work(struct rte_mbuf *mbuf,
 		pkt_work_stats(data, total_length);
 	}
 
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_TIME)) {
+		void *data =
+			action_data_get(table_entry, action, RTE_TABLE_ACTION_TIME);
+
+		pkt_work_time(data, time);
+	}
+
 	return drop_mask;
 }
 
@@ -2076,6 +2136,22 @@ pkt4_work(struct rte_mbuf **mbufs,
 		pkt_work_stats(data3, total_length3);
 	}
 
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_TIME)) {
+		void *data0 =
+			action_data_get(table_entry0, action, RTE_TABLE_ACTION_TIME);
+		void *data1 =
+			action_data_get(table_entry1, action, RTE_TABLE_ACTION_TIME);
+		void *data2 =
+			action_data_get(table_entry2, action, RTE_TABLE_ACTION_TIME);
+		void *data3 =
+			action_data_get(table_entry3, action, RTE_TABLE_ACTION_TIME);
+
+		pkt_work_time(data0, time);
+		pkt_work_time(data1, time);
+		pkt_work_time(data2, time);
+		pkt_work_time(data3, time);
+	}
+
 	return drop_mask0 |
 		(drop_mask1 << 1) |
 		(drop_mask2 << 2) |
@@ -2093,7 +2169,8 @@ ah(struct rte_pipeline *p,
 	uint64_t pkts_drop_mask = 0;
 	uint64_t time = 0;
 
-	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_MTR))
+	if (cfg->action_mask & ((1LLU << RTE_TABLE_ACTION_MTR) |
+		(1LLU << RTE_TABLE_ACTION_TIME)))
 		time = rte_rdtsc();
 
 	if ((pkts_mask & (pkts_mask + 1)) == 0) {
diff --git a/lib/librte_pipeline/rte_table_action.h b/lib/librte_pipeline/rte_table_action.h
index 53b9866..e9b30ab 100644
--- a/lib/librte_pipeline/rte_table_action.h
+++ b/lib/librte_pipeline/rte_table_action.h
@@ -86,6 +86,9 @@ enum rte_table_action_type {
 
 	/** Statistics. */
 	RTE_TABLE_ACTION_STATS,
+
+	/** Timestamp. */
+	RTE_TABLE_ACTION_TIME,
 };
 
 /** Common action configuration (per table action profile). */
@@ -542,6 +545,15 @@ struct rte_table_action_stats_counters {
 };
 
 /**
+ * RTE_TABLE_ACTION_TIME
+ */
+/** Timestamp action parameters (per table rule). */
+struct rte_table_action_time_params {
+	/** Initial timestamp value. Typically set to current time. */
+	uint64_t time;
+};
+
+/**
  * Table action profile.
  */
 struct rte_table_action_profile;
@@ -815,6 +827,25 @@ rte_table_action_stats_read(struct rte_table_action *action,
 	struct rte_table_action_stats_counters *stats,
 	int clear);
 
+/**
+ * Table action timestamp read.
+ *
+ * @param[in] action
+ *   Handle to table action object (needs to be valid).
+ * @param[in] data
+ *   Data byte array (typically table rule data) with timestamp action
+ *   previously applied on it.
+ * @param[inout] timestamp
+ *   Pre-allocated memory where the timestamp read from *data* is saved (has to
+ *   be non-NULL).
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_table_action_time_read(struct rte_table_action *action,
+	void *data,
+	uint64_t *timestamp);
+
 #ifdef __cplusplus
 }
 #endif
-- 
2.9.3

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

* [dpdk-dev] [PATCH v4 10/49] pipeline: add load balance action
  2018-03-29 18:31           ` [dpdk-dev] [PATCH v4 00/49] ip_pipeline: refactoring Jasvinder Singh
                               ` (8 preceding siblings ...)
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 09/49] pipeline: add timestamp action Jasvinder Singh
@ 2018-03-29 18:31             ` Jasvinder Singh
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 11/49] pipeline: add pipeline port in action APIs Jasvinder Singh
                               ` (39 subsequent siblings)
  49 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-29 18:31 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add implementation of the load balance action.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 lib/librte_pipeline/rte_table_action.c | 102 +++++++++++++++++++++++++++++++++
 lib/librte_pipeline/rte_table_action.h |  52 +++++++++++++++++
 2 files changed, 154 insertions(+)

diff --git a/lib/librte_pipeline/rte_table_action.c b/lib/librte_pipeline/rte_table_action.c
index 1a32c71..83ffa5d 100644
--- a/lib/librte_pipeline/rte_table_action.c
+++ b/lib/librte_pipeline/rte_table_action.c
@@ -45,6 +45,55 @@ fwd_apply(struct fwd_data *data,
 }
 
 /**
+ * RTE_TABLE_ACTION_LB
+ */
+static int
+lb_cfg_check(struct rte_table_action_lb_config *cfg)
+{
+	if ((cfg == NULL) ||
+		(cfg->key_size < RTE_TABLE_ACTION_LB_KEY_SIZE_MIN) ||
+		(cfg->key_size > RTE_TABLE_ACTION_LB_KEY_SIZE_MAX) ||
+		(!rte_is_power_of_2(cfg->key_size)) ||
+		(cfg->f_hash == NULL))
+		return -1;
+
+	return 0;
+}
+
+struct lb_data {
+	uint32_t out[RTE_TABLE_ACTION_LB_TABLE_SIZE];
+} __attribute__((__packed__));
+
+static int
+lb_apply(struct lb_data *data,
+	struct rte_table_action_lb_params *p)
+{
+	memcpy(data->out, p->out, sizeof(data->out));
+
+	return 0;
+}
+
+static __rte_always_inline void
+pkt_work_lb(struct rte_mbuf *mbuf,
+	struct lb_data *data,
+	struct rte_table_action_lb_config *cfg)
+{
+	uint8_t *pkt_key = RTE_MBUF_METADATA_UINT8_PTR(mbuf, cfg->key_offset);
+	uint32_t *out = RTE_MBUF_METADATA_UINT32_PTR(mbuf, cfg->out_offset);
+	uint64_t digest, pos;
+	uint32_t out_val;
+
+	digest = cfg->f_hash(pkt_key,
+		cfg->key_mask,
+		cfg->key_size,
+		cfg->seed);
+	pos = digest & (RTE_TABLE_ACTION_LB_TABLE_SIZE - 1);
+	out_val = data->out[pos];
+
+	*out = out_val;
+}
+
+/**
  * RTE_TABLE_ACTION_MTR
  */
 static int
@@ -1178,6 +1227,7 @@ action_valid(enum rte_table_action_type action)
 {
 	switch (action) {
 	case RTE_TABLE_ACTION_FWD:
+	case RTE_TABLE_ACTION_LB:
 	case RTE_TABLE_ACTION_MTR:
 	case RTE_TABLE_ACTION_TM:
 	case RTE_TABLE_ACTION_ENCAP:
@@ -1197,6 +1247,7 @@ action_valid(enum rte_table_action_type action)
 struct ap_config {
 	uint64_t action_mask;
 	struct rte_table_action_common_config common;
+	struct rte_table_action_lb_config lb;
 	struct rte_table_action_mtr_config mtr;
 	struct rte_table_action_tm_config tm;
 	struct rte_table_action_encap_config encap;
@@ -1209,6 +1260,8 @@ static size_t
 action_cfg_size(enum rte_table_action_type action)
 {
 	switch (action) {
+	case RTE_TABLE_ACTION_LB:
+		return sizeof(struct rte_table_action_lb_config);
 	case RTE_TABLE_ACTION_MTR:
 		return sizeof(struct rte_table_action_mtr_config);
 	case RTE_TABLE_ACTION_TM:
@@ -1231,6 +1284,9 @@ action_cfg_get(struct ap_config *ap_config,
 	enum rte_table_action_type type)
 {
 	switch (type) {
+	case RTE_TABLE_ACTION_LB:
+		return &ap_config->lb;
+
 	case RTE_TABLE_ACTION_MTR:
 		return &ap_config->mtr;
 
@@ -1280,6 +1336,9 @@ action_data_size(enum rte_table_action_type action,
 	case RTE_TABLE_ACTION_FWD:
 		return sizeof(struct fwd_data);
 
+	case RTE_TABLE_ACTION_LB:
+		return sizeof(struct lb_data);
+
 	case RTE_TABLE_ACTION_MTR:
 		return mtr_data_size(&ap_config->mtr);
 
@@ -1373,6 +1432,10 @@ rte_table_action_profile_action_register(struct rte_table_action_profile *profil
 		return -EINVAL;
 
 	switch (type) {
+	case RTE_TABLE_ACTION_LB:
+		status = lb_cfg_check(action_config);
+		break;
+
 	case RTE_TABLE_ACTION_MTR:
 		status = mtr_cfg_check(action_config);
 		break;
@@ -1507,6 +1570,10 @@ rte_table_action_apply(struct rte_table_action *action,
 		return fwd_apply(action_data,
 			action_params);
 
+	case RTE_TABLE_ACTION_LB:
+		return lb_apply(action_data,
+			action_params);
+
 	case RTE_TABLE_ACTION_MTR:
 		return mtr_apply(action_data,
 			action_params,
@@ -1822,6 +1889,14 @@ pkt_work(struct rte_mbuf *mbuf,
 			rte_ntohs(hdr->payload_len) + sizeof(struct ipv6_hdr);
 	}
 
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_LB)) {
+		void *data =
+			action_data_get(table_entry, action, RTE_TABLE_ACTION_LB);
+
+		pkt_work_lb(mbuf,
+			data,
+			&cfg->lb);
+	}
 	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) {
 		void *data =
 			action_data_get(table_entry, action, RTE_TABLE_ACTION_MTR);
@@ -1961,6 +2036,33 @@ pkt4_work(struct rte_mbuf **mbufs,
 			rte_ntohs(hdr3->payload_len) + sizeof(struct ipv6_hdr);
 	}
 
+	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_LB)) {
+		void *data0 =
+			action_data_get(table_entry0, action, RTE_TABLE_ACTION_LB);
+		void *data1 =
+			action_data_get(table_entry1, action, RTE_TABLE_ACTION_LB);
+		void *data2 =
+			action_data_get(table_entry2, action, RTE_TABLE_ACTION_LB);
+		void *data3 =
+			action_data_get(table_entry3, action, RTE_TABLE_ACTION_LB);
+
+		pkt_work_lb(mbuf0,
+			data0,
+			&cfg->lb);
+
+		pkt_work_lb(mbuf1,
+			data1,
+			&cfg->lb);
+
+		pkt_work_lb(mbuf2,
+			data2,
+			&cfg->lb);
+
+		pkt_work_lb(mbuf3,
+			data3,
+			&cfg->lb);
+	}
+
 	if (cfg->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) {
 		void *data0 =
 			action_data_get(table_entry0, action, RTE_TABLE_ACTION_MTR);
diff --git a/lib/librte_pipeline/rte_table_action.h b/lib/librte_pipeline/rte_table_action.h
index e9b30ab..c7f751a 100644
--- a/lib/librte_pipeline/rte_table_action.h
+++ b/lib/librte_pipeline/rte_table_action.h
@@ -61,6 +61,7 @@ extern "C" {
 #include <rte_compat.h>
 #include <rte_ether.h>
 #include <rte_meter.h>
+#include <rte_table_hash.h>
 
 #include "rte_pipeline.h"
 
@@ -69,6 +70,9 @@ enum rte_table_action_type {
 	/** Forward to next pipeline table, output port or drop. */
 	RTE_TABLE_ACTION_FWD = 0,
 
+	/**  Load balance. */
+	RTE_TABLE_ACTION_LB,
+
 	/**  Traffic Metering and Policing. */
 	RTE_TABLE_ACTION_MTR,
 
@@ -117,6 +121,54 @@ struct rte_table_action_fwd_params {
 };
 
 /**
+ * RTE_TABLE_ACTION_LB
+ */
+/** Load balance key size min (number of bytes). */
+#define RTE_TABLE_ACTION_LB_KEY_SIZE_MIN                    8
+
+/** Load balance key size max (number of bytes). */
+#define RTE_TABLE_ACTION_LB_KEY_SIZE_MAX                    64
+
+/** Load balance table size. */
+#define RTE_TABLE_ACTION_LB_TABLE_SIZE                      8
+
+/** Load balance action configuration (per table action profile). */
+struct rte_table_action_lb_config {
+	/** Key size (number of bytes). */
+	uint32_t key_size;
+
+	/** Key offset within the input packet buffer. Offset 0 points to the
+	 * first byte of the MBUF structure.
+	 */
+	uint32_t key_offset;
+
+	/** Key mask (*key_size* bytes are valid). */
+	uint8_t key_mask[RTE_TABLE_ACTION_LB_KEY_SIZE_MAX];
+
+	/** Hash function. */
+	rte_table_hash_op_hash f_hash;
+
+	/** Seed value for *f_hash*. */
+	uint64_t seed;
+
+	/** Output value offset within the input packet buffer. Offset 0 points
+	 * to the first byte of the MBUF structure.
+	 */
+	uint32_t out_offset;
+};
+
+/** Load balance action parameters (per table rule). */
+struct rte_table_action_lb_params {
+	/** Table defining the output values and their weights. The weights are
+	 * set in 1/RTE_TABLE_ACTION_LB_TABLE_SIZE increments. To assign a
+	 * weight of N/RTE_TABLE_ACTION_LB_TABLE_SIZE to a given output value
+	 * (0 <= N <= RTE_TABLE_ACTION_LB_TABLE_SIZE), the same output value
+	 * needs to show up exactly N times in this table.
+	 */
+	uint32_t out[RTE_TABLE_ACTION_LB_TABLE_SIZE];
+};
+
+/**
  * RTE_TABLE_ACTION_MTR
  */
 /** Max number of traffic classes (TCs). */
-- 
2.9.3

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

* [dpdk-dev] [PATCH v4 11/49] pipeline: add pipeline port in action APIs
  2018-03-29 18:31           ` [dpdk-dev] [PATCH v4 00/49] ip_pipeline: refactoring Jasvinder Singh
                               ` (9 preceding siblings ...)
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 10/49] pipeline: add load balance action Jasvinder Singh
@ 2018-03-29 18:31             ` Jasvinder Singh
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 12/49] librte_table/acl: remove incorrect check Jasvinder Singh
                               ` (38 subsequent siblings)
  49 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-29 18:31 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

This API provides a common set of actions for pipeline input ports to speed
up application development.

Each pipeline input port can be assigned an action handler to be executed
on every input packet during the pipeline execution.

The pipeline library allows the user to define his own input port actions
by providing customized input port action handler. While the user can
still follow this process, this API is intended to provide a quicker
development alternative for a set of predefined actions.

The typical steps to use this API are:
* Define an input port action profile.
* Instantiate the input port action profile to create input port action
  objects.
* Use the input port action to generate the input port action handler
  invoked by the pipeline.
* Use the input port action object to generate the internal data structures
  used by the input port action handler based on given action parameters.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 lib/librte_pipeline/Makefile                 |   3 +-
 lib/librte_pipeline/meson.build              |   4 +-
 lib/librte_pipeline/rte_pipeline_version.map |   8 +
 lib/librte_pipeline/rte_port_in_action.c     | 531 +++++++++++++++++++++++++++
 lib/librte_pipeline/rte_port_in_action.h     | 301 +++++++++++++++
 5 files changed, 844 insertions(+), 3 deletions(-)
 create mode 100644 lib/librte_pipeline/rte_port_in_action.c
 create mode 100644 lib/librte_pipeline/rte_port_in_action.h

diff --git a/lib/librte_pipeline/Makefile b/lib/librte_pipeline/Makefile
index c0eaa09..84afe98 100644
--- a/lib/librte_pipeline/Makefile
+++ b/lib/librte_pipeline/Makefile
@@ -22,9 +22,10 @@ LIBABIVER := 3
 # all source are stored in SRCS-y
 #
 SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) := rte_pipeline.c
+SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += rte_port_in_action.c
 SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += rte_table_action.c
 
 # install includes
-SYMLINK-$(CONFIG_RTE_LIBRTE_PIPELINE)-include += rte_pipeline.h rte_table_action.h
+SYMLINK-$(CONFIG_RTE_LIBRTE_PIPELINE)-include += rte_pipeline.h rte_port_in_action.h rte_table_action.h
 
 include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_pipeline/meson.build b/lib/librte_pipeline/meson.build
index 1ee276f..dc16ab4 100644
--- a/lib/librte_pipeline/meson.build
+++ b/lib/librte_pipeline/meson.build
@@ -3,6 +3,6 @@
 
 version = 3
 allow_experimental_apis = true
-sources = files('rte_pipeline.c', 'rte_table_action.c')
-headers = files('rte_pipeline.h', 'rte_table_action.h')
+sources = files('rte_pipeline.c', 'rte_port_in_action.c', 'rte_table_action.c')
+headers = files('rte_pipeline.h', 'rte_port_in_action.h', 'rte_table_action.h')
 deps += ['port', 'table', 'meter', 'sched']
diff --git a/lib/librte_pipeline/rte_pipeline_version.map b/lib/librte_pipeline/rte_pipeline_version.map
index 4e948b8..53d31a9 100644
--- a/lib/librte_pipeline/rte_pipeline_version.map
+++ b/lib/librte_pipeline/rte_pipeline_version.map
@@ -49,6 +49,14 @@ DPDK_16.04 {
 EXPERIMENTAL {
 	global:
 
+	rte_port_in_action_apply;
+	rte_port_in_action_create;
+	rte_port_in_action_free;
+	rte_port_in_action_params_get;
+	rte_port_in_action_profile_action_register;
+	rte_port_in_action_profile_create;
+	rte_port_in_action_profile_free;
+	rte_port_in_action_profile_freeze;
 	rte_table_action_apply;
 	rte_table_action_create;
 	rte_table_action_dscp_table_update;
diff --git a/lib/librte_pipeline/rte_port_in_action.c b/lib/librte_pipeline/rte_port_in_action.c
new file mode 100644
index 0000000..e3b00df
--- /dev/null
+++ b/lib/librte_pipeline/rte_port_in_action.c
@@ -0,0 +1,531 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <rte_common.h>
+#include <rte_byteorder.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+
+#include "rte_port_in_action.h"
+
+/**
+ * RTE_PORT_IN_ACTION_FLTR
+ */
+static int
+fltr_cfg_check(struct rte_port_in_action_fltr_config *cfg)
+{
+	if (cfg == NULL)
+		return -1;
+
+	return 0;
+}
+
+struct fltr_data {
+	uint32_t port_id;
+};
+
+static void
+fltr_init(struct fltr_data *data,
+	struct rte_port_in_action_fltr_config *cfg)
+{
+	data->port_id = cfg->port_id;
+}
+
+static int
+fltr_apply(struct fltr_data *data,
+	struct rte_port_in_action_fltr_params *p)
+{
+	/* Check input arguments */
+	if (p == NULL)
+		return -1;
+
+	data->port_id = p->port_id;
+
+	return 0;
+}
+
+/**
+ * RTE_PORT_IN_ACTION_LB
+ */
+static int
+lb_cfg_check(struct rte_port_in_action_lb_config *cfg)
+{
+	if ((cfg == NULL) ||
+		(cfg->key_size < RTE_PORT_IN_ACTION_LB_KEY_SIZE_MIN) ||
+		(cfg->key_size > RTE_PORT_IN_ACTION_LB_KEY_SIZE_MAX) ||
+		(!rte_is_power_of_2(cfg->key_size)) ||
+		(cfg->f_hash == NULL))
+		return -1;
+
+	return 0;
+}
+
+struct lb_data {
+	uint32_t port_id[RTE_PORT_IN_ACTION_LB_TABLE_SIZE];
+};
+
+static void
+lb_init(struct lb_data *data,
+	struct rte_port_in_action_lb_config *cfg)
+{
+	memcpy(data->port_id, cfg->port_id, sizeof(cfg->port_id));
+}
+
+static int
+lb_apply(struct lb_data *data,
+	struct rte_port_in_action_lb_params *p)
+{
+	/* Check input arguments */
+	if (p == NULL)
+		return -1;
+
+	memcpy(data->port_id, p->port_id, sizeof(p->port_id));
+
+	return 0;
+}
+
+/**
+ * Action profile
+ */
+static int
+action_valid(enum rte_port_in_action_type action)
+{
+	switch (action) {
+	case RTE_PORT_IN_ACTION_FLTR:
+	case RTE_PORT_IN_ACTION_LB:
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+#define RTE_PORT_IN_ACTION_MAX                             64
+
+struct ap_config {
+	uint64_t action_mask;
+	struct rte_port_in_action_fltr_config fltr;
+	struct rte_port_in_action_lb_config lb;
+};
+
+static size_t
+action_cfg_size(enum rte_port_in_action_type action)
+{
+	switch (action) {
+	case RTE_PORT_IN_ACTION_FLTR:
+		return sizeof(struct rte_port_in_action_fltr_config);
+	case RTE_PORT_IN_ACTION_LB:
+		return sizeof(struct rte_port_in_action_lb_config);
+	default:
+		return 0;
+	}
+}
+
+static void*
+action_cfg_get(struct ap_config *ap_config,
+	enum rte_port_in_action_type type)
+{
+	switch (type) {
+	case RTE_PORT_IN_ACTION_FLTR:
+		return &ap_config->fltr;
+
+	case RTE_PORT_IN_ACTION_LB:
+		return &ap_config->lb;
+
+	default:
+		return NULL;
+	}
+}
+
+static void
+action_cfg_set(struct ap_config *ap_config,
+	enum rte_port_in_action_type type,
+	void *action_cfg)
+{
+	void *dst = action_cfg_get(ap_config, type);
+
+	if (dst)
+		memcpy(dst, action_cfg, action_cfg_size(type));
+
+	ap_config->action_mask |= 1LLU << type;
+}
+
+struct ap_data {
+	size_t offset[RTE_PORT_IN_ACTION_MAX];
+	size_t total_size;
+};
+
+static size_t
+action_data_size(enum rte_port_in_action_type action,
+	struct ap_config *ap_config __rte_unused)
+{
+	switch (action) {
+	case RTE_PORT_IN_ACTION_FLTR:
+		return sizeof(struct fltr_data);
+
+	case RTE_PORT_IN_ACTION_LB:
+		return sizeof(struct lb_data);
+
+	default:
+		return 0;
+	}
+}
+
+static void
+action_data_offset_set(struct ap_data *ap_data,
+	struct ap_config *ap_config)
+{
+	uint64_t action_mask = ap_config->action_mask;
+	size_t offset;
+	uint32_t action;
+
+	memset(ap_data->offset, 0, sizeof(ap_data->offset));
+
+	offset = 0;
+	for (action = 0; action < RTE_PORT_IN_ACTION_MAX; action++)
+		if (action_mask & (1LLU << action)) {
+			ap_data->offset[action] = offset;
+			offset += action_data_size((enum rte_port_in_action_type)action,
+				ap_config);
+		}
+
+	ap_data->total_size = offset;
+}
+
+struct rte_port_in_action_profile {
+	struct ap_config cfg;
+	struct ap_data data;
+	int frozen;
+};
+
+struct rte_port_in_action_profile *
+rte_port_in_action_profile_create(uint32_t socket_id)
+{
+	struct rte_port_in_action_profile *ap;
+
+	/* Memory allocation */
+	ap = rte_zmalloc_socket(NULL,
+		sizeof(struct rte_port_in_action_profile),
+		RTE_CACHE_LINE_SIZE,
+		socket_id);
+	if (ap == NULL)
+		return NULL;
+
+	return ap;
+}
+
+int
+rte_port_in_action_profile_action_register(struct rte_port_in_action_profile *profile,
+	enum rte_port_in_action_type type,
+	void *action_config)
+{
+	int status;
+
+	/* Check input arguments */
+	if ((profile == NULL) ||
+		profile->frozen ||
+		(action_valid(type) == 0) ||
+		(profile->cfg.action_mask & (1LLU << type)) ||
+		((action_cfg_size(type) == 0) && action_config) ||
+		(action_cfg_size(type) && (action_config == NULL)))
+		return -EINVAL;
+
+	switch (type) {
+	case RTE_PORT_IN_ACTION_FLTR:
+		status = fltr_cfg_check(action_config);
+		break;
+
+	case RTE_PORT_IN_ACTION_LB:
+		status = lb_cfg_check(action_config);
+		break;
+
+	default:
+		status = 0;
+		break;
+	}
+
+	if (status)
+		return status;
+
+	/* Action enable */
+	action_cfg_set(&profile->cfg, type, action_config);
+
+	return 0;
+}
+
+int
+rte_port_in_action_profile_freeze(struct rte_port_in_action_profile *profile)
+{
+	if (profile->frozen)
+		return -EBUSY;
+
+	action_data_offset_set(&profile->data, &profile->cfg);
+	profile->frozen = 1;
+
+	return 0;
+}
+
+int
+rte_port_in_action_profile_free(struct rte_port_in_action_profile *profile)
+{
+	if (profile == NULL)
+		return 0;
+
+	free(profile);
+	return 0;
+}
+
+/**
+ * Action
+ */
+struct rte_port_in_action {
+	struct ap_config cfg;
+	struct ap_data data;
+	uint8_t memory[0] __rte_cache_aligned;
+};
+
+static __rte_always_inline void *
+action_data_get(struct rte_port_in_action *action,
+	enum rte_port_in_action_type type)
+{
+	size_t offset = action->data.offset[type];
+
+	return &action->memory[offset];
+}
+
+static void
+action_data_init(struct rte_port_in_action *action,
+	enum rte_port_in_action_type type)
+{
+	void *data = action_data_get(action, type);
+
+	switch (type) {
+	case RTE_PORT_IN_ACTION_FLTR:
+		fltr_init(data, &action->cfg.fltr);
+		return;
+
+	case RTE_PORT_IN_ACTION_LB:
+		lb_init(data, &action->cfg.lb);
+		return;
+
+	default:
+		return;
+	}
+}
+
+struct rte_port_in_action *
+rte_port_in_action_create(struct rte_port_in_action_profile *profile,
+	uint32_t socket_id)
+{
+	struct rte_port_in_action *action;
+	size_t size;
+	uint32_t i;
+
+	/* Check input arguments */
+	if ((profile == NULL) ||
+		(profile->frozen == 0))
+		return NULL;
+
+	/* Memory allocation */
+	size = sizeof(struct rte_port_in_action) + profile->data.total_size;
+	size = RTE_CACHE_LINE_ROUNDUP(size);
+
+	action = rte_zmalloc_socket(NULL,
+		size,
+		RTE_CACHE_LINE_SIZE,
+		socket_id);
+	if (action == NULL)
+		return NULL;
+
+	/* Initialization */
+	memcpy(&action->cfg, &profile->cfg, sizeof(profile->cfg));
+	memcpy(&action->data, &profile->data, sizeof(profile->data));
+
+	for (i = 0; i < RTE_PORT_IN_ACTION_MAX; i++)
+		if (action->cfg.action_mask & (1LLU << i))
+			action_data_init(action,
+				(enum rte_port_in_action_type)i);
+
+	return action;
+}
+
+int
+rte_port_in_action_apply(struct rte_port_in_action *action,
+	enum rte_port_in_action_type type,
+	void *action_params)
+{
+	void *action_data;
+
+	/* Check input arguments */
+	if ((action == NULL) ||
+		(action_valid(type) == 0) ||
+		((action->cfg.action_mask & (1LLU << type)) == 0) ||
+		(action_params == NULL))
+		return -EINVAL;
+
+	/* Data update */
+	action_data = action_data_get(action, type);
+
+	switch (type) {
+	case RTE_PORT_IN_ACTION_FLTR:
+		return fltr_apply(action_data,
+			action_params);
+
+	case RTE_PORT_IN_ACTION_LB:
+		return lb_apply(action_data,
+			action_params);
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static int
+ah_filter_on_match(struct rte_pipeline *p,
+	struct rte_mbuf **pkts,
+	uint32_t n_pkts,
+	void *arg)
+{
+	struct rte_port_in_action *action = arg;
+	struct rte_port_in_action_fltr_config *cfg = &action->cfg.fltr;
+	uint64_t *key_mask = (uint64_t *) cfg->key_mask;
+	uint64_t *key = (uint64_t *) cfg->key;
+	uint32_t key_offset = cfg->key_offset;
+	struct fltr_data *data = action_data_get(action,
+						RTE_PORT_IN_ACTION_FLTR);
+	uint32_t i;
+
+	for (i = 0; i < n_pkts; i++) {
+		struct rte_mbuf *pkt = pkts[i];
+		uint64_t *pkt_key = RTE_MBUF_METADATA_UINT64_PTR(pkt,
+					key_offset);
+
+		uint64_t xor0 = (pkt_key[0] & key_mask[0]) ^ key[0];
+		uint64_t xor1 = (pkt_key[1] & key_mask[1]) ^ key[1];
+		uint64_t or = xor0 | xor1;
+
+		if (or == 0) {
+			rte_pipeline_ah_packet_hijack(p, 1LLU << i);
+			rte_pipeline_port_out_packet_insert(p,
+				data->port_id, pkt);
+		}
+	}
+
+	return 0;
+}
+
+static int
+ah_filter_on_mismatch(struct rte_pipeline *p,
+	struct rte_mbuf **pkts,
+	uint32_t n_pkts,
+	void *arg)
+{
+	struct rte_port_in_action *action = arg;
+	struct rte_port_in_action_fltr_config *cfg = &action->cfg.fltr;
+	uint64_t *key_mask = (uint64_t *) cfg->key_mask;
+	uint64_t *key = (uint64_t *) cfg->key;
+	uint32_t key_offset = cfg->key_offset;
+	struct fltr_data *data = action_data_get(action,
+						RTE_PORT_IN_ACTION_FLTR);
+	uint32_t i;
+
+	for (i = 0; i < n_pkts; i++) {
+		struct rte_mbuf *pkt = pkts[i];
+		uint64_t *pkt_key = RTE_MBUF_METADATA_UINT64_PTR(pkt,
+						key_offset);
+
+		uint64_t xor0 = (pkt_key[0] & key_mask[0]) ^ key[0];
+		uint64_t xor1 = (pkt_key[1] & key_mask[1]) ^ key[1];
+		uint64_t or = xor0 | xor1;
+
+		if (or) {
+			rte_pipeline_ah_packet_hijack(p, 1LLU << i);
+			rte_pipeline_port_out_packet_insert(p,
+				data->port_id, pkt);
+		}
+	}
+
+	return 0;
+}
+
+static int
+ah_lb(struct rte_pipeline *p,
+	struct rte_mbuf **pkts,
+	uint32_t n_pkts,
+	void *arg)
+{
+	struct rte_port_in_action *action = arg;
+	struct rte_port_in_action_lb_config *cfg = &action->cfg.lb;
+	struct lb_data *data = action_data_get(action, RTE_PORT_IN_ACTION_LB);
+	uint64_t pkt_mask = RTE_LEN2MASK(n_pkts, uint64_t);
+	uint32_t i;
+
+	rte_pipeline_ah_packet_hijack(p, pkt_mask);
+
+	for (i = 0; i < n_pkts; i++) {
+		struct rte_mbuf *pkt = pkts[i];
+		uint8_t *pkt_key = RTE_MBUF_METADATA_UINT8_PTR(pkt,
+					cfg->key_offset);
+
+		uint64_t digest = cfg->f_hash(pkt_key,
+			cfg->key_mask,
+			cfg->key_size,
+			cfg->seed);
+		uint64_t pos = digest & (RTE_PORT_IN_ACTION_LB_TABLE_SIZE - 1);
+		uint32_t port_id = data->port_id[pos];
+
+		rte_pipeline_port_out_packet_insert(p, port_id, pkt);
+	}
+
+	return 0;
+}
+
+static rte_pipeline_port_in_action_handler
+ah_selector(struct rte_port_in_action *action)
+{
+	if (action->cfg.action_mask == 0)
+		return NULL;
+
+	if (action->cfg.action_mask == 1LLU << RTE_PORT_IN_ACTION_FLTR)
+		return (action->cfg.fltr.filter_on_match) ?
+			ah_filter_on_match : ah_filter_on_mismatch;
+
+	if (action->cfg.action_mask == 1LLU << RTE_PORT_IN_ACTION_LB)
+		return ah_lb;
+
+	return NULL;
+}
+
+int
+rte_port_in_action_params_get(struct rte_port_in_action *action,
+	struct rte_pipeline_port_in_params *params)
+{
+	rte_pipeline_port_in_action_handler f_action;
+
+	/* Check input arguments */
+	if ((action == NULL) ||
+		(params == NULL))
+		return -EINVAL;
+
+	f_action = ah_selector(action);
+
+	/* Fill in params */
+	params->f_action = f_action;
+	params->arg_ah = (f_action) ? action : NULL;
+
+	return 0;
+}
+
+int
+rte_port_in_action_free(struct rte_port_in_action *action)
+{
+	if (action == NULL)
+		return 0;
+
+	rte_free(action);
+
+	return 0;
+}
diff --git a/lib/librte_pipeline/rte_port_in_action.h b/lib/librte_pipeline/rte_port_in_action.h
new file mode 100644
index 0000000..da5320b
--- /dev/null
+++ b/lib/librte_pipeline/rte_port_in_action.h
@@ -0,0 +1,301 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation
+ */
+
+#ifndef __INCLUDE_RTE_PORT_IN_ACTION_H__
+#define __INCLUDE_RTE_PORT_IN_ACTION_H__
+
+/**
+ * @file
+ * RTE Pipeline Input Port Actions
+ *
+ * This API provides a common set of actions for pipeline input ports to speed
+ * up application development.
+ *
+ * Each pipeline input port can be assigned an action handler to be executed
+ * on every input packet during the pipeline execution. The pipeline library
+ * allows the user to define his own input port actions by providing customized
+ * input port action handler. While the user can still follow this process, this
+ * API is intended to provide a quicker development alternative for a set of
+ * predefined actions.
+ *
+ * The typical steps to use this API are:
+ *  - Define an input port action profile. This is a configuration template that
+ *    can potentially be shared by multiple input ports from the same or
+ *    different pipelines, with different input ports from the same pipeline
+ *    able to use different action profiles. For every input port using a given
+ *    action profile, the profile defines the set of actions and the action
+ *    configuration to be executed by the input port. API functions:
+ *    rte_port_in_action_profile_create(),
+ *    rte_port_in_action_profile_action_register(),
+ *    rte_port_in_action_profile_freeze().
+ *
+ *  - Instantiate the input port action profile to create input port action
+ *    objects. Each pipeline input port has its own action object.
+ *    API functions: rte_port_in_action_create().
+ *
+ *  - Use the input port action object to generate the input port action handler
+ *    invoked by the pipeline. API functions:
+ *    rte_port_in_action_params_get().
+ *
+ *  - Use the input port action object to generate the internal data structures
+ *    used by the input port action handler based on given action parameters.
+ *    API functions: rte_port_in_action_apply().
+ *
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+
+#include <rte_compat.h>
+#include <rte_table_hash.h>
+
+#include "rte_pipeline.h"
+
+/** Input port actions. */
+enum rte_port_in_action_type {
+	/** Filter selected input packets. */
+	RTE_PORT_IN_ACTION_FLTR = 0,
+
+	/**  Load balance. */
+	RTE_PORT_IN_ACTION_LB,
+};
+
+/**
+ * RTE_PORT_IN_ACTION_FLTR
+ */
+/** Filter key size (number of bytes) */
+#define RTE_PORT_IN_ACTION_FLTR_KEY_SIZE                   16
+
+/** Filter action configuration (per action profile). */
+struct rte_port_in_action_fltr_config {
+	/** Key offset within the input packet buffer. Offset 0 points to the
+	 * first byte of the MBUF structure.
+	 */
+	uint32_t key_offset;
+
+	/** Key mask. */
+	uint8_t key_mask[RTE_PORT_IN_ACTION_FLTR_KEY_SIZE];
+
+	/** Key value. */
+	uint8_t key[RTE_PORT_IN_ACTION_FLTR_KEY_SIZE];
+
+	/** When non-zero, all the input packets that match the *key* (with the
+	* *key_mask* applied) are sent to the pipeline output port *port_id*.
+	* When zero, all the input packets that do NOT match the *key* (with the
+	* *key_mask* applied) are sent to the pipeline output port *port_id*.
+	*/
+	int filter_on_match;
+
+	/** Pipeline output port ID to send the filtered input packets to.
+	 * Can be updated later.
+	 *
+	 * @see struct rte_port_in_action_fltr_params
+	 */
+	uint32_t port_id;
+};
+
+/** Filter action parameters (per action). */
+struct rte_port_in_action_fltr_params {
+	/** Pipeline output port ID to send the filtered input packets to. */
+	uint32_t port_id;
+};
+
+/**
+ * RTE_PORT_IN_ACTION_LB
+ */
+/** Load balance key size min (number of bytes). */
+#define RTE_PORT_IN_ACTION_LB_KEY_SIZE_MIN                    8
+
+/** Load balance key size max (number of bytes). */
+#define RTE_PORT_IN_ACTION_LB_KEY_SIZE_MAX                    64
+
+/** Load balance table size. */
+#define RTE_PORT_IN_ACTION_LB_TABLE_SIZE                   16
+
+/** Load balance action configuration (per action profile). */
+struct rte_port_in_action_lb_config {
+	/** Key size (number of bytes). */
+	uint32_t key_size;
+
+	/** Key offset within the input packet buffer. Offset 0 points to the
+	 * first byte of the MBUF structure.
+	 */
+	uint32_t key_offset;
+
+	/** Key mask(*key_size* bytes are valid). */
+	uint8_t key_mask[RTE_PORT_IN_ACTION_LB_KEY_SIZE_MAX];
+
+	/** Hash function. */
+	rte_table_hash_op_hash f_hash;
+
+	/** Seed value for *f_hash*. */
+	uint64_t seed;
+
+	/** Table defining the weight of each pipeline output port. The weights
+	 * are set in 1/RTE_PORT_IN_ACTION_LB_TABLE_SIZE increments. To assign a
+	 * weight of N/RTE_PORT_IN_ACTION_LB_TABLE_SIZE to a given output port
+	 * (0 <= N <= RTE_PORT_IN_ACTION_LB_TABLE_SIZE), the output port needs
+	 * to show up exactly N times in this table. Can be updated later.
+	 *
+	 * @see struct rte_port_in_action_lb_params
+	 */
+	uint32_t port_id[RTE_PORT_IN_ACTION_LB_TABLE_SIZE];
+};
+
+/** Load balance action parameters (per action). */
+struct rte_port_in_action_lb_params {
+	/** Table defining the weight of each pipeline output port. The weights
+	 * are set in 1/RTE_PORT_IN_ACTION_LB_TABLE_SIZE increments. To assign a
+	 * weight of N/RTE_PORT_IN_ACTION_LB_TABLE_SIZE to a given output port
+	 * (0 <= N <= RTE_PORT_IN_ACTION_LB_TABLE_SIZE), the output port needs
+	 * to show up exactly N times in this table.
+	 */
+	uint32_t port_id[RTE_PORT_IN_ACTION_LB_TABLE_SIZE];
+};
+
+/**
+ * Input port action profile.
+ */
+struct rte_port_in_action_profile;
+
+/**
+ * Input port action profile create.
+ *
+ * @param[in] socket_id
+ *   CPU socket ID for the internal data structures memory allocation.
+ * @return
+ *   Input port action profile handle on success, NULL otherwise.
+ */
+struct rte_port_in_action_profile * __rte_experimental
+rte_port_in_action_profile_create(uint32_t socket_id);
+
+/**
+ * Input port action profile free.
+ *
+ * @param[in] profile
+ *   Input port action profile handle (needs to be valid).
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_port_in_action_profile_free(struct rte_port_in_action_profile *profile);
+
+/**
+ * Input port action profile action register.
+ *
+ * @param[in] profile
+ *   Input port action profile handle (needs to be valid and not in frozen
+ *   state).
+ * @param[in] type
+ *   Specific input port action to be registered for *profile*.
+ * @param[in] action_config
+ *   Configuration for the *type* action.
+ *   If struct rte_port_in_action_*type*_config is defined, it needs to point to
+ *   a valid instance of this structure, otherwise it needs to be set to NULL.
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_port_in_action_profile_action_register(
+	struct rte_port_in_action_profile *profile,
+	enum rte_port_in_action_type type,
+	void *action_config);
+
+/**
+ * Input port action profile freeze.
+ *
+ * Once this function is called successfully, the given profile enters the
+ * frozen state with the following immediate effects: no more actions can be
+ * registered for this profile, so the profile can be instantiated to create
+ * input port action objects.
+ *
+ * @param[in] profile
+ *   Input port profile action handle (needs to be valid and not in frozen
+ *   state).
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ *
+ * @see rte_port_in_action_create()
+ */
+int __rte_experimental
+rte_port_in_action_profile_freeze(struct rte_port_in_action_profile *profile);
+
+/**
+ * Input port action.
+ */
+struct rte_port_in_action;
+
+/**
+ * Input port action create.
+ *
+ * Instantiates the given input port action profile to create an input port
+ * action object.
+ *
+ * @param[in] profile
+ *   Input port profile action handle (needs to be valid and in frozen state).
+ * @param[in] socket_id
+ *   CPU socket ID where the internal data structures required by the new input
+ *   port action object should be allocated.
+ * @return
+ *   Handle to input port action object on success, NULL on error.
+ */
+struct rte_port_in_action * __rte_experimental
+rte_port_in_action_create(struct rte_port_in_action_profile *profile,
+	uint32_t socket_id);
+
+/**
+ * Input port action free.
+ *
+ * @param[in] action
+ *   Handle to input port action object (needs to be valid).
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_port_in_action_free(struct rte_port_in_action *action);
+
+/**
+ * Input port params get.
+ *
+ * @param[in] action
+ *   Handle to input port action object (needs to be valid).
+ * @param[inout] params
+ *   Pipeline input port parameters (needs to be pre-allocated).
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_port_in_action_params_get(struct rte_port_in_action *action,
+	struct rte_pipeline_port_in_params *params);
+
+/**
+ * Input port action apply.
+ *
+ * @param[in] action
+ *   Handle to input port action object (needs to be valid).
+ * @param[in] type
+ *   Specific input port action previously registered for the input port action
+ *   profile of the *action* object.
+ * @param[in] action_params
+ *   Parameters for the *type* action.
+ *   If struct rte_port_in_action_*type*_params is defined, it needs to point to
+ *   a valid instance of this structure, otherwise it needs to be set to NULL.
+ * @return
+ *   Zero on success, non-zero error code otherwise.
+ */
+int __rte_experimental
+rte_port_in_action_apply(struct rte_port_in_action *action,
+	enum rte_port_in_action_type type,
+	void *action_params);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __INCLUDE_RTE_PORT_IN_ACTION_H__ */
-- 
2.9.3

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

* [dpdk-dev] [PATCH v4 12/49] librte_table/acl: remove incorrect check
  2018-03-29 18:31           ` [dpdk-dev] [PATCH v4 00/49] ip_pipeline: refactoring Jasvinder Singh
                               ` (10 preceding siblings ...)
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 11/49] pipeline: add pipeline port in action APIs Jasvinder Singh
@ 2018-03-29 18:31             ` Jasvinder Singh
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 13/49] ip_pipeline: remove passthrough pipeline Jasvinder Singh
                               ` (37 subsequent siblings)
  49 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-29 18:31 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Remove wrong check for table entry pointer.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 lib/librte_table/rte_table_acl.c | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/lib/librte_table/rte_table_acl.c b/lib/librte_table/rte_table_acl.c
index 73d3910..14d5401 100644
--- a/lib/librte_table/rte_table_acl.c
+++ b/lib/librte_table/rte_table_acl.c
@@ -472,12 +472,6 @@ rte_table_acl_entry_add_bulk(
 			return -EINVAL;
 		}
 
-		if (entries_ptr[i] == NULL) {
-			RTE_LOG(ERR, TABLE, "%s: entries_ptr[%" PRIu32 "] parameter is NULL\n",
-					__func__, i);
-			return -EINVAL;
-		}
-
 		rule = keys[i];
 		if (rule->priority > RTE_ACL_MAX_PRIORITY) {
 			RTE_LOG(ERR, TABLE, "%s: Priority is too high\n", __func__);
-- 
2.9.3

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

* [dpdk-dev] [PATCH v4 13/49] ip_pipeline: remove passthrough pipeline
  2018-03-29 18:31           ` [dpdk-dev] [PATCH v4 00/49] ip_pipeline: refactoring Jasvinder Singh
                               ` (11 preceding siblings ...)
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 12/49] librte_table/acl: remove incorrect check Jasvinder Singh
@ 2018-03-29 18:31             ` Jasvinder Singh
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 14/49] ip_pipeline: remove routing pipeline Jasvinder Singh
                               ` (36 subsequent siblings)
  49 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-29 18:31 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

remove passthrough pipeline.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/Makefile                      |   2 -
 examples/ip_pipeline/init.c                        |   2 -
 examples/ip_pipeline/meson.build                   |   2 -
 .../ip_pipeline/pipeline/pipeline_passthrough.c    |  45 -
 .../ip_pipeline/pipeline/pipeline_passthrough.h    |  12 -
 .../ip_pipeline/pipeline/pipeline_passthrough_be.c | 929 ---------------------
 .../ip_pipeline/pipeline/pipeline_passthrough_be.h |  44 -
 7 files changed, 1036 deletions(-)
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_passthrough.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_passthrough.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_passthrough_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_passthrough_be.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index 85fbbaf..089c269 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -19,8 +19,6 @@ SRCS-y += pipeline_common_be.c
 SRCS-y += pipeline_common_fe.c
 SRCS-y += pipeline_master_be.c
 SRCS-y += pipeline_master.c
-SRCS-y += pipeline_passthrough_be.c
-SRCS-y += pipeline_passthrough.c
 SRCS-y += pipeline_firewall_be.c
 SRCS-y += pipeline_firewall.c
 SRCS-y += pipeline_flow_classification_be.c
diff --git a/examples/ip_pipeline/init.c b/examples/ip_pipeline/init.c
index bb07efa..73b93d7 100644
--- a/examples/ip_pipeline/init.c
+++ b/examples/ip_pipeline/init.c
@@ -26,7 +26,6 @@
 #include "pipeline.h"
 #include "pipeline_common_fe.h"
 #include "pipeline_master.h"
-#include "pipeline_passthrough.h"
 #include "pipeline_firewall.h"
 #include "pipeline_flow_classification.h"
 #include "pipeline_flow_actions.h"
@@ -1822,7 +1821,6 @@ int app_init(struct app_params *app)
 	app_pipeline_common_cmd_push(app);
 	app_pipeline_thread_cmd_push(app);
 	app_pipeline_type_register(app, &pipeline_master);
-	app_pipeline_type_register(app, &pipeline_passthrough);
 	app_pipeline_type_register(app, &pipeline_flow_classification);
 	app_pipeline_type_register(app, &pipeline_flow_actions);
 	app_pipeline_type_register(app, &pipeline_firewall);
diff --git a/examples/ip_pipeline/meson.build b/examples/ip_pipeline/meson.build
index 00d4033..17f4e16 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -29,8 +29,6 @@ sources = files(
 	'pipeline/pipeline_flow_classification.c',
 	'pipeline/pipeline_master_be.c',
 	'pipeline/pipeline_master.c',
-	'pipeline/pipeline_passthrough_be.c',
-	'pipeline/pipeline_passthrough.c',
 	'pipeline/pipeline_routing_be.c',
 	'pipeline/pipeline_routing.c',
 )
diff --git a/examples/ip_pipeline/pipeline/pipeline_passthrough.c b/examples/ip_pipeline/pipeline/pipeline_passthrough.c
deleted file mode 100644
index 031f5f0..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_passthrough.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#include "pipeline_passthrough.h"
-#include "pipeline_passthrough_be.h"
-
-static int
-app_pipeline_passthrough_track(struct pipeline_params *p,
-	uint32_t port_in,
-	uint32_t *port_out)
-{
-	struct pipeline_passthrough_params pp;
-	int status;
-
-	/* Check input arguments */
-	if ((p == NULL) ||
-		(port_in >= p->n_ports_in) ||
-		(port_out == NULL))
-		return -1;
-
-	status = pipeline_passthrough_parse_args(&pp, p);
-	if (status)
-		return -1;
-
-	if (pp.dma_hash_lb_enabled)
-		return -1;
-
-	*port_out = port_in / (p->n_ports_in / p->n_ports_out);
-	return 0;
-}
-
-static struct pipeline_fe_ops pipeline_passthrough_fe_ops = {
-	.f_init = NULL,
-	.f_post_init = NULL,
-	.f_free = NULL,
-	.f_track = app_pipeline_passthrough_track,
-	.cmds = NULL,
-};
-
-struct pipeline_type pipeline_passthrough = {
-	.name = "PASS-THROUGH",
-	.be_ops = &pipeline_passthrough_be_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
deleted file mode 100644
index 7a7a2fc..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_passthrough.h
+++ /dev/null
@@ -1,12 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#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_be.c b/examples/ip_pipeline/pipeline/pipeline_passthrough_be.c
deleted file mode 100644
index b2bbaed..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_passthrough_be.c
+++ /dev/null
@@ -1,929 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2016 Intel Corporation
- */
-
-#include <stdio.h>
-#include <string.h>
-
-#include <rte_common.h>
-#include <rte_malloc.h>
-#include <rte_byteorder.h>
-#include <rte_table_stub.h>
-#include <rte_table_hash.h>
-#include <rte_pipeline.h>
-
-#include "pipeline_passthrough_be.h"
-#include "pipeline_actions_common.h"
-#include "parser.h"
-#include "hash_func.h"
-
-#define SWAP_DIM (PIPELINE_PASSTHROUGH_SWAP_N_FIELDS_MAX * \
-	(PIPELINE_PASSTHROUGH_SWAP_FIELD_SIZE_MAX / sizeof(uint64_t)))
-
-struct pipeline_passthrough {
-	struct pipeline p;
-	struct pipeline_passthrough_params params;
-	rte_table_hash_op_hash f_hash;
-	uint32_t swap_field0_offset[SWAP_DIM];
-	uint32_t swap_field1_offset[SWAP_DIM];
-	uint64_t swap_field_mask[SWAP_DIM];
-	uint32_t swap_n_fields;
-} __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 __rte_always_inline void
-pkt_work_dma(
-	struct rte_mbuf *pkt,
-	void *arg,
-	uint32_t dma_size,
-	uint32_t hash_enabled,
-	uint32_t lb_hash,
-	uint32_t port_out_pow2)
-{
-	struct pipeline_passthrough *p = arg;
-
-	uint64_t *dma_dst = RTE_MBUF_METADATA_UINT64_PTR(pkt,
-		p->params.dma_dst_offset);
-	uint64_t *dma_src = RTE_MBUF_METADATA_UINT64_PTR(pkt,
-		p->params.dma_src_offset);
-	uint64_t *dma_mask = (uint64_t *) p->params.dma_src_mask;
-	uint32_t *dma_hash = RTE_MBUF_METADATA_UINT32_PTR(pkt,
-		p->params.dma_hash_offset);
-	uint32_t i;
-
-	/* Read (dma_src), compute (dma_dst), write (dma_dst) */
-	for (i = 0; i < (dma_size / 8); i++)
-		dma_dst[i] = dma_src[i] & dma_mask[i];
-
-	/* Read (dma_dst), compute (hash), write (hash) */
-	if (hash_enabled) {
-		uint32_t hash = p->f_hash(dma_src, dma_mask, dma_size, 0);
-		*dma_hash = hash;
-
-		if (lb_hash) {
-			uint32_t port_out;
-
-			if (port_out_pow2)
-				port_out
-					= hash & (p->p.n_ports_out - 1);
-			else
-				port_out
-					= hash % p->p.n_ports_out;
-
-			rte_pipeline_port_out_packet_insert(p->p.p,
-				port_out, pkt);
-		}
-	}
-}
-
-static __rte_always_inline void
-pkt4_work_dma(
-	struct rte_mbuf **pkts,
-	void *arg,
-	uint32_t dma_size,
-	uint32_t hash_enabled,
-	uint32_t lb_hash,
-	uint32_t port_out_pow2)
-{
-	struct pipeline_passthrough *p = arg;
-
-	uint64_t *dma_dst0 = RTE_MBUF_METADATA_UINT64_PTR(pkts[0],
-		p->params.dma_dst_offset);
-	uint64_t *dma_dst1 = RTE_MBUF_METADATA_UINT64_PTR(pkts[1],
-		p->params.dma_dst_offset);
-	uint64_t *dma_dst2 = RTE_MBUF_METADATA_UINT64_PTR(pkts[2],
-		p->params.dma_dst_offset);
-	uint64_t *dma_dst3 = RTE_MBUF_METADATA_UINT64_PTR(pkts[3],
-		p->params.dma_dst_offset);
-
-	uint64_t *dma_src0 = RTE_MBUF_METADATA_UINT64_PTR(pkts[0],
-		p->params.dma_src_offset);
-	uint64_t *dma_src1 = RTE_MBUF_METADATA_UINT64_PTR(pkts[1],
-		p->params.dma_src_offset);
-	uint64_t *dma_src2 = RTE_MBUF_METADATA_UINT64_PTR(pkts[2],
-		p->params.dma_src_offset);
-	uint64_t *dma_src3 = RTE_MBUF_METADATA_UINT64_PTR(pkts[3],
-		p->params.dma_src_offset);
-
-	uint64_t *dma_mask = (uint64_t *) p->params.dma_src_mask;
-
-	uint32_t *dma_hash0 = RTE_MBUF_METADATA_UINT32_PTR(pkts[0],
-		p->params.dma_hash_offset);
-	uint32_t *dma_hash1 = RTE_MBUF_METADATA_UINT32_PTR(pkts[1],
-		p->params.dma_hash_offset);
-	uint32_t *dma_hash2 = RTE_MBUF_METADATA_UINT32_PTR(pkts[2],
-		p->params.dma_hash_offset);
-	uint32_t *dma_hash3 = RTE_MBUF_METADATA_UINT32_PTR(pkts[3],
-		p->params.dma_hash_offset);
-
-	uint32_t i;
-
-	/* Read (dma_src), compute (dma_dst), write (dma_dst) */
-	for (i = 0; i < (dma_size / 8); i++) {
-		dma_dst0[i] = dma_src0[i] & dma_mask[i];
-		dma_dst1[i] = dma_src1[i] & dma_mask[i];
-		dma_dst2[i] = dma_src2[i] & dma_mask[i];
-		dma_dst3[i] = dma_src3[i] & dma_mask[i];
-	}
-
-	/* Read (dma_dst), compute (hash), write (hash) */
-	if (hash_enabled) {
-		uint32_t hash0 = p->f_hash(dma_src0, dma_mask, dma_size, 0);
-		uint32_t hash1 = p->f_hash(dma_src1, dma_mask, dma_size, 0);
-		uint32_t hash2 = p->f_hash(dma_src2, dma_mask, dma_size, 0);
-		uint32_t hash3 = p->f_hash(dma_src3, dma_mask, dma_size, 0);
-
-		*dma_hash0 = hash0;
-		*dma_hash1 = hash1;
-		*dma_hash2 = hash2;
-		*dma_hash3 = hash3;
-
-		if (lb_hash) {
-			uint32_t port_out0, port_out1, port_out2, port_out3;
-
-			if (port_out_pow2) {
-				port_out0
-					= hash0 & (p->p.n_ports_out - 1);
-				port_out1
-					= hash1 & (p->p.n_ports_out - 1);
-				port_out2
-					= hash2 & (p->p.n_ports_out - 1);
-				port_out3
-					= hash3 & (p->p.n_ports_out - 1);
-			} else {
-				port_out0
-					= hash0 % p->p.n_ports_out;
-				port_out1
-					= hash1 % p->p.n_ports_out;
-				port_out2
-					= hash2 % p->p.n_ports_out;
-				port_out3
-					= hash3 % p->p.n_ports_out;
-			}
-			rte_pipeline_port_out_packet_insert(p->p.p,
-				port_out0, pkts[0]);
-			rte_pipeline_port_out_packet_insert(p->p.p,
-				port_out1, pkts[1]);
-			rte_pipeline_port_out_packet_insert(p->p.p,
-				port_out2, pkts[2]);
-			rte_pipeline_port_out_packet_insert(p->p.p,
-				port_out3, pkts[3]);
-		}
-	}
-}
-
-static __rte_always_inline void
-pkt_work_swap(
-	struct rte_mbuf *pkt,
-	void *arg)
-{
-	struct pipeline_passthrough *p = arg;
-	uint32_t i;
-
-	/* Read(field0, field1), compute(field0, field1), write(field0, field1) */
-	for (i = 0; i < p->swap_n_fields; i++) {
-		uint64_t *field0_ptr = RTE_MBUF_METADATA_UINT64_PTR(pkt,
-			p->swap_field0_offset[i]);
-		uint64_t *field1_ptr = RTE_MBUF_METADATA_UINT64_PTR(pkt,
-			p->swap_field1_offset[i]);
-		uint64_t mask = p->swap_field_mask[i];
-
-		uint64_t field0 = *field0_ptr;
-		uint64_t field1 = *field1_ptr;
-
-		*field0_ptr = (field0 & (~mask)) + (field1 & mask);
-		*field1_ptr = (field0 & mask) + (field1 & (~mask));
-	}
-}
-
-static __rte_always_inline void
-pkt4_work_swap(
-	struct rte_mbuf **pkts,
-	void *arg)
-{
-	struct pipeline_passthrough *p = arg;
-	uint32_t i;
-
-	/* Read(field0, field1), compute(field0, field1), write(field0, field1) */
-	for (i = 0; i < p->swap_n_fields; i++) {
-		uint64_t *pkt0_field0_ptr = RTE_MBUF_METADATA_UINT64_PTR(pkts[0],
-			p->swap_field0_offset[i]);
-		uint64_t *pkt1_field0_ptr = RTE_MBUF_METADATA_UINT64_PTR(pkts[1],
-			p->swap_field0_offset[i]);
-		uint64_t *pkt2_field0_ptr = RTE_MBUF_METADATA_UINT64_PTR(pkts[2],
-			p->swap_field0_offset[i]);
-		uint64_t *pkt3_field0_ptr = RTE_MBUF_METADATA_UINT64_PTR(pkts[3],
-			p->swap_field0_offset[i]);
-
-		uint64_t *pkt0_field1_ptr = RTE_MBUF_METADATA_UINT64_PTR(pkts[0],
-			p->swap_field1_offset[i]);
-		uint64_t *pkt1_field1_ptr = RTE_MBUF_METADATA_UINT64_PTR(pkts[1],
-			p->swap_field1_offset[i]);
-		uint64_t *pkt2_field1_ptr = RTE_MBUF_METADATA_UINT64_PTR(pkts[2],
-			p->swap_field1_offset[i]);
-		uint64_t *pkt3_field1_ptr = RTE_MBUF_METADATA_UINT64_PTR(pkts[3],
-			p->swap_field1_offset[i]);
-
-		uint64_t mask = p->swap_field_mask[i];
-
-		uint64_t pkt0_field0 = *pkt0_field0_ptr;
-		uint64_t pkt1_field0 = *pkt1_field0_ptr;
-		uint64_t pkt2_field0 = *pkt2_field0_ptr;
-		uint64_t pkt3_field0 = *pkt3_field0_ptr;
-
-		uint64_t pkt0_field1 = *pkt0_field1_ptr;
-		uint64_t pkt1_field1 = *pkt1_field1_ptr;
-		uint64_t pkt2_field1 = *pkt2_field1_ptr;
-		uint64_t pkt3_field1 = *pkt3_field1_ptr;
-
-		*pkt0_field0_ptr = (pkt0_field0 & (~mask)) + (pkt0_field1 & mask);
-		*pkt1_field0_ptr = (pkt1_field0 & (~mask)) + (pkt1_field1 & mask);
-		*pkt2_field0_ptr = (pkt2_field0 & (~mask)) + (pkt2_field1 & mask);
-		*pkt3_field0_ptr = (pkt3_field0 & (~mask)) + (pkt3_field1 & mask);
-
-		*pkt0_field1_ptr = (pkt0_field0 & mask) + (pkt0_field1 & (~mask));
-		*pkt1_field1_ptr = (pkt1_field0 & mask) + (pkt1_field1 & (~mask));
-		*pkt2_field1_ptr = (pkt2_field0 & mask) + (pkt2_field1 & (~mask));
-		*pkt3_field1_ptr = (pkt3_field0 & mask) + (pkt3_field1 & (~mask));
-	}
-}
-
-#define PKT_WORK_DMA(dma_size, hash_enabled, lb_hash, port_pow2)	\
-static inline void						\
-pkt_work_dma_size##dma_size##_hash##hash_enabled		\
-	##_lb##lb_hash##_pw##port_pow2(			\
-	struct rte_mbuf *pkt,					\
-	void *arg)						\
-{								\
-	pkt_work_dma(pkt, arg, dma_size, hash_enabled, lb_hash, port_pow2);	\
-}
-
-#define PKT4_WORK_DMA(dma_size, hash_enabled, lb_hash, port_pow2)	\
-static inline void						\
-pkt4_work_dma_size##dma_size##_hash##hash_enabled			\
-	##_lb##lb_hash##_pw##port_pow2(			\
-	struct rte_mbuf **pkts,					\
-	void *arg)						\
-{								\
-	pkt4_work_dma(pkts, arg, dma_size, hash_enabled, lb_hash, port_pow2); \
-}
-
-#define port_in_ah_dma(dma_size, hash_enabled, lb_hash, port_pow2)	\
-PKT_WORK_DMA(dma_size, hash_enabled, lb_hash, port_pow2)			\
-PKT4_WORK_DMA(dma_size, hash_enabled, lb_hash, port_pow2)			\
-PIPELINE_PORT_IN_AH(port_in_ah_dma_size##dma_size##_hash	\
-	##hash_enabled##_lb##lb_hash##_pw##port_pow2,		\
-	pkt_work_dma_size##dma_size##_hash##hash_enabled		\
-	##_lb##lb_hash##_pw##port_pow2,			\
-	pkt4_work_dma_size##dma_size##_hash##hash_enabled		\
-	##_lb##lb_hash##_pw##port_pow2)
-
-
-#define port_in_ah_lb(dma_size, hash_enabled, lb_hash, port_pow2) \
-PKT_WORK_DMA(dma_size, hash_enabled, lb_hash, port_pow2)		\
-PKT4_WORK_DMA(dma_size, hash_enabled, lb_hash, port_pow2)	\
-PIPELINE_PORT_IN_AH_HIJACK_ALL(						\
-	port_in_ah_lb_size##dma_size##_hash##hash_enabled		\
-	##_lb##lb_hash##_pw##port_pow2,			\
-	pkt_work_dma_size##dma_size##_hash##hash_enabled		\
-	##_lb##lb_hash##_pw##port_pow2,	\
-	pkt4_work_dma_size##dma_size##_hash##hash_enabled		\
-	##_lb##lb_hash##_pw##port_pow2)
-
-PIPELINE_PORT_IN_AH(port_in_ah_swap, pkt_work_swap,	pkt4_work_swap)
-
-
-/* Port in AH DMA(dma_size, hash_enabled, lb_hash, port_pow2) */
-
-port_in_ah_dma(8, 0, 0, 0)
-port_in_ah_dma(8, 1, 0, 0)
-port_in_ah_lb(8, 1, 1, 0)
-port_in_ah_lb(8, 1, 1, 1)
-
-port_in_ah_dma(16, 0, 0, 0)
-port_in_ah_dma(16, 1, 0, 0)
-port_in_ah_lb(16, 1, 1, 0)
-port_in_ah_lb(16, 1, 1, 1)
-
-port_in_ah_dma(24, 0, 0, 0)
-port_in_ah_dma(24, 1, 0, 0)
-port_in_ah_lb(24, 1, 1, 0)
-port_in_ah_lb(24, 1, 1, 1)
-
-port_in_ah_dma(32, 0, 0, 0)
-port_in_ah_dma(32, 1, 0, 0)
-port_in_ah_lb(32, 1, 1, 0)
-port_in_ah_lb(32, 1, 1, 1)
-
-port_in_ah_dma(40, 0, 0, 0)
-port_in_ah_dma(40, 1, 0, 0)
-port_in_ah_lb(40, 1, 1, 0)
-port_in_ah_lb(40, 1, 1, 1)
-
-port_in_ah_dma(48, 0, 0, 0)
-port_in_ah_dma(48, 1, 0, 0)
-port_in_ah_lb(48, 1, 1, 0)
-port_in_ah_lb(48, 1, 1, 1)
-
-port_in_ah_dma(56, 0, 0, 0)
-port_in_ah_dma(56, 1, 0, 0)
-port_in_ah_lb(56, 1, 1, 0)
-port_in_ah_lb(56, 1, 1, 1)
-
-port_in_ah_dma(64, 0, 0, 0)
-port_in_ah_dma(64, 1, 0, 0)
-port_in_ah_lb(64, 1, 1, 0)
-port_in_ah_lb(64, 1, 1, 1)
-
-static rte_pipeline_port_in_action_handler
-get_port_in_ah(struct pipeline_passthrough *p)
-{
-	if ((p->params.dma_enabled == 0) &&
-		(p->params.swap_enabled == 0))
-		return NULL;
-
-	if (p->params.swap_enabled)
-		return port_in_ah_swap;
-
-	if (p->params.dma_hash_enabled) {
-		if (p->params.dma_hash_lb_enabled) {
-			if (rte_is_power_of_2(p->p.n_ports_out))
-				switch (p->params.dma_size) {
-
-				case 8: return port_in_ah_lb_size8_hash1_lb1_pw1;
-				case 16: return port_in_ah_lb_size16_hash1_lb1_pw1;
-				case 24: return port_in_ah_lb_size24_hash1_lb1_pw1;
-				case 32: return port_in_ah_lb_size32_hash1_lb1_pw1;
-				case 40: return port_in_ah_lb_size40_hash1_lb1_pw1;
-				case 48: return port_in_ah_lb_size48_hash1_lb1_pw1;
-				case 56: return port_in_ah_lb_size56_hash1_lb1_pw1;
-				case 64: return port_in_ah_lb_size64_hash1_lb1_pw1;
-				default: return NULL;
-				}
-			else
-				switch (p->params.dma_size) {
-
-				case 8: return port_in_ah_lb_size8_hash1_lb1_pw0;
-				case 16: return port_in_ah_lb_size16_hash1_lb1_pw0;
-				case 24: return port_in_ah_lb_size24_hash1_lb1_pw0;
-				case 32: return port_in_ah_lb_size32_hash1_lb1_pw0;
-				case 40: return port_in_ah_lb_size40_hash1_lb1_pw0;
-				case 48: return port_in_ah_lb_size48_hash1_lb1_pw0;
-				case 56: return port_in_ah_lb_size56_hash1_lb1_pw0;
-				case 64: return port_in_ah_lb_size64_hash1_lb1_pw0;
-				default: return NULL;
-			}
-		} else
-			switch (p->params.dma_size) {
-
-			case 8: return port_in_ah_dma_size8_hash1_lb0_pw0;
-			case 16: return port_in_ah_dma_size16_hash1_lb0_pw0;
-			case 24: return port_in_ah_dma_size24_hash1_lb0_pw0;
-			case 32: return port_in_ah_dma_size32_hash1_lb0_pw0;
-			case 40: return port_in_ah_dma_size40_hash1_lb0_pw0;
-			case 48: return port_in_ah_dma_size48_hash1_lb0_pw0;
-			case 56: return port_in_ah_dma_size56_hash1_lb0_pw0;
-			case 64: return port_in_ah_dma_size64_hash1_lb0_pw0;
-			default: return NULL;
-		}
-	} else
-		switch (p->params.dma_size) {
-
-		case 8: return port_in_ah_dma_size8_hash0_lb0_pw0;
-		case 16: return port_in_ah_dma_size16_hash0_lb0_pw0;
-		case 24: return port_in_ah_dma_size24_hash0_lb0_pw0;
-		case 32: return port_in_ah_dma_size32_hash0_lb0_pw0;
-		case 40: return port_in_ah_dma_size40_hash0_lb0_pw0;
-		case 48: return port_in_ah_dma_size48_hash0_lb0_pw0;
-		case 56: return port_in_ah_dma_size56_hash0_lb0_pw0;
-		case 64: return port_in_ah_dma_size64_hash0_lb0_pw0;
-		default: return NULL;
-		}
-}
-
-int
-pipeline_passthrough_parse_args(struct pipeline_passthrough_params *p,
-	struct pipeline_params *params)
-{
-	uint32_t dma_dst_offset_present = 0;
-	uint32_t dma_src_offset_present = 0;
-	uint32_t dma_src_mask_present = 0;
-	char dma_mask_str[PIPELINE_PASSTHROUGH_DMA_SIZE_MAX * 2 + 1];
-	uint32_t dma_size_present = 0;
-	uint32_t dma_hash_offset_present = 0;
-	uint32_t dma_hash_lb_present = 0;
-	uint32_t i;
-
-	/* default values */
-	p->dma_enabled = 0;
-	p->dma_hash_enabled = 0;
-	p->dma_hash_lb_enabled = 0;
-	memset(p->dma_src_mask, 0xFF, sizeof(p->dma_src_mask));
-	p->swap_enabled = 0;
-	p->swap_n_fields = 0;
-
-	for (i = 0; i < params->n_args; i++) {
-		char *arg_name = params->args_name[i];
-		char *arg_value = params->args_value[i];
-
-		/* dma_dst_offset */
-		if (strcmp(arg_name, "dma_dst_offset") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				dma_dst_offset_present == 0, params->name,
-				arg_name);
-			dma_dst_offset_present = 1;
-
-			status = parser_read_uint32(&p->dma_dst_offset,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			p->dma_enabled = 1;
-
-			continue;
-		}
-
-		/* dma_src_offset */
-		if (strcmp(arg_name, "dma_src_offset") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				dma_src_offset_present == 0, params->name,
-				arg_name);
-			dma_src_offset_present = 1;
-
-			status = parser_read_uint32(&p->dma_src_offset,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			p->dma_enabled = 1;
-
-			continue;
-		}
-
-		/* dma_size */
-		if (strcmp(arg_name, "dma_size") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				dma_size_present == 0, params->name,
-				arg_name);
-			dma_size_present = 1;
-
-			status = parser_read_uint32(&p->dma_size,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL(((status != -EINVAL) &&
-				(p->dma_size != 0) &&
-				((p->dma_size % 8) == 0)),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG(((status != -ERANGE) &&
-				(p->dma_size <=
-				PIPELINE_PASSTHROUGH_DMA_SIZE_MAX)),
-				params->name, arg_name, arg_value);
-
-			p->dma_enabled = 1;
-
-			continue;
-		}
-
-		/* dma_src_mask */
-		if (strcmp(arg_name, "dma_src_mask") == 0) {
-			int mask_str_len = strlen(arg_value);
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				dma_src_mask_present == 0,
-				params->name, arg_name);
-			dma_src_mask_present = 1;
-
-			PIPELINE_ARG_CHECK((mask_str_len <=
-				(PIPELINE_PASSTHROUGH_DMA_SIZE_MAX * 2)),
-				"Parse error in section \"%s\": entry "
-				"\"%s\" too long", params->name,
-				arg_name);
-
-			snprintf(dma_mask_str, mask_str_len + 1,
-				"%s", arg_value);
-
-			p->dma_enabled = 1;
-
-			continue;
-		}
-
-		/* dma_hash_offset */
-		if (strcmp(arg_name, "dma_hash_offset") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				dma_hash_offset_present == 0,
-				params->name, arg_name);
-			dma_hash_offset_present = 1;
-
-			status = parser_read_uint32(&p->dma_hash_offset,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			p->dma_hash_enabled = 1;
-
-			continue;
-		}
-
-		/* load_balance mode */
-		if (strcmp(arg_name, "lb") == 0) {
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				dma_hash_lb_present == 0,
-				params->name, arg_name);
-			dma_hash_lb_present = 1;
-
-			if (strcmp(arg_value, "hash") &&
-				strcmp(arg_value, "HASH"))
-
-				PIPELINE_PARSE_ERR_INV_VAL(0,
-					params->name,
-					arg_name,
-					arg_value);
-
-			p->dma_hash_lb_enabled = 1;
-
-			continue;
-		}
-
-		/* swap */
-		if (strcmp(arg_name, "swap") == 0) {
-			uint32_t a, b, n_args;
-			int len;
-
-			n_args = sscanf(arg_value, "%" SCNu32 " %" SCNu32 "%n",
-				&a, &b, &len);
-			PIPELINE_PARSE_ERR_INV_VAL(((n_args == 2) &&
-				((size_t) len == strlen(arg_value))),
-				params->name, arg_name, arg_value);
-
-			p->swap_field0_offset[p->swap_n_fields] = a;
-			p->swap_field1_offset[p->swap_n_fields] = b;
-			p->swap_n_fields++;
-			p->swap_enabled = 1;
-
-			continue;
-		}
-
-		/* any other */
-		PIPELINE_PARSE_ERR_INV_ENT(0, params->name, arg_name);
-	}
-
-	/* Check correlations between arguments */
-	PIPELINE_ARG_CHECK((p->dma_enabled + p->swap_enabled < 2),
-		"Parse error in section \"%s\": DMA and SWAP actions are both enabled",
-		params->name);
-	PIPELINE_ARG_CHECK((dma_dst_offset_present == p->dma_enabled),
-		"Parse error in section \"%s\": missing entry "
-		"\"dma_dst_offset\"", params->name);
-	PIPELINE_ARG_CHECK((dma_src_offset_present == p->dma_enabled),
-		"Parse error in section \"%s\": missing entry "
-		"\"dma_src_offset\"", params->name);
-	PIPELINE_ARG_CHECK((dma_size_present == p->dma_enabled),
-		"Parse error in section \"%s\": missing entry "
-		"\"dma_size\"", params->name);
-	PIPELINE_ARG_CHECK((p->dma_hash_enabled <= p->dma_enabled),
-		"Parse error in section \"%s\": missing all DMA entries",
-		params->name);
-	PIPELINE_ARG_CHECK((p->dma_hash_lb_enabled <= p->dma_hash_enabled),
-		"Parse error in section \"%s\": missing all DMA hash entries ",
-		params->name);
-
-	if (dma_src_mask_present) {
-		uint32_t dma_size = p->dma_size;
-		int status;
-
-		PIPELINE_ARG_CHECK((strlen(dma_mask_str) ==
-			(dma_size * 2)), "Parse error in section "
-			"\"%s\": dma_src_mask should have exactly %u hex "
-			"digits", params->name, (dma_size * 2));
-
-		status = parse_hex_string(dma_mask_str, p->dma_src_mask,
-			&p->dma_size);
-
-		PIPELINE_PARSE_ERR_INV_VAL(((status == 0) &&
-			(dma_size == p->dma_size)), params->name,
-			"dma_src_mask", dma_mask_str);
-	}
-
-	if (p->dma_hash_lb_enabled)
-		PIPELINE_ARG_CHECK((params->n_ports_out > 1),
-			"Parse error in section \"%s\": entry \"lb\" not "
-			"allowed for single output port pipeline",
-			params->name);
-	else
-		PIPELINE_ARG_CHECK(((params->n_ports_in >= params->n_ports_out)
-			&& ((params->n_ports_in % params->n_ports_out) == 0)),
-			"Parse error in section \"%s\": n_ports_in needs to be "
-			"a multiple of n_ports_out (lb mode disabled)",
-			params->name);
-
-	return 0;
-}
-
-static rte_table_hash_op_hash
-get_hash_function(struct pipeline_passthrough *p)
-{
-	switch (p->params.dma_size) {
-
-	case 8: return hash_default_key8;
-	case 16: return hash_default_key16;
-	case 24: return hash_default_key24;
-	case 32: return hash_default_key32;
-	case 40: return hash_default_key40;
-	case 48: return hash_default_key48;
-	case 56: return hash_default_key56;
-	case 64: return hash_default_key64;
-	default: return NULL;
-	}
-}
-
-static int
-pipeline_passthrough_swap_convert(struct pipeline_passthrough *p)
-{
-	uint32_t i;
-
-	p->swap_n_fields = 0;
-
-	for (i = 0; i < p->params.swap_n_fields; i++) {
-		uint32_t offset0 = p->params.swap_field0_offset[i];
-		uint32_t offset1 = p->params.swap_field1_offset[i];
-		uint32_t size = offset1 - offset0;
-		uint32_t j;
-
-		/* Check */
-		if ((offset0 >= offset1) ||
-			(size > PIPELINE_PASSTHROUGH_SWAP_FIELD_SIZE_MAX) ||
-			(p->swap_n_fields >= SWAP_DIM))
-			return -1;
-
-		for (j = 0; j < (size / sizeof(uint64_t)); j++) {
-			p->swap_field0_offset[p->swap_n_fields] = offset0;
-			p->swap_field1_offset[p->swap_n_fields] = offset1;
-			p->swap_field_mask[p->swap_n_fields] = UINT64_MAX;
-			p->swap_n_fields++;
-			offset0 += sizeof(uint64_t);
-			offset1 += sizeof(uint64_t);
-		}
-		if (size % sizeof(uint64_t)) {
-			uint32_t n_bits = (size % sizeof(uint64_t)) * 8;
-
-			p->swap_field0_offset[p->swap_n_fields] = offset0;
-			p->swap_field1_offset[p->swap_n_fields] = offset1;
-			p->swap_field_mask[p->swap_n_fields] =
-				RTE_LEN2MASK(n_bits, uint64_t);
-			p->swap_n_fields++;
-		}
-	}
-
-	return 0;
-}
-
-static void*
-pipeline_passthrough_init(struct pipeline_params *params,
-	__rte_unused void *arg)
-{
-	struct pipeline *p;
-	struct pipeline_passthrough *p_pt;
-	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_passthrough));
-	p = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
-	p_pt = (struct pipeline_passthrough *) p;
-	if (p == NULL)
-		return NULL;
-
-	strcpy(p->name, params->name);
-	p->log_level = params->log_level;
-
-	PLOG(p, HIGH, "Pass-through");
-
-	/* Parse arguments */
-	if (pipeline_passthrough_parse_args(&p_pt->params, params))
-		return NULL;
-	if (pipeline_passthrough_swap_convert(p_pt))
-		return NULL;
-	p_pt->f_hash = get_hash_function(p_pt);
-
-	/* 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;
-		}
-	}
-
-	p->n_ports_in = params->n_ports_in;
-	p->n_ports_out = params->n_ports_out;
-	p->n_tables = p->n_ports_in;
-
-	/*Input ports*/
-	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 = get_port_in_ah(p_pt),
-			.arg_ah = p_pt,
-			.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 */
-	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,
-			.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 */
-	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++) {
-		uint32_t port_out_id = (p_pt->params.dma_hash_lb_enabled == 0) ?
-			(i / (p->n_ports_in / p->n_ports_out)) :
-			0;
-
-		struct rte_pipeline_table_entry default_entry = {
-			.action = RTE_PIPELINE_ACTION_PORT,
-			{.port_id = p->port_out_id[port_out_id]},
-		};
-
-		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;
-}
-
-struct pipeline_be_ops pipeline_passthrough_be_ops = {
-	.f_init = pipeline_passthrough_init,
-	.f_free = pipeline_passthrough_free,
-	.f_run = NULL,
-	.f_timer = pipeline_passthrough_timer,
-};
diff --git a/examples/ip_pipeline/pipeline/pipeline_passthrough_be.h b/examples/ip_pipeline/pipeline/pipeline_passthrough_be.h
deleted file mode 100644
index 94d1d1c..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_passthrough_be.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#ifndef __INCLUDE_PIPELINE_PASSTHROUGH_BE_H__
-#define __INCLUDE_PIPELINE_PASSTHROUGH_BE_H__
-
-#include "pipeline_common_be.h"
-
-#define PIPELINE_PASSTHROUGH_DMA_SIZE_MAX                             64
-
-#ifndef PIPELINE_PASSTHROUGH_SWAP_N_FIELDS_MAX
-#define PIPELINE_PASSTHROUGH_SWAP_N_FIELDS_MAX                        8
-#endif
-
-#ifndef PIPELINE_PASSTHROUGH_SWAP_FIELD_SIZE_MAX
-#define PIPELINE_PASSTHROUGH_SWAP_FIELD_SIZE_MAX                      16
-#endif
-
-struct pipeline_passthrough_params {
-	uint32_t dma_enabled;
-	uint32_t dma_dst_offset;
-	uint32_t dma_src_offset;
-	uint8_t dma_src_mask[PIPELINE_PASSTHROUGH_DMA_SIZE_MAX];
-	uint32_t dma_size;
-
-	uint32_t dma_hash_enabled;
-	uint32_t dma_hash_offset;
-
-	uint32_t dma_hash_lb_enabled;
-
-	uint32_t swap_enabled;
-	uint32_t swap_field0_offset[PIPELINE_PASSTHROUGH_SWAP_N_FIELDS_MAX];
-	uint32_t swap_field1_offset[PIPELINE_PASSTHROUGH_SWAP_N_FIELDS_MAX];
-	uint32_t swap_n_fields;
-};
-
-int
-pipeline_passthrough_parse_args(struct pipeline_passthrough_params *p,
-	struct pipeline_params *params);
-
-extern struct pipeline_be_ops pipeline_passthrough_be_ops;
-
-#endif
-- 
2.9.3

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

* [dpdk-dev] [PATCH v4 14/49] ip_pipeline: remove routing pipeline
  2018-03-29 18:31           ` [dpdk-dev] [PATCH v4 00/49] ip_pipeline: refactoring Jasvinder Singh
                               ` (12 preceding siblings ...)
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 13/49] ip_pipeline: remove passthrough pipeline Jasvinder Singh
@ 2018-03-29 18:31             ` Jasvinder Singh
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 15/49] ip_pipeline: remove flow classification pipeline Jasvinder Singh
                               ` (35 subsequent siblings)
  49 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-29 18:31 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Remove routing pipeline.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/Makefile                      |    2 -
 examples/ip_pipeline/init.c                        |    2 -
 examples/ip_pipeline/meson.build                   |    2 -
 examples/ip_pipeline/pipeline/pipeline_routing.c   | 1613 ----------------
 examples/ip_pipeline/pipeline/pipeline_routing.h   |   71 -
 .../ip_pipeline/pipeline/pipeline_routing_be.c     | 1966 --------------------
 .../ip_pipeline/pipeline/pipeline_routing_be.h     |  283 ---
 7 files changed, 3939 deletions(-)
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_routing.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_routing.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_routing_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_routing_be.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index 089c269..f67cfe6 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -25,8 +25,6 @@ SRCS-y += pipeline_flow_classification_be.c
 SRCS-y += pipeline_flow_classification.c
 SRCS-y += pipeline_flow_actions_be.c
 SRCS-y += pipeline_flow_actions.c
-SRCS-y += pipeline_routing_be.c
-SRCS-y += pipeline_routing.c
 
 # Build using pkg-config variables if possible
 $(shell pkg-config --exists libdpdk)
diff --git a/examples/ip_pipeline/init.c b/examples/ip_pipeline/init.c
index 73b93d7..241d80a 100644
--- a/examples/ip_pipeline/init.c
+++ b/examples/ip_pipeline/init.c
@@ -29,7 +29,6 @@
 #include "pipeline_firewall.h"
 #include "pipeline_flow_classification.h"
 #include "pipeline_flow_actions.h"
-#include "pipeline_routing.h"
 #include "thread_fe.h"
 
 #define APP_NAME_SIZE	32
@@ -1824,7 +1823,6 @@ int app_init(struct app_params *app)
 	app_pipeline_type_register(app, &pipeline_flow_classification);
 	app_pipeline_type_register(app, &pipeline_flow_actions);
 	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/meson.build b/examples/ip_pipeline/meson.build
index 17f4e16..f9eab1b 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -29,6 +29,4 @@ sources = files(
 	'pipeline/pipeline_flow_classification.c',
 	'pipeline/pipeline_master_be.c',
 	'pipeline/pipeline_master.c',
-	'pipeline/pipeline_routing_be.c',
-	'pipeline/pipeline_routing.c',
 )
diff --git a/examples/ip_pipeline/pipeline/pipeline_routing.c b/examples/ip_pipeline/pipeline/pipeline_routing.c
deleted file mode 100644
index 0562c63..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_routing.c
+++ /dev/null
@@ -1,1613 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2016 Intel Corporation
- */
-
-#include <cmdline_parse.h>
-#include <cmdline_parse_num.h>
-#include <cmdline_parse_string.h>
-
-#include "app.h"
-#include "pipeline_common_fe.h"
-#include "pipeline_routing.h"
-#include "parser.h"
-
-struct app_pipeline_routing_route {
-	struct pipeline_routing_route_key key;
-	struct pipeline_routing_route_data data;
-	void *entry_ptr;
-
-	TAILQ_ENTRY(app_pipeline_routing_route) node;
-};
-
-struct app_pipeline_routing_arp_entry {
-	struct pipeline_routing_arp_key key;
-	struct ether_addr macaddr;
-	void *entry_ptr;
-
-	TAILQ_ENTRY(app_pipeline_routing_arp_entry) node;
-};
-
-struct pipeline_routing {
-	/* Parameters */
-	struct app_params *app;
-	uint32_t pipeline_id;
-	uint32_t n_ports_in;
-	uint32_t n_ports_out;
-	struct pipeline_routing_params rp;
-
-	/* Links */
-	uint32_t link_id[PIPELINE_MAX_PORT_OUT];
-
-	/* Routes */
-	TAILQ_HEAD(, app_pipeline_routing_route) routes;
-	uint32_t n_routes;
-
-	uint32_t default_route_present;
-	uint32_t default_route_port_id;
-	void *default_route_entry_ptr;
-
-	/* 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;
-};
-
-static int
-app_pipeline_routing_find_link(struct pipeline_routing *p,
-	uint32_t link_id,
-	uint32_t *port_id)
-{
-	uint32_t i;
-
-	for (i = 0; i < p->n_ports_out; i++)
-		if (p->link_id[i] == link_id) {
-			*port_id = i;
-			return 0;
-		}
-
-	return -1;
-}
-
-static void
-app_pipeline_routing_link_op(__rte_unused struct app_params *app,
-	uint32_t link_id,
-	uint32_t up,
-	void *arg)
-{
-	struct pipeline_routing_route_key key0, key1;
-	struct pipeline_routing *p = arg;
-	struct app_link_params *lp;
-	uint32_t port_id, netmask;
-	int status;
-
-	if (app == NULL)
-		return;
-
-	APP_PARAM_FIND_BY_ID(app->link_params, "LINK", link_id, lp);
-	if (lp == NULL)
-		return;
-
-	status = app_pipeline_routing_find_link(p,
-		link_id,
-		&port_id);
-	if (status)
-		return;
-
-	netmask = (~0U) << (32 - lp->depth);
-
-	/* Local network (directly attached network) */
-	key0.type = PIPELINE_ROUTING_ROUTE_IPV4;
-	key0.key.ipv4.ip = lp->ip & netmask;
-	key0.key.ipv4.depth = lp->depth;
-
-	/* Local termination */
-	key1.type = PIPELINE_ROUTING_ROUTE_IPV4;
-	key1.key.ipv4.ip = lp->ip;
-	key1.key.ipv4.depth = 32;
-
-	if (up) {
-		struct pipeline_routing_route_data data0, data1;
-
-		/* Local network (directly attached network) */
-		memset(&data0, 0, sizeof(data0));
-		data0.flags = PIPELINE_ROUTING_ROUTE_LOCAL |
-			PIPELINE_ROUTING_ROUTE_ARP;
-		if (p->rp.encap == PIPELINE_ROUTING_ENCAP_ETHERNET_QINQ)
-			data0.flags |= PIPELINE_ROUTING_ROUTE_QINQ;
-		if (p->rp.encap == PIPELINE_ROUTING_ENCAP_ETHERNET_MPLS) {
-			data0.flags |= PIPELINE_ROUTING_ROUTE_MPLS;
-			data0.l2.mpls.n_labels = 1;
-		}
-		data0.port_id = port_id;
-
-		if (p->rp.n_arp_entries)
-			app_pipeline_routing_add_route(app,
-				p->pipeline_id,
-				&key0,
-				&data0);
-
-		/* Local termination */
-		memset(&data1, 0, sizeof(data1));
-		data1.flags = PIPELINE_ROUTING_ROUTE_LOCAL |
-			PIPELINE_ROUTING_ROUTE_ARP;
-		if (p->rp.encap == PIPELINE_ROUTING_ENCAP_ETHERNET_QINQ)
-			data1.flags |= PIPELINE_ROUTING_ROUTE_QINQ;
-		if (p->rp.encap == PIPELINE_ROUTING_ENCAP_ETHERNET_MPLS) {
-			data1.flags |= PIPELINE_ROUTING_ROUTE_MPLS;
-			data1.l2.mpls.n_labels = 1;
-		}
-		data1.port_id = p->rp.port_local_dest;
-
-		app_pipeline_routing_add_route(app,
-			p->pipeline_id,
-			&key1,
-			&data1);
-	} else {
-		/* Local network (directly attached network) */
-		if (p->rp.n_arp_entries)
-			app_pipeline_routing_delete_route(app,
-				p->pipeline_id,
-				&key0);
-
-		/* Local termination */
-		app_pipeline_routing_delete_route(app,
-			p->pipeline_id,
-			&key1);
-	}
-}
-
-static int
-app_pipeline_routing_set_link_op(
-	struct app_params *app,
-	struct pipeline_routing *p)
-{
-	uint32_t port_id;
-
-	for (port_id = 0; port_id < p->n_ports_out; port_id++) {
-		struct app_link_params *link;
-		uint32_t link_id;
-		int status;
-
-		link = app_pipeline_track_pktq_out_to_link(app,
-			p->pipeline_id,
-			port_id);
-		if (link == NULL)
-			continue;
-
-		link_id = link - app->link_params;
-		p->link_id[port_id] = link_id;
-
-		status = app_link_set_op(app,
-			link_id,
-			p->pipeline_id,
-			app_pipeline_routing_link_op,
-			(void *) p);
-		if (status)
-			return status;
-	}
-
-	return 0;
-}
-
-static void *
-app_pipeline_routing_init(struct pipeline_params *params,
-	void *arg)
-{
-	struct app_params *app = (struct app_params *) arg;
-	struct pipeline_routing *p;
-	uint32_t pipeline_id, size;
-	int status;
-
-	/* Check input arguments */
-	if ((params == NULL) ||
-		(params->n_ports_in == 0) ||
-		(params->n_ports_out == 0))
-		return NULL;
-
-	APP_PARAM_GET_ID(params, "PIPELINE", pipeline_id);
-
-	/* 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->app = app;
-	p->pipeline_id = pipeline_id;
-	p->n_ports_in = params->n_ports_in;
-	p->n_ports_out = params->n_ports_out;
-
-	status = pipeline_routing_parse_args(&p->rp, params);
-	if (status) {
-		rte_free(p);
-		return NULL;
-	}
-	TAILQ_INIT(&p->routes);
-	p->n_routes = 0;
-
-	TAILQ_INIT(&p->arp_entries);
-	p->n_arp_entries = 0;
-
-	app_pipeline_routing_set_link_op(app, p);
-
-	return p;
-}
-
-static int
-app_pipeline_routing_post_init(void *pipeline)
-{
-	struct pipeline_routing *p = pipeline;
-
-	/* Check input arguments */
-	if (p == NULL)
-		return -1;
-
-	return app_pipeline_routing_set_macaddr(p->app, p->pipeline_id);
-}
-
-static int
-app_pipeline_routing_free(void *pipeline)
-{
-	struct pipeline_routing *p = pipeline;
-
-	/* Check input arguments */
-	if (p == NULL)
-		return -1;
-
-	/* Free resources */
-	while (!TAILQ_EMPTY(&p->routes)) {
-		struct app_pipeline_routing_route *route;
-
-		route = TAILQ_FIRST(&p->routes);
-		TAILQ_REMOVE(&p->routes, route, node);
-		rte_free(route);
-	}
-
-	while (!TAILQ_EMPTY(&p->arp_entries)) {
-		struct app_pipeline_routing_arp_entry *arp_entry;
-
-		arp_entry = TAILQ_FIRST(&p->arp_entries);
-		TAILQ_REMOVE(&p->arp_entries, arp_entry, node);
-		rte_free(arp_entry);
-	}
-
-	rte_free(p);
-	return 0;
-}
-
-static struct app_pipeline_routing_route *
-app_pipeline_routing_find_route(struct pipeline_routing *p,
-		const struct pipeline_routing_route_key *key)
-{
-	struct app_pipeline_routing_route *it, *found;
-
-	found = NULL;
-	TAILQ_FOREACH(it, &p->routes, node) {
-		if ((key->type == it->key.type) &&
-			(key->key.ipv4.ip == it->key.key.ipv4.ip) &&
-			(key->key.ipv4.depth == it->key.key.ipv4.depth)) {
-			found = it;
-			break;
-		}
-	}
-
-	return found;
-}
-
-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;
-
-	found = NULL;
-	TAILQ_FOREACH(it, &p->arp_entries, node) {
-		if ((key->type == it->key.type) &&
-			(key->key.ipv4.port_id == it->key.key.ipv4.port_id) &&
-			(key->key.ipv4.ip == it->key.key.ipv4.ip)) {
-			found = it;
-			break;
-		}
-	}
-
-	return found;
-}
-
-static void
-print_route(const struct app_pipeline_routing_route *route)
-{
-	if (route->key.type == PIPELINE_ROUTING_ROUTE_IPV4) {
-		const struct pipeline_routing_route_key_ipv4 *key =
-				&route->key.key.ipv4;
-
-		printf("IP Prefix = %" PRIu32 ".%" PRIu32
-			".%" PRIu32 ".%" PRIu32 "/%" PRIu32
-			" => (Port = %" PRIu32,
-
-			(key->ip >> 24) & 0xFF,
-			(key->ip >> 16) & 0xFF,
-			(key->ip >> 8) & 0xFF,
-			key->ip & 0xFF,
-
-			key->depth,
-			route->data.port_id);
-
-		if (route->data.flags & PIPELINE_ROUTING_ROUTE_LOCAL)
-			printf(", Local");
-		else if (route->data.flags & PIPELINE_ROUTING_ROUTE_ARP)
-			printf(
-				", Next Hop IP = %" PRIu32 ".%" PRIu32
-				".%" PRIu32 ".%" PRIu32,
-
-				(route->data.ethernet.ip >> 24) & 0xFF,
-				(route->data.ethernet.ip >> 16) & 0xFF,
-				(route->data.ethernet.ip >> 8) & 0xFF,
-				route->data.ethernet.ip & 0xFF);
-		else
-			printf(
-				", Next Hop HWaddress = %02" PRIx32
-				":%02" PRIx32 ":%02" PRIx32
-				":%02" PRIx32 ":%02" PRIx32
-				":%02" PRIx32,
-
-				route->data.ethernet.macaddr.addr_bytes[0],
-				route->data.ethernet.macaddr.addr_bytes[1],
-				route->data.ethernet.macaddr.addr_bytes[2],
-				route->data.ethernet.macaddr.addr_bytes[3],
-				route->data.ethernet.macaddr.addr_bytes[4],
-				route->data.ethernet.macaddr.addr_bytes[5]);
-
-		if (route->data.flags & PIPELINE_ROUTING_ROUTE_QINQ)
-			printf(", QinQ SVLAN = %" PRIu32 " CVLAN = %" PRIu32,
-				route->data.l2.qinq.svlan,
-				route->data.l2.qinq.cvlan);
-
-		if (route->data.flags & PIPELINE_ROUTING_ROUTE_MPLS) {
-			uint32_t i;
-
-			printf(", MPLS labels");
-			for (i = 0; i < route->data.l2.mpls.n_labels; i++)
-				printf(" %" PRIu32,
-					route->data.l2.mpls.labels[i]);
-		}
-
-		printf(")\n");
-	}
-}
-
-static void
-print_arp_entry(const struct app_pipeline_routing_arp_entry *entry)
-{
-	printf("(Port = %" PRIu32 ", IP = %" PRIu32 ".%" PRIu32
-		".%" PRIu32 ".%" PRIu32
-		") => HWaddress = %02" PRIx32 ":%02" PRIx32 ":%02" PRIx32
-		":%02" PRIx32 ":%02" PRIx32 ":%02" PRIx32 "\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->macaddr.addr_bytes[0],
-		entry->macaddr.addr_bytes[1],
-		entry->macaddr.addr_bytes[2],
-		entry->macaddr.addr_bytes[3],
-		entry->macaddr.addr_bytes[4],
-		entry->macaddr.addr_bytes[5]);
-}
-
-static int
-app_pipeline_routing_route_ls(struct app_params *app, uint32_t pipeline_id)
-{
-	struct pipeline_routing *p;
-	struct app_pipeline_routing_route *it;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_routing);
-	if (p == NULL)
-		return -EINVAL;
-
-	TAILQ_FOREACH(it, &p->routes, node)
-		print_route(it);
-
-	if (p->default_route_present)
-		printf("Default route: port %" PRIu32 " (entry ptr = %p)\n",
-				p->default_route_port_id,
-				p->default_route_entry_ptr);
-	else
-		printf("Default: DROP\n");
-
-	return 0;
-}
-
-int
-app_pipeline_routing_add_route(struct app_params *app,
-	uint32_t pipeline_id,
-	struct pipeline_routing_route_key *key,
-	struct pipeline_routing_route_data *data)
-{
-	struct pipeline_routing *p;
-
-	struct pipeline_routing_route_add_msg_req *req;
-	struct pipeline_routing_route_add_msg_rsp *rsp;
-
-	struct app_pipeline_routing_route *entry;
-
-	int new_entry;
-
-	/* Check input arguments */
-	if ((app == NULL) ||
-		(key == NULL) ||
-		(data == NULL))
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_routing);
-	if (p == NULL)
-		return -1;
-
-	switch (key->type) {
-	case PIPELINE_ROUTING_ROUTE_IPV4:
-	{
-		uint32_t depth = key->key.ipv4.depth;
-		uint32_t netmask;
-
-		/* key */
-		if ((depth == 0) || (depth > 32))
-			return -1;
-
-		netmask = (~0U) << (32 - depth);
-		key->key.ipv4.ip &= netmask;
-
-		/* data */
-		if (data->port_id >= p->n_ports_out)
-			return -1;
-
-		/* Valid range of VLAN tags 12 bits */
-		if (data->flags & PIPELINE_ROUTING_ROUTE_QINQ)
-			if ((data->l2.qinq.svlan & 0xF000) ||
-					(data->l2.qinq.cvlan & 0xF000))
-				return -1;
-
-		/* Max number of MPLS labels supported */
-		if (data->flags & PIPELINE_ROUTING_ROUTE_MPLS) {
-			uint32_t i;
-
-			if (data->l2.mpls.n_labels >
-					PIPELINE_ROUTING_MPLS_LABELS_MAX)
-				return -1;
-
-			/* Max MPLS label value 20 bits */
-			for (i = 0; i < data->l2.mpls.n_labels; i++)
-				if (data->l2.mpls.labels[i] & 0xFFF00000)
-					return -1;
-		}
-	}
-	break;
-
-	default:
-		return -1;
-	}
-
-	/* 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;
-	}
-
-	/* Allocate and write request */
-	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_ROUTE_ADD;
-	memcpy(&req->key, key, sizeof(*key));
-	memcpy(&req->data, data, sizeof(*data));
-
-	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL) {
-		if (new_entry)
-			rte_free(entry);
-		return -1;
-	}
-
-	/* Read response and write entry */
-	if (rsp->status ||
-		(rsp->entry_ptr == NULL) ||
-		((new_entry == 0) && (rsp->key_found == 0)) ||
-		((new_entry == 1) && (rsp->key_found == 1))) {
-		app_msg_free(app, rsp);
-		if (new_entry)
-			rte_free(entry);
-		return -1;
-	}
-
-	memcpy(&entry->key, key, sizeof(*key));
-	memcpy(&entry->data, data, sizeof(*data));
-	entry->entry_ptr = rsp->entry_ptr;
-
-	/* Commit entry */
-	if (new_entry) {
-		TAILQ_INSERT_TAIL(&p->routes, entry, node);
-		p->n_routes++;
-	}
-
-	/* 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_route *entry;
-
-	/* Check input arguments */
-	if ((app == NULL) ||
-		(key == NULL))
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_routing);
-	if (p == NULL)
-		return -1;
-
-	switch (key->type) {
-	case PIPELINE_ROUTING_ROUTE_IPV4:
-	{
-		uint32_t depth = key->key.ipv4.depth;
-		uint32_t netmask;
-
-		/* key */
-		if ((depth == 0) || (depth > 32))
-			return -1;
-
-		netmask = (~0U) << (32 - depth);
-		key->key.ipv4.ip &= netmask;
-	}
-	break;
-
-	default:
-		return -1;
-	}
-
-	/* 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_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	/* Read response */
-	if (rsp->status || !rsp->key_found) {
-		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;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_routing);
-	if (p == NULL)
-		return -1;
-
-	if (port_id >= p->n_ports_out)
-		return -1;
-
-	/* 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_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	/* Read response and write route */
-	if (rsp->status || (rsp->entry_ptr == NULL)) {
-		app_msg_free(app, rsp);
-		return -1;
-	}
-
-	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;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_routing);
-	if (p == NULL)
-		return -1;
-
-	/* 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_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	/* Read response and write route */
-	if (rsp->status) {
-		app_msg_free(app, rsp);
-		return -1;
-	}
-
-	/* Commit route */
-	p->default_route_present = 0;
-
-	/* Free response */
-	app_msg_free(app, rsp);
-
-	return 0;
-}
-
-static int
-app_pipeline_routing_arp_ls(struct app_params *app, uint32_t pipeline_id)
-{
-	struct pipeline_routing *p;
-	struct app_pipeline_routing_arp_entry *it;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_routing);
-	if (p == NULL)
-		return -EINVAL;
-
-	TAILQ_FOREACH(it, &p->arp_entries, node)
-		print_arp_entry(it);
-
-	if (p->default_arp_entry_present)
-		printf("Default entry: port %" PRIu32 " (entry ptr = %p)\n",
-				p->default_arp_entry_port_id,
-				p->default_arp_entry_ptr);
-	else
-		printf("Default: DROP\n");
-
-	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;
-
-	/* Check input arguments */
-	if ((app == NULL) ||
-		(key == NULL) ||
-		(macaddr == NULL))
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_routing);
-	if (p == NULL)
-		return -1;
-
-	switch (key->type) {
-	case PIPELINE_ROUTING_ARP_IPV4:
-	{
-		uint32_t port_id = key->key.ipv4.port_id;
-
-		/* key */
-		if (port_id >= p->n_ports_out)
-			return -1;
-	}
-	break;
-
-	default:
-		return -1;
-	}
-
-	/* 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_DEFAULT);
-	if (rsp == NULL) {
-		if (new_entry)
-			rte_free(entry);
-		return -1;
-	}
-
-	/* Read response and write entry */
-	if (rsp->status ||
-		(rsp->entry_ptr == NULL) ||
-		((new_entry == 0) && (rsp->key_found == 0)) ||
-		((new_entry == 1) && (rsp->key_found == 1))) {
-		app_msg_free(app, rsp);
-		if (new_entry)
-			rte_free(entry);
-		return -1;
-	}
-
-	memcpy(&entry->key, key, sizeof(*key));
-	ether_addr_copy(macaddr, &entry->macaddr);
-	entry->entry_ptr = rsp->entry_ptr;
-
-	/* Commit entry */
-	if (new_entry) {
-		TAILQ_INSERT_TAIL(&p->arp_entries, entry, node);
-		p->n_arp_entries++;
-	}
-
-	/* Message buffer free */
-	app_msg_free(app, rsp);
-	return 0;
-}
-
-int
-app_pipeline_routing_delete_arp_entry(struct app_params *app,
-	uint32_t pipeline_id,
-	struct pipeline_routing_arp_key *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;
-
-	/* Check input arguments */
-	if ((app == NULL) ||
-		(key == NULL))
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_routing);
-	if (p == NULL)
-		return -EINVAL;
-
-	switch (key->type) {
-	case PIPELINE_ROUTING_ARP_IPV4:
-	{
-		uint32_t port_id = key->key.ipv4.port_id;
-
-		/* key */
-		if (port_id >= p->n_ports_out)
-			return -1;
-	}
-	break;
-
-	default:
-		return -1;
-	}
-
-	/* 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_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	/* Read response */
-	if (rsp->status || !rsp->key_found) {
-		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;
-}
-
-int
-app_pipeline_routing_add_default_arp_entry(struct app_params *app,
-		uint32_t pipeline_id,
-		uint32_t port_id)
-{
-	struct pipeline_routing *p;
-
-	struct pipeline_routing_arp_add_default_msg_req *req;
-	struct pipeline_routing_arp_add_default_msg_rsp *rsp;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_routing);
-	if (p == NULL)
-		return -1;
-
-	if (port_id >= p->n_ports_out)
-		return -1;
-
-	/* 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_DEFAULT);
-	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;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_routing);
-	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_DEFAULT);
-	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;
-}
-
-int
-app_pipeline_routing_set_macaddr(struct app_params *app,
-	uint32_t pipeline_id)
-{
-	struct app_pipeline_params *p;
-	struct pipeline_routing_set_macaddr_msg_req *req;
-	struct pipeline_routing_set_macaddr_msg_rsp *rsp;
-	uint32_t port_id;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -EINVAL;
-
-	APP_PARAM_FIND_BY_ID(app->pipeline_params, "PIPELINE", pipeline_id, p);
-	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_SET_MACADDR;
-
-	memset(req->macaddr, 0, sizeof(req->macaddr));
-	for (port_id = 0; port_id < p->n_pktq_out; port_id++) {
-		struct app_link_params *link;
-
-		link = app_pipeline_track_pktq_out_to_link(app,
-			pipeline_id,
-			port_id);
-		if (link)
-			req->macaddr[port_id] = link->mac_addr;
-	}
-
-	/* Send request and wait for response */
-	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL)
-		return -ETIMEDOUT;
-
-	/* Read response and write entry */
-	if (rsp->status) {
-		app_msg_free(app, rsp);
-		return rsp->status;
-	}
-
-	/* Free response */
-	app_msg_free(app, rsp);
-
-	return 0;
-}
-
-/*
- * route
- *
- * route add (ARP = ON/OFF, MPLS = ON/OFF, QINQ = ON/OFF):
- *    p <pipelineid> route add <ipaddr> <depth> port <portid> ether <nhmacaddr>
- *    p <pipelineid> route add <ipaddr> <depth> port <portid> ether <nhipaddr>
- *    p <pipelineid> route add <ipaddr> <depth> port <portid> ether <nhmacaddr> qinq <svlan> <cvlan>
- *    p <pipelineid> route add <ipaddr> <depth> port <portid> ether <nhipaddr> qinq <svlan> <cvlan>
- *    p <pipelineid> route add <ipaddr> <depth> port <portid> ether <nhmacaddr> mpls <mpls labels>
- *    p <pipelineid> route add <ipaddr> <depth> port <portid> ether <nhipaddr> mpls <mpls labels>
- *
- * route add default:
- *    p <pipelineid> route add default <portid>
- *
- * route del:
- *    p <pipelineid> route del <ipaddr> <depth>
- *
- * route del default:
- *    p <pipelineid> route del default
- *
- * route ls:
- *    p <pipelineid> route ls
- */
-
-struct cmd_route_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t p;
-	cmdline_fixed_string_t route_string;
-	cmdline_multi_string_t multi_string;
-};
-
-static void
-cmd_route_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_route_result *params = parsed_result;
-	struct app_params *app = data;
-
-	char *tokens[16];
-	uint32_t n_tokens = RTE_DIM(tokens);
-	int status;
-
-	status = parse_tokenize_string(params->multi_string, tokens, &n_tokens);
-	if (status != 0) {
-		printf(CMD_MSG_TOO_MANY_ARGS, "route");
-		return;
-	}
-
-	/* route add */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "add") == 0) &&
-		strcmp(tokens[1], "default")) {
-		struct pipeline_routing_route_key key;
-		struct pipeline_routing_route_data route_data;
-		struct in_addr ipv4, nh_ipv4;
-		struct ether_addr mac_addr;
-		uint32_t depth, port_id, svlan, cvlan, i;
-		uint32_t mpls_labels[PIPELINE_ROUTING_MPLS_LABELS_MAX];
-		uint32_t n_labels = RTE_DIM(mpls_labels);
-
-		memset(&key, 0, sizeof(key));
-		memset(&route_data, 0, sizeof(route_data));
-
-		if (n_tokens < 7) {
-			printf(CMD_MSG_NOT_ENOUGH_ARGS, "route add");
-			return;
-		}
-
-		if (parse_ipv4_addr(tokens[1], &ipv4)) {
-			printf(CMD_MSG_INVALID_ARG, "ipaddr");
-			return;
-		}
-
-		if (parser_read_uint32(&depth, tokens[2])) {
-			printf(CMD_MSG_INVALID_ARG, "depth");
-			return;
-		}
-
-		if (strcmp(tokens[3], "port")) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "port");
-			return;
-		}
-
-		if (parser_read_uint32(&port_id, tokens[4])) {
-			printf(CMD_MSG_INVALID_ARG, "portid");
-			return;
-		}
-
-		if (strcmp(tokens[5], "ether")) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "ether");
-			return;
-		}
-
-		if (parse_mac_addr(tokens[6], &mac_addr)) {
-			if (parse_ipv4_addr(tokens[6], &nh_ipv4)) {
-				printf(CMD_MSG_INVALID_ARG, "nhmacaddr or nhipaddr");
-				return;
-			}
-
-			route_data.flags |= PIPELINE_ROUTING_ROUTE_ARP;
-		}
-
-		if (n_tokens > 7) {
-			if (strcmp(tokens[7], "mpls") == 0) {
-				if (n_tokens != 9) {
-					printf(CMD_MSG_MISMATCH_ARGS, "route add mpls");
-					return;
-				}
-
-				if (parse_mpls_labels(tokens[8], mpls_labels, &n_labels)) {
-					printf(CMD_MSG_INVALID_ARG, "mpls labels");
-					return;
-				}
-
-				route_data.flags |= PIPELINE_ROUTING_ROUTE_MPLS;
-			} else if (strcmp(tokens[7], "qinq") == 0) {
-				if (n_tokens != 10) {
-					printf(CMD_MSG_MISMATCH_ARGS, "route add qinq");
-					return;
-				}
-
-				if (parser_read_uint32(&svlan, tokens[8])) {
-					printf(CMD_MSG_INVALID_ARG, "svlan");
-					return;
-				}
-				if (parser_read_uint32(&cvlan, tokens[9])) {
-					printf(CMD_MSG_INVALID_ARG, "cvlan");
-					return;
-				}
-
-				route_data.flags |= PIPELINE_ROUTING_ROUTE_QINQ;
-			} else {
-				printf(CMD_MSG_ARG_NOT_FOUND, "mpls or qinq");
-				return;
-			}
-		}
-
-		switch (route_data.flags) {
-		case 0:
-			route_data.port_id = port_id;
-			route_data.ethernet.macaddr = mac_addr;
-			break;
-
-		case PIPELINE_ROUTING_ROUTE_ARP:
-			route_data.port_id = port_id;
-			route_data.ethernet.ip = rte_be_to_cpu_32(nh_ipv4.s_addr);
-			break;
-
-		case PIPELINE_ROUTING_ROUTE_MPLS:
-			route_data.port_id = port_id;
-			route_data.ethernet.macaddr = mac_addr;
-			for (i = 0; i < n_labels; i++)
-				route_data.l2.mpls.labels[i] = mpls_labels[i];
-			route_data.l2.mpls.n_labels = n_labels;
-			break;
-
-		case PIPELINE_ROUTING_ROUTE_MPLS | PIPELINE_ROUTING_ROUTE_ARP:
-			route_data.port_id = port_id;
-			route_data.ethernet.ip = rte_be_to_cpu_32(nh_ipv4.s_addr);
-			for (i = 0; i < n_labels; i++)
-				route_data.l2.mpls.labels[i] = mpls_labels[i];
-			route_data.l2.mpls.n_labels = n_labels;
-			break;
-
-		case PIPELINE_ROUTING_ROUTE_QINQ:
-			route_data.port_id = port_id;
-			route_data.ethernet.macaddr = mac_addr;
-			route_data.l2.qinq.svlan = svlan;
-			route_data.l2.qinq.cvlan = cvlan;
-			break;
-
-		case PIPELINE_ROUTING_ROUTE_QINQ | PIPELINE_ROUTING_ROUTE_ARP:
-		default:
-			route_data.port_id = port_id;
-			route_data.ethernet.ip = rte_be_to_cpu_32(nh_ipv4.s_addr);
-			route_data.l2.qinq.svlan = svlan;
-			route_data.l2.qinq.cvlan = cvlan;
-			break;
-		}
-
-		key.type = PIPELINE_ROUTING_ROUTE_IPV4;
-		key.key.ipv4.ip = rte_be_to_cpu_32(ipv4.s_addr);
-		key.key.ipv4.depth = depth;
-
-		status = app_pipeline_routing_add_route(app,
-			params->p,
-			&key,
-			&route_data);
-		if (status != 0)
-			printf(CMD_MSG_FAIL, "route add");
-
-		return;
-	} /* route add */
-
-	/* route add default */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "add") == 0) &&
-		(strcmp(tokens[1], "default") == 0)) {
-		uint32_t port_id;
-
-		if (n_tokens != 3) {
-			printf(CMD_MSG_MISMATCH_ARGS, "route add default");
-			return;
-		}
-
-		if (parser_read_uint32(&port_id, tokens[2])) {
-			printf(CMD_MSG_INVALID_ARG, "portid");
-			return;
-		}
-
-		status = app_pipeline_routing_add_default_route(app,
-			params->p,
-			port_id);
-		if (status != 0)
-			printf(CMD_MSG_FAIL, "route add default");
-
-		return;
-	} /* route add default */
-
-	/* route del*/
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "del") == 0) &&
-		strcmp(tokens[1], "default")) {
-		struct pipeline_routing_route_key key;
-		struct in_addr ipv4;
-		uint32_t depth;
-
-		memset(&key, 0, sizeof(key));
-
-		if (n_tokens != 3) {
-			printf(CMD_MSG_MISMATCH_ARGS, "route del");
-			return;
-		}
-
-		if (parse_ipv4_addr(tokens[1], &ipv4)) {
-			printf(CMD_MSG_INVALID_ARG, "ipaddr");
-			return;
-		}
-
-		if (parser_read_uint32(&depth, tokens[2])) {
-			printf(CMD_MSG_INVALID_ARG, "depth");
-			return;
-		}
-
-		key.type = PIPELINE_ROUTING_ROUTE_IPV4;
-		key.key.ipv4.ip = rte_be_to_cpu_32(ipv4.s_addr);
-		key.key.ipv4.depth = depth;
-
-		status = app_pipeline_routing_delete_route(app, params->p, &key);
-		if (status != 0)
-			printf(CMD_MSG_FAIL, "route del");
-
-		return;
-	} /* route del */
-
-	/* route del default */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "del") == 0) &&
-		(strcmp(tokens[1], "default") == 0)) {
-		if (n_tokens != 2) {
-			printf(CMD_MSG_MISMATCH_ARGS, "route del default");
-			return;
-		}
-
-		status = app_pipeline_routing_delete_default_route(app,
-			params->p);
-		if (status != 0)
-			printf(CMD_MSG_FAIL, "route del default");
-
-		return;
-	} /* route del default */
-
-	/* route ls */
-	if ((n_tokens >= 1) && (strcmp(tokens[0], "ls") == 0)) {
-		if (n_tokens != 1) {
-			printf(CMD_MSG_MISMATCH_ARGS, "route ls");
-			return;
-		}
-
-		status = app_pipeline_routing_route_ls(app, params->p);
-		if (status != 0)
-			printf(CMD_MSG_FAIL, "route ls");
-
-		return;
-	} /* route ls */
-
-	printf(CMD_MSG_MISMATCH_ARGS, "route");
-}
-
-static cmdline_parse_token_string_t cmd_route_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_result, p_string, "p");
-
-static cmdline_parse_token_num_t cmd_route_p =
-	TOKEN_NUM_INITIALIZER(struct cmd_route_result, p, UINT32);
-
-static cmdline_parse_token_string_t cmd_route_route_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_result, route_string, "route");
-
-static cmdline_parse_token_string_t cmd_route_multi_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_route_result, multi_string,
-	TOKEN_STRING_MULTI);
-
-static cmdline_parse_inst_t cmd_route = {
-	.f = cmd_route_parsed,
-	.data = NULL,
-	.help_str = "route add / add default / del / del default / ls",
-	.tokens = {
-		(void *)&cmd_route_p_string,
-		(void *)&cmd_route_p,
-		(void *)&cmd_route_route_string,
-		(void *)&cmd_route_multi_string,
-		NULL,
-	},
-};
-
-/*
- * arp
- *
- * arp add:
- *    p <pipelineid> arp add <portid> <ipaddr> <macaddr>
- *
- * arp add default:
- *    p <pipelineid> arp add default <portid>
- *
- * arp del:
- *    p <pipelineid> arp del <portid> <ipaddr>
- *
- * arp del default:
- *    p <pipelineid> arp del default
- *
- * arp ls:
- *    p <pipelineid> arp ls
- */
-
-struct cmd_arp_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t p;
-	cmdline_fixed_string_t arp_string;
-	cmdline_multi_string_t multi_string;
-};
-
-static void
-cmd_arp_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_arp_result *params = parsed_result;
-	struct app_params *app = data;
-
-	char *tokens[16];
-	uint32_t n_tokens = RTE_DIM(tokens);
-	int status;
-
-	status = parse_tokenize_string(params->multi_string, tokens, &n_tokens);
-	if (status != 0) {
-		printf(CMD_MSG_TOO_MANY_ARGS, "arp");
-		return;
-	}
-
-	/* arp add */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "add") == 0) &&
-		strcmp(tokens[1], "default")) {
-		struct pipeline_routing_arp_key key;
-		struct in_addr ipv4;
-		struct ether_addr mac_addr;
-		uint32_t port_id;
-
-		memset(&key, 0, sizeof(key));
-
-		if (n_tokens != 4) {
-			printf(CMD_MSG_MISMATCH_ARGS, "arp add");
-			return;
-		}
-
-		if (parser_read_uint32(&port_id, tokens[1])) {
-			printf(CMD_MSG_INVALID_ARG, "portid");
-			return;
-		}
-
-		if (parse_ipv4_addr(tokens[2], &ipv4)) {
-			printf(CMD_MSG_INVALID_ARG, "ipaddr");
-			return;
-		}
-
-		if (parse_mac_addr(tokens[3], &mac_addr)) {
-			printf(CMD_MSG_INVALID_ARG, "macaddr");
-			return;
-		}
-
-		key.type = PIPELINE_ROUTING_ARP_IPV4;
-		key.key.ipv4.port_id = port_id;
-		key.key.ipv4.ip = rte_be_to_cpu_32(ipv4.s_addr);
-
-		status = app_pipeline_routing_add_arp_entry(app,
-			params->p,
-			&key,
-			&mac_addr);
-		if (status != 0)
-			printf(CMD_MSG_FAIL, "arp add");
-
-		return;
-	} /* arp add */
-
-	/* arp add default */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "add") == 0) &&
-		(strcmp(tokens[1], "default") == 0)) {
-		uint32_t port_id;
-
-		if (n_tokens != 3) {
-			printf(CMD_MSG_MISMATCH_ARGS, "arp add default");
-			return;
-		}
-
-		if (parser_read_uint32(&port_id, tokens[2])) {
-			printf(CMD_MSG_INVALID_ARG, "portid");
-			return;
-		}
-
-		status = app_pipeline_routing_add_default_arp_entry(app,
-			params->p,
-			port_id);
-		if (status != 0)
-			printf(CMD_MSG_FAIL, "arp add default");
-
-		return;
-	} /* arp add default */
-
-	/* arp del*/
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "del") == 0) &&
-		strcmp(tokens[1], "default")) {
-		struct pipeline_routing_arp_key key;
-		struct in_addr ipv4;
-		uint32_t port_id;
-
-		memset(&key, 0, sizeof(key));
-
-		if (n_tokens != 3) {
-			printf(CMD_MSG_MISMATCH_ARGS, "arp del");
-			return;
-		}
-
-		if (parser_read_uint32(&port_id, tokens[1])) {
-			printf(CMD_MSG_INVALID_ARG, "portid");
-			return;
-		}
-
-		if (parse_ipv4_addr(tokens[2], &ipv4)) {
-			printf(CMD_MSG_INVALID_ARG, "ipaddr");
-			return;
-		}
-
-		key.type = PIPELINE_ROUTING_ARP_IPV4;
-		key.key.ipv4.ip = rte_be_to_cpu_32(ipv4.s_addr);
-		key.key.ipv4.port_id = port_id;
-
-		status = app_pipeline_routing_delete_arp_entry(app,
-			params->p,
-			&key);
-		if (status != 0)
-			printf(CMD_MSG_FAIL, "arp del");
-
-		return;
-	} /* arp del */
-
-	/* arp del default */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "del") == 0) &&
-		(strcmp(tokens[1], "default") == 0)) {
-			if (n_tokens != 2) {
-				printf(CMD_MSG_MISMATCH_ARGS, "arp del default");
-				return;
-			}
-
-			status = app_pipeline_routing_delete_default_arp_entry(app,
-				params->p);
-			if (status != 0)
-				printf(CMD_MSG_FAIL, "arp del default");
-
-			return;
-	} /* arp del default */
-
-	/* arp ls */
-	if ((n_tokens >= 1) && (strcmp(tokens[0], "ls") == 0)) {
-		if (n_tokens != 1) {
-			printf(CMD_MSG_MISMATCH_ARGS, "arp ls");
-			return;
-		}
-
-		status = app_pipeline_routing_arp_ls(app, params->p);
-		if (status != 0)
-			printf(CMD_MSG_FAIL, "arp ls");
-
-		return;
-	} /* arp ls */
-
-	printf(CMD_MSG_FAIL, "arp");
-}
-
-static cmdline_parse_token_string_t cmd_arp_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_result, p_string, "p");
-
-static cmdline_parse_token_num_t cmd_arp_p =
-	TOKEN_NUM_INITIALIZER(struct cmd_arp_result, p, UINT32);
-
-static cmdline_parse_token_string_t cmd_arp_arp_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_result, arp_string, "arp");
-
-static cmdline_parse_token_string_t cmd_arp_multi_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_arp_result, multi_string,
-	TOKEN_STRING_MULTI);
-
-static cmdline_parse_inst_t cmd_arp = {
-	.f = cmd_arp_parsed,
-	.data = NULL,
-	.help_str = "arp add / add default / del / del default / ls",
-	.tokens = {
-		(void *)&cmd_arp_p_string,
-		(void *)&cmd_arp_p,
-		(void *)&cmd_arp_arp_string,
-		(void *)&cmd_arp_multi_string,
-		NULL,
-	},
-};
-
-static cmdline_parse_ctx_t pipeline_cmds[] = {
-	(cmdline_parse_inst_t *)&cmd_route,
-	(cmdline_parse_inst_t *)&cmd_arp,
-	NULL,
-};
-
-static struct pipeline_fe_ops pipeline_routing_fe_ops = {
-	.f_init = app_pipeline_routing_init,
-	.f_post_init = app_pipeline_routing_post_init,
-	.f_free = app_pipeline_routing_free,
-	.f_track = app_pipeline_track_default,
-	.cmds = pipeline_cmds,
-};
-
-struct pipeline_type pipeline_routing = {
-	.name = "ROUTING",
-	.be_ops = &pipeline_routing_be_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
deleted file mode 100644
index f249295..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_routing.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#ifndef __INCLUDE_PIPELINE_ROUTING_H__
-#define __INCLUDE_PIPELINE_ROUTING_H__
-
-#include "pipeline.h"
-#include "pipeline_routing_be.h"
-
-/*
- * Route
- */
-
-int
-app_pipeline_routing_add_route(struct app_params *app,
-	uint32_t pipeline_id,
-	struct pipeline_routing_route_key *key,
-	struct pipeline_routing_route_data *data);
-
-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);
-
-/*
- * SETTINGS
- */
-int
-app_pipeline_routing_set_macaddr(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_be.c b/examples/ip_pipeline/pipeline/pipeline_routing_be.c
deleted file mode 100644
index 6258a1a..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_routing_be.c
+++ /dev/null
@@ -1,1966 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2016 Intel Corporation
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <rte_common.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_routing_be.h"
-#include "pipeline_actions_common.h"
-#include "parser.h"
-#include "hash_func.h"
-
-#define MPLS_LABEL(label, exp, s, ttl)					\
-	(((((uint64_t) (label)) & 0xFFFFFLLU) << 12) |		\
-	((((uint64_t) (exp)) & 0x7LLU) << 9) |				\
-	((((uint64_t) (s)) & 0x1LLU) << 8) |				\
-	(((uint64_t) (ttl)) & 0xFFLU))
-
-#define RTE_SCHED_PORT_HIERARCHY(subport, pipe,		\
-	traffic_class, queue, color)				\
-	((((uint64_t) (queue)) & 0x3) |                \
-	((((uint64_t) (traffic_class)) & 0x3) << 2) |  \
-	((((uint64_t) (color)) & 0x3) << 4) |          \
-	((((uint64_t) (subport)) & 0xFFFF) << 16) |    \
-	((((uint64_t) (pipe)) & 0xFFFFFFFF) << 32))
-
-
-/* Network Byte Order (NBO) */
-#define SLAB_NBO_MACADDRSRC_ETHERTYPE(macaddr, ethertype)	\
-	(((uint64_t) macaddr) | (((uint64_t) rte_cpu_to_be_16(ethertype)) << 48))
-
-#ifndef PIPELINE_ROUTING_LPM_TABLE_NUMBER_TABLE8s
-#define PIPELINE_ROUTING_LPM_TABLE_NUMBER_TABLE8s 256
-#endif
-
-struct pipeline_routing {
-	struct pipeline p;
-	struct pipeline_routing_params params;
-	pipeline_msg_req_handler custom_handlers[PIPELINE_ROUTING_MSG_REQS];
-	uint64_t macaddr[PIPELINE_MAX_PORT_OUT];
-} __rte_cache_aligned;
-
-/*
- * Message handlers
- */
-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 void *
-pipeline_routing_msg_req_set_macaddr_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,
-	[PIPELINE_ROUTING_MSG_REQ_SET_MACADDR] =
-		pipeline_routing_msg_req_set_macaddr_handler,
-};
-
-/*
- * Routing table
- */
-struct routing_table_entry {
-	struct rte_pipeline_table_entry head;
-	uint32_t flags;
-	uint32_t port_id; /* Output port ID */
-	uint32_t ip; /* Next hop IP address (only valid for remote routes) */
-
-	/* ether_l2 */
-	uint16_t data_offset;
-	uint16_t ether_l2_length;
-	uint64_t slab[4];
-	uint16_t slab_offset[4];
-};
-
-struct layout {
-	uint16_t a;
-	uint32_t b;
-	uint16_t c;
-} __attribute__((__packed__));
-
-#define MACADDR_DST_WRITE(slab_ptr, slab)			\
-{								\
-	struct layout *dst = (struct layout *) (slab_ptr);	\
-	struct layout *src = (struct layout *) &(slab);		\
-								\
-	dst->b = src->b;					\
-	dst->c = src->c;					\
-}
-
-static __rte_always_inline void
-pkt_work_routing(
-	struct rte_mbuf *pkt,
-	struct rte_pipeline_table_entry *table_entry,
-	void *arg,
-	int arp,
-	int qinq,
-	int qinq_sched,
-	int mpls,
-	int mpls_color_mark)
-{
-	struct pipeline_routing *p_rt = arg;
-
-	struct routing_table_entry *entry =
-		(struct routing_table_entry *) table_entry;
-
-	struct ipv4_hdr *ip = (struct ipv4_hdr *)
-		RTE_MBUF_METADATA_UINT8_PTR(pkt, p_rt->params.ip_hdr_offset);
-
-	enum rte_meter_color pkt_color = (enum rte_meter_color)
-		RTE_MBUF_METADATA_UINT32(pkt, p_rt->params.color_offset);
-
-	struct pipeline_routing_arp_key_ipv4 *arp_key =
-		(struct pipeline_routing_arp_key_ipv4 *)
-		RTE_MBUF_METADATA_UINT8_PTR(pkt, p_rt->params.arp_key_offset);
-
-	uint64_t *slab0_ptr, *slab1_ptr, *slab2_ptr, *slab3_ptr, sched;
-	uint32_t ip_da, nh_ip, port_id;
-	uint16_t total_length, data_offset, ether_l2_length;
-
-	/* Read */
-	total_length = rte_bswap16(ip->total_length);
-	ip_da = ip->dst_addr;
-	data_offset = entry->data_offset;
-	ether_l2_length = entry->ether_l2_length;
-	slab0_ptr = RTE_MBUF_METADATA_UINT64_PTR(pkt, entry->slab_offset[0]);
-	slab1_ptr = RTE_MBUF_METADATA_UINT64_PTR(pkt, entry->slab_offset[1]);
-	slab2_ptr = RTE_MBUF_METADATA_UINT64_PTR(pkt, entry->slab_offset[2]);
-	slab3_ptr = RTE_MBUF_METADATA_UINT64_PTR(pkt, entry->slab_offset[3]);
-
-	if (arp) {
-		port_id = entry->port_id;
-		nh_ip = entry->ip;
-		if (entry->flags & PIPELINE_ROUTING_ROUTE_LOCAL)
-			nh_ip = ip_da;
-	}
-
-	/* Compute */
-	total_length += ether_l2_length;
-
-	if (qinq && qinq_sched) {
-		uint32_t dscp = ip->type_of_service >> 2;
-		uint32_t svlan, cvlan, tc, tc_q;
-
-		if (qinq_sched == 1) {
-			uint64_t slab_qinq = rte_bswap64(entry->slab[0]);
-
-			svlan = (slab_qinq >> 48) & 0xFFF;
-			cvlan = (slab_qinq >> 16) & 0xFFF;
-			tc = (dscp >> 2) & 0x3;
-			tc_q = dscp & 0x3;
-		} else {
-			uint32_t ip_src = rte_bswap32(ip->src_addr);
-
-			svlan = 0;
-			cvlan = (ip_src >> 16) & 0xFFF;
-			tc = (ip_src >> 2) & 0x3;
-			tc_q = ip_src & 0x3;
-		}
-		sched = RTE_SCHED_PORT_HIERARCHY(svlan,
-			cvlan,
-			tc,
-			tc_q,
-			e_RTE_METER_GREEN);
-	}
-
-	/* Write */
-	pkt->data_off = data_offset;
-	pkt->data_len = total_length;
-	pkt->pkt_len = total_length;
-
-	if ((qinq == 0) && (mpls == 0)) {
-		*slab0_ptr = entry->slab[0];
-
-		if (arp == 0)
-			MACADDR_DST_WRITE(slab1_ptr, entry->slab[1]);
-	}
-
-	if (qinq) {
-		*slab0_ptr = entry->slab[0];
-		*slab1_ptr = entry->slab[1];
-
-		if (arp == 0)
-			MACADDR_DST_WRITE(slab2_ptr, entry->slab[2]);
-
-		if (qinq_sched) {
-			pkt->hash.sched.lo = sched & 0xFFFFFFFF;
-			pkt->hash.sched.hi = sched >> 32;
-		}
-	}
-
-	if (mpls) {
-		if (mpls_color_mark) {
-			uint64_t mpls_exp = rte_bswap64(
-				(MPLS_LABEL(0, pkt_color, 0, 0) << 32) |
-				MPLS_LABEL(0, pkt_color, 0, 0));
-
-			*slab0_ptr = entry->slab[0] | mpls_exp;
-			*slab1_ptr = entry->slab[1] | mpls_exp;
-			*slab2_ptr = entry->slab[2];
-		} else {
-			*slab0_ptr = entry->slab[0];
-			*slab1_ptr = entry->slab[1];
-			*slab2_ptr = entry->slab[2];
-		}
-
-		if (arp == 0)
-			MACADDR_DST_WRITE(slab3_ptr, entry->slab[3]);
-	}
-
-	if (arp) {
-		arp_key->port_id = port_id;
-		arp_key->ip = nh_ip;
-	}
-}
-
-static __rte_always_inline void
-pkt4_work_routing(
-	struct rte_mbuf **pkts,
-	struct rte_pipeline_table_entry **table_entries,
-	void *arg,
-	int arp,
-	int qinq,
-	int qinq_sched,
-	int mpls,
-	int mpls_color_mark)
-{
-	struct pipeline_routing *p_rt = arg;
-
-	struct routing_table_entry *entry0 =
-		(struct routing_table_entry *) table_entries[0];
-	struct routing_table_entry *entry1 =
-		(struct routing_table_entry *) table_entries[1];
-	struct routing_table_entry *entry2 =
-		(struct routing_table_entry *) table_entries[2];
-	struct routing_table_entry *entry3 =
-		(struct routing_table_entry *) table_entries[3];
-
-	struct ipv4_hdr *ip0 = (struct ipv4_hdr *)
-		RTE_MBUF_METADATA_UINT8_PTR(pkts[0],
-			p_rt->params.ip_hdr_offset);
-	struct ipv4_hdr *ip1 = (struct ipv4_hdr *)
-		RTE_MBUF_METADATA_UINT8_PTR(pkts[1],
-			p_rt->params.ip_hdr_offset);
-	struct ipv4_hdr *ip2 = (struct ipv4_hdr *)
-		RTE_MBUF_METADATA_UINT8_PTR(pkts[2],
-			p_rt->params.ip_hdr_offset);
-	struct ipv4_hdr *ip3 = (struct ipv4_hdr *)
-		RTE_MBUF_METADATA_UINT8_PTR(pkts[3],
-			p_rt->params.ip_hdr_offset);
-
-	enum rte_meter_color pkt0_color = (enum rte_meter_color)
-		RTE_MBUF_METADATA_UINT32(pkts[0], p_rt->params.color_offset);
-	enum rte_meter_color pkt1_color = (enum rte_meter_color)
-		RTE_MBUF_METADATA_UINT32(pkts[1], p_rt->params.color_offset);
-	enum rte_meter_color pkt2_color = (enum rte_meter_color)
-		RTE_MBUF_METADATA_UINT32(pkts[2], p_rt->params.color_offset);
-	enum rte_meter_color pkt3_color = (enum rte_meter_color)
-		RTE_MBUF_METADATA_UINT32(pkts[3], p_rt->params.color_offset);
-
-	struct pipeline_routing_arp_key_ipv4 *arp_key0 =
-		(struct pipeline_routing_arp_key_ipv4 *)
-		RTE_MBUF_METADATA_UINT8_PTR(pkts[0],
-			p_rt->params.arp_key_offset);
-	struct pipeline_routing_arp_key_ipv4 *arp_key1 =
-		(struct pipeline_routing_arp_key_ipv4 *)
-		RTE_MBUF_METADATA_UINT8_PTR(pkts[1],
-			p_rt->params.arp_key_offset);
-	struct pipeline_routing_arp_key_ipv4 *arp_key2 =
-		(struct pipeline_routing_arp_key_ipv4 *)
-		RTE_MBUF_METADATA_UINT8_PTR(pkts[2],
-			p_rt->params.arp_key_offset);
-	struct pipeline_routing_arp_key_ipv4 *arp_key3 =
-		(struct pipeline_routing_arp_key_ipv4 *)
-		RTE_MBUF_METADATA_UINT8_PTR(pkts[3],
-			p_rt->params.arp_key_offset);
-
-	uint64_t *slab0_ptr0, *slab1_ptr0, *slab2_ptr0, *slab3_ptr0;
-	uint64_t *slab0_ptr1, *slab1_ptr1, *slab2_ptr1, *slab3_ptr1;
-	uint64_t *slab0_ptr2, *slab1_ptr2, *slab2_ptr2, *slab3_ptr2;
-	uint64_t *slab0_ptr3, *slab1_ptr3, *slab2_ptr3, *slab3_ptr3;
-	uint64_t sched0, sched1, sched2, sched3;
-
-	uint32_t ip_da0, nh_ip0, port_id0;
-	uint32_t ip_da1, nh_ip1, port_id1;
-	uint32_t ip_da2, nh_ip2, port_id2;
-	uint32_t ip_da3, nh_ip3, port_id3;
-
-	uint16_t total_length0, data_offset0, ether_l2_length0;
-	uint16_t total_length1, data_offset1, ether_l2_length1;
-	uint16_t total_length2, data_offset2, ether_l2_length2;
-	uint16_t total_length3, data_offset3, ether_l2_length3;
-
-	/* Read */
-	total_length0 = rte_bswap16(ip0->total_length);
-	total_length1 = rte_bswap16(ip1->total_length);
-	total_length2 = rte_bswap16(ip2->total_length);
-	total_length3 = rte_bswap16(ip3->total_length);
-
-	ip_da0 = ip0->dst_addr;
-	ip_da1 = ip1->dst_addr;
-	ip_da2 = ip2->dst_addr;
-	ip_da3 = ip3->dst_addr;
-
-	data_offset0 = entry0->data_offset;
-	data_offset1 = entry1->data_offset;
-	data_offset2 = entry2->data_offset;
-	data_offset3 = entry3->data_offset;
-
-	ether_l2_length0 = entry0->ether_l2_length;
-	ether_l2_length1 = entry1->ether_l2_length;
-	ether_l2_length2 = entry2->ether_l2_length;
-	ether_l2_length3 = entry3->ether_l2_length;
-
-	slab0_ptr0 = RTE_MBUF_METADATA_UINT64_PTR(pkts[0],
-		entry0->slab_offset[0]);
-	slab1_ptr0 = RTE_MBUF_METADATA_UINT64_PTR(pkts[0],
-		entry0->slab_offset[1]);
-	slab2_ptr0 = RTE_MBUF_METADATA_UINT64_PTR(pkts[0],
-		entry0->slab_offset[2]);
-	slab3_ptr0 = RTE_MBUF_METADATA_UINT64_PTR(pkts[0],
-		entry0->slab_offset[3]);
-
-	slab0_ptr1 = RTE_MBUF_METADATA_UINT64_PTR(pkts[1],
-		entry1->slab_offset[0]);
-	slab1_ptr1 = RTE_MBUF_METADATA_UINT64_PTR(pkts[1],
-		entry1->slab_offset[1]);
-	slab2_ptr1 = RTE_MBUF_METADATA_UINT64_PTR(pkts[1],
-		entry1->slab_offset[2]);
-	slab3_ptr1 = RTE_MBUF_METADATA_UINT64_PTR(pkts[1],
-		entry1->slab_offset[3]);
-
-	slab0_ptr2 = RTE_MBUF_METADATA_UINT64_PTR(pkts[2],
-		entry2->slab_offset[0]);
-	slab1_ptr2 = RTE_MBUF_METADATA_UINT64_PTR(pkts[2],
-		entry2->slab_offset[1]);
-	slab2_ptr2 = RTE_MBUF_METADATA_UINT64_PTR(pkts[2],
-		entry2->slab_offset[2]);
-	slab3_ptr2 = RTE_MBUF_METADATA_UINT64_PTR(pkts[2],
-		entry2->slab_offset[3]);
-
-	slab0_ptr3 = RTE_MBUF_METADATA_UINT64_PTR(pkts[3],
-		entry3->slab_offset[0]);
-	slab1_ptr3 = RTE_MBUF_METADATA_UINT64_PTR(pkts[3],
-		entry3->slab_offset[1]);
-	slab2_ptr3 = RTE_MBUF_METADATA_UINT64_PTR(pkts[3],
-		entry3->slab_offset[2]);
-	slab3_ptr3 = RTE_MBUF_METADATA_UINT64_PTR(pkts[3],
-		entry3->slab_offset[3]);
-
-	if (arp) {
-		port_id0 = entry0->port_id;
-		nh_ip0 = entry0->ip;
-		if (entry0->flags & PIPELINE_ROUTING_ROUTE_LOCAL)
-			nh_ip0 = ip_da0;
-
-		port_id1 = entry1->port_id;
-		nh_ip1 = entry1->ip;
-		if (entry1->flags & PIPELINE_ROUTING_ROUTE_LOCAL)
-			nh_ip1 = ip_da1;
-
-		port_id2 = entry2->port_id;
-		nh_ip2 = entry2->ip;
-		if (entry2->flags & PIPELINE_ROUTING_ROUTE_LOCAL)
-			nh_ip2 = ip_da2;
-
-		port_id3 = entry3->port_id;
-		nh_ip3 = entry3->ip;
-		if (entry3->flags & PIPELINE_ROUTING_ROUTE_LOCAL)
-			nh_ip3 = ip_da3;
-	}
-
-	/* Compute */
-	total_length0 += ether_l2_length0;
-	total_length1 += ether_l2_length1;
-	total_length2 += ether_l2_length2;
-	total_length3 += ether_l2_length3;
-
-	if (qinq && qinq_sched) {
-		uint32_t dscp0 = ip0->type_of_service >> 2;
-		uint32_t dscp1 = ip1->type_of_service >> 2;
-		uint32_t dscp2 = ip2->type_of_service >> 2;
-		uint32_t dscp3 = ip3->type_of_service >> 2;
-		uint32_t svlan0, cvlan0, tc0, tc_q0;
-		uint32_t svlan1, cvlan1, tc1, tc_q1;
-		uint32_t svlan2, cvlan2, tc2, tc_q2;
-		uint32_t svlan3, cvlan3, tc3, tc_q3;
-
-		if (qinq_sched == 1) {
-			uint64_t slab_qinq0 = rte_bswap64(entry0->slab[0]);
-			uint64_t slab_qinq1 = rte_bswap64(entry1->slab[0]);
-			uint64_t slab_qinq2 = rte_bswap64(entry2->slab[0]);
-			uint64_t slab_qinq3 = rte_bswap64(entry3->slab[0]);
-
-			svlan0 = (slab_qinq0 >> 48) & 0xFFF;
-			svlan1 = (slab_qinq1 >> 48) & 0xFFF;
-			svlan2 = (slab_qinq2 >> 48) & 0xFFF;
-			svlan3 = (slab_qinq3 >> 48) & 0xFFF;
-
-			cvlan0 = (slab_qinq0 >> 16) & 0xFFF;
-			cvlan1 = (slab_qinq1 >> 16) & 0xFFF;
-			cvlan2 = (slab_qinq2 >> 16) & 0xFFF;
-			cvlan3 = (slab_qinq3 >> 16) & 0xFFF;
-
-			tc0 = (dscp0 >> 2) & 0x3;
-			tc1 = (dscp1 >> 2) & 0x3;
-			tc2 = (dscp2 >> 2) & 0x3;
-			tc3 = (dscp3 >> 2) & 0x3;
-
-			tc_q0 = dscp0 & 0x3;
-			tc_q1 = dscp1 & 0x3;
-			tc_q2 = dscp2 & 0x3;
-			tc_q3 = dscp3 & 0x3;
-		} else {
-			uint32_t ip_src0 = rte_bswap32(ip0->src_addr);
-			uint32_t ip_src1 = rte_bswap32(ip1->src_addr);
-			uint32_t ip_src2 = rte_bswap32(ip2->src_addr);
-			uint32_t ip_src3 = rte_bswap32(ip3->src_addr);
-
-			svlan0 = 0;
-			svlan1 = 0;
-			svlan2 = 0;
-			svlan3 = 0;
-
-			cvlan0 = (ip_src0 >> 16) & 0xFFF;
-			cvlan1 = (ip_src1 >> 16) & 0xFFF;
-			cvlan2 = (ip_src2 >> 16) & 0xFFF;
-			cvlan3 = (ip_src3 >> 16) & 0xFFF;
-
-			tc0 = (ip_src0 >> 2) & 0x3;
-			tc1 = (ip_src1 >> 2) & 0x3;
-			tc2 = (ip_src2 >> 2) & 0x3;
-			tc3 = (ip_src3 >> 2) & 0x3;
-
-			tc_q0 = ip_src0 & 0x3;
-			tc_q1 = ip_src1 & 0x3;
-			tc_q2 = ip_src2 & 0x3;
-			tc_q3 = ip_src3 & 0x3;
-		}
-
-		sched0 = RTE_SCHED_PORT_HIERARCHY(svlan0,
-			cvlan0,
-			tc0,
-			tc_q0,
-			e_RTE_METER_GREEN);
-		sched1 = RTE_SCHED_PORT_HIERARCHY(svlan1,
-			cvlan1,
-			tc1,
-			tc_q1,
-			e_RTE_METER_GREEN);
-		sched2 = RTE_SCHED_PORT_HIERARCHY(svlan2,
-			cvlan2,
-			tc2,
-			tc_q2,
-			e_RTE_METER_GREEN);
-		sched3 = RTE_SCHED_PORT_HIERARCHY(svlan3,
-			cvlan3,
-			tc3,
-			tc_q3,
-			e_RTE_METER_GREEN);
-
-	}
-
-	/* Write */
-	pkts[0]->data_off = data_offset0;
-	pkts[1]->data_off = data_offset1;
-	pkts[2]->data_off = data_offset2;
-	pkts[3]->data_off = data_offset3;
-
-	pkts[0]->data_len = total_length0;
-	pkts[1]->data_len = total_length1;
-	pkts[2]->data_len = total_length2;
-	pkts[3]->data_len = total_length3;
-
-	pkts[0]->pkt_len = total_length0;
-	pkts[1]->pkt_len = total_length1;
-	pkts[2]->pkt_len = total_length2;
-	pkts[3]->pkt_len = total_length3;
-
-	if ((qinq == 0) && (mpls == 0)) {
-		*slab0_ptr0 = entry0->slab[0];
-		*slab0_ptr1 = entry1->slab[0];
-		*slab0_ptr2 = entry2->slab[0];
-		*slab0_ptr3 = entry3->slab[0];
-
-		if (arp == 0) {
-			MACADDR_DST_WRITE(slab1_ptr0, entry0->slab[1]);
-			MACADDR_DST_WRITE(slab1_ptr1, entry1->slab[1]);
-			MACADDR_DST_WRITE(slab1_ptr2, entry2->slab[1]);
-			MACADDR_DST_WRITE(slab1_ptr3, entry3->slab[1]);
-		}
-	}
-
-	if (qinq) {
-		*slab0_ptr0 = entry0->slab[0];
-		*slab0_ptr1 = entry1->slab[0];
-		*slab0_ptr2 = entry2->slab[0];
-		*slab0_ptr3 = entry3->slab[0];
-
-		*slab1_ptr0 = entry0->slab[1];
-		*slab1_ptr1 = entry1->slab[1];
-		*slab1_ptr2 = entry2->slab[1];
-		*slab1_ptr3 = entry3->slab[1];
-
-		if (arp == 0) {
-			MACADDR_DST_WRITE(slab2_ptr0, entry0->slab[2]);
-			MACADDR_DST_WRITE(slab2_ptr1, entry1->slab[2]);
-			MACADDR_DST_WRITE(slab2_ptr2, entry2->slab[2]);
-			MACADDR_DST_WRITE(slab2_ptr3, entry3->slab[2]);
-		}
-
-		if (qinq_sched) {
-			pkts[0]->hash.sched.lo = sched0 & 0xFFFFFFFF;
-			pkts[0]->hash.sched.hi = sched0 >> 32;
-			pkts[1]->hash.sched.lo = sched1 & 0xFFFFFFFF;
-			pkts[1]->hash.sched.hi = sched1 >> 32;
-			pkts[2]->hash.sched.lo = sched2 & 0xFFFFFFFF;
-			pkts[2]->hash.sched.hi = sched2 >> 32;
-			pkts[3]->hash.sched.lo = sched3 & 0xFFFFFFFF;
-			pkts[3]->hash.sched.hi = sched3 >> 32;
-		}
-	}
-
-	if (mpls) {
-		if (mpls_color_mark) {
-			uint64_t mpls_exp0 = rte_bswap64(
-				(MPLS_LABEL(0, pkt0_color, 0, 0) << 32) |
-				MPLS_LABEL(0, pkt0_color, 0, 0));
-			uint64_t mpls_exp1 = rte_bswap64(
-				(MPLS_LABEL(0, pkt1_color, 0, 0) << 32) |
-				MPLS_LABEL(0, pkt1_color, 0, 0));
-			uint64_t mpls_exp2 = rte_bswap64(
-				(MPLS_LABEL(0, pkt2_color, 0, 0) << 32) |
-				MPLS_LABEL(0, pkt2_color, 0, 0));
-			uint64_t mpls_exp3 = rte_bswap64(
-				(MPLS_LABEL(0, pkt3_color, 0, 0) << 32) |
-				MPLS_LABEL(0, pkt3_color, 0, 0));
-
-			*slab0_ptr0 = entry0->slab[0] | mpls_exp0;
-			*slab0_ptr1 = entry1->slab[0] | mpls_exp1;
-			*slab0_ptr2 = entry2->slab[0] | mpls_exp2;
-			*slab0_ptr3 = entry3->slab[0] | mpls_exp3;
-
-			*slab1_ptr0 = entry0->slab[1] | mpls_exp0;
-			*slab1_ptr1 = entry1->slab[1] | mpls_exp1;
-			*slab1_ptr2 = entry2->slab[1] | mpls_exp2;
-			*slab1_ptr3 = entry3->slab[1] | mpls_exp3;
-
-			*slab2_ptr0 = entry0->slab[2];
-			*slab2_ptr1 = entry1->slab[2];
-			*slab2_ptr2 = entry2->slab[2];
-			*slab2_ptr3 = entry3->slab[2];
-		} else {
-			*slab0_ptr0 = entry0->slab[0];
-			*slab0_ptr1 = entry1->slab[0];
-			*slab0_ptr2 = entry2->slab[0];
-			*slab0_ptr3 = entry3->slab[0];
-
-			*slab1_ptr0 = entry0->slab[1];
-			*slab1_ptr1 = entry1->slab[1];
-			*slab1_ptr2 = entry2->slab[1];
-			*slab1_ptr3 = entry3->slab[1];
-
-			*slab2_ptr0 = entry0->slab[2];
-			*slab2_ptr1 = entry1->slab[2];
-			*slab2_ptr2 = entry2->slab[2];
-			*slab2_ptr3 = entry3->slab[2];
-		}
-
-		if (arp == 0) {
-			MACADDR_DST_WRITE(slab3_ptr0, entry0->slab[3]);
-			MACADDR_DST_WRITE(slab3_ptr1, entry1->slab[3]);
-			MACADDR_DST_WRITE(slab3_ptr2, entry2->slab[3]);
-			MACADDR_DST_WRITE(slab3_ptr3, entry3->slab[3]);
-		}
-	}
-
-	if (arp) {
-		arp_key0->port_id = port_id0;
-		arp_key1->port_id = port_id1;
-		arp_key2->port_id = port_id2;
-		arp_key3->port_id = port_id3;
-
-		arp_key0->ip = nh_ip0;
-		arp_key1->ip = nh_ip1;
-		arp_key2->ip = nh_ip2;
-		arp_key3->ip = nh_ip3;
-	}
-}
-
-#define PKT_WORK_ROUTING_ETHERNET(arp)				\
-static inline void						\
-pkt_work_routing_ether_arp##arp(				\
-	struct rte_mbuf *pkt,					\
-	struct rte_pipeline_table_entry *table_entry,		\
-	void *arg)						\
-{								\
-	pkt_work_routing(pkt, table_entry, arg, arp, 0, 0, 0, 0);\
-}
-
-#define PKT4_WORK_ROUTING_ETHERNET(arp)				\
-static inline void						\
-pkt4_work_routing_ether_arp##arp(				\
-	struct rte_mbuf **pkts,					\
-	struct rte_pipeline_table_entry **table_entries,	\
-	void *arg)						\
-{								\
-	pkt4_work_routing(pkts, table_entries, arg, arp, 0, 0, 0, 0);\
-}
-
-#define routing_table_ah_hit_ether(arp)				\
-PKT_WORK_ROUTING_ETHERNET(arp)					\
-PKT4_WORK_ROUTING_ETHERNET(arp)					\
-PIPELINE_TABLE_AH_HIT(routing_table_ah_hit_ether_arp##arp,	\
-	pkt_work_routing_ether_arp##arp,			\
-	pkt4_work_routing_ether_arp##arp)
-
-routing_table_ah_hit_ether(0)
-routing_table_ah_hit_ether(1)
-
-#define PKT_WORK_ROUTING_ETHERNET_QINQ(sched, arp)		\
-static inline void						\
-pkt_work_routing_ether_qinq_sched##sched##_arp##arp(		\
-	struct rte_mbuf *pkt,					\
-	struct rte_pipeline_table_entry *table_entry,		\
-	void *arg)						\
-{								\
-	pkt_work_routing(pkt, table_entry, arg, arp, 1, sched, 0, 0);\
-}
-
-#define PKT4_WORK_ROUTING_ETHERNET_QINQ(sched, arp)		\
-static inline void						\
-pkt4_work_routing_ether_qinq_sched##sched##_arp##arp(		\
-	struct rte_mbuf **pkts,					\
-	struct rte_pipeline_table_entry **table_entries,	\
-	void *arg)						\
-{								\
-	pkt4_work_routing(pkts, table_entries, arg, arp, 1, sched, 0, 0);\
-}
-
-#define routing_table_ah_hit_ether_qinq(sched, arp)		\
-PKT_WORK_ROUTING_ETHERNET_QINQ(sched, arp)			\
-PKT4_WORK_ROUTING_ETHERNET_QINQ(sched, arp)			\
-PIPELINE_TABLE_AH_HIT(routing_table_ah_hit_ether_qinq_sched##sched##_arp##arp,\
-	pkt_work_routing_ether_qinq_sched##sched##_arp##arp,	\
-	pkt4_work_routing_ether_qinq_sched##sched##_arp##arp)
-
-routing_table_ah_hit_ether_qinq(0, 0)
-routing_table_ah_hit_ether_qinq(1, 0)
-routing_table_ah_hit_ether_qinq(2, 0)
-routing_table_ah_hit_ether_qinq(0, 1)
-routing_table_ah_hit_ether_qinq(1, 1)
-routing_table_ah_hit_ether_qinq(2, 1)
-
-#define PKT_WORK_ROUTING_ETHERNET_MPLS(color, arp)		\
-static inline void						\
-pkt_work_routing_ether_mpls_color##color##_arp##arp(		\
-	struct rte_mbuf *pkt,					\
-	struct rte_pipeline_table_entry *table_entry,		\
-	void *arg)						\
-{								\
-	pkt_work_routing(pkt, table_entry, arg, arp, 0, 0, 1, color);\
-}
-
-#define PKT4_WORK_ROUTING_ETHERNET_MPLS(color, arp)		\
-static inline void						\
-pkt4_work_routing_ether_mpls_color##color##_arp##arp(		\
-	struct rte_mbuf **pkts,					\
-	struct rte_pipeline_table_entry **table_entries,	\
-	void *arg)						\
-{								\
-	pkt4_work_routing(pkts, table_entries, arg, arp, 0, 0, 1, color);\
-}
-
-#define routing_table_ah_hit_ether_mpls(color, arp)		\
-PKT_WORK_ROUTING_ETHERNET_MPLS(color, arp)			\
-PKT4_WORK_ROUTING_ETHERNET_MPLS(color, arp)			\
-PIPELINE_TABLE_AH_HIT(routing_table_ah_hit_ether_mpls_color##color##_arp##arp,\
-	pkt_work_routing_ether_mpls_color##color##_arp##arp,	\
-	pkt4_work_routing_ether_mpls_color##color##_arp##arp)
-
-routing_table_ah_hit_ether_mpls(0, 0)
-routing_table_ah_hit_ether_mpls(1, 0)
-routing_table_ah_hit_ether_mpls(0, 1)
-routing_table_ah_hit_ether_mpls(1, 1)
-
-static rte_pipeline_table_action_handler_hit
-get_routing_table_ah_hit(struct pipeline_routing *p)
-{
-	if (p->params.dbg_ah_disable)
-		return NULL;
-
-	switch (p->params.encap) {
-	case PIPELINE_ROUTING_ENCAP_ETHERNET:
-		return (p->params.n_arp_entries) ?
-			routing_table_ah_hit_ether_arp1 :
-			routing_table_ah_hit_ether_arp0;
-
-	case PIPELINE_ROUTING_ENCAP_ETHERNET_QINQ:
-		if (p->params.n_arp_entries)
-			switch (p->params.qinq_sched) {
-			case 0:
-				return routing_table_ah_hit_ether_qinq_sched0_arp1;
-			case 1:
-				return routing_table_ah_hit_ether_qinq_sched1_arp1;
-			case 2:
-				return routing_table_ah_hit_ether_qinq_sched2_arp1;
-			default:
-				return NULL;
-			}
-		 else
-			switch (p->params.qinq_sched) {
-			case 0:
-				return routing_table_ah_hit_ether_qinq_sched0_arp0;
-			case 1:
-				return routing_table_ah_hit_ether_qinq_sched1_arp0;
-			case 2:
-				return routing_table_ah_hit_ether_qinq_sched2_arp0;
-			default:
-				return NULL;
-			}
-
-	case PIPELINE_ROUTING_ENCAP_ETHERNET_MPLS:
-		if (p->params.n_arp_entries)
-			if (p->params.mpls_color_mark)
-				return routing_table_ah_hit_ether_mpls_color1_arp1;
-			else
-				return routing_table_ah_hit_ether_mpls_color0_arp1;
-		else
-			if (p->params.mpls_color_mark)
-				return routing_table_ah_hit_ether_mpls_color1_arp0;
-			else
-				return routing_table_ah_hit_ether_mpls_color0_arp0;
-
-	default:
-		return NULL;
-	}
-}
-
-/*
- * ARP table
- */
-struct arp_table_entry {
-	struct rte_pipeline_table_entry head;
-	uint64_t macaddr;
-};
-
-/**
- * ARP table AH
- */
-static inline void
-pkt_work_arp(
-	struct rte_mbuf *pkt,
-	struct rte_pipeline_table_entry *table_entry,
-	__rte_unused void *arg)
-{
-	struct arp_table_entry *entry = (struct arp_table_entry *) table_entry;
-
-	/* Read */
-	uint64_t macaddr_dst = entry->macaddr;
-	uint64_t *slab_ptr = (uint64_t *) ((char *) pkt->buf_addr +
-		(pkt->data_off - 2));
-
-	/* Compute */
-
-	/* Write */
-	MACADDR_DST_WRITE(slab_ptr, macaddr_dst);
-}
-
-static inline void
-pkt4_work_arp(
-	struct rte_mbuf **pkts,
-	struct rte_pipeline_table_entry **table_entries,
-	__rte_unused void *arg)
-{
-	struct arp_table_entry *entry0 =
-		(struct arp_table_entry *) table_entries[0];
-	struct arp_table_entry *entry1 =
-		(struct arp_table_entry *) table_entries[1];
-	struct arp_table_entry *entry2 =
-		(struct arp_table_entry *) table_entries[2];
-	struct arp_table_entry *entry3 =
-		(struct arp_table_entry *) table_entries[3];
-
-	/* Read */
-	uint64_t macaddr_dst0 = entry0->macaddr;
-	uint64_t macaddr_dst1 = entry1->macaddr;
-	uint64_t macaddr_dst2 = entry2->macaddr;
-	uint64_t macaddr_dst3 = entry3->macaddr;
-
-	uint64_t *slab_ptr0 = (uint64_t *) ((char *) pkts[0]->buf_addr +
-		(pkts[0]->data_off - 2));
-	uint64_t *slab_ptr1 = (uint64_t *) ((char *) pkts[1]->buf_addr +
-		(pkts[1]->data_off - 2));
-	uint64_t *slab_ptr2 = (uint64_t *) ((char *) pkts[2]->buf_addr +
-		(pkts[2]->data_off - 2));
-	uint64_t *slab_ptr3 = (uint64_t *) ((char *) pkts[3]->buf_addr +
-		(pkts[3]->data_off - 2));
-
-	/* Compute */
-
-	/* Write */
-	MACADDR_DST_WRITE(slab_ptr0, macaddr_dst0);
-	MACADDR_DST_WRITE(slab_ptr1, macaddr_dst1);
-	MACADDR_DST_WRITE(slab_ptr2, macaddr_dst2);
-	MACADDR_DST_WRITE(slab_ptr3, macaddr_dst3);
-}
-
-PIPELINE_TABLE_AH_HIT(arp_table_ah_hit,
-	pkt_work_arp,
-	pkt4_work_arp);
-
-static rte_pipeline_table_action_handler_hit
-get_arp_table_ah_hit(struct pipeline_routing *p)
-{
-	if (p->params.dbg_ah_disable)
-		return NULL;
-
-	return arp_table_ah_hit;
-}
-
-/*
- * Argument parsing
- */
-int
-pipeline_routing_parse_args(struct pipeline_routing_params *p,
-	struct pipeline_params *params)
-{
-	uint32_t n_routes_present = 0;
-	uint32_t port_local_dest_present = 0;
-	uint32_t encap_present = 0;
-	uint32_t qinq_sched_present = 0;
-	uint32_t mpls_color_mark_present = 0;
-	uint32_t n_arp_entries_present = 0;
-	uint32_t ip_hdr_offset_present = 0;
-	uint32_t arp_key_offset_present = 0;
-	uint32_t color_offset_present = 0;
-	uint32_t dbg_ah_disable_present = 0;
-	uint32_t i;
-
-	/* default values */
-	p->n_routes = PIPELINE_ROUTING_N_ROUTES_DEFAULT;
-	p->port_local_dest = params->n_ports_out - 1;
-	p->encap = PIPELINE_ROUTING_ENCAP_ETHERNET;
-	p->qinq_sched = 0;
-	p->mpls_color_mark = 0;
-	p->n_arp_entries = 0;
-	p->dbg_ah_disable = 0;
-
-	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) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				n_routes_present == 0, params->name,
-				arg_name);
-			n_routes_present = 1;
-
-			status = parser_read_uint32(&p->n_routes,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL(((status != -EINVAL) &&
-				(p->n_routes != 0)), params->name,
-				arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			continue;
-		}
-		/* port_local_dest */
-		if (strcmp(arg_name, "port_local_dest") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				port_local_dest_present == 0, params->name,
-				arg_name);
-			port_local_dest_present = 1;
-
-			status = parser_read_uint32(&p->port_local_dest,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL(((status == 0) &&
-				(p->port_local_dest < params->n_ports_out)),
-				params->name, arg_name, arg_value);
-
-			continue;
-		}
-
-		/* encap */
-		if (strcmp(arg_name, "encap") == 0) {
-			PIPELINE_PARSE_ERR_DUPLICATE(encap_present == 0,
-				params->name, arg_name);
-			encap_present = 1;
-
-			/* ethernet */
-			if (strcmp(arg_value, "ethernet") == 0) {
-				p->encap = PIPELINE_ROUTING_ENCAP_ETHERNET;
-				continue;
-			}
-
-			/* ethernet_qinq */
-			if (strcmp(arg_value, "ethernet_qinq") == 0) {
-				p->encap = PIPELINE_ROUTING_ENCAP_ETHERNET_QINQ;
-				continue;
-			}
-
-			/* ethernet_mpls */
-			if (strcmp(arg_value, "ethernet_mpls") == 0) {
-				p->encap = PIPELINE_ROUTING_ENCAP_ETHERNET_MPLS;
-				continue;
-			}
-
-			/* any other */
-			PIPELINE_PARSE_ERR_INV_VAL(0, params->name,
-				arg_name, arg_value);
-		}
-
-		/* qinq_sched */
-		if (strcmp(arg_name, "qinq_sched") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				qinq_sched_present == 0, params->name,
-				arg_name);
-			qinq_sched_present = 1;
-
-			status = parser_read_arg_bool(arg_value);
-			if (status == -EINVAL) {
-				if (strcmp(arg_value, "test") == 0) {
-					p->qinq_sched = 2;
-					continue;
-				}
-			} else {
-				p->qinq_sched = status;
-				continue;
-			}
-
-			PIPELINE_PARSE_ERR_INV_VAL(0, params->name,
-				arg_name, arg_value);
-		}
-
-		/* mpls_color_mark */
-		if (strcmp(arg_name, "mpls_color_mark") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				mpls_color_mark_present == 0,
-				params->name, arg_name);
-			mpls_color_mark_present = 1;
-
-
-			status = parser_read_arg_bool(arg_value);
-			if (status >= 0) {
-				p->mpls_color_mark = status;
-				continue;
-			}
-
-			PIPELINE_PARSE_ERR_INV_VAL(0, params->name,
-				arg_name, arg_value);
-		}
-
-		/* n_arp_entries */
-		if (strcmp(arg_name, "n_arp_entries") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				n_arp_entries_present == 0, params->name,
-				arg_name);
-			n_arp_entries_present = 1;
-
-			status = parser_read_uint32(&p->n_arp_entries,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			continue;
-		}
-
-		/* ip_hdr_offset */
-		if (strcmp(arg_name, "ip_hdr_offset") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				ip_hdr_offset_present == 0, params->name,
-				arg_name);
-			ip_hdr_offset_present = 1;
-
-			status = parser_read_uint32(&p->ip_hdr_offset,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			continue;
-		}
-
-		/* arp_key_offset */
-		if (strcmp(arg_name, "arp_key_offset") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				arp_key_offset_present == 0, params->name,
-				arg_name);
-			arp_key_offset_present = 1;
-
-			status = parser_read_uint32(&p->arp_key_offset,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			continue;
-		}
-
-		/* color_offset */
-		if (strcmp(arg_name, "color_offset") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				color_offset_present == 0, params->name,
-				arg_name);
-			color_offset_present = 1;
-
-			status = parser_read_uint32(&p->color_offset,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			continue;
-		}
-
-		/* debug */
-		if (strcmp(arg_name, "dbg_ah_disable") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				dbg_ah_disable_present == 0, params->name,
-				arg_name);
-			dbg_ah_disable_present = 1;
-
-			status = parser_read_arg_bool(arg_value);
-			if (status >= 0) {
-				p->dbg_ah_disable = status;
-				continue;
-			}
-
-			PIPELINE_PARSE_ERR_INV_VAL(0, params->name,
-				arg_name, arg_value);
-
-			continue;
-		}
-
-		/* any other */
-		PIPELINE_PARSE_ERR_INV_ENT(0, params->name, arg_name);
-	}
-
-	/* Check that mandatory arguments are present */
-	PIPELINE_PARSE_ERR_MANDATORY(ip_hdr_offset_present, params->name,
-		"ip_hdr_offset");
-
-	/* Check relations between arguments */
-	switch (p->encap) {
-	case PIPELINE_ROUTING_ENCAP_ETHERNET:
-		PIPELINE_ARG_CHECK((!p->qinq_sched), "Parse error in "
-			"section \"%s\": encap = ethernet, therefore "
-			"qinq_sched = yes/test is not allowed",
-			params->name);
-		PIPELINE_ARG_CHECK((!p->mpls_color_mark), "Parse error "
-			"in section \"%s\": encap = ethernet, therefore "
-			"mpls_color_mark = yes is not allowed",
-			params->name);
-		PIPELINE_ARG_CHECK((!color_offset_present), "Parse error "
-			"in section \"%s\": encap = ethernet, therefore "
-			"color_offset is not allowed",
-			params->name);
-		break;
-
-	case PIPELINE_ROUTING_ENCAP_ETHERNET_QINQ:
-		PIPELINE_ARG_CHECK((!p->mpls_color_mark), "Parse error "
-			"in section \"%s\": encap = ethernet_qinq, "
-			"therefore mpls_color_mark = yes is not allowed",
-			params->name);
-		PIPELINE_ARG_CHECK((!color_offset_present), "Parse error "
-			"in section \"%s\": encap = ethernet_qinq, "
-			"therefore color_offset is not allowed",
-			params->name);
-		break;
-
-	case PIPELINE_ROUTING_ENCAP_ETHERNET_MPLS:
-		PIPELINE_ARG_CHECK((!p->qinq_sched), "Parse error in "
-			"section \"%s\": encap = ethernet_mpls, therefore "
-			"qinq_sched  = yes/test is not allowed",
-			params->name);
-		break;
-	}
-
-	PIPELINE_ARG_CHECK((!(p->n_arp_entries &&
-		(!arp_key_offset_present))), "Parse error in section "
-			"\"%s\": n_arp_entries is set while "
-			"arp_key_offset is not set", params->name);
-
-	PIPELINE_ARG_CHECK((!((p->n_arp_entries == 0) &&
-		arp_key_offset_present)), "Parse error in section "
-			"\"%s\": arp_key_offset present while "
-			"n_arp_entries is not set", params->name);
-
-	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);
-	p->log_level = params->log_level;
-
-	PLOG(p, HIGH, "Routing");
-
-	/* Parse arguments */
-	if (pipeline_routing_parse_args(&p_rt->params, 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,
-			.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 = {
-			.name = p->name,
-			.n_rules = p_rt->params.n_routes,
-			.number_tbl8s = PIPELINE_ROUTING_LPM_TABLE_NUMBER_TABLE8s,
-			.flags = 0,
-			.entry_unique_size = sizeof(struct routing_table_entry),
-			.offset = p_rt->params.ip_hdr_offset +
-				__builtin_offsetof(struct ipv4_hdr, dst_addr),
-		};
-
-		struct rte_pipeline_table_params table_params = {
-				.ops = &rte_table_lpm_ops,
-				.arg_create = &table_lpm_params,
-				.f_action_hit = get_routing_table_ah_hit(p_rt),
-				.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->params.n_arp_entries) {
-		struct rte_table_hash_params table_arp_params = {
-			.name = p->name,
-			.key_size = 8,
-			.key_offset = p_rt->params.arp_key_offset,
-			.key_mask = NULL,
-			.n_keys = p_rt->params.n_arp_entries,
-			.n_buckets =
-				rte_align32pow2(p_rt->params.n_arp_entries / 4),
-			.f_hash = hash_default_key8,
-			.seed = 0,
-		};
-
-		struct rte_pipeline_table_params table_params = {
-			.ops = &rte_table_hash_key8_ext_ops,
-			.arg_create = &table_arp_params,
-			.f_action_hit = get_arp_table_ah_hit(p_rt),
-			.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_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 *p_rt = (struct pipeline_routing *) p;
-	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_arp0 = {
-		.head = {
-			.action = RTE_PIPELINE_ACTION_PORT,
-			{.port_id = p->port_out_id[req->data.port_id]},
-		},
-
-		.flags = req->data.flags,
-		.port_id = req->data.port_id,
-		.ip = 0,
-		.data_offset = 0,
-		.ether_l2_length = 0,
-		.slab = {0},
-		.slab_offset = {0},
-	};
-
-	struct routing_table_entry entry_arp1 = {
-		.head = {
-			.action = RTE_PIPELINE_ACTION_TABLE,
-			{.table_id = p->table_id[1]},
-		},
-
-		.flags = req->data.flags,
-		.port_id = req->data.port_id,
-		.ip = rte_bswap32(req->data.ethernet.ip),
-		.data_offset = 0,
-		.ether_l2_length = 0,
-		.slab = {0},
-		.slab_offset = {0},
-	};
-
-	struct rte_pipeline_table_entry *entry = (p_rt->params.n_arp_entries) ?
-		(struct rte_pipeline_table_entry *) &entry_arp1 :
-		(struct rte_pipeline_table_entry *) &entry_arp0;
-
-	if ((req->key.type != PIPELINE_ROUTING_ROUTE_IPV4) ||
-		((p_rt->params.n_arp_entries == 0) &&
-			(req->data.flags & PIPELINE_ROUTING_ROUTE_ARP)) ||
-		(p_rt->params.n_arp_entries &&
-			((req->data.flags & PIPELINE_ROUTING_ROUTE_ARP) == 0)) ||
-		((p_rt->params.encap != PIPELINE_ROUTING_ENCAP_ETHERNET_QINQ) &&
-			(req->data.flags & PIPELINE_ROUTING_ROUTE_QINQ)) ||
-		((p_rt->params.encap == PIPELINE_ROUTING_ENCAP_ETHERNET_QINQ) &&
-			((req->data.flags & PIPELINE_ROUTING_ROUTE_QINQ) == 0)) ||
-		((p_rt->params.encap != PIPELINE_ROUTING_ENCAP_ETHERNET_MPLS) &&
-			(req->data.flags & PIPELINE_ROUTING_ROUTE_MPLS)) ||
-		((p_rt->params.encap == PIPELINE_ROUTING_ENCAP_ETHERNET_MPLS) &&
-			((req->data.flags & PIPELINE_ROUTING_ROUTE_MPLS) == 0))) {
-		rsp->status = -1;
-		return rsp;
-	}
-
-	/* Ether - ARP off */
-	if ((p_rt->params.encap == PIPELINE_ROUTING_ENCAP_ETHERNET) &&
-		(p_rt->params.n_arp_entries == 0)) {
-		uint64_t macaddr_src = p_rt->macaddr[req->data.port_id];
-		uint64_t macaddr_dst;
-		uint64_t ethertype = ETHER_TYPE_IPv4;
-
-		macaddr_dst = *((uint64_t *)&(req->data.ethernet.macaddr));
-		macaddr_dst = rte_bswap64(macaddr_dst << 16);
-
-		entry_arp0.slab[0] =
-			SLAB_NBO_MACADDRSRC_ETHERTYPE(macaddr_src, ethertype);
-		entry_arp0.slab_offset[0] = p_rt->params.ip_hdr_offset - 8;
-
-		entry_arp0.slab[1] = rte_bswap64(macaddr_dst);
-		entry_arp0.slab_offset[1] = p_rt->params.ip_hdr_offset - 2 * 8;
-
-		entry_arp0.data_offset = entry_arp0.slab_offset[1] + 2
-			- sizeof(struct rte_mbuf);
-		entry_arp0.ether_l2_length = 14;
-	}
-
-	/* Ether - ARP on */
-	if ((p_rt->params.encap == PIPELINE_ROUTING_ENCAP_ETHERNET) &&
-		p_rt->params.n_arp_entries) {
-		uint64_t macaddr_src = p_rt->macaddr[req->data.port_id];
-		uint64_t ethertype = ETHER_TYPE_IPv4;
-
-		entry_arp1.slab[0] =
-			SLAB_NBO_MACADDRSRC_ETHERTYPE(macaddr_src, ethertype);
-		entry_arp1.slab_offset[0] = p_rt->params.ip_hdr_offset - 8;
-
-		entry_arp1.data_offset = entry_arp1.slab_offset[0] - 6
-			- sizeof(struct rte_mbuf);
-		entry_arp1.ether_l2_length = 14;
-	}
-
-	/* Ether QinQ - ARP off */
-	if ((p_rt->params.encap == PIPELINE_ROUTING_ENCAP_ETHERNET_QINQ) &&
-		(p_rt->params.n_arp_entries == 0)) {
-		uint64_t macaddr_src = p_rt->macaddr[req->data.port_id];
-		uint64_t macaddr_dst;
-		uint64_t ethertype_ipv4 = ETHER_TYPE_IPv4;
-		uint64_t ethertype_vlan = 0x8100;
-		uint64_t ethertype_qinq = 0x9100;
-		uint64_t svlan = req->data.l2.qinq.svlan;
-		uint64_t cvlan = req->data.l2.qinq.cvlan;
-
-		macaddr_dst = *((uint64_t *)&(req->data.ethernet.macaddr));
-		macaddr_dst = rte_bswap64(macaddr_dst << 16);
-
-		entry_arp0.slab[0] = rte_bswap64((svlan << 48) |
-			(ethertype_vlan << 32) |
-			(cvlan << 16) |
-			ethertype_ipv4);
-		entry_arp0.slab_offset[0] = p_rt->params.ip_hdr_offset - 8;
-
-		entry_arp0.slab[1] =
-			SLAB_NBO_MACADDRSRC_ETHERTYPE(macaddr_src, ethertype_qinq);
-		entry_arp0.slab_offset[1] = p_rt->params.ip_hdr_offset - 2 * 8;
-
-		entry_arp0.slab[2] = rte_bswap64(macaddr_dst);
-		entry_arp0.slab_offset[2] = p_rt->params.ip_hdr_offset - 3 * 8;
-
-		entry_arp0.data_offset = entry_arp0.slab_offset[2] + 2
-			- sizeof(struct rte_mbuf);
-		entry_arp0.ether_l2_length = 22;
-	}
-
-	/* Ether QinQ - ARP on */
-	if ((p_rt->params.encap == PIPELINE_ROUTING_ENCAP_ETHERNET_QINQ) &&
-		p_rt->params.n_arp_entries) {
-		uint64_t macaddr_src = p_rt->macaddr[req->data.port_id];
-		uint64_t ethertype_ipv4 = ETHER_TYPE_IPv4;
-		uint64_t ethertype_vlan = 0x8100;
-		uint64_t ethertype_qinq = 0x9100;
-		uint64_t svlan = req->data.l2.qinq.svlan;
-		uint64_t cvlan = req->data.l2.qinq.cvlan;
-
-		entry_arp1.slab[0] = rte_bswap64((svlan << 48) |
-			(ethertype_vlan << 32) |
-			(cvlan << 16) |
-			ethertype_ipv4);
-		entry_arp1.slab_offset[0] = p_rt->params.ip_hdr_offset - 8;
-
-		entry_arp1.slab[1] =
-			SLAB_NBO_MACADDRSRC_ETHERTYPE(macaddr_src, ethertype_qinq);
-		entry_arp1.slab_offset[1] = p_rt->params.ip_hdr_offset - 2 * 8;
-
-		entry_arp1.data_offset = entry_arp1.slab_offset[1] - 6
-			- sizeof(struct rte_mbuf);
-		entry_arp1.ether_l2_length = 22;
-	}
-
-	/* Ether MPLS - ARP off */
-	if ((p_rt->params.encap == PIPELINE_ROUTING_ENCAP_ETHERNET_MPLS) &&
-		(p_rt->params.n_arp_entries == 0)) {
-		uint64_t macaddr_src = p_rt->macaddr[req->data.port_id];
-		uint64_t macaddr_dst;
-		uint64_t ethertype_mpls = 0x8847;
-
-		uint64_t label0 = req->data.l2.mpls.labels[0];
-		uint64_t label1 = req->data.l2.mpls.labels[1];
-		uint64_t label2 = req->data.l2.mpls.labels[2];
-		uint64_t label3 = req->data.l2.mpls.labels[3];
-		uint32_t n_labels = req->data.l2.mpls.n_labels;
-
-		macaddr_dst = *((uint64_t *)&(req->data.ethernet.macaddr));
-		macaddr_dst = rte_bswap64(macaddr_dst << 16);
-
-		switch (n_labels) {
-		case 1:
-			entry_arp0.slab[0] = 0;
-			entry_arp0.slab_offset[0] =
-				p_rt->params.ip_hdr_offset - 8;
-
-			entry_arp0.slab[1] = rte_bswap64(
-				MPLS_LABEL(label0, 0, 1, 0));
-			entry_arp0.slab_offset[1] =
-				p_rt->params.ip_hdr_offset - 8;
-			break;
-
-		case 2:
-			entry_arp0.slab[0] = 0;
-			entry_arp0.slab_offset[0] =
-				p_rt->params.ip_hdr_offset - 8;
-
-			entry_arp0.slab[1] = rte_bswap64(
-				(MPLS_LABEL(label0, 0, 0, 0) << 32) |
-				MPLS_LABEL(label1, 0, 1, 0));
-			entry_arp0.slab_offset[1] =
-				p_rt->params.ip_hdr_offset - 8;
-			break;
-
-		case 3:
-			entry_arp0.slab[0] = rte_bswap64(
-				(MPLS_LABEL(label1, 0, 0, 0) << 32) |
-				MPLS_LABEL(label2, 0, 1, 0));
-			entry_arp0.slab_offset[0] =
-				p_rt->params.ip_hdr_offset - 8;
-
-			entry_arp0.slab[1] = rte_bswap64(
-				MPLS_LABEL(label0, 0, 0, 0));
-			entry_arp0.slab_offset[1] =
-				p_rt->params.ip_hdr_offset - 2 * 8;
-			break;
-
-		case 4:
-			entry_arp0.slab[0] = rte_bswap64(
-				(MPLS_LABEL(label2, 0, 0, 0) << 32) |
-				MPLS_LABEL(label3, 0, 1, 0));
-			entry_arp0.slab_offset[0] =
-				p_rt->params.ip_hdr_offset - 8;
-
-			entry_arp0.slab[1] = rte_bswap64(
-				(MPLS_LABEL(label0, 0, 0, 0) << 32) |
-				MPLS_LABEL(label1, 0, 0, 0));
-			entry_arp0.slab_offset[1] =
-				p_rt->params.ip_hdr_offset - 2 * 8;
-			break;
-
-		default:
-			rsp->status = -1;
-			return rsp;
-		}
-
-		entry_arp0.slab[2] =
-			SLAB_NBO_MACADDRSRC_ETHERTYPE(macaddr_src, ethertype_mpls);
-		entry_arp0.slab_offset[2] = p_rt->params.ip_hdr_offset -
-			(n_labels * 4 + 8);
-
-		entry_arp0.slab[3] = rte_bswap64(macaddr_dst);
-		entry_arp0.slab_offset[3] = p_rt->params.ip_hdr_offset -
-			(n_labels * 4 + 2 * 8);
-
-		entry_arp0.data_offset = entry_arp0.slab_offset[3] + 2
-			- sizeof(struct rte_mbuf);
-		entry_arp0.ether_l2_length = n_labels * 4 + 14;
-	}
-
-	/* Ether MPLS - ARP on */
-	if ((p_rt->params.encap == PIPELINE_ROUTING_ENCAP_ETHERNET_MPLS) &&
-		p_rt->params.n_arp_entries) {
-		uint64_t macaddr_src = p_rt->macaddr[req->data.port_id];
-		uint64_t ethertype_mpls = 0x8847;
-
-		uint64_t label0 = req->data.l2.mpls.labels[0];
-		uint64_t label1 = req->data.l2.mpls.labels[1];
-		uint64_t label2 = req->data.l2.mpls.labels[2];
-		uint64_t label3 = req->data.l2.mpls.labels[3];
-		uint32_t n_labels = req->data.l2.mpls.n_labels;
-
-		switch (n_labels) {
-		case 1:
-			entry_arp1.slab[0] = 0;
-			entry_arp1.slab_offset[0] =
-				p_rt->params.ip_hdr_offset - 8;
-
-			entry_arp1.slab[1] = rte_bswap64(
-				MPLS_LABEL(label0, 0, 1, 0));
-			entry_arp1.slab_offset[1] =
-				p_rt->params.ip_hdr_offset - 8;
-			break;
-
-		case 2:
-			entry_arp1.slab[0] = 0;
-			entry_arp1.slab_offset[0] =
-				p_rt->params.ip_hdr_offset - 8;
-
-			entry_arp1.slab[1] = rte_bswap64(
-				(MPLS_LABEL(label0, 0, 0, 0) << 32) |
-				MPLS_LABEL(label1, 0, 1, 0));
-			entry_arp1.slab_offset[1] =
-				p_rt->params.ip_hdr_offset - 8;
-			break;
-
-		case 3:
-			entry_arp1.slab[0] = rte_bswap64(
-				(MPLS_LABEL(label1, 0, 0, 0) << 32) |
-				MPLS_LABEL(label2, 0, 1, 0));
-			entry_arp1.slab_offset[0] =
-				p_rt->params.ip_hdr_offset - 8;
-
-			entry_arp1.slab[1] = rte_bswap64(
-				MPLS_LABEL(label0, 0, 0, 0));
-			entry_arp1.slab_offset[1] =
-				p_rt->params.ip_hdr_offset - 2 * 8;
-			break;
-
-		case 4:
-			entry_arp1.slab[0] = rte_bswap64(
-				(MPLS_LABEL(label2, 0, 0, 0) << 32) |
-				MPLS_LABEL(label3, 0, 1, 0));
-			entry_arp1.slab_offset[0] =
-				p_rt->params.ip_hdr_offset - 8;
-
-			entry_arp1.slab[1] = rte_bswap64(
-				(MPLS_LABEL(label0, 0, 0, 0) << 32) |
-				MPLS_LABEL(label1, 0, 0, 0));
-			entry_arp1.slab_offset[1] =
-				p_rt->params.ip_hdr_offset - 2 * 8;
-			break;
-
-		default:
-			rsp->status = -1;
-			return rsp;
-		}
-
-		entry_arp1.slab[2] =
-			SLAB_NBO_MACADDRSRC_ETHERTYPE(macaddr_src, ethertype_mpls);
-		entry_arp1.slab_offset[2] = p_rt->params.ip_hdr_offset -
-			(n_labels * 4 + 8);
-
-		entry_arp1.data_offset = entry_arp1.slab_offset[2] - 6
-			- sizeof(struct rte_mbuf);
-		entry_arp1.ether_l2_length = n_labels * 4 + 14;
-	}
-
-	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);
-
-	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);
-
-	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_ipv4 key = {
-		.port_id = req->key.key.ipv4.port_id,
-		.ip = rte_bswap32(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, /* set below */
-	};
-
-	if (req->key.type != PIPELINE_ROUTING_ARP_IPV4) {
-		rsp->status = -1;
-		return rsp;
-	}
-
-	entry.macaddr = *((uint64_t *)&(req->macaddr));
-	entry.macaddr = entry.macaddr << 16;
-
-	rsp->status = rte_pipeline_table_entry_add(p->p,
-		p->table_id[1],
-		&key,
-		(struct rte_pipeline_table_entry *) &entry,
-		&rsp->key_found,
-		(struct rte_pipeline_table_entry **) &rsp->entry_ptr);
-
-	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_ipv4 key = {
-		.port_id = req->key.key.ipv4.port_id,
-		.ip = rte_bswap32(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);
-
-	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;
-}
-
-void *
-pipeline_routing_msg_req_set_macaddr_handler(struct pipeline *p, void *msg)
-{
-	struct pipeline_routing *p_rt = (struct pipeline_routing *) p;
-	struct pipeline_routing_set_macaddr_msg_req *req = msg;
-	struct pipeline_routing_set_macaddr_msg_rsp *rsp = msg;
-	uint32_t port_id;
-
-	for (port_id = 0; port_id < p->n_ports_out; port_id++)
-		p_rt->macaddr[port_id] = req->macaddr[port_id];
-
-	rsp->status = 0;
-
-	return rsp;
-}
-
-struct pipeline_be_ops pipeline_routing_be_ops = {
-	.f_init = pipeline_routing_init,
-	.f_free = pipeline_routing_free,
-	.f_run = NULL,
-	.f_timer = pipeline_routing_timer,
-};
diff --git a/examples/ip_pipeline/pipeline/pipeline_routing_be.h b/examples/ip_pipeline/pipeline/pipeline_routing_be.h
deleted file mode 100644
index 7140ee4..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_routing_be.h
+++ /dev/null
@@ -1,283 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#ifndef __INCLUDE_PIPELINE_ROUTING_BE_H__
-#define __INCLUDE_PIPELINE_ROUTING_BE_H__
-
-#include <rte_ether.h>
-
-#include "pipeline_common_be.h"
-
-/*
- * Pipeline argument parsing
- */
-#ifndef PIPELINE_ROUTING_N_ROUTES_DEFAULT
-#define PIPELINE_ROUTING_N_ROUTES_DEFAULT                  4096
-#endif
-
-enum pipeline_routing_encap {
-	PIPELINE_ROUTING_ENCAP_ETHERNET = 0,
-	PIPELINE_ROUTING_ENCAP_ETHERNET_QINQ,
-	PIPELINE_ROUTING_ENCAP_ETHERNET_MPLS,
-};
-
-struct pipeline_routing_params {
-	/* routing */
-	uint32_t n_routes;
-	uint32_t port_local_dest;
-
-	/* routing packet encapsulation */
-	enum pipeline_routing_encap encap;
-	uint32_t qinq_sched;
-	uint32_t mpls_color_mark;
-
-	/* arp */
-	uint32_t n_arp_entries;
-
-	/* packet buffer offsets */
-	uint32_t ip_hdr_offset;
-	uint32_t arp_key_offset;
-	uint32_t color_offset;
-
-	/* debug */
-	uint32_t dbg_ah_disable;
-};
-
-int
-pipeline_routing_parse_args(struct pipeline_routing_params *p,
-	struct pipeline_params *params);
-
-/*
- * Route
- */
-enum pipeline_routing_route_key_type {
-	PIPELINE_ROUTING_ROUTE_IPV4,
-};
-
-struct pipeline_routing_route_key_ipv4 {
-	uint32_t ip;
-	uint32_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 */
-	PIPELINE_ROUTING_ROUTE_ARP = 1 << 1, /* 0 = ARP OFF; 1 = ARP ON */
-	PIPELINE_ROUTING_ROUTE_QINQ = 1 << 2, /* 0 = QINQ OFF; 1 = QINQ ON */
-	PIPELINE_ROUTING_ROUTE_MPLS = 1 << 3, /* 0 = MPLS OFF; 1 = MPLS ON */
-};
-
-#define PIPELINE_ROUTING_MPLS_LABELS_MAX         4
-
-struct pipeline_routing_route_data {
-	uint32_t flags;
-	uint32_t port_id; /* Output port ID */
-
-	union {
-		/* Next hop IP (valid only when ARP is enabled) */
-		uint32_t ip;
-
-		/* Next hop MAC address (valid only when ARP disabled */
-		struct ether_addr macaddr;
-	} ethernet;
-
-	union {
-		struct {
-			uint16_t svlan;
-			uint16_t cvlan;
-		} qinq;
-
-		struct {
-			uint32_t labels[PIPELINE_ROUTING_MPLS_LABELS_MAX];
-			uint32_t n_labels;
-		} mpls;
-	} l2;
-};
-
-/*
- * 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_REQ_SET_MACADDR,
-	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 */
-	struct pipeline_routing_route_data data;
-};
-
-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;
-};
-
-/*
- * MSG SET MACADDR
- */
-struct pipeline_routing_set_macaddr_msg_req {
-	enum pipeline_msg_req_type type;
-	enum pipeline_routing_msg_req_type subtype;
-
-	uint64_t macaddr[PIPELINE_MAX_PORT_OUT];
-};
-
-struct pipeline_routing_set_macaddr_msg_rsp {
-	int status;
-};
-
-extern struct pipeline_be_ops pipeline_routing_be_ops;
-
-#endif
-- 
2.9.3

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

* [dpdk-dev] [PATCH v4 15/49] ip_pipeline: remove flow classification pipeline
  2018-03-29 18:31           ` [dpdk-dev] [PATCH v4 00/49] ip_pipeline: refactoring Jasvinder Singh
                               ` (13 preceding siblings ...)
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 14/49] ip_pipeline: remove routing pipeline Jasvinder Singh
@ 2018-03-29 18:31             ` Jasvinder Singh
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 16/49] ip_pipeline: remove flow actions pipeline Jasvinder Singh
                               ` (34 subsequent siblings)
  49 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-29 18:31 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Remove flow classification pipeline.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/Makefile                      |    2 -
 examples/ip_pipeline/init.c                        |    2 -
 examples/ip_pipeline/meson.build                   |    2 -
 .../pipeline/pipeline_flow_classification.c        | 1878 --------------------
 .../pipeline/pipeline_flow_classification.h        |  106 --
 .../pipeline/pipeline_flow_classification_be.c     |  723 --------
 .../pipeline/pipeline_flow_classification_be.h     |  113 --
 7 files changed, 2826 deletions(-)
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_classification.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_classification.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_classification_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_classification_be.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index f67cfe6..e43001f 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -21,8 +21,6 @@ SRCS-y += pipeline_master_be.c
 SRCS-y += pipeline_master.c
 SRCS-y += pipeline_firewall_be.c
 SRCS-y += pipeline_firewall.c
-SRCS-y += pipeline_flow_classification_be.c
-SRCS-y += pipeline_flow_classification.c
 SRCS-y += pipeline_flow_actions_be.c
 SRCS-y += pipeline_flow_actions.c
 
diff --git a/examples/ip_pipeline/init.c b/examples/ip_pipeline/init.c
index 241d80a..4780bb1 100644
--- a/examples/ip_pipeline/init.c
+++ b/examples/ip_pipeline/init.c
@@ -27,7 +27,6 @@
 #include "pipeline_common_fe.h"
 #include "pipeline_master.h"
 #include "pipeline_firewall.h"
-#include "pipeline_flow_classification.h"
 #include "pipeline_flow_actions.h"
 #include "thread_fe.h"
 
@@ -1820,7 +1819,6 @@ int app_init(struct app_params *app)
 	app_pipeline_common_cmd_push(app);
 	app_pipeline_thread_cmd_push(app);
 	app_pipeline_type_register(app, &pipeline_master);
-	app_pipeline_type_register(app, &pipeline_flow_classification);
 	app_pipeline_type_register(app, &pipeline_flow_actions);
 	app_pipeline_type_register(app, &pipeline_firewall);
 
diff --git a/examples/ip_pipeline/meson.build b/examples/ip_pipeline/meson.build
index f9eab1b..dd12870 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -25,8 +25,6 @@ sources = files(
 	'pipeline/pipeline_firewall.c',
 	'pipeline/pipeline_flow_actions_be.c',
 	'pipeline/pipeline_flow_actions.c',
-	'pipeline/pipeline_flow_classification_be.c',
-	'pipeline/pipeline_flow_classification.c',
 	'pipeline/pipeline_master_be.c',
 	'pipeline/pipeline_master.c',
 )
diff --git a/examples/ip_pipeline/pipeline/pipeline_flow_classification.c b/examples/ip_pipeline/pipeline/pipeline_flow_classification.c
deleted file mode 100644
index d39e0fb..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_flow_classification.c
+++ /dev/null
@@ -1,1878 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2016 Intel Corporation
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <sys/queue.h>
-#include <netinet/in.h>
-#include <unistd.h>
-
-#include <rte_common.h>
-#include <rte_hexdump.h>
-#include <rte_malloc.h>
-#include <cmdline_rdline.h>
-#include <cmdline_parse.h>
-#include <cmdline_parse_num.h>
-#include <cmdline_parse_string.h>
-
-#include "app.h"
-#include "pipeline_common_fe.h"
-#include "pipeline_flow_classification.h"
-#include "hash_func.h"
-#include "parser.h"
-
-/*
- * Key conversion
- */
-
-struct pkt_key_qinq {
-	uint16_t ethertype_svlan;
-	uint16_t svlan;
-	uint16_t ethertype_cvlan;
-	uint16_t cvlan;
-} __attribute__((__packed__));
-
-struct pkt_key_ipv4_5tuple {
-	uint8_t ttl;
-	uint8_t proto;
-	uint16_t checksum;
-	uint32_t ip_src;
-	uint32_t ip_dst;
-	uint16_t port_src;
-	uint16_t port_dst;
-} __attribute__((__packed__));
-
-struct pkt_key_ipv6_5tuple {
-	uint16_t payload_length;
-	uint8_t proto;
-	uint8_t hop_limit;
-	uint8_t ip_src[16];
-	uint8_t ip_dst[16];
-	uint16_t port_src;
-	uint16_t port_dst;
-} __attribute__((__packed__));
-
-static int
-app_pipeline_fc_key_convert(struct pipeline_fc_key *key_in,
-	uint8_t *key_out,
-	uint32_t *signature)
-{
-	uint8_t buffer[PIPELINE_FC_FLOW_KEY_MAX_SIZE];
-	uint8_t m[PIPELINE_FC_FLOW_KEY_MAX_SIZE]; /* key mask */
-	void *key_buffer = (key_out) ? key_out : buffer;
-
-	memset(m, 0xFF, sizeof(m));
-	switch (key_in->type) {
-	case FLOW_KEY_QINQ:
-	{
-		struct pkt_key_qinq *qinq = key_buffer;
-
-		qinq->ethertype_svlan = 0;
-		qinq->svlan = rte_cpu_to_be_16(key_in->key.qinq.svlan);
-		qinq->ethertype_cvlan = 0;
-		qinq->cvlan = rte_cpu_to_be_16(key_in->key.qinq.cvlan);
-
-		if (signature)
-			*signature = (uint32_t) hash_default_key8(qinq, m, 8, 0);
-		return 0;
-	}
-
-	case FLOW_KEY_IPV4_5TUPLE:
-	{
-		struct pkt_key_ipv4_5tuple *ipv4 = key_buffer;
-
-		ipv4->ttl = 0;
-		ipv4->proto = key_in->key.ipv4_5tuple.proto;
-		ipv4->checksum = 0;
-		ipv4->ip_src = rte_cpu_to_be_32(key_in->key.ipv4_5tuple.ip_src);
-		ipv4->ip_dst = rte_cpu_to_be_32(key_in->key.ipv4_5tuple.ip_dst);
-		ipv4->port_src = rte_cpu_to_be_16(key_in->key.ipv4_5tuple.port_src);
-		ipv4->port_dst = rte_cpu_to_be_16(key_in->key.ipv4_5tuple.port_dst);
-
-		if (signature)
-			*signature = (uint32_t) hash_default_key16(ipv4, m, 16, 0);
-		return 0;
-	}
-
-	case FLOW_KEY_IPV6_5TUPLE:
-	{
-		struct pkt_key_ipv6_5tuple *ipv6 = key_buffer;
-
-		memset(ipv6, 0, 64);
-		ipv6->payload_length = 0;
-		ipv6->proto = key_in->key.ipv6_5tuple.proto;
-		ipv6->hop_limit = 0;
-		memcpy(&ipv6->ip_src, &key_in->key.ipv6_5tuple.ip_src, 16);
-		memcpy(&ipv6->ip_dst, &key_in->key.ipv6_5tuple.ip_dst, 16);
-		ipv6->port_src = rte_cpu_to_be_16(key_in->key.ipv6_5tuple.port_src);
-		ipv6->port_dst = rte_cpu_to_be_16(key_in->key.ipv6_5tuple.port_dst);
-
-		if (signature)
-			*signature = (uint32_t) hash_default_key64(ipv6, m, 64, 0);
-		return 0;
-	}
-
-	default:
-		return -1;
-	}
-}
-
-/*
- * Flow classification pipeline
- */
-
-struct app_pipeline_fc_flow {
-	struct pipeline_fc_key key;
-	uint32_t port_id;
-	uint32_t flow_id;
-	uint32_t signature;
-	void *entry_ptr;
-
-	TAILQ_ENTRY(app_pipeline_fc_flow) node;
-};
-
-#define N_BUCKETS                                65536
-
-struct app_pipeline_fc {
-	/* Parameters */
-	uint32_t n_ports_in;
-	uint32_t n_ports_out;
-
-	/* Flows */
-	TAILQ_HEAD(, app_pipeline_fc_flow) flows[N_BUCKETS];
-	uint32_t n_flows;
-
-	/* Default flow */
-	uint32_t default_flow_present;
-	uint32_t default_flow_port_id;
-	void *default_flow_entry_ptr;
-};
-
-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;
-	uint32_t signature, bucket_id;
-
-	app_pipeline_fc_key_convert(key, NULL, &signature);
-	bucket_id = signature & (N_BUCKETS - 1);
-
-	TAILQ_FOREACH(f, &p->flows[bucket_id], node)
-		if ((signature == f->signature) &&
-			(memcmp(key,
-				&f->key,
-				sizeof(struct pipeline_fc_key)) == 0))
-			return f;
-
-	return NULL;
-}
-
-static void*
-app_pipeline_fc_init(struct pipeline_params *params,
-	__rte_unused void *arg)
-{
-	struct app_pipeline_fc *p;
-	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 app_pipeline_fc));
-	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;
-
-	for (i = 0; i < N_BUCKETS; i++)
-		TAILQ_INIT(&p->flows[i]);
-	p->n_flows = 0;
-
-	return (void *) p;
-}
-
-static int
-app_pipeline_fc_free(void *pipeline)
-{
-	struct app_pipeline_fc *p = pipeline;
-	uint32_t i;
-
-	/* Check input arguments */
-	if (p == NULL)
-		return -1;
-
-	/* Free resources */
-	for (i = 0; i < N_BUCKETS; i++)
-		while (!TAILQ_EMPTY(&p->flows[i])) {
-			struct app_pipeline_fc_flow *flow;
-
-			flow = TAILQ_FIRST(&p->flows[i]);
-			TAILQ_REMOVE(&p->flows[i], flow, node);
-			rte_free(flow);
-		}
-
-	rte_free(p);
-	return 0;
-}
-
-static int
-app_pipeline_fc_key_check(struct pipeline_fc_key *key)
-{
-	switch (key->type) {
-	case FLOW_KEY_QINQ:
-	{
-		uint16_t svlan = key->key.qinq.svlan;
-		uint16_t cvlan = key->key.qinq.cvlan;
-
-		if ((svlan & 0xF000) ||
-			(cvlan & 0xF000))
-			return -1;
-
-		return 0;
-	}
-
-	case FLOW_KEY_IPV4_5TUPLE:
-		return 0;
-
-	case FLOW_KEY_IPV6_5TUPLE:
-		return 0;
-
-	default:
-		return -1;
-	}
-}
-
-int
-app_pipeline_fc_load_file_qinq(char *filename,
-	struct pipeline_fc_key *keys,
-	uint32_t *port_ids,
-	uint32_t *flow_ids,
-	uint32_t *n_keys,
-	uint32_t *line)
-{
-	FILE *f = NULL;
-	char file_buf[1024];
-	uint32_t i, l;
-
-	/* Check input arguments */
-	if ((filename == NULL) ||
-		(keys == NULL) ||
-		(port_ids == NULL) ||
-		(flow_ids == NULL) ||
-		(n_keys == NULL) ||
-		(*n_keys == 0) ||
-		(line == NULL)) {
-		if (line)
-			*line = 0;
-		return -1;
-		}
-
-	/* Open input file */
-	f = fopen(filename, "r");
-	if (f == NULL) {
-		*line = 0;
-		return -1;
-	}
-
-	/* Read file */
-	for (i = 0, l = 1; i < *n_keys; l++) {
-		char *tokens[32];
-		uint32_t n_tokens = RTE_DIM(tokens);
-
-		uint16_t svlan, cvlan;
-		uint32_t portid, flowid;
-		int status;
-
-		if (fgets(file_buf, sizeof(file_buf), f) == NULL)
-			break;
-
-		status = parse_tokenize_string(file_buf, tokens, &n_tokens);
-		if (status)
-			goto error1;
-
-		if ((n_tokens == 0) || (tokens[0][0] == '#'))
-			continue;
-
-		if ((n_tokens != 7) ||
-			strcmp(tokens[0], "qinq") ||
-			parser_read_uint16(&svlan, tokens[1]) ||
-			parser_read_uint16(&cvlan, tokens[2]) ||
-			strcmp(tokens[3], "port") ||
-			parser_read_uint32(&portid, tokens[4]) ||
-			strcmp(tokens[5], "id") ||
-			parser_read_uint32(&flowid, tokens[6]))
-			goto error1;
-
-		keys[i].type = FLOW_KEY_QINQ;
-		keys[i].key.qinq.svlan = svlan;
-		keys[i].key.qinq.cvlan = cvlan;
-
-		port_ids[i] = portid;
-		flow_ids[i] = flowid;
-
-		if (app_pipeline_fc_key_check(&keys[i]))
-			goto error1;
-
-		i++;
-	}
-
-	/* Close file */
-	*n_keys = i;
-	fclose(f);
-	return 0;
-
-error1:
-	*line = l;
-	fclose(f);
-	return -1;
-}
-
-int
-app_pipeline_fc_load_file_ipv4(char *filename,
-	struct pipeline_fc_key *keys,
-	uint32_t *port_ids,
-	uint32_t *flow_ids,
-	uint32_t *n_keys,
-	uint32_t *line)
-{
-	FILE *f = NULL;
-	char file_buf[1024];
-	uint32_t i, l;
-
-	/* Check input arguments */
-	if ((filename == NULL) ||
-		(keys == NULL) ||
-		(port_ids == NULL) ||
-		(flow_ids == NULL) ||
-		(n_keys == NULL) ||
-		(*n_keys == 0) ||
-		(line == NULL)) {
-		if (line)
-			*line = 0;
-		return -1;
-		}
-
-	/* Open input file */
-	f = fopen(filename, "r");
-	if (f == NULL) {
-		*line = 0;
-		return -1;
-	}
-
-	/* Read file */
-	for (i = 0, l = 1; i < *n_keys; l++) {
-		char *tokens[32];
-		uint32_t n_tokens = RTE_DIM(tokens);
-
-		struct in_addr sipaddr, dipaddr;
-		uint16_t sport, dport;
-		uint8_t proto;
-		uint32_t portid, flowid;
-		int status;
-
-		if (fgets(file_buf, sizeof(file_buf), f) == NULL)
-			break;
-
-		status = parse_tokenize_string(file_buf, tokens, &n_tokens);
-		if (status)
-			goto error2;
-
-		if ((n_tokens == 0) || (tokens[0][0] == '#'))
-			continue;
-
-		if ((n_tokens != 10) ||
-			strcmp(tokens[0], "ipv4") ||
-			parse_ipv4_addr(tokens[1], &sipaddr) ||
-			parse_ipv4_addr(tokens[2], &dipaddr) ||
-			parser_read_uint16(&sport, tokens[3]) ||
-			parser_read_uint16(&dport, tokens[4]) ||
-			parser_read_uint8(&proto, tokens[5]) ||
-			strcmp(tokens[6], "port") ||
-			parser_read_uint32(&portid, tokens[7]) ||
-			strcmp(tokens[8], "id") ||
-			parser_read_uint32(&flowid, tokens[9]))
-			goto error2;
-
-		keys[i].type = FLOW_KEY_IPV4_5TUPLE;
-		keys[i].key.ipv4_5tuple.ip_src = rte_be_to_cpu_32(sipaddr.s_addr);
-		keys[i].key.ipv4_5tuple.ip_dst = rte_be_to_cpu_32(dipaddr.s_addr);
-		keys[i].key.ipv4_5tuple.port_src = sport;
-		keys[i].key.ipv4_5tuple.port_dst = dport;
-		keys[i].key.ipv4_5tuple.proto = proto;
-
-		port_ids[i] = portid;
-		flow_ids[i] = flowid;
-
-		if (app_pipeline_fc_key_check(&keys[i]))
-			goto error2;
-
-		i++;
-	}
-
-	/* Close file */
-	*n_keys = i;
-	fclose(f);
-	return 0;
-
-error2:
-	*line = l;
-	fclose(f);
-	return -1;
-}
-
-int
-app_pipeline_fc_load_file_ipv6(char *filename,
-	struct pipeline_fc_key *keys,
-	uint32_t *port_ids,
-	uint32_t *flow_ids,
-	uint32_t *n_keys,
-	uint32_t *line)
-{
-	FILE *f = NULL;
-	char file_buf[1024];
-	uint32_t i, l;
-
-	/* Check input arguments */
-	if ((filename == NULL) ||
-		(keys == NULL) ||
-		(port_ids == NULL) ||
-		(flow_ids == NULL) ||
-		(n_keys == NULL) ||
-		(*n_keys == 0) ||
-		(line == NULL)) {
-		if (line)
-			*line = 0;
-		return -1;
-		}
-
-	/* Open input file */
-	f = fopen(filename, "r");
-	if (f == NULL) {
-		*line = 0;
-		return -1;
-	}
-
-	/* Read file */
-	for (i = 0, l = 1; i < *n_keys; l++) {
-		char *tokens[32];
-		uint32_t n_tokens = RTE_DIM(tokens);
-
-		struct in6_addr sipaddr, dipaddr;
-		uint16_t sport, dport;
-		uint8_t proto;
-		uint32_t portid, flowid;
-		int status;
-
-		if (fgets(file_buf, sizeof(file_buf), f) == NULL)
-			break;
-
-		status = parse_tokenize_string(file_buf, tokens, &n_tokens);
-		if (status)
-			goto error3;
-
-		if ((n_tokens == 0) || (tokens[0][0] == '#'))
-			continue;
-
-		if ((n_tokens != 10) ||
-			strcmp(tokens[0], "ipv6") ||
-			parse_ipv6_addr(tokens[1], &sipaddr) ||
-			parse_ipv6_addr(tokens[2], &dipaddr) ||
-			parser_read_uint16(&sport, tokens[3]) ||
-			parser_read_uint16(&dport, tokens[4]) ||
-			parser_read_uint8(&proto, tokens[5]) ||
-			strcmp(tokens[6], "port") ||
-			parser_read_uint32(&portid, tokens[7]) ||
-			strcmp(tokens[8], "id") ||
-			parser_read_uint32(&flowid, tokens[9]))
-			goto error3;
-
-		keys[i].type = FLOW_KEY_IPV6_5TUPLE;
-		memcpy(keys[i].key.ipv6_5tuple.ip_src,
-			sipaddr.s6_addr,
-			sizeof(sipaddr.s6_addr));
-		memcpy(keys[i].key.ipv6_5tuple.ip_dst,
-			dipaddr.s6_addr,
-			sizeof(dipaddr.s6_addr));
-		keys[i].key.ipv6_5tuple.port_src = sport;
-		keys[i].key.ipv6_5tuple.port_dst = dport;
-		keys[i].key.ipv6_5tuple.proto = proto;
-
-		port_ids[i] = portid;
-		flow_ids[i] = flowid;
-
-		if (app_pipeline_fc_key_check(&keys[i]))
-			goto error3;
-
-		i++;
-	}
-
-	/* Close file */
-	*n_keys = i;
-	fclose(f);
-	return 0;
-
-error3:
-	*line = l;
-	fclose(f);
-	return -1;
-}
-
-
-
-int
-app_pipeline_fc_add(struct app_params *app,
-	uint32_t pipeline_id,
-	struct pipeline_fc_key *key,
-	uint32_t port_id,
-	uint32_t flow_id)
-{
-	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;
-
-	uint32_t signature;
-	int new_flow;
-
-	/* Check input arguments */
-	if ((app == NULL) ||
-		(key == NULL))
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_flow_classification);
-	if (p == NULL)
-		return -1;
-
-	if (port_id >= p->n_ports_out)
-		return -1;
-
-	if (app_pipeline_fc_key_check(key) != 0)
-		return -1;
-
-	/* 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;
-	}
-
-	/* 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;
-	app_pipeline_fc_key_convert(key, req->key, &signature);
-	req->port_id = port_id;
-	req->flow_id = flow_id;
-
-	/* Send request and wait for response */
-	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL) {
-		if (new_flow)
-			rte_free(flow);
-		return -1;
-	}
-
-	/* Read response and write flow */
-	if (rsp->status ||
-		(rsp->entry_ptr == NULL) ||
-		((new_flow == 0) && (rsp->key_found == 0)) ||
-		((new_flow == 1) && (rsp->key_found == 1))) {
-		app_msg_free(app, rsp);
-		if (new_flow)
-			rte_free(flow);
-		return -1;
-	}
-
-	memset(&flow->key, 0, sizeof(flow->key));
-	memcpy(&flow->key, key, sizeof(flow->key));
-	flow->port_id = port_id;
-	flow->flow_id = flow_id;
-	flow->signature = signature;
-	flow->entry_ptr = rsp->entry_ptr;
-
-	/* Commit rule */
-	if (new_flow) {
-		uint32_t bucket_id = signature & (N_BUCKETS - 1);
-
-		TAILQ_INSERT_TAIL(&p->flows[bucket_id], flow, node);
-		p->n_flows++;
-	}
-
-	/* Free response */
-	app_msg_free(app, rsp);
-
-	return 0;
-}
-
-int
-app_pipeline_fc_add_bulk(struct app_params *app,
-	uint32_t pipeline_id,
-	struct pipeline_fc_key *key,
-	uint32_t *port_id,
-	uint32_t *flow_id,
-	uint32_t n_keys)
-{
-	struct app_pipeline_fc *p;
-	struct pipeline_fc_add_bulk_msg_req *req;
-	struct pipeline_fc_add_bulk_msg_rsp *rsp;
-
-	struct app_pipeline_fc_flow **flow;
-	uint32_t *signature;
-	int *new_flow;
-	struct pipeline_fc_add_bulk_flow_req *flow_req;
-	struct pipeline_fc_add_bulk_flow_rsp *flow_rsp;
-
-	uint32_t i;
-	int status;
-
-	/* Check input arguments */
-	if ((app == NULL) ||
-		(key == NULL) ||
-		(port_id == NULL) ||
-		(flow_id == NULL) ||
-		(n_keys == 0))
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_flow_classification);
-	if (p == NULL)
-		return -1;
-
-	for (i = 0; i < n_keys; i++)
-		if (port_id[i] >= p->n_ports_out)
-			return -1;
-
-	for (i = 0; i < n_keys; i++)
-		if (app_pipeline_fc_key_check(&key[i]) != 0)
-			return -1;
-
-	/* Memory allocation */
-	flow = rte_malloc(NULL,
-		n_keys * sizeof(struct app_pipeline_fc_flow *),
-		RTE_CACHE_LINE_SIZE);
-	if (flow == NULL)
-		return -1;
-
-	signature = rte_malloc(NULL,
-		n_keys * sizeof(uint32_t),
-		RTE_CACHE_LINE_SIZE);
-	if (signature == NULL) {
-		rte_free(flow);
-		return -1;
-	}
-
-	new_flow = rte_malloc(
-		NULL,
-		n_keys * sizeof(int),
-		RTE_CACHE_LINE_SIZE);
-	if (new_flow == NULL) {
-		rte_free(signature);
-		rte_free(flow);
-		return -1;
-	}
-
-	flow_req = rte_malloc(NULL,
-		n_keys * sizeof(struct pipeline_fc_add_bulk_flow_req),
-		RTE_CACHE_LINE_SIZE);
-	if (flow_req == NULL) {
-		rte_free(new_flow);
-		rte_free(signature);
-		rte_free(flow);
-		return -1;
-	}
-
-	flow_rsp = rte_malloc(NULL,
-		n_keys * sizeof(struct pipeline_fc_add_bulk_flow_rsp),
-		RTE_CACHE_LINE_SIZE);
-	if (flow_rsp == NULL) {
-		rte_free(flow_req);
-		rte_free(new_flow);
-		rte_free(signature);
-		rte_free(flow);
-		return -1;
-	}
-
-	/* Find existing flow or allocate new flow */
-	for (i = 0; i < n_keys; i++) {
-		flow[i] = app_pipeline_fc_flow_find(p, &key[i]);
-		new_flow[i] = (flow[i] == NULL);
-		if (flow[i] == NULL) {
-			flow[i] = rte_zmalloc(NULL,
-				sizeof(struct app_pipeline_fc_flow),
-				RTE_CACHE_LINE_SIZE);
-
-			if (flow[i] == NULL) {
-				uint32_t j;
-
-				for (j = 0; j < i; j++)
-					if (new_flow[j])
-						rte_free(flow[j]);
-
-				rte_free(flow_rsp);
-				rte_free(flow_req);
-				rte_free(new_flow);
-				rte_free(signature);
-				rte_free(flow);
-				return -1;
-			}
-		}
-	}
-
-	/* Allocate and write request */
-	req = app_msg_alloc(app);
-	if (req == NULL) {
-		for (i = 0; i < n_keys; i++)
-			if (new_flow[i])
-				rte_free(flow[i]);
-
-		rte_free(flow_rsp);
-		rte_free(flow_req);
-		rte_free(new_flow);
-		rte_free(signature);
-		rte_free(flow);
-		return -1;
-	}
-
-	for (i = 0; i < n_keys; i++) {
-		app_pipeline_fc_key_convert(&key[i],
-			flow_req[i].key,
-			&signature[i]);
-		flow_req[i].port_id = port_id[i];
-		flow_req[i].flow_id = flow_id[i];
-	}
-
-	req->type = PIPELINE_MSG_REQ_CUSTOM;
-	req->subtype = PIPELINE_FC_MSG_REQ_FLOW_ADD_BULK;
-	req->req = flow_req;
-	req->rsp = flow_rsp;
-	req->n_keys = n_keys;
-
-	/* Send request and wait for response */
-	rsp = app_msg_send_recv(app, pipeline_id, req, 10000);
-	if (rsp == NULL) {
-		for (i = 0; i < n_keys; i++)
-			if (new_flow[i])
-				rte_free(flow[i]);
-
-		rte_free(flow_rsp);
-		rte_free(flow_req);
-		rte_free(new_flow);
-		rte_free(signature);
-		rte_free(flow);
-		return -1;
-	}
-
-	/* Read response */
-	status = 0;
-
-	for (i = 0; i < rsp->n_keys; i++)
-		if ((flow_rsp[i].entry_ptr == NULL) ||
-			((new_flow[i] == 0) && (flow_rsp[i].key_found == 0)) ||
-			((new_flow[i] == 1) && (flow_rsp[i].key_found == 1)))
-			status = -1;
-
-	if (rsp->n_keys < n_keys)
-		status = -1;
-
-	/* Commit flows */
-	for (i = 0; i < rsp->n_keys; i++) {
-		memcpy(&flow[i]->key, &key[i], sizeof(flow[i]->key));
-		flow[i]->port_id = port_id[i];
-		flow[i]->flow_id = flow_id[i];
-		flow[i]->signature = signature[i];
-		flow[i]->entry_ptr = flow_rsp[i].entry_ptr;
-
-		if (new_flow[i]) {
-			uint32_t bucket_id = signature[i] & (N_BUCKETS - 1);
-
-			TAILQ_INSERT_TAIL(&p->flows[bucket_id], flow[i], node);
-			p->n_flows++;
-		}
-	}
-
-	/* Free resources */
-
-	for (i = rsp->n_keys; i < n_keys; i++)
-		if (new_flow[i])
-			rte_free(flow[i]);
-
-	app_msg_free(app, rsp);
-	rte_free(flow_rsp);
-	rte_free(flow_req);
-	rte_free(new_flow);
-	rte_free(signature);
-	rte_free(flow);
-
-	return status;
-}
-
-int
-app_pipeline_fc_del(struct app_params *app,
-	uint32_t pipeline_id,
-	struct pipeline_fc_key *key)
-{
-	struct app_pipeline_fc *p;
-	struct app_pipeline_fc_flow *flow;
-
-	struct pipeline_fc_del_msg_req *req;
-	struct pipeline_fc_del_msg_rsp *rsp;
-
-	uint32_t signature, bucket_id;
-
-	/* Check input arguments */
-	if ((app == NULL) ||
-		(key == NULL))
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_flow_classification);
-	if (p == NULL)
-		return -1;
-
-	if (app_pipeline_fc_key_check(key) != 0)
-		return -1;
-
-	/* 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;
-	app_pipeline_fc_key_convert(key, req->key, &signature);
-
-	/* Send request and wait for response */
-	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	/* Read response */
-	if (rsp->status || !rsp->key_found) {
-		app_msg_free(app, rsp);
-		return -1;
-	}
-
-	/* Remove rule */
-	bucket_id = signature & (N_BUCKETS - 1);
-	TAILQ_REMOVE(&p->flows[bucket_id], flow, node);
-	p->n_flows--;
-	rte_free(flow);
-
-	/* Free response */
-	app_msg_free(app, rsp);
-
-	return 0;
-}
-
-int
-app_pipeline_fc_add_default(struct app_params *app,
-	uint32_t pipeline_id,
-	uint32_t port_id)
-{
-	struct app_pipeline_fc *p;
-
-	struct pipeline_fc_add_default_msg_req *req;
-	struct pipeline_fc_add_default_msg_rsp *rsp;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_flow_classification);
-	if (p == NULL)
-		return -1;
-
-	if (port_id >= p->n_ports_out)
-		return -1;
-
-	/* 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_DEFAULT;
-	req->port_id = port_id;
-
-	/* Send request and wait for response */
-	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	/* Read response and write flow */
-	if (rsp->status || (rsp->entry_ptr == NULL)) {
-		app_msg_free(app, rsp);
-		return -1;
-	}
-
-	p->default_flow_port_id = port_id;
-	p->default_flow_entry_ptr = rsp->entry_ptr;
-
-	/* Commit route */
-	p->default_flow_present = 1;
-
-	/* Free response */
-	app_msg_free(app, rsp);
-
-	return 0;
-}
-
-int
-app_pipeline_fc_del_default(struct app_params *app,
-	uint32_t pipeline_id)
-{
-	struct app_pipeline_fc *p;
-
-	struct pipeline_fc_del_default_msg_req *req;
-	struct pipeline_fc_del_default_msg_rsp *rsp;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_flow_classification);
-	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_FC_MSG_REQ_FLOW_DEL_DEFAULT;
-
-	/* Send request and wait for response */
-	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	/* Read response */
-	if (rsp->status) {
-		app_msg_free(app, rsp);
-		return -1;
-	}
-
-	/* Commit route */
-	p->default_flow_present = 0;
-
-	/* Free response */
-	app_msg_free(app, rsp);
-
-	return 0;
-}
-
-/*
- * Flow ls
- */
-
-static void
-print_fc_qinq_flow(struct app_pipeline_fc_flow *flow)
-{
-	printf("(SVLAN = %" PRIu32 ", "
-		"CVLAN = %" PRIu32 ") => "
-		"Port = %" PRIu32 ", "
-		"Flow ID = %" PRIu32 ", "
-		"(signature = 0x%08" PRIx32 ", "
-		"entry_ptr = %p)\n",
-
-		flow->key.key.qinq.svlan,
-		flow->key.key.qinq.cvlan,
-		flow->port_id,
-		flow->flow_id,
-		flow->signature,
-		flow->entry_ptr);
-}
-
-static void
-print_fc_ipv4_5tuple_flow(struct app_pipeline_fc_flow *flow)
-{
-	printf("(SA = %" PRIu32 ".%" PRIu32 ".%" PRIu32 ".%" PRIu32 ", "
-		   "DA = %" PRIu32 ".%" PRIu32 ".%" PRIu32 ".%" PRIu32 ", "
-		   "SP = %" PRIu32 ", "
-		   "DP = %" PRIu32 ", "
-		   "Proto = %" PRIu32 ") => "
-		   "Port = %" PRIu32 ", "
-		   "Flow ID = %" PRIu32 " "
-		   "(signature = 0x%08" PRIx32 ", "
-		   "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->flow_id,
-		   flow->signature,
-		   flow->entry_ptr);
-}
-
-static void
-print_fc_ipv6_5tuple_flow(struct app_pipeline_fc_flow *flow) {
-	printf("(SA = %02" PRIx32 "%02" PRIx32 ":%02" PRIx32 "%02" PRIx32
-		":%02" PRIx32 "%02" PRIx32 ":%02" PRIx32 "%02" PRIx32
-		":%02" PRIx32 "%02" PRIx32 ":%02" PRIx32 "%02" PRIx32
-		":%02" PRIx32 "%02" PRIx32 ":%02" PRIx32 "%02" PRIx32 ", "
-		"DA = %02" PRIx32 "%02" PRIx32 ":%02" PRIx32 "%02" PRIx32
-		":%02" PRIx32 "%02" PRIx32 ":%02" PRIx32 "%02" PRIx32
-		":%02" PRIx32 "%02" PRIx32 ":%02" PRIx32 "%02" PRIx32
-		":%02" PRIx32 "%02" PRIx32 ":%02" PRIx32 "%02" PRIx32 ", "
-		"SP = %" PRIu32 ", "
-		"DP = %" PRIu32 " "
-		"Proto = %" PRIu32 " "
-		"=> Port = %" PRIu32 ", "
-		"Flow ID = %" PRIu32 " "
-		"(signature = 0x%08" PRIx32 ", "
-		"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],
-
-		flow->key.key.ipv6_5tuple.port_src,
-		flow->key.key.ipv6_5tuple.port_dst,
-
-		flow->key.key.ipv6_5tuple.proto,
-
-		flow->port_id,
-		flow->flow_id,
-		flow->signature,
-		flow->entry_ptr);
-}
-
-static void
-print_fc_flow(struct app_pipeline_fc_flow *flow)
-{
-	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;
-	}
-}
-
-static int
-app_pipeline_fc_ls(struct app_params *app,
-		uint32_t pipeline_id)
-{
-	struct app_pipeline_fc *p;
-	struct app_pipeline_fc_flow *flow;
-	uint32_t i;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_flow_classification);
-	if (p == NULL)
-		return -1;
-
-	for (i = 0; i < N_BUCKETS; i++)
-		TAILQ_FOREACH(flow, &p->flows[i], node)
-			print_fc_flow(flow);
-
-	if (p->default_flow_present)
-		printf("Default flow: port %" PRIu32 " (entry ptr = %p)\n",
-			p->default_flow_port_id,
-			p->default_flow_entry_ptr);
-	else
-		printf("Default: DROP\n");
-
-	return 0;
-}
-/*
- * flow
- *
- * flow add:
- *    p <pipelineid> flow add qinq <svlan> <cvlan> port <portid> id <flowid>
- *    p <pipelineid> flow add qinq bulk <file>
- *    p <pipelineid> flow add ipv4 <sipaddr> <dipaddr> <sport> <dport> <proto> port <port ID> id <flowid>
- *    p <pipelineid> flow add ipv4 bulk <file>
- *    p <pipelineid> flow add ipv6 <sipaddr> <dipaddr> <sport> <dport> <proto> port <port ID> id <flowid>
- *    p <pipelineid> flow add ipv6 bulk <file>
- *
- * flow add default:
- *    p <pipelineid> flow add default <portid>
- *
- * flow del:
- *    p <pipelineid> flow del qinq <svlan> <cvlan>
- *    p <pipelineid> flow del ipv4 <sipaddr> <dipaddr> <sport> <dport> <proto>
- *    p <pipelineid> flow del ipv6 <sipaddr> <dipaddr> <sport> <dport> <proto>
- *
- * flow del default:
- *    p <pipelineid> flow del default
- *
- * flow ls:
- *    p <pipelineid> flow ls
- */
-
-struct cmd_flow_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t flow_string;
-	cmdline_multi_string_t multi_string;
-};
-
-static void
-cmd_flow_parsed(void *parsed_result,
-	__attribute__((unused)) struct cmdline *cl,
-	void *data)
-{
-	struct cmd_flow_result *results = parsed_result;
-	struct app_params *app = data;
-
-	char *tokens[16];
-	uint32_t n_tokens = RTE_DIM(tokens);
-	int status;
-
-	status = parse_tokenize_string(results->multi_string, tokens, &n_tokens);
-	if (status) {
-		printf(CMD_MSG_TOO_MANY_ARGS, "flow");
-		return;
-	}
-
-	/* flow add qinq */
-	if ((n_tokens >= 3) &&
-		(strcmp(tokens[0], "add") == 0) &&
-		(strcmp(tokens[1], "qinq") == 0) &&
-		strcmp(tokens[2], "bulk")) {
-		struct pipeline_fc_key key;
-		uint32_t svlan;
-		uint32_t cvlan;
-		uint32_t port_id;
-		uint32_t flow_id;
-
-		memset(&key, 0, sizeof(key));
-
-		if (n_tokens != 8) {
-			printf(CMD_MSG_MISMATCH_ARGS, "flow add qinq");
-			return;
-		}
-
-		if (parser_read_uint32(&svlan, tokens[2]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "svlan");
-			return;
-		}
-
-		if (parser_read_uint32(&cvlan, tokens[3]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "cvlan");
-			return;
-		}
-
-		if (strcmp(tokens[4], "port") != 0) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "port");
-			return;
-		}
-
-		if (parser_read_uint32(&port_id, tokens[5]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "portid");
-			return;
-		}
-
-		if (strcmp(tokens[6], "id") != 0) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "id");
-			return;
-		}
-
-		if (parser_read_uint32(&flow_id, tokens[7]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "flowid");
-			return;
-		}
-
-		key.type = FLOW_KEY_QINQ;
-		key.key.qinq.svlan = svlan;
-		key.key.qinq.cvlan = cvlan;
-
-		status = app_pipeline_fc_add(app,
-			results->pipeline_id,
-			&key,
-			port_id,
-			flow_id);
-		if (status)
-			printf(CMD_MSG_FAIL, "flow add qinq");
-
-		return;
-	} /* flow add qinq */
-
-	/* flow add ipv4 */
-	if ((n_tokens >= 3) &&
-		(strcmp(tokens[0], "add") == 0) &&
-		(strcmp(tokens[1], "ipv4") == 0) &&
-		strcmp(tokens[2], "bulk")) {
-		struct pipeline_fc_key key;
-		struct in_addr sipaddr;
-		struct in_addr dipaddr;
-		uint32_t sport;
-		uint32_t dport;
-		uint32_t proto;
-		uint32_t port_id;
-		uint32_t flow_id;
-
-		memset(&key, 0, sizeof(key));
-
-		if (n_tokens != 11) {
-			printf(CMD_MSG_MISMATCH_ARGS, "flow add ipv4");
-			return;
-		}
-
-		if (parse_ipv4_addr(tokens[2], &sipaddr) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "sipv4addr");
-			return;
-		}
-		if (parse_ipv4_addr(tokens[3], &dipaddr) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "dipv4addr");
-			return;
-		}
-
-		if (parser_read_uint32(&sport, tokens[4]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "sport");
-			return;
-		}
-
-		if (parser_read_uint32(&dport, tokens[5]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "dport");
-			return;
-		}
-
-		if (parser_read_uint32(&proto, tokens[6]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "proto");
-			return;
-		}
-
-		if (strcmp(tokens[7], "port") != 0) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "port");
-			return;
-		}
-
-		if (parser_read_uint32(&port_id, tokens[8]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "portid");
-			return;
-		}
-
-		if (strcmp(tokens[9], "id") != 0) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "id");
-			return;
-		}
-
-		if (parser_read_uint32(&flow_id, tokens[10]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "flowid");
-			return;
-		}
-
-		key.type = FLOW_KEY_IPV4_5TUPLE;
-		key.key.ipv4_5tuple.ip_src = rte_be_to_cpu_32(sipaddr.s_addr);
-		key.key.ipv4_5tuple.ip_dst = rte_be_to_cpu_32(dipaddr.s_addr);
-		key.key.ipv4_5tuple.port_src = sport;
-		key.key.ipv4_5tuple.port_dst = dport;
-		key.key.ipv4_5tuple.proto = proto;
-
-		status = app_pipeline_fc_add(app,
-			results->pipeline_id,
-			&key,
-			port_id,
-			flow_id);
-		if (status)
-			printf(CMD_MSG_FAIL, "flow add ipv4");
-
-		return;
-	} /* flow add ipv4 */
-
-	/* flow add ipv6 */
-	if ((n_tokens >= 3) &&
-		(strcmp(tokens[0], "add") == 0) &&
-		(strcmp(tokens[1], "ipv6") == 0) &&
-		strcmp(tokens[2], "bulk")) {
-		struct pipeline_fc_key key;
-		struct in6_addr sipaddr;
-		struct in6_addr dipaddr;
-		uint32_t sport;
-		uint32_t dport;
-		uint32_t proto;
-		uint32_t port_id;
-		uint32_t flow_id;
-
-		memset(&key, 0, sizeof(key));
-
-		if (n_tokens != 11) {
-			printf(CMD_MSG_MISMATCH_ARGS, "flow add ipv6");
-			return;
-		}
-
-		if (parse_ipv6_addr(tokens[2], &sipaddr) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "sipv6addr");
-			return;
-		}
-		if (parse_ipv6_addr(tokens[3], &dipaddr) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "dipv6addr");
-			return;
-		}
-
-		if (parser_read_uint32(&sport, tokens[4]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "sport");
-			return;
-		}
-
-		if (parser_read_uint32(&dport, tokens[5]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "dport");
-			return;
-		}
-
-		if (parser_read_uint32(&proto, tokens[6]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "proto");
-			return;
-		}
-
-		if (strcmp(tokens[7], "port") != 0) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "port");
-			return;
-		}
-
-		if (parser_read_uint32(&port_id, tokens[8]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "portid");
-			return;
-		}
-
-		if (strcmp(tokens[9], "id") != 0) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "id");
-			return;
-		}
-
-		if (parser_read_uint32(&flow_id, tokens[10]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "flowid");
-			return;
-		}
-
-		key.type = FLOW_KEY_IPV6_5TUPLE;
-		memcpy(key.key.ipv6_5tuple.ip_src, (void *)&sipaddr, 16);
-		memcpy(key.key.ipv6_5tuple.ip_dst, (void *)&dipaddr, 16);
-		key.key.ipv6_5tuple.port_src = sport;
-		key.key.ipv6_5tuple.port_dst = dport;
-		key.key.ipv6_5tuple.proto = proto;
-
-		status = app_pipeline_fc_add(app,
-			results->pipeline_id,
-			&key,
-			port_id,
-			flow_id);
-		if (status)
-			printf(CMD_MSG_FAIL, "flow add ipv6");
-
-		return;
-	} /* flow add ipv6 */
-
-	/* flow add qinq bulk */
-	if ((n_tokens >= 3) &&
-		(strcmp(tokens[0], "add") == 0) &&
-		(strcmp(tokens[1], "qinq") == 0) &&
-		(strcmp(tokens[2], "bulk") == 0)) {
-		struct pipeline_fc_key *keys;
-		uint32_t *port_ids, *flow_ids, n_keys, line;
-		char *filename;
-
-		if (n_tokens != 4) {
-			printf(CMD_MSG_MISMATCH_ARGS, "flow add qinq bulk");
-			return;
-		}
-
-		filename = tokens[3];
-
-		n_keys = APP_PIPELINE_FC_MAX_FLOWS_IN_FILE;
-		keys = malloc(n_keys * sizeof(struct pipeline_fc_key));
-		if (keys == NULL)
-			return;
-		memset(keys, 0, n_keys * sizeof(struct pipeline_fc_key));
-
-		port_ids = malloc(n_keys * sizeof(uint32_t));
-		if (port_ids == NULL) {
-			free(keys);
-			return;
-		}
-
-		flow_ids = malloc(n_keys * sizeof(uint32_t));
-		if (flow_ids == NULL) {
-			free(port_ids);
-			free(keys);
-			return;
-		}
-
-		status = app_pipeline_fc_load_file_qinq(filename,
-			keys,
-			port_ids,
-			flow_ids,
-			&n_keys,
-			&line);
-		if (status != 0) {
-			printf(CMD_MSG_FILE_ERR, filename, line);
-			free(flow_ids);
-			free(port_ids);
-			free(keys);
-			return;
-		}
-
-		status = app_pipeline_fc_add_bulk(app,
-			results->pipeline_id,
-			keys,
-			port_ids,
-			flow_ids,
-			n_keys);
-		if (status)
-			printf(CMD_MSG_FAIL, "flow add qinq bulk");
-
-		free(flow_ids);
-		free(port_ids);
-		free(keys);
-		return;
-	} /* flow add qinq bulk */
-
-	/* flow add ipv4 bulk */
-	if ((n_tokens >= 3) &&
-		(strcmp(tokens[0], "add") == 0) &&
-		(strcmp(tokens[1], "ipv4") == 0) &&
-		(strcmp(tokens[2], "bulk") == 0)) {
-		struct pipeline_fc_key *keys;
-		uint32_t *port_ids, *flow_ids, n_keys, line;
-		char *filename;
-
-		if (n_tokens != 4) {
-			printf(CMD_MSG_MISMATCH_ARGS, "flow add ipv4 bulk");
-			return;
-		}
-
-		filename = tokens[3];
-
-		n_keys = APP_PIPELINE_FC_MAX_FLOWS_IN_FILE;
-		keys = malloc(n_keys * sizeof(struct pipeline_fc_key));
-		if (keys == NULL)
-			return;
-		memset(keys, 0, n_keys * sizeof(struct pipeline_fc_key));
-
-		port_ids = malloc(n_keys * sizeof(uint32_t));
-		if (port_ids == NULL) {
-			free(keys);
-			return;
-		}
-
-		flow_ids = malloc(n_keys * sizeof(uint32_t));
-		if (flow_ids == NULL) {
-			free(port_ids);
-			free(keys);
-			return;
-		}
-
-		status = app_pipeline_fc_load_file_ipv4(filename,
-			keys,
-			port_ids,
-			flow_ids,
-			&n_keys,
-			&line);
-		if (status != 0) {
-			printf(CMD_MSG_FILE_ERR, filename, line);
-			free(flow_ids);
-			free(port_ids);
-			free(keys);
-			return;
-		}
-
-		status = app_pipeline_fc_add_bulk(app,
-			results->pipeline_id,
-			keys,
-			port_ids,
-			flow_ids,
-			n_keys);
-		if (status)
-			printf(CMD_MSG_FAIL, "flow add ipv4 bulk");
-
-		free(flow_ids);
-		free(port_ids);
-		free(keys);
-		return;
-	} /* flow add ipv4 bulk */
-
-	/* flow add ipv6 bulk */
-	if ((n_tokens >= 3) &&
-		(strcmp(tokens[0], "add") == 0) &&
-		(strcmp(tokens[1], "ipv6") == 0) &&
-		(strcmp(tokens[2], "bulk") == 0)) {
-		struct pipeline_fc_key *keys;
-		uint32_t *port_ids, *flow_ids, n_keys, line;
-		char *filename;
-
-		if (n_tokens != 4) {
-			printf(CMD_MSG_MISMATCH_ARGS, "flow add ipv6 bulk");
-			return;
-		}
-
-		filename = tokens[3];
-
-		n_keys = APP_PIPELINE_FC_MAX_FLOWS_IN_FILE;
-		keys = malloc(n_keys * sizeof(struct pipeline_fc_key));
-		if (keys == NULL)
-			return;
-		memset(keys, 0, n_keys * sizeof(struct pipeline_fc_key));
-
-		port_ids = malloc(n_keys * sizeof(uint32_t));
-		if (port_ids == NULL) {
-			free(keys);
-			return;
-		}
-
-		flow_ids = malloc(n_keys * sizeof(uint32_t));
-		if (flow_ids == NULL) {
-			free(port_ids);
-			free(keys);
-			return;
-		}
-
-		status = app_pipeline_fc_load_file_ipv6(filename,
-			keys,
-			port_ids,
-			flow_ids,
-			&n_keys,
-			&line);
-		if (status != 0) {
-			printf(CMD_MSG_FILE_ERR, filename, line);
-			free(flow_ids);
-			free(port_ids);
-			free(keys);
-			return;
-		}
-
-		status = app_pipeline_fc_add_bulk(app,
-			results->pipeline_id,
-			keys,
-			port_ids,
-			flow_ids,
-			n_keys);
-		if (status)
-			printf(CMD_MSG_FAIL, "flow add ipv6 bulk");
-
-		free(flow_ids);
-		free(port_ids);
-		free(keys);
-		return;
-	} /* flow add ipv6 bulk */
-
-	/* flow add default*/
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "add") == 0) &&
-		(strcmp(tokens[1], "default") == 0)) {
-		uint32_t port_id;
-
-		if (n_tokens != 3) {
-			printf(CMD_MSG_MISMATCH_ARGS, "flow add default");
-			return;
-		}
-
-		if (parser_read_uint32(&port_id, tokens[2]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "portid");
-			return;
-		}
-
-		status = app_pipeline_fc_add_default(app,
-			results->pipeline_id,
-			port_id);
-		if (status)
-			printf(CMD_MSG_FAIL, "flow add default");
-
-		return;
-	} /* flow add default */
-
-	/* flow del qinq */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "del") == 0) &&
-		(strcmp(tokens[1], "qinq") == 0)) {
-		struct pipeline_fc_key key;
-		uint32_t svlan;
-		uint32_t cvlan;
-
-		memset(&key, 0, sizeof(key));
-
-		if (n_tokens != 4) {
-			printf(CMD_MSG_MISMATCH_ARGS, "flow del qinq");
-			return;
-		}
-
-		if (parser_read_uint32(&svlan, tokens[2]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "svlan");
-			return;
-		}
-
-		if (parser_read_uint32(&cvlan, tokens[3]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "cvlan");
-			return;
-		}
-
-		key.type = FLOW_KEY_QINQ;
-		key.key.qinq.svlan = svlan;
-		key.key.qinq.cvlan = cvlan;
-
-		status = app_pipeline_fc_del(app,
-			results->pipeline_id,
-			&key);
-		if (status)
-			printf(CMD_MSG_FAIL, "flow del qinq");
-
-		return;
-	} /* flow del qinq */
-
-	/* flow del ipv4 */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "del") == 0) &&
-		(strcmp(tokens[1], "ipv4") == 0)) {
-		struct pipeline_fc_key key;
-		struct in_addr sipaddr;
-		struct in_addr dipaddr;
-		uint32_t sport;
-		uint32_t dport;
-		uint32_t proto;
-
-		memset(&key, 0, sizeof(key));
-
-		if (n_tokens != 7) {
-			printf(CMD_MSG_MISMATCH_ARGS, "flow del ipv4");
-			return;
-		}
-
-		if (parse_ipv4_addr(tokens[2], &sipaddr) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "sipv4addr");
-			return;
-		}
-		if (parse_ipv4_addr(tokens[3], &dipaddr) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "dipv4addr");
-			return;
-		}
-
-		if (parser_read_uint32(&sport, tokens[4]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "sport");
-			return;
-		}
-
-		if (parser_read_uint32(&dport, tokens[5]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "dport");
-			return;
-		}
-
-		if (parser_read_uint32(&proto, tokens[6]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "proto");
-			return;
-		}
-
-		key.type = FLOW_KEY_IPV4_5TUPLE;
-		key.key.ipv4_5tuple.ip_src = rte_be_to_cpu_32(sipaddr.s_addr);
-		key.key.ipv4_5tuple.ip_dst = rte_be_to_cpu_32(dipaddr.s_addr);
-		key.key.ipv4_5tuple.port_src = sport;
-		key.key.ipv4_5tuple.port_dst = dport;
-		key.key.ipv4_5tuple.proto = proto;
-
-		status = app_pipeline_fc_del(app,
-			results->pipeline_id,
-			&key);
-		if (status)
-			printf(CMD_MSG_FAIL, "flow del ipv4");
-
-		return;
-	} /* flow del ipv4 */
-
-	/* flow del ipv6 */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "del") == 0) &&
-		(strcmp(tokens[1], "ipv6") == 0)) {
-		struct pipeline_fc_key key;
-		struct in6_addr sipaddr;
-		struct in6_addr dipaddr;
-		uint32_t sport;
-		uint32_t dport;
-		uint32_t proto;
-
-		memset(&key, 0, sizeof(key));
-
-		if (n_tokens != 7) {
-			printf(CMD_MSG_MISMATCH_ARGS, "flow del ipv6");
-			return;
-		}
-
-		if (parse_ipv6_addr(tokens[2], &sipaddr) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "sipv6addr");
-			return;
-		}
-
-		if (parse_ipv6_addr(tokens[3], &dipaddr) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "dipv6addr");
-			return;
-		}
-
-		if (parser_read_uint32(&sport, tokens[4]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "sport");
-			return;
-		}
-
-		if (parser_read_uint32(&dport, tokens[5]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "dport");
-			return;
-		}
-
-		if (parser_read_uint32(&proto, tokens[6]) != 0) {
-			printf(CMD_MSG_INVALID_ARG, "proto");
-			return;
-		}
-
-		key.type = FLOW_KEY_IPV6_5TUPLE;
-		memcpy(key.key.ipv6_5tuple.ip_src, &sipaddr, 16);
-		memcpy(key.key.ipv6_5tuple.ip_dst, &dipaddr, 16);
-		key.key.ipv6_5tuple.port_src = sport;
-		key.key.ipv6_5tuple.port_dst = dport;
-		key.key.ipv6_5tuple.proto = proto;
-
-		status = app_pipeline_fc_del(app,
-			results->pipeline_id,
-			&key);
-		if (status)
-			printf(CMD_MSG_FAIL, "flow del ipv6");
-
-		return;
-	} /* flow del ipv6 */
-
-	/* flow del default*/
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "del") == 0) &&
-		(strcmp(tokens[1], "default") == 0)) {
-		if (n_tokens != 2) {
-			printf(CMD_MSG_MISMATCH_ARGS, "flow del default");
-			return;
-		}
-
-		status = app_pipeline_fc_del_default(app,
-			results->pipeline_id);
-		if (status)
-			printf(CMD_MSG_FAIL, "flow del default");
-
-		return;
-	} /* flow del default */
-
-	/* flow ls */
-	if ((n_tokens >= 1) && (strcmp(tokens[0], "ls") == 0)) {
-		if (n_tokens != 1) {
-			printf(CMD_MSG_MISMATCH_ARGS, "flow ls");
-			return;
-		}
-
-		status = app_pipeline_fc_ls(app, results->pipeline_id);
-		if (status)
-			printf(CMD_MSG_FAIL, "flow ls");
-
-		return;
-	} /* flow ls */
-
-	printf(CMD_MSG_MISMATCH_ARGS, "flow");
-}
-
-static cmdline_parse_token_string_t cmd_flow_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_flow_result, p_string, "p");
-
-static cmdline_parse_token_num_t cmd_flow_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_flow_result, pipeline_id, UINT32);
-
-static cmdline_parse_token_string_t cmd_flow_flow_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_flow_result, flow_string, "flow");
-
-static cmdline_parse_token_string_t cmd_flow_multi_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_flow_result, multi_string,
-		TOKEN_STRING_MULTI);
-
-static cmdline_parse_inst_t cmd_flow = {
-	.f = cmd_flow_parsed,
-	.data = NULL,
-	.help_str = "flow add / add bulk / add default / del / del default / ls",
-	.tokens = {
-		(void *) &cmd_flow_p_string,
-		(void *) &cmd_flow_pipeline_id,
-		(void *) &cmd_flow_flow_string,
-		(void *) &cmd_flow_multi_string,
-		NULL,
-	},
-};
-
-static cmdline_parse_ctx_t pipeline_cmds[] = {
-	(cmdline_parse_inst_t *) &cmd_flow,
-	NULL,
-};
-
-static struct pipeline_fe_ops pipeline_flow_classification_fe_ops = {
-	.f_init = app_pipeline_fc_init,
-	.f_post_init = NULL,
-	.f_free = app_pipeline_fc_free,
-	.f_track = app_pipeline_track_default,
-	.cmds = pipeline_cmds,
-};
-
-struct pipeline_type pipeline_flow_classification = {
-	.name = "FLOW_CLASSIFICATION",
-	.be_ops = &pipeline_flow_classification_be_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
deleted file mode 100644
index 8c35498..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_flow_classification.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#ifndef __INCLUDE_PIPELINE_FLOW_CLASSIFICATION_H__
-#define __INCLUDE_PIPELINE_FLOW_CLASSIFICATION_H__
-
-#include "pipeline.h"
-#include "pipeline_flow_classification_be.h"
-
-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;
-	} key;
-};
-
-int
-app_pipeline_fc_add(struct app_params *app,
-	uint32_t pipeline_id,
-	struct pipeline_fc_key *key,
-	uint32_t port_id,
-	uint32_t flow_id);
-
-int
-app_pipeline_fc_add_bulk(struct app_params *app,
-	uint32_t pipeline_id,
-	struct pipeline_fc_key *key,
-	uint32_t *port_id,
-	uint32_t *flow_id,
-	uint32_t n_keys);
-
-int
-app_pipeline_fc_del(struct app_params *app,
-	uint32_t pipeline_id,
-	struct pipeline_fc_key *key);
-
-int
-app_pipeline_fc_add_default(struct app_params *app,
-	uint32_t pipeline_id,
-	uint32_t port_id);
-
-int
-app_pipeline_fc_del_default(struct app_params *app,
-	uint32_t pipeline_id);
-
-#ifndef APP_PIPELINE_FC_MAX_FLOWS_IN_FILE
-#define APP_PIPELINE_FC_MAX_FLOWS_IN_FILE	(16 * 1024 * 1024)
-#endif
-
-int
-app_pipeline_fc_load_file_qinq(char *filename,
-	struct pipeline_fc_key *keys,
-	uint32_t *port_ids,
-	uint32_t *flow_ids,
-	uint32_t *n_keys,
-	uint32_t *line);
-
-int
-app_pipeline_fc_load_file_ipv4(char *filename,
-	struct pipeline_fc_key *keys,
-	uint32_t *port_ids,
-	uint32_t *flow_ids,
-	uint32_t *n_keys,
-	uint32_t *line);
-
-int
-app_pipeline_fc_load_file_ipv6(char *filename,
-	struct pipeline_fc_key *keys,
-	uint32_t *port_ids,
-	uint32_t *flow_ids,
-	uint32_t *n_keys,
-	uint32_t *line);
-
-extern struct pipeline_type pipeline_flow_classification;
-
-#endif
diff --git a/examples/ip_pipeline/pipeline/pipeline_flow_classification_be.c b/examples/ip_pipeline/pipeline/pipeline_flow_classification_be.c
deleted file mode 100644
index 097ec34..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_flow_classification_be.c
+++ /dev/null
@@ -1,723 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2016 Intel Corporation
- */
-
-#include <string.h>
-
-#include <rte_common.h>
-#include <rte_malloc.h>
-#include <rte_table_hash.h>
-#include <rte_byteorder.h>
-#include <pipeline.h>
-
-#include "pipeline_flow_classification_be.h"
-#include "pipeline_actions_common.h"
-#include "parser.h"
-#include "hash_func.h"
-
-struct pipeline_flow_classification {
-	struct pipeline p;
-	pipeline_msg_req_handler custom_handlers[PIPELINE_FC_MSG_REQS];
-
-	uint32_t n_flows;
-	uint32_t key_size;
-	uint32_t flow_id;
-
-	uint32_t key_offset;
-	uint32_t hash_offset;
-	uint8_t key_mask[PIPELINE_FC_FLOW_KEY_MAX_SIZE];
-	uint32_t key_mask_present;
-	uint32_t flow_id_offset;
-
-} __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_add_bulk_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 pipeline_msg_req_handler custom_handlers[] = {
-	[PIPELINE_FC_MSG_REQ_FLOW_ADD] =
-		pipeline_fc_msg_req_add_handler,
-	[PIPELINE_FC_MSG_REQ_FLOW_ADD_BULK] =
-		pipeline_fc_msg_req_add_bulk_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,
-};
-
-/*
- * Flow table
- */
-struct flow_table_entry {
-	struct rte_pipeline_table_entry head;
-
-	uint32_t flow_id;
-	uint32_t pad;
-};
-
-rte_table_hash_op_hash hash_func[] = {
-	hash_default_key8,
-	hash_default_key16,
-	hash_default_key24,
-	hash_default_key32,
-	hash_default_key40,
-	hash_default_key48,
-	hash_default_key56,
-	hash_default_key64
-};
-
-/*
- * Flow table AH - Write flow_id to packet meta-data
- */
-static inline void
-pkt_work_flow_id(
-	struct rte_mbuf *pkt,
-	struct rte_pipeline_table_entry *table_entry,
-	void *arg)
-{
-	struct pipeline_flow_classification *p_fc = arg;
-	uint32_t *flow_id_ptr =
-		RTE_MBUF_METADATA_UINT32_PTR(pkt, p_fc->flow_id_offset);
-	struct flow_table_entry *entry =
-		(struct flow_table_entry *) table_entry;
-
-	/* Read */
-	uint32_t flow_id = entry->flow_id;
-
-	/* Compute */
-
-	/* Write */
-	*flow_id_ptr = flow_id;
-}
-
-static inline void
-pkt4_work_flow_id(
-	struct rte_mbuf **pkts,
-	struct rte_pipeline_table_entry **table_entries,
-	void *arg)
-{
-	struct pipeline_flow_classification *p_fc = arg;
-
-	uint32_t *flow_id_ptr0 =
-		RTE_MBUF_METADATA_UINT32_PTR(pkts[0], p_fc->flow_id_offset);
-	uint32_t *flow_id_ptr1 =
-		RTE_MBUF_METADATA_UINT32_PTR(pkts[1], p_fc->flow_id_offset);
-	uint32_t *flow_id_ptr2 =
-		RTE_MBUF_METADATA_UINT32_PTR(pkts[2], p_fc->flow_id_offset);
-	uint32_t *flow_id_ptr3 =
-		RTE_MBUF_METADATA_UINT32_PTR(pkts[3], p_fc->flow_id_offset);
-
-	struct flow_table_entry *entry0 =
-		(struct flow_table_entry *) table_entries[0];
-	struct flow_table_entry *entry1 =
-		(struct flow_table_entry *) table_entries[1];
-	struct flow_table_entry *entry2 =
-		(struct flow_table_entry *) table_entries[2];
-	struct flow_table_entry *entry3 =
-		(struct flow_table_entry *) table_entries[3];
-
-	/* Read */
-	uint32_t flow_id0 = entry0->flow_id;
-	uint32_t flow_id1 = entry1->flow_id;
-	uint32_t flow_id2 = entry2->flow_id;
-	uint32_t flow_id3 = entry3->flow_id;
-
-	/* Compute */
-
-	/* Write */
-	*flow_id_ptr0 = flow_id0;
-	*flow_id_ptr1 = flow_id1;
-	*flow_id_ptr2 = flow_id2;
-	*flow_id_ptr3 = flow_id3;
-}
-
-PIPELINE_TABLE_AH_HIT(fc_table_ah_hit,
-		pkt_work_flow_id, pkt4_work_flow_id);
-
-static rte_pipeline_table_action_handler_hit
-get_fc_table_ah_hit(struct pipeline_flow_classification *p)
-{
-	if (p->flow_id)
-		return fc_table_ah_hit;
-
-	return NULL;
-}
-
-/*
- * Argument parsing
- */
-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 key_mask_present = 0;
-	uint32_t flow_id_offset_present = 0;
-
-	uint32_t i;
-	char key_mask_str[PIPELINE_FC_FLOW_KEY_MAX_SIZE * 2 + 1];
-
-	p->hash_offset = 0;
-
-	/* default values */
-	p->flow_id = 0;
-
-	for (i = 0; i < params->n_args; i++) {
-		char *arg_name = params->args_name[i];
-		char *arg_value = params->args_value[i];
-
-		/* n_flows */
-		if (strcmp(arg_name, "n_flows") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				n_flows_present == 0, params->name,
-				arg_name);
-			n_flows_present = 1;
-
-			status = parser_read_uint32(&p->n_flows,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL(((status != -EINVAL) &&
-				(p->n_flows != 0)), params->name,
-				arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			continue;
-		}
-
-		/* key_offset */
-		if (strcmp(arg_name, "key_offset") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				key_offset_present == 0, params->name,
-				arg_name);
-			key_offset_present = 1;
-
-			status = parser_read_uint32(&p->key_offset,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			continue;
-		}
-
-		/* key_size */
-		if (strcmp(arg_name, "key_size") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				key_size_present == 0, params->name,
-				arg_name);
-			key_size_present = 1;
-
-			status = parser_read_uint32(&p->key_size,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL(((status != -EINVAL) &&
-				(p->key_size != 0) &&
-				(p->key_size % 8 == 0)),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG(((status != -ERANGE) &&
-				(p->key_size <=
-				PIPELINE_FC_FLOW_KEY_MAX_SIZE)),
-				params->name, arg_name, arg_value);
-
-			continue;
-		}
-
-		/* key_mask */
-		if (strcmp(arg_name, "key_mask") == 0) {
-			int mask_str_len = strlen(arg_value);
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				key_mask_present == 0,
-				params->name, arg_name);
-			key_mask_present = 1;
-
-			PIPELINE_ARG_CHECK((mask_str_len <=
-				(PIPELINE_FC_FLOW_KEY_MAX_SIZE * 2)),
-				"Parse error in section \"%s\": entry "
-				"\"%s\" is too long", params->name,
-				arg_name);
-
-			snprintf(key_mask_str, mask_str_len + 1, "%s",
-				arg_value);
-
-			continue;
-		}
-
-		/* hash_offset */
-		if (strcmp(arg_name, "hash_offset") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				hash_offset_present == 0, params->name,
-				arg_name);
-			hash_offset_present = 1;
-
-			status = parser_read_uint32(&p->hash_offset,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			continue;
-		}
-
-		/* flow_id_offset */
-		if (strcmp(arg_name, "flowid_offset") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				flow_id_offset_present == 0, params->name,
-				arg_name);
-			flow_id_offset_present = 1;
-
-			status = parser_read_uint32(&p->flow_id_offset,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			p->flow_id = 1;
-
-			continue;
-		}
-
-		/* Unknown argument */
-		PIPELINE_PARSE_ERR_INV_ENT(0, params->name, arg_name);
-	}
-
-	/* Check that mandatory arguments are present */
-	PIPELINE_PARSE_ERR_MANDATORY((n_flows_present), params->name,
-		"n_flows");
-	PIPELINE_PARSE_ERR_MANDATORY((key_offset_present), params->name,
-		"key_offset");
-	PIPELINE_PARSE_ERR_MANDATORY((key_size_present), params->name,
-		"key_size");
-
-	if (key_mask_present) {
-		uint32_t key_size = p->key_size;
-		int status;
-
-		PIPELINE_ARG_CHECK(((key_size == 8) || (key_size == 16)),
-			"Parse error in section \"%s\": entry key_mask "
-			"only allowed for key_size of 8 or 16 bytes",
-			params->name);
-
-		PIPELINE_ARG_CHECK((strlen(key_mask_str) ==
-			(key_size * 2)), "Parse error in section "
-			"\"%s\": key_mask should have exactly %u hex "
-			"digits", params->name, (key_size * 2));
-
-		PIPELINE_ARG_CHECK((hash_offset_present == 0), "Parse "
-			"error in section \"%s\": entry hash_offset only "
-			"allowed when key_mask is not present",
-			params->name);
-
-		status = parse_hex_string(key_mask_str, p->key_mask,
-			&p->key_size);
-
-		PIPELINE_PARSE_ERR_INV_VAL(((status == 0) &&
-			(key_size == p->key_size)), params->name,
-			"key_mask", key_mask_str);
-	}
-
-	p->key_mask_present = key_mask_present;
-
-	return 0;
-}
-
-static void *pipeline_fc_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 = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
-	if (p == NULL)
-		return NULL;
-	p_fc = (struct pipeline_flow_classification *) p;
-
-	strcpy(p->name, params->name);
-	p->log_level = params->log_level;
-
-	PLOG(p, HIGH, "Flow classification");
-
-	/* Parse arguments */
-	if (pipeline_fc_parse_args(p_fc, 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,
-			.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_params table_hash_params = {
-			.name = p->name,
-			.key_size = p_fc->key_size,
-			.key_offset = p_fc->key_offset,
-			.key_mask = (p_fc->key_mask_present) ?
-				p_fc->key_mask : NULL,
-			.n_keys = p_fc->n_flows,
-			.n_buckets = rte_align32pow2(p_fc->n_flows / 4),
-			.f_hash = hash_func[(p_fc->key_size / 8) - 1],
-			.seed = 0,
-		};
-
-		struct rte_pipeline_table_params table_params = {
-			.ops = NULL, /* set below */
-			.arg_create = NULL, /* set below */
-			.f_action_hit = get_fc_table_ah_hit(p_fc),
-			.f_action_miss = NULL,
-			.arg_ah = p_fc,
-			.action_data_size = sizeof(struct flow_table_entry) -
-				sizeof(struct rte_pipeline_table_entry),
-		};
-
-		int status;
-
-		switch (p_fc->key_size) {
-		case 8:
-			table_params.ops = &rte_table_hash_key8_ext_ops;
-			break;
-
-		case 16:
-			table_params.ops = &rte_table_hash_key16_ext_ops;
-			break;
-
-		default:
-			table_params.ops = &rte_table_hash_ext_ops;
-		}
-
-		table_params.arg_create = &table_hash_params;
-
-		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_fc_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_fc_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 flow_table_entry entry = {
-		.head = {
-			.action = RTE_PIPELINE_ACTION_PORT,
-			{.port_id = p->port_out_id[req->port_id]},
-		},
-		.flow_id = req->flow_id,
-	};
-
-	rsp->status = rte_pipeline_table_entry_add(p->p,
-		p->table_id[0],
-		&req->key,
-		(struct rte_pipeline_table_entry *) &entry,
-		&rsp->key_found,
-		(struct rte_pipeline_table_entry **) &rsp->entry_ptr);
-
-	return rsp;
-}
-
-static void *
-pipeline_fc_msg_req_add_bulk_handler(struct pipeline *p, void *msg)
-{
-	struct pipeline_fc_add_bulk_msg_req *req = msg;
-	struct pipeline_fc_add_bulk_msg_rsp *rsp = msg;
-	uint32_t i;
-
-	for (i = 0; i < req->n_keys; i++) {
-		struct pipeline_fc_add_bulk_flow_req *flow_req = &req->req[i];
-		struct pipeline_fc_add_bulk_flow_rsp *flow_rsp = &req->rsp[i];
-
-		struct flow_table_entry entry = {
-			.head = {
-				.action = RTE_PIPELINE_ACTION_PORT,
-				{.port_id = p->port_out_id[flow_req->port_id]},
-			},
-			.flow_id = flow_req->flow_id,
-		};
-
-		int status = rte_pipeline_table_entry_add(p->p,
-			p->table_id[0],
-			&flow_req->key,
-			(struct rte_pipeline_table_entry *) &entry,
-			&flow_rsp->key_found,
-			(struct rte_pipeline_table_entry **)
-				&flow_rsp->entry_ptr);
-
-		if (status)
-			break;
-	}
-
-	rsp->n_keys = i;
-
-	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;
-
-	rsp->status = rte_pipeline_table_entry_delete(p->p,
-		p->table_id[0],
-		&req->key,
-		&rsp->key_found,
-		NULL);
-
-	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 flow_table_entry default_entry = {
-		.head = {
-			.action = RTE_PIPELINE_ACTION_PORT,
-			{.port_id = p->port_out_id[req->port_id]},
-		},
-
-		.flow_id = 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;
-}
-
-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;
-}
-
-struct pipeline_be_ops pipeline_flow_classification_be_ops = {
-	.f_init = pipeline_fc_init,
-	.f_free = pipeline_fc_free,
-	.f_run = NULL,
-	.f_timer = pipeline_fc_timer,
-};
diff --git a/examples/ip_pipeline/pipeline/pipeline_flow_classification_be.h b/examples/ip_pipeline/pipeline/pipeline_flow_classification_be.h
deleted file mode 100644
index 18f5bb4..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_flow_classification_be.h
+++ /dev/null
@@ -1,113 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#ifndef __INCLUDE_PIPELINE_FLOW_CLASSIFICATION_BE_H__
-#define __INCLUDE_PIPELINE_FLOW_CLASSIFICATION_BE_H__
-
-#include "pipeline_common_be.h"
-
-enum pipeline_fc_msg_req_type {
-	PIPELINE_FC_MSG_REQ_FLOW_ADD = 0,
-	PIPELINE_FC_MSG_REQ_FLOW_ADD_BULK,
-	PIPELINE_FC_MSG_REQ_FLOW_DEL,
-	PIPELINE_FC_MSG_REQ_FLOW_ADD_DEFAULT,
-	PIPELINE_FC_MSG_REQ_FLOW_DEL_DEFAULT,
-	PIPELINE_FC_MSG_REQS,
-};
-
-#ifndef PIPELINE_FC_FLOW_KEY_MAX_SIZE
-#define PIPELINE_FC_FLOW_KEY_MAX_SIZE            64
-#endif
-
-/*
- * MSG ADD
- */
-struct pipeline_fc_add_msg_req {
-	enum pipeline_msg_req_type type;
-	enum pipeline_fc_msg_req_type subtype;
-
-	uint8_t key[PIPELINE_FC_FLOW_KEY_MAX_SIZE];
-
-	uint32_t port_id;
-	uint32_t flow_id;
-};
-
-struct pipeline_fc_add_msg_rsp {
-	int status;
-	int key_found;
-	void *entry_ptr;
-};
-
-/*
- * MSG ADD BULK
- */
-struct pipeline_fc_add_bulk_flow_req {
-	uint8_t key[PIPELINE_FC_FLOW_KEY_MAX_SIZE];
-	uint32_t port_id;
-	uint32_t flow_id;
-};
-
-struct pipeline_fc_add_bulk_flow_rsp {
-	int key_found;
-	void *entry_ptr;
-};
-
-struct pipeline_fc_add_bulk_msg_req {
-	enum pipeline_msg_req_type type;
-	enum pipeline_fc_msg_req_type subtype;
-
-	struct pipeline_fc_add_bulk_flow_req *req;
-	struct pipeline_fc_add_bulk_flow_rsp *rsp;
-	uint32_t n_keys;
-};
-
-struct pipeline_fc_add_bulk_msg_rsp {
-	uint32_t n_keys;
-};
-
-/*
- * MSG DEL
- */
-struct pipeline_fc_del_msg_req {
-	enum pipeline_msg_req_type type;
-	enum pipeline_fc_msg_req_type subtype;
-
-	uint8_t key[PIPELINE_FC_FLOW_KEY_MAX_SIZE];
-};
-
-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 *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_be_ops pipeline_flow_classification_be_ops;
-
-#endif
-- 
2.9.3

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

* [dpdk-dev] [PATCH v4 16/49] ip_pipeline: remove flow actions pipeline
  2018-03-29 18:31           ` [dpdk-dev] [PATCH v4 00/49] ip_pipeline: refactoring Jasvinder Singh
                               ` (14 preceding siblings ...)
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 15/49] ip_pipeline: remove flow classification pipeline Jasvinder Singh
@ 2018-03-29 18:31             ` Jasvinder Singh
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 17/49] ip_pipeline: remove firewall pipeline Jasvinder Singh
                               ` (33 subsequent siblings)
  49 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-29 18:31 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Remove flow actions pipeline.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/Makefile                      |    2 -
 examples/ip_pipeline/init.c                        |    2 -
 examples/ip_pipeline/meson.build                   |    2 -
 .../ip_pipeline/pipeline/pipeline_flow_actions.c   | 1286 --------------------
 .../ip_pipeline/pipeline/pipeline_flow_actions.h   |   60 -
 .../pipeline/pipeline_flow_actions_be.c            |  983 ---------------
 .../pipeline/pipeline_flow_actions_be.h            |  139 ---
 7 files changed, 2474 deletions(-)
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_actions.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_actions.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_actions_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_flow_actions_be.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index e43001f..0782308 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -21,8 +21,6 @@ SRCS-y += pipeline_master_be.c
 SRCS-y += pipeline_master.c
 SRCS-y += pipeline_firewall_be.c
 SRCS-y += pipeline_firewall.c
-SRCS-y += pipeline_flow_actions_be.c
-SRCS-y += pipeline_flow_actions.c
 
 # Build using pkg-config variables if possible
 $(shell pkg-config --exists libdpdk)
diff --git a/examples/ip_pipeline/init.c b/examples/ip_pipeline/init.c
index 4780bb1..6599b0d 100644
--- a/examples/ip_pipeline/init.c
+++ b/examples/ip_pipeline/init.c
@@ -27,7 +27,6 @@
 #include "pipeline_common_fe.h"
 #include "pipeline_master.h"
 #include "pipeline_firewall.h"
-#include "pipeline_flow_actions.h"
 #include "thread_fe.h"
 
 #define APP_NAME_SIZE	32
@@ -1819,7 +1818,6 @@ int app_init(struct app_params *app)
 	app_pipeline_common_cmd_push(app);
 	app_pipeline_thread_cmd_push(app);
 	app_pipeline_type_register(app, &pipeline_master);
-	app_pipeline_type_register(app, &pipeline_flow_actions);
 	app_pipeline_type_register(app, &pipeline_firewall);
 
 	app_init_pipelines(app);
diff --git a/examples/ip_pipeline/meson.build b/examples/ip_pipeline/meson.build
index dd12870..71812f4 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -23,8 +23,6 @@ sources = files(
 	'pipeline/pipeline_common_fe.c',
 	'pipeline/pipeline_firewall_be.c',
 	'pipeline/pipeline_firewall.c',
-	'pipeline/pipeline_flow_actions_be.c',
-	'pipeline/pipeline_flow_actions.c',
 	'pipeline/pipeline_master_be.c',
 	'pipeline/pipeline_master.c',
 )
diff --git a/examples/ip_pipeline/pipeline/pipeline_flow_actions.c b/examples/ip_pipeline/pipeline/pipeline_flow_actions.c
deleted file mode 100644
index 021aee1..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_flow_actions.c
+++ /dev/null
@@ -1,1286 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <sys/queue.h>
-#include <netinet/in.h>
-#include <unistd.h>
-
-#include <rte_common.h>
-#include <rte_hexdump.h>
-#include <rte_malloc.h>
-#include <cmdline_rdline.h>
-#include <cmdline_parse.h>
-#include <cmdline_parse_num.h>
-#include <cmdline_parse_string.h>
-
-#include "app.h"
-#include "pipeline_common_fe.h"
-#include "pipeline_flow_actions.h"
-#include "hash_func.h"
-#include "parser.h"
-
-/*
- * Flow actions pipeline
- */
-#ifndef N_FLOWS_BULK
-#define N_FLOWS_BULK					4096
-#endif
-
-struct app_pipeline_fa_flow {
-	struct pipeline_fa_flow_params params;
-	void *entry_ptr;
-};
-
-struct app_pipeline_fa_dscp {
-	uint32_t traffic_class;
-	enum rte_meter_color color;
-};
-
-struct app_pipeline_fa {
-	/* Parameters */
-	uint32_t n_ports_in;
-	uint32_t n_ports_out;
-	struct pipeline_fa_params params;
-
-	/* Flows */
-	struct app_pipeline_fa_dscp dscp[PIPELINE_FA_N_DSCP];
-	struct app_pipeline_fa_flow *flows;
-} __rte_cache_aligned;
-
-static void*
-app_pipeline_fa_init(struct pipeline_params *params,
-	__rte_unused void *arg)
-{
-	struct app_pipeline_fa *p;
-	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 app_pipeline_fa));
-	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;
-	if (pipeline_fa_parse_args(&p->params, params)) {
-		rte_free(p);
-		return NULL;
-	}
-
-	/* Memory allocation */
-	size = RTE_CACHE_LINE_ROUNDUP(
-		p->params.n_flows * sizeof(struct app_pipeline_fa_flow));
-	p->flows = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
-	if (p->flows == NULL) {
-		rte_free(p);
-		return NULL;
-	}
-
-	/* Initialization of flow table */
-	for (i = 0; i < p->params.n_flows; i++)
-		pipeline_fa_flow_params_set_default(&p->flows[i].params);
-
-	/* Initialization of DSCP table */
-	for (i = 0; i < RTE_DIM(p->dscp); i++) {
-		p->dscp[i].traffic_class = 0;
-		p->dscp[i].color = e_RTE_METER_GREEN;
-	}
-
-	return (void *) p;
-}
-
-static int
-app_pipeline_fa_free(void *pipeline)
-{
-	struct app_pipeline_fa *p = pipeline;
-
-	/* Check input arguments */
-	if (p == NULL)
-		return -1;
-
-	/* Free resources */
-	rte_free(p->flows);
-	rte_free(p);
-
-	return 0;
-}
-
-static int
-flow_params_check(struct app_pipeline_fa *p,
-	__rte_unused uint32_t meter_update_mask,
-	uint32_t policer_update_mask,
-	uint32_t port_update,
-	struct pipeline_fa_flow_params *params)
-{
-	uint32_t mask, i;
-
-	/* Meter */
-
-	/* Policer */
-	for (i = 0, mask = 1; i < PIPELINE_FA_N_TC_MAX; i++, mask <<= 1) {
-		struct pipeline_fa_policer_params *p = &params->p[i];
-		uint32_t j;
-
-		if ((mask & policer_update_mask) == 0)
-			continue;
-
-		for (j = 0; j < e_RTE_METER_COLORS; j++) {
-			struct pipeline_fa_policer_action *action =
-				&p->action[j];
-
-			if ((action->drop == 0) &&
-				(action->color >= e_RTE_METER_COLORS))
-				return -1;
-		}
-	}
-
-	/* Port */
-	if (port_update && (params->port_id >= p->n_ports_out))
-		return -1;
-
-	return 0;
-}
-
-int
-app_pipeline_fa_flow_config(struct app_params *app,
-	uint32_t pipeline_id,
-	uint32_t flow_id,
-	uint32_t meter_update_mask,
-	uint32_t policer_update_mask,
-	uint32_t port_update,
-	struct pipeline_fa_flow_params *params)
-{
-	struct app_pipeline_fa *p;
-	struct app_pipeline_fa_flow *flow;
-
-	struct pipeline_fa_flow_config_msg_req *req;
-	struct pipeline_fa_flow_config_msg_rsp *rsp;
-
-	uint32_t i, mask;
-
-	/* Check input arguments */
-	if ((app == NULL) ||
-		((meter_update_mask == 0) &&
-		(policer_update_mask == 0) &&
-		(port_update == 0)) ||
-		(meter_update_mask >= (1 << PIPELINE_FA_N_TC_MAX)) ||
-		(policer_update_mask >= (1 << PIPELINE_FA_N_TC_MAX)) ||
-		(params == NULL))
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id,
-		&pipeline_flow_actions);
-	if (p == NULL)
-		return -1;
-
-	if (flow_params_check(p,
-		meter_update_mask,
-		policer_update_mask,
-		port_update,
-		params) != 0)
-		return -1;
-
-	flow_id %= p->params.n_flows;
-	flow = &p->flows[flow_id];
-
-	/* Allocate and write request */
-	req = app_msg_alloc(app);
-	if (req == NULL)
-		return -1;
-
-	req->type = PIPELINE_MSG_REQ_CUSTOM;
-	req->subtype = PIPELINE_FA_MSG_REQ_FLOW_CONFIG;
-	req->entry_ptr = flow->entry_ptr;
-	req->flow_id = flow_id;
-	req->meter_update_mask = meter_update_mask;
-	req->policer_update_mask = policer_update_mask;
-	req->port_update = port_update;
-	memcpy(&req->params, params, sizeof(*params));
-
-	/* Send request and wait for response */
-	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	/* Read response */
-	if (rsp->status ||
-		(rsp->entry_ptr == NULL)) {
-		app_msg_free(app, rsp);
-		return -1;
-	}
-
-	/* Commit flow */
-	for (i = 0, mask = 1; i < PIPELINE_FA_N_TC_MAX; i++, mask <<= 1) {
-		if ((mask & meter_update_mask) == 0)
-			continue;
-
-		memcpy(&flow->params.m[i], &params->m[i], sizeof(params->m[i]));
-	}
-
-	for (i = 0, mask = 1; i < PIPELINE_FA_N_TC_MAX; i++, mask <<= 1) {
-		if ((mask & policer_update_mask) == 0)
-			continue;
-
-		memcpy(&flow->params.p[i], &params->p[i], sizeof(params->p[i]));
-	}
-
-	if (port_update)
-		flow->params.port_id = params->port_id;
-
-	flow->entry_ptr = rsp->entry_ptr;
-
-	/* Free response */
-	app_msg_free(app, rsp);
-
-	return 0;
-}
-
-int
-app_pipeline_fa_flow_config_bulk(struct app_params *app,
-	uint32_t pipeline_id,
-	uint32_t *flow_id,
-	uint32_t n_flows,
-	uint32_t meter_update_mask,
-	uint32_t policer_update_mask,
-	uint32_t port_update,
-	struct pipeline_fa_flow_params *params)
-{
-	struct app_pipeline_fa *p;
-	struct pipeline_fa_flow_config_bulk_msg_req *req;
-	struct pipeline_fa_flow_config_bulk_msg_rsp *rsp;
-	void **req_entry_ptr;
-	uint32_t *req_flow_id;
-	uint32_t i;
-	int status;
-
-	/* Check input arguments */
-	if ((app == NULL) ||
-		(flow_id == NULL) ||
-		(n_flows == 0) ||
-		((meter_update_mask == 0) &&
-		(policer_update_mask == 0) &&
-		(port_update == 0)) ||
-		(meter_update_mask >= (1 << PIPELINE_FA_N_TC_MAX)) ||
-		(policer_update_mask >= (1 << PIPELINE_FA_N_TC_MAX)) ||
-		(params == NULL))
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id,
-		&pipeline_flow_actions);
-	if (p == NULL)
-		return -1;
-
-	for (i = 0; i < n_flows; i++) {
-		struct pipeline_fa_flow_params *flow_params = &params[i];
-
-		if (flow_params_check(p,
-			meter_update_mask,
-			policer_update_mask,
-			port_update,
-			flow_params) != 0)
-			return -1;
-	}
-
-	/* Allocate and write request */
-	req_entry_ptr = (void **) rte_malloc(NULL,
-		n_flows * sizeof(void *),
-		RTE_CACHE_LINE_SIZE);
-	if (req_entry_ptr == NULL)
-		return -1;
-
-	req_flow_id = (uint32_t *) rte_malloc(NULL,
-		n_flows * sizeof(uint32_t),
-		RTE_CACHE_LINE_SIZE);
-	if (req_flow_id == NULL) {
-		rte_free(req_entry_ptr);
-		return -1;
-	}
-
-	for (i = 0; i < n_flows; i++) {
-		uint32_t fid = flow_id[i] % p->params.n_flows;
-		struct app_pipeline_fa_flow *flow = &p->flows[fid];
-
-		req_flow_id[i] = fid;
-		req_entry_ptr[i] = flow->entry_ptr;
-	}
-
-	req = app_msg_alloc(app);
-	if (req == NULL) {
-		rte_free(req_flow_id);
-		rte_free(req_entry_ptr);
-		return -1;
-	}
-
-	req->type = PIPELINE_MSG_REQ_CUSTOM;
-	req->subtype = PIPELINE_FA_MSG_REQ_FLOW_CONFIG_BULK;
-	req->entry_ptr = req_entry_ptr;
-	req->flow_id = req_flow_id;
-	req->n_flows = n_flows;
-	req->meter_update_mask = meter_update_mask;
-	req->policer_update_mask = policer_update_mask;
-	req->port_update = port_update;
-	req->params = params;
-
-	/* Send request and wait for response */
-	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL) {
-		rte_free(req_flow_id);
-		rte_free(req_entry_ptr);
-		return -1;
-	}
-
-	/* Read response */
-	status = (rsp->n_flows == n_flows) ? 0 : -1;
-
-	/* Commit flows */
-	for (i = 0; i < rsp->n_flows; i++) {
-		uint32_t fid = flow_id[i] % p->params.n_flows;
-		struct app_pipeline_fa_flow *flow = &p->flows[fid];
-		struct pipeline_fa_flow_params *flow_params = &params[i];
-		void *entry_ptr = req_entry_ptr[i];
-		uint32_t j, mask;
-
-		for (j = 0, mask = 1; j < PIPELINE_FA_N_TC_MAX;
-			j++, mask <<= 1) {
-			if ((mask & meter_update_mask) == 0)
-				continue;
-
-			memcpy(&flow->params.m[j],
-				&flow_params->m[j],
-				sizeof(flow_params->m[j]));
-		}
-
-		for (j = 0, mask = 1; j < PIPELINE_FA_N_TC_MAX;
-			j++, mask <<= 1) {
-			if ((mask & policer_update_mask) == 0)
-				continue;
-
-			memcpy(&flow->params.p[j],
-				&flow_params->p[j],
-				sizeof(flow_params->p[j]));
-		}
-
-		if (port_update)
-			flow->params.port_id = flow_params->port_id;
-
-		flow->entry_ptr = entry_ptr;
-	}
-
-	/* Free response */
-	app_msg_free(app, rsp);
-	rte_free(req_flow_id);
-	rte_free(req_entry_ptr);
-
-	return status;
-}
-
-int
-app_pipeline_fa_dscp_config(struct app_params *app,
-	uint32_t pipeline_id,
-	uint32_t dscp,
-	uint32_t traffic_class,
-	enum rte_meter_color color)
-{
-	struct app_pipeline_fa *p;
-
-	struct pipeline_fa_dscp_config_msg_req *req;
-	struct pipeline_fa_dscp_config_msg_rsp *rsp;
-
-	/* Check input arguments */
-	if ((app == NULL) ||
-		(dscp >= PIPELINE_FA_N_DSCP) ||
-		(traffic_class >= PIPELINE_FA_N_TC_MAX) ||
-		(color >= e_RTE_METER_COLORS))
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id,
-		&pipeline_flow_actions);
-	if (p == NULL)
-		return -1;
-
-	if (p->params.dscp_enabled == 0)
-		return -1;
-
-	/* Allocate and write request */
-	req = app_msg_alloc(app);
-	if (req == NULL)
-		return -1;
-
-	req->type = PIPELINE_MSG_REQ_CUSTOM;
-	req->subtype = PIPELINE_FA_MSG_REQ_DSCP_CONFIG;
-	req->dscp = dscp;
-	req->traffic_class = traffic_class;
-	req->color = color;
-
-	/* Send request and wait for response */
-	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	/* Read response */
-	if (rsp->status) {
-		app_msg_free(app, rsp);
-		return -1;
-	}
-
-	/* Commit DSCP */
-	p->dscp[dscp].traffic_class = traffic_class;
-	p->dscp[dscp].color = color;
-
-	/* Free response */
-	app_msg_free(app, rsp);
-
-	return 0;
-}
-
-int
-app_pipeline_fa_flow_policer_stats_read(struct app_params *app,
-	uint32_t pipeline_id,
-	uint32_t flow_id,
-	uint32_t policer_id,
-	int clear,
-	struct pipeline_fa_policer_stats *stats)
-{
-	struct app_pipeline_fa *p;
-	struct app_pipeline_fa_flow *flow;
-
-	struct pipeline_fa_policer_stats_msg_req *req;
-	struct pipeline_fa_policer_stats_msg_rsp *rsp;
-
-	/* Check input arguments */
-	if ((app == NULL) || (stats == NULL))
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id,
-		&pipeline_flow_actions);
-	if (p == NULL)
-		return -1;
-
-	flow_id %= p->params.n_flows;
-	flow = &p->flows[flow_id];
-
-	if ((policer_id >= p->params.n_meters_per_flow) ||
-		(flow->entry_ptr == NULL))
-		return -1;
-
-	/* Allocate and write request */
-	req = app_msg_alloc(app);
-	if (req == NULL)
-		return -1;
-
-	req->type = PIPELINE_MSG_REQ_CUSTOM;
-	req->subtype = PIPELINE_FA_MSG_REQ_POLICER_STATS_READ;
-	req->entry_ptr = flow->entry_ptr;
-	req->policer_id = policer_id;
-	req->clear = clear;
-
-	/* Send request and wait for response */
-	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	/* Read response */
-	if (rsp->status) {
-		app_msg_free(app, rsp);
-		return -1;
-	}
-
-	memcpy(stats, &rsp->stats, sizeof(*stats));
-
-	/* Free response */
-	app_msg_free(app, rsp);
-
-	return 0;
-}
-
-static const char *
-color_to_string(enum rte_meter_color color)
-{
-	switch (color) {
-	case e_RTE_METER_GREEN: return "G";
-	case e_RTE_METER_YELLOW: return "Y";
-	case e_RTE_METER_RED: return "R";
-	default: return "?";
-	}
-}
-
-static int
-string_to_color(char *s, enum rte_meter_color *c)
-{
-	if (strcmp(s, "G") == 0) {
-		*c = e_RTE_METER_GREEN;
-		return 0;
-	}
-
-	if (strcmp(s, "Y") == 0) {
-		*c = e_RTE_METER_YELLOW;
-		return 0;
-	}
-
-	if (strcmp(s, "R") == 0) {
-		*c = e_RTE_METER_RED;
-		return 0;
-	}
-
-	return -1;
-}
-
-static const char *
-policer_action_to_string(struct pipeline_fa_policer_action *a)
-{
-	if (a->drop)
-		return "D";
-
-	return color_to_string(a->color);
-}
-
-static int
-string_to_policer_action(char *s, struct pipeline_fa_policer_action *a)
-{
-	if (strcmp(s, "G") == 0) {
-		a->drop = 0;
-		a->color = e_RTE_METER_GREEN;
-		return 0;
-	}
-
-	if (strcmp(s, "Y") == 0) {
-		a->drop = 0;
-		a->color = e_RTE_METER_YELLOW;
-		return 0;
-	}
-
-	if (strcmp(s, "R") == 0) {
-		a->drop = 0;
-		a->color = e_RTE_METER_RED;
-		return 0;
-	}
-
-	if (strcmp(s, "D") == 0) {
-		a->drop = 1;
-		a->color = e_RTE_METER_GREEN;
-		return 0;
-	}
-
-	return -1;
-}
-
-static void
-print_flow(struct app_pipeline_fa *p,
-	uint32_t flow_id,
-	struct app_pipeline_fa_flow *flow)
-{
-	uint32_t i;
-
-	printf("Flow ID = %" PRIu32 "\n", flow_id);
-
-	for (i = 0; i < p->params.n_meters_per_flow; i++) {
-		struct rte_meter_trtcm_params *meter = &flow->params.m[i];
-		struct pipeline_fa_policer_params *policer = &flow->params.p[i];
-
-	printf("\ttrTCM [CIR = %" PRIu64
-		", CBS = %" PRIu64 ", PIR = %" PRIu64
-		", PBS = %" PRIu64	"] Policer [G : %s, Y : %s, R : %s]\n",
-		meter->cir,
-		meter->cbs,
-		meter->pir,
-		meter->pbs,
-		policer_action_to_string(&policer->action[e_RTE_METER_GREEN]),
-		policer_action_to_string(&policer->action[e_RTE_METER_YELLOW]),
-		policer_action_to_string(&policer->action[e_RTE_METER_RED]));
-	}
-
-	printf("\tPort %u (entry_ptr = %p)\n",
-		flow->params.port_id,
-		flow->entry_ptr);
-}
-
-
-static int
-app_pipeline_fa_flow_ls(struct app_params *app,
-		uint32_t pipeline_id)
-{
-	struct app_pipeline_fa *p;
-	uint32_t i;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id,
-		&pipeline_flow_actions);
-	if (p == NULL)
-		return -1;
-
-	for (i = 0; i < p->params.n_flows; i++) {
-		struct app_pipeline_fa_flow *flow = &p->flows[i];
-
-		print_flow(p, i, flow);
-	}
-
-	return 0;
-}
-
-static int
-app_pipeline_fa_dscp_ls(struct app_params *app,
-		uint32_t pipeline_id)
-{
-	struct app_pipeline_fa *p;
-	uint32_t i;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id,
-		&pipeline_flow_actions);
-	if (p == NULL)
-		return -1;
-
-	if (p->params.dscp_enabled == 0)
-		return -1;
-
-	for (i = 0; i < RTE_DIM(p->dscp); i++) {
-		struct app_pipeline_fa_dscp *dscp =	&p->dscp[i];
-
-		printf("DSCP = %2" PRIu32 ": Traffic class = %" PRIu32
-			", Color = %s\n",
-			i,
-			dscp->traffic_class,
-			color_to_string(dscp->color));
-	}
-
-	return 0;
-}
-
-int
-app_pipeline_fa_load_file(char *filename,
-	uint32_t *flow_ids,
-	struct pipeline_fa_flow_params *p,
-	uint32_t *n_flows,
-	uint32_t *line)
-{
-	FILE *f = NULL;
-	char file_buf[1024];
-	uint32_t i, l;
-
-	/* Check input arguments */
-	if ((filename == NULL) ||
-		(flow_ids == NULL) ||
-		(p == NULL) ||
-		(n_flows == NULL) ||
-		(*n_flows == 0) ||
-		(line == NULL)) {
-		if (line)
-			*line = 0;
-		return -1;
-		}
-
-	/* Open input file */
-	f = fopen(filename, "r");
-	if (f == NULL) {
-		*line = 0;
-		return -1;
-	}
-
-	/* Read file */
-	for (i = 0, l = 1; i < *n_flows; l++) {
-		char *tokens[64];
-		uint32_t n_tokens = RTE_DIM(tokens);
-
-		int status;
-
-		if (fgets(file_buf, sizeof(file_buf), f) == NULL)
-			break;
-
-		status = parse_tokenize_string(file_buf, tokens, &n_tokens);
-		if (status)
-			goto error1;
-
-		if ((n_tokens == 0) || (tokens[0][0] == '#'))
-			continue;
-
-
-		if ((n_tokens != 64) ||
-			/* flow */
-			strcmp(tokens[0], "flow") ||
-			parser_read_uint32(&flow_ids[i], tokens[1]) ||
-
-			/* meter & policer 0 */
-			strcmp(tokens[2], "meter") ||
-			strcmp(tokens[3], "0") ||
-			strcmp(tokens[4], "trtcm") ||
-			parser_read_uint64(&p[i].m[0].cir, tokens[5]) ||
-			parser_read_uint64(&p[i].m[0].pir, tokens[6]) ||
-			parser_read_uint64(&p[i].m[0].cbs, tokens[7]) ||
-			parser_read_uint64(&p[i].m[0].pbs, tokens[8]) ||
-			strcmp(tokens[9], "policer") ||
-			strcmp(tokens[10], "0") ||
-			strcmp(tokens[11], "g") ||
-			string_to_policer_action(tokens[12],
-				&p[i].p[0].action[e_RTE_METER_GREEN]) ||
-			strcmp(tokens[13], "y") ||
-			string_to_policer_action(tokens[14],
-				&p[i].p[0].action[e_RTE_METER_YELLOW]) ||
-			strcmp(tokens[15], "r") ||
-			string_to_policer_action(tokens[16],
-				&p[i].p[0].action[e_RTE_METER_RED]) ||
-
-			/* meter & policer 1 */
-			strcmp(tokens[17], "meter") ||
-			strcmp(tokens[18], "1") ||
-			strcmp(tokens[19], "trtcm") ||
-			parser_read_uint64(&p[i].m[1].cir, tokens[20]) ||
-			parser_read_uint64(&p[i].m[1].pir, tokens[21]) ||
-			parser_read_uint64(&p[i].m[1].cbs, tokens[22]) ||
-			parser_read_uint64(&p[i].m[1].pbs, tokens[23]) ||
-			strcmp(tokens[24], "policer") ||
-			strcmp(tokens[25], "1") ||
-			strcmp(tokens[26], "g") ||
-			string_to_policer_action(tokens[27],
-				&p[i].p[1].action[e_RTE_METER_GREEN]) ||
-			strcmp(tokens[28], "y") ||
-			string_to_policer_action(tokens[29],
-				&p[i].p[1].action[e_RTE_METER_YELLOW]) ||
-			strcmp(tokens[30], "r") ||
-			string_to_policer_action(tokens[31],
-				&p[i].p[1].action[e_RTE_METER_RED]) ||
-
-			/* meter & policer 2 */
-			strcmp(tokens[32], "meter") ||
-			strcmp(tokens[33], "2") ||
-			strcmp(tokens[34], "trtcm") ||
-			parser_read_uint64(&p[i].m[2].cir, tokens[35]) ||
-			parser_read_uint64(&p[i].m[2].pir, tokens[36]) ||
-			parser_read_uint64(&p[i].m[2].cbs, tokens[37]) ||
-			parser_read_uint64(&p[i].m[2].pbs, tokens[38]) ||
-			strcmp(tokens[39], "policer") ||
-			strcmp(tokens[40], "2") ||
-			strcmp(tokens[41], "g") ||
-			string_to_policer_action(tokens[42],
-				&p[i].p[2].action[e_RTE_METER_GREEN]) ||
-			strcmp(tokens[43], "y") ||
-			string_to_policer_action(tokens[44],
-				&p[i].p[2].action[e_RTE_METER_YELLOW]) ||
-			strcmp(tokens[45], "r") ||
-			string_to_policer_action(tokens[46],
-				&p[i].p[2].action[e_RTE_METER_RED]) ||
-
-			/* meter & policer 3 */
-			strcmp(tokens[47], "meter") ||
-			strcmp(tokens[48], "3") ||
-			strcmp(tokens[49], "trtcm") ||
-			parser_read_uint64(&p[i].m[3].cir, tokens[50]) ||
-			parser_read_uint64(&p[i].m[3].pir, tokens[51]) ||
-			parser_read_uint64(&p[i].m[3].cbs, tokens[52]) ||
-			parser_read_uint64(&p[i].m[3].pbs, tokens[53]) ||
-			strcmp(tokens[54], "policer") ||
-			strcmp(tokens[55], "3") ||
-			strcmp(tokens[56], "g") ||
-			string_to_policer_action(tokens[57],
-				&p[i].p[3].action[e_RTE_METER_GREEN]) ||
-			strcmp(tokens[58], "y") ||
-			string_to_policer_action(tokens[59],
-				&p[i].p[3].action[e_RTE_METER_YELLOW]) ||
-			strcmp(tokens[60], "r") ||
-			string_to_policer_action(tokens[61],
-				&p[i].p[3].action[e_RTE_METER_RED]) ||
-
-			/* port */
-			strcmp(tokens[62], "port") ||
-			parser_read_uint32(&p[i].port_id, tokens[63]))
-			goto error1;
-
-		i++;
-	}
-
-	/* Close file */
-	*n_flows = i;
-	fclose(f);
-	return 0;
-
-error1:
-	*line = l;
-	fclose(f);
-	return -1;
-}
-
-/*
- * action
- *
- * flow meter, policer and output port configuration:
- *    p <pipelineid> action flow <flowid> meter <meterid> trtcm <cir> <pir> <cbs> <pbs>
- *
- *    p <pipelineid> action flow <flowid> policer <policerid> g <gaction> y <yaction> r <raction>
- *  <action> is one of the following:
- *      G = recolor to green
- *      Y = recolor as yellow
- *      R = recolor as red
- *      D = drop
- *
- *    p <pipelineid> action flow <flowid> port <port ID>
- *
- *    p <pipelineid> action flow bulk <file>
- *
- * flow policer stats read:
- *    p <pipelineid> action flow <flowid> stats
- *
- * flow ls:
- *    p <pipelineid> action flow ls
- *
- * dscp table configuration:
- *    p <pipelineid> action dscp <dscpid> class <class ID> color <color>
- *
- * dscp table ls:
- *    p <pipelineid> action dscp ls
-**/
-
-struct cmd_action_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t action_string;
-	cmdline_multi_string_t multi_string;
-};
-
-static void
-cmd_action_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	void *data)
-{
-	struct cmd_action_result *params = parsed_result;
-	struct app_params *app = data;
-
-	char *tokens[16];
-	uint32_t n_tokens = RTE_DIM(tokens);
-	int status;
-
-	status = parse_tokenize_string(params->multi_string, tokens, &n_tokens);
-	if (status != 0) {
-		printf(CMD_MSG_TOO_MANY_ARGS, "action");
-		return;
-	}
-
-	/* action flow meter */
-	if ((n_tokens >= 3) &&
-		(strcmp(tokens[0], "flow") == 0) &&
-		strcmp(tokens[1], "bulk") &&
-		strcmp(tokens[1], "ls") &&
-		(strcmp(tokens[2], "meter") == 0)) {
-		struct pipeline_fa_flow_params flow_params;
-		uint32_t flow_id, meter_id;
-
-		if (n_tokens != 9) {
-			printf(CMD_MSG_MISMATCH_ARGS, "action flow meter");
-			return;
-		}
-
-		memset(&flow_params, 0, sizeof(flow_params));
-
-		if (parser_read_uint32(&flow_id, tokens[1])) {
-			printf(CMD_MSG_INVALID_ARG, "flowid");
-			return;
-		}
-
-		if (parser_read_uint32(&meter_id, tokens[3]) ||
-			(meter_id >= PIPELINE_FA_N_TC_MAX)) {
-			printf(CMD_MSG_INVALID_ARG, "meterid");
-			return;
-		}
-
-		if (strcmp(tokens[4], "trtcm")) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "trtcm");
-			return;
-		}
-
-		if (parser_read_uint64(&flow_params.m[meter_id].cir, tokens[5])) {
-			printf(CMD_MSG_INVALID_ARG, "cir");
-			return;
-		}
-
-		if (parser_read_uint64(&flow_params.m[meter_id].pir, tokens[6])) {
-			printf(CMD_MSG_INVALID_ARG, "pir");
-			return;
-		}
-
-		if (parser_read_uint64(&flow_params.m[meter_id].cbs, tokens[7])) {
-			printf(CMD_MSG_INVALID_ARG, "cbs");
-			return;
-		}
-
-		if (parser_read_uint64(&flow_params.m[meter_id].pbs, tokens[8])) {
-			printf(CMD_MSG_INVALID_ARG, "pbs");
-			return;
-		}
-
-		status = app_pipeline_fa_flow_config(app,
-			params->pipeline_id,
-			flow_id,
-			1 << meter_id,
-			0,
-			0,
-			&flow_params);
-		if (status)
-			printf(CMD_MSG_FAIL, "action flow meter");
-
-		return;
-	} /* action flow meter */
-
-	/* action flow policer */
-	if ((n_tokens >= 3) &&
-		(strcmp(tokens[0], "flow") == 0) &&
-		strcmp(tokens[1], "bulk") &&
-		strcmp(tokens[1], "ls") &&
-		(strcmp(tokens[2], "policer") == 0)) {
-		struct pipeline_fa_flow_params flow_params;
-		uint32_t flow_id, policer_id;
-
-		if (n_tokens != 10) {
-			printf(CMD_MSG_MISMATCH_ARGS, "action flow policer");
-			return;
-		}
-
-		memset(&flow_params, 0, sizeof(flow_params));
-
-		if (parser_read_uint32(&flow_id, tokens[1])) {
-			printf(CMD_MSG_INVALID_ARG, "flowid");
-			return;
-		}
-
-		if (parser_read_uint32(&policer_id, tokens[3]) ||
-			(policer_id >= PIPELINE_FA_N_TC_MAX)) {
-			printf(CMD_MSG_INVALID_ARG, "policerid");
-			return;
-		}
-
-		if (strcmp(tokens[4], "g")) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "g");
-			return;
-		}
-
-		if (string_to_policer_action(tokens[5],
-			&flow_params.p[policer_id].action[e_RTE_METER_GREEN])) {
-			printf(CMD_MSG_INVALID_ARG, "gaction");
-			return;
-		}
-
-		if (strcmp(tokens[6], "y")) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "y");
-			return;
-		}
-
-		if (string_to_policer_action(tokens[7],
-			&flow_params.p[policer_id].action[e_RTE_METER_YELLOW])) {
-			printf(CMD_MSG_INVALID_ARG, "yaction");
-			return;
-		}
-
-		if (strcmp(tokens[8], "r")) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "r");
-			return;
-		}
-
-		if (string_to_policer_action(tokens[9],
-			&flow_params.p[policer_id].action[e_RTE_METER_RED])) {
-			printf(CMD_MSG_INVALID_ARG, "raction");
-			return;
-		}
-
-		status = app_pipeline_fa_flow_config(app,
-			params->pipeline_id,
-			flow_id,
-			0,
-			1 << policer_id,
-			0,
-			&flow_params);
-		if (status != 0)
-			printf(CMD_MSG_FAIL, "action flow policer");
-
-		return;
-	} /* action flow policer */
-
-	/* action flow port */
-	if ((n_tokens >= 3) &&
-		(strcmp(tokens[0], "flow") == 0) &&
-		strcmp(tokens[1], "bulk") &&
-		strcmp(tokens[1], "ls") &&
-		(strcmp(tokens[2], "port") == 0)) {
-		struct pipeline_fa_flow_params flow_params;
-		uint32_t flow_id, port_id;
-
-		if (n_tokens != 4) {
-			printf(CMD_MSG_MISMATCH_ARGS, "action flow port");
-			return;
-		}
-
-		memset(&flow_params, 0, sizeof(flow_params));
-
-		if (parser_read_uint32(&flow_id, tokens[1])) {
-			printf(CMD_MSG_INVALID_ARG, "flowid");
-			return;
-		}
-
-		if (parser_read_uint32(&port_id, tokens[3])) {
-			printf(CMD_MSG_INVALID_ARG, "portid");
-			return;
-		}
-
-		flow_params.port_id = port_id;
-
-		status = app_pipeline_fa_flow_config(app,
-			params->pipeline_id,
-			flow_id,
-			0,
-			0,
-			1,
-			&flow_params);
-		if (status)
-			printf(CMD_MSG_FAIL, "action flow port");
-
-		return;
-	} /* action flow port */
-
-	/* action flow stats */
-	if ((n_tokens >= 3) &&
-		(strcmp(tokens[0], "flow") == 0) &&
-		strcmp(tokens[1], "bulk") &&
-		strcmp(tokens[1], "ls") &&
-		(strcmp(tokens[2], "stats") == 0)) {
-		struct pipeline_fa_policer_stats stats;
-		uint32_t flow_id, policer_id;
-
-		if (n_tokens != 3) {
-			printf(CMD_MSG_MISMATCH_ARGS, "action flow stats");
-			return;
-		}
-
-		if (parser_read_uint32(&flow_id, tokens[1])) {
-			printf(CMD_MSG_INVALID_ARG, "flowid");
-			return;
-		}
-
-		for (policer_id = 0;
-			policer_id < PIPELINE_FA_N_TC_MAX;
-			policer_id++) {
-			status = app_pipeline_fa_flow_policer_stats_read(app,
-				params->pipeline_id,
-				flow_id,
-				policer_id,
-				1,
-				&stats);
-			if (status != 0) {
-				printf(CMD_MSG_FAIL, "action flow stats");
-				return;
-			}
-
-			/* Display stats */
-			printf("\tPolicer: %" PRIu32
-				"\tPkts G: %" PRIu64
-				"\tPkts Y: %" PRIu64
-				"\tPkts R: %" PRIu64
-				"\tPkts D: %" PRIu64 "\n",
-				policer_id,
-				stats.n_pkts[e_RTE_METER_GREEN],
-				stats.n_pkts[e_RTE_METER_YELLOW],
-				stats.n_pkts[e_RTE_METER_RED],
-				stats.n_pkts_drop);
-		}
-
-		return;
-	} /* action flow stats */
-
-	/* action flow bulk */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "flow") == 0) &&
-		(strcmp(tokens[1], "bulk") == 0)) {
-		struct pipeline_fa_flow_params *flow_params;
-		uint32_t *flow_ids, n_flows, line;
-		char *filename;
-
-		if (n_tokens != 3) {
-			printf(CMD_MSG_MISMATCH_ARGS, "action flow bulk");
-			return;
-		}
-
-		filename = tokens[2];
-
-		n_flows = APP_PIPELINE_FA_MAX_RECORDS_IN_FILE;
-		flow_ids = malloc(n_flows * sizeof(uint32_t));
-		if (flow_ids == NULL) {
-			printf(CMD_MSG_OUT_OF_MEMORY);
-			return;
-		}
-
-		flow_params = malloc(n_flows * sizeof(struct pipeline_fa_flow_params));
-		if (flow_params == NULL) {
-			printf(CMD_MSG_OUT_OF_MEMORY);
-			free(flow_ids);
-			return;
-		}
-
-		status = app_pipeline_fa_load_file(filename,
-			flow_ids,
-			flow_params,
-			&n_flows,
-			&line);
-		if (status) {
-			printf(CMD_MSG_FILE_ERR, filename, line);
-			free(flow_params);
-			free(flow_ids);
-			return;
-		}
-
-		status = app_pipeline_fa_flow_config_bulk(app,
-			params->pipeline_id,
-			flow_ids,
-			n_flows,
-			0xF,
-			0xF,
-			1,
-			flow_params);
-		if (status)
-			printf(CMD_MSG_FAIL, "action flow bulk");
-
-		free(flow_params);
-		free(flow_ids);
-		return;
-	} /* action flow bulk */
-
-	/* action flow ls */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "flow") == 0) &&
-		(strcmp(tokens[1], "ls") == 0)) {
-		if (n_tokens != 2) {
-			printf(CMD_MSG_MISMATCH_ARGS, "action flow ls");
-			return;
-		}
-
-		status = app_pipeline_fa_flow_ls(app,
-			params->pipeline_id);
-		if (status)
-			printf(CMD_MSG_FAIL, "action flow ls");
-
-		return;
-	} /* action flow ls */
-
-	/* action dscp */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "dscp") == 0) &&
-		strcmp(tokens[1], "ls")) {
-		uint32_t dscp_id, tc_id;
-		enum rte_meter_color color;
-
-		if (n_tokens != 6) {
-			printf(CMD_MSG_MISMATCH_ARGS, "action dscp");
-			return;
-		}
-
-		if (parser_read_uint32(&dscp_id, tokens[1])) {
-			printf(CMD_MSG_INVALID_ARG, "dscpid");
-			return;
-		}
-
-		if (strcmp(tokens[2], "class")) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "class");
-			return;
-		}
-
-		if (parser_read_uint32(&tc_id, tokens[3])) {
-			printf(CMD_MSG_INVALID_ARG, "classid");
-			return;
-		}
-
-		if (strcmp(tokens[4], "color")) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "color");
-			return;
-		}
-
-		if (string_to_color(tokens[5], &color)) {
-			printf(CMD_MSG_INVALID_ARG, "colorid");
-			return;
-		}
-
-		status = app_pipeline_fa_dscp_config(app,
-			params->pipeline_id,
-			dscp_id,
-			tc_id,
-			color);
-		if (status != 0)
-			printf(CMD_MSG_FAIL, "action dscp");
-
-		return;
-	} /* action dscp */
-
-	/* action dscp ls */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "dscp") == 0) &&
-		(strcmp(tokens[1], "ls") == 0)) {
-		if (n_tokens != 2) {
-			printf(CMD_MSG_MISMATCH_ARGS, "action dscp ls");
-			return;
-		}
-
-		status = app_pipeline_fa_dscp_ls(app,
-			params->pipeline_id);
-		if (status)
-			printf(CMD_MSG_FAIL, "action dscp ls");
-
-		return;
-	} /* action dscp ls */
-
-	printf(CMD_MSG_FAIL, "action");
-}
-
-static cmdline_parse_token_string_t cmd_action_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_action_result, p_string, "p");
-
-static cmdline_parse_token_num_t cmd_action_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_action_result, pipeline_id, UINT32);
-
-static cmdline_parse_token_string_t cmd_action_action_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_action_result, action_string, "action");
-
-static cmdline_parse_token_string_t cmd_action_multi_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_action_result, multi_string,
-	TOKEN_STRING_MULTI);
-
-cmdline_parse_inst_t cmd_action = {
-	.f = cmd_action_parsed,
-	.data = NULL,
-	.help_str = "flow actions (meter, policer, policer stats, dscp table)",
-	.tokens = {
-		(void *) &cmd_action_p_string,
-		(void *) &cmd_action_pipeline_id,
-		(void *) &cmd_action_action_string,
-		(void *) &cmd_action_multi_string,
-		NULL,
-	},
-};
-
-static cmdline_parse_ctx_t pipeline_cmds[] = {
-	(cmdline_parse_inst_t *) &cmd_action,
-	NULL,
-};
-
-static struct pipeline_fe_ops pipeline_flow_actions_fe_ops = {
-	.f_init = app_pipeline_fa_init,
-	.f_post_init = NULL,
-	.f_free = app_pipeline_fa_free,
-	.f_track = app_pipeline_track_default,
-	.cmds = pipeline_cmds,
-};
-
-struct pipeline_type pipeline_flow_actions = {
-	.name = "FLOW_ACTIONS",
-	.be_ops = &pipeline_flow_actions_be_ops,
-	.fe_ops = &pipeline_flow_actions_fe_ops,
-};
diff --git a/examples/ip_pipeline/pipeline/pipeline_flow_actions.h b/examples/ip_pipeline/pipeline/pipeline_flow_actions.h
deleted file mode 100644
index 885923e..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_flow_actions.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#ifndef __INCLUDE_PIPELINE_FLOW_ACTIONS_H__
-#define __INCLUDE_PIPELINE_FLOW_ACTIONS_H__
-
-#include <rte_meter.h>
-
-#include "pipeline.h"
-#include "pipeline_flow_actions_be.h"
-
-int
-app_pipeline_fa_flow_config(struct app_params *app,
-	uint32_t pipeline_id,
-	uint32_t flow_id,
-	uint32_t meter_update_mask,
-	uint32_t policer_update_mask,
-	uint32_t port_update,
-	struct pipeline_fa_flow_params *params);
-
-int
-app_pipeline_fa_flow_config_bulk(struct app_params *app,
-	uint32_t pipeline_id,
-	uint32_t *flow_id,
-	uint32_t n_flows,
-	uint32_t meter_update_mask,
-	uint32_t policer_update_mask,
-	uint32_t port_update,
-	struct pipeline_fa_flow_params *params);
-
-int
-app_pipeline_fa_dscp_config(struct app_params *app,
-	uint32_t pipeline_id,
-	uint32_t dscp,
-	uint32_t traffic_class,
-	enum rte_meter_color color);
-
-int
-app_pipeline_fa_flow_policer_stats_read(struct app_params *app,
-	uint32_t pipeline_id,
-	uint32_t flow_id,
-	uint32_t policer_id,
-	int clear,
-	struct pipeline_fa_policer_stats *stats);
-
-#ifndef APP_PIPELINE_FA_MAX_RECORDS_IN_FILE
-#define APP_PIPELINE_FA_MAX_RECORDS_IN_FILE		65536
-#endif
-
-int
-app_pipeline_fa_load_file(char *filename,
-	uint32_t *flow_ids,
-	struct pipeline_fa_flow_params *p,
-	uint32_t *n_flows,
-	uint32_t *line);
-
-extern struct pipeline_type pipeline_flow_actions;
-
-#endif
diff --git a/examples/ip_pipeline/pipeline/pipeline_flow_actions_be.c b/examples/ip_pipeline/pipeline/pipeline_flow_actions_be.c
deleted file mode 100644
index 33f1c41..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_flow_actions_be.c
+++ /dev/null
@@ -1,983 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2016 Intel Corporation
- */
-
-#include <string.h>
-
-#include <rte_common.h>
-#include <rte_malloc.h>
-#include <rte_cycles.h>
-#include <rte_table_array.h>
-#include <rte_byteorder.h>
-#include <rte_ip.h>
-
-#include "pipeline_actions_common.h"
-#include "pipeline_flow_actions_be.h"
-#include "parser.h"
-#include "hash_func.h"
-
-int
-pipeline_fa_flow_params_set_default(struct pipeline_fa_flow_params *params)
-{
-	uint32_t i;
-
-	if (params == NULL)
-		return -1;
-
-	for (i = 0; i < PIPELINE_FA_N_TC_MAX; i++) {
-		struct rte_meter_trtcm_params *m = &params->m[i];
-
-		m->cir = 1;
-		m->cbs = 1;
-		m->pir = 1;
-		m->pbs = 2;
-	}
-
-	for (i = 0; i < PIPELINE_FA_N_TC_MAX; i++) {
-		struct pipeline_fa_policer_params *p = &params->p[i];
-		uint32_t j;
-
-		for (j = 0; j < e_RTE_METER_COLORS; j++) {
-			struct pipeline_fa_policer_action *a = &p->action[j];
-
-			a->drop = 0;
-			a->color = (enum rte_meter_color) j;
-		}
-	}
-
-	params->port_id = 0;
-
-	return 0;
-}
-
-struct dscp_entry {
-	uint32_t traffic_class;
-	enum rte_meter_color color;
-};
-
-struct pipeline_flow_actions {
-	struct pipeline p;
-	struct pipeline_fa_params params;
-	pipeline_msg_req_handler custom_handlers[PIPELINE_FA_MSG_REQS];
-
-	struct dscp_entry dscp[PIPELINE_FA_N_DSCP];
-} __rte_cache_aligned;
-
-static void *
-pipeline_fa_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_fa_msg_req_custom_handler,
-};
-
-static void *
-pipeline_fa_msg_req_flow_config_handler(struct pipeline *p, void *msg);
-
-static void *
-pipeline_fa_msg_req_flow_config_bulk_handler(struct pipeline *p, void *msg);
-
-static void *
-pipeline_fa_msg_req_dscp_config_handler(struct pipeline *p, void *msg);
-
-static void *
-pipeline_fa_msg_req_policer_stats_read_handler(struct pipeline *p, void *msg);
-
-static pipeline_msg_req_handler custom_handlers[] = {
-	[PIPELINE_FA_MSG_REQ_FLOW_CONFIG] =
-		pipeline_fa_msg_req_flow_config_handler,
-	[PIPELINE_FA_MSG_REQ_FLOW_CONFIG_BULK] =
-		pipeline_fa_msg_req_flow_config_bulk_handler,
-	[PIPELINE_FA_MSG_REQ_DSCP_CONFIG] =
-		pipeline_fa_msg_req_dscp_config_handler,
-	[PIPELINE_FA_MSG_REQ_POLICER_STATS_READ] =
-		pipeline_fa_msg_req_policer_stats_read_handler,
-};
-
-/*
- * Flow table
- */
-struct meter_policer {
-	struct rte_meter_trtcm meter;
-	struct rte_meter_trtcm_profile meter_profile;
-	struct pipeline_fa_policer_params policer;
-	struct pipeline_fa_policer_stats stats;
-};
-
-struct flow_table_entry {
-	struct rte_pipeline_table_entry head;
-	struct meter_policer mp[PIPELINE_FA_N_TC_MAX];
-};
-
-static int
-flow_table_entry_set_meter(struct flow_table_entry *entry,
-	uint32_t meter_id,
-	struct pipeline_fa_flow_params *params)
-{
-	struct rte_meter_trtcm *meter = &entry->mp[meter_id].meter;
-	struct rte_meter_trtcm_params *meter_params = &params->m[meter_id];
-	struct rte_meter_trtcm_profile *meter_profile =
-					&entry->mp[meter_id].meter_profile;
-	int status;
-
-	status = rte_meter_trtcm_profile_config(meter_profile, meter_params);
-	if (status)
-		return status;
-
-	return rte_meter_trtcm_config(meter, meter_profile);
-}
-
-static void
-flow_table_entry_set_policer(struct flow_table_entry *entry,
-	uint32_t policer_id,
-	struct pipeline_fa_flow_params *params)
-{
-	struct pipeline_fa_policer_params *p0 = &entry->mp[policer_id].policer;
-	struct pipeline_fa_policer_params *p1 = &params->p[policer_id];
-
-	memcpy(p0, p1, sizeof(*p0));
-}
-
-static void
-flow_table_entry_set_port_id(struct pipeline_flow_actions *p,
-	struct flow_table_entry *entry,
-	struct pipeline_fa_flow_params *params)
-{
-	entry->head.action = RTE_PIPELINE_ACTION_PORT;
-	entry->head.port_id = p->p.port_out_id[params->port_id];
-}
-
-static int
-flow_table_entry_set_default(struct pipeline_flow_actions *p,
-	struct flow_table_entry *entry)
-{
-	struct pipeline_fa_flow_params params;
-	uint32_t i;
-
-	pipeline_fa_flow_params_set_default(&params);
-
-	memset(entry, 0, sizeof(*entry));
-
-	flow_table_entry_set_port_id(p, entry, &params);
-
-	for (i = 0; i < PIPELINE_FA_N_TC_MAX; i++) {
-		int status;
-
-		status = flow_table_entry_set_meter(entry, i, &params);
-		if (status)
-			return status;
-	}
-
-	for (i = 0; i < PIPELINE_FA_N_TC_MAX; i++)
-		flow_table_entry_set_policer(entry, i, &params);
-
-	return 0;
-}
-
-static inline uint64_t
-pkt_work(
-	struct rte_mbuf *pkt,
-	struct rte_pipeline_table_entry *table_entry,
-	void *arg,
-	uint64_t time)
-{
-	struct pipeline_flow_actions *p = arg;
-	struct flow_table_entry *entry =
-		(struct flow_table_entry *) table_entry;
-
-	struct ipv4_hdr *pkt_ip = (struct ipv4_hdr *)
-		RTE_MBUF_METADATA_UINT32_PTR(pkt, p->params.ip_hdr_offset);
-	enum rte_meter_color *pkt_color = (enum rte_meter_color *)
-		RTE_MBUF_METADATA_UINT32_PTR(pkt, p->params.color_offset);
-
-	/* Read (IP header) */
-	uint32_t total_length = rte_bswap16(pkt_ip->total_length);
-	uint32_t dscp = pkt_ip->type_of_service >> 2;
-
-	uint32_t tc = p->dscp[dscp].traffic_class;
-	enum rte_meter_color color = p->dscp[dscp].color;
-
-	struct rte_meter_trtcm *meter = &entry->mp[tc].meter;
-	struct rte_meter_trtcm_profile *meter_profile =
-					&entry->mp[tc].meter_profile;
-	struct pipeline_fa_policer_params *policer = &entry->mp[tc].policer;
-	struct pipeline_fa_policer_stats *stats = &entry->mp[tc].stats;
-
-	/* Read (entry), compute */
-	enum rte_meter_color color2 = rte_meter_trtcm_color_aware_check(meter,
-		meter_profile,
-		time,
-		total_length,
-		color);
-
-	enum rte_meter_color color3 = policer->action[color2].color;
-	uint64_t drop = policer->action[color2].drop;
-
-	/* Read (entry), write (entry, color) */
-	stats->n_pkts[color3] += drop ^ 1LLU;
-	stats->n_pkts_drop += drop;
-	*pkt_color = color3;
-
-	return drop;
-}
-
-static inline uint64_t
-pkt4_work(
-	struct rte_mbuf **pkts,
-	struct rte_pipeline_table_entry **table_entries,
-	void *arg,
-	uint64_t time)
-{
-	struct pipeline_flow_actions *p = arg;
-
-	struct flow_table_entry *entry0 =
-		(struct flow_table_entry *) table_entries[0];
-	struct flow_table_entry *entry1 =
-		(struct flow_table_entry *) table_entries[1];
-	struct flow_table_entry *entry2 =
-		(struct flow_table_entry *) table_entries[2];
-	struct flow_table_entry *entry3 =
-		(struct flow_table_entry *) table_entries[3];
-
-	struct ipv4_hdr *pkt0_ip = (struct ipv4_hdr *)
-		RTE_MBUF_METADATA_UINT32_PTR(pkts[0], p->params.ip_hdr_offset);
-	struct ipv4_hdr *pkt1_ip = (struct ipv4_hdr *)
-		RTE_MBUF_METADATA_UINT32_PTR(pkts[1], p->params.ip_hdr_offset);
-	struct ipv4_hdr *pkt2_ip = (struct ipv4_hdr *)
-		RTE_MBUF_METADATA_UINT32_PTR(pkts[2], p->params.ip_hdr_offset);
-	struct ipv4_hdr *pkt3_ip = (struct ipv4_hdr *)
-		RTE_MBUF_METADATA_UINT32_PTR(pkts[3], p->params.ip_hdr_offset);
-
-	enum rte_meter_color *pkt0_color = (enum rte_meter_color *)
-		RTE_MBUF_METADATA_UINT32_PTR(pkts[0], p->params.color_offset);
-	enum rte_meter_color *pkt1_color = (enum rte_meter_color *)
-		RTE_MBUF_METADATA_UINT32_PTR(pkts[1], p->params.color_offset);
-	enum rte_meter_color *pkt2_color = (enum rte_meter_color *)
-		RTE_MBUF_METADATA_UINT32_PTR(pkts[2], p->params.color_offset);
-	enum rte_meter_color *pkt3_color = (enum rte_meter_color *)
-		RTE_MBUF_METADATA_UINT32_PTR(pkts[3], p->params.color_offset);
-
-	/* Read (IP header) */
-	uint32_t total_length0 = rte_bswap16(pkt0_ip->total_length);
-	uint32_t dscp0 = pkt0_ip->type_of_service >> 2;
-
-	uint32_t total_length1 = rte_bswap16(pkt1_ip->total_length);
-	uint32_t dscp1 = pkt1_ip->type_of_service >> 2;
-
-	uint32_t total_length2 = rte_bswap16(pkt2_ip->total_length);
-	uint32_t dscp2 = pkt2_ip->type_of_service >> 2;
-
-	uint32_t total_length3 = rte_bswap16(pkt3_ip->total_length);
-	uint32_t dscp3 = pkt3_ip->type_of_service >> 2;
-
-	uint32_t tc0 = p->dscp[dscp0].traffic_class;
-	enum rte_meter_color color0 = p->dscp[dscp0].color;
-
-	uint32_t tc1 = p->dscp[dscp1].traffic_class;
-	enum rte_meter_color color1 = p->dscp[dscp1].color;
-
-	uint32_t tc2 = p->dscp[dscp2].traffic_class;
-	enum rte_meter_color color2 = p->dscp[dscp2].color;
-
-	uint32_t tc3 = p->dscp[dscp3].traffic_class;
-	enum rte_meter_color color3 = p->dscp[dscp3].color;
-
-	struct rte_meter_trtcm *meter0 = &entry0->mp[tc0].meter;
-	struct rte_meter_trtcm_profile *meter0_profile =
-				&entry0->mp[tc0].meter_profile;
-	struct pipeline_fa_policer_params *policer0 = &entry0->mp[tc0].policer;
-	struct pipeline_fa_policer_stats *stats0 = &entry0->mp[tc0].stats;
-
-	struct rte_meter_trtcm *meter1 = &entry1->mp[tc1].meter;
-	struct rte_meter_trtcm_profile *meter1_profile =
-				&entry1->mp[tc1].meter_profile;
-	struct pipeline_fa_policer_params *policer1 = &entry1->mp[tc1].policer;
-	struct pipeline_fa_policer_stats *stats1 = &entry1->mp[tc1].stats;
-
-	struct rte_meter_trtcm *meter2 = &entry2->mp[tc2].meter;
-	struct rte_meter_trtcm_profile *meter2_profile =
-				&entry2->mp[tc2].meter_profile;
-	struct pipeline_fa_policer_params *policer2 = &entry2->mp[tc2].policer;
-	struct pipeline_fa_policer_stats *stats2 = &entry2->mp[tc2].stats;
-
-	struct rte_meter_trtcm *meter3 = &entry3->mp[tc3].meter;
-	struct rte_meter_trtcm_profile *meter3_profile =
-				&entry3->mp[tc3].meter_profile;
-	struct pipeline_fa_policer_params *policer3 = &entry3->mp[tc3].policer;
-	struct pipeline_fa_policer_stats *stats3 = &entry3->mp[tc3].stats;
-
-	/* Read (entry), compute, write (entry) */
-	enum rte_meter_color color2_0 = rte_meter_trtcm_color_aware_check(
-		meter0,
-		meter0_profile,
-		time,
-		total_length0,
-		color0);
-
-	enum rte_meter_color color2_1 = rte_meter_trtcm_color_aware_check(
-		meter1,
-		meter1_profile,
-		time,
-		total_length1,
-		color1);
-
-	enum rte_meter_color color2_2 = rte_meter_trtcm_color_aware_check(
-		meter2,
-		meter2_profile,
-		time,
-		total_length2,
-		color2);
-
-	enum rte_meter_color color2_3 = rte_meter_trtcm_color_aware_check(
-		meter3,
-		meter3_profile,
-		time,
-		total_length3,
-		color3);
-
-	enum rte_meter_color color3_0 = policer0->action[color2_0].color;
-	enum rte_meter_color color3_1 = policer1->action[color2_1].color;
-	enum rte_meter_color color3_2 = policer2->action[color2_2].color;
-	enum rte_meter_color color3_3 = policer3->action[color2_3].color;
-
-	uint64_t drop0 = policer0->action[color2_0].drop;
-	uint64_t drop1 = policer1->action[color2_1].drop;
-	uint64_t drop2 = policer2->action[color2_2].drop;
-	uint64_t drop3 = policer3->action[color2_3].drop;
-
-	/* Read (entry), write (entry, color) */
-	stats0->n_pkts[color3_0] += drop0 ^ 1LLU;
-	stats0->n_pkts_drop += drop0;
-
-	stats1->n_pkts[color3_1] += drop1 ^ 1LLU;
-	stats1->n_pkts_drop += drop1;
-
-	stats2->n_pkts[color3_2] += drop2 ^ 1LLU;
-	stats2->n_pkts_drop += drop2;
-
-	stats3->n_pkts[color3_3] += drop3 ^ 1LLU;
-	stats3->n_pkts_drop += drop3;
-
-	*pkt0_color = color3_0;
-	*pkt1_color = color3_1;
-	*pkt2_color = color3_2;
-	*pkt3_color = color3_3;
-
-	return drop0 | (drop1 << 1) | (drop2 << 2) | (drop3 << 3);
-}
-
-PIPELINE_TABLE_AH_HIT_DROP_TIME(fa_table_ah_hit, pkt_work, pkt4_work);
-
-static rte_pipeline_table_action_handler_hit
-get_fa_table_ah_hit(__rte_unused struct pipeline_flow_actions *p)
-{
-	return fa_table_ah_hit;
-}
-
-/*
- * Argument parsing
- */
-int
-pipeline_fa_parse_args(struct pipeline_fa_params *p,
-	struct pipeline_params *params)
-{
-	uint32_t n_flows_present = 0;
-	uint32_t n_meters_per_flow_present = 0;
-	uint32_t flow_id_offset_present = 0;
-	uint32_t ip_hdr_offset_present = 0;
-	uint32_t color_offset_present = 0;
-	uint32_t i;
-
-	/* Default values */
-	p->n_meters_per_flow = 1;
-	p->dscp_enabled = 0;
-
-	for (i = 0; i < params->n_args; i++) {
-		char *arg_name = params->args_name[i];
-		char *arg_value = params->args_value[i];
-
-		/* n_flows */
-		if (strcmp(arg_name, "n_flows") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				n_flows_present == 0, params->name,
-				arg_name);
-			n_flows_present = 1;
-
-			status = parser_read_uint32(&p->n_flows,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL(((status != -EINVAL) &&
-				(p->n_flows != 0)), params->name,
-				arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			continue;
-		}
-
-		/* n_meters_per_flow */
-		if (strcmp(arg_name, "n_meters_per_flow") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				n_meters_per_flow_present == 0,
-				params->name, arg_name);
-			n_meters_per_flow_present = 1;
-
-			status = parser_read_uint32(&p->n_meters_per_flow,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL(((status != -EINVAL) &&
-				(p->n_meters_per_flow != 0)),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG(((status != -ERANGE) &&
-				(p->n_meters_per_flow <=
-				PIPELINE_FA_N_TC_MAX)), params->name,
-				arg_name, arg_value);
-
-			continue;
-		}
-
-		/* flow_id_offset */
-		if (strcmp(arg_name, "flow_id_offset") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				flow_id_offset_present == 0,
-				params->name, arg_name);
-			flow_id_offset_present = 1;
-
-			status = parser_read_uint32(&p->flow_id_offset,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			continue;
-		}
-
-		/* ip_hdr_offset */
-		if (strcmp(arg_name, "ip_hdr_offset") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				ip_hdr_offset_present == 0,
-				params->name, arg_name);
-			ip_hdr_offset_present = 1;
-
-			status = parser_read_uint32(&p->ip_hdr_offset,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			continue;
-		}
-
-		/* color_offset */
-		if (strcmp(arg_name, "color_offset") == 0) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				color_offset_present == 0, params->name,
-				arg_name);
-			color_offset_present = 1;
-
-			status = parser_read_uint32(&p->color_offset,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-
-			p->dscp_enabled = 1;
-
-			continue;
-		}
-
-		/* Unknown argument */
-		PIPELINE_PARSE_ERR_INV_ENT(0, params->name, arg_name);
-	}
-
-	/* Check that mandatory arguments are present */
-	PIPELINE_PARSE_ERR_MANDATORY((n_flows_present), params->name,
-		"n_flows");
-	PIPELINE_PARSE_ERR_MANDATORY((flow_id_offset_present),
-		params->name, "flow_id_offset");
-	PIPELINE_PARSE_ERR_MANDATORY((ip_hdr_offset_present),
-		params->name, "ip_hdr_offset");
-	PIPELINE_PARSE_ERR_MANDATORY((color_offset_present), params->name,
-		"color_offset");
-
-	return 0;
-}
-
-static void
-dscp_init(struct pipeline_flow_actions *p)
-{
-	uint32_t i;
-
-	for (i = 0; i < PIPELINE_FA_N_DSCP; i++) {
-		p->dscp[i].traffic_class = 0;
-		p->dscp[i].color = e_RTE_METER_GREEN;
-	}
-}
-
-static void *pipeline_fa_init(struct pipeline_params *params,
-	__rte_unused void *arg)
-{
-	struct pipeline *p;
-	struct pipeline_flow_actions *p_fa;
-	uint32_t size, i;
-
-	/* Check input arguments */
-	if (params == NULL)
-		return NULL;
-
-	if (params->n_ports_in != params->n_ports_out)
-		return NULL;
-
-	/* Memory allocation */
-	size = RTE_CACHE_LINE_ROUNDUP(
-		sizeof(struct pipeline_flow_actions));
-	p = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
-	if (p == NULL)
-		return NULL;
-	p_fa = (struct pipeline_flow_actions *) p;
-
-	strcpy(p->name, params->name);
-	p->log_level = params->log_level;
-
-	PLOG(p, HIGH, "Flow actions");
-
-	/* Parse arguments */
-	if (pipeline_fa_parse_args(&p_fa->params, params))
-		return NULL;
-
-	dscp_init(p_fa);
-
-	/* 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,
-			.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_array_params table_array_params = {
-			.n_entries = p_fa->params.n_flows,
-			.offset = p_fa->params.flow_id_offset,
-		};
-
-		struct rte_pipeline_table_params table_params = {
-			.ops = &rte_table_array_ops,
-			.arg_create = &table_array_params,
-			.f_action_hit = get_fa_table_ah_hit(p_fa),
-			.f_action_miss = NULL,
-			.arg_ah = p_fa,
-			.action_data_size =
-				sizeof(struct flow_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;
-		}
-	}
-
-	/* 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;
-		}
-	}
-
-	/* Initialize table entries */
-	for (i = 0; i < p_fa->params.n_flows; i++) {
-		struct rte_table_array_key key = {
-			.pos = i,
-		};
-
-		struct flow_table_entry entry;
-		struct rte_pipeline_table_entry *entry_ptr;
-		int key_found, status;
-
-		flow_table_entry_set_default(p_fa, &entry);
-
-		status = rte_pipeline_table_entry_add(p->p,
-			p->table_id[0],
-			&key,
-			(struct rte_pipeline_table_entry *) &entry,
-			&key_found,
-			&entry_ptr);
-
-		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_fa->custom_handlers,
-		custom_handlers,
-		sizeof(p_fa->custom_handlers));
-
-	return p;
-}
-
-static int
-pipeline_fa_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_fa_timer(void *pipeline)
-{
-	struct pipeline *p = (struct pipeline *) pipeline;
-
-	pipeline_msg_req_handle(p);
-	rte_pipeline_flush(p->p);
-
-	return 0;
-}
-
-void *
-pipeline_fa_msg_req_custom_handler(struct pipeline *p, void *msg)
-{
-	struct pipeline_flow_actions *p_fa =
-			(struct pipeline_flow_actions *) p;
-	struct pipeline_custom_msg_req *req = msg;
-	pipeline_msg_req_handler f_handle;
-
-	f_handle = (req->subtype < PIPELINE_FA_MSG_REQS) ?
-		p_fa->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_fa_msg_req_flow_config_handler(struct pipeline *p, void *msg)
-{
-	struct pipeline_flow_actions *p_fa = (struct pipeline_flow_actions *) p;
-	struct pipeline_fa_flow_config_msg_req *req = msg;
-	struct pipeline_fa_flow_config_msg_rsp *rsp = msg;
-	struct flow_table_entry *entry;
-	uint32_t mask, i;
-
-	/* Set flow table entry to default if not configured before */
-	if (req->entry_ptr == NULL) {
-		struct rte_table_array_key key = {
-			.pos = req->flow_id % p_fa->params.n_flows,
-		};
-
-		struct flow_table_entry default_entry;
-
-		int key_found, status;
-
-		flow_table_entry_set_default(p_fa, &default_entry);
-
-		status = rte_pipeline_table_entry_add(p->p,
-			p->table_id[0],
-			&key,
-			(struct rte_pipeline_table_entry *) &default_entry,
-			&key_found,
-			(struct rte_pipeline_table_entry **) &entry);
-		if (status) {
-			rsp->status = -1;
-			return rsp;
-		}
-	} else
-		entry = (struct flow_table_entry *) req->entry_ptr;
-
-	/* Meter */
-	for (i = 0, mask = 1; i < PIPELINE_FA_N_TC_MAX; i++, mask <<= 1) {
-		int status;
-
-		if ((mask & req->meter_update_mask) == 0)
-			continue;
-
-		status = flow_table_entry_set_meter(entry, i, &req->params);
-		if (status) {
-			rsp->status = -1;
-			return rsp;
-		}
-	}
-
-	/* Policer */
-	for (i = 0, mask = 1; i < PIPELINE_FA_N_TC_MAX; i++, mask <<= 1) {
-		if ((mask & req->policer_update_mask) == 0)
-			continue;
-
-		flow_table_entry_set_policer(entry, i, &req->params);
-	}
-
-	/* Port */
-	if (req->port_update)
-		flow_table_entry_set_port_id(p_fa, entry, &req->params);
-
-	/* Response */
-	rsp->status = 0;
-	rsp->entry_ptr = (void *) entry;
-	return rsp;
-}
-
-void *
-pipeline_fa_msg_req_flow_config_bulk_handler(struct pipeline *p, void *msg)
-{
-	struct pipeline_flow_actions *p_fa = (struct pipeline_flow_actions *) p;
-	struct pipeline_fa_flow_config_bulk_msg_req *req = msg;
-	struct pipeline_fa_flow_config_bulk_msg_rsp *rsp = msg;
-	uint32_t i;
-
-	for (i = 0; i < req->n_flows; i++) {
-		struct flow_table_entry *entry;
-		uint32_t j, mask;
-
-		/* Set flow table entry to default if not configured before */
-		if (req->entry_ptr[i] == NULL) {
-			struct rte_table_array_key key = {
-				.pos = req->flow_id[i] % p_fa->params.n_flows,
-			};
-
-			struct flow_table_entry entry_to_add;
-
-			int key_found, status;
-
-			flow_table_entry_set_default(p_fa, &entry_to_add);
-
-			status = rte_pipeline_table_entry_add(p->p,
-			 p->table_id[0],
-			 &key,
-			 (struct rte_pipeline_table_entry *) &entry_to_add,
-			 &key_found,
-			 (struct rte_pipeline_table_entry **) &entry);
-			if (status) {
-				rsp->n_flows = i;
-				return rsp;
-			}
-
-			req->entry_ptr[i] = (void *) entry;
-		} else
-			entry = (struct flow_table_entry *) req->entry_ptr[i];
-
-		/* Meter */
-		for (j = 0, mask = 1;
-			j < PIPELINE_FA_N_TC_MAX;
-			j++, mask <<= 1) {
-			int status;
-
-			if ((mask & req->meter_update_mask) == 0)
-				continue;
-
-			status = flow_table_entry_set_meter(entry,
-				j, &req->params[i]);
-			if (status) {
-				rsp->n_flows = i;
-				return rsp;
-			}
-		}
-
-		/* Policer */
-		for (j = 0, mask = 1;
-			j < PIPELINE_FA_N_TC_MAX;
-			j++, mask <<= 1) {
-			if ((mask & req->policer_update_mask) == 0)
-				continue;
-
-			flow_table_entry_set_policer(entry,
-			 j, &req->params[i]);
-		}
-
-		/* Port */
-		if (req->port_update)
-			flow_table_entry_set_port_id(p_fa,
-			 entry, &req->params[i]);
-	}
-
-	/* Response */
-	rsp->n_flows = i;
-	return rsp;
-}
-
-void *
-pipeline_fa_msg_req_dscp_config_handler(struct pipeline *p, void *msg)
-{
-	struct pipeline_flow_actions *p_fa = (struct pipeline_flow_actions *) p;
-	struct pipeline_fa_dscp_config_msg_req *req = msg;
-	struct pipeline_fa_dscp_config_msg_rsp *rsp = msg;
-
-	/* Check request */
-	if ((req->dscp >= PIPELINE_FA_N_DSCP) ||
-		(req->traffic_class >= PIPELINE_FA_N_TC_MAX) ||
-		(req->color >= e_RTE_METER_COLORS)) {
-		rsp->status = -1;
-		return rsp;
-	}
-
-	p_fa->dscp[req->dscp].traffic_class = req->traffic_class;
-	p_fa->dscp[req->dscp].color = req->color;
-	rsp->status = 0;
-	return rsp;
-}
-
-void *
-pipeline_fa_msg_req_policer_stats_read_handler(__rte_unused struct pipeline *p,
-	void *msg)
-{
-	struct pipeline_fa_policer_stats_msg_req *req = msg;
-	struct pipeline_fa_policer_stats_msg_rsp *rsp = msg;
-
-	struct flow_table_entry *entry = req->entry_ptr;
-	uint32_t policer_id = req->policer_id;
-	int clear = req->clear;
-
-	/* Check request */
-	if ((req->entry_ptr == NULL) ||
-		(req->policer_id >= PIPELINE_FA_N_TC_MAX)) {
-		rsp->status = -1;
-		return rsp;
-	}
-
-	memcpy(&rsp->stats,
-		&entry->mp[policer_id].stats,
-		sizeof(rsp->stats));
-	if (clear)
-		memset(&entry->mp[policer_id].stats,
-			0, sizeof(entry->mp[policer_id].stats));
-	rsp->status = 0;
-	return rsp;
-}
-
-struct pipeline_be_ops pipeline_flow_actions_be_ops = {
-	.f_init = pipeline_fa_init,
-	.f_free = pipeline_fa_free,
-	.f_run = NULL,
-	.f_timer = pipeline_fa_timer,
-};
diff --git a/examples/ip_pipeline/pipeline/pipeline_flow_actions_be.h b/examples/ip_pipeline/pipeline/pipeline_flow_actions_be.h
deleted file mode 100644
index ef6cb26..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_flow_actions_be.h
+++ /dev/null
@@ -1,139 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#ifndef __INCLUDE_PIPELINE_FLOW_ACTIONS_BE_H__
-#define __INCLUDE_PIPELINE_FLOW_ACTIONS_BE_H__
-
-#include <rte_meter.h>
-
-#include "pipeline_common_be.h"
-
-#ifndef PIPELINE_FA_N_TC_MAX
-#define PIPELINE_FA_N_TC_MAX                               4
-#endif
-
-#define PIPELINE_FA_N_DSCP                                 64
-
-struct pipeline_fa_params {
-	uint32_t n_flows;
-	uint32_t n_meters_per_flow;
-	uint32_t flow_id_offset;
-	uint32_t ip_hdr_offset;
-	uint32_t color_offset;
-	uint32_t dscp_enabled;
-};
-
-int
-pipeline_fa_parse_args(struct pipeline_fa_params *p,
-	struct pipeline_params *params);
-
-struct pipeline_fa_policer_action {
-	uint32_t drop;
-	enum rte_meter_color color;
-};
-
-struct pipeline_fa_policer_params {
-	struct pipeline_fa_policer_action action[e_RTE_METER_COLORS];
-};
-
-struct pipeline_fa_flow_params {
-	struct rte_meter_trtcm_params m[PIPELINE_FA_N_TC_MAX];
-	struct pipeline_fa_policer_params p[PIPELINE_FA_N_TC_MAX];
-	uint32_t port_id;
-};
-
-int
-pipeline_fa_flow_params_set_default(struct pipeline_fa_flow_params *params);
-
-struct pipeline_fa_policer_stats {
-	uint64_t n_pkts[e_RTE_METER_COLORS];
-	uint64_t n_pkts_drop;
-};
-
-enum pipeline_fa_msg_req_type {
-	PIPELINE_FA_MSG_REQ_FLOW_CONFIG = 0,
-	PIPELINE_FA_MSG_REQ_FLOW_CONFIG_BULK,
-	PIPELINE_FA_MSG_REQ_DSCP_CONFIG,
-	PIPELINE_FA_MSG_REQ_POLICER_STATS_READ,
-	PIPELINE_FA_MSG_REQS,
-};
-
-/*
- * MSG FLOW CONFIG
- */
-struct pipeline_fa_flow_config_msg_req {
-	enum pipeline_msg_req_type type;
-	enum pipeline_fa_msg_req_type subtype;
-
-	void *entry_ptr;
-	uint32_t flow_id;
-
-	uint32_t meter_update_mask;
-	uint32_t policer_update_mask;
-	uint32_t port_update;
-	struct pipeline_fa_flow_params params;
-};
-
-struct pipeline_fa_flow_config_msg_rsp {
-	int status;
-	void *entry_ptr;
-};
-
-/*
- * MSG FLOW CONFIG BULK
- */
-struct pipeline_fa_flow_config_bulk_msg_req {
-	enum pipeline_msg_req_type type;
-	enum pipeline_fa_msg_req_type subtype;
-
-	void **entry_ptr;
-	uint32_t *flow_id;
-	uint32_t n_flows;
-
-	uint32_t meter_update_mask;
-	uint32_t policer_update_mask;
-	uint32_t port_update;
-	struct pipeline_fa_flow_params *params;
-};
-
-struct pipeline_fa_flow_config_bulk_msg_rsp {
-	uint32_t n_flows;
-};
-
-/*
- * MSG DSCP CONFIG
- */
-struct pipeline_fa_dscp_config_msg_req {
-	enum pipeline_msg_req_type type;
-	enum pipeline_fa_msg_req_type subtype;
-
-	uint32_t dscp;
-	uint32_t traffic_class;
-	enum rte_meter_color color;
-};
-
-struct pipeline_fa_dscp_config_msg_rsp {
-	int status;
-};
-
-/*
- * MSG POLICER STATS READ
- */
-struct pipeline_fa_policer_stats_msg_req {
-	enum pipeline_msg_req_type type;
-	enum pipeline_fa_msg_req_type subtype;
-
-	void *entry_ptr;
-	uint32_t policer_id;
-	int clear;
-};
-
-struct pipeline_fa_policer_stats_msg_rsp {
-	int status;
-	struct pipeline_fa_policer_stats stats;
-};
-
-extern struct pipeline_be_ops pipeline_flow_actions_be_ops;
-
-#endif
-- 
2.9.3

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

* [dpdk-dev] [PATCH v4 17/49] ip_pipeline: remove firewall pipeline
  2018-03-29 18:31           ` [dpdk-dev] [PATCH v4 00/49] ip_pipeline: refactoring Jasvinder Singh
                               ` (15 preceding siblings ...)
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 16/49] ip_pipeline: remove flow actions pipeline Jasvinder Singh
@ 2018-03-29 18:31             ` Jasvinder Singh
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 18/49] ip_pipeline: remove master pipeline Jasvinder Singh
                               ` (32 subsequent siblings)
  49 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-29 18:31 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Remove firewall pipeline.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/Makefile                      |    2 -
 examples/ip_pipeline/init.c                        |    2 -
 examples/ip_pipeline/meson.build                   |    2 -
 examples/ip_pipeline/pipeline/pipeline_firewall.c  | 1421 --------------------
 examples/ip_pipeline/pipeline/pipeline_firewall.h  |   60 -
 .../ip_pipeline/pipeline/pipeline_firewall_be.c    |  856 ------------
 .../ip_pipeline/pipeline/pipeline_firewall_be.h    |  147 --
 7 files changed, 2490 deletions(-)
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_firewall.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_firewall.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_firewall_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_firewall_be.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index 0782308..ae76edc 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -19,8 +19,6 @@ SRCS-y += pipeline_common_be.c
 SRCS-y += pipeline_common_fe.c
 SRCS-y += pipeline_master_be.c
 SRCS-y += pipeline_master.c
-SRCS-y += pipeline_firewall_be.c
-SRCS-y += pipeline_firewall.c
 
 # Build using pkg-config variables if possible
 $(shell pkg-config --exists libdpdk)
diff --git a/examples/ip_pipeline/init.c b/examples/ip_pipeline/init.c
index 6599b0d..f848310 100644
--- a/examples/ip_pipeline/init.c
+++ b/examples/ip_pipeline/init.c
@@ -26,7 +26,6 @@
 #include "pipeline.h"
 #include "pipeline_common_fe.h"
 #include "pipeline_master.h"
-#include "pipeline_firewall.h"
 #include "thread_fe.h"
 
 #define APP_NAME_SIZE	32
@@ -1818,7 +1817,6 @@ int app_init(struct app_params *app)
 	app_pipeline_common_cmd_push(app);
 	app_pipeline_thread_cmd_push(app);
 	app_pipeline_type_register(app, &pipeline_master);
-	app_pipeline_type_register(app, &pipeline_firewall);
 
 	app_init_pipelines(app);
 	app_init_threads(app);
diff --git a/examples/ip_pipeline/meson.build b/examples/ip_pipeline/meson.build
index 71812f4..1fdfc48 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -21,8 +21,6 @@ sources = files(
 	'thread_fe.c',
 	'pipeline/pipeline_common_be.c',
 	'pipeline/pipeline_common_fe.c',
-	'pipeline/pipeline_firewall_be.c',
-	'pipeline/pipeline_firewall.c',
 	'pipeline/pipeline_master_be.c',
 	'pipeline/pipeline_master.c',
 )
diff --git a/examples/ip_pipeline/pipeline/pipeline_firewall.c b/examples/ip_pipeline/pipeline/pipeline_firewall.c
deleted file mode 100644
index 0cae9d7..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_firewall.c
+++ /dev/null
@@ -1,1421 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-#include <errno.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/queue.h>
-#include <netinet/in.h>
-
-#include <rte_common.h>
-#include <rte_hexdump.h>
-#include <rte_malloc.h>
-#include <cmdline_rdline.h>
-#include <cmdline_parse.h>
-#include <cmdline_parse_num.h>
-#include <cmdline_parse_string.h>
-
-#include "app.h"
-#include "pipeline_common_fe.h"
-#include "pipeline_firewall.h"
-#include "parser.h"
-
-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;
-};
-
-static void
-print_firewall_ipv4_rule(struct app_pipeline_firewall_rule *rule)
-{
-	printf("Prio = %" PRId32 " (SA = %" PRIu32 ".%" PRIu32
-		".%" PRIu32 ".%" PRIu32 "/%" PRIu32 ", "
-		"DA = %" PRIu32 ".%" PRIu32
-		".%"PRIu32 ".%" PRIu32 "/%" PRIu32 ", "
-		"SP = %" PRIu32 "-%" PRIu32 ", "
-		"DP = %" PRIu32 "-%" PRIu32 ", "
-		"Proto = %" PRIu32 " / 0x%" PRIx32 ") => "
-		"Port = %" PRIu32 " (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);
-}
-
-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;
-
-	TAILQ_FOREACH(r, &p->rules, node)
-		if (memcmp(key,
-			&r->key,
-			sizeof(struct pipeline_firewall_key)) == 0)
-			return r;
-
-	return NULL;
-}
-
-static int
-app_pipeline_firewall_ls(
-	struct app_params *app,
-	uint32_t pipeline_id)
-{
-	struct app_pipeline_firewall *p;
-	struct app_pipeline_firewall_rule *rule;
-	uint32_t n_rules;
-	int priority;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_firewall);
-	if (p == NULL)
-		return -1;
-
-	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 %" PRIu32 " (entry ptr = %p)\n",
-			p->default_rule_port_id,
-			p->default_rule_entry_ptr);
-	else
-		printf("Default rule: DROP\n");
-
-	printf("\n");
-
-	return 0;
-}
-
-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;
-
-	/* Initialization */
-	p->n_ports_in = params->n_ports_in;
-	p->n_ports_out = params->n_ports_out;
-
-	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;
-
-	return (void *) p;
-}
-
-static int
-app_pipeline_firewall_free(void *pipeline)
-{
-	struct app_pipeline_firewall *p = pipeline;
-
-	/* Check input arguments */
-	if (p == NULL)
-		return -1;
-
-	/* Free resources */
-	while (!TAILQ_EMPTY(&p->rules)) {
-		struct app_pipeline_firewall_rule *rule;
-
-		rule = TAILQ_FIRST(&p->rules);
-		TAILQ_REMOVE(&p->rules, rule, node);
-		rte_free(rule);
-	}
-
-	rte_free(p);
-	return 0;
-}
-
-static int
-app_pipeline_firewall_key_check_and_normalize(struct pipeline_firewall_key *key)
-{
-	switch (key->type) {
-	case PIPELINE_FIREWALL_IPV4_5TUPLE:
-	{
-		uint32_t src_ip_depth = key->key.ipv4_5tuple.src_ip_mask;
-		uint32_t dst_ip_depth = key->key.ipv4_5tuple.dst_ip_mask;
-		uint16_t src_port_from = key->key.ipv4_5tuple.src_port_from;
-		uint16_t src_port_to = key->key.ipv4_5tuple.src_port_to;
-		uint16_t dst_port_from = key->key.ipv4_5tuple.dst_port_from;
-		uint16_t dst_port_to = key->key.ipv4_5tuple.dst_port_to;
-
-		uint32_t src_ip_netmask = 0;
-		uint32_t dst_ip_netmask = 0;
-
-		if ((src_ip_depth > 32) ||
-			(dst_ip_depth > 32) ||
-			(src_port_from > src_port_to) ||
-			(dst_port_from > dst_port_to))
-			return -1;
-
-		if (src_ip_depth)
-			src_ip_netmask = (~0U) << (32 - src_ip_depth);
-
-		if (dst_ip_depth)
-			dst_ip_netmask = ((~0U) << (32 - dst_ip_depth));
-
-		key->key.ipv4_5tuple.src_ip &= src_ip_netmask;
-		key->key.ipv4_5tuple.dst_ip &= dst_ip_netmask;
-
-		return 0;
-	}
-
-	default:
-		return -1;
-	}
-}
-
-int
-app_pipeline_firewall_load_file(char *filename,
-	struct pipeline_firewall_key *keys,
-	uint32_t *priorities,
-	uint32_t *port_ids,
-	uint32_t *n_keys,
-	uint32_t *line)
-{
-	FILE *f = NULL;
-	char file_buf[1024];
-	uint32_t i, l;
-
-	/* Check input arguments */
-	if ((filename == NULL) ||
-		(keys == NULL) ||
-		(priorities == NULL) ||
-		(port_ids == NULL) ||
-		(n_keys == NULL) ||
-		(*n_keys == 0) ||
-		(line == NULL)) {
-		if (line)
-			*line = 0;
-		return -1;
-		}
-
-	/* Open input file */
-	f = fopen(filename, "r");
-	if (f == NULL) {
-		*line = 0;
-		return -1;
-	}
-
-	/* Read file */
-	for (i = 0, l = 1; i < *n_keys; l++) {
-		char *tokens[32];
-		uint32_t n_tokens = RTE_DIM(tokens);
-
-		uint32_t priority = 0;
-		struct in_addr sipaddr;
-		uint32_t sipdepth = 0;
-		struct in_addr dipaddr;
-		uint32_t dipdepth = 0;
-		uint16_t sport0 = 0;
-		uint16_t sport1 = 0;
-		uint16_t dport0 = 0;
-		uint16_t dport1 = 0;
-		uint8_t proto = 0;
-		uint8_t protomask = 0;
-		uint32_t port_id = 0;
-
-		int status;
-
-		if (fgets(file_buf, sizeof(file_buf), f) == NULL)
-			break;
-
-		status = parse_tokenize_string(file_buf, tokens, &n_tokens);
-		if (status)
-			goto error1;
-
-		if ((n_tokens == 0) || (tokens[0][0] == '#'))
-			continue;
-
-		if ((n_tokens != 15) ||
-			strcmp(tokens[0], "priority") ||
-			parser_read_uint32(&priority, tokens[1]) ||
-			strcmp(tokens[2], "ipv4") ||
-			parse_ipv4_addr(tokens[3], &sipaddr) ||
-			parser_read_uint32(&sipdepth, tokens[4]) ||
-			parse_ipv4_addr(tokens[5], &dipaddr) ||
-			parser_read_uint32(&dipdepth, tokens[6]) ||
-			parser_read_uint16(&sport0, tokens[7]) ||
-			parser_read_uint16(&sport1, tokens[8]) ||
-			parser_read_uint16(&dport0, tokens[9]) ||
-			parser_read_uint16(&dport1, tokens[10]) ||
-			parser_read_uint8(&proto, tokens[11]) ||
-			parser_read_uint8_hex(&protomask, tokens[12]) ||
-			strcmp(tokens[13], "port") ||
-			parser_read_uint32(&port_id, tokens[14]))
-			goto error1;
-
-		keys[i].type = PIPELINE_FIREWALL_IPV4_5TUPLE;
-		keys[i].key.ipv4_5tuple.src_ip =
-			rte_be_to_cpu_32(sipaddr.s_addr);
-		keys[i].key.ipv4_5tuple.src_ip_mask = sipdepth;
-		keys[i].key.ipv4_5tuple.dst_ip =
-			rte_be_to_cpu_32(dipaddr.s_addr);
-		keys[i].key.ipv4_5tuple.dst_ip_mask = dipdepth;
-		keys[i].key.ipv4_5tuple.src_port_from = sport0;
-		keys[i].key.ipv4_5tuple.src_port_to = sport1;
-		keys[i].key.ipv4_5tuple.dst_port_from = dport0;
-		keys[i].key.ipv4_5tuple.dst_port_to = dport1;
-		keys[i].key.ipv4_5tuple.proto = proto;
-		keys[i].key.ipv4_5tuple.proto_mask = protomask;
-
-		port_ids[i] = port_id;
-		priorities[i] = priority;
-
-		if (app_pipeline_firewall_key_check_and_normalize(&keys[i]))
-			goto error1;
-
-		i++;
-	}
-
-	/* Close file */
-	*n_keys = i;
-	fclose(f);
-	return 0;
-
-error1:
-	*line = l;
-	fclose(f);
-	return -1;
-}
-
-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_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;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_firewall);
-	if (p == NULL)
-		return -1;
-
-	if (port_id >= p->n_ports_out)
-		return -1;
-
-	if (app_pipeline_firewall_key_check_and_normalize(key) != 0)
-		return -1;
-
-	/* 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;
-	}
-
-	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_DEFAULT);
-	if (rsp == NULL) {
-		if (new_rule)
-			rte_free(rule);
-		return -1;
-	}
-
-	/* Read response and write rule */
-	if (rsp->status ||
-		(rsp->entry_ptr == NULL) ||
-		((new_rule == 0) && (rsp->key_found == 0)) ||
-		((new_rule == 1) && (rsp->key_found == 1))) {
-		app_msg_free(app, rsp);
-		if (new_rule)
-			rte_free(rule);
-		return -1;
-	}
-
-	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;
-}
-
-int
-app_pipeline_firewall_delete_rule(struct app_params *app,
-	uint32_t pipeline_id,
-	struct pipeline_firewall_key *key)
-{
-	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;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_firewall);
-	if (p == NULL)
-		return -1;
-
-	if (app_pipeline_firewall_key_check_and_normalize(key) != 0)
-		return -1;
-
-	/* 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_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	/* Read response */
-	if (rsp->status || !rsp->key_found) {
-		app_msg_free(app, rsp);
-		return -1;
-	}
-
-	/* Remove rule */
-	TAILQ_REMOVE(&p->rules, rule, node);
-	p->n_rules--;
-	rte_free(rule);
-
-	/* Free response */
-	app_msg_free(app, rsp);
-
-	return 0;
-}
-
-int
-app_pipeline_firewall_add_bulk(struct app_params *app,
-		uint32_t pipeline_id,
-		struct pipeline_firewall_key *keys,
-		uint32_t n_keys,
-		uint32_t *priorities,
-		uint32_t *port_ids)
-{
-	struct app_pipeline_firewall *p;
-	struct pipeline_firewall_add_bulk_msg_req *req;
-	struct pipeline_firewall_add_bulk_msg_rsp *rsp;
-
-	struct app_pipeline_firewall_rule **rules;
-	int *new_rules;
-
-	int *keys_found;
-	void **entries_ptr;
-
-	uint32_t i;
-	int status = 0;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_firewall);
-	if (p == NULL)
-		return -1;
-
-	rules = rte_malloc(NULL,
-		n_keys * sizeof(struct app_pipeline_firewall_rule *),
-		RTE_CACHE_LINE_SIZE);
-	if (rules == NULL)
-		return -1;
-
-	new_rules = rte_malloc(NULL,
-		n_keys * sizeof(int),
-		RTE_CACHE_LINE_SIZE);
-	if (new_rules == NULL) {
-		rte_free(rules);
-		return -1;
-	}
-
-	/* check data integrity and add to rule list */
-	for (i = 0; i < n_keys; i++) {
-		if (port_ids[i]  >= p->n_ports_out) {
-			rte_free(rules);
-			rte_free(new_rules);
-			return -1;
-		}
-
-		if (app_pipeline_firewall_key_check_and_normalize(&keys[i]) != 0) {
-			rte_free(rules);
-			rte_free(new_rules);
-			return -1;
-		}
-
-		rules[i] = app_pipeline_firewall_rule_find(p, &keys[i]);
-		new_rules[i] = (rules[i] == NULL);
-		if (rules[i] == NULL) {
-			rules[i] = rte_malloc(NULL,
-				sizeof(*rules[i]),
-				RTE_CACHE_LINE_SIZE);
-
-			if (rules[i] == NULL) {
-				uint32_t j;
-
-				for (j = 0; j <= i; j++)
-					if (new_rules[j])
-						rte_free(rules[j]);
-
-				rte_free(rules);
-				rte_free(new_rules);
-				return -1;
-			}
-		}
-	}
-
-	keys_found = rte_malloc(NULL,
-		n_keys * sizeof(int),
-		RTE_CACHE_LINE_SIZE);
-	if (keys_found == NULL) {
-		uint32_t j;
-
-		for (j = 0; j < n_keys; j++)
-			if (new_rules[j])
-				rte_free(rules[j]);
-
-		rte_free(rules);
-		rte_free(new_rules);
-		return -1;
-	}
-
-	entries_ptr = rte_malloc(NULL,
-		n_keys * sizeof(struct rte_pipeline_table_entry *),
-		RTE_CACHE_LINE_SIZE);
-	if (entries_ptr == NULL) {
-		uint32_t j;
-
-		for (j = 0; j < n_keys; j++)
-			if (new_rules[j])
-				rte_free(rules[j]);
-
-		rte_free(rules);
-		rte_free(new_rules);
-		rte_free(keys_found);
-		return -1;
-	}
-	for (i = 0; i < n_keys; i++) {
-		entries_ptr[i] = rte_malloc(NULL,
-			sizeof(struct rte_pipeline_table_entry),
-			RTE_CACHE_LINE_SIZE);
-
-		if (entries_ptr[i] == NULL) {
-			uint32_t j;
-
-			for (j = 0; j < n_keys; j++)
-				if (new_rules[j])
-					rte_free(rules[j]);
-
-			for (j = 0; j <= i; j++)
-				rte_free(entries_ptr[j]);
-
-			rte_free(rules);
-			rte_free(new_rules);
-			rte_free(keys_found);
-			rte_free(entries_ptr);
-			return -1;
-		}
-	}
-
-	/* Allocate and write request */
-	req = app_msg_alloc(app);
-	if (req == NULL) {
-		uint32_t j;
-
-		for (j = 0; j < n_keys; j++)
-			if (new_rules[j])
-				rte_free(rules[j]);
-
-		for (j = 0; j < n_keys; j++)
-			rte_free(entries_ptr[j]);
-
-		rte_free(rules);
-		rte_free(new_rules);
-		rte_free(keys_found);
-		rte_free(entries_ptr);
-		return -1;
-	}
-
-	req->type = PIPELINE_MSG_REQ_CUSTOM;
-	req->subtype = PIPELINE_FIREWALL_MSG_REQ_ADD_BULK;
-
-	req->keys = keys;
-	req->n_keys = n_keys;
-	req->port_ids = port_ids;
-	req->priorities = priorities;
-	req->keys_found = keys_found;
-	req->entries_ptr = entries_ptr;
-
-	/* Send request and wait for response */
-	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL) {
-		uint32_t j;
-
-		for (j = 0; j < n_keys; j++)
-			if (new_rules[j])
-				rte_free(rules[j]);
-
-		for (j = 0; j < n_keys; j++)
-			rte_free(entries_ptr[j]);
-
-		rte_free(rules);
-		rte_free(new_rules);
-		rte_free(keys_found);
-		rte_free(entries_ptr);
-		return -1;
-	}
-
-	if (rsp->status) {
-		for (i = 0; i < n_keys; i++)
-			if (new_rules[i])
-				rte_free(rules[i]);
-
-		for (i = 0; i < n_keys; i++)
-			rte_free(entries_ptr[i]);
-
-		status = -1;
-		goto cleanup;
-	}
-
-	for (i = 0; i < n_keys; i++) {
-		if (entries_ptr[i] == NULL ||
-			((new_rules[i] == 0) && (keys_found[i] == 0)) ||
-			((new_rules[i] == 1) && (keys_found[i] == 1))) {
-			for (i = 0; i < n_keys; i++)
-				if (new_rules[i])
-					rte_free(rules[i]);
-
-			for (i = 0; i < n_keys; i++)
-				rte_free(entries_ptr[i]);
-
-			status = -1;
-			goto cleanup;
-		}
-	}
-
-	for (i = 0; i < n_keys; i++) {
-		memcpy(&rules[i]->key, &keys[i], sizeof(keys[i]));
-		rules[i]->priority = priorities[i];
-		rules[i]->port_id = port_ids[i];
-		rules[i]->entry_ptr = entries_ptr[i];
-
-		/* Commit rule */
-		if (new_rules[i]) {
-			TAILQ_INSERT_TAIL(&p->rules, rules[i], node);
-			p->n_rules++;
-		}
-
-		print_firewall_ipv4_rule(rules[i]);
-	}
-
-cleanup:
-	app_msg_free(app, rsp);
-	rte_free(rules);
-	rte_free(new_rules);
-	rte_free(keys_found);
-	rte_free(entries_ptr);
-
-	return status;
-}
-
-int
-app_pipeline_firewall_delete_bulk(struct app_params *app,
-	uint32_t pipeline_id,
-	struct pipeline_firewall_key *keys,
-	uint32_t n_keys)
-{
-	struct app_pipeline_firewall *p;
-	struct pipeline_firewall_del_bulk_msg_req *req;
-	struct pipeline_firewall_del_bulk_msg_rsp *rsp;
-
-	struct app_pipeline_firewall_rule **rules;
-	int *keys_found;
-
-	uint32_t i;
-	int status = 0;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_firewall);
-	if (p == NULL)
-		return -1;
-
-	rules = rte_malloc(NULL,
-		n_keys * sizeof(struct app_pipeline_firewall_rule *),
-		RTE_CACHE_LINE_SIZE);
-	if (rules == NULL)
-		return -1;
-
-	for (i = 0; i < n_keys; i++) {
-		if (app_pipeline_firewall_key_check_and_normalize(&keys[i]) != 0) {
-			return -1;
-		}
-
-		rules[i] = app_pipeline_firewall_rule_find(p, &keys[i]);
-	}
-
-	keys_found = rte_malloc(NULL,
-		n_keys * sizeof(int),
-		RTE_CACHE_LINE_SIZE);
-	if (keys_found == NULL) {
-		rte_free(rules);
-		return -1;
-	}
-
-	/* Allocate and write request */
-	req = app_msg_alloc(app);
-	if (req == NULL) {
-		rte_free(rules);
-		rte_free(keys_found);
-		return -1;
-	}
-
-	req->type = PIPELINE_MSG_REQ_CUSTOM;
-	req->subtype = PIPELINE_FIREWALL_MSG_REQ_DEL_BULK;
-
-	req->keys = keys;
-	req->n_keys = n_keys;
-	req->keys_found = keys_found;
-
-	/* Send request and wait for response */
-	rsp = app_msg_send_recv(app, pipeline_id, req, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL) {
-		rte_free(rules);
-		rte_free(keys_found);
-		return -1;
-	}
-
-	if (rsp->status) {
-		status = -1;
-		goto cleanup;
-	}
-
-	for (i = 0; i < n_keys; i++) {
-		if (keys_found[i] == 0) {
-			status = -1;
-			goto cleanup;
-		}
-	}
-
-	for (i = 0; i < n_keys; i++) {
-		TAILQ_REMOVE(&p->rules, rules[i], node);
-		p->n_rules--;
-		rte_free(rules[i]);
-	}
-
-cleanup:
-	app_msg_free(app, rsp);
-	rte_free(rules);
-	rte_free(keys_found);
-
-	return status;
-}
-
-int
-app_pipeline_firewall_add_default_rule(struct app_params *app,
-	uint32_t pipeline_id,
-	uint32_t port_id)
-{
-	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;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_firewall);
-	if (p == NULL)
-		return -1;
-
-	if (port_id >= p->n_ports_out)
-		return -1;
-
-	/* 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_DEFAULT);
-	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_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;
-
-	p = app_pipeline_data_fe(app, pipeline_id, &pipeline_firewall);
-	if (p == NULL)
-		return -1;
-
-	/* 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_DEFAULT);
-	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);
-
-	return 0;
-}
-
-/*
- * firewall
- *
- * firewall add:
- *    p <pipelineid> firewall add priority <priority>
- *       ipv4 <sipaddr> <sipdepth> <dipaddr> <dipdepth>
- *       <sport0> <sport1> <dport0> <dport1> <proto> <protomask>
- *       port <portid>
- *       Note: <protomask> is a hex value
- *
- *    p <pipelineid> firewall add bulk <file>
- *
- * firewall add default:
- *    p <pipelineid> firewall add default <port ID>
- *
- * firewall del:
- *    p <pipelineid> firewall del
- *       ipv4 <sipaddr> <sipdepth> <dipaddr> <dipdepth>
- *       <sport0> <sport1> <dport0> <dport1> <proto> <protomask>
- *
- *    p <pipelineid> firewall del bulk <file>
- *
- * firewall del default:
- *    p <pipelineid> firewall del default
- *
- * firewall ls:
- *    p <pipelineid> firewall ls
- */
-
-struct cmd_firewall_result {
-	cmdline_fixed_string_t p_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t firewall_string;
-	cmdline_multi_string_t multi_string;
-};
-
-static void cmd_firewall_parsed(void *parsed_result,
-	__attribute__((unused))  struct cmdline *cl,
-	void *data)
-{
-	struct cmd_firewall_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
-
-	char *tokens[17];
-	uint32_t n_tokens = RTE_DIM(tokens);
-
-	status = parse_tokenize_string(params->multi_string, tokens, &n_tokens);
-	if (status) {
-		printf(CMD_MSG_TOO_MANY_ARGS, "firewall");
-		return;
-	}
-
-	/* firewall add */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "add") == 0) &&
-		(strcmp(tokens[1], "priority") == 0)) {
-		struct pipeline_firewall_key key;
-		uint32_t priority;
-		struct in_addr sipaddr;
-		uint32_t sipdepth;
-		struct in_addr dipaddr;
-		uint32_t dipdepth;
-		uint16_t sport0;
-		uint16_t sport1;
-		uint16_t dport0;
-		uint16_t dport1;
-		uint8_t proto;
-		uint8_t protomask;
-		uint32_t port_id;
-
-		memset(&key, 0, sizeof(key));
-
-		if (n_tokens != 16) {
-			printf(CMD_MSG_MISMATCH_ARGS, "firewall add");
-			return;
-		}
-
-		if (parser_read_uint32(&priority, tokens[2])) {
-			printf(CMD_MSG_INVALID_ARG, "priority");
-			return;
-		}
-
-		if (strcmp(tokens[3], "ipv4")) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "ipv4");
-			return;
-		}
-
-		if (parse_ipv4_addr(tokens[4], &sipaddr)) {
-			printf(CMD_MSG_INVALID_ARG, "sipaddr");
-			return;
-		}
-
-		if (parser_read_uint32(&sipdepth, tokens[5])) {
-			printf(CMD_MSG_INVALID_ARG, "sipdepth");
-			return;
-		}
-
-		if (parse_ipv4_addr(tokens[6], &dipaddr)) {
-			printf(CMD_MSG_INVALID_ARG, "dipaddr");
-			return;
-		}
-
-		if (parser_read_uint32(&dipdepth, tokens[7])) {
-			printf(CMD_MSG_INVALID_ARG, "dipdepth");
-			return;
-		}
-
-		if (parser_read_uint16(&sport0, tokens[8])) {
-			printf(CMD_MSG_INVALID_ARG, "sport0");
-			return;
-		}
-
-		if (parser_read_uint16(&sport1, tokens[9])) {
-			printf(CMD_MSG_INVALID_ARG, "sport1");
-			return;
-		}
-
-		if (parser_read_uint16(&dport0, tokens[10])) {
-			printf(CMD_MSG_INVALID_ARG, "dport0");
-			return;
-		}
-
-		if (parser_read_uint16(&dport1, tokens[11])) {
-			printf(CMD_MSG_INVALID_ARG, "dport1");
-			return;
-		}
-
-		if (parser_read_uint8(&proto, tokens[12])) {
-			printf(CMD_MSG_INVALID_ARG, "proto");
-			return;
-		}
-
-		if (parser_read_uint8_hex(&protomask, tokens[13])) {
-			printf(CMD_MSG_INVALID_ARG, "protomask");
-			return;
-		}
-
-		if (strcmp(tokens[14], "port")) {
-			printf(CMD_MSG_ARG_NOT_FOUND, "port");
-			return;
-		}
-
-		if (parser_read_uint32(&port_id, tokens[15])) {
-			printf(CMD_MSG_INVALID_ARG, "portid");
-			return;
-		}
-
-		key.type = PIPELINE_FIREWALL_IPV4_5TUPLE;
-		key.key.ipv4_5tuple.src_ip = rte_be_to_cpu_32(sipaddr.s_addr);
-		key.key.ipv4_5tuple.src_ip_mask = sipdepth;
-		key.key.ipv4_5tuple.dst_ip = rte_be_to_cpu_32(dipaddr.s_addr);
-		key.key.ipv4_5tuple.dst_ip_mask = dipdepth;
-		key.key.ipv4_5tuple.src_port_from = sport0;
-		key.key.ipv4_5tuple.src_port_to = sport1;
-		key.key.ipv4_5tuple.dst_port_from = dport0;
-		key.key.ipv4_5tuple.dst_port_to = dport1;
-		key.key.ipv4_5tuple.proto = proto;
-		key.key.ipv4_5tuple.proto_mask = protomask;
-
-		status = app_pipeline_firewall_add_rule(app,
-			params->pipeline_id,
-			&key,
-			priority,
-			port_id);
-		if (status)
-			printf(CMD_MSG_FAIL, "firewall add");
-
-		return;
-	} /* firewall add */
-
-	/* firewall add bulk */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "add") == 0) &&
-		(strcmp(tokens[1], "bulk") == 0)) {
-		struct pipeline_firewall_key *keys;
-		uint32_t *priorities, *port_ids, n_keys, line;
-		char *filename;
-
-		if (n_tokens != 3) {
-			printf(CMD_MSG_MISMATCH_ARGS, "firewall add bulk");
-			return;
-		}
-
-		filename = tokens[2];
-
-		n_keys = APP_PIPELINE_FIREWALL_MAX_RULES_IN_FILE;
-		keys = malloc(n_keys * sizeof(struct pipeline_firewall_key));
-		if (keys == NULL) {
-			printf(CMD_MSG_OUT_OF_MEMORY);
-			return;
-		}
-		memset(keys, 0, n_keys * sizeof(struct pipeline_firewall_key));
-
-		priorities = malloc(n_keys * sizeof(uint32_t));
-		if (priorities == NULL) {
-			printf(CMD_MSG_OUT_OF_MEMORY);
-			free(keys);
-			return;
-		}
-
-		port_ids = malloc(n_keys * sizeof(uint32_t));
-		if (port_ids == NULL) {
-			printf(CMD_MSG_OUT_OF_MEMORY);
-			free(priorities);
-			free(keys);
-			return;
-		}
-
-		status = app_pipeline_firewall_load_file(filename,
-			keys,
-			priorities,
-			port_ids,
-			&n_keys,
-			&line);
-		if (status != 0) {
-			printf(CMD_MSG_FILE_ERR, filename, line);
-			free(port_ids);
-			free(priorities);
-			free(keys);
-			return;
-		}
-
-		status = app_pipeline_firewall_add_bulk(app,
-			params->pipeline_id,
-			keys,
-			n_keys,
-			priorities,
-			port_ids);
-		if (status)
-			printf(CMD_MSG_FAIL, "firewall add bulk");
-
-		free(keys);
-		free(priorities);
-		free(port_ids);
-		return;
-	} /* firewall add bulk */
-
-	/* firewall add default */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "add") == 0) &&
-		(strcmp(tokens[1], "default") == 0)) {
-		uint32_t port_id;
-
-		if (n_tokens != 3) {
-			printf(CMD_MSG_MISMATCH_ARGS, "firewall add default");
-			return;
-		}
-
-		if (parser_read_uint32(&port_id, tokens[2])) {
-			printf(CMD_MSG_INVALID_ARG, "portid");
-			return;
-		}
-
-		status = app_pipeline_firewall_add_default_rule(app,
-			params->pipeline_id,
-			port_id);
-		if (status)
-			printf(CMD_MSG_FAIL, "firewall add default");
-
-		return;
-	} /* firewall add default */
-
-	/* firewall del */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "del") == 0) &&
-		(strcmp(tokens[1], "ipv4") == 0)) {
-		struct pipeline_firewall_key key;
-		struct in_addr sipaddr;
-		uint32_t sipdepth;
-		struct in_addr dipaddr;
-		uint32_t dipdepth;
-		uint16_t sport0;
-		uint16_t sport1;
-		uint16_t dport0;
-		uint16_t dport1;
-		uint8_t proto;
-		uint8_t protomask;
-
-		memset(&key, 0, sizeof(key));
-
-		if (n_tokens != 12) {
-			printf(CMD_MSG_MISMATCH_ARGS, "firewall del");
-			return;
-		}
-
-		if (parse_ipv4_addr(tokens[2], &sipaddr)) {
-			printf(CMD_MSG_INVALID_ARG, "sipaddr");
-			return;
-		}
-
-		if (parser_read_uint32(&sipdepth, tokens[3])) {
-			printf(CMD_MSG_INVALID_ARG, "sipdepth");
-			return;
-		}
-
-		if (parse_ipv4_addr(tokens[4], &dipaddr)) {
-			printf(CMD_MSG_INVALID_ARG, "dipaddr");
-			return;
-		}
-
-		if (parser_read_uint32(&dipdepth, tokens[5])) {
-			printf(CMD_MSG_INVALID_ARG, "dipdepth");
-			return;
-		}
-
-		if (parser_read_uint16(&sport0, tokens[6])) {
-			printf(CMD_MSG_INVALID_ARG, "sport0");
-			return;
-		}
-
-		if (parser_read_uint16(&sport1, tokens[7])) {
-			printf(CMD_MSG_INVALID_ARG, "sport1");
-			return;
-		}
-
-		if (parser_read_uint16(&dport0, tokens[8])) {
-			printf(CMD_MSG_INVALID_ARG, "dport0");
-			return;
-		}
-
-		if (parser_read_uint16(&dport1, tokens[9])) {
-			printf(CMD_MSG_INVALID_ARG, "dport1");
-			return;
-		}
-
-		if (parser_read_uint8(&proto, tokens[10])) {
-			printf(CMD_MSG_INVALID_ARG, "proto");
-			return;
-		}
-
-		if (parser_read_uint8_hex(&protomask, tokens[11])) {
-			printf(CMD_MSG_INVALID_ARG, "protomask");
-			return;
-		}
-
-		key.type = PIPELINE_FIREWALL_IPV4_5TUPLE;
-		key.key.ipv4_5tuple.src_ip = rte_be_to_cpu_32(sipaddr.s_addr);
-		key.key.ipv4_5tuple.src_ip_mask = sipdepth;
-		key.key.ipv4_5tuple.dst_ip = rte_be_to_cpu_32(dipaddr.s_addr);
-		key.key.ipv4_5tuple.dst_ip_mask = dipdepth;
-		key.key.ipv4_5tuple.src_port_from = sport0;
-		key.key.ipv4_5tuple.src_port_to = sport1;
-		key.key.ipv4_5tuple.dst_port_from = dport0;
-		key.key.ipv4_5tuple.dst_port_to = dport1;
-		key.key.ipv4_5tuple.proto = proto;
-		key.key.ipv4_5tuple.proto_mask = protomask;
-
-		status = app_pipeline_firewall_delete_rule(app,
-			params->pipeline_id,
-			&key);
-		if (status)
-			printf(CMD_MSG_FAIL, "firewall del");
-
-		return;
-	} /* firewall del */
-
-	/* firewall del bulk */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "del") == 0) &&
-		(strcmp(tokens[1], "bulk") == 0)) {
-		struct pipeline_firewall_key *keys;
-		uint32_t *priorities, *port_ids, n_keys, line;
-		char *filename;
-
-		if (n_tokens != 3) {
-			printf(CMD_MSG_MISMATCH_ARGS, "firewall del bulk");
-			return;
-		}
-
-		filename = tokens[2];
-
-		n_keys = APP_PIPELINE_FIREWALL_MAX_RULES_IN_FILE;
-		keys = malloc(n_keys * sizeof(struct pipeline_firewall_key));
-		if (keys == NULL) {
-			printf(CMD_MSG_OUT_OF_MEMORY);
-			return;
-		}
-		memset(keys, 0, n_keys * sizeof(struct pipeline_firewall_key));
-
-		priorities = malloc(n_keys * sizeof(uint32_t));
-		if (priorities == NULL) {
-			printf(CMD_MSG_OUT_OF_MEMORY);
-			free(keys);
-			return;
-		}
-
-		port_ids = malloc(n_keys * sizeof(uint32_t));
-		if (port_ids == NULL) {
-			printf(CMD_MSG_OUT_OF_MEMORY);
-			free(priorities);
-			free(keys);
-			return;
-		}
-
-		status = app_pipeline_firewall_load_file(filename,
-			keys,
-			priorities,
-			port_ids,
-			&n_keys,
-			&line);
-		if (status != 0) {
-			printf(CMD_MSG_FILE_ERR, filename, line);
-			free(port_ids);
-			free(priorities);
-			free(keys);
-			return;
-		}
-
-		status = app_pipeline_firewall_delete_bulk(app,
-			params->pipeline_id,
-			keys,
-			n_keys);
-		if (status)
-			printf(CMD_MSG_FAIL, "firewall del bulk");
-
-		free(port_ids);
-		free(priorities);
-		free(keys);
-		return;
-	} /* firewall del bulk */
-
-	/* firewall del default */
-	if ((n_tokens >= 2) &&
-		(strcmp(tokens[0], "del") == 0) &&
-		(strcmp(tokens[1], "default") == 0)) {
-		if (n_tokens != 2) {
-			printf(CMD_MSG_MISMATCH_ARGS, "firewall del default");
-			return;
-		}
-
-		status = app_pipeline_firewall_delete_default_rule(app,
-			params->pipeline_id);
-		if (status)
-			printf(CMD_MSG_FAIL, "firewall del default");
-
-		return;
-
-	} /* firewall del default */
-
-	/* firewall ls */
-	if ((n_tokens >= 1) && (strcmp(tokens[0], "ls") == 0)) {
-		if (n_tokens != 1) {
-			printf(CMD_MSG_MISMATCH_ARGS, "firewall ls");
-			return;
-		}
-
-		status = app_pipeline_firewall_ls(app, params->pipeline_id);
-		if (status)
-			printf(CMD_MSG_FAIL, "firewall ls");
-
-		return;
-	} /* firewall ls */
-
-	printf(CMD_MSG_MISMATCH_ARGS, "firewall");
-}
-
-static cmdline_parse_token_string_t cmd_firewall_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_result, p_string, "p");
-
-static cmdline_parse_token_num_t cmd_firewall_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_firewall_result, pipeline_id, UINT32);
-
-static cmdline_parse_token_string_t cmd_firewall_firewall_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_result, firewall_string,
-	"firewall");
-
-static cmdline_parse_token_string_t cmd_firewall_multi_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_firewall_result, multi_string,
-	TOKEN_STRING_MULTI);
-
-static cmdline_parse_inst_t cmd_firewall = {
-	.f = cmd_firewall_parsed,
-	.data = NULL,
-	.help_str =	"firewall add / add bulk / add default / del / del bulk"
-		" / del default / ls",
-	.tokens = {
-		(void *) &cmd_firewall_p_string,
-		(void *) &cmd_firewall_pipeline_id,
-		(void *) &cmd_firewall_firewall_string,
-		(void *) &cmd_firewall_multi_string,
-		NULL,
-	},
-};
-
-static cmdline_parse_ctx_t pipeline_cmds[] = {
-	(cmdline_parse_inst_t *) &cmd_firewall,
-	NULL,
-};
-
-static struct pipeline_fe_ops pipeline_firewall_fe_ops = {
-	.f_init = app_pipeline_firewall_init,
-	.f_post_init = NULL,
-	.f_free = app_pipeline_firewall_free,
-	.f_track = app_pipeline_track_default,
-	.cmds = pipeline_cmds,
-};
-
-struct pipeline_type pipeline_firewall = {
-	.name = "FIREWALL",
-	.be_ops = &pipeline_firewall_be_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
deleted file mode 100644
index 27304b0..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_firewall.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#ifndef __INCLUDE_PIPELINE_FIREWALL_H__
-#define __INCLUDE_PIPELINE_FIREWALL_H__
-
-#include "pipeline.h"
-#include "pipeline_firewall_be.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_bulk(struct app_params *app,
-		uint32_t pipeline_id,
-		struct pipeline_firewall_key *keys,
-		uint32_t n_keys,
-		uint32_t *priorities,
-		uint32_t *port_ids);
-
-int
-app_pipeline_firewall_delete_bulk(struct app_params *app,
-	uint32_t pipeline_id,
-	struct pipeline_firewall_key *keys,
-	uint32_t n_keys);
-
-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);
-
-#ifndef APP_PIPELINE_FIREWALL_MAX_RULES_IN_FILE
-#define APP_PIPELINE_FIREWALL_MAX_RULES_IN_FILE		65536
-#endif
-
-int
-app_pipeline_firewall_load_file(char *filename,
-	struct pipeline_firewall_key *keys,
-	uint32_t *priorities,
-	uint32_t *port_ids,
-	uint32_t *n_keys,
-	uint32_t *line);
-
-extern struct pipeline_type pipeline_firewall;
-
-#endif
diff --git a/examples/ip_pipeline/pipeline/pipeline_firewall_be.c b/examples/ip_pipeline/pipeline/pipeline_firewall_be.c
deleted file mode 100644
index bd5e1b2..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_firewall_be.c
+++ /dev/null
@@ -1,856 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2016 Intel Corporation
- */
-
-#include <string.h>
-
-#include <rte_common.h>
-#include <rte_malloc.h>
-#include <rte_ether.h>
-#include <rte_ip.h>
-#include <rte_tcp.h>
-#include <rte_byteorder.h>
-#include <rte_table_acl.h>
-
-#include "pipeline_firewall_be.h"
-#include "parser.h"
-
-struct pipeline_firewall {
-	struct pipeline p;
-	pipeline_msg_req_handler custom_handlers[PIPELINE_FIREWALL_MSG_REQS];
-
-	uint32_t n_rules;
-	uint32_t n_rule_fields;
-	struct rte_acl_field_def *field_format;
-	uint32_t field_format_size;
-} __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_bulk_handler(struct pipeline *p, void *msg);
-
-static void *
-pipeline_firewall_msg_req_del_bulk_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_BULK] =
-		pipeline_firewall_msg_req_add_bulk_handler,
-	[PIPELINE_FIREWALL_MSG_REQ_DEL_BULK] =
-		pipeline_firewall_msg_req_del_bulk_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,
-};
-
-/*
- * Firewall table
- */
-struct firewall_table_entry {
-	struct rte_pipeline_table_entry head;
-};
-
-static struct rte_acl_field_def field_format_ipv4[] = {
-	/* Protocol */
-	[0] = {
-		.type = RTE_ACL_FIELD_TYPE_BITMASK,
-		.size = sizeof(uint8_t),
-		.field_index = 0,
-		.input_index = 0,
-		.offset = sizeof(struct ether_hdr) +
-			offsetof(struct ipv4_hdr, next_proto_id),
-	},
-
-	/* Source IP address (IPv4) */
-	[1] = {
-		.type = RTE_ACL_FIELD_TYPE_MASK,
-		.size = sizeof(uint32_t),
-		.field_index = 1,
-		.input_index = 1,
-		.offset = sizeof(struct ether_hdr) +
-			offsetof(struct ipv4_hdr, src_addr),
-	},
-
-	/* Destination IP address (IPv4) */
-	[2] = {
-		.type = RTE_ACL_FIELD_TYPE_MASK,
-		.size = sizeof(uint32_t),
-		.field_index = 2,
-		.input_index = 2,
-		.offset = sizeof(struct ether_hdr) +
-			offsetof(struct ipv4_hdr, dst_addr),
-	},
-
-	/* Source Port */
-	[3] = {
-		.type = RTE_ACL_FIELD_TYPE_RANGE,
-		.size = sizeof(uint16_t),
-		.field_index = 3,
-		.input_index = 3,
-		.offset = sizeof(struct ether_hdr) +
-			sizeof(struct ipv4_hdr) +
-			offsetof(struct tcp_hdr, src_port),
-	},
-
-	/* Destination Port */
-	[4] = {
-		.type = RTE_ACL_FIELD_TYPE_RANGE,
-		.size = sizeof(uint16_t),
-		.field_index = 4,
-		.input_index = 3,
-		.offset = sizeof(struct ether_hdr) +
-			sizeof(struct ipv4_hdr) +
-			offsetof(struct tcp_hdr, dst_port),
-	},
-};
-
-#define SIZEOF_VLAN_HDR                          4
-
-static struct rte_acl_field_def field_format_vlan_ipv4[] = {
-	/* Protocol */
-	[0] = {
-		.type = RTE_ACL_FIELD_TYPE_BITMASK,
-		.size = sizeof(uint8_t),
-		.field_index = 0,
-		.input_index = 0,
-		.offset = sizeof(struct ether_hdr) +
-			SIZEOF_VLAN_HDR +
-			offsetof(struct ipv4_hdr, next_proto_id),
-	},
-
-	/* Source IP address (IPv4) */
-	[1] = {
-		.type = RTE_ACL_FIELD_TYPE_MASK,
-		.size = sizeof(uint32_t),
-		.field_index = 1,
-		.input_index = 1,
-		.offset = sizeof(struct ether_hdr) +
-			SIZEOF_VLAN_HDR +
-			offsetof(struct ipv4_hdr, src_addr),
-	},
-
-	/* Destination IP address (IPv4) */
-	[2] = {
-		.type = RTE_ACL_FIELD_TYPE_MASK,
-		.size = sizeof(uint32_t),
-		.field_index = 2,
-		.input_index = 2,
-		.offset = sizeof(struct ether_hdr) +
-			SIZEOF_VLAN_HDR +
-			offsetof(struct ipv4_hdr, dst_addr),
-	},
-
-	/* Source Port */
-	[3] = {
-		.type = RTE_ACL_FIELD_TYPE_RANGE,
-		.size = sizeof(uint16_t),
-		.field_index = 3,
-		.input_index = 3,
-		.offset = sizeof(struct ether_hdr) +
-			SIZEOF_VLAN_HDR +
-			sizeof(struct ipv4_hdr) +
-			offsetof(struct tcp_hdr, src_port),
-	},
-
-	/* Destination Port */
-	[4] = {
-		.type = RTE_ACL_FIELD_TYPE_RANGE,
-		.size = sizeof(uint16_t),
-		.field_index = 4,
-		.input_index = 3,
-		.offset = sizeof(struct ether_hdr) +
-			SIZEOF_VLAN_HDR +
-			sizeof(struct ipv4_hdr) +
-			offsetof(struct tcp_hdr, dst_port),
-	},
-};
-
-#define SIZEOF_QINQ_HEADER                       8
-
-static struct rte_acl_field_def field_format_qinq_ipv4[] = {
-	/* Protocol */
-	[0] = {
-		.type = RTE_ACL_FIELD_TYPE_BITMASK,
-		.size = sizeof(uint8_t),
-		.field_index = 0,
-		.input_index = 0,
-		.offset = sizeof(struct ether_hdr) +
-			SIZEOF_QINQ_HEADER +
-			offsetof(struct ipv4_hdr, next_proto_id),
-	},
-
-	/* Source IP address (IPv4) */
-	[1] = {
-		.type = RTE_ACL_FIELD_TYPE_MASK,
-		.size = sizeof(uint32_t),
-		.field_index = 1,
-		.input_index = 1,
-		.offset = sizeof(struct ether_hdr) +
-			SIZEOF_QINQ_HEADER +
-			offsetof(struct ipv4_hdr, src_addr),
-	},
-
-	/* Destination IP address (IPv4) */
-	[2] = {
-		.type = RTE_ACL_FIELD_TYPE_MASK,
-		.size = sizeof(uint32_t),
-		.field_index = 2,
-		.input_index = 2,
-		.offset = sizeof(struct ether_hdr) +
-			SIZEOF_QINQ_HEADER +
-			offsetof(struct ipv4_hdr, dst_addr),
-	},
-
-	/* Source Port */
-	[3] = {
-		.type = RTE_ACL_FIELD_TYPE_RANGE,
-		.size = sizeof(uint16_t),
-		.field_index = 3,
-		.input_index = 3,
-		.offset = sizeof(struct ether_hdr) +
-			SIZEOF_QINQ_HEADER +
-			sizeof(struct ipv4_hdr) +
-			offsetof(struct tcp_hdr, src_port),
-	},
-
-	/* Destination Port */
-	[4] = {
-		.type = RTE_ACL_FIELD_TYPE_RANGE,
-		.size = sizeof(uint16_t),
-		.field_index = 4,
-		.input_index = 3,
-		.offset = sizeof(struct ether_hdr) +
-			SIZEOF_QINQ_HEADER +
-			sizeof(struct ipv4_hdr) +
-			offsetof(struct tcp_hdr, dst_port),
-	},
-};
-
-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;
-
-	/* defaults */
-	p->n_rules = 4 * 1024;
-	p->n_rule_fields = RTE_DIM(field_format_ipv4);
-	p->field_format = field_format_ipv4;
-	p->field_format_size = sizeof(field_format_ipv4);
-
-	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) {
-			int status;
-
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				n_rules_present == 0, params->name,
-				arg_name);
-			n_rules_present = 1;
-
-			status = parser_read_uint32(&p->n_rules,
-				arg_value);
-			PIPELINE_PARSE_ERR_INV_VAL((status != -EINVAL),
-				params->name, arg_name, arg_value);
-			PIPELINE_PARSE_ERR_OUT_RNG((status != -ERANGE),
-				params->name, arg_name, arg_value);
-			continue;
-		}
-
-		if (strcmp(arg_name, "pkt_type") == 0) {
-			PIPELINE_PARSE_ERR_DUPLICATE(
-				pkt_type_present == 0, params->name,
-				arg_name);
-			pkt_type_present = 1;
-
-			/* ipv4 */
-			if (strcmp(arg_value, "ipv4") == 0) {
-				p->n_rule_fields = RTE_DIM(field_format_ipv4);
-				p->field_format = field_format_ipv4;
-				p->field_format_size =
-					sizeof(field_format_ipv4);
-				continue;
-			}
-
-			/* vlan_ipv4 */
-			if (strcmp(arg_value, "vlan_ipv4") == 0) {
-				p->n_rule_fields =
-					RTE_DIM(field_format_vlan_ipv4);
-				p->field_format = field_format_vlan_ipv4;
-				p->field_format_size =
-					sizeof(field_format_vlan_ipv4);
-				continue;
-			}
-
-			/* qinq_ipv4 */
-			if (strcmp(arg_value, "qinq_ipv4") == 0) {
-				p->n_rule_fields =
-					RTE_DIM(field_format_qinq_ipv4);
-				p->field_format = field_format_qinq_ipv4;
-				p->field_format_size =
-					sizeof(field_format_qinq_ipv4);
-				continue;
-			}
-
-			/* other */
-			PIPELINE_PARSE_ERR_INV_VAL(0, params->name,
-				arg_name, arg_value);
-		}
-
-		/* other */
-		PIPELINE_PARSE_ERR_INV_ENT(0, params->name, arg_name);
-	}
-
-	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);
-	p->log_level = params->log_level;
-
-	PLOG(p, HIGH, "Firewall");
-
-	/* 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,
-			.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 = params->name,
-			.n_rules = p_fw->n_rules,
-			.n_rule_fields = p_fw->n_rule_fields,
-		};
-
-		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 =
-					sizeof(struct firewall_table_entry) -
-					sizeof(struct rte_pipeline_table_entry),
-			};
-
-		int status;
-
-		memcpy(table_acl_params.field_format,
-			p_fw->field_format,
-			p_fw->field_format_size);
-
-		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_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 firewall_table_entry entry = {
-		.head = {
-			.action = RTE_PIPELINE_ACTION_PORT,
-			{.port_id = p->port_out_id[req->port_id]},
-		},
-	};
-
-	memset(&params, 0, sizeof(params));
-
-	switch (req->key.type) {
-	case PIPELINE_FIREWALL_IPV4_5TUPLE:
-		params.priority = req->priority;
-		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,
-		(struct rte_pipeline_table_entry *) &entry,
-		&rsp->key_found,
-		(struct rte_pipeline_table_entry **) &rsp->entry_ptr);
-
-	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;
-
-	memset(&params, 0, sizeof(params));
-
-	switch (req->key.type) {
-	case PIPELINE_FIREWALL_IPV4_5TUPLE:
-		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);
-
-	return rsp;
-}
-
-static void *
-pipeline_firewall_msg_req_add_bulk_handler(struct pipeline *p, void *msg)
-{
-	struct pipeline_firewall_add_bulk_msg_req *req = msg;
-	struct pipeline_firewall_add_bulk_msg_rsp *rsp = msg;
-
-	struct rte_table_acl_rule_add_params *params[req->n_keys];
-	struct firewall_table_entry *entries[req->n_keys];
-
-	uint32_t i, n_keys;
-
-	n_keys = req->n_keys;
-
-	for (i = 0; i < n_keys; i++) {
-		entries[i] = rte_zmalloc(NULL,
-				sizeof(struct firewall_table_entry),
-				RTE_CACHE_LINE_SIZE);
-		if (entries[i] == NULL) {
-			rsp->status = -1;
-			return rsp;
-		}
-
-		params[i] = rte_zmalloc(NULL,
-				sizeof(struct rte_table_acl_rule_add_params),
-				RTE_CACHE_LINE_SIZE);
-		if (params[i] == NULL) {
-			rsp->status = -1;
-			return rsp;
-		}
-
-		entries[i]->head.action = RTE_PIPELINE_ACTION_PORT;
-		entries[i]->head.port_id = p->port_out_id[req->port_ids[i]];
-
-		switch (req->keys[i].type) {
-		case PIPELINE_FIREWALL_IPV4_5TUPLE:
-			params[i]->priority = req->priorities[i];
-			params[i]->field_value[0].value.u8 =
-				req->keys[i].key.ipv4_5tuple.proto;
-			params[i]->field_value[0].mask_range.u8 =
-				req->keys[i].key.ipv4_5tuple.proto_mask;
-			params[i]->field_value[1].value.u32 =
-				req->keys[i].key.ipv4_5tuple.src_ip;
-			params[i]->field_value[1].mask_range.u32 =
-				req->keys[i].key.ipv4_5tuple.src_ip_mask;
-			params[i]->field_value[2].value.u32 =
-				req->keys[i].key.ipv4_5tuple.dst_ip;
-			params[i]->field_value[2].mask_range.u32 =
-				req->keys[i].key.ipv4_5tuple.dst_ip_mask;
-			params[i]->field_value[3].value.u16 =
-				req->keys[i].key.ipv4_5tuple.src_port_from;
-			params[i]->field_value[3].mask_range.u16 =
-				req->keys[i].key.ipv4_5tuple.src_port_to;
-			params[i]->field_value[4].value.u16 =
-				req->keys[i].key.ipv4_5tuple.dst_port_from;
-			params[i]->field_value[4].mask_range.u16 =
-				req->keys[i].key.ipv4_5tuple.dst_port_to;
-			break;
-
-		default:
-			rsp->status = -1; /* Error */
-
-			for (i = 0; i < n_keys; i++) {
-				rte_free(entries[i]);
-				rte_free(params[i]);
-			}
-
-			return rsp;
-		}
-	}
-
-	rsp->status = rte_pipeline_table_entry_add_bulk(p->p, p->table_id[0],
-			(void *)params, (struct rte_pipeline_table_entry **)entries,
-			n_keys, req->keys_found,
-			(struct rte_pipeline_table_entry **)req->entries_ptr);
-
-	for (i = 0; i < n_keys; i++) {
-		rte_free(entries[i]);
-		rte_free(params[i]);
-	}
-
-	return rsp;
-}
-
-static void *
-pipeline_firewall_msg_req_del_bulk_handler(struct pipeline *p, void *msg)
-{
-	struct pipeline_firewall_del_bulk_msg_req *req = msg;
-	struct pipeline_firewall_del_bulk_msg_rsp *rsp = msg;
-
-	struct rte_table_acl_rule_delete_params *params[req->n_keys];
-
-	uint32_t i, n_keys;
-
-	n_keys = req->n_keys;
-
-	for (i = 0; i < n_keys; i++) {
-		params[i] = rte_zmalloc(NULL,
-				sizeof(struct rte_table_acl_rule_delete_params),
-				RTE_CACHE_LINE_SIZE);
-		if (params[i] == NULL) {
-			rsp->status = -1;
-			return rsp;
-		}
-
-		switch (req->keys[i].type) {
-		case PIPELINE_FIREWALL_IPV4_5TUPLE:
-			params[i]->field_value[0].value.u8 =
-				req->keys[i].key.ipv4_5tuple.proto;
-			params[i]->field_value[0].mask_range.u8 =
-				req->keys[i].key.ipv4_5tuple.proto_mask;
-			params[i]->field_value[1].value.u32 =
-				req->keys[i].key.ipv4_5tuple.src_ip;
-			params[i]->field_value[1].mask_range.u32 =
-				req->keys[i].key.ipv4_5tuple.src_ip_mask;
-			params[i]->field_value[2].value.u32 =
-				req->keys[i].key.ipv4_5tuple.dst_ip;
-			params[i]->field_value[2].mask_range.u32 =
-				req->keys[i].key.ipv4_5tuple.dst_ip_mask;
-			params[i]->field_value[3].value.u16 =
-				req->keys[i].key.ipv4_5tuple.src_port_from;
-			params[i]->field_value[3].mask_range.u16 =
-				req->keys[i].key.ipv4_5tuple.src_port_to;
-			params[i]->field_value[4].value.u16 =
-				req->keys[i].key.ipv4_5tuple.dst_port_from;
-			params[i]->field_value[4].mask_range.u16 =
-				req->keys[i].key.ipv4_5tuple.dst_port_to;
-			break;
-
-		default:
-			rsp->status = -1; /* Error */
-
-			for (i = 0; i < n_keys; i++)
-				rte_free(params[i]);
-
-			return rsp;
-		}
-	}
-
-	rsp->status = rte_pipeline_table_entry_delete_bulk(p->p, p->table_id[0],
-			(void **)&params, n_keys, req->keys_found, NULL);
-
-	for (i = 0; i < n_keys; i++)
-		rte_free(params[i]);
-
-	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 firewall_table_entry default_entry = {
-		.head = {
-			.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],
-		(struct rte_pipeline_table_entry *) &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_be_ops pipeline_firewall_be_ops = {
-	.f_init = pipeline_firewall_init,
-	.f_free = pipeline_firewall_free,
-	.f_run = NULL,
-	.f_timer = pipeline_firewall_timer,
-};
diff --git a/examples/ip_pipeline/pipeline/pipeline_firewall_be.h b/examples/ip_pipeline/pipeline/pipeline_firewall_be.h
deleted file mode 100644
index 246f0a6..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_firewall_be.h
+++ /dev/null
@@ -1,147 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#ifndef __INCLUDE_PIPELINE_FIREWALL_BE_H__
-#define __INCLUDE_PIPELINE_FIREWALL_BE_H__
-
-#include "pipeline_common_be.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_BULK,
-	PIPELINE_FIREWALL_MSG_REQ_DEL_BULK,
-	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 BULK
- */
-struct pipeline_firewall_add_bulk_msg_req {
-	enum pipeline_msg_req_type type;
-	enum pipeline_firewall_msg_req_type subtype;
-
-	struct pipeline_firewall_key *keys;
-	uint32_t n_keys;
-
-	uint32_t *priorities;
-	uint32_t *port_ids;
-	int *keys_found;
-	void **entries_ptr;
-};
-struct pipeline_firewall_add_bulk_msg_rsp {
-	int status;
-};
-
-/*
- * MSG DEL BULK
- */
-struct pipeline_firewall_del_bulk_msg_req {
-	enum pipeline_msg_req_type type;
-	enum pipeline_firewall_msg_req_type subtype;
-
-	/* key */
-	struct pipeline_firewall_key *keys;
-	uint32_t n_keys;
-	int *keys_found;
-};
-
-struct pipeline_firewall_del_bulk_msg_rsp {
-	int status;
-};
-
-/*
- * 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_be_ops pipeline_firewall_be_ops;
-
-#endif
-- 
2.9.3

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

* [dpdk-dev] [PATCH v4 18/49] ip_pipeline: remove master pipeline
  2018-03-29 18:31           ` [dpdk-dev] [PATCH v4 00/49] ip_pipeline: refactoring Jasvinder Singh
                               ` (16 preceding siblings ...)
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 17/49] ip_pipeline: remove firewall pipeline Jasvinder Singh
@ 2018-03-29 18:31             ` Jasvinder Singh
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 19/49] ip_pipeline: remove config Jasvinder Singh
                               ` (31 subsequent siblings)
  49 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-29 18:31 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

remove master pipeline.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/Makefile                      |    6 -
 examples/ip_pipeline/app.h                         |   12 -
 examples/ip_pipeline/{pipeline => }/hash_func.h    |    3 +-
 .../ip_pipeline/{pipeline => }/hash_func_arm64.h   |    0
 examples/ip_pipeline/init.c                        |  574 --------
 examples/ip_pipeline/meson.build                   |    9 +-
 .../ip_pipeline/pipeline/pipeline_actions_common.h |  202 ---
 examples/ip_pipeline/pipeline/pipeline_common_be.c |  176 ---
 examples/ip_pipeline/pipeline/pipeline_common_be.h |  134 --
 examples/ip_pipeline/pipeline/pipeline_common_fe.c | 1455 --------------------
 examples/ip_pipeline/pipeline/pipeline_common_fe.h |  231 ----
 examples/ip_pipeline/pipeline/pipeline_master.c    |   20 -
 examples/ip_pipeline/pipeline/pipeline_master.h    |   12 -
 examples/ip_pipeline/pipeline/pipeline_master_be.c |  141 --
 examples/ip_pipeline/pipeline/pipeline_master_be.h |   12 -
 examples/ip_pipeline/thread.c                      |   53 -
 examples/ip_pipeline/thread_fe.c                   |  457 ------
 examples/ip_pipeline/thread_fe.h                   |   72 -
 18 files changed, 3 insertions(+), 3566 deletions(-)
 rename examples/ip_pipeline/{pipeline => }/hash_func.h (99%)
 rename examples/ip_pipeline/{pipeline => }/hash_func_arm64.h (100%)
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_actions_common.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_common_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_common_be.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_common_fe.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_common_fe.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_master.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_master.h
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_master_be.c
 delete mode 100644 examples/ip_pipeline/pipeline/pipeline_master_be.h
 delete mode 100644 examples/ip_pipeline/thread_fe.c
 delete mode 100644 examples/ip_pipeline/thread_fe.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index ae76edc..8ba7887 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -12,14 +12,8 @@ SRCS-y += config_parse_tm.c
 SRCS-y += config_check.c
 SRCS-y += init.c
 SRCS-y += thread.c
-SRCS-y += thread_fe.c
 SRCS-y += cpu_core_map.c
 
-SRCS-y += pipeline_common_be.c
-SRCS-y += pipeline_common_fe.c
-SRCS-y += pipeline_master_be.c
-SRCS-y += pipeline_master.c
-
 # Build using pkg-config variables if possible
 $(shell pkg-config --exists libdpdk)
 ifeq ($(.SHELLSTATUS),0)
diff --git a/examples/ip_pipeline/app.h b/examples/ip_pipeline/app.h
index 907d4e7..dadaf2b 100644
--- a/examples/ip_pipeline/app.h
+++ b/examples/ip_pipeline/app.h
@@ -1359,10 +1359,6 @@ app_core_build_core_mask_string(struct app_params *app, char *mask_buffer)
 	}
 }
 
-void app_pipeline_params_get(struct app_params *app,
-	struct app_pipeline_params *p_in,
-	struct pipeline_params *p_out);
-
 int app_config_init(struct app_params *app);
 
 int app_config_args(struct app_params *app,
@@ -1382,16 +1378,8 @@ int app_config_check(struct app_params *app);
 
 int app_init(struct app_params *app);
 
-int app_post_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);
 
diff --git a/examples/ip_pipeline/pipeline/hash_func.h b/examples/ip_pipeline/hash_func.h
similarity index 99%
rename from examples/ip_pipeline/pipeline/hash_func.h
rename to examples/ip_pipeline/hash_func.h
index 806ac22..f1b9d94 100644
--- a/examples/ip_pipeline/pipeline/hash_func.h
+++ b/examples/ip_pipeline/hash_func.h
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
+ * Copyright(c) 2010-2018 Intel Corporation
  */
+
 #ifndef __INCLUDE_HASH_FUNC_H__
 #define __INCLUDE_HASH_FUNC_H__
 
diff --git a/examples/ip_pipeline/pipeline/hash_func_arm64.h b/examples/ip_pipeline/hash_func_arm64.h
similarity index 100%
rename from examples/ip_pipeline/pipeline/hash_func_arm64.h
rename to examples/ip_pipeline/hash_func_arm64.h
diff --git a/examples/ip_pipeline/init.c b/examples/ip_pipeline/init.c
index f848310..9430809 100644
--- a/examples/ip_pipeline/init.c
+++ b/examples/ip_pipeline/init.c
@@ -24,9 +24,6 @@
 
 #include "app.h"
 #include "pipeline.h"
-#include "pipeline_common_fe.h"
-#include "pipeline_master.h"
-#include "thread_fe.h"
 
 #define APP_NAME_SIZE	32
 
@@ -1328,478 +1325,6 @@ app_init_msgq(struct app_params *app)
 	}
 }
 
-void app_pipeline_params_get(struct app_params *app,
-	struct app_pipeline_params *p_in,
-	struct pipeline_params *p_out)
-{
-	uint32_t i;
-
-	snprintf(p_out->name, PIPELINE_NAME_SIZE, "%s", p_in->name);
-
-	snprintf(p_out->type, PIPELINE_TYPE_SIZE, "%s", p_in->type);
-
-	p_out->socket_id = (int) p_in->socket_id;
-
-	p_out->log_level = app->log_level;
-
-	/* 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];
-
-		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%" SCNu32 ".%" SCNu32,
-				&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:
-		{
-			struct app_pktq_swq_params *swq_params = &app->swq_params[in->id];
-
-			if ((swq_params->ipv4_frag == 0) && (swq_params->ipv6_frag == 0)) {
-				if (app_swq_get_readers(app, swq_params) == 1) {
-					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;
-				} else {
-					out->type = PIPELINE_PORT_IN_RING_MULTI_READER;
-					out->params.ring_multi.ring = app->swq[in->id];
-					out->burst_size = swq_params->burst_read;
-				}
-			} else {
-				if (swq_params->ipv4_frag == 1) {
-					struct rte_port_ring_reader_ipv4_frag_params *params =
-						&out->params.ring_ipv4_frag;
-
-					out->type = PIPELINE_PORT_IN_RING_READER_IPV4_FRAG;
-					params->ring = app->swq[in->id];
-					params->mtu = swq_params->mtu;
-					params->metadata_size = swq_params->metadata_size;
-					params->pool_direct =
-						app->mempool[swq_params->mempool_direct_id];
-					params->pool_indirect =
-						app->mempool[swq_params->mempool_indirect_id];
-					out->burst_size = swq_params->burst_read;
-				} else {
-					struct rte_port_ring_reader_ipv6_frag_params *params =
-						&out->params.ring_ipv6_frag;
-
-					out->type = PIPELINE_PORT_IN_RING_READER_IPV6_FRAG;
-					params->ring = app->swq[in->id];
-					params->mtu = swq_params->mtu;
-					params->metadata_size = swq_params->metadata_size;
-					params->pool_direct =
-						app->mempool[swq_params->mempool_direct_id];
-					params->pool_indirect =
-						app->mempool[swq_params->mempool_indirect_id];
-					out->burst_size = swq_params->burst_read;
-				}
-			}
-			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;
-		}
-#ifdef RTE_EXEC_ENV_LINUXAPP
-		case APP_PKTQ_IN_TAP:
-		{
-			struct app_pktq_tap_params *tap_params =
-				&app->tap_params[in->id];
-			struct app_mempool_params *mempool_params =
-				&app->mempool_params[tap_params->mempool_id];
-			struct rte_mempool *mempool =
-				app->mempool[tap_params->mempool_id];
-
-			out->type = PIPELINE_PORT_IN_FD_READER;
-			out->params.fd.fd = app->tap[in->id];
-			out->params.fd.mtu = mempool_params->buffer_size;
-			out->params.fd.mempool = mempool;
-			out->burst_size = app->tap_params[in->id].burst_read;
-			break;
-		}
-#endif
-#ifdef RTE_LIBRTE_KNI
-		case APP_PKTQ_IN_KNI:
-		{
-			out->type = PIPELINE_PORT_IN_KNI_READER;
-			out->params.kni.kni = app->kni[in->id];
-			out->burst_size = app->kni_params[in->id].burst_read;
-			break;
-		}
-#endif /* RTE_LIBRTE_KNI */
-		case APP_PKTQ_IN_SOURCE:
-		{
-			uint32_t mempool_id =
-				app->source_params[in->id].mempool_id;
-
-			out->type = PIPELINE_PORT_IN_SOURCE;
-			out->params.source.mempool = app->mempool[mempool_id];
-			out->burst_size = app->source_params[in->id].burst;
-			out->params.source.file_name =
-				app->source_params[in->id].file_name;
-			out->params.source.n_bytes_per_pkt =
-				app->source_params[in->id].n_bytes_per_pkt;
-			break;
-		}
-		default:
-			break;
-		}
-	}
-
-	/* 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%" SCNu32 ".%" SCNu32,
-				&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:
-		{
-			struct app_pktq_swq_params *swq_params = &app->swq_params[in->id];
-
-			if ((swq_params->ipv4_ras == 0) && (swq_params->ipv6_ras == 0)) {
-				if (app_swq_get_writers(app, swq_params) == 1) {
-					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;
-					}
-				} else {
-					if (swq_params->dropless == 0) {
-						struct rte_port_ring_multi_writer_params *params =
-							&out->params.ring_multi;
-
-						out->type = PIPELINE_PORT_OUT_RING_MULTI_WRITER;
-						params->ring = app->swq[in->id];
-						params->tx_burst_sz = swq_params->burst_write;
-					} else {
-						struct rte_port_ring_multi_writer_nodrop_params
-							*params = &out->params.ring_multi_nodrop;
-
-						out->type = PIPELINE_PORT_OUT_RING_MULTI_WRITER_NODROP;
-						params->ring = app->swq[in->id];
-						params->tx_burst_sz = swq_params->burst_write;
-						params->n_retries = swq_params->n_retries;
-					}
-				}
-			} else {
-				if (swq_params->ipv4_ras == 1) {
-					struct rte_port_ring_writer_ipv4_ras_params *params =
-						&out->params.ring_ipv4_ras;
-
-					out->type = PIPELINE_PORT_OUT_RING_WRITER_IPV4_RAS;
-					params->ring = app->swq[in->id];
-					params->tx_burst_sz = swq_params->burst_write;
-				} else {
-					struct rte_port_ring_writer_ipv6_ras_params *params =
-						&out->params.ring_ipv6_ras;
-
-					out->type = PIPELINE_PORT_OUT_RING_WRITER_IPV6_RAS;
-					params->ring = app->swq[in->id];
-					params->tx_burst_sz = swq_params->burst_write;
-				}
-			}
-			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;
-		}
-#ifdef RTE_EXEC_ENV_LINUXAPP
-		case APP_PKTQ_OUT_TAP:
-		{
-			struct rte_port_fd_writer_params *params =
-				&out->params.fd;
-
-			out->type = PIPELINE_PORT_OUT_FD_WRITER;
-			params->fd = app->tap[in->id];
-			params->tx_burst_sz =
-				app->tap_params[in->id].burst_write;
-			break;
-		}
-#endif
-#ifdef RTE_LIBRTE_KNI
-		case APP_PKTQ_OUT_KNI:
-		{
-			struct app_pktq_kni_params *p_kni =
-				&app->kni_params[in->id];
-
-			if (p_kni->dropless == 0) {
-				struct rte_port_kni_writer_params *params =
-					&out->params.kni;
-
-				out->type = PIPELINE_PORT_OUT_KNI_WRITER;
-				params->kni = app->kni[in->id];
-				params->tx_burst_sz =
-					app->kni_params[in->id].burst_write;
-			} else {
-				struct rte_port_kni_writer_nodrop_params
-					*params = &out->params.kni_nodrop;
-
-				out->type = PIPELINE_PORT_OUT_KNI_WRITER_NODROP;
-				params->kni = app->kni[in->id];
-				params->tx_burst_sz =
-					app->kni_params[in->id].burst_write;
-				params->n_retries =
-					app->kni_params[in->id].n_retries;
-			}
-			break;
-		}
-#endif /* RTE_LIBRTE_KNI */
-		case APP_PKTQ_OUT_SINK:
-		{
-			out->type = PIPELINE_PORT_OUT_SINK;
-			out->params.sink.file_name =
-				app->sink_params[in->id].file_name;
-			out->params.sink.max_n_pkts =
-				app->sink_params[in->id].
-				n_pkts_to_dump;
-
-			break;
-		}
-		default:
-			break;
-		}
-	}
-
-	/* msgq */
-	p_out->n_msgq = p_in->n_msgq_in;
-
-	for (i = 0; i < p_in->n_msgq_in; i++)
-		p_out->msgq_in[i] = app->msgq[p_in->msgq_in[i]];
-
-	for (i = 0; i < p_in->n_msgq_out; i++)
-		p_out->msgq_out[i] = app->msgq[p_in->msgq_out[i]];
-
-	/* 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];
-	}
-}
-
-static void
-app_init_pipelines(struct app_params *app)
-{
-	uint32_t p_id;
-
-	for (p_id = 0; p_id < app->n_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;
-
-		APP_LOG(app, HIGH, "Initializing %s ...", 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->be_ops->f_init) {
-			data->be = ptype->be_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->ptype = ptype;
-
-		data->timer_period = (rte_get_tsc_hz() *
-			params->timer_period) / 1000;
-	}
-}
-
-static void
-app_post_init_pipelines(struct app_params *app)
-{
-	uint32_t p_id;
-
-	for (p_id = 0; p_id < app->n_pipelines; p_id++) {
-		struct app_pipeline_params *params =
-			&app->pipeline_params[p_id];
-		struct app_pipeline_data *data = &app->pipeline_data[p_id];
-		int status;
-
-		if (data->ptype->fe_ops->f_post_init == NULL)
-			continue;
-
-		status = data->ptype->fe_ops->f_post_init(data->fe);
-		if (status)
-			rte_panic("Pipeline instance \"%s\" front-end "
-				"post-init error\n", params->name);
-	}
-}
-
-static void
-app_init_threads(struct app_params *app)
-{
-	uint64_t time = rte_get_tsc_cycles();
-	uint32_t p_id;
-
-	for (p_id = 0; p_id < app->n_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;
-
-		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%" PRIu32 "c%" PRIu32 "%s\n",
-				params->socket_id,
-				params->core_id,
-				(params->hyper_th_id) ? "h" : "");
-
-		t = &app->thread_data[lcore_id];
-
-		t->timer_period = (rte_get_tsc_hz() * APP_THREAD_TIMER_PERIOD) / 1000;
-		t->thread_req_deadline = time + t->timer_period;
-
-		t->headroom_cycles = 0;
-		t->headroom_time = rte_get_tsc_cycles();
-		t->headroom_ratio = 0.0;
-
-		t->msgq_in = app_thread_msgq_in_get(app,
-				params->socket_id,
-				params->core_id,
-				params->hyper_th_id);
-		if (t->msgq_in == NULL)
-			rte_panic("Init error: Cannot find MSGQ_IN for thread %" PRId32,
-				lcore_id);
-
-		t->msgq_out = app_thread_msgq_out_get(app,
-				params->socket_id,
-				params->core_id,
-				params->hyper_th_id);
-		if (t->msgq_out == NULL)
-			rte_panic("Init error: Cannot find MSGQ_OUT for thread %" PRId32,
-				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->be_ops->f_run == NULL) ?
-			&t->regular[t->n_regular] :
-			&t->custom[t->n_custom];
-
-		p->pipeline_id = p_id;
-		p->be = data->be;
-		p->f_run = ptype->be_ops->f_run;
-		p->f_timer = ptype->be_ops->f_timer;
-		p->timer_period = data->timer_period;
-		p->deadline = time + data->timer_period;
-
-		data->enabled = 1;
-
-		if (ptype->be_ops->f_run == NULL)
-			t->n_regular++;
-		else
-			t->n_custom++;
-	}
-}
-
 int app_init(struct app_params *app)
 {
 	app_init_core_map(app);
@@ -1814,104 +1339,5 @@ int app_init(struct app_params *app)
 	app_init_kni(app);
 	app_init_msgq(app);
 
-	app_pipeline_common_cmd_push(app);
-	app_pipeline_thread_cmd_push(app);
-	app_pipeline_type_register(app, &pipeline_master);
-
-	app_init_pipelines(app);
-	app_init_threads(app);
-
 	return 0;
 }
-
-int app_post_init(struct app_params *app)
-{
-	app_post_init_pipelines(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)
-{
-	uint32_t n_cmds, i;
-
-	/* Check input arguments */
-	if ((app == NULL) ||
-		(ptype == NULL) ||
-		(ptype->name == NULL) ||
-		(strlen(ptype->name) == 0) ||
-		(ptype->be_ops->f_init == NULL) ||
-		(ptype->be_ops->f_timer == 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;
-}
-
-struct
-pipeline_type *app_pipeline_type_find(struct app_params *app, char *name)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_pipeline_types; i++)
-		if (strcmp(app->pipeline_type[i].name, name) == 0)
-			return &app->pipeline_type[i];
-
-	return NULL;
-}
diff --git a/examples/ip_pipeline/meson.build b/examples/ip_pipeline/meson.build
index 1fdfc48..be3f3e5 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -6,9 +6,7 @@
 # To build this example as a standalone application with an already-installed
 # DPDK instance, use 'make'
 
-deps += ['cfgfile', 'pipeline', 'bus_pci']
-allow_experimental_apis = true
-includes += include_directories('pipeline')
+deps += ['cfgfile', 'bus_pci']
 sources = files(
 	'config_check.c',
 	'config_parse.c',
@@ -18,9 +16,4 @@ sources = files(
 	'main.c',
 	'parser.c',
 	'thread.c',
-	'thread_fe.c',
-	'pipeline/pipeline_common_be.c',
-	'pipeline/pipeline_common_fe.c',
-	'pipeline/pipeline_master_be.c',
-	'pipeline/pipeline_master.c',
 )
diff --git a/examples/ip_pipeline/pipeline/pipeline_actions_common.h b/examples/ip_pipeline/pipeline/pipeline_actions_common.h
deleted file mode 100644
index 23f8836..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_actions_common.h
+++ /dev/null
@@ -1,202 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2016 Intel Corporation
- */
-#ifndef __INCLUDE_PIPELINE_ACTIONS_COMMON_H__
-#define __INCLUDE_PIPELINE_ACTIONS_COMMON_H__
-
-#include <stdint.h>
-
-#include <rte_common.h>
-#include <rte_cycles.h>
-#include <rte_mbuf.h>
-#include <rte_pipeline.h>
-
-#define PIPELINE_PORT_IN_AH(f_ah, f_pkt_work, f_pkt4_work)		\
-static int								\
-f_ah(									\
-	__rte_unused struct rte_pipeline *p,				\
-	struct rte_mbuf **pkts,						\
-	uint32_t n_pkts,						\
-	void *arg)							\
-{									\
-	uint32_t i;							\
-									\
-	for (i = 0; i < (n_pkts & (~0x3LLU)); i += 4)			\
-		f_pkt4_work(&pkts[i], arg);				\
-									\
-	for ( ; i < n_pkts; i++)					\
-		f_pkt_work(pkts[i], arg);				\
-									\
-	return 0;							\
-}
-
-#define PIPELINE_PORT_IN_AH_HIJACK_ALL(f_ah, f_pkt_work, f_pkt4_work) \
-static int								\
-f_ah(									\
-	struct rte_pipeline *p,				\
-	struct rte_mbuf **pkts,					\
-	uint32_t n_pkts,						\
-	void *arg)						\
-{									\
-	uint64_t pkt_mask = RTE_LEN2MASK(n_pkts, uint64_t);	\
-	uint32_t i;							\
-									\
-	rte_pipeline_ah_packet_hijack(p, pkt_mask);	\
-									\
-	for (i = 0; i < (n_pkts & (~0x3LLU)); i += 4)	\
-		f_pkt4_work(&pkts[i], arg);				\
-									\
-	for ( ; i < n_pkts; i++)				\
-		f_pkt_work(pkts[i], arg);			\
-									\
-	return 0;							\
-}
-
-#define PIPELINE_TABLE_AH_HIT(f_ah, f_pkt_work, f_pkt4_work)		\
-static int								\
-f_ah(									\
-	__rte_unused struct rte_pipeline *p,				\
-	struct rte_mbuf **pkts,						\
-	uint64_t pkts_in_mask,						\
-	struct rte_pipeline_table_entry **entries,			\
-	void *arg)							\
-{									\
-	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 & (~0x3LLU)); i += 4)		\
-			f_pkt4_work(&pkts[i], &entries[i], arg);	\
-									\
-		for ( ; i < n_pkts; i++)				\
-			f_pkt_work(pkts[i], entries[i], arg);		\
-	} else								\
-		for ( ; pkts_in_mask; ) {				\
-			uint32_t pos = __builtin_ctzll(pkts_in_mask);	\
-			uint64_t pkt_mask = 1LLU << pos;		\
-									\
-			pkts_in_mask &= ~pkt_mask;			\
-			f_pkt_work(pkts[pos], entries[pos], arg);	\
-		}							\
-									\
-	return 0;							\
-}
-
-#define PIPELINE_TABLE_AH_MISS(f_ah, f_pkt_work, f_pkt4_work)		\
-static int								\
-f_ah(									\
-	__rte_unused struct rte_pipeline *p,				\
-	struct rte_mbuf **pkts,						\
-	uint64_t pkts_in_mask,						\
-	struct rte_pipeline_table_entry *entry,				\
-	void *arg)							\
-{									\
-	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 & (~0x3LLU)); i += 4)		\
-			f_pkt4_work(&pkts[i], entry, arg);		\
-									\
-		for ( ; i < n_pkts; i++)				\
-			f_pkt_work(pkts[i], entry, arg);		\
-	} else								\
-		for ( ; pkts_in_mask; ) {				\
-			uint32_t pos = __builtin_ctzll(pkts_in_mask);	\
-			uint64_t pkt_mask = 1LLU << pos;		\
-									\
-			pkts_in_mask &= ~pkt_mask;			\
-			f_pkt_work(pkts[pos], entry, arg);		\
-		}							\
-									\
-	return 0;							\
-}
-
-#define PIPELINE_TABLE_AH_HIT_DROP_TIME(f_ah, f_pkt_work, f_pkt4_work)	\
-static int								\
-f_ah(									\
-	struct rte_pipeline *p,						\
-	struct rte_mbuf **pkts,						\
-	uint64_t pkts_mask,						\
-	struct rte_pipeline_table_entry **entries,			\
-	void *arg)							\
-{									\
-	uint64_t pkts_in_mask = pkts_mask;				\
-	uint64_t pkts_out_mask = pkts_mask;				\
-	uint64_t time = rte_rdtsc();					\
-									\
-	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 & (~0x3LLU)); i += 4) {		\
-			uint64_t mask = f_pkt4_work(&pkts[i],		\
-				&entries[i], arg, time);		\
-			pkts_out_mask ^= mask << i;			\
-		}							\
-									\
-		for ( ; i < n_pkts; i++) {				\
-			uint64_t mask = f_pkt_work(pkts[i],		\
-				entries[i], arg, time);			\
-			pkts_out_mask ^= mask << i;			\
-		}							\
-	} else								\
-		for ( ; pkts_in_mask; ) {				\
-			uint32_t pos = __builtin_ctzll(pkts_in_mask);	\
-			uint64_t pkt_mask = 1LLU << pos;		\
-			uint64_t mask = f_pkt_work(pkts[pos],		\
-				entries[pos], arg, time);		\
-									\
-			pkts_in_mask &= ~pkt_mask;			\
-			pkts_out_mask ^= mask << pos;			\
-		}							\
-									\
-	rte_pipeline_ah_packet_drop(p, pkts_out_mask ^ pkts_mask);	\
-									\
-	return 0;							\
-}
-
-#define PIPELINE_TABLE_AH_MISS_DROP_TIME(f_ah, f_pkt_work, f_pkt4_work)	\
-static int								\
-f_ah(									\
-	struct rte_pipeline *p,						\
-	struct rte_mbuf **pkts,						\
-	uint64_t pkts_mask,						\
-	struct rte_pipeline_table_entry *entry,				\
-	void *arg)							\
-{									\
-	uint64_t pkts_in_mask = pkts_mask;				\
-	uint64_t pkts_out_mask = pkts_mask;				\
-	uint64_t time = rte_rdtsc();					\
-									\
-	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 & (~0x3LLU)); i += 4) {		\
-			uint64_t mask = f_pkt4_work(&pkts[i],		\
-				entry, arg, time);			\
-			pkts_out_mask ^= mask << i;			\
-		}							\
-									\
-		for ( ; i < n_pkts; i++) {				\
-			uint64_t mask = f_pkt_work(pkts[i], entry, arg, time);\
-			pkts_out_mask ^= mask << i;			\
-		}							\
-	} else								\
-		for ( ; pkts_in_mask; ) {				\
-			uint32_t pos = __builtin_ctzll(pkts_in_mask);	\
-			uint64_t pkt_mask = 1LLU << pos;		\
-			uint64_t mask = f_pkt_work(pkts[pos],		\
-				entry, arg, time);		\
-									\
-			pkts_in_mask &= ~pkt_mask;			\
-			pkts_out_mask ^= mask << pos;			\
-		}							\
-									\
-	rte_pipeline_ah_packet_drop(p, pkts_out_mask ^ pkts_mask);	\
-									\
-	return 0;							\
-}
-
-#endif
diff --git a/examples/ip_pipeline/pipeline/pipeline_common_be.c b/examples/ip_pipeline/pipeline/pipeline_common_be.c
deleted file mode 100644
index 5d84989..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_common_be.c
+++ /dev/null
@@ -1,176 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#include <rte_common.h>
-#include <rte_malloc.h>
-
-#include "pipeline_common_be.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(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(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(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(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(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_be.h b/examples/ip_pipeline/pipeline/pipeline_common_be.h
deleted file mode 100644
index 83bd04e..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_common_be.h
+++ /dev/null
@@ -1,134 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#ifndef __INCLUDE_PIPELINE_COMMON_BE_H__
-#define __INCLUDE_PIPELINE_COMMON_BE_H__
-
-#include <rte_common.h>
-#include <rte_ring.h>
-#include <rte_pipeline.h>
-
-#include "pipeline_be.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];
-	uint32_t log_level;
-};
-
-enum pipeline_log_level {
-	PIPELINE_LOG_LEVEL_HIGH = 1,
-	PIPELINE_LOG_LEVEL_LOW,
-	PIPELINE_LOG_LEVELS
-};
-
-#define PLOG(p, level, fmt, ...)					\
-do {									\
-	if (p->log_level >= PIPELINE_LOG_LEVEL_ ## level)		\
-		fprintf(stdout, "[%s] " fmt "\n", p->name, ## __VA_ARGS__);\
-} while (0)
-
-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_common_fe.c b/examples/ip_pipeline/pipeline/pipeline_common_fe.c
deleted file mode 100644
index cc5214c..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_common_fe.c
+++ /dev/null
@@ -1,1455 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2016 Intel Corporation
- */
-
-#include <stdio.h>
-#include <fcntl.h>
-#include <unistd.h>
-
-#include <rte_common.h>
-#include <rte_malloc.h>
-#include <cmdline_rdline.h>
-#include <cmdline_parse.h>
-#include <cmdline_parse_num.h>
-#include <cmdline_parse_string.h>
-#include <cmdline.h>
-
-#include "pipeline_common_fe.h"
-#include "parser.h"
-
-struct app_link_params *
-app_pipeline_track_pktq_out_to_link(struct app_params *app,
-	uint32_t pipeline_id,
-	uint32_t pktq_out_id)
-{
-	struct app_pipeline_params *p;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return NULL;
-
-	APP_PARAM_FIND_BY_ID(app->pipeline_params, "PIPELINE", pipeline_id, p);
-	if (p == NULL)
-		return NULL;
-
-	for ( ; ; ) {
-		struct app_pktq_out_params *pktq_out =
-			&p->pktq_out[pktq_out_id];
-
-		switch (pktq_out->type) {
-		case APP_PKTQ_OUT_HWQ:
-		{
-			struct app_pktq_hwq_out_params *hwq_out;
-
-			hwq_out = &app->hwq_out_params[pktq_out->id];
-
-			return app_get_link_for_txq(app, hwq_out);
-		}
-
-		case APP_PKTQ_OUT_SWQ:
-		{
-			struct pipeline_params pp;
-			struct pipeline_type *ptype;
-			struct app_pktq_swq_params *swq;
-			uint32_t pktq_in_id;
-			int status;
-
-			swq = &app->swq_params[pktq_out->id];
-			p = app_swq_get_reader(app, swq, &pktq_in_id);
-			if (p == NULL)
-				return NULL;
-
-			ptype = app_pipeline_type_find(app, p->type);
-			if ((ptype == NULL) || (ptype->fe_ops->f_track == NULL))
-				return NULL;
-
-			app_pipeline_params_get(app, p, &pp);
-			status = ptype->fe_ops->f_track(&pp,
-				pktq_in_id,
-				&pktq_out_id);
-			if (status)
-				return NULL;
-
-			break;
-		}
-
-		case APP_PKTQ_OUT_TM:
-		{
-			struct pipeline_params pp;
-			struct pipeline_type *ptype;
-			struct app_pktq_tm_params *tm;
-			uint32_t pktq_in_id;
-			int status;
-
-			tm = &app->tm_params[pktq_out->id];
-			p = app_tm_get_reader(app, tm, &pktq_in_id);
-			if (p == NULL)
-				return NULL;
-
-			ptype = app_pipeline_type_find(app, p->type);
-			if ((ptype == NULL) || (ptype->fe_ops->f_track == NULL))
-				return NULL;
-
-			app_pipeline_params_get(app, p, &pp);
-			status = ptype->fe_ops->f_track(&pp,
-				pktq_in_id,
-				&pktq_out_id);
-			if (status)
-				return NULL;
-
-			break;
-		}
-
-		case APP_PKTQ_OUT_KNI:
-		{
-			struct pipeline_params pp;
-			struct pipeline_type *ptype;
-			struct app_pktq_kni_params *kni;
-			uint32_t pktq_in_id;
-			int status;
-
-			kni = &app->kni_params[pktq_out->id];
-			p = app_kni_get_reader(app, kni, &pktq_in_id);
-			if (p == NULL)
-				return NULL;
-
-			ptype = app_pipeline_type_find(app, p->type);
-			if ((ptype == NULL) || (ptype->fe_ops->f_track == NULL))
-				return NULL;
-
-			app_pipeline_params_get(app, p, &pp);
-			status = ptype->fe_ops->f_track(&pp,
-				pktq_in_id,
-				&pktq_out_id);
-			if (status)
-				return NULL;
-
-			break;
-		}
-
-		case APP_PKTQ_OUT_TAP:
-		case APP_PKTQ_OUT_SINK:
-		default:
-			return NULL;
-		}
-	}
-}
-
-int
-app_pipeline_track_default(struct pipeline_params *p,
-	uint32_t port_in,
-	uint32_t *port_out)
-{
-	/* Check input arguments */
-	if ((p == NULL) ||
-		(port_in >= p->n_ports_in) ||
-		(port_out == NULL))
-		return -1;
-
-	if (p->n_ports_out == 1) {
-		*port_out = 0;
-		return 0;
-	}
-
-	return -1;
-}
-
-int
-app_pipeline_ping(struct app_params *app,
-	uint32_t pipeline_id)
-{
-	struct app_pipeline_params *p;
-	struct pipeline_msg_req *req;
-	struct pipeline_msg_rsp *rsp;
-	int status = 0;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	APP_PARAM_FIND_BY_ID(app->pipeline_params, "PIPELINE", pipeline_id, p);
-	if (p == NULL)
-		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, MSG_TIMEOUT_DEFAULT);
-	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 app_pipeline_params *p;
-	struct pipeline_stats_msg_req *req;
-	struct pipeline_stats_port_in_msg_rsp *rsp;
-	int status = 0;
-
-	/* Check input arguments */
-	if ((app == NULL) ||
-		(stats == NULL))
-		return -1;
-
-	APP_PARAM_FIND_BY_ID(app->pipeline_params, "PIPELINE", pipeline_id, p);
-	if ((p == NULL) ||
-		(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, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	/* Check response */
-	status = rsp->status;
-	if (status == 0)
-		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 app_pipeline_params *p;
-	struct pipeline_stats_msg_req *req;
-	struct pipeline_stats_port_out_msg_rsp *rsp;
-	int status = 0;
-
-	/* Check input arguments */
-	if ((app == NULL) ||
-		(pipeline_id >= app->n_pipelines) ||
-		(stats == NULL))
-		return -1;
-
-	APP_PARAM_FIND_BY_ID(app->pipeline_params, "PIPELINE", pipeline_id, p);
-	if ((p == NULL) ||
-		(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, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	/* Check response */
-	status = rsp->status;
-	if (status == 0)
-		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 app_pipeline_params *p;
-	struct pipeline_stats_msg_req *req;
-	struct pipeline_stats_table_msg_rsp *rsp;
-	int status = 0;
-
-	/* Check input arguments */
-	if ((app == NULL) ||
-		(stats == NULL))
-		return -1;
-
-	APP_PARAM_FIND_BY_ID(app->pipeline_params, "PIPELINE", pipeline_id, p);
-	if (p == 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, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	/* Check response */
-	status = rsp->status;
-	if (status == 0)
-		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 app_pipeline_params *p;
-	struct pipeline_port_in_msg_req *req;
-	struct pipeline_msg_rsp *rsp;
-	int status = 0;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	APP_PARAM_FIND_BY_ID(app->pipeline_params, "PIPELINE", pipeline_id, p);
-	if ((p == NULL) ||
-		(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, MSG_TIMEOUT_DEFAULT);
-	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 app_pipeline_params *p;
-	struct pipeline_port_in_msg_req *req;
-	struct pipeline_msg_rsp *rsp;
-	int status = 0;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	APP_PARAM_FIND_BY_ID(app->pipeline_params, "PIPELINE", pipeline_id, p);
-	if ((p == NULL) ||
-		(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, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	/* Check response */
-	status = rsp->status;
-
-	/* Message buffer free */
-	app_msg_free(app, rsp);
-
-	return status;
-}
-
-int
-app_link_set_op(struct app_params *app,
-	uint32_t link_id,
-	uint32_t pipeline_id,
-	app_link_op op,
-	void *arg)
-{
-	struct app_pipeline_params *pp;
-	struct app_link_params *lp;
-	struct app_link_data *ld;
-	uint32_t ppos, lpos;
-
-	/* Check input arguments */
-	if ((app == NULL) ||
-		(op == NULL))
-		return -1;
-
-	APP_PARAM_FIND_BY_ID(app->link_params, "LINK", link_id, lp);
-	if (lp == NULL)
-		return -1;
-	lpos = lp - app->link_params;
-	ld = &app->link_data[lpos];
-
-	APP_PARAM_FIND_BY_ID(app->pipeline_params, "PIPELINE", pipeline_id, pp);
-	if (pp == NULL)
-		return -1;
-	ppos = pp - app->pipeline_params;
-
-	ld->f_link[ppos] = op;
-	ld->arg[ppos] = arg;
-
-	return 0;
-}
-
-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;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	APP_PARAM_FIND_BY_ID(app->link_params, "LINK", link_id, p);
-	if (p == NULL) {
-		APP_LOG(app, HIGH, "LINK%" PRIu32 " is not a valid link",
-			link_id);
-		return -1;
-	}
-
-	if (p->state) {
-		APP_LOG(app, HIGH, "%s is UP, please bring it DOWN first",
-			p->name);
-		return -1;
-	}
-
-	netmask = (~0U) << (32 - depth);
-	host = ip & netmask;
-	bcast = host | (~netmask);
-
-	if ((ip == 0) ||
-		(ip == UINT32_MAX) ||
-		(ip == host) ||
-		(ip == bcast)) {
-		APP_LOG(app, HIGH, "Illegal IP address");
-		return -1;
-	}
-
-	for (i = 0; i < app->n_links; i++) {
-		struct app_link_params *link = &app->link_params[i];
-
-		if (strcmp(p->name, link->name) == 0)
-			continue;
-
-		if (link->ip == ip) {
-			APP_LOG(app, HIGH,
-				"%s is already assigned this IP address",
-				link->name);
-			return -1;
-		}
-	}
-
-	if ((depth == 0) || (depth > 32)) {
-		APP_LOG(app, HIGH, "Illegal value for depth parameter "
-			"(%" PRIu32 ")",
-			depth);
-		return -1;
-	}
-
-	/* Save link parameters */
-	p->ip = ip;
-	p->depth = depth;
-
-	return 0;
-}
-
-int
-app_link_up(struct app_params *app,
-	uint32_t link_id)
-{
-	struct app_link_params *p;
-	struct app_link_data *d;
-	int i;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	APP_PARAM_FIND_BY_ID(app->link_params, "LINK", link_id, p);
-	if (p == NULL) {
-		APP_LOG(app, HIGH, "LINK%" PRIu32 " is not a valid link",
-			link_id);
-		return -1;
-	}
-
-	d = &app->link_data[p - app->link_params];
-
-	/* Check link state */
-	if (p->state) {
-		APP_LOG(app, HIGH, "%s is already UP", p->name);
-		return 0;
-	}
-
-	/* Check that IP address is valid */
-	if (p->ip == 0) {
-		APP_LOG(app, HIGH, "%s IP address is not set", p->name);
-		return 0;
-	}
-
-	app_link_up_internal(app, p);
-
-	/* Callbacks */
-	for (i = 0; i < APP_MAX_PIPELINES; i++)
-		if (d->f_link[i])
-			d->f_link[i](app, link_id, 1, d->arg[i]);
-
-	return 0;
-}
-
-int
-app_link_down(struct app_params *app,
-	uint32_t link_id)
-{
-	struct app_link_params *p;
-	struct app_link_data *d;
-	uint32_t i;
-
-	/* Check input arguments */
-	if (app == NULL)
-		return -1;
-
-	APP_PARAM_FIND_BY_ID(app->link_params, "LINK", link_id, p);
-	if (p == NULL) {
-		APP_LOG(app, HIGH, "LINK%" PRIu32 " is not a valid link",
-			link_id);
-		return -1;
-	}
-
-	d = &app->link_data[p - app->link_params];
-
-	/* Check link state */
-	if (p->state == 0) {
-		APP_LOG(app, HIGH, "%s is already DOWN", p->name);
-		return 0;
-	}
-
-	app_link_down_internal(app, p);
-
-	/* Callbacks */
-	for (i = 0; i < APP_MAX_PIPELINES; i++)
-		if (d->f_link[i])
-			d->f_link[i](app, link_id, 0, d->arg[i]);
-
-	return 0;
-}
-
-/*
- * 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("Command failed\n");
-}
-
-static cmdline_parse_token_string_t cmd_ping_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_ping_result, p_string, "p");
-
-static cmdline_parse_token_num_t cmd_ping_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_ping_result, pipeline_id, UINT32);
-
-static cmdline_parse_token_string_t cmd_ping_ping_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_ping_result, ping_string, "ping");
-
-static cmdline_parse_inst_t cmd_ping = {
-	.f = cmd_ping_parsed,
-	.data = NULL,
-	.help_str = "Pipeline ping",
-	.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("Command failed\n");
-		return;
-	}
-
-	/* Display stats */
-	printf("Pipeline %" PRIu32 " - stats for input port %" PRIu32 ":\n"
-		"\tPkts in: %" PRIu64 "\n"
-		"\tPkts dropped by AH: %" PRIu64 "\n"
-		"\tPkts dropped by other: %" PRIu64 "\n",
-		params->pipeline_id,
-		params->port_in_id,
-		stats.stats.n_pkts_in,
-		stats.n_pkts_dropped_by_ah,
-		stats.stats.n_pkts_drop);
-}
-
-static cmdline_parse_token_string_t cmd_stats_port_in_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_stats_port_in_result, p_string,
-		"p");
-
-static cmdline_parse_token_num_t cmd_stats_port_in_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_stats_port_in_result, pipeline_id,
-		UINT32);
-
-static cmdline_parse_token_string_t cmd_stats_port_in_stats_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_stats_port_in_result, stats_string,
-		"stats");
-
-static cmdline_parse_token_string_t cmd_stats_port_in_port_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_stats_port_in_result, port_string,
-		"port");
-
-static 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);
-
-static cmdline_parse_inst_t cmd_stats_port_in = {
-	.f = cmd_stats_port_in_parsed,
-	.data = NULL,
-	.help_str = "Pipeline input port stats",
-	.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("Command failed\n");
-		return;
-	}
-
-	/* Display stats */
-	printf("Pipeline %" PRIu32 " - stats for output port %" PRIu32 ":\n"
-		"\tPkts in: %" PRIu64 "\n"
-		"\tPkts dropped by AH: %" PRIu64 "\n"
-		"\tPkts dropped by other: %" PRIu64 "\n",
-		params->pipeline_id,
-		params->port_out_id,
-		stats.stats.n_pkts_in,
-		stats.n_pkts_dropped_by_ah,
-		stats.stats.n_pkts_drop);
-}
-
-static cmdline_parse_token_string_t cmd_stats_port_out_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_stats_port_out_result, p_string,
-	"p");
-
-static cmdline_parse_token_num_t cmd_stats_port_out_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_stats_port_out_result, pipeline_id,
-		UINT32);
-
-static cmdline_parse_token_string_t cmd_stats_port_out_stats_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_stats_port_out_result, stats_string,
-		"stats");
-
-static cmdline_parse_token_string_t cmd_stats_port_out_port_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_stats_port_out_result, port_string,
-		"port");
-
-static cmdline_parse_token_string_t cmd_stats_port_out_out_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_stats_port_out_result, out_string,
-		"out");
-
-static 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);
-
-static cmdline_parse_inst_t cmd_stats_port_out = {
-	.f = cmd_stats_port_out_parsed,
-	.data = NULL,
-	.help_str = "Pipeline output port stats",
-	.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("Command failed\n");
-		return;
-	}
-
-	/* Display stats */
-	printf("Pipeline %" PRIu32 " - stats for table %" PRIu32 ":\n"
-		"\tPkts in: %" PRIu64 "\n"
-		"\tPkts in with lookup miss: %" PRIu64 "\n"
-		"\tPkts in with lookup hit dropped by AH: %" PRIu64 "\n"
-		"\tPkts in with lookup hit dropped by others: %" PRIu64 "\n"
-		"\tPkts in with lookup miss dropped by AH: %" PRIu64 "\n"
-		"\tPkts in with lookup miss dropped by others: %" PRIu64 "\n",
-		params->pipeline_id,
-		params->table_id,
-		stats.stats.n_pkts_in,
-		stats.stats.n_pkts_lookup_miss,
-		stats.n_pkts_dropped_by_lkp_hit_ah,
-		stats.n_pkts_dropped_lkp_hit,
-		stats.n_pkts_dropped_by_lkp_miss_ah,
-		stats.n_pkts_dropped_lkp_miss);
-}
-
-static cmdline_parse_token_string_t cmd_stats_table_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_stats_table_result, p_string,
-		"p");
-
-static cmdline_parse_token_num_t cmd_stats_table_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_stats_table_result, pipeline_id,
-		UINT32);
-
-static cmdline_parse_token_string_t cmd_stats_table_stats_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_stats_table_result, stats_string,
-		"stats");
-
-static cmdline_parse_token_string_t cmd_stats_table_table_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_stats_table_result, table_string,
-		"table");
-
-static cmdline_parse_token_num_t cmd_stats_table_table_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_stats_table_result, table_id, UINT32);
-
-static cmdline_parse_inst_t cmd_stats_table = {
-	.f = cmd_stats_table_parsed,
-	.data = NULL,
-	.help_str = "Pipeline table stats",
-	.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("Command failed\n");
-}
-
-static cmdline_parse_token_string_t cmd_port_in_enable_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_port_in_enable_result, p_string,
-		"p");
-
-static cmdline_parse_token_num_t cmd_port_in_enable_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_port_in_enable_result, pipeline_id,
-		UINT32);
-
-static cmdline_parse_token_string_t cmd_port_in_enable_port_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_port_in_enable_result, port_string,
-	"port");
-
-static cmdline_parse_token_string_t cmd_port_in_enable_in_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_port_in_enable_result, in_string,
-		"in");
-
-static 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);
-
-static cmdline_parse_token_string_t cmd_port_in_enable_enable_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_port_in_enable_result,
-		enable_string, "enable");
-
-static 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("Command failed\n");
-}
-
-static cmdline_parse_token_string_t cmd_port_in_disable_p_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_port_in_disable_result, p_string,
-		"p");
-
-static cmdline_parse_token_num_t cmd_port_in_disable_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_port_in_disable_result, pipeline_id,
-		UINT32);
-
-static cmdline_parse_token_string_t cmd_port_in_disable_port_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_port_in_disable_result, port_string,
-		"port");
-
-static cmdline_parse_token_string_t cmd_port_in_disable_in_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_port_in_disable_result, in_string,
-		"in");
-
-static 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);
-
-static cmdline_parse_token_string_t cmd_port_in_disable_disable_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_port_in_disable_result,
-		disable_string, "disable");
-
-static 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,
-	},
-};
-
-/*
- * 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 = (~0U) << (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;
-
-	if (strlen(p->pci_bdf))
-		printf("%s(%s): flags=<%s>\n",
-			p->name,
-			p->pci_bdf,
-			(p->state) ? "UP" : "DOWN");
-	else
-		printf("%s: flags=<%s>\n",
-			p->name,
-			(p->state) ? "UP" : "DOWN");
-
-	if (p->ip)
-		printf("\tinet %" PRIu32 ".%" PRIu32
-			".%" PRIu32 ".%" PRIu32
-			" netmask %" PRIu32 ".%" PRIu32
-			".%" PRIu32 ".%" PRIu32 " "
-			"broadcast %" PRIu32 ".%" PRIu32
-			".%" PRIu32 ".%" PRIu32 "\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 %02" PRIx32 ":%02" PRIx32 ":%02" PRIx32
-		":%02" PRIx32 ":%02" PRIx32 ":%02" PRIx32 "\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 errors %" PRIu64
-		"  missed %" PRIu64
-		"  no-mbuf %" PRIu64
-		"\n",
-		stats.ierrors,
-		stats.imissed,
-		stats.rx_nombuf);
-
-	printf("\tTX packets %" PRIu64
-		"  bytes %" PRIu64 "\n",
-		stats.opackets,
-		stats.obytes);
-
-	printf("\tTX errors %" PRIu64
-		"\n",
-		stats.oerrors);
-
-	printf("\n");
-}
-
-/*
- * link
- *
- * link config:
- *    link <linkid> config <ipaddr> <depth>
- *
- * link up:
- *    link <linkid> up
- *
- * link down:
- *    link <linkid> down
- *
- * link ls:
- *    link ls
- */
-
-struct cmd_link_result {
-	cmdline_fixed_string_t link_string;
-	cmdline_multi_string_t multi_string;
-};
-
-static void
-cmd_link_parsed(
-	void *parsed_result,
-	__attribute__((unused)) struct cmdline *cl,
-	 void *data)
-{
-	struct cmd_link_result *params = parsed_result;
-	struct app_params *app = data;
-
-	char *tokens[16];
-	uint32_t n_tokens = RTE_DIM(tokens);
-	int status;
-
-	uint32_t link_id;
-
-	status = parse_tokenize_string(params->multi_string, tokens, &n_tokens);
-	if (status != 0) {
-		printf(CMD_MSG_TOO_MANY_ARGS, "link");
-		return;
-	}
-
-	/* link ls */
-	if ((n_tokens == 1) && (strcmp(tokens[0], "ls") == 0)) {
-		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);
-		}
-		return;
-	} /* link ls */
-
-	if (n_tokens < 2) {
-		printf(CMD_MSG_MISMATCH_ARGS, "link");
-		return;
-	}
-
-	if (parser_read_uint32(&link_id, tokens[0])) {
-		printf(CMD_MSG_INVALID_ARG, "linkid");
-		return;
-	}
-
-	/* link config */
-	if (strcmp(tokens[1], "config") == 0) {
-		struct in_addr ipaddr_ipv4;
-		uint32_t depth;
-
-		if (n_tokens != 4) {
-			printf(CMD_MSG_MISMATCH_ARGS, "link config");
-			return;
-		}
-
-		if (parse_ipv4_addr(tokens[2], &ipaddr_ipv4)) {
-			printf(CMD_MSG_INVALID_ARG, "ipaddr");
-			return;
-		}
-
-		if (parser_read_uint32(&depth, tokens[3])) {
-			printf(CMD_MSG_INVALID_ARG, "depth");
-			return;
-		}
-
-		status = app_link_config(app,
-			link_id,
-			rte_be_to_cpu_32(ipaddr_ipv4.s_addr),
-			depth);
-		if (status)
-			printf(CMD_MSG_FAIL, "link config");
-
-		return;
-	} /* link config */
-
-	/* link up */
-	if (strcmp(tokens[1], "up") == 0) {
-		if (n_tokens != 2) {
-			printf(CMD_MSG_MISMATCH_ARGS, "link up");
-			return;
-		}
-
-		status = app_link_up(app, link_id);
-		if (status)
-			printf(CMD_MSG_FAIL, "link up");
-
-		return;
-	} /* link up */
-
-	/* link down */
-	if (strcmp(tokens[1], "down") == 0) {
-		if (n_tokens != 2) {
-			printf(CMD_MSG_MISMATCH_ARGS, "link down");
-			return;
-		}
-
-		status = app_link_down(app, link_id);
-		if (status)
-			printf(CMD_MSG_FAIL, "link down");
-
-		return;
-	} /* link down */
-
-	printf(CMD_MSG_MISMATCH_ARGS, "link");
-}
-
-static cmdline_parse_token_string_t cmd_link_link_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_link_result, link_string, "link");
-
-static cmdline_parse_token_string_t cmd_link_multi_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_link_result, multi_string,
-	TOKEN_STRING_MULTI);
-
-static cmdline_parse_inst_t cmd_link = {
-	.f = cmd_link_parsed,
-	.data = NULL,
-	.help_str = "link config / up / down / ls",
-	.tokens = {
-		(void *) &cmd_link_link_string,
-		(void *) &cmd_link_multi_string,
-		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,
-	},
-};
-
-/*
- * run
- *
- *    run <file>
- *    run <file> [<count> [<interval>]]
-	 <count> default is 1
- *       <interval> is measured in milliseconds, default is 1 second
- */
-
-static void
-app_run_file(
-	cmdline_parse_ctx_t *ctx,
-	const char *file_name)
-{
-	struct cmdline *file_cl;
-	int fd;
-
-	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_result {
-	cmdline_fixed_string_t run_string;
-	cmdline_multi_string_t multi_string;
-};
-
-static void
-cmd_run_parsed(
-	void *parsed_result,
-	struct cmdline *cl,
-	__attribute__((unused)) void *data)
-{
-	struct cmd_run_result *params = parsed_result;
-
-	char *tokens[16];
-	uint32_t n_tokens = RTE_DIM(tokens);
-	int status;
-
-	char *file_name;
-	uint32_t count, interval, i;
-
-	status = parse_tokenize_string(params->multi_string, tokens, &n_tokens);
-	if (status) {
-		printf(CMD_MSG_TOO_MANY_ARGS, "run");
-		return;
-	}
-
-	switch (n_tokens) {
-	case 0:
-		printf(CMD_MSG_NOT_ENOUGH_ARGS, "run");
-		return;
-
-	case 1:
-		file_name = tokens[0];
-		count = 1;
-		interval = 1000;
-		break;
-
-	case 2:
-		file_name = tokens[0];
-
-		if (parser_read_uint32(&count, tokens[1]) ||
-			(count == 0)) {
-			printf(CMD_MSG_INVALID_ARG, "count");
-			return;
-		}
-
-		interval = 1000;
-		break;
-
-	case 3:
-		file_name = tokens[0];
-
-		if (parser_read_uint32(&count, tokens[1]) ||
-			(count == 0)) {
-			printf(CMD_MSG_INVALID_ARG, "count");
-			return;
-		}
-
-		if (parser_read_uint32(&interval, tokens[2]) ||
-			(interval == 0)) {
-			printf(CMD_MSG_INVALID_ARG, "interval");
-			return;
-		}
-		break;
-
-	default:
-		printf(CMD_MSG_MISMATCH_ARGS, "run");
-		return;
-	}
-
-	for (i = 0; i < count; i++) {
-		app_run_file(cl->ctx, file_name);
-		if (interval)
-			usleep(interval * 1000);
-	}
-}
-
-static cmdline_parse_token_string_t cmd_run_run_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_run_result, run_string, "run");
-
-static cmdline_parse_token_string_t cmd_run_multi_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_run_result, multi_string,
-	TOKEN_STRING_MULTI);
-
-
-static 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_multi_string,
-		NULL,
-	},
-};
-
-static cmdline_parse_ctx_t pipeline_common_cmds[] = {
-	(cmdline_parse_inst_t *) &cmd_quit,
-	(cmdline_parse_inst_t *) &cmd_run,
-	(cmdline_parse_inst_t *) &cmd_link,
-	(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,
-	NULL,
-};
-
-int
-app_pipeline_common_cmd_push(struct app_params *app)
-{
-	uint32_t n_cmds, i;
-
-	/* Check for available slots in the application commands array */
-	n_cmds = RTE_DIM(pipeline_common_cmds) - 1;
-	if (n_cmds > APP_MAX_CMDS - app->n_cmds)
-		return -ENOMEM;
-
-	/* Push pipeline commands into the application */
-	memcpy(&app->cmds[app->n_cmds],
-		pipeline_common_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;
-}
diff --git a/examples/ip_pipeline/pipeline/pipeline_common_fe.h b/examples/ip_pipeline/pipeline/pipeline_common_fe.h
deleted file mode 100644
index 7227544..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_common_fe.h
+++ /dev/null
@@ -1,231 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#ifndef __INCLUDE_PIPELINE_COMMON_FE_H__
-#define __INCLUDE_PIPELINE_COMMON_FE_H__
-
-#include <rte_common.h>
-#include <rte_cycles.h>
-#include <rte_malloc.h>
-#include <cmdline_parse.h>
-
-#include "pipeline_common_be.h"
-#include "pipeline.h"
-#include "app.h"
-
-#ifndef MSG_TIMEOUT_DEFAULT
-#define MSG_TIMEOUT_DEFAULT                      1000
-#endif
-
-static inline struct app_pipeline_data *
-app_pipeline_data(struct app_params *app, uint32_t id)
-{
-	struct app_pipeline_params *params;
-
-	APP_PARAM_FIND_BY_ID(app->pipeline_params, "PIPELINE", id, params);
-	if (params == NULL)
-		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 pipeline_type *ptype)
-{
-	struct app_pipeline_data *pipeline_data;
-
-	pipeline_data = app_pipeline_data(app, id);
-	if (pipeline_data == NULL)
-		return NULL;
-
-	if (strcmp(pipeline_data->ptype->name, ptype->name) != 0)
-		return NULL;
-
-	if (pipeline_data->enabled == 0)
-		return NULL;
-
-	return pipeline_data->fe;
-}
-
-static inline struct rte_ring *
-app_pipeline_msgq_in_get(struct app_params *app,
-	uint32_t pipeline_id)
-{
-	struct app_msgq_params *p;
-
-	APP_PARAM_FIND_BY_ID(app->msgq_params,
-		"MSGQ-REQ-PIPELINE",
-		pipeline_id,
-		p);
-	if (p == NULL)
-		return NULL;
-
-	return app->msgq[p - app->msgq_params];
-}
-
-static inline struct rte_ring *
-app_pipeline_msgq_out_get(struct app_params *app,
-	uint32_t pipeline_id)
-{
-	struct app_msgq_params *p;
-
-	APP_PARAM_FIND_BY_ID(app->msgq_params,
-		"MSGQ-RSP-PIPELINE",
-		pipeline_id,
-		p);
-	if (p == NULL)
-		return NULL;
-
-	return app->msgq[p - app->msgq_params];
-}
-
-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;
-}
-
-struct app_link_params *
-app_pipeline_track_pktq_out_to_link(struct app_params *app,
-	uint32_t pipeline_id,
-	uint32_t pktq_out_id);
-
-int
-app_pipeline_track_default(struct pipeline_params *params,
-	uint32_t port_in,
-	uint32_t *port_out);
-
-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_set_op(struct app_params *app,
-	uint32_t link_id,
-	uint32_t pipeline_id,
-	app_link_op op,
-	void *arg);
-
-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);
-
-int
-app_pipeline_common_cmd_push(struct app_params *app);
-
-#define CMD_MSG_OUT_OF_MEMORY	"Not enough memory\n"
-#define CMD_MSG_NOT_ENOUGH_ARGS	"Not enough arguments for command \"%s\"\n"
-#define CMD_MSG_TOO_MANY_ARGS	"Too many arguments for command \"%s\"\n"
-#define CMD_MSG_MISMATCH_ARGS	"Incorrect set of arguments for command \"%s\"\n"
-#define CMD_MSG_INVALID_ARG	"Invalid value for argument \"%s\"\n"
-#define CMD_MSG_ARG_NOT_FOUND	"Syntax error: \"%s\" not found\n"
-#define CMD_MSG_FILE_ERR	"Error in file \"%s\" at line %u\n"
-#define CMD_MSG_FAIL		"Command \"%s\" failed\n"
-
-#endif
diff --git a/examples/ip_pipeline/pipeline/pipeline_master.c b/examples/ip_pipeline/pipeline/pipeline_master.c
deleted file mode 100644
index b0d730a..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_master.c
+++ /dev/null
@@ -1,20 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#include "pipeline_master.h"
-#include "pipeline_master_be.h"
-
-static struct pipeline_fe_ops pipeline_master_fe_ops = {
-	.f_init = NULL,
-	.f_post_init = NULL,
-	.f_free = NULL,
-	.f_track = NULL,
-	.cmds = NULL,
-};
-
-struct pipeline_type pipeline_master = {
-	.name = "MASTER",
-	.be_ops = &pipeline_master_be_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
deleted file mode 100644
index a5183e3..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_master.h
+++ /dev/null
@@ -1,12 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#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_be.c b/examples/ip_pipeline/pipeline/pipeline_master_be.c
deleted file mode 100644
index c72038e..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_master_be.c
+++ /dev/null
@@ -1,141 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#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_be.h"
-
-struct pipeline_master {
-	struct app_params *app;
-	struct cmdline *cl;
-	int post_init_done;
-	int script_file_done;
-} __rte_cache_aligned;
-
-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 (app == NULL)
-		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;
-
-	/* Initialization */
-	p->app = app;
-
-	p->cl = cmdline_stdin_new(app->cmds, "pipeline> ");
-	if (p->cl == NULL) {
-		rte_free(p);
-		return NULL;
-	}
-
-	p->post_init_done = 0;
-	p->script_file_done = 0;
-	if (app->script_file == NULL)
-		p->script_file_done = 1;
-
-	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;
-	struct app_params *app = p->app;
-	int status;
-#ifdef RTE_LIBRTE_KNI
-	uint32_t i;
-#endif /* RTE_LIBRTE_KNI */
-
-	/* Application post-init phase */
-	if (p->post_init_done == 0) {
-		app_post_init(app);
-
-		p->post_init_done = 1;
-	}
-
-	/* Run startup script file */
-	if (p->script_file_done == 0) {
-		struct app_params *app = p->app;
-		int fd = open(app->script_file, O_RDONLY);
-
-		if (fd < 0)
-			printf("Cannot open CLI script file \"%s\"\n",
-				app->script_file);
-		else {
-			struct cmdline *file_cl;
-
-			printf("Running CLI script file \"%s\" ...\n",
-				app->script_file);
-			file_cl = cmdline_new(p->cl->ctx, "", fd, 1);
-			cmdline_interact(file_cl);
-			close(fd);
-		}
-
-		p->script_file_done = 1;
-	}
-
-	/* Command Line Interface (CLI) */
-	status = cmdline_poll(p->cl);
-	if (status < 0)
-		rte_panic("CLI poll error (%" PRId32 ")\n", status);
-	else if (status == RDLINE_EXITED) {
-		cmdline_stdin_exit(p->cl);
-		rte_exit(0, "Bye!\n");
-	}
-
-#ifdef RTE_LIBRTE_KNI
-	/* Handle KNI requests from Linux kernel */
-	for (i = 0; i < app->n_pktq_kni; i++)
-		rte_kni_handle_request(app->kni[i]);
-#endif /* RTE_LIBRTE_KNI */
-
-	return 0;
-}
-
-static int
-pipeline_timer(__rte_unused void *pipeline)
-{
-	return 0;
-}
-
-struct pipeline_be_ops pipeline_master_be_ops = {
-		.f_init = pipeline_init,
-		.f_free = pipeline_free,
-		.f_run = pipeline_run,
-		.f_timer = pipeline_timer,
-};
diff --git a/examples/ip_pipeline/pipeline/pipeline_master_be.h b/examples/ip_pipeline/pipeline/pipeline_master_be.h
deleted file mode 100644
index 847c564..0000000
--- a/examples/ip_pipeline/pipeline/pipeline_master_be.h
+++ /dev/null
@@ -1,12 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#ifndef __INCLUDE_PIPELINE_MASTER_BE_H__
-#define __INCLUDE_PIPELINE_MASTER_BE_H__
-
-#include "pipeline_common_be.h"
-
-extern struct pipeline_be_ops pipeline_master_be_ops;
-
-#endif
diff --git a/examples/ip_pipeline/thread.c b/examples/ip_pipeline/thread.c
index 9013afd..a36bf92 100644
--- a/examples/ip_pipeline/thread.c
+++ b/examples/ip_pipeline/thread.c
@@ -6,47 +6,9 @@
 #include <rte_cycles.h>
 #include <rte_pipeline.h>
 
-#include "pipeline_common_be.h"
 #include "app.h"
 #include "thread.h"
 
-#if APP_THREAD_HEADROOM_STATS_COLLECT
-
-#define PIPELINE_RUN_REGULAR(thread, pipeline)		\
-do {							\
-	uint64_t t0 = rte_rdtsc_precise();		\
-	int n_pkts = rte_pipeline_run(pipeline->p);	\
-							\
-	if (n_pkts == 0) {				\
-		uint64_t t1 = rte_rdtsc_precise();	\
-							\
-		thread->headroom_cycles += t1 - t0;	\
-	}						\
-} while (0)
-
-
-#define PIPELINE_RUN_CUSTOM(thread, data)		\
-do {							\
-	uint64_t t0 = rte_rdtsc_precise();		\
-	int n_pkts = data->f_run(data->be);		\
-							\
-	if (n_pkts == 0) {				\
-		uint64_t t1 = rte_rdtsc_precise();	\
-							\
-		thread->headroom_cycles += t1 - t0;	\
-	}						\
-} while (0)
-
-#else
-
-#define PIPELINE_RUN_REGULAR(thread, pipeline)		\
-	rte_pipeline_run(pipeline->p)
-
-#define PIPELINE_RUN_CUSTOM(thread, data)		\
-	data->f_run(data->be)
-
-#endif
-
 static inline void *
 thread_msg_recv(struct rte_ring *r)
 {
@@ -214,21 +176,6 @@ app_thread(void *arg)
 		uint32_t n_regular = RTE_MIN(t->n_regular, RTE_DIM(t->regular));
 		uint32_t n_custom = RTE_MIN(t->n_custom, RTE_DIM(t->custom));
 
-		/* Run regular pipelines */
-		for (j = 0; j < n_regular; j++) {
-			struct app_thread_pipeline_data *data = &t->regular[j];
-			struct pipeline *p = data->be;
-
-			PIPELINE_RUN_REGULAR(t, p);
-		}
-
-		/* Run custom pipelines */
-		for (j = 0; j < n_custom; j++) {
-			struct app_thread_pipeline_data *data = &t->custom[j];
-
-			PIPELINE_RUN_CUSTOM(t, data);
-		}
-
 		/* Timer */
 		if ((i & 0xF) == 0) {
 			uint64_t time = rte_get_tsc_cycles();
diff --git a/examples/ip_pipeline/thread_fe.c b/examples/ip_pipeline/thread_fe.c
deleted file mode 100644
index 4590c2b..0000000
--- a/examples/ip_pipeline/thread_fe.c
+++ /dev/null
@@ -1,457 +0,0 @@
-#include <rte_common.h>
-#include <rte_ring.h>
-#include <rte_malloc.h>
-#include <cmdline_rdline.h>
-#include <cmdline_parse.h>
-#include <cmdline_parse_num.h>
-#include <cmdline_parse_string.h>
-
-#include "thread.h"
-#include "thread_fe.h"
-#include "pipeline.h"
-#include "pipeline_common_fe.h"
-#include "app.h"
-
-static inline void *
-thread_msg_send_recv(struct app_params *app,
-	uint32_t socket_id, uint32_t core_id, uint32_t ht_id,
-	void *msg,
-	uint32_t timeout_ms)
-{
-	struct rte_ring *r_req = app_thread_msgq_in_get(app,
-		socket_id, core_id, ht_id);
-	struct rte_ring *r_rsp = app_thread_msgq_out_get(app,
-		socket_id, core_id, ht_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_enable(struct app_params *app,
-		uint32_t socket_id,
-		uint32_t core_id,
-		uint32_t hyper_th_id,
-		uint32_t pipeline_id)
-{
-	struct thread_pipeline_enable_msg_req *req;
-	struct thread_pipeline_enable_msg_rsp *rsp;
-	int thread_id;
-	struct app_pipeline_data *p;
-	struct app_pipeline_params *p_params;
-	struct pipeline_type *p_type;
-	int status;
-
-	if (app == NULL)
-		return -1;
-
-	thread_id = cpu_core_map_get_lcore_id(app->core_map,
-			socket_id,
-			core_id,
-			hyper_th_id);
-
-	if ((thread_id < 0) || !app_core_is_enabled(app, thread_id))
-		return -1;
-
-	if (app_pipeline_data(app, pipeline_id) == NULL)
-		return -1;
-
-	p = &app->pipeline_data[pipeline_id];
-	p_params = &app->pipeline_params[pipeline_id];
-	p_type = app_pipeline_type_find(app, p_params->type);
-
-	if (p_type == NULL)
-		return -1;
-
-	if (p->enabled == 1)
-		return -1;
-
-	req = app_msg_alloc(app);
-	if (req == NULL)
-		return -1;
-
-	req->type = THREAD_MSG_REQ_PIPELINE_ENABLE;
-	req->pipeline_id = pipeline_id;
-	req->be = p->be;
-	req->f_run = p_type->be_ops->f_run;
-	req->f_timer = p_type->be_ops->f_timer;
-	req->timer_period = p->timer_period;
-
-	rsp = thread_msg_send_recv(app,
-		socket_id, core_id, hyper_th_id, req, MSG_TIMEOUT_DEFAULT);
-	if (rsp == NULL)
-		return -1;
-
-	status = rsp->status;
-	app_msg_free(app, rsp);
-
-	if (status != 0)
-		return -1;
-
-	p->enabled = 1;
-	return 0;
-}
-
-int
-app_pipeline_disable(struct app_params *app,
-		uint32_t socket_id,
-		uint32_t core_id,
-		uint32_t hyper_th_id,
-		uint32_t pipeline_id)
-{
-	struct thread_pipeline_disable_msg_req *req;
-	struct thread_pipeline_disable_msg_rsp *rsp;
-	int thread_id;
-	struct app_pipeline_data *p;
-	int status;
-
-	if (app == NULL)
-		return -1;
-
-	thread_id = cpu_core_map_get_lcore_id(app->core_map,
-			socket_id,
-			core_id,
-			hyper_th_id);
-
-	if ((thread_id < 0) || !app_core_is_enabled(app, thread_id))
-		return -1;
-
-	if (app_pipeline_data(app, pipeline_id) == NULL)
-		return -1;
-
-	p = &app->pipeline_data[pipeline_id];
-
-	if (p->enabled == 0)
-		return -1;
-
-	req = app_msg_alloc(app);
-	if (req == NULL)
-		return -1;
-
-	req->type = THREAD_MSG_REQ_PIPELINE_DISABLE;
-	req->pipeline_id = pipeline_id;
-
-	rsp = thread_msg_send_recv(app,
-		socket_id, core_id, hyper_th_id, req, MSG_TIMEOUT_DEFAULT);
-
-	if (rsp == NULL)
-		return -1;
-
-	status = rsp->status;
-	app_msg_free(app, rsp);
-
-	if (status != 0)
-		return -1;
-
-	p->enabled = 0;
-	return 0;
-}
-
-int
-app_thread_headroom(struct app_params *app,
-		uint32_t socket_id,
-		uint32_t core_id,
-		uint32_t hyper_th_id)
-{
-	struct thread_headroom_read_msg_req *req;
-	struct thread_headroom_read_msg_rsp *rsp;
-	int thread_id;
-	int status;
-
-	if (app == NULL)
-		return -1;
-
-	thread_id = cpu_core_map_get_lcore_id(app->core_map,
-			socket_id,
-			core_id,
-			hyper_th_id);
-
-	if ((thread_id < 0) || !app_core_is_enabled(app, thread_id))
-		return -1;
-
-	req = app_msg_alloc(app);
-	if (req == NULL)
-		return -1;
-
-	req->type = THREAD_MSG_REQ_HEADROOM_READ;
-
-	rsp = thread_msg_send_recv(app,
-		socket_id, core_id, hyper_th_id, req, MSG_TIMEOUT_DEFAULT);
-
-	if (rsp == NULL)
-		return -1;
-
-	status = rsp->status;
-
-	if (status != 0)
-		return -1;
-
-	printf("%.3f%%\n", rsp->headroom_ratio * 100);
-
-
-	app_msg_free(app, rsp);
-
-	return 0;
-}
-
-/*
- * pipeline enable
- */
-
-struct cmd_pipeline_enable_result {
-	cmdline_fixed_string_t t_string;
-	cmdline_fixed_string_t t_id_string;
-	cmdline_fixed_string_t pipeline_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t enable_string;
-};
-
-static void
-cmd_pipeline_enable_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	 void *data)
-{
-	struct cmd_pipeline_enable_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
-	uint32_t core_id, socket_id, hyper_th_id;
-
-	if (parse_pipeline_core(&socket_id,
-			&core_id,
-			&hyper_th_id,
-			params->t_id_string) != 0) {
-		printf("Command failed\n");
-		return;
-	}
-
-	status = app_pipeline_enable(app,
-			socket_id,
-			core_id,
-			hyper_th_id,
-			params->pipeline_id);
-
-	if (status != 0)
-		printf("Command failed\n");
-}
-
-static cmdline_parse_token_string_t cmd_pipeline_enable_t_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_pipeline_enable_result, t_string, "t");
-
-static cmdline_parse_token_string_t cmd_pipeline_enable_t_id_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_pipeline_enable_result, t_id_string,
-		NULL);
-
-static cmdline_parse_token_string_t cmd_pipeline_enable_pipeline_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_pipeline_enable_result, pipeline_string,
-		"pipeline");
-
-static cmdline_parse_token_num_t cmd_pipeline_enable_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_pipeline_enable_result, pipeline_id,
-		UINT32);
-
-static cmdline_parse_token_string_t cmd_pipeline_enable_enable_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_pipeline_enable_result, enable_string,
-		"enable");
-
-static cmdline_parse_inst_t cmd_pipeline_enable = {
-	.f = cmd_pipeline_enable_parsed,
-	.data = NULL,
-	.help_str = "Enable pipeline on specified core",
-	.tokens = {
-		(void *)&cmd_pipeline_enable_t_string,
-		(void *)&cmd_pipeline_enable_t_id_string,
-		(void *)&cmd_pipeline_enable_pipeline_string,
-		(void *)&cmd_pipeline_enable_pipeline_id,
-		(void *)&cmd_pipeline_enable_enable_string,
-		NULL,
-	},
-};
-
-/*
- * pipeline disable
- */
-
-struct cmd_pipeline_disable_result {
-	cmdline_fixed_string_t t_string;
-	cmdline_fixed_string_t t_id_string;
-	cmdline_fixed_string_t pipeline_string;
-	uint32_t pipeline_id;
-	cmdline_fixed_string_t disable_string;
-};
-
-static void
-cmd_pipeline_disable_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	 void *data)
-{
-	struct cmd_pipeline_disable_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
-	uint32_t core_id, socket_id, hyper_th_id;
-
-	if (parse_pipeline_core(&socket_id,
-			&core_id,
-			&hyper_th_id,
-			params->t_id_string) != 0) {
-		printf("Command failed\n");
-		return;
-	}
-
-	status = app_pipeline_disable(app,
-			socket_id,
-			core_id,
-			hyper_th_id,
-			params->pipeline_id);
-
-	if (status != 0)
-		printf("Command failed\n");
-}
-
-static cmdline_parse_token_string_t cmd_pipeline_disable_t_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_pipeline_disable_result, t_string, "t");
-
-static cmdline_parse_token_string_t cmd_pipeline_disable_t_id_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_pipeline_disable_result, t_id_string,
-		NULL);
-
-static cmdline_parse_token_string_t cmd_pipeline_disable_pipeline_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_pipeline_disable_result,
-		pipeline_string, "pipeline");
-
-static cmdline_parse_token_num_t cmd_pipeline_disable_pipeline_id =
-	TOKEN_NUM_INITIALIZER(struct cmd_pipeline_disable_result, pipeline_id,
-		UINT32);
-
-static cmdline_parse_token_string_t cmd_pipeline_disable_disable_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_pipeline_disable_result, disable_string,
-		"disable");
-
-static cmdline_parse_inst_t cmd_pipeline_disable = {
-	.f = cmd_pipeline_disable_parsed,
-	.data = NULL,
-	.help_str = "Disable pipeline on specified core",
-	.tokens = {
-		(void *)&cmd_pipeline_disable_t_string,
-		(void *)&cmd_pipeline_disable_t_id_string,
-		(void *)&cmd_pipeline_disable_pipeline_string,
-		(void *)&cmd_pipeline_disable_pipeline_id,
-		(void *)&cmd_pipeline_disable_disable_string,
-		NULL,
-	},
-};
-
-
-/*
- * thread headroom
- */
-
-struct cmd_thread_headroom_result {
-	cmdline_fixed_string_t t_string;
-	cmdline_fixed_string_t t_id_string;
-	cmdline_fixed_string_t headroom_string;
-};
-
-static void
-cmd_thread_headroom_parsed(
-	void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	 void *data)
-{
-	struct cmd_thread_headroom_result *params = parsed_result;
-	struct app_params *app = data;
-	int status;
-	uint32_t core_id, socket_id, hyper_th_id;
-
-	if (parse_pipeline_core(&socket_id,
-			&core_id,
-			&hyper_th_id,
-			params->t_id_string) != 0) {
-		printf("Command failed\n");
-		return;
-	}
-
-	status = app_thread_headroom(app,
-			socket_id,
-			core_id,
-			hyper_th_id);
-
-	if (status != 0)
-		printf("Command failed\n");
-}
-
-static cmdline_parse_token_string_t cmd_thread_headroom_t_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_thread_headroom_result,
-	t_string, "t");
-
-static cmdline_parse_token_string_t cmd_thread_headroom_t_id_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_thread_headroom_result,
-	t_id_string, NULL);
-
-static cmdline_parse_token_string_t cmd_thread_headroom_headroom_string =
-	TOKEN_STRING_INITIALIZER(struct cmd_thread_headroom_result,
-		headroom_string, "headroom");
-
-static cmdline_parse_inst_t cmd_thread_headroom = {
-	.f = cmd_thread_headroom_parsed,
-	.data = NULL,
-	.help_str = "Display thread headroom",
-	.tokens = {
-		(void *)&cmd_thread_headroom_t_string,
-		(void *)&cmd_thread_headroom_t_id_string,
-		(void *)&cmd_thread_headroom_headroom_string,
-		NULL,
-	},
-};
-
-
-static cmdline_parse_ctx_t thread_cmds[] = {
-	(cmdline_parse_inst_t *) &cmd_pipeline_enable,
-	(cmdline_parse_inst_t *) &cmd_pipeline_disable,
-	(cmdline_parse_inst_t *) &cmd_thread_headroom,
-	NULL,
-};
-
-int
-app_pipeline_thread_cmd_push(struct app_params *app)
-{
-	uint32_t n_cmds, i;
-
-	/* Check for available slots in the application commands array */
-	n_cmds = RTE_DIM(thread_cmds) - 1;
-	if (n_cmds > APP_MAX_CMDS - app->n_cmds)
-		return -ENOMEM;
-
-	/* Push thread commands into the application */
-	memcpy(&app->cmds[app->n_cmds], thread_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;
-}
diff --git a/examples/ip_pipeline/thread_fe.h b/examples/ip_pipeline/thread_fe.h
deleted file mode 100644
index 056a5e8..0000000
--- a/examples/ip_pipeline/thread_fe.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#ifndef THREAD_FE_H_
-#define THREAD_FE_H_
-
-static inline struct rte_ring *
-app_thread_msgq_in_get(struct app_params *app,
-		uint32_t socket_id, uint32_t core_id, uint32_t ht_id)
-{
-	char msgq_name[32];
-	ssize_t param_idx;
-
-	snprintf(msgq_name, sizeof(msgq_name),
-		"MSGQ-REQ-CORE-s%" PRIu32 "c%" PRIu32 "%s",
-		socket_id,
-		core_id,
-		(ht_id) ? "h" : "");
-	param_idx = APP_PARAM_FIND(app->msgq_params, msgq_name);
-
-	if (param_idx < 0)
-		return NULL;
-
-	return app->msgq[param_idx];
-}
-
-static inline struct rte_ring *
-app_thread_msgq_out_get(struct app_params *app,
-		uint32_t socket_id, uint32_t core_id, uint32_t ht_id)
-{
-	char msgq_name[32];
-	ssize_t param_idx;
-
-	snprintf(msgq_name, sizeof(msgq_name),
-		"MSGQ-RSP-CORE-s%" PRIu32 "c%" PRIu32 "%s",
-		socket_id,
-		core_id,
-		(ht_id) ? "h" : "");
-	param_idx = APP_PARAM_FIND(app->msgq_params, msgq_name);
-
-	if (param_idx < 0)
-		return NULL;
-
-	return app->msgq[param_idx];
-
-}
-
-int
-app_pipeline_thread_cmd_push(struct app_params *app);
-
-int
-app_pipeline_enable(struct app_params *app,
-		uint32_t core_id,
-		uint32_t socket_id,
-		uint32_t hyper_th_id,
-		uint32_t pipeline_id);
-
-int
-app_pipeline_disable(struct app_params *app,
-		uint32_t core_id,
-		uint32_t socket_id,
-		uint32_t hyper_th_id,
-		uint32_t pipeline_id);
-
-int
-app_thread_headroom(struct app_params *app,
-		uint32_t core_id,
-		uint32_t socket_id,
-		uint32_t hyper_th_id);
-
-#endif /* THREAD_FE_H_ */
-- 
2.9.3

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

* [dpdk-dev] [PATCH v4 19/49] ip_pipeline: remove config
  2018-03-29 18:31           ` [dpdk-dev] [PATCH v4 00/49] ip_pipeline: refactoring Jasvinder Singh
                               ` (17 preceding siblings ...)
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 18/49] ip_pipeline: remove master pipeline Jasvinder Singh
@ 2018-03-29 18:31             ` Jasvinder Singh
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 20/49] ip_pipeline: rework and improvements Jasvinder Singh
                               ` (30 subsequent siblings)
  49 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-29 18:31 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Remove application configuration and script files.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/config/action.cfg             |  68 --
 examples/ip_pipeline/config/action.sh              | 119 ---
 examples/ip_pipeline/config/action.txt             |   8 -
 examples/ip_pipeline/config/diagram-generator.py   | 317 -------
 .../ip_pipeline/config/edge_router_downstream.cfg  |  97 ---
 .../ip_pipeline/config/edge_router_downstream.sh   |  13 -
 .../ip_pipeline/config/edge_router_upstream.cfg    | 124 ---
 .../ip_pipeline/config/edge_router_upstream.sh     |  33 -
 examples/ip_pipeline/config/firewall.cfg           |  68 --
 examples/ip_pipeline/config/firewall.sh            |  13 -
 examples/ip_pipeline/config/firewall.txt           |   9 -
 examples/ip_pipeline/config/flow.cfg               |  72 --
 examples/ip_pipeline/config/flow.sh                |  25 -
 examples/ip_pipeline/config/flow.txt               |  17 -
 examples/ip_pipeline/config/ip_pipeline.cfg        |   9 -
 examples/ip_pipeline/config/ip_pipeline.sh         |   5 -
 examples/ip_pipeline/config/kni.cfg                |  67 --
 examples/ip_pipeline/config/l2fwd.cfg              |  58 --
 examples/ip_pipeline/config/l3fwd.cfg              |  68 --
 examples/ip_pipeline/config/l3fwd.sh               |  33 -
 examples/ip_pipeline/config/l3fwd_arp.cfg          |  70 --
 examples/ip_pipeline/config/l3fwd_arp.sh           |  43 -
 examples/ip_pipeline/config/network_layers.cfg     | 227 ------
 examples/ip_pipeline/config/network_layers.sh      |  79 --
 .../ip_pipeline/config/pipeline-to-core-mapping.py | 906 ---------------------
 examples/ip_pipeline/config/tap.cfg                |  64 --
 examples/ip_pipeline/config/tm_profile.cfg         | 105 ---
 27 files changed, 2717 deletions(-)
 delete mode 100644 examples/ip_pipeline/config/action.cfg
 delete mode 100644 examples/ip_pipeline/config/action.sh
 delete mode 100644 examples/ip_pipeline/config/action.txt
 delete mode 100755 examples/ip_pipeline/config/diagram-generator.py
 delete mode 100644 examples/ip_pipeline/config/edge_router_downstream.cfg
 delete mode 100644 examples/ip_pipeline/config/edge_router_downstream.sh
 delete mode 100644 examples/ip_pipeline/config/edge_router_upstream.cfg
 delete mode 100644 examples/ip_pipeline/config/edge_router_upstream.sh
 delete mode 100644 examples/ip_pipeline/config/firewall.cfg
 delete mode 100644 examples/ip_pipeline/config/firewall.sh
 delete mode 100644 examples/ip_pipeline/config/firewall.txt
 delete mode 100644 examples/ip_pipeline/config/flow.cfg
 delete mode 100644 examples/ip_pipeline/config/flow.sh
 delete mode 100644 examples/ip_pipeline/config/flow.txt
 delete mode 100644 examples/ip_pipeline/config/ip_pipeline.cfg
 delete mode 100644 examples/ip_pipeline/config/ip_pipeline.sh
 delete mode 100644 examples/ip_pipeline/config/kni.cfg
 delete mode 100644 examples/ip_pipeline/config/l2fwd.cfg
 delete mode 100644 examples/ip_pipeline/config/l3fwd.cfg
 delete mode 100644 examples/ip_pipeline/config/l3fwd.sh
 delete mode 100644 examples/ip_pipeline/config/l3fwd_arp.cfg
 delete mode 100644 examples/ip_pipeline/config/l3fwd_arp.sh
 delete mode 100644 examples/ip_pipeline/config/network_layers.cfg
 delete mode 100644 examples/ip_pipeline/config/network_layers.sh
 delete mode 100755 examples/ip_pipeline/config/pipeline-to-core-mapping.py
 delete mode 100644 examples/ip_pipeline/config/tap.cfg
 delete mode 100644 examples/ip_pipeline/config/tm_profile.cfg

diff --git a/examples/ip_pipeline/config/action.cfg b/examples/ip_pipeline/config/action.cfg
deleted file mode 100644
index 994ae94..0000000
--- a/examples/ip_pipeline/config/action.cfg
+++ /dev/null
@@ -1,68 +0,0 @@
-;   BSD LICENSE
-;
-;   Copyright(c) 2016 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.
-
-;             ________________
-; RXQ0.0 --->|                |---> TXQ0.0
-;            |                |
-; RXQ1.0 --->|                |---> TXQ1.0
-;            |      Flow      |
-; RXQ2.0 --->|     Actions    |---> TXQ2.0
-;            |                |
-; RXQ3.0 --->|                |---> TXQ3.0
-;            |________________|
-;
-;
-; Input packet: Ethernet/IPv4
-;
-; Packet buffer layout:
-; #	Field Name		Offset (Bytes)	Size (Bytes)
-; 0	Mbuf			0 		128
-; 1	Headroom		128 		128
-; 2	Ethernet header		256 		14
-; 3	IPv4 header		270 		20
-
-[EAL]
-log_level = 0
-
-[PIPELINE0]
-type = MASTER
-core = 0
-
-[PIPELINE1]
-type = FLOW_ACTIONS
-core = 1
-pktq_in = RXQ0.0 RXQ1.0 RXQ2.0 RXQ3.0
-pktq_out = TXQ0.0 TXQ1.0 TXQ2.0 TXQ3.0
-n_flows = 65536
-n_meters_per_flow = 4
-flow_id_offset = 286; ipdaddr
-ip_hdr_offset = 270
-color_offset = 128
diff --git a/examples/ip_pipeline/config/action.sh b/examples/ip_pipeline/config/action.sh
deleted file mode 100644
index 2986ae6..0000000
--- a/examples/ip_pipeline/config/action.sh
+++ /dev/null
@@ -1,119 +0,0 @@
-#
-# run ./config/action.sh
-#
-
-p 1 action flow 0 meter 0 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 0 policer 0 g G y Y r R
-p 1 action flow 0 meter 1 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 0 policer 1 g G y Y r R
-p 1 action flow 0 meter 2 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 0 policer 2 g G y Y r R
-p 1 action flow 0 meter 3 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 0 policer 3 g G y Y r R
-p 1 action flow 0 port 0
-
-p 1 action flow 1 meter 0 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 1 policer 0 g G y Y r R
-p 1 action flow 1 meter 1 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 1 policer 1 g G y Y r R
-p 1 action flow 1 meter 2 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 1 policer 2 g G y Y r R
-p 1 action flow 1 meter 3 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 1 policer 3 g G y Y r R
-p 1 action flow 1 port 1
-
-p 1 action flow 2 meter 0 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 2 policer 0 g G y Y r R
-p 1 action flow 2 meter 1 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 2 policer 1 g G y Y r R
-p 1 action flow 2 meter 2 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 2 policer 2 g G y Y r R
-p 1 action flow 2 meter 3 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 2 policer 3 g G y Y r R
-p 1 action flow 2 port 2
-
-p 1 action flow 3 meter 0 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 3 policer 0 g G y Y r R
-p 1 action flow 3 meter 1 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 3 policer 1 g G y Y r R
-p 1 action flow 3 meter 2 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 3 policer 2 g G y Y r R
-p 1 action flow 3 meter 3 trtcm 1250000000 1250000000 1000000 1000000
-p 1 action flow 3 policer 3 g G y Y r R
-p 1 action flow 3 port 3
-
-#p 1 action flow bulk ./config/action.txt
-
-#p 1 action flow ls
-
-p 1 action flow 0 stats
-p 1 action flow 1 stats
-p 1 action flow 2 stats
-p 1 action flow 3 stats
-
-p 1 action dscp 0 class 0 color G
-p 1 action dscp 1 class 1 color G
-p 1 action dscp 2 class 2 color G
-p 1 action dscp 3 class 3 color G
-p 1 action dscp 4 class 0 color G
-p 1 action dscp 5 class 1 color G
-p 1 action dscp 6 class 2 color G
-p 1 action dscp 7 class 3 color G
-p 1 action dscp 8 class 0 color G
-p 1 action dscp 9 class 1 color G
-p 1 action dscp 10 class 2 color G
-p 1 action dscp 11 class 3 color G
-p 1 action dscp 12 class 0 color G
-p 1 action dscp 13 class 1 color G
-p 1 action dscp 14 class 2 color G
-p 1 action dscp 15 class 3 color G
-p 1 action dscp 16 class 0 color G
-p 1 action dscp 17 class 1 color G
-p 1 action dscp 18 class 2 color G
-p 1 action dscp 19 class 3 color G
-p 1 action dscp 20 class 0 color G
-p 1 action dscp 21 class 1 color G
-p 1 action dscp 22 class 2 color G
-p 1 action dscp 23 class 3 color G
-p 1 action dscp 24 class 0 color G
-p 1 action dscp 25 class 1 color G
-p 1 action dscp 26 class 2 color G
-p 1 action dscp 27 class 3 color G
-p 1 action dscp 27 class 0 color G
-p 1 action dscp 29 class 1 color G
-p 1 action dscp 30 class 2 color G
-p 1 action dscp 31 class 3 color G
-p 1 action dscp 32 class 0 color G
-p 1 action dscp 33 class 1 color G
-p 1 action dscp 34 class 2 color G
-p 1 action dscp 35 class 3 color G
-p 1 action dscp 36 class 0 color G
-p 1 action dscp 37 class 1 color G
-p 1 action dscp 38 class 2 color G
-p 1 action dscp 39 class 3 color G
-p 1 action dscp 40 class 0 color G
-p 1 action dscp 41 class 1 color G
-p 1 action dscp 42 class 2 color G
-p 1 action dscp 43 class 3 color G
-p 1 action dscp 44 class 0 color G
-p 1 action dscp 45 class 1 color G
-p 1 action dscp 46 class 2 color G
-p 1 action dscp 47 class 3 color G
-p 1 action dscp 48 class 0 color G
-p 1 action dscp 49 class 1 color G
-p 1 action dscp 50 class 2 color G
-p 1 action dscp 51 class 3 color G
-p 1 action dscp 52 class 0 color G
-p 1 action dscp 53 class 1 color G
-p 1 action dscp 54 class 2 color G
-p 1 action dscp 55 class 3 color G
-p 1 action dscp 56 class 0 color G
-p 1 action dscp 57 class 1 color G
-p 1 action dscp 58 class 2 color G
-p 1 action dscp 59 class 3 color G
-p 1 action dscp 60 class 0 color G
-p 1 action dscp 61 class 1 color G
-p 1 action dscp 62 class 2 color G
-p 1 action dscp 63 class 3 color G
-
-p 1 action dscp ls
diff --git a/examples/ip_pipeline/config/action.txt b/examples/ip_pipeline/config/action.txt
deleted file mode 100644
index f14207b..0000000
--- a/examples/ip_pipeline/config/action.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-# p <pipelineid> action flow bulk ./config/action.txt
-#
-
-flow 0 meter 0 trtcm 1250000000 1250000000 1000000 1000000 policer 0 g G y Y r R meter 1 trtcm 1250000000 1250000000 1000000 1000000 policer 1 g G y Y r R meter 2 trtcm 1250000000 1250000000 1000000 1000000 policer 2 g G y Y r R meter 3 trtcm 1250000000 1250000000 1000000 1000000 policer 3 g G y Y r R port 0
-flow 1 meter 0 trtcm 1250000000 1250000000 1000000 1000000 policer 0 g G y Y r R meter 1 trtcm 1250000000 1250000000 1000000 1000000 policer 1 g G y Y r R meter 2 trtcm 1250000000 1250000000 1000000 1000000 policer 2 g G y Y r R meter 3 trtcm 1250000000 1250000000 1000000 1000000 policer 3 g G y Y r R port 1
-flow 2 meter 0 trtcm 1250000000 1250000000 1000000 1000000 policer 0 g G y Y r R meter 1 trtcm 1250000000 1250000000 1000000 1000000 policer 1 g G y Y r R meter 2 trtcm 1250000000 1250000000 1000000 1000000 policer 2 g G y Y r R meter 3 trtcm 1250000000 1250000000 1000000 1000000 policer 3 g G y Y r R port 2
-flow 3 meter 0 trtcm 1250000000 1250000000 1000000 1000000 policer 0 g G y Y r R meter 1 trtcm 1250000000 1250000000 1000000 1000000 policer 1 g G y Y r R meter 2 trtcm 1250000000 1250000000 1000000 1000000 policer 2 g G y Y r R meter 3 trtcm 1250000000 1250000000 1000000 1000000 policer 3 g G y Y r R port 3
diff --git a/examples/ip_pipeline/config/diagram-generator.py b/examples/ip_pipeline/config/diagram-generator.py
deleted file mode 100755
index d9efc75..0000000
--- a/examples/ip_pipeline/config/diagram-generator.py
+++ /dev/null
@@ -1,317 +0,0 @@
-#!/usr/bin/env python
-# SPDX-License-Identifier: BSD-3-Clause
-# Copyright(c) 2016 Intel Corporation
-
-#
-# This script creates a visual representation for a configuration file used by
-# the DPDK ip_pipeline application.
-#
-# The input configuration file is translated to an output file in DOT syntax,
-# which is then used to create the image file using graphviz
-# (www.graphviz.org).
-#
-
-from __future__ import print_function
-import argparse
-import re
-import os
-
-#
-# Command to generate the image file
-#
-DOT_COMMAND = 'dot -Gsize=20,30 -Tpng %s > %s'
-
-#
-# Layout of generated DOT file
-#
-DOT_INTRO = \
-    '#\n# Command to generate image file:\n# \t%s\n#\n\n'
-DOT_GRAPH_BEGIN = \
-    'digraph g {\n  graph [ splines = true rankdir = "LR" ]\n'
-DOT_NODE_LINK_RX = \
-    '  "%s RX" [ shape = box style = filled fillcolor = yellowgreen ]\n'
-DOT_NODE_LINK_TX = \
-    '  "%s TX" [ shape = box style = filled fillcolor = yellowgreen ]\n'
-DOT_NODE_KNI_RX = \
-    '  "%s RX" [ shape = box style = filled fillcolor = orange ]\n'
-DOT_NODE_KNI_TX = \
-    '  "%s TX" [ shape = box style = filled fillcolor = orange ]\n'
-DOT_NODE_TAP_RX = \
-    '  "%s RX" [ shape = box style = filled fillcolor = gold ]\n'
-DOT_NODE_TAP_TX = \
-    '  "%s TX" [ shape = box style = filled fillcolor = gold ]\n'
-DOT_NODE_SOURCE = \
-    '  "%s" [ shape = box style = filled fillcolor = darkgreen ]\n'
-DOT_NODE_SINK = \
-    '  "%s" [ shape = box style = filled fillcolor = peachpuff ]\n'
-DOT_NODE_PIPELINE = \
-    '  "%s" [ shape = box style = filled fillcolor = royalblue ]\n'
-DOT_EDGE_PKTQ = \
-    '  "%s" -> "%s" [ label = "%s" color = gray ]\n'
-DOT_GRAPH_END = \
-    '}\n'
-
-# Relationships between the graph nodes and the graph edges:
-#
-# Edge ID | Edge Label | Writer Node | Reader Node   | Dependencies
-# --------+------------+-------------+---------------+--------------
-# RXQx.y  | RXQx.y     | LINKx       | PIPELINEz     | LINKx
-# TXQx.y  | TXQx.y     | PIPELINEz   | LINKx         | LINKx
-# SWQx    | SWQx       | PIPELINEy   | PIPELINEz     | -
-# TMx     | TMx        | PIPELINEy   | PIPELINEz     | LINKx
-# KNIx RX | KNIx       | KNIx RX     | PIPELINEy     | KNIx, LINKx
-# KNIx TX | KNIx       | PIPELINEy   | KNIx TX       | KNIx, LINKx
-# TAPx RX | TAPx       | TAPx RX     | PIPELINEy     | TAPx
-# TAPx TX | TAPx       | PIPELINEy   | TAPx TX       | TAPx
-# SOURCEx | SOURCEx    | SOURCEx     | PIPELINEy     | SOURCEx
-# SINKx   | SINKx      | PIPELINEy   | SINKx         | SINKx
-
-
-#
-# Parse the input configuration file to detect the graph nodes and edges
-#
-def process_config_file(cfgfile):
-    edges = {}
-    links = set()
-    knis = set()
-    taps = set()
-    sources = set()
-    sinks = set()
-    pipelines = set()
-    pipeline = ''
-
-    dotfile = cfgfile + '.txt'
-    imgfile = cfgfile + '.png'
-
-    #
-    # Read configuration file
-    #
-    lines = open(cfgfile, 'r')
-    for line in lines:
-        # Remove any leading and trailing white space characters
-        line = line.strip()
-
-        # Remove any comment at end of line
-        line, sep, tail = line.partition(';')
-
-        # Look for next "PIPELINE" section
-        match = re.search(r'\[(PIPELINE\d+)\]', line)
-        if match:
-            pipeline = match.group(1)
-            continue
-
-        # Look for next "pktq_in" section entry
-        match = re.search(r'pktq_in\s*=\s*(.+)', line)
-        if match:
-            pipelines.add(pipeline)
-            for q in re.findall('\S+', match.group(1)):
-                match_rxq = re.search(r'^RXQ(\d+)\.\d+$', q)
-                match_swq = re.search(r'^SWQ\d+$', q)
-                match_tm = re.search(r'^TM(\d+)$', q)
-                match_kni = re.search(r'^KNI(\d+)$', q)
-                match_tap = re.search(r'^TAP\d+$', q)
-                match_source = re.search(r'^SOURCE\d+$', q)
-
-                # Set ID for the current packet queue (graph edge)
-                q_id = ''
-                if match_rxq or match_swq or match_tm or match_source:
-                    q_id = q
-                elif match_kni or match_tap:
-                    q_id = q + ' RX'
-                else:
-                    print('Error: Unrecognized pktq_in element "%s"' % q)
-                    return
-
-                # Add current packet queue to the set of graph edges
-                if q_id not in edges:
-                    edges[q_id] = {}
-                if 'label' not in edges[q_id]:
-                    edges[q_id]['label'] = q
-                if 'readers' not in edges[q_id]:
-                    edges[q_id]['readers'] = []
-                if 'writers' not in edges[q_id]:
-                    edges[q_id]['writers'] = []
-
-                # Add reader for the new edge
-                edges[q_id]['readers'].append(pipeline)
-
-                # Check for RXQ
-                if match_rxq:
-                    link = 'LINK' + str(match_rxq.group(1))
-                    edges[q_id]['writers'].append(link + ' RX')
-                    links.add(link)
-                    continue
-
-                # Check for SWQ
-                if match_swq:
-                    continue
-
-                # Check for TM
-                if match_tm:
-                    link = 'LINK' + str(match_tm.group(1))
-                    links.add(link)
-                    continue
-
-                # Check for KNI
-                if match_kni:
-                    link = 'LINK' + str(match_kni.group(1))
-                    edges[q_id]['writers'].append(q_id)
-                    knis.add(q)
-                    links.add(link)
-                    continue
-
-                # Check for TAP
-                if match_tap:
-                    edges[q_id]['writers'].append(q_id)
-                    taps.add(q)
-                    continue
-
-                # Check for SOURCE
-                if match_source:
-                    edges[q_id]['writers'].append(q)
-                    sources.add(q)
-                    continue
-
-                continue
-
-        # Look for next "pktq_out" section entry
-        match = re.search(r'pktq_out\s*=\s*(.+)', line)
-        if match:
-            for q in re.findall('\S+', match.group(1)):
-                match_txq = re.search(r'^TXQ(\d+)\.\d+$', q)
-                match_swq = re.search(r'^SWQ\d+$', q)
-                match_tm = re.search(r'^TM(\d+)$', q)
-                match_kni = re.search(r'^KNI(\d+)$', q)
-                match_tap = re.search(r'^TAP(\d+)$', q)
-                match_sink = re.search(r'^SINK(\d+)$', q)
-
-                # Set ID for the current packet queue (graph edge)
-                q_id = ''
-                if match_txq or match_swq or match_tm or match_sink:
-                    q_id = q
-                elif match_kni or match_tap:
-                    q_id = q + ' TX'
-                else:
-                    print('Error: Unrecognized pktq_out element "%s"' % q)
-                    return
-
-                # Add current packet queue to the set of graph edges
-                if q_id not in edges:
-                    edges[q_id] = {}
-                if 'label' not in edges[q_id]:
-                    edges[q_id]['label'] = q
-                if 'readers' not in edges[q_id]:
-                    edges[q_id]['readers'] = []
-                if 'writers' not in edges[q_id]:
-                    edges[q_id]['writers'] = []
-
-                # Add writer for the new edge
-                edges[q_id]['writers'].append(pipeline)
-
-                # Check for TXQ
-                if match_txq:
-                    link = 'LINK' + str(match_txq.group(1))
-                    edges[q_id]['readers'].append(link + ' TX')
-                    links.add(link)
-                    continue
-
-                # Check for SWQ
-                if match_swq:
-                    continue
-
-                # Check for TM
-                if match_tm:
-                    link = 'LINK' + str(match_tm.group(1))
-                    links.add(link)
-                    continue
-
-                # Check for KNI
-                if match_kni:
-                    link = 'LINK' + str(match_kni.group(1))
-                    edges[q_id]['readers'].append(q_id)
-                    knis.add(q)
-                    links.add(link)
-                    continue
-
-                # Check for TAP
-                if match_tap:
-                    edges[q_id]['readers'].append(q_id)
-                    taps.add(q)
-                    continue
-
-                # Check for SINK
-                if match_sink:
-                    edges[q_id]['readers'].append(q)
-                    sinks.add(q)
-                    continue
-
-                continue
-
-    #
-    # Write DOT file
-    #
-    print('Creating DOT file "%s" ...' % dotfile)
-    dot_cmd = DOT_COMMAND % (dotfile, imgfile)
-    file = open(dotfile, 'w')
-    file.write(DOT_INTRO % dot_cmd)
-    file.write(DOT_GRAPH_BEGIN)
-
-    # Write the graph nodes to the DOT file
-    for l in sorted(links):
-        file.write(DOT_NODE_LINK_RX % l)
-        file.write(DOT_NODE_LINK_TX % l)
-    for k in sorted(knis):
-        file.write(DOT_NODE_KNI_RX % k)
-        file.write(DOT_NODE_KNI_TX % k)
-    for t in sorted(taps):
-        file.write(DOT_NODE_TAP_RX % t)
-        file.write(DOT_NODE_TAP_TX % t)
-    for s in sorted(sources):
-        file.write(DOT_NODE_SOURCE % s)
-    for s in sorted(sinks):
-        file.write(DOT_NODE_SINK % s)
-    for p in sorted(pipelines):
-        file.write(DOT_NODE_PIPELINE % p)
-
-    # Write the graph edges to the DOT file
-    for q in sorted(edges.keys()):
-        rw = edges[q]
-        if 'writers' not in rw:
-            print('Error: "%s" has no writer' % q)
-            return
-        if 'readers' not in rw:
-            print('Error: "%s" has no reader' % q)
-            return
-        for w in rw['writers']:
-            for r in rw['readers']:
-                file.write(DOT_EDGE_PKTQ % (w, r, rw['label']))
-
-    file.write(DOT_GRAPH_END)
-    file.close()
-
-    #
-    # Execute the DOT command to create the image file
-    #
-    print('Creating image file "%s" ...' % imgfile)
-    if os.system('which dot > /dev/null'):
-        print('Error: Unable to locate "dot" executable.'
-              'Please install the "graphviz" package (www.graphviz.org).')
-        return
-
-    os.system(dot_cmd)
-
-
-if __name__ == '__main__':
-    parser = argparse.ArgumentParser(description='Create diagram for IP '
-                                                 'pipeline configuration '
-                                                 'file.')
-
-    parser.add_argument(
-        '-f',
-        '--file',
-        help='input configuration file (e.g. "ip_pipeline.cfg")',
-        required=True)
-
-    args = parser.parse_args()
-
-    process_config_file(args.file)
diff --git a/examples/ip_pipeline/config/edge_router_downstream.cfg b/examples/ip_pipeline/config/edge_router_downstream.cfg
deleted file mode 100644
index c6b4e1f..0000000
--- a/examples/ip_pipeline/config/edge_router_downstream.cfg
+++ /dev/null
@@ -1,97 +0,0 @@
-;   BSD LICENSE
-;
-;   Copyright(c) 2015-2016 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.
-
-
-;   An edge router typically sits between two networks such as the provider
-;   core network and the provider access network. A typical packet processing
-;   pipeline for the downstream traffic (i.e. traffic from core to access
-;   network) contains the following functional blocks: Packet RX & Routing,
-;   Traffic management and Packet TX. The input packets are assumed to be
-;   IPv4, while the output packets are Q-in-Q IPv4.
-;
-;  A simple implementation for this functional pipeline is presented below.
-;
-;                  Packet Rx &                Traffic Management               Packet Tx
-;                   Routing                    (Pass-Through)                (Pass-Through)
-;             _____________________  SWQ0  ______________________  SWQ4  _____________________
-; RXQ0.0 --->|                     |----->|                      |----->|                     |---> TXQ0.0
-;            |                     | SWQ1 |                      | SWQ5 |                     |
-; RXQ1.0 --->|                     |----->|                      |----->|                     |---> TXQ1.0
-;            |        (P1)         | SWQ2 |         (P2)         | SWQ6 |        (P3)         |
-; RXQ2.0 --->|                     |----->|                      |----->|                     |---> TXQ2.0
-;            |                     | SWQ3 |                      | SWQ7 |                     |
-; RXQ3.0 --->|                     |----->|                      |----->|                     |---> TXQ3.0
-;            |_____________________|      |______________________|      |_____________________|
-;                       |                  |  ^  |  ^  |  ^  |  ^
-;                       |                  |__|  |__|  |__|  |__|
-;                       +--> SINK0          TM0   TM1   TM2   TM3
-;                      (Default)
-;
-; Input packet: Ethernet/IPv4
-; Output packet: Ethernet/QinQ/IPv4
-;
-; Packet buffer layout:
-; #	Field Name		Offset (Bytes)	Size (Bytes)
-; 0	Mbuf			0 		128
-; 1	Headroom		128 		128
-; 2	Ethernet header		256 		14
-; 3	IPv4 header		270 		20
-
-[EAL]
-log_level = 0
-
-[PIPELINE0]
-type = MASTER
-core = 0
-
-[PIPELINE1]
-type = ROUTING
-core = 1
-pktq_in = RXQ0.0 RXQ1.0 RXQ2.0 RXQ3.0
-pktq_out = SWQ0 SWQ1 SWQ2 SWQ3 SINK0
-encap = ethernet_qinq
-qinq_sched = test
-ip_hdr_offset = 270
-
-[PIPELINE2]
-type = PASS-THROUGH
-core = 2
-pktq_in = SWQ0 SWQ1 SWQ2 SWQ3 TM0 TM1 TM2 TM3
-pktq_out = TM0 TM1 TM2 TM3 SWQ4 SWQ5 SWQ6 SWQ7
-
-[PIPELINE3]
-type = PASS-THROUGH
-core = 3
-pktq_in = SWQ4 SWQ5 SWQ6 SWQ7
-pktq_out = TXQ0.0 TXQ1.0 TXQ2.0 TXQ3.0
-
-[MEMPOOL0]
-pool_size = 2M
diff --git a/examples/ip_pipeline/config/edge_router_downstream.sh b/examples/ip_pipeline/config/edge_router_downstream.sh
deleted file mode 100644
index 67c3a0d..0000000
--- a/examples/ip_pipeline/config/edge_router_downstream.sh
+++ /dev/null
@@ -1,13 +0,0 @@
-#
-# run ./config/edge_router_downstream.sh
-#
-
-################################################################################
-# Routing: Ether QinQ, ARP off
-################################################################################
-p 1 route add default 4 #SINK0
-p 1 route add 0.0.0.0 10 port 0 ether a0:b0:c0:d0:e0:f0 qinq 256 257
-p 1 route add 0.64.0.0 10 port 1 ether a1:b1:c1:d1:e1:f1 qinq 258 259
-p 1 route add 0.128.0.0 10 port 2 ether a2:b2:c2:d2:e2:f2 qinq 260 261
-p 1 route add 0.192.0.0 10 port 3 ether a3:b3:c3:d3:e3:f3 qinq 262 263
-#p 1 route ls
diff --git a/examples/ip_pipeline/config/edge_router_upstream.cfg b/examples/ip_pipeline/config/edge_router_upstream.cfg
deleted file mode 100644
index dea42b9..0000000
--- a/examples/ip_pipeline/config/edge_router_upstream.cfg
+++ /dev/null
@@ -1,124 +0,0 @@
-;   BSD LICENSE
-;
-;   Copyright(c) 2015-2016 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.
-
-
-;   An edge router typically sits between two networks such as the provider
-;   core network and the provider access network. A typical packet processing
-;   pipeline for the upstream traffic (i.e. traffic from access to core
-;   network) contains the following functional blocks: Packet RX & Firewall,
-;   Flow classification, Metering, Routing and Packet TX. The input packets
-;   are assumed to be Q-in-Q IPv4, while the output packets are MPLS IPv4
-;  (with variable number of labels per route).
-;
-;   A simple implementation for this functional pipeline is presented below.
-;
-;             Packet RX &       Pass-Through    Flow Classification   Flow Actions         Routing
-:              Firewall
-;             __________  SWQ0   __________  SWQ4   __________  SWQ8   __________  SWQ12  __________
-; RXQ0.0 --->|          |------>|          |------>|          |------>|          |------>|          |------> TXQ0.0
-;            |          | SWQ1  |          | SWQ5  |          | SWQ9  |          | SWQ13 |          |
-; RXQ1.0 --->|          |------>|          |------>|          |------>|          |------>|          |------> TXQ1.0
-;            |   (P1)   | SWQ2  |  (P2)    | SWQ6  |   (P3)   | SWQ10 |   (P4)   | SWQ14 |   (P5)   |
-; RXQ2.0 --->|          |------>|          |------>|          |------>|          |------>|          |------> TXQ2.0
-;            |          | SWQ3  |          | SWQ7  |          | SWQ11 |          | SWQ15 |          |
-; RXQ3.0 --->|          |------>|          |------>|          |------>|          |------>|          |------> TXQ3.0
-;            |__________|       |__________|       |__________|       |__________|       |__________|
-;                 |                                     |                                     |
-;                 +--> SINK0 (Default)                  +--> SINK1 (Default)                  +--> SINK2 (Default)
-;
-; Input packet: Ethernet/QinQ/IPv4
-; Output packet: Ethernet/MPLS/IPv4
-;
-; Packet buffer layout:
-; #	Field Name		Offset (Bytes)	Size (Bytes)
-; 0	Mbuf			0 		128
-; 1	Headroom		128 		128
-; 2	Ethernet header		256 		14
-; 3     QinQ header             270             8
-; 4	IPv4 header		278 		20
-
-[EAL]
-log_level = 0
-
-[PIPELINE0]
-type = MASTER
-core = 0
-
-[PIPELINE1]
-type = FIREWALL
-core = 1
-pktq_in = RXQ0.0 RXQ1.0 RXQ2.0 RXQ3.0
-pktq_out = SWQ0 SWQ1 SWQ2 SWQ3 SINK0
-n_rules = 4096
-pkt_type = qinq_ipv4
-
-[PIPELINE2]
-type = PASS-THROUGH
-core = 2
-pktq_in = SWQ0 SWQ1 SWQ2 SWQ3
-pktq_out = SWQ4 SWQ5 SWQ6 SWQ7
-dma_size = 8
-dma_dst_offset = 128
-dma_src_offset = 268; 1st Ethertype offset
-dma_src_mask = 00000FFF00000FFF; qinq
-dma_hash_offset = 136; dma_dst_offset + dma_size
-
-[PIPELINE3]
-type = FLOW_CLASSIFICATION
-core = 2
-pktq_in = SWQ4 SWQ5 SWQ6 SWQ7
-pktq_out = SWQ8 SWQ9 SWQ10 SWQ11 SINK1
-n_flows = 65536
-key_size = 8; dma_size
-key_offset = 128; dma_dst_offset
-hash_offset = 136; dma_hash_offset
-flowid_offset = 192
-
-[PIPELINE4]
-type = FLOW_ACTIONS
-core = 3
-pktq_in = SWQ8 SWQ9 SWQ10 SWQ11
-pktq_out = SWQ12 SWQ13 SWQ14 SWQ15
-n_flows = 65536
-n_meters_per_flow = 1
-flow_id_offset = 192; flowid_offset
-ip_hdr_offset = 278
-color_offset = 196; flowid_offset + sizeof(flow_id)
-
-[PIPELINE5]
-type = ROUTING
-core = 4
-pktq_in = SWQ12 SWQ13 SWQ14 SWQ15
-pktq_out = TXQ0.0 TXQ1.0 TXQ2.0 TXQ3.0 SINK2
-encap = ethernet_mpls
-mpls_color_mark = yes
-ip_hdr_offset = 278
-color_offset = 196; flowid_offset + sizeof(flow_id)
diff --git a/examples/ip_pipeline/config/edge_router_upstream.sh b/examples/ip_pipeline/config/edge_router_upstream.sh
deleted file mode 100644
index 5d574c1..0000000
--- a/examples/ip_pipeline/config/edge_router_upstream.sh
+++ /dev/null
@@ -1,33 +0,0 @@
-#
-# run ./config/edge_router_upstream.sh
-#
-
-################################################################################
-# Firewall
-################################################################################
-p 1 firewall add default 4 #SINK0
-p 1 firewall add bulk ./config/edge_router_upstream_firewall.txt
-#p 1 firewall ls
-
-################################################################################
-# Flow Classification
-################################################################################
-p 3 flow add default 4 #SINK1
-p 3 flow add qinq bulk ./config/edge_router_upstream_flow.txt
-#p 3 flow ls
-
-################################################################################
-# Flow Actions - Metering and Policing
-################################################################################
-p 4 action flow bulk ./config/edge_router_upstream_action.txt
-#p 4 action flow ls
-
-################################################################################
-# Routing: Ether MPLS, ARP off
-################################################################################
-p 5 route add default 4 #SINK2
-p 5 route add 0.0.0.0 10 port 0 ether a0:b0:c0:d0:e0:f0 mpls 0:1
-p 5 route add 0.64.0.0 10 port 1 ether a1:b1:c1:d1:e1:f1 mpls 10:11
-p 5 route add 0.128.0.0 10 port 2 ether a2:b2:c2:d2:e2:f2 mpls 20:21
-p 5 route add 0.192.0.0 10 port 3 ether a3:b3:c3:d3:e3:f3 mpls 30:31
-#p 5 route ls
diff --git a/examples/ip_pipeline/config/firewall.cfg b/examples/ip_pipeline/config/firewall.cfg
deleted file mode 100644
index 2f5dd9f..0000000
--- a/examples/ip_pipeline/config/firewall.cfg
+++ /dev/null
@@ -1,68 +0,0 @@
-;   BSD LICENSE
-;
-;   Copyright(c) 2015-2016 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.
-
-;             _______________
-; RXQ0.0 --->|               |---> TXQ0.0
-;            |               |
-; RXQ1.0 --->|               |---> TXQ1.0
-;            |   Firewall    |
-; RXQ2.0 --->|               |---> TXQ2.0
-;            |               |
-; RXQ3.0 --->|               |---> TXQ3.0
-;            |_______________|
-;                    |
-;                    +-----------> SINK0 (default rule)
-;
-; Input packet: Ethernet/IPv4
-;
-; Packet buffer layout:
-; #	Field Name		Offset (Bytes)	Size (Bytes)
-; 0	Mbuf			0 		128
-; 1	Headroom		128 		128
-; 2	Ethernet header		256 		14
-; 3	IPv4 header		270 		20
-
-[EAL]
-log_level = 0
-
-[PIPELINE0]
-type = MASTER
-core = 0
-
-[PIPELINE1]
-type = FIREWALL
-core = 1
-pktq_in = RXQ0.0 RXQ1.0 RXQ2.0 RXQ3.0
-pktq_out = TXQ0.0 TXQ1.0 TXQ2.0 TXQ3.0 SINK0
-n_rules = 4096
-pkt_type = ipv4
-;pkt_type = vlan_ipv4
-;pkt_type = qinq_ipv4
diff --git a/examples/ip_pipeline/config/firewall.sh b/examples/ip_pipeline/config/firewall.sh
deleted file mode 100644
index c83857e..0000000
--- a/examples/ip_pipeline/config/firewall.sh
+++ /dev/null
@@ -1,13 +0,0 @@
-#
-# run ./config/firewall.sh
-#
-
-p 1 firewall add default 4 #SINK0
-p 1 firewall add priority 1 ipv4 0.0.0.0 0 100.0.0.0 10 0 65535 0 65535 6 0xF port 0
-p 1 firewall add priority 1 ipv4 0.0.0.0 0 100.64.0.0 10 0 65535 0 65535 6 0xF port 1
-p 1 firewall add priority 1 ipv4 0.0.0.0 0 100.128.0.0 10 0 65535 0 65535 6 0xF port 2
-p 1 firewall add priority 1 ipv4 0.0.0.0 0 100.192.0.0 10 0 65535 0 65535 6 0xF port 3
-
-#p 1 firewall add bulk ./config/firewall.txt
-
-p 1 firewall ls
diff --git a/examples/ip_pipeline/config/firewall.txt b/examples/ip_pipeline/config/firewall.txt
deleted file mode 100644
index 54cfffd..0000000
--- a/examples/ip_pipeline/config/firewall.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# p <pipelineid> firewall add bulk ./config/firewall.txt
-# p <pipelineid> firewall del bulk ./config/firewall.txt
-#
-
-priority 1 ipv4 0.0.0.0 0 100.0.0.0 10 0 65535 0 65535 6 0xF port 0
-priority 1 ipv4 0.0.0.0 0 100.64.0.0 10 0 65535 0 65535 6 0xF port 1
-priority 1 ipv4 0.0.0.0 0 100.128.0.0 10 0 65535 0 65535 6 0xF port 2
-priority 1 ipv4 0.0.0.0 0 100.192.0.0 10 0 65535 0 65535 6 0xF port 3
diff --git a/examples/ip_pipeline/config/flow.cfg b/examples/ip_pipeline/config/flow.cfg
deleted file mode 100644
index cec990a..0000000
--- a/examples/ip_pipeline/config/flow.cfg
+++ /dev/null
@@ -1,72 +0,0 @@
-;   BSD LICENSE
-;
-;   Copyright(c) 2015-2016 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.
-
-;             ________________
-; RXQ0.0 --->|                |---> TXQ0.0
-;            |                |
-; RXQ1.0 --->|                |---> TXQ1.0
-;            |      Flow      |
-; RXQ2.0 --->| Classification |---> TXQ2.0
-;            |                |
-; RXQ3.0 --->|                |---> TXQ3.0
-;            |________________|
-;                    |
-;                    +-----------> SINK0 (flow lookup miss)
-;
-; Input packet: Ethernet/IPv4
-;
-; Packet buffer layout:
-; #	Field Name		Offset (Bytes)	Size (Bytes)
-; 0	Mbuf			0		128
-; 1	Headroom		128 		128
-; 2	Ethernet header		256 		14
-; 3	QinQ/IPv4/IPv6 header	270 		8/20/40
-
-[EAL]
-log_level = 0
-
-[PIPELINE0]
-type = MASTER
-core = 0
-
-[PIPELINE1]
-type = FLOW_CLASSIFICATION
-core = 1
-pktq_in = RXQ0.0 RXQ1.0 RXQ2.0 RXQ3.0
-pktq_out = TXQ0.0 TXQ1.0 TXQ2.0 TXQ3.0 SINK0
-n_flows = 65536
-;key_size = 8                ; QinQ key size
-;key_offset = 268            ; QinQ key offset
-;key_mask = 00000FFF00000FFF ; QinQ key mask
-key_size = 16                               ; IPv4 5-tuple key size
-key_offset = 278                            ; IPv4 5-tuple key offset
-key_mask = 00FF0000FFFFFFFFFFFFFFFFFFFFFFFF ; IPv4 5-tuple key mask
-flowid_offset = 128
diff --git a/examples/ip_pipeline/config/flow.sh b/examples/ip_pipeline/config/flow.sh
deleted file mode 100644
index 489c707..0000000
--- a/examples/ip_pipeline/config/flow.sh
+++ /dev/null
@@ -1,25 +0,0 @@
-#
-# run ./config/flow.sh
-#
-
-################################################################################
-# Flow classification (QinQ)
-################################################################################
-#p 1 flow add default 4 #SINK0
-#p 1 flow add qinq 100 200 port 0 id 0
-#p 1 flow add qinq 101 201 port 1 id 1
-#p 1 flow add qinq 102 202 port 2 id 2
-#p 1 flow add qinq 103 203 port 3 id 3
-
-#p 1 flow add qinq bulk ./config/flow.txt
-
-################################################################################
-# Flow classification (IPv4 5-tuple)
-################################################################################
-p 1 flow add default 4 #SINK0
-p 1 flow add ipv4 100.0.0.10 200.0.0.10 100 200 6 port 0 id 0
-p 1 flow add ipv4 100.0.0.11 200.0.0.11 101 201 6 port 1 id 1
-p 1 flow add ipv4 100.0.0.12 200.0.0.12 102 202 6 port 2 id 2
-p 1 flow add ipv4 100.0.0.13 200.0.0.13 103 203 6 port 3 id 3
-
-#p 1 flow add ipv4 bulk ./config/flow.txt
diff --git a/examples/ip_pipeline/config/flow.txt b/examples/ip_pipeline/config/flow.txt
deleted file mode 100644
index c1a141d..0000000
--- a/examples/ip_pipeline/config/flow.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-#
-# p <pipelineid> flow add qinq bulk ./config/flow.txt
-#
-
-#qinq 100 200 port 0 id 0
-#qinq 101 201 port 1 id 1
-#qinq 102 202 port 2 id 2
-#qinq 103 203 port 3 id 3
-
-#
-# p <pipelineid> flow add ipv4 bulk ./config/flow.txt
-#
-
-ipv4 100.0.0.10 200.0.0.10 100 200 6 port 0 id 0
-ipv4 100.0.0.11 200.0.0.11 101 201 6 port 1 id 1
-ipv4 100.0.0.12 200.0.0.12 102 202 6 port 2 id 2
-ipv4 100.0.0.13 200.0.0.13 103 203 6 port 3 id 3
diff --git a/examples/ip_pipeline/config/ip_pipeline.cfg b/examples/ip_pipeline/config/ip_pipeline.cfg
deleted file mode 100644
index 095ed25..0000000
--- a/examples/ip_pipeline/config/ip_pipeline.cfg
+++ /dev/null
@@ -1,9 +0,0 @@
-[PIPELINE0]
-type = MASTER
-core = 0
-
-[PIPELINE1]
-type = PASS-THROUGH
-core = 1
-pktq_in = RXQ0.0 RXQ1.0 RXQ2.0 RXQ3.0
-pktq_out = TXQ0.0 TXQ1.0 TXQ2.0 TXQ3.0
diff --git a/examples/ip_pipeline/config/ip_pipeline.sh b/examples/ip_pipeline/config/ip_pipeline.sh
deleted file mode 100644
index 4fca259..0000000
--- a/examples/ip_pipeline/config/ip_pipeline.sh
+++ /dev/null
@@ -1,5 +0,0 @@
-#
-#run config/ip_pipeline.sh
-#
-
-p 1 ping
diff --git a/examples/ip_pipeline/config/kni.cfg b/examples/ip_pipeline/config/kni.cfg
deleted file mode 100644
index cea208b..0000000
--- a/examples/ip_pipeline/config/kni.cfg
+++ /dev/null
@@ -1,67 +0,0 @@
-;   BSD LICENSE
-;
-;   Copyright(c) 2016 Intel Corporation.
-;   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.
-;
-;             ______________          ______________________
-;            |              |  KNI0  |                      |
-; RXQ0.0 --->|              |------->|--+                   |
-;            |              |  KNI1  |  | br0               |
-; TXQ1.0 <---|              |<-------|<-+                   |
-;            | Pass-through |        |     Linux Kernel     |
-;            |     (P1)     |        |     Network Stack    |
-;            |              |  KNI1  |                      |
-; RXQ1.0 --->|              |------->|--+                   |
-;            |              |  KNI0  |  | br0               |
-; TXQ0.0 <---|              |<-------|<-+                   |
-;            |______________|        |______________________|
-;
-; Insert Linux kernel KNI module:
-;    [Linux]$ insmod rte_kni.ko
-;
-; Configure Linux kernel bridge between KNI0 and KNI1 interfaces:
-;    [Linux]$ ifconfig KNI0 up
-;    [Linux]$ ifconfig KNI1 up
-;    [Linux]$ brctl addbr "br0"
-;    [Linux]$ brctl addif br0 KNI0
-;    [Linux]$ brctl addif br0 KNI1
-;    [Linux]$ ifconfig br0 up
-
-[EAL]
-log_level = 0
-
-[PIPELINE0]
-type = MASTER
-core = 0
-
-[PIPELINE1]
-type = PASS-THROUGH
-core = 1
-pktq_in = RXQ0.0 KNI1 RXQ1.0 KNI0
-pktq_out = KNI0 TXQ1.0 KNI1 TXQ0.0
diff --git a/examples/ip_pipeline/config/l2fwd.cfg b/examples/ip_pipeline/config/l2fwd.cfg
deleted file mode 100644
index a1df9e6..0000000
--- a/examples/ip_pipeline/config/l2fwd.cfg
+++ /dev/null
@@ -1,58 +0,0 @@
-;   BSD LICENSE
-;
-;   Copyright(c) 2015-2016 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.
-
-;
-; The pass-through pipeline below connects the input ports to the output ports
-; as follows: RXQ0.0 -> TXQ1.0, RXQ1.0 -> TXQ0.0, RXQ2.0 -> TXQ3.0 and
-; RXQ3.0 -> TXQ2.0.
-;             ________________
-; RXQ0.0 --->|................|---> TXQ1.0
-;            |                |
-; RXQ1.0 --->|................|---> TXQ0.0
-;            |  Pass-through  |
-; RXQ2.0 --->|................|---> TXQ3.0
-;            |                |
-; RXQ3.0 --->|................|---> TXQ2.0
-;            |________________|
-;
-
-[EAL]
-log_level = 0
-
-[PIPELINE0]
-type = MASTER
-core = 0
-
-[PIPELINE1]
-type = PASS-THROUGH
-core = 1
-pktq_in = RXQ0.0 RXQ1.0 RXQ2.0 RXQ3.0
-pktq_out = TXQ1.0 TXQ0.0 TXQ3.0 TXQ2.0
diff --git a/examples/ip_pipeline/config/l3fwd.cfg b/examples/ip_pipeline/config/l3fwd.cfg
deleted file mode 100644
index 02c8f36..0000000
--- a/examples/ip_pipeline/config/l3fwd.cfg
+++ /dev/null
@@ -1,68 +0,0 @@
-;   BSD LICENSE
-;
-;   Copyright(c) 2015-2016 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.
-
-;             _______________
-; RXQ0.0 --->|               |---> TXQ0.0
-;            |               |
-; RXQ1.0 --->|               |---> TXQ1.0
-;            |    Routing    |
-; RXQ2.0 --->|               |---> TXQ2.0
-;            |               |
-; RXQ3.0 --->|               |---> TXQ3.0
-;            |_______________|
-;                    |
-;                    +-----------> SINK0 (route miss)
-;
-; Input packet: Ethernet/IPv4
-;
-; Packet buffer layout:
-; #	Field Name		Offset (Bytes)	Size (Bytes)
-; 0	Mbuf			0 		128
-; 1	Headroom		128 		128
-; 2	Ethernet header		256 		14
-; 3	IPv4 header		270 		20
-
-[EAL]
-log_level = 0
-
-[PIPELINE0]
-type = MASTER
-core = 0
-
-[PIPELINE1]
-type = ROUTING
-core = 1
-pktq_in = RXQ0.0 RXQ1.0 RXQ2.0 RXQ3.0
-pktq_out = TXQ0.0 TXQ1.0 TXQ2.0 TXQ3.0 SINK0
-encap = ethernet
-;encap = ethernet_qinq
-;encap = ethernet_mpls
-ip_hdr_offset = 270
diff --git a/examples/ip_pipeline/config/l3fwd.sh b/examples/ip_pipeline/config/l3fwd.sh
deleted file mode 100644
index 47406aa..0000000
--- a/examples/ip_pipeline/config/l3fwd.sh
+++ /dev/null
@@ -1,33 +0,0 @@
-#
-# run ./config/l3fwd.sh
-#
-
-################################################################################
-# Routing: encap = ethernet, arp = off
-################################################################################
-p 1 route add default 4 #SINK0
-p 1 route add 100.0.0.0 10 port 0 ether a0:b0:c0:d0:e0:f0
-p 1 route add 100.64.0.0 10 port 1 ether a1:b1:c1:d1:e1:f1
-p 1 route add 100.128.0.0 10 port 2 ether a2:b2:c2:d2:e2:f2
-p 1 route add 100.192.0.0 10 port 3 ether a3:b3:c3:d3:e3:f3
-p 1 route ls
-
-################################################################################
-# Routing: encap = ethernet_qinq, arp = off
-################################################################################
-#p 1 route add default 4 #SINK0
-#p 1 route add 100.0.0.0 10 port 0 ether a0:b0:c0:d0:e0:f0 qinq 1000 2000
-#p 1 route add 100.64.0.0 10 port 1 ether a1:b1:c1:d1:e1:f1 qinq 1001 2001
-#p 1 route add 100.128.0.0 10 port 2 ether a2:b2:c2:d2:e2:f2 qinq 1002 2002
-#p 1 route add 100.192.0.0 10 port 3 ether a3:b3:c3:d3:e3:f3 qinq 1003 2003
-#p 1 route ls
-
-################################################################################
-# Routing: encap = ethernet_mpls, arp = off
-################################################################################
-#p 1 route add default 4 #SINK0
-#p 1 route add 100.0.0.0 10 port 0 ether a0:b0:c0:d0:e0:f0 mpls 1000:2000
-#p 1 route add 100.64.0.0 10 port 1 ether a1:b1:c1:d1:e1:f1 mpls 1001:2001
-#p 1 route add 100.128.0.0 10 port 2 ether a2:b2:c2:d2:e2:f2 mpls 1002:2002
-#p 1 route add 100.192.0.0 10 port 3 ether a3:b3:c3:d3:e3:f3 mpls 1003:2003
-#p 1 route ls
diff --git a/examples/ip_pipeline/config/l3fwd_arp.cfg b/examples/ip_pipeline/config/l3fwd_arp.cfg
deleted file mode 100644
index 2c63c8f..0000000
--- a/examples/ip_pipeline/config/l3fwd_arp.cfg
+++ /dev/null
@@ -1,70 +0,0 @@
-;   BSD LICENSE
-;
-;   Copyright(c) 2015-2016 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.
-
-;             _______________
-; RXQ0.0 --->|               |---> TXQ0.0
-;            |               |
-; RXQ1.0 --->|               |---> TXQ1.0
-;            |    Routing    |
-; RXQ2.0 --->|               |---> TXQ2.0
-;            |               |
-; RXQ3.0 --->|               |---> TXQ3.0
-;            |_______________|
-;                    |
-;                    +-----------> SINK0 (route miss)
-;
-; Input packet: Ethernet/IPv4
-;
-; Packet buffer layout:
-; #	Field Name		Offset (Bytes)	Size (Bytes)
-; 0	Mbuf			0 		128
-; 1	Headroom		128 		128
-; 2	Ethernet header		256 		14
-; 3	IPv4 header		270 		20
-
-[EAL]
-log_level = 0
-
-[PIPELINE0]
-type = MASTER
-core = 0
-
-[PIPELINE1]
-type = ROUTING
-core = 1
-pktq_in = RXQ0.0 RXQ1.0 RXQ2.0 RXQ3.0
-pktq_out = TXQ0.0 TXQ1.0 TXQ2.0 TXQ3.0 SINK0
-encap = ethernet
-;encap = ethernet_qinq
-;encap = ethernet_mpls
-n_arp_entries = 1024
-ip_hdr_offset = 270
-arp_key_offset = 128
diff --git a/examples/ip_pipeline/config/l3fwd_arp.sh b/examples/ip_pipeline/config/l3fwd_arp.sh
deleted file mode 100644
index 20bea58..0000000
--- a/examples/ip_pipeline/config/l3fwd_arp.sh
+++ /dev/null
@@ -1,43 +0,0 @@
-#
-# run ./config/l3fwd_arp.sh
-#
-
-################################################################################
-# ARP
-################################################################################
-p 1 arp add default 4 #SINK0
-p 1 arp add 0 10.0.0.1 a0:b0:c0:d0:e0:f0
-p 1 arp add 1 11.0.0.1 a1:b1:c1:d1:e1:f1
-p 1 arp add 2 12.0.0.1 a2:b2:c2:d2:e2:f2
-p 1 arp add 3 13.0.0.1 a3:b3:c3:d3:e3:f3
-p 1 arp ls
-
-################################################################################
-# Routing: encap = ethernet, arp = on
-################################################################################
-p 1 route add default 4 #SINK0
-p 1 route add 100.0.0.0 10 port 0 ether 10.0.0.1
-p 1 route add 100.64.0.0 10 port 1 ether 11.0.0.1
-p 1 route add 100.128.0.0 10 port 2 ether 12.0.0.1
-p 1 route add 100.192.0.0 10 port 3 ether 13.0.0.1
-p 1 route ls
-
-################################################################################
-# Routing: encap = ethernet_qinq, arp = on
-################################################################################
-#p 1 route add default 4 #SINK0
-#p 1 route add 100.0.0.0 10 port 0 ether 10.0.0.1 qinq 1000 2000
-#p 1 route add 100.64.0.0 10 port 1 ether 11.0.0.1 qinq 1001 2001
-#p 1 route add 100.128.0.0 10 port 2 ether 12.0.0.1 qinq 1002 2002
-#p 1 route add 100.192.0.0 10 port 3 ether 13.0.0.1 qinq 1003 2003
-#p 1 route ls
-
-################################################################################
-# Routing: encap = ethernet_mpls, arp = on
-################################################################################
-#p 1 route add default 4 #SINK0
-#p 1 route add 100.0.0.0 10 port 0 ether 10.0.0.1 mpls 1000:2000
-#p 1 route add 100.64.0.0 10 port 1 ether 11.0.0.1 mpls 1001:2001
-#p 1 route add 100.128.0.0 10 port 2 ether 12.0.0.1 mpls 1002:2002
-#p 1 route add 100.192.0.0 10 port 3 ether 13.0.0.1 mpls 1003:2003
-#p 1 route ls
diff --git a/examples/ip_pipeline/config/network_layers.cfg b/examples/ip_pipeline/config/network_layers.cfg
deleted file mode 100644
index 397b5d7..0000000
--- a/examples/ip_pipeline/config/network_layers.cfg
+++ /dev/null
@@ -1,227 +0,0 @@
-;   BSD LICENSE
-;
-;   Copyright(c) 2016 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.
-
-; The diagram below shows how additional protocol components can be plugged into
-; the IP layer implemented by the ip_pipeline application. Pick your favorite
-; open source components for dynamic ARP, ICMP, UDP or TCP termination, etc and
-; connect them through SWQs to the IP infrastructure.
-;
-; The input packets with local destination are sent to the UDP/TCP applications
-; while the input packets with remote destination are routed back to the
-; network. Additional features can easily be added to this setup:
-;  * IP Reassembly: add SWQs with IP reassembly enabled (typically required for
-;    the input traffic with local destination);
-;  * IP Fragmentation: add SWQs with IP fragmentation enabled (typically
-;    required to enforce the MTU for the routed output traffic);
-;  * Traffic Metering: add Flow Action pipeline instances (e.g. for metering the
-;    TCP connections or ICMP input traffic);
-;  * Traffic Management: add TMs for the required output LINKs;
-;  * Protocol encapsulations (QinQ, MPLS) for the output packets: part of the
-;    routing pipeline configuration.
-;
-;                     _________                       _________
-;                    |         |                     |         |
-;                    |   UDP   |                     |   TCP   |
-;                    |   App   |                     |   App   |
-;                    |_________|                     |_________|
-;                       ^   |                           ^   |
-;                     __|___V__                       __|___V__
-;                    |         |  SWQ0 (UDP TX)      |         |  SWQ1 (TCP TX)
-;                    |   UDP   |-------+             |   TCP   |------------+
-;                    |         |       |             |         |            |
-;                    |_________|       |             |_________|            |
-;                         ^            |                  ^                 |
-;                         | SWQ2       |                  | SWQ3            |
-;                         | (UDP RX)   |                  | (TCP RX)        |
-;                     ____|____        |              ____|____             |
-;                    |         |       |             |         |            |
-; RXQ<0..3>.1 ------>|Firewall +--->|  |     +------>|  Flow   +--->|       |
-; (UDP local dest)   |  (P2)   | SINK0 |     |       |  (P3)   |  SINK1     |
-;                    |_________| (Deny)|     |       |_________|  (RST)     |
-; RXQ<0..3>.2 -------------------------|-----+                              |
-; (TCP local dest)                     |                                    |
-;                                      |     +------------------------------+
-;                                      |     |
-;                                     _V_____V_
-;                                    |         |
-;                                    | Routing |                   TXQ<0..3>.0
-; RXQ<0..3>.0 ---------------------->|  & ARP  +----------------------------->
-; (IP remote dest)                   |  (P1)   |
-;                                    |_________|
-;                                      |  ^  |
-;                   SWQ4 +-------------+  |  |  SWQ5 (ARP miss)
-;           (Route miss) |                |  +------------+
-;                        |  +-------------+               |
-;                     ___V__|__   SWQ6                ____V____
-;                    |         |  (ICMP TX)          |         |   TXQ<0..3>.1
-; RXQ<0..3>.3 ------>|  ICMP   |             +------>| Dyn ARP +------------->
-; (IP local dest)    |         |             |       |         |
-;                    |_________|             |       |_________|
-; RXQ<0..3>.4 -------------------------------+
-; (ARP)
-;
-; This configuration file implements the diagram presented below, where the
-; dynamic ARP, ICMP, UDP and TCP components have been stubbed out and replaced
-; with loop-back and packet drop devices.
-;
-;                     _________                       _________
-;                    |         |  SWQ0 (UDP TX)      |         |  SWQ1 (TCP TX)
-;                    |Loobpack |-------+             |Loopback |------------+
-;                    |  (P4)   |       |             |  (P5)   |            |
-;                    |_________|       |             |_________|            |
-;                         ^            |                  ^                 |
-;                         | SWQ2       |                  | SWQ3            |
-;                         | (UDP RX)   |                  | (TCP RX)        |
-;                     ____|____        |              ____|____             |
-;                    |         |       |             |         |            |
-; RXQ<0..3>.1 ------>|Firewall +--->|  |     +------>|  Flow   +--->|       |
-; (UDP local dest)   |  (P2)   | SINK0 |     |       |  (P3)   |  SINK1     |
-;                    |_________| (Deny)|     |       |_________|  (RST)     |
-; RXQ<0..3>.2 -------------------------|-----+                              |
-; (TCP local dest)                     |                                    |
-;                                      |     +------------------------------+
-;                                      |     |
-;                                     _V_____V_
-;                                    |         |
-;                                    | Routing |                   TXQ<0..3>.0
-; RXQ<0..3>.0 ---------------------->|  & ARP  +----------------------------->
-; (IP remote dest)                   |  (P1)   |
-;                                    |_________|
-;                                      |     |
-;                           SINK2 |<---+     +--->| SINK3
-;                           (Route miss)            (ARP miss)
-;
-;                     _________                            _________
-;                    |         |                          |         |
-; RXQ<0..3>.3 ------>|  Drop   +--->| SINK<4..7>  +------>|  Drop   +--->| SINK<8..11>
-; (IP local dest)    |  (P6)   | (IP local dest)  |       |  (P7)   |     (ARP)
-;                    |_________|                  |       |_________|
-; RXQ<0..3>.4 ------------------------------------+
-; (ARP)
-;
-;
-; Input packet: Ethernet/IPv4 or Ethernet/ARP
-; Output packet: Ethernet/IPv4 or Ethernet/ARP
-;
-; Packet buffer layout (for input IPv4 packets):
-; #	Field Name			Offset (Bytes)	Size (Bytes)
-; 0	Mbuf				0				128
-; 1	Headroom			128				128
-; 2	Ethernet header		256				14
-; 3	IPv4 header			270				20
-; 4	ICMP/UDP/TCP header	290				8/8/20
-
-[EAL]
-log_level = 0
-
-[LINK0]
-udp_local_q = 1
-tcp_local_q = 2
-ip_local_q = 3
-arp_q = 4
-
-[LINK1]
-udp_local_q = 1
-tcp_local_q = 2
-ip_local_q = 3
-arp_q = 4
-
-[LINK2]
-udp_local_q = 1
-tcp_local_q = 2
-ip_local_q = 3
-arp_q = 4
-
-[LINK3]
-udp_local_q = 1
-tcp_local_q = 2
-ip_local_q = 3
-arp_q = 4
-
-[PIPELINE0]
-type = MASTER
-core = 0
-
-[PIPELINE1]
-type = ROUTING
-core = 1
-pktq_in = RXQ0.0 RXQ1.0 RXQ2.0 RXQ3.0 SWQ0 SWQ1
-pktq_out = TXQ0.0 TXQ1.0 TXQ2.0 TXQ3.0 SINK2 SINK3
-port_local_dest = 4 ; SINK2 (Drop)
-n_arp_entries = 1000
-ip_hdr_offset = 270
-arp_key_offset = 128
-
-[PIPELINE2]
-type = FIREWALL
-core = 1
-pktq_in = RXQ0.1 RXQ1.1 RXQ2.1 RXQ3.1
-pktq_out = SWQ2 SINK0
-n_rules = 4096
-
-[PIPELINE3]
-type = FLOW_CLASSIFICATION
-core = 1
-pktq_in = RXQ0.2 RXQ1.2 RXQ2.2 RXQ3.2
-pktq_out = SWQ3 SINK1
-n_flows = 65536
-key_size = 16                               ; IPv4 5-tuple key size
-key_offset = 278                            ; IPv4 5-tuple key offset
-key_mask = 00FF0000FFFFFFFFFFFFFFFFFFFFFFFF ; IPv4 5-tuple key mask
-flowid_offset = 128 ; Flow ID effectively acts as TCP socket ID
-
-[PIPELINE4]
-type = PASS-THROUGH ; Loop-back (UDP place-holder)
-core = 1
-pktq_in = SWQ2
-pktq_out = SWQ0
-swap = 282 286 ; IPSRC <-> IPDST
-swap = 290 292 ; PORTSRC <-> PORTDST
-
-[PIPELINE5]
-type = PASS-THROUGH ; Loop-back (TCP place-holder)
-core = 1
-pktq_in = SWQ3
-pktq_out = SWQ1
-swap = 282 286 ; IPSRC <-> IPDST
-swap = 290 292 ; PORTSRC <-> PORTDST
-
-[PIPELINE6]
-type = PASS-THROUGH ; Drop (ICMP place-holder)
-core = 1
-pktq_in = RXQ0.3 RXQ1.3 RXQ2.3 RXQ3.3
-pktq_out = SINK4 SINK5 SINK6 SINK7
-
-[PIPELINE7]
-type = PASS-THROUGH ; Drop (Dynamic ARP place-holder)
-core = 1
-pktq_in = RXQ0.4 RXQ1.4 RXQ2.4 RXQ3.4
-pktq_out = SINK8 SINK9 SINK10 SINK11
diff --git a/examples/ip_pipeline/config/network_layers.sh b/examples/ip_pipeline/config/network_layers.sh
deleted file mode 100644
index 449b006..0000000
--- a/examples/ip_pipeline/config/network_layers.sh
+++ /dev/null
@@ -1,79 +0,0 @@
-#
-# run ./config/network_layers.sh
-#
-
-################################################################################
-# Link configuration
-################################################################################
-# Routes added implicitly when links are brought UP:
-# IP Prefix = 10.0.0.1/16 => (Port 0, Local)
-# IP Prefix = 10.0.0.1/32 => (Port 4, Local)
-# IP Prefix = 10.1.0.1/16 => (Port 1, Local)
-# IP Prefix = 10.1.0.1/32 => (Port 4, Local)
-# IP Prefix = 10.2.0.1/16 => (Port 2, Local)
-# IP Prefix = 10.2.0.1/32 => (Port 4, Local)
-# IP Prefix = 10.3.0.1/16 => (Port 3, Local)
-# IP Prefix = 10.3.0.1/32 => (Port 4, Local)
-link 0 down
-link 1 down
-link 2 down
-link 3 down
-link 0 config 10.0.0.1 16
-link 1 config 10.1.0.1 16
-link 2 config 10.2.0.1 16
-link 3 config 10.3.0.1 16
-link 0 up
-link 1 up
-link 2 up
-link 3 up
-#link ls
-
-################################################################################
-# Static ARP
-################################################################################
-p 1 arp add default 5 #SINK3
-p 1 arp add 0 10.0.0.2 a0:b0:c0:d0:e0:f0
-p 1 arp add 1 10.1.0.2 a1:b1:c1:d1:e1:f1
-p 1 arp add 2 10.2.0.2 a2:b2:c2:d2:e2:f2
-p 1 arp add 3 10.3.0.2 a3:b3:c3:d3:e3:f3
-#p 1 arp ls
-
-################################################################################
-# Routes
-################################################################################
-p 1 route add default 4 #SINK2
-p 1 route add 100.0.0.0 16 port 0 ether 10.0.0.2
-p 1 route add 100.1.0.0 16 port 1 ether 10.1.0.2
-p 1 route add 100.2.0.0 16 port 2 ether 10.2.0.2
-p 1 route add 100.3.0.0 16 port 3 ether 10.3.0.2
-#p 1 route ls
-
-################################################################################
-# Local destination UDP traffic
-################################################################################
-# Prio = Lowest: [SA = ANY, DA = ANY, SP = ANY, DP = ANY, PROTO = ANY] => Drop
-# Prio = 1 (High): [SA = ANY, DA = 10.0.0.1, SP = ANY, DP = 1000, PROTO = UDP] => Allow
-# Prio = 1 (High): [SA = ANY, DA = 10.1.0.1, SP = ANY, DP = 1001, PROTO = UDP] => Allow
-# Prio = 1 (High): [SA = ANY, DA = 10.2.0.1, SP = ANY, DP = 1002, PROTO = UDP] => Allow
-# Prio = 1 (High): [SA = ANY, DA = 10.3.0.1, SP = ANY, DP = 1003, PROTO = UDP] => Allow
-p 2 firewall add default 1 #SINK0
-p 2 firewall add priority 1 ipv4 0.0.0.0 0 10.0.0.1 32 0 65535 1000 1000 17 0xF port 0
-p 2 firewall add priority 1 ipv4 0.0.0.0 0 10.1.0.1 32 0 65535 1001 1001 17 0xF port 0
-p 2 firewall add priority 1 ipv4 0.0.0.0 0 10.2.0.1 32 0 65535 1002 1002 17 0xF port 0
-p 2 firewall add priority 1 ipv4 0.0.0.0 0 10.3.0.1 32 0 65535 1003 1003 17 0xF port 0
-#p 2 firewall ls
-
-################################################################################
-# Local destination TCP traffic
-################################################################################
-# Unknown connection => Drop
-# TCP [SA = 100.0.0.10, DA = 10.0.0.1, SP = 1000, DP = 80] => socket ID = 0
-# TCP [SA = 100.1.0.10, DA = 10.1.0.1, SP = 1001, DP = 80] => socket ID = 1
-# TCP [SA = 100.2.0.10, DA = 10.2.0.1, SP = 1002, DP = 80] => socket ID = 2
-# TCP [SA = 100.3.0.10, DA = 10.3.0.1, SP = 1003, DP = 80] => socket ID = 3
-p 3 flow add default 1 #SINK1
-p 3 flow add ipv4 100.0.0.10 10.0.0.1 1000 80 6 port 0 id 0
-p 3 flow add ipv4 100.1.0.10 10.1.0.1 1001 80 6 port 0 id 1
-p 3 flow add ipv4 100.2.0.10 10.2.0.1 1002 80 6 port 0 id 2
-p 3 flow add ipv4 100.3.0.10 10.3.0.1 1003 80 6 port 0 id 3
-#p 3 flow ls
diff --git a/examples/ip_pipeline/config/pipeline-to-core-mapping.py b/examples/ip_pipeline/config/pipeline-to-core-mapping.py
deleted file mode 100755
index fc52b2b..0000000
--- a/examples/ip_pipeline/config/pipeline-to-core-mapping.py
+++ /dev/null
@@ -1,906 +0,0 @@
-#!/usr/bin/env python
-# SPDX-License-Identifier: BSD-3-Clause
-# Copyright(c) 2016 Intel Corporation
-
-#
-# This script maps the set of pipelines identified (MASTER pipelines are
-# ignored) from the input configuration file to the set of cores
-# provided as input argument and creates configuration files for each of
-# the mapping combinations.
-#
-
-from __future__ import print_function
-from collections import namedtuple
-import argparse
-import array
-import errno
-import itertools
-import os
-import re
-import sys
-
-# default values
-enable_stage0_traceout = 1
-enable_stage1_traceout = 1
-enable_stage2_traceout = 1
-
-enable_stage1_fileout = 1
-enable_stage2_fileout = 1
-
-Constants = namedtuple('Constants', ['MAX_CORES', 'MAX_PIPELINES'])
-constants = Constants(16, 64)
-
-# pattern for physical core
-pattern_phycore = '^(s|S)\d(c|C)[1-9][0-9]*$'
-reg_phycore = re.compile(pattern_phycore)
-
-
-def popcount(mask):
-    return bin(mask).count("1")
-
-
-def len2mask(length):
-    if (length == 0):
-        return 0
-
-    if (length > 64):
-        sys.exit('error: len2mask - length %i > 64. exiting' % length)
-
-    return int('1' * length, 2)
-
-
-def bitstring_write(n, n_bits):
-    tmpstr = ""
-    if (n_bits > 64):
-        return
-
-    i = n_bits - 1
-    while (i >= 0):
-        cond = (n & (1 << i))
-        if (cond):
-            print('1', end='')
-            tmpstr += '1'
-        else:
-            print('0', end='')
-            tmpstr += '0'
-        i -= 1
-    return tmpstr
-
-
-class Cores0:
-
-    def __init__(self):
-        self.n_pipelines = 0
-
-
-class Cores1:
-
-    def __init__(self):
-        self.pipelines = 0
-        self.n_pipelines = 0
-
-
-class Cores2:
-
-    def __init__(self):
-        self.pipelines = 0
-        self.n_pipelines = 0
-        self.counter = 0
-        self.counter_max = 0
-        self.bitpos = array.array(
-            "L", itertools.repeat(0, constants.MAX_PIPELINES))
-
-
-class Context0:
-
-    def __init__(self):
-        self.cores = [Cores0() for i in range(0, constants.MAX_CORES)]
-        self.n_cores = 0
-        self.n_pipelines = 0
-        self.n_pipelines0 = 0
-        self.pos = 0
-        self.file_comment = ""
-        self.ctx1 = None
-        self.ctx2 = None
-
-    def stage0_print(self):
-        print('printing Context0 obj')
-        print('c0.cores(n_pipelines) = [ ', end='')
-        for cores_count in range(0, constants.MAX_CORES):
-            print(self.cores[cores_count].n_pipelines, end=' ')
-        print(']')
-        print('c0.n_cores = %d' % self.n_cores)
-        print('c0.n_pipelines = %d' % self.n_pipelines)
-        print('c0.n_pipelines0 = %d' % self.n_pipelines0)
-        print('c0.pos = %d' % self.pos)
-        print('c0.file_comment = %s' % self.file_comment)
-        if (self.ctx1 is not None):
-            print('c0.ctx1 = ', end='')
-            print(repr(self.ctx1))
-        else:
-            print('c0.ctx1 = None')
-
-        if (self.ctx2 is not None):
-            print('c0.ctx2 = ', end='')
-            print(repr(self.ctx2))
-        else:
-            print('c0.ctx2 = None')
-
-    def stage0_init(self, num_cores, num_pipelines, ctx1, ctx2):
-        self.n_cores = num_cores
-        self.n_pipelines = num_pipelines
-        self.ctx1 = ctx1
-        self.ctx2 = ctx2
-
-    def stage0_process(self):
-        # stage0 init
-        self.cores[0].n_pipelines = self.n_pipelines
-        self.n_pipelines0 = 0
-        self.pos = 1
-
-        while True:
-            # go forward
-            while True:
-                if ((self.pos < self.n_cores) and (self.n_pipelines0 > 0)):
-                    self.cores[self.pos].n_pipelines = min(
-                        self.cores[self.pos - 1].n_pipelines,
-                        self.n_pipelines0)
-                    self.n_pipelines0 -= self.cores[self.pos].n_pipelines
-                    self.pos += 1
-                else:
-                    break
-
-            # check solution
-            if (self.n_pipelines0 == 0):
-                self.stage0_log()
-                self.ctx1.stage1_init(self, self.ctx2)  # self is object c0
-                self.ctx1.stage1_process()
-
-            # go backward
-            while True:
-                if (self.pos == 0):
-                    return
-
-                self.pos -= 1
-                if ((self.cores[self.pos].n_pipelines > 1) and
-                        (self.pos != (self.n_cores - 1))):
-                    break
-
-                self.n_pipelines0 += self.cores[self.pos].n_pipelines
-                self.cores[self.pos].n_pipelines = 0
-
-            # rearm
-            self.cores[self.pos].n_pipelines -= 1
-            self.n_pipelines0 += 1
-            self.pos += 1
-
-    def stage0_log(self):
-        tmp_file_comment = ""
-        if(enable_stage0_traceout != 1):
-            return
-
-        print('STAGE0: ', end='')
-        tmp_file_comment += 'STAGE0: '
-        for cores_count in range(0, self.n_cores):
-            print('C%d = %d\t'
-                  % (cores_count,
-                      self.cores[cores_count].n_pipelines), end='')
-            tmp_file_comment += "C{} = {}\t".format(
-                cores_count, self.cores[cores_count].n_pipelines)
-        # end for
-        print('')
-        self.ctx1.stage0_file_comment = tmp_file_comment
-        self.ctx2.stage0_file_comment = tmp_file_comment
-
-
-class Context1:
-    _fileTrace = None
-
-    def __init__(self):
-        self.cores = [Cores1() for i in range(constants.MAX_CORES)]
-        self.n_cores = 0
-        self.n_pipelines = 0
-        self.pos = 0
-        self.stage0_file_comment = ""
-        self.stage1_file_comment = ""
-
-        self.ctx2 = None
-        self.arr_pipelines2cores = []
-
-    def stage1_reset(self):
-        for i in range(constants.MAX_CORES):
-            self.cores[i].pipelines = 0
-            self.cores[i].n_pipelines = 0
-
-        self.n_cores = 0
-        self.n_pipelines = 0
-        self.pos = 0
-        self.ctx2 = None
-        # clear list
-        del self.arr_pipelines2cores[:]
-
-    def stage1_print(self):
-        print('printing Context1 obj')
-        print('ctx1.cores(pipelines,n_pipelines) = [ ', end='')
-        for cores_count in range(0, constants.MAX_CORES):
-            print('(%d,%d)' % (self.cores[cores_count].pipelines,
-                               self.cores[cores_count].n_pipelines), end=' ')
-        print(']')
-        print('ctx1.n_cores = %d' % self.n_cores)
-        print('ctx1.n_pipelines = %d' % self.n_pipelines)
-        print('ctx1.pos = %d' % self.pos)
-        print('ctx1.stage0_file_comment = %s' % self.stage0_file_comment)
-        print('ctx1.stage1_file_comment = %s' % self.stage1_file_comment)
-        if (self.ctx2 is not None):
-            print('ctx1.ctx2 = ', end='')
-            print(self.ctx2)
-        else:
-            print('ctx1.ctx2 = None')
-
-    def stage1_init(self, c0, ctx2):
-        self.stage1_reset()
-        self.n_cores = 0
-        while (c0.cores[self.n_cores].n_pipelines > 0):
-            self.n_cores += 1
-
-        self.n_pipelines = c0.n_pipelines
-        self.ctx2 = ctx2
-
-        self.arr_pipelines2cores = [0] * self.n_pipelines
-
-        i = 0
-        while (i < self.n_cores):
-            self.cores[i].n_pipelines = c0.cores[i].n_pipelines
-            i += 1
-
-    def stage1_process(self):
-        pipelines_max = len2mask(self.n_pipelines)
-        while True:
-            pos = 0
-            overlap = 0
-
-            if (self.cores[self.pos].pipelines == pipelines_max):
-                if (self.pos == 0):
-                    return
-
-                self.cores[self.pos].pipelines = 0
-                self.pos -= 1
-                continue
-
-            self.cores[self.pos].pipelines += 1
-            if (popcount(self.cores[self.pos].pipelines) !=
-                    self.cores[self.pos].n_pipelines):
-                continue
-
-            overlap = 0
-            pos = 0
-            while (pos < self.pos):
-                if ((self.cores[self.pos].pipelines) &
-                        (self.cores[pos].pipelines)):
-                    overlap = 1
-                    break
-                pos += 1
-
-            if (overlap):
-                continue
-
-            if ((self.pos > 0) and
-                ((self.cores[self.pos].n_pipelines) ==
-                    (self.cores[self.pos - 1].n_pipelines)) and
-                    ((self.cores[self.pos].pipelines) <
-                        (self.cores[self.pos - 1].pipelines))):
-                continue
-
-            if (self.pos == self.n_cores - 1):
-                self.stage1_log()
-                self.ctx2.stage2_init(self)
-                self.ctx2.stage2_process()
-
-                if (self.pos == 0):
-                    return
-
-                self.cores[self.pos].pipelines = 0
-                self.pos -= 1
-                continue
-
-            self.pos += 1
-
-    def stage1_log(self):
-        tmp_file_comment = ""
-        if(enable_stage1_traceout == 1):
-            print('STAGE1: ', end='')
-            tmp_file_comment += 'STAGE1: '
-            i = 0
-            while (i < self.n_cores):
-                print('C%d = [' % i, end='')
-                tmp_file_comment += "C{} = [".format(i)
-
-                j = self.n_pipelines - 1
-                while (j >= 0):
-                    cond = ((self.cores[i].pipelines) & (1 << j))
-                    if (cond):
-                        print('1', end='')
-                        tmp_file_comment += '1'
-                    else:
-                        print('0', end='')
-                        tmp_file_comment += '0'
-                    j -= 1
-
-                print(']\t', end='')
-                tmp_file_comment += ']\t'
-                i += 1
-
-            print('\n', end='')
-            self.stage1_file_comment = tmp_file_comment
-            self.ctx2.stage1_file_comment = tmp_file_comment
-
-        # check if file traceing is enabled
-        if(enable_stage1_fileout != 1):
-            return
-
-        # spit out the combination to file
-        self.stage1_process_file()
-
-    def stage1_updateCoresInBuf(self, nPipeline, sCore):
-        rePipeline = self._fileTrace.arr_pipelines[nPipeline]
-        rePipeline = rePipeline.replace("[", "\[").replace("]", "\]")
-        reCore = 'core\s*=\s*((\d*)|(((s|S)\d)?(c|C)[1-9][0-9]*)).*\n'
-        sSubs = 'core = ' + sCore + '\n'
-
-        reg_pipeline = re.compile(rePipeline)
-        search_match = reg_pipeline.search(self._fileTrace.in_buf)
-
-        if(search_match):
-            pos = search_match.start()
-            substr1 = self._fileTrace.in_buf[:pos]
-            substr2 = self._fileTrace.in_buf[pos:]
-            substr2 = re.sub(reCore, sSubs, substr2, 1)
-            self._fileTrace.in_buf = substr1 + substr2
-
-    def stage1_process_file(self):
-        outFileName = os.path.join(self._fileTrace.out_path,
-                                   self._fileTrace.prefix_outfile)
-        outFileName += "_{}CoReS".format(self.n_cores)
-
-        i = 0  # represents core number
-        while (i < self.n_cores):
-            j = self.n_pipelines - 1
-            pipeline_idx = 0
-            while(j >= 0):
-                cond = ((self.cores[i].pipelines) & (1 << j))
-                if (cond):
-                    # update the pipelines array to match the core
-                    # only in case of cond match
-                    self.arr_pipelines2cores[
-                        pipeline_idx] = fileTrace.in_physical_cores[i]
-
-                j -= 1
-                pipeline_idx += 1
-
-            i += 1
-
-        # update the in_buf as per the arr_pipelines2cores
-        for pipeline_idx in range(len(self.arr_pipelines2cores)):
-            outFileName += "_{}".format(self.arr_pipelines2cores[pipeline_idx])
-            self.stage1_updateCoresInBuf(
-                pipeline_idx, self.arr_pipelines2cores[pipeline_idx])
-
-        # by now the in_buf is all set to be written to file
-        outFileName += self._fileTrace.suffix_outfile
-        outputFile = open(outFileName, "w")
-
-        # write out the comments
-        strTruncated = ("", "(Truncated)")[self._fileTrace.ncores_truncated]
-        outputFile.write(
-            "; =============== Pipeline-to-Core Mapping ================\n"
-            "; Generated from file {}\n"
-            "; Input pipelines = {}\n"
-            "; Input cores = {}\n"
-            "; N_PIPELINES = {} N_CORES = {} {} hyper_thread = {}\n"
-            .format(
-                self._fileTrace.in_file_namepath,
-                fileTrace.arr_pipelines,
-                fileTrace.in_physical_cores,
-                self._fileTrace.n_pipelines,
-                self._fileTrace.n_cores,
-                strTruncated,
-                self._fileTrace.hyper_thread))
-
-        outputFile.write(
-            "; {stg0cmt}\n"
-            "; {stg1cmt}\n"
-            "; ========================================================\n"
-            "; \n"
-            .format(
-                stg0cmt=self.stage0_file_comment,
-                stg1cmt=self.stage1_file_comment))
-
-        # write buffer contents
-        outputFile.write(self._fileTrace.in_buf)
-        outputFile.flush()
-        outputFile.close()
-
-
-class Context2:
-    _fileTrace = None
-
-    def __init__(self):
-        self.cores = [Cores2() for i in range(constants.MAX_CORES)]
-        self.n_cores = 0
-        self.n_pipelines = 0
-        self.pos = 0
-        self.stage0_file_comment = ""
-        self.stage1_file_comment = ""
-        self.stage2_file_comment = ""
-
-        # each array entry is a pipeline mapped to core stored as string
-        # pipeline ranging from 1 to n, however stored in zero based array
-        self.arr2_pipelines2cores = []
-
-    def stage2_print(self):
-        print('printing Context2 obj')
-        print('ctx2.cores(pipelines, n_pipelines, counter, counter_max) =')
-        for cores_count in range(0, constants.MAX_CORES):
-            print('core[%d] = (%d,%d,%d,%d)' % (
-                cores_count,
-                self.cores[cores_count].pipelines,
-                self.cores[cores_count].n_pipelines,
-                self.cores[cores_count].counter,
-                self.cores[cores_count].counter_max))
-
-            print('ctx2.n_cores = %d' % self.n_cores, end='')
-            print('ctx2.n_pipelines = %d' % self.n_pipelines, end='')
-            print('ctx2.pos = %d' % self.pos)
-            print('ctx2.stage0_file_comment = %s' %
-                  self.self.stage0_file_comment)
-            print('ctx2.stage1_file_comment = %s' %
-                  self.self.stage1_file_comment)
-            print('ctx2.stage2_file_comment = %s' %
-                  self.self.stage2_file_comment)
-
-    def stage2_reset(self):
-        for i in range(0, constants.MAX_CORES):
-            self.cores[i].pipelines = 0
-            self.cores[i].n_pipelines = 0
-            self.cores[i].counter = 0
-            self.cores[i].counter_max = 0
-
-            for idx in range(0, constants.MAX_PIPELINES):
-                self.cores[i].bitpos[idx] = 0
-
-        self.n_cores = 0
-        self.n_pipelines = 0
-        self.pos = 0
-        # clear list
-        del self.arr2_pipelines2cores[:]
-
-    def bitpos_load(self, coreidx):
-        i = j = 0
-        while (i < self.n_pipelines):
-            if ((self.cores[coreidx].pipelines) &
-                    (1 << i)):
-                self.cores[coreidx].bitpos[j] = i
-                j += 1
-            i += 1
-        self.cores[coreidx].n_pipelines = j
-
-    def bitpos_apply(self, in_buf, pos, n_pos):
-        out = 0
-        for i in range(0, n_pos):
-            out |= (in_buf & (1 << i)) << (pos[i] - i)
-
-        return out
-
-    def stage2_init(self, ctx1):
-        self.stage2_reset()
-        self.n_cores = ctx1.n_cores
-        self.n_pipelines = ctx1.n_pipelines
-
-        self.arr2_pipelines2cores = [''] * self.n_pipelines
-
-        core_idx = 0
-        while (core_idx < self.n_cores):
-            self.cores[core_idx].pipelines = ctx1.cores[core_idx].pipelines
-
-            self.bitpos_load(core_idx)
-            core_idx += 1
-
-    def stage2_log(self):
-        tmp_file_comment = ""
-        if(enable_stage2_traceout == 1):
-            print('STAGE2: ', end='')
-            tmp_file_comment += 'STAGE2: '
-
-            for i in range(0, self.n_cores):
-                mask = len2mask(self.cores[i].n_pipelines)
-                pipelines_ht0 = self.bitpos_apply(
-                    (~self.cores[i].counter) & mask,
-                    self.cores[i].bitpos,
-                    self.cores[i].n_pipelines)
-
-                pipelines_ht1 = self.bitpos_apply(
-                    self.cores[i].counter,
-                    self.cores[i].bitpos,
-                    self.cores[i].n_pipelines)
-
-                print('C%dHT0 = [' % i, end='')
-                tmp_file_comment += "C{}HT0 = [".format(i)
-                tmp_file_comment += bitstring_write(
-                    pipelines_ht0, self.n_pipelines)
-
-                print(']\tC%dHT1 = [' % i, end='')
-                tmp_file_comment += "]\tC{}HT1 = [".format(i)
-                tmp_file_comment += bitstring_write(
-                    pipelines_ht1, self.n_pipelines)
-                print(']\t', end='')
-                tmp_file_comment += ']\t'
-
-            print('')
-            self.stage2_file_comment = tmp_file_comment
-
-        # check if file traceing is enabled
-        if(enable_stage2_fileout != 1):
-            return
-        # spit out the combination to file
-        self.stage2_process_file()
-
-    def stage2_updateCoresInBuf(self, nPipeline, sCore):
-        rePipeline = self._fileTrace.arr_pipelines[nPipeline]
-        rePipeline = rePipeline.replace("[", "\[").replace("]", "\]")
-        reCore = 'core\s*=\s*((\d*)|(((s|S)\d)?(c|C)[1-9][0-9]*)).*\n'
-        sSubs = 'core = ' + sCore + '\n'
-
-        reg_pipeline = re.compile(rePipeline)
-        search_match = reg_pipeline.search(self._fileTrace.in_buf)
-
-        if(search_match):
-            pos = search_match.start()
-            substr1 = self._fileTrace.in_buf[:pos]
-            substr2 = self._fileTrace.in_buf[pos:]
-            substr2 = re.sub(reCore, sSubs, substr2, 1)
-            self._fileTrace.in_buf = substr1 + substr2
-
-    def pipelines2cores(self, n, n_bits, nCore, bHT):
-        if (n_bits > 64):
-            return
-
-        i = n_bits - 1
-        pipeline_idx = 0
-        while (i >= 0):
-            cond = (n & (1 << i))
-            if (cond):
-                # update the pipelines array to match the core
-                # only in case of cond match
-                # PIPELINE0 and core 0 are reserved
-                if(bHT):
-                    tmpCore = fileTrace.in_physical_cores[nCore] + 'h'
-                    self.arr2_pipelines2cores[pipeline_idx] = tmpCore
-                else:
-                    self.arr2_pipelines2cores[pipeline_idx] = \
-                        fileTrace.in_physical_cores[nCore]
-
-            i -= 1
-            pipeline_idx += 1
-
-    def stage2_process_file(self):
-        outFileName = os.path.join(self._fileTrace.out_path,
-                                   self._fileTrace.prefix_outfile)
-        outFileName += "_{}CoReS".format(self.n_cores)
-
-        for i in range(0, self.n_cores):
-            mask = len2mask(self.cores[i].n_pipelines)
-            pipelines_ht0 = self.bitpos_apply((~self.cores[i].counter) & mask,
-                                              self.cores[i].bitpos,
-                                              self.cores[i].n_pipelines)
-
-            pipelines_ht1 = self.bitpos_apply(self.cores[i].counter,
-                                              self.cores[i].bitpos,
-                                              self.cores[i].n_pipelines)
-
-            # update pipelines to core mapping
-            self.pipelines2cores(pipelines_ht0, self.n_pipelines, i, False)
-            self.pipelines2cores(pipelines_ht1, self.n_pipelines, i, True)
-
-        # update the in_buf as per the arr_pipelines2cores
-        for pipeline_idx in range(len(self.arr2_pipelines2cores)):
-            outFileName += "_{}".format(
-                self.arr2_pipelines2cores[pipeline_idx])
-            self.stage2_updateCoresInBuf(
-                pipeline_idx, self.arr2_pipelines2cores[pipeline_idx])
-
-        # by now the in_buf is all set to be written to file
-        outFileName += self._fileTrace.suffix_outfile
-        outputFile = open(outFileName, "w")
-
-        # write the file comments
-        strTruncated = ("", "(Truncated)")[self._fileTrace.ncores_truncated]
-        outputFile.write(
-            "; =============== Pipeline-to-Core Mapping ================\n"
-            "; Generated from file {}\n"
-            "; Input pipelines = {}\n"
-            "; Input cores = {}\n"
-            "; N_PIPELINES = {}  N_CORES = {} {} hyper_thread = {} \n"
-            .format(
-                self._fileTrace.in_file_namepath,
-                fileTrace.arr_pipelines,
-                fileTrace.in_physical_cores,
-                self._fileTrace.n_pipelines,
-                self._fileTrace.n_cores,
-                strTruncated,
-                self._fileTrace.hyper_thread))
-
-        outputFile.write(
-            "; {stg0cmt}\n"
-            "; {stg1cmt}\n"
-            "; {stg2cmt}\n"
-            "; ========================================================\n"
-            "; \n"
-            .format(
-                stg0cmt=self.stage0_file_comment,
-                stg1cmt=self.stage1_file_comment,
-                stg2cmt=self.stage2_file_comment))
-
-        # write the buffer contents
-        outputFile.write(self._fileTrace.in_buf)
-        outputFile.flush()
-        outputFile.close()
-
-    def stage2_process(self):
-        i = 0
-        while(i < self.n_cores):
-            self.cores[i].counter_max = len2mask(
-                self.cores[i].n_pipelines - 1)
-            i += 1
-
-        self.pos = self.n_cores - 1
-        while True:
-            if (self.pos == self.n_cores - 1):
-                self.stage2_log()
-
-            if (self.cores[self.pos].counter ==
-                    self.cores[self.pos].counter_max):
-                if (self.pos == 0):
-                    return
-
-                self.cores[self.pos].counter = 0
-                self.pos -= 1
-                continue
-
-            self.cores[self.pos].counter += 1
-            if(self.pos < self.n_cores - 1):
-                self.pos += 1
-
-
-class FileTrace:
-
-    def __init__(self, filenamepath):
-        self.in_file_namepath = os.path.abspath(filenamepath)
-        self.in_filename = os.path.basename(self.in_file_namepath)
-        self.in_path = os.path.dirname(self.in_file_namepath)
-
-        filenamesplit = self.in_filename.split('.')
-        self.prefix_outfile = filenamesplit[0]
-        self.suffix_outfile = ".cfg"
-
-        # output folder:  in the same folder as input file
-        # create new folder in the name of input file
-        self.out_path = os.path.join(
-            os.path.abspath(os.path.dirname(__file__)),
-            self.prefix_outfile)
-
-        try:
-            os.makedirs(self.out_path)
-        except OSError as excep:
-            if excep.errno == errno.EEXIST and os.path.isdir(self.out_path):
-                pass
-            else:
-                raise
-
-        self.in_buf = None
-        self.arr_pipelines = []  # holds the positions of search
-
-        self.max_cores = 15
-        self.max_pipelines = 15
-
-        self.in_physical_cores = None
-        self.hyper_thread = None
-
-        # save the num of pipelines determined from input file
-        self.n_pipelines = 0
-        # save the num of cores input (or the truncated value)
-        self.n_cores = 0
-        self.ncores_truncated = False
-
-    def print_TraceFile(self):
-        print("self.in_file_namepath = ", self.in_file_namepath)
-        print("self.in_filename = ", self.in_filename)
-        print("self.in_path = ", self.in_path)
-        print("self.out_path = ", self.out_path)
-        print("self.prefix_outfile = ", self.prefix_outfile)
-        print("self.suffix_outfile = ", self.suffix_outfile)
-        print("self.in_buf = ", self.in_buf)
-        print("self.arr_pipelines =", self.arr_pipelines)
-        print("self.in_physical_cores", self.in_physical_cores)
-        print("self.hyper_thread", self.hyper_thread)
-
-
-def process(n_cores, n_pipelines, fileTrace):
-    '''process and map pipelines, cores.'''
-    if (n_cores == 0):
-        sys.exit('N_CORES is 0, exiting')
-
-    if (n_pipelines == 0):
-        sys.exit('N_PIPELINES is 0, exiting')
-
-    if (n_cores > n_pipelines):
-        print('\nToo many cores, truncating N_CORES to N_PIPELINES')
-        n_cores = n_pipelines
-        fileTrace.ncores_truncated = True
-
-    fileTrace.n_pipelines = n_pipelines
-    fileTrace.n_cores = n_cores
-
-    strTruncated = ("", "(Truncated)")[fileTrace.ncores_truncated]
-    print("N_PIPELINES = {}, N_CORES = {} {}"
-          .format(n_pipelines, n_cores, strTruncated))
-    print("---------------------------------------------------------------")
-
-    ctx0_inst = Context0()
-    ctx1_inst = Context1()
-    ctx2_inst = Context2()
-
-    # initialize the class variables
-    ctx1_inst._fileTrace = fileTrace
-    ctx2_inst._fileTrace = fileTrace
-
-    ctx0_inst.stage0_init(n_cores, n_pipelines, ctx1_inst, ctx2_inst)
-    ctx0_inst.stage0_process()
-
-
-def validate_core(core):
-    match = reg_phycore.match(core)
-    if(match):
-        return True
-    else:
-        return False
-
-
-def validate_phycores(phy_cores):
-    '''validate physical cores, check if unique.'''
-    # eat up whitespaces
-    phy_cores = phy_cores.strip().split(',')
-
-    # check if the core list is unique
-    if(len(phy_cores) != len(set(phy_cores))):
-        print('list of physical cores has duplicates')
-        return None
-
-    for core in phy_cores:
-        if not validate_core(core):
-            print('invalid physical core specified.')
-            return None
-    return phy_cores
-
-
-def scanconfigfile(fileTrace):
-    '''scan input file for pipelines, validate then process.'''
-    # open file
-    filetoscan = open(fileTrace.in_file_namepath, 'r')
-    fileTrace.in_buf = filetoscan.read()
-
-    # reset iterator on open file
-    filetoscan.seek(0)
-
-    # scan input file for pipelines
-    # master pipelines to be ignored
-    pattern_pipeline = r'\[PIPELINE\d*\]'
-    pattern_mastertype = r'type\s*=\s*MASTER'
-
-    pending_pipeline = False
-    for line in filetoscan:
-        match_pipeline = re.search(pattern_pipeline, line)
-        match_type = re.search('type\s*=', line)
-        match_mastertype = re.search(pattern_mastertype, line)
-
-        if(match_pipeline):
-            sPipeline = line[match_pipeline.start():match_pipeline.end()]
-            pending_pipeline = True
-        elif(match_type):
-            # found a type definition...
-            if(match_mastertype is None):
-                # and this is not a master pipeline...
-                if(pending_pipeline):
-                    # add it to the list of pipelines to be mapped
-                    fileTrace.arr_pipelines.append(sPipeline)
-                    pending_pipeline = False
-            else:
-                # and this is a master pipeline...
-                # ignore the current and move on to next
-                sPipeline = ""
-                pending_pipeline = False
-    filetoscan.close()
-
-    # validate if pipelines are unique
-    if(len(fileTrace.arr_pipelines) != len(set(fileTrace.arr_pipelines))):
-        sys.exit('Error: duplicate pipelines in input file')
-
-    num_pipelines = len(fileTrace.arr_pipelines)
-    num_cores = len(fileTrace.in_physical_cores)
-
-    print("-------------------Pipeline-to-core mapping--------------------")
-    print("Input pipelines = {}\nInput cores = {}"
-          .format(fileTrace.arr_pipelines, fileTrace.in_physical_cores))
-
-    # input configuration file validations goes here
-    if (num_cores > fileTrace.max_cores):
-        sys.exit('Error: number of cores specified > max_cores (%d)' %
-                 fileTrace.max_cores)
-
-    if (num_pipelines > fileTrace.max_pipelines):
-        sys.exit('Error: number of pipelines in input \
-                cfg file > max_pipelines (%d)' % fileTrace.max_pipelines)
-
-    # call process to generate pipeline-to-core mapping, trace and log
-    process(num_cores, num_pipelines, fileTrace)
-
-
-if __name__ == "__main__":
-    parser = argparse.ArgumentParser(description='mappipelines')
-
-    reqNamedGrp = parser.add_argument_group('required named args')
-    reqNamedGrp.add_argument(
-        '-i',
-        '--input-file',
-        type=argparse.FileType('r'),
-        help='Input config file',
-        required=True)
-
-    reqNamedGrp.add_argument(
-        '-pc',
-        '--physical-cores',
-        type=validate_phycores,
-        help='''Enter available CPU cores in
-                format:\"<core>,<core>,...\"
-                where each core format: \"s<SOCKETID>c<COREID>\"
-                where SOCKETID={0..9}, COREID={1-99}''',
-        required=True)
-
-    # add optional arguments
-    parser.add_argument(
-        '-ht',
-        '--hyper-thread',
-        help='enable/disable hyper threading. default is ON',
-        default='ON',
-        choices=['ON', 'OFF'])
-
-    parser.add_argument(
-        '-nO',
-        '--no-output-file',
-        help='''disable output config file generation.
-                Output file generation is enabled by default''',
-        action="store_true")
-
-    args = parser.parse_args()
-
-    if(args.physical_cores is None):
-        parser.error("invalid physical_cores specified")
-
-    # create object of FileTrace and initialise
-    fileTrace = FileTrace(args.input_file.name)
-    fileTrace.in_physical_cores = args.physical_cores
-    fileTrace.hyper_thread = args.hyper_thread
-
-    if(fileTrace.hyper_thread == 'OFF'):
-        print("!!!!disabling stage2 HT!!!!")
-        enable_stage2_traceout = 0
-        enable_stage2_fileout = 0
-    elif(fileTrace.hyper_thread == 'ON'):
-        print("!!!!HT enabled. disabling stage1 file generation.!!!!")
-        enable_stage1_fileout = 0
-
-    if(args.no_output_file is True):
-        print("!!!!disabling stage1 and stage2 fileout!!!!")
-        enable_stage1_fileout = 0
-        enable_stage2_fileout = 0
-
-    scanconfigfile(fileTrace)
diff --git a/examples/ip_pipeline/config/tap.cfg b/examples/ip_pipeline/config/tap.cfg
deleted file mode 100644
index 10d35eb..0000000
--- a/examples/ip_pipeline/config/tap.cfg
+++ /dev/null
@@ -1,64 +0,0 @@
-;   BSD LICENSE
-;
-;   Copyright(c) 2016 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.
-
-;             ______________          ______________________
-;            |              |  TAP0  |                      |
-; RXQ0.0 --->|              |------->|--+                   |
-;            |              |  TAP1  |  | br0               |
-; TXQ1.0 <---|              |<-------|<-+                   |
-;            | Pass-through |        |     Linux Kernel     |
-;            |     (P1)     |        |     Network Stack    |
-;            |              |  TAP1  |                      |
-; RXQ1.0 --->|              |------->|--+                   |
-;            |              |  TAP0  |  | br0               |
-; TXQ0.0 <---|              |<-------|<-+                   |
-;            |______________|        |______________________|
-;
-; Configure Linux kernel bridge between TAP0 and TAP1 interfaces:
-;    [Linux]$ ifconfig TAP0 up
-;    [Linux]$ ifconfig TAP1 up
-;    [Linux]$ brctl addbr "br0"
-;    [Linux]$ brctl addif br0 TAP0
-;    [Linux]$ brctl addif br0 TAP1
-;    [Linux]$ ifconfig br0 up
-
-[EAL]
-log_level = 0
-
-[PIPELINE0]
-type = MASTER
-core = 0
-
-[PIPELINE1]
-type = PASS-THROUGH
-core = 1
-pktq_in = RXQ0.0 TAP1 RXQ1.0 TAP0
-pktq_out = TAP0 TXQ1.0 TAP1 TXQ0.0
diff --git a/examples/ip_pipeline/config/tm_profile.cfg b/examples/ip_pipeline/config/tm_profile.cfg
deleted file mode 100644
index 2dfb215..0000000
--- a/examples/ip_pipeline/config/tm_profile.cfg
+++ /dev/null
@@ -1,105 +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.
-
-; This file enables the following hierarchical scheduler configuration for each
-; 10GbE output port:
-;	* Single subport (subport 0):
-;		- Subport rate set to 100% of port rate
-;		- Each of the 4 traffic classes has rate set to 100% of port rate
-;	* 4K pipes per subport 0 (pipes 0 .. 4095) with identical configuration:
-;		- Pipe rate set to 1/4K of port rate
-;		- Each of the 4 traffic classes has rate set to 100% of pipe rate
-;		- Within each traffic class, the byte-level WRR weights for the 4 queues
-;         are set to 1:1:1:1
-;
-; For more details, please refer to chapter "Quality of Service (QoS) Framework"
-; of Data Plane Development Kit (DPDK) Programmer's Guide.
-
-; Port configuration
-[port]
-frame overhead = 24 ; frame overhead = Preamble (7) + SFD (1) + FCS (4) + IFG (12)
-mtu = 1522; mtu = Q-in-Q MTU (FCS not included)
-number of subports per port = 1
-number of pipes per subport = 4096
-queue sizes = 64 64 64 64
-
-; Subport configuration
-[subport 0]
-tb rate = 1250000000           ; Bytes per second
-tb size = 1000000              ; Bytes
-
-tc 0 rate = 1250000000         ; Bytes per second
-tc 1 rate = 1250000000         ; Bytes per second
-tc 2 rate = 1250000000         ; Bytes per second
-tc 3 rate = 1250000000         ; Bytes per second
-tc period = 10                 ; Milliseconds
-
-pipe 0-4095 = 0                ; These pipes are configured with pipe profile 0
-
-; Pipe configuration
-[pipe profile 0]
-tb rate = 305175               ; Bytes per second
-tb size = 1000000              ; Bytes
-
-tc 0 rate = 305175             ; Bytes per second
-tc 1 rate = 305175             ; Bytes per second
-tc 2 rate = 305175             ; Bytes per second
-tc 3 rate = 305175             ; Bytes per second
-tc period = 40                 ; Milliseconds
-
-tc 3 oversubscription weight = 1
-
-tc 0 wrr weights = 1 1 1 1
-tc 1 wrr weights = 1 1 1 1
-tc 2 wrr weights = 1 1 1 1
-tc 3 wrr weights = 1 1 1 1
-
-; RED params per traffic class and color (Green / Yellow / Red)
-[red]
-tc 0 wred min = 48 40 32
-tc 0 wred max = 64 64 64
-tc 0 wred inv prob = 10 10 10
-tc 0 wred weight = 9 9 9
-
-tc 1 wred min = 48 40 32
-tc 1 wred max = 64 64 64
-tc 1 wred inv prob = 10 10 10
-tc 1 wred weight = 9 9 9
-
-tc 2 wred min = 48 40 32
-tc 2 wred max = 64 64 64
-tc 2 wred inv prob = 10 10 10
-tc 2 wred weight = 9 9 9
-
-tc 3 wred min = 48 40 32
-tc 3 wred max = 64 64 64
-tc 3 wred inv prob = 10 10 10
-tc 3 wred weight = 9 9 9
-- 
2.9.3

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

* [dpdk-dev] [PATCH v4 20/49] ip_pipeline: rework and improvements
  2018-03-29 18:31           ` [dpdk-dev] [PATCH v4 00/49] ip_pipeline: refactoring Jasvinder Singh
                               ` (18 preceding siblings ...)
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 19/49] ip_pipeline: remove config Jasvinder Singh
@ 2018-03-29 18:31             ` Jasvinder Singh
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 21/49] ip_pipeline: add cli interface Jasvinder Singh
                               ` (29 subsequent siblings)
  49 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-29 18:31 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

All the actions associated with application pipelines
tables and ports are now implemented using the new action
APIs. Therefore, thousands of lines of code are eliminated
from the application. The reduced code size is easier to
maintain and extend.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/Makefile          |   22 +-
 examples/ip_pipeline/app.h             | 1389 -------------
 examples/ip_pipeline/config_check.c    |  488 -----
 examples/ip_pipeline/config_parse.c    | 3395 --------------------------------
 examples/ip_pipeline/config_parse_tm.c |  419 ----
 examples/ip_pipeline/cpu_core_map.c    |  471 -----
 examples/ip_pipeline/cpu_core_map.h    |   40 -
 examples/ip_pipeline/init.c            | 1343 -------------
 examples/ip_pipeline/main.c            |   36 +-
 examples/ip_pipeline/meson.build       |   10 +-
 examples/ip_pipeline/parser.c          |   16 +-
 examples/ip_pipeline/parser.h          |    8 +
 examples/ip_pipeline/pipeline.h        |   73 -
 examples/ip_pipeline/pipeline_be.h     |  322 ---
 examples/ip_pipeline/thread.c          |  240 ---
 examples/ip_pipeline/thread.h          |   69 -
 16 files changed, 37 insertions(+), 8304 deletions(-)
 delete mode 100644 examples/ip_pipeline/app.h
 delete mode 100644 examples/ip_pipeline/config_check.c
 delete mode 100644 examples/ip_pipeline/config_parse.c
 delete mode 100644 examples/ip_pipeline/config_parse_tm.c
 delete mode 100644 examples/ip_pipeline/cpu_core_map.c
 delete mode 100644 examples/ip_pipeline/cpu_core_map.h
 delete mode 100644 examples/ip_pipeline/init.c
 delete mode 100644 examples/ip_pipeline/pipeline.h
 delete mode 100644 examples/ip_pipeline/pipeline_be.h
 delete mode 100644 examples/ip_pipeline/thread.c
 delete mode 100644 examples/ip_pipeline/thread.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index 8ba7887..981c4f7 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -1,18 +1,13 @@
 # SPDX-License-Identifier: BSD-3-Clause
-# Copyright(c) 2010-2014 Intel Corporation
+# Copyright(c) 2010-2018 Intel Corporation
 
 # binary name
 APP = ip_pipeline
 
 # all source are stored in SRCS-y
 SRCS-y := main.c
-SRCS-y += config_parse.c
 SRCS-y += parser.c
-SRCS-y += config_parse_tm.c
-SRCS-y += config_check.c
-SRCS-y += init.c
-SRCS-y += thread.c
-SRCS-y += cpu_core_map.c
+#SRCS-y += thread.c
 
 # Build using pkg-config variables if possible
 $(shell pkg-config --exists libdpdk)
@@ -30,9 +25,7 @@ CFLAGS += -O3 $(shell pkg-config --cflags libdpdk)
 LDFLAGS_SHARED = $(shell pkg-config --libs libdpdk)
 LDFLAGS_STATIC = -Wl,-Bstatic $(shell pkg-config --static --libs libdpdk)
 
-VPATH += pipeline
-CFLAGS += -I. -I./pipeline/
-CFLAGS += -DALLOW_EXPERIMENTAL_API
+CFLAGS += -I.
 
 OBJS := $(patsubst %.c,build/%.o,$(SRCS-y))
 
@@ -59,21 +52,18 @@ ifeq ($(RTE_SDK),)
 $(error "Please define RTE_SDK environment variable")
 endif
 
-VPATH += $(SRCDIR)/pipeline
-
 # Default target, can be overridden by command line or environment
 RTE_TARGET ?= x86_64-native-linuxapp-gcc
 
 include $(RTE_SDK)/mk/rte.vars.mk
 
-INC += $(sort $(wildcard *.h)) $(sort $(wildcard pipeline/*.h))
+INC += $(sort $(wildcard *.h))
 
 SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) := $(SRCS-y)
 
-CFLAGS += -I$(SRCDIR) -I$(SRCDIR)/pipeline
+CFLAGS += -I$(SRCDIR)
 CFLAGS += -O3
-CFLAGS += $(WERROR_FLAGS) -Wno-error=unused-function -Wno-error=unused-variable
-CFLAGS += -DALLOW_EXPERIMENTAL_API
+CFLAGS += $(WERROR_FLAGS)
 
 include $(RTE_SDK)/mk/rte.extapp.mk
 
diff --git a/examples/ip_pipeline/app.h b/examples/ip_pipeline/app.h
deleted file mode 100644
index dadaf2b..0000000
--- a/examples/ip_pipeline/app.h
+++ /dev/null
@@ -1,1389 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2016 Intel Corporation
- */
-
-#ifndef __INCLUDE_APP_H__
-#define __INCLUDE_APP_H__
-
-#include <stdint.h>
-#include <string.h>
-
-#include <rte_common.h>
-#include <rte_mempool.h>
-#include <rte_ring.h>
-#include <rte_sched.h>
-#include <cmdline_parse.h>
-
-#include <rte_ethdev.h>
-#ifdef RTE_LIBRTE_KNI
-#include <rte_kni.h>
-#endif
-
-#include "cpu_core_map.h"
-#include "pipeline.h"
-
-#define APP_PARAM_NAME_SIZE                      PIPELINE_NAME_SIZE
-#define APP_LINK_PCI_BDF_SIZE                    16
-
-#ifndef APP_LINK_MAX_HWQ_IN
-#define APP_LINK_MAX_HWQ_IN                      128
-#endif
-
-#ifndef APP_LINK_MAX_HWQ_OUT
-#define APP_LINK_MAX_HWQ_OUT                     128
-#endif
-
-struct app_mempool_params {
-	char *name;
-	uint32_t parsed;
-	uint32_t buffer_size;
-	uint32_t pool_size;
-	uint32_t cache_size;
-	uint32_t cpu_socket_id;
-};
-
-struct app_link_params {
-	char *name;
-	uint32_t parsed;
-	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_q; /* 0 = Disabled (pkts go to default queue) */
-	uint32_t ip_local_q; /* 0 = Disabled (pkts go to default queue 0) */
-	uint32_t tcp_local_q; /* 0 = Disabled (pkts go to default queue 0) */
-	uint32_t udp_local_q; /* 0 = Disabled (pkts go to default queue 0) */
-	uint32_t sctp_local_q; /* 0 = Disabled (pkts go to default queue 0) */
-	uint32_t rss_qs[APP_LINK_MAX_HWQ_IN];
-	uint32_t n_rss_qs;
-	uint64_t rss_proto_ipv4;
-	uint64_t rss_proto_ipv6;
-	uint64_t rss_proto_l2;
-	uint32_t promisc;
-	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 */
-	char pci_bdf[APP_LINK_PCI_BDF_SIZE];
-
-	struct rte_eth_conf conf;
-};
-
-struct app_pktq_hwq_in_params {
-	char *name;
-	uint32_t parsed;
-	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;
-	uint32_t parsed;
-	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;
-	uint32_t parsed;
-	uint32_t size;
-	uint32_t burst_read;
-	uint32_t burst_write;
-	uint32_t dropless;
-	uint64_t n_retries;
-	uint32_t cpu_socket_id;
-	uint32_t ipv4_frag;
-	uint32_t ipv6_frag;
-	uint32_t ipv4_ras;
-	uint32_t ipv6_ras;
-	uint32_t mtu;
-	uint32_t metadata_size;
-	uint32_t mempool_direct_id;
-	uint32_t mempool_indirect_id;
-};
-
-struct app_pktq_kni_params {
-	char *name;
-	uint32_t parsed;
-
-	uint32_t socket_id;
-	uint32_t core_id;
-	uint32_t hyper_th_id;
-	uint32_t force_bind;
-
-	uint32_t mempool_id; /* Position in the app->mempool_params */
-	uint32_t burst_read;
-	uint32_t burst_write;
-	uint32_t dropless;
-	uint64_t n_retries;
-};
-
-#ifndef APP_FILE_NAME_SIZE
-#define APP_FILE_NAME_SIZE                       256
-#endif
-
-#ifndef APP_MAX_SCHED_SUBPORTS
-#define APP_MAX_SCHED_SUBPORTS                   8
-#endif
-
-#ifndef APP_MAX_SCHED_PIPES
-#define APP_MAX_SCHED_PIPES                      4096
-#endif
-
-struct app_pktq_tm_params {
-	char *name;
-	uint32_t parsed;
-	const char *file_name;
-	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_tap_params {
-	char *name;
-	uint32_t parsed;
-	uint32_t burst_read;
-	uint32_t burst_write;
-	uint32_t dropless;
-	uint64_t n_retries;
-	uint32_t mempool_id; /* Position in the app->mempool_params */
-};
-
-struct app_pktq_source_params {
-	char *name;
-	uint32_t parsed;
-	uint32_t mempool_id; /* Position in the app->mempool_params array */
-	uint32_t burst;
-	const char *file_name; /* Full path of PCAP file to be copied to mbufs */
-	uint32_t n_bytes_per_pkt;
-};
-
-struct app_pktq_sink_params {
-	char *name;
-	uint8_t parsed;
-	const char *file_name; /* Full path of PCAP file to be copied to mbufs */
-	uint32_t n_pkts_to_dump;
-};
-
-struct app_msgq_params {
-	char *name;
-	uint32_t parsed;
-	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_TAP,
-	APP_PKTQ_IN_KNI,
-	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_TAP,
-	APP_PKTQ_OUT_KNI,
-	APP_PKTQ_OUT_SINK,
-};
-
-struct app_pktq_out_params {
-	enum app_pktq_out_type type;
-	uint32_t id; /* Position in the appropriate app array */
-};
-
-#define APP_PIPELINE_TYPE_SIZE                   PIPELINE_TYPE_SIZE
-
-#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
-
-#define APP_MAX_PIPELINE_ARGS                    PIPELINE_MAX_ARGS
-
-struct app_pipeline_params {
-	char *name;
-	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_params;
-
-typedef void (*app_link_op)(struct app_params *app,
-	uint32_t link_id,
-	uint32_t up,
-	void *arg);
-
-#ifndef APP_MAX_PIPELINES
-#define APP_MAX_PIPELINES                        64
-#endif
-
-struct app_link_data {
-	app_link_op f_link[APP_MAX_PIPELINES];
-	void *arg[APP_MAX_PIPELINES];
-};
-
-struct app_pipeline_data {
-	void *be;
-	void *fe;
-	struct pipeline_type *ptype;
-	uint64_t timer_period;
-	uint32_t enabled;
-};
-
-struct app_thread_pipeline_data {
-	uint32_t pipeline_id;
-	void *be;
-	pipeline_be_op_run f_run;
-	pipeline_be_op_timer f_timer;
-	uint64_t timer_period;
-	uint64_t deadline;
-};
-
-#ifndef APP_MAX_THREAD_PIPELINES
-#define APP_MAX_THREAD_PIPELINES                 64
-#endif
-
-#ifndef APP_THREAD_TIMER_PERIOD
-#define APP_THREAD_TIMER_PERIOD                  1
-#endif
-
-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 timer_period;
-	uint64_t thread_req_deadline;
-
-	uint64_t deadline;
-
-	struct rte_ring *msgq_in;
-	struct rte_ring *msgq_out;
-
-	uint64_t headroom_time;
-	uint64_t headroom_cycles;
-	double headroom_ratio;
-} __rte_cache_aligned;
-
-#ifndef APP_MAX_LINKS
-#define APP_MAX_LINKS                            16
-#endif
-
-struct app_eal_params {
-	/* Map lcore set to physical cpu set */
-	char *coremap;
-
-	/* Core ID that is used as master */
-	uint32_t master_lcore_present;
-	uint32_t master_lcore;
-
-	/* Number of memory channels */
-	uint32_t channels_present;
-	uint32_t channels;
-
-	/* Memory to allocate (see also --socket-mem) */
-	uint32_t memory_present;
-	uint32_t memory;
-
-	/* Force number of memory ranks (don't detect) */
-	uint32_t ranks_present;
-	uint32_t ranks;
-
-	/* Add a PCI device in black list. */
-	char *pci_blacklist[APP_MAX_LINKS];
-
-	/* Add a PCI device in white list. */
-	char *pci_whitelist[APP_MAX_LINKS];
-
-	/* Add a virtual device. */
-	char *vdev[APP_MAX_LINKS];
-
-	 /* Use VMware TSC map instead of native RDTSC */
-	uint32_t vmware_tsc_map_present;
-	int vmware_tsc_map;
-
-	 /* Type of this process (primary|secondary|auto) */
-	char *proc_type;
-
-	 /* Set syslog facility */
-	char *syslog;
-
-	/* Set default log level */
-	uint32_t log_level_present;
-	uint32_t log_level;
-
-	/* Display version information on startup */
-	uint32_t version_present;
-	int version;
-
-	/* This help */
-	uint32_t help_present;
-	int help;
-
-	 /* Use malloc instead of hugetlbfs */
-	uint32_t no_huge_present;
-	int no_huge;
-
-	/* Disable PCI */
-	uint32_t no_pci_present;
-	int no_pci;
-
-	/* Disable HPET */
-	uint32_t no_hpet_present;
-	int no_hpet;
-
-	/* No shared config (mmap'd files) */
-	uint32_t no_shconf_present;
-	int no_shconf;
-
-	/* Add driver */
-	char *add_driver;
-
-	/*  Memory to allocate on sockets (comma separated values)*/
-	char *socket_mem;
-
-	/* Directory where hugetlbfs is mounted */
-	char *huge_dir;
-
-	/* Prefix for hugepage filenames */
-	char *file_prefix;
-
-	/* Base virtual address */
-	char *base_virtaddr;
-
-	/* Create /dev/uioX (usually done by hotplug) */
-	uint32_t create_uio_dev_present;
-	int create_uio_dev;
-
-	/* Interrupt mode for VFIO (legacy|msi|msix) */
-	char *vfio_intr;
-
-	uint32_t parsed;
-};
-
-#ifndef APP_APPNAME_SIZE
-#define APP_APPNAME_SIZE                         256
-#endif
-
-#ifndef APP_MAX_MEMPOOLS
-#define APP_MAX_MEMPOOLS                         8
-#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_TAP
-#define APP_MAX_PKTQ_TAP                         APP_MAX_LINKS
-#endif
-
-#define APP_MAX_PKTQ_KNI                         APP_MAX_LINKS
-
-#ifndef APP_MAX_PKTQ_SOURCE
-#define APP_MAX_PKTQ_SOURCE                      64
-#endif
-
-#ifndef APP_MAX_PKTQ_SINK
-#define APP_MAX_PKTQ_SINK                        64
-#endif
-
-#ifndef APP_MAX_MSGQ
-#define APP_MAX_MSGQ                             256
-#endif
-
-#ifndef APP_EAL_ARGC
-#define APP_EAL_ARGC                             64
-#endif
-
-#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
-
-#ifndef APP_THREAD_HEADROOM_STATS_COLLECT
-#define APP_THREAD_HEADROOM_STATS_COLLECT        1
-#endif
-
-#define APP_CORE_MASK_SIZE					\
-	(RTE_MAX_LCORE / 64 + ((RTE_MAX_LCORE % 64) ? 1 : 0))
-
-struct app_params {
-	/* Config */
-	char app_name[APP_APPNAME_SIZE];
-	const char *config_file;
-	const char *script_file;
-	const char *parser_file;
-	const char *output_file;
-	const char *preproc;
-	const char *preproc_args;
-	uint64_t port_mask;
-	uint32_t log_level;
-
-	struct app_eal_params eal_params;
-	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_tap_params tap_params[APP_MAX_PKTQ_TAP];
-	struct app_pktq_kni_params kni_params[APP_MAX_PKTQ_KNI];
-	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_tap;
-	uint32_t n_pktq_kni;
-	uint32_t n_pktq_source;
-	uint32_t n_pktq_sink;
-	uint32_t n_msgq;
-	uint32_t n_pipelines;
-
-	/* Init */
-	char *eal_argv[1 + APP_EAL_ARGC];
-	struct cpu_core_map *core_map;
-	uint64_t core_mask[APP_CORE_MASK_SIZE];
-	struct rte_mempool *mempool[APP_MAX_MEMPOOLS];
-	struct app_link_data link_data[APP_MAX_LINKS];
-	struct rte_ring *swq[APP_MAX_PKTQ_SWQ];
-	struct rte_sched_port *tm[APP_MAX_PKTQ_TM];
-	int tap[APP_MAX_PKTQ_TAP];
-#ifdef RTE_LIBRTE_KNI
-	struct rte_kni *kni[APP_MAX_PKTQ_KNI];
-#endif /* RTE_LIBRTE_KNI */
-	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];
-
-	int eal_argc;
-	uint32_t n_pipeline_types;
-	uint32_t n_cmds;
-};
-
-#define APP_PARAM_VALID(obj) ((obj)->name != NULL)
-
-#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++;					\
-}
-
-#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 "%" PRIu32, 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 "%" SCNu32, &id);				\
-while (0)								\
-
-#define	APP_CHECK(exp, fmt, ...)					\
-do {									\
-	if (!(exp)) {							\
-		fprintf(stderr, fmt "\n", ## __VA_ARGS__);		\
-		abort();						\
-	}								\
-} while (0)
-
-enum app_log_level {
-	APP_LOG_LEVEL_HIGH = 1,
-	APP_LOG_LEVEL_LOW,
-	APP_LOG_LEVELS
-};
-
-#define APP_LOG(app, level, fmt, ...)					\
-do {									\
-	if (app->log_level >= APP_LOG_LEVEL_ ## level)			\
-		fprintf(stdout, "[APP] " fmt "\n", ## __VA_ARGS__);	\
-} while (0)
-
-static inline uint32_t
-app_link_get_n_rxq(struct app_params *app, struct app_link_params *link)
-{
-	uint32_t n_rxq = 0, link_id, i;
-	uint32_t n_pktq_hwq_in = RTE_MIN(app->n_pktq_hwq_in,
-		RTE_DIM(app->hwq_in_params));
-
-	APP_PARAM_GET_ID(link, "LINK", link_id);
-
-	for (i = 0; i < n_pktq_hwq_in; i++) {
-		struct app_pktq_hwq_in_params *p = &app->hwq_in_params[i];
-		uint32_t rxq_link_id, rxq_queue_id;
-
-		sscanf(p->name, "RXQ%" SCNu32 ".%" SCNu32,
-			&rxq_link_id, &rxq_queue_id);
-		if (rxq_link_id == link_id)
-			n_rxq++;
-	}
-
-	return n_rxq;
-}
-
-static inline uint32_t
-app_link_get_n_txq(struct app_params *app, struct app_link_params *link)
-{
-	uint32_t n_txq = 0, link_id, i;
-	uint32_t n_pktq_hwq_out = RTE_MIN(app->n_pktq_hwq_out,
-		RTE_DIM(app->hwq_out_params));
-
-	APP_PARAM_GET_ID(link, "LINK", link_id);
-
-	for (i = 0; i < n_pktq_hwq_out; i++) {
-		struct app_pktq_hwq_out_params *p = &app->hwq_out_params[i];
-		uint32_t txq_link_id, txq_queue_id;
-
-		sscanf(p->name, "TXQ%" SCNu32 ".%" SCNu32,
-			&txq_link_id, &txq_queue_id);
-		if (txq_link_id == link_id)
-			n_txq++;
-	}
-
-	return n_txq;
-}
-
-static inline uint32_t
-app_rxq_get_readers(struct app_params *app, struct app_pktq_hwq_in_params *rxq)
-{
-	uint32_t pos = rxq - app->hwq_in_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_readers = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_in = RTE_MIN(p->n_pktq_in, RTE_DIM(p->pktq_in));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_in; j++) {
-			struct app_pktq_in_params *pktq = &p->pktq_in[j];
-
-			if ((pktq->type == APP_PKTQ_IN_HWQ) &&
-				(pktq->id == pos))
-				n_readers++;
-		}
-	}
-
-	return n_readers;
-}
-
-static inline uint32_t
-app_swq_get_readers(struct app_params *app, struct app_pktq_swq_params *swq)
-{
-	uint32_t pos = swq - app->swq_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_readers = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_in = RTE_MIN(p->n_pktq_in, RTE_DIM(p->pktq_in));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_in; j++) {
-			struct app_pktq_in_params *pktq = &p->pktq_in[j];
-
-			if ((pktq->type == APP_PKTQ_IN_SWQ) &&
-				(pktq->id == pos))
-				n_readers++;
-		}
-	}
-
-	return n_readers;
-}
-
-static inline struct app_pipeline_params *
-app_swq_get_reader(struct app_params *app,
-	struct app_pktq_swq_params *swq,
-	uint32_t *pktq_in_id)
-{
-	struct app_pipeline_params *reader = NULL;
-	uint32_t pos = swq - app->swq_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_readers = 0, id = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_in = RTE_MIN(p->n_pktq_in, RTE_DIM(p->pktq_in));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_in; j++) {
-			struct app_pktq_in_params *pktq = &p->pktq_in[j];
-
-			if ((pktq->type == APP_PKTQ_IN_SWQ) &&
-				(pktq->id == pos)) {
-				n_readers++;
-				reader = p;
-				id = j;
-			}
-		}
-	}
-
-	if (n_readers != 1)
-		return NULL;
-
-	*pktq_in_id = id;
-	return reader;
-}
-
-static inline uint32_t
-app_tm_get_readers(struct app_params *app, struct app_pktq_tm_params *tm)
-{
-	uint32_t pos = tm - app->tm_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_readers = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_in = RTE_MIN(p->n_pktq_in, RTE_DIM(p->pktq_in));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_in; j++) {
-			struct app_pktq_in_params *pktq = &p->pktq_in[j];
-
-			if ((pktq->type == APP_PKTQ_IN_TM) &&
-				(pktq->id == pos))
-				n_readers++;
-		}
-	}
-
-	return n_readers;
-}
-
-static inline struct app_pipeline_params *
-app_tm_get_reader(struct app_params *app,
-	struct app_pktq_tm_params *tm,
-	uint32_t *pktq_in_id)
-{
-	struct app_pipeline_params *reader = NULL;
-	uint32_t pos = tm - app->tm_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_readers = 0, id = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_in = RTE_MIN(p->n_pktq_in, RTE_DIM(p->pktq_in));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_in; j++) {
-			struct app_pktq_in_params *pktq = &p->pktq_in[j];
-
-			if ((pktq->type == APP_PKTQ_IN_TM) &&
-				(pktq->id == pos)) {
-				n_readers++;
-				reader = p;
-				id = j;
-			}
-		}
-	}
-
-	if (n_readers != 1)
-		return NULL;
-
-	*pktq_in_id = id;
-	return reader;
-}
-
-static inline uint32_t
-app_tap_get_readers(struct app_params *app, struct app_pktq_tap_params *tap)
-{
-	uint32_t pos = tap - app->tap_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_readers = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_in = RTE_MIN(p->n_pktq_in, RTE_DIM(p->pktq_in));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_in; j++) {
-			struct app_pktq_in_params *pktq = &p->pktq_in[j];
-
-			if ((pktq->type == APP_PKTQ_IN_TAP) &&
-				(pktq->id == pos))
-				n_readers++;
-		}
-	}
-
-	return n_readers;
-}
-
-static inline struct app_pipeline_params *
-app_tap_get_reader(struct app_params *app,
-	struct app_pktq_tap_params *tap,
-	uint32_t *pktq_in_id)
-{
-	struct app_pipeline_params *reader = NULL;
-	uint32_t pos = tap - app->tap_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_readers = 0, id = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_in = RTE_MIN(p->n_pktq_in, RTE_DIM(p->pktq_in));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_in; j++) {
-			struct app_pktq_in_params *pktq = &p->pktq_in[j];
-
-			if ((pktq->type == APP_PKTQ_IN_TAP) &&
-				(pktq->id == pos)) {
-				n_readers++;
-				reader = p;
-				id = j;
-			}
-		}
-	}
-
-	if (n_readers != 1)
-		return NULL;
-
-	*pktq_in_id = id;
-	return reader;
-}
-
-static inline uint32_t
-app_kni_get_readers(struct app_params *app, struct app_pktq_kni_params *kni)
-{
-	uint32_t pos = kni - app->kni_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_readers = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_in = RTE_MIN(p->n_pktq_in, RTE_DIM(p->pktq_in));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_in; j++) {
-			struct app_pktq_in_params *pktq = &p->pktq_in[j];
-
-			if ((pktq->type == APP_PKTQ_IN_KNI) &&
-				(pktq->id == pos))
-				n_readers++;
-		}
-	}
-
-	return n_readers;
-}
-
-static inline struct app_pipeline_params *
-app_kni_get_reader(struct app_params *app,
-				  struct app_pktq_kni_params *kni,
-				  uint32_t *pktq_in_id)
-{
-	struct app_pipeline_params *reader = NULL;
-	uint32_t pos = kni - app->kni_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_readers = 0, id = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_in = RTE_MIN(p->n_pktq_in, RTE_DIM(p->pktq_in));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_in; j++) {
-			struct app_pktq_in_params *pktq = &p->pktq_in[j];
-
-			if ((pktq->type == APP_PKTQ_IN_KNI) &&
-				(pktq->id == pos)) {
-				n_readers++;
-				reader = p;
-				id = j;
-			}
-		}
-	}
-
-	if (n_readers != 1)
-		return NULL;
-
-	*pktq_in_id = id;
-	return reader;
-}
-
-static inline uint32_t
-app_source_get_readers(struct app_params *app,
-struct app_pktq_source_params *source)
-{
-	uint32_t pos = source - app->source_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_readers = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_in = RTE_MIN(p->n_pktq_in, RTE_DIM(p->pktq_in));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_in; j++) {
-			struct app_pktq_in_params *pktq = &p->pktq_in[j];
-
-			if ((pktq->type == APP_PKTQ_IN_SOURCE) &&
-				(pktq->id == pos))
-				n_readers++;
-		}
-	}
-
-	return n_readers;
-}
-
-static inline uint32_t
-app_msgq_get_readers(struct app_params *app, struct app_msgq_params *msgq)
-{
-	uint32_t pos = msgq - app->msgq_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_readers = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_msgq_in = RTE_MIN(p->n_msgq_in, RTE_DIM(p->msgq_in));
-		uint32_t j;
-
-		for (j = 0; j < n_msgq_in; j++)
-			if (p->msgq_in[j] == pos)
-				n_readers++;
-	}
-
-	return n_readers;
-}
-
-static inline uint32_t
-app_txq_get_writers(struct app_params *app, struct app_pktq_hwq_out_params *txq)
-{
-	uint32_t pos = txq - app->hwq_out_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_writers = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_out = RTE_MIN(p->n_pktq_out,
-			RTE_DIM(p->pktq_out));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_out; j++) {
-			struct app_pktq_out_params *pktq = &p->pktq_out[j];
-
-			if ((pktq->type == APP_PKTQ_OUT_HWQ) &&
-				(pktq->id == pos))
-				n_writers++;
-		}
-	}
-
-	return n_writers;
-}
-
-static inline uint32_t
-app_swq_get_writers(struct app_params *app, struct app_pktq_swq_params *swq)
-{
-	uint32_t pos = swq - app->swq_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_writers = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_out = RTE_MIN(p->n_pktq_out,
-			RTE_DIM(p->pktq_out));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_out; j++) {
-			struct app_pktq_out_params *pktq = &p->pktq_out[j];
-
-			if ((pktq->type == APP_PKTQ_OUT_SWQ) &&
-				(pktq->id == pos))
-				n_writers++;
-		}
-	}
-
-	return n_writers;
-}
-
-static inline struct app_pipeline_params *
-app_swq_get_writer(struct app_params *app,
-	struct app_pktq_swq_params *swq,
-	uint32_t *pktq_out_id)
-{
-	struct app_pipeline_params *writer = NULL;
-	uint32_t pos = swq - app->swq_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_writers = 0, id = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_out = RTE_MIN(p->n_pktq_out,
-			RTE_DIM(p->pktq_out));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_out; j++) {
-			struct app_pktq_out_params *pktq = &p->pktq_out[j];
-
-			if ((pktq->type == APP_PKTQ_OUT_SWQ) &&
-				(pktq->id == pos)) {
-				n_writers++;
-				writer = p;
-				id = j;
-			}
-		}
-	}
-
-	if (n_writers != 1)
-		return NULL;
-
-	*pktq_out_id = id;
-	return writer;
-}
-
-static inline uint32_t
-app_tm_get_writers(struct app_params *app, struct app_pktq_tm_params *tm)
-{
-	uint32_t pos = tm - app->tm_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_writers = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_out = RTE_MIN(p->n_pktq_out,
-			RTE_DIM(p->pktq_out));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_out; j++) {
-			struct app_pktq_out_params *pktq = &p->pktq_out[j];
-
-			if ((pktq->type == APP_PKTQ_OUT_TM) &&
-				(pktq->id == pos))
-				n_writers++;
-		}
-	}
-
-	return n_writers;
-}
-
-static inline struct app_pipeline_params *
-app_tm_get_writer(struct app_params *app,
-	struct app_pktq_tm_params *tm,
-	uint32_t *pktq_out_id)
-{
-	struct app_pipeline_params *writer = NULL;
-	uint32_t pos = tm - app->tm_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_writers = 0, id = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_out = RTE_MIN(p->n_pktq_out,
-			RTE_DIM(p->pktq_out));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_out; j++) {
-			struct app_pktq_out_params *pktq = &p->pktq_out[j];
-
-			if ((pktq->type == APP_PKTQ_OUT_TM) &&
-				(pktq->id == pos)) {
-				n_writers++;
-				writer = p;
-				id = j;
-			}
-		}
-	}
-
-	if (n_writers != 1)
-		return NULL;
-
-	*pktq_out_id = id;
-	return writer;
-}
-
-static inline uint32_t
-app_tap_get_writers(struct app_params *app, struct app_pktq_tap_params *tap)
-{
-	uint32_t pos = tap - app->tap_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_writers = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_out = RTE_MIN(p->n_pktq_out,
-			RTE_DIM(p->pktq_out));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_out; j++) {
-			struct app_pktq_out_params *pktq = &p->pktq_out[j];
-
-		if ((pktq->type == APP_PKTQ_OUT_TAP) &&
-			(pktq->id == pos))
-			n_writers++;
-		}
-	}
-
-	return n_writers;
-}
-
-static inline struct app_pipeline_params *
-app_tap_get_writer(struct app_params *app,
-	struct app_pktq_tap_params *tap,
-	uint32_t *pktq_out_id)
-{
-	struct app_pipeline_params *writer = NULL;
-	uint32_t pos = tap - app->tap_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_writers = 0, id = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_out = RTE_MIN(p->n_pktq_out,
-			RTE_DIM(p->pktq_out));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_out; j++) {
-			struct app_pktq_out_params *pktq = &p->pktq_out[j];
-
-			if ((pktq->type == APP_PKTQ_OUT_TAP) &&
-				(pktq->id == pos)) {
-				n_writers++;
-				writer = p;
-				id = j;
-			}
-		}
-	}
-
-	if (n_writers != 1)
-		return NULL;
-
-	*pktq_out_id = id;
-	return writer;
-}
-
-static inline uint32_t
-app_kni_get_writers(struct app_params *app, struct app_pktq_kni_params *kni)
-{
-	uint32_t pos = kni - app->kni_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_writers = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_out = RTE_MIN(p->n_pktq_out,
-			RTE_DIM(p->pktq_out));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_out; j++) {
-			struct app_pktq_out_params *pktq = &p->pktq_out[j];
-
-			if ((pktq->type == APP_PKTQ_OUT_KNI) &&
-				(pktq->id == pos))
-				n_writers++;
-		}
-	}
-
-	return n_writers;
-}
-
-static inline struct app_pipeline_params *
-app_kni_get_writer(struct app_params *app,
-				  struct app_pktq_kni_params *kni,
-				  uint32_t *pktq_out_id)
-{
-	struct app_pipeline_params *writer = NULL;
-	uint32_t pos = kni - app->kni_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_writers = 0, id = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_out = RTE_MIN(p->n_pktq_out,
-			RTE_DIM(p->pktq_out));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_out; j++) {
-			struct app_pktq_out_params *pktq = &p->pktq_out[j];
-
-			if ((pktq->type == APP_PKTQ_OUT_KNI) &&
-				(pktq->id == pos)) {
-				n_writers++;
-				writer = p;
-				id = j;
-			}
-		}
-	}
-
-	if (n_writers != 1)
-		return NULL;
-
-	*pktq_out_id = id;
-	return writer;
-}
-
-static inline uint32_t
-app_sink_get_writers(struct app_params *app, struct app_pktq_sink_params *sink)
-{
-	uint32_t pos = sink - app->sink_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_writers = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_pktq_out = RTE_MIN(p->n_pktq_out,
-			RTE_DIM(p->pktq_out));
-		uint32_t j;
-
-		for (j = 0; j < n_pktq_out; j++) {
-			struct app_pktq_out_params *pktq = &p->pktq_out[j];
-
-			if ((pktq->type == APP_PKTQ_OUT_SINK) &&
-				(pktq->id == pos))
-				n_writers++;
-		}
-	}
-
-	return n_writers;
-}
-
-static inline uint32_t
-app_msgq_get_writers(struct app_params *app, struct app_msgq_params *msgq)
-{
-	uint32_t pos = msgq - app->msgq_params;
-	uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
-		RTE_DIM(app->pipeline_params));
-	uint32_t n_writers = 0, i;
-
-	for (i = 0; i < n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		uint32_t n_msgq_out = RTE_MIN(p->n_msgq_out,
-			RTE_DIM(p->msgq_out));
-		uint32_t j;
-
-		for (j = 0; j < n_msgq_out; j++)
-			if (p->msgq_out[j] == pos)
-				n_writers++;
-	}
-
-	return n_writers;
-}
-
-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%" SCNu32 ".%" SCNu32,
-		&rxq_link_id, &rxq_queue_id);
-	sprintf(link_name, "LINK%" PRIu32, 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%" SCNu32 ".%" SCNu32,
-		&txq_link_id, &txq_queue_id);
-	sprintf(link_name, "LINK%" PRIu32, 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%" PRIu32, &link_id);
-	sprintf(link_name, "LINK%" PRIu32, 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];
-}
-
-static inline struct app_link_params *
-app_get_link_for_kni(struct app_params *app, struct app_pktq_kni_params *p_kni)
-{
-	char link_name[APP_PARAM_NAME_SIZE];
-	uint32_t link_id;
-	ssize_t link_param_idx;
-
-	sscanf(p_kni->name, "KNI%" PRIu32, &link_id);
-	sprintf(link_name, "LINK%" PRIu32, 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_kni->name);
-
-	return &app->link_params[link_param_idx];
-}
-
-static inline uint32_t
-app_core_is_enabled(struct app_params *app, uint32_t lcore_id)
-{
-	return(app->core_mask[lcore_id / 64] &
-		(1LLU << (lcore_id % 64)));
-}
-
-static inline void
-app_core_enable_in_core_mask(struct app_params *app, int lcore_id)
-{
-	app->core_mask[lcore_id / 64] |= 1LLU << (lcore_id % 64);
-
-}
-
-static inline void
-app_core_build_core_mask_string(struct app_params *app, char *mask_buffer)
-{
-	int i;
-
-	mask_buffer[0] = '\0';
-	for (i = (int)RTE_DIM(app->core_mask); i > 0; i--) {
-		/* For Hex representation of bits in uint64_t */
-		char buffer[(64 / 8) * 2 + 1];
-		memset(buffer, 0, sizeof(buffer));
-		snprintf(buffer, sizeof(buffer), "%016" PRIx64,
-			 app->core_mask[i-1]);
-		strcat(mask_buffer, buffer);
-	}
-}
-
-int app_config_init(struct app_params *app);
-
-int app_config_args(struct app_params *app,
-	int argc, char **argv);
-
-int app_config_preproc(struct app_params *app);
-
-int app_config_parse(struct app_params *app,
-	const char *file_name);
-
-int app_config_parse_tm(struct app_params *app);
-
-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);
-
-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_check.c b/examples/ip_pipeline/config_check.c
deleted file mode 100644
index 86d1191..0000000
--- a/examples/ip_pipeline/config_check.c
+++ /dev/null
@@ -1,488 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2016 Intel Corporation
- */
-
-#include <stdio.h>
-
-#include <rte_ip.h>
-
-#include "app.h"
-
-static void
-check_mempools(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_mempools; i++) {
-		struct app_mempool_params *p = &app->mempool_params[i];
-
-		APP_CHECK((p->pool_size > 0),
-			"Mempool %s size is 0\n", p->name);
-
-		APP_CHECK((p->cache_size > 0),
-			"Mempool %s cache size is 0\n", p->name);
-
-		APP_CHECK(rte_is_power_of_2(p->cache_size),
-			"Mempool %s cache size not a power of 2\n", p->name);
-	}
-}
-
-static inline uint32_t
-link_rxq_used(struct app_link_params *link, uint32_t q_id)
-{
-	uint32_t i;
-
-	if ((link->arp_q == q_id) ||
-		(link->tcp_syn_q == q_id) ||
-		(link->ip_local_q == q_id) ||
-		(link->tcp_local_q == q_id) ||
-		(link->udp_local_q == q_id) ||
-		(link->sctp_local_q == q_id))
-		return 1;
-
-	for (i = 0; i < link->n_rss_qs; i++)
-		if (link->rss_qs[i] == q_id)
-			return 1;
-
-	return 0;
-}
-
-static void
-check_links(struct app_params *app)
-{
-	uint32_t i;
-
-	/* Check that number of links matches the port mask */
-	if (app->port_mask) {
-		uint32_t n_links_port_mask =
-			__builtin_popcountll(app->port_mask);
-
-		APP_CHECK((app->n_links == n_links_port_mask),
-			"Not enough links provided in the PORT_MASK\n");
-	}
-
-	for (i = 0; i < app->n_links; i++) {
-		struct app_link_params *link = &app->link_params[i];
-		uint32_t rxq_max, n_rxq, n_txq, link_id, i;
-
-		APP_PARAM_GET_ID(link, "LINK", link_id);
-
-		/* Check that link RXQs are contiguous */
-		rxq_max = 0;
-		if (link->arp_q > rxq_max)
-			rxq_max = link->arp_q;
-		if (link->tcp_syn_q > rxq_max)
-			rxq_max = link->tcp_syn_q;
-		if (link->ip_local_q > rxq_max)
-			rxq_max = link->ip_local_q;
-		if (link->tcp_local_q > rxq_max)
-			rxq_max = link->tcp_local_q;
-		if (link->udp_local_q > rxq_max)
-			rxq_max = link->udp_local_q;
-		if (link->sctp_local_q > rxq_max)
-			rxq_max = link->sctp_local_q;
-		for (i = 0; i < link->n_rss_qs; i++)
-			if (link->rss_qs[i] > rxq_max)
-				rxq_max = link->rss_qs[i];
-
-		for (i = 1; i <= rxq_max; i++)
-			APP_CHECK((link_rxq_used(link, i)),
-				"%s RXQs are not contiguous (A)\n", link->name);
-
-		n_rxq = app_link_get_n_rxq(app, link);
-
-		APP_CHECK((n_rxq), "%s does not have any RXQ\n", link->name);
-
-		APP_CHECK((n_rxq == rxq_max + 1),
-			"%s RXQs are not contiguous (B)\n", link->name);
-
-		for (i = 0; i < n_rxq; i++) {
-			char name[APP_PARAM_NAME_SIZE];
-			int pos;
-
-			sprintf(name, "RXQ%" PRIu32 ".%" PRIu32,
-				link_id, i);
-			pos = APP_PARAM_FIND(app->hwq_in_params, name);
-			APP_CHECK((pos >= 0),
-				"%s RXQs are not contiguous (C)\n", link->name);
-		}
-
-		/* Check that link TXQs are contiguous */
-		n_txq = app_link_get_n_txq(app, link);
-
-		APP_CHECK((n_txq),  "%s does not have any TXQ\n", link->name);
-
-		for (i = 0; i < n_txq; i++) {
-			char name[APP_PARAM_NAME_SIZE];
-			int pos;
-
-			sprintf(name, "TXQ%" PRIu32 ".%" PRIu32,
-				link_id, i);
-			pos = APP_PARAM_FIND(app->hwq_out_params, name);
-			APP_CHECK((pos >= 0),
-				"%s TXQs are not contiguous\n", link->name);
-		}
-	}
-}
-
-static void
-check_rxqs(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_pktq_hwq_in; i++) {
-		struct app_pktq_hwq_in_params *p = &app->hwq_in_params[i];
-		uint32_t n_readers = app_rxq_get_readers(app, p);
-
-		APP_CHECK((p->size > 0),
-			"%s size is 0\n", p->name);
-
-		APP_CHECK((rte_is_power_of_2(p->size)),
-			"%s size is not a power of 2\n", p->name);
-
-		APP_CHECK((p->burst > 0),
-			"%s burst size is 0\n", p->name);
-
-		APP_CHECK((p->burst <= p->size),
-			"%s burst size is bigger than its size\n", p->name);
-
-		APP_CHECK((n_readers != 0),
-			"%s has no reader\n", p->name);
-
-		APP_CHECK((n_readers == 1),
-			"%s has more than one reader\n", p->name);
-	}
-}
-
-static void
-check_txqs(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_pktq_hwq_out; i++) {
-		struct app_pktq_hwq_out_params *p = &app->hwq_out_params[i];
-		uint32_t n_writers = app_txq_get_writers(app, p);
-
-		APP_CHECK((p->size > 0),
-			"%s size is 0\n", p->name);
-
-		APP_CHECK((rte_is_power_of_2(p->size)),
-			"%s size is not a power of 2\n", p->name);
-
-		APP_CHECK((p->burst > 0),
-			"%s burst size is 0\n", p->name);
-
-		APP_CHECK((p->burst <= p->size),
-			"%s burst size is bigger than its size\n", p->name);
-
-		APP_CHECK((n_writers != 0),
-			"%s has no writer\n", p->name);
-
-		APP_CHECK((n_writers == 1),
-			"%s has more than one writer\n", p->name);
-	}
-}
-
-static void
-check_swqs(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_pktq_swq; i++) {
-		struct app_pktq_swq_params *p = &app->swq_params[i];
-		uint32_t n_readers = app_swq_get_readers(app, p);
-		uint32_t n_writers = app_swq_get_writers(app, p);
-		uint32_t n_flags;
-
-		APP_CHECK((p->size > 0),
-			"%s size is 0\n", p->name);
-
-		APP_CHECK((rte_is_power_of_2(p->size)),
-			"%s size is not a power of 2\n", p->name);
-
-		APP_CHECK((p->burst_read > 0),
-			"%s read burst size is 0\n", p->name);
-
-		APP_CHECK((p->burst_read <= p->size),
-			"%s read burst size is bigger than its size\n",
-			p->name);
-
-		APP_CHECK((p->burst_write > 0),
-			"%s write burst size is 0\n", p->name);
-
-		APP_CHECK((p->burst_write <= p->size),
-			"%s write burst size is bigger than its size\n",
-			p->name);
-
-		APP_CHECK((n_readers != 0),
-			"%s has no reader\n", p->name);
-
-		if (n_readers > 1)
-			APP_LOG(app, LOW, "%s has more than one reader", p->name);
-
-		APP_CHECK((n_writers != 0),
-			"%s has no writer\n", p->name);
-
-		if (n_writers > 1)
-			APP_LOG(app, LOW, "%s has more than one writer", p->name);
-
-		n_flags = p->ipv4_frag + p->ipv6_frag + p->ipv4_ras + p->ipv6_ras;
-
-		APP_CHECK((n_flags < 2),
-			"%s has more than one fragmentation or reassembly mode enabled\n",
-			p->name);
-
-		APP_CHECK((!((n_readers > 1) && (n_flags == 1))),
-			"%s has more than one reader when fragmentation or reassembly"
-			" mode enabled\n",
-			p->name);
-
-		APP_CHECK((!((n_writers > 1) && (n_flags == 1))),
-			"%s has more than one writer when fragmentation or reassembly"
-			" mode enabled\n",
-			p->name);
-
-		n_flags = p->ipv4_ras + p->ipv6_ras;
-
-		APP_CHECK((!((p->dropless == 1) && (n_flags == 1))),
-			"%s has dropless when reassembly mode enabled\n", p->name);
-
-		n_flags = p->ipv4_frag + p->ipv6_frag;
-
-		if (n_flags == 1) {
-			uint16_t ip_hdr_size = (p->ipv4_frag) ? sizeof(struct ipv4_hdr) :
-				sizeof(struct ipv6_hdr);
-
-			APP_CHECK((p->mtu > ip_hdr_size),
-				"%s mtu size is smaller than ip header\n", p->name);
-
-			APP_CHECK((!((p->mtu - ip_hdr_size) % 8)),
-				"%s mtu size is incorrect\n", p->name);
-		}
-	}
-}
-
-static void
-check_tms(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_pktq_tm; i++) {
-		struct app_pktq_tm_params *p = &app->tm_params[i];
-		uint32_t n_readers = app_tm_get_readers(app, p);
-		uint32_t n_writers = app_tm_get_writers(app, p);
-
-		APP_CHECK((n_readers != 0),
-			"%s has no reader\n", p->name);
-
-		APP_CHECK((n_readers == 1),
-			"%s has more than one reader\n", p->name);
-
-		APP_CHECK((n_writers != 0),
-			"%s has no writer\n", p->name);
-
-		APP_CHECK((n_writers == 1),
-			"%s has more than one writer\n", p->name);
-	}
-}
-
-static void
-check_taps(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_pktq_tap; i++) {
-		struct app_pktq_tap_params *p = &app->tap_params[i];
-		uint32_t n_readers = app_tap_get_readers(app, p);
-		uint32_t n_writers = app_tap_get_writers(app, p);
-
-		APP_CHECK((n_readers != 0),
-			"%s has no reader\n", p->name);
-
-		APP_CHECK((n_readers == 1),
-			"%s has more than one reader\n", p->name);
-
-		APP_CHECK((n_writers != 0),
-			"%s has no writer\n", p->name);
-
-		APP_CHECK((n_writers == 1),
-			"%s has more than one writer\n", p->name);
-
-		APP_CHECK((p->burst_read > 0),
-			"%s read burst size is 0\n", p->name);
-
-		APP_CHECK((p->burst_write > 0),
-			"%s write burst size is 0\n", p->name);
-	}
-}
-
-static void
-check_knis(struct app_params *app) {
-	uint32_t i;
-
-	for (i = 0; i < app->n_pktq_kni; i++) {
-		struct app_pktq_kni_params *p = &app->kni_params[i];
-		uint32_t n_readers = app_kni_get_readers(app, p);
-		uint32_t n_writers = app_kni_get_writers(app, p);
-
-		APP_CHECK((n_readers != 0),
-			"%s has no reader\n", p->name);
-
-		APP_CHECK((n_readers == 1),
-			"%s has more than one reader\n", p->name);
-
-		APP_CHECK((n_writers != 0),
-			"%s has no writer\n", p->name);
-
-		APP_CHECK((n_writers == 1),
-			"%s has more than one writer\n", p->name);
-	}
-}
-
-static void
-check_sources(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_pktq_source; i++) {
-		struct app_pktq_source_params *p = &app->source_params[i];
-		uint32_t n_readers = app_source_get_readers(app, p);
-
-		APP_CHECK((n_readers != 0),
-			"%s has no reader\n", p->name);
-
-		APP_CHECK((n_readers == 1),
-			"%s has more than one reader\n", p->name);
-	}
-}
-
-static void
-check_sinks(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_pktq_sink; i++) {
-		struct app_pktq_sink_params *p = &app->sink_params[i];
-		uint32_t n_writers = app_sink_get_writers(app, p);
-
-		APP_CHECK((n_writers != 0),
-			"%s has no writer\n", p->name);
-
-		APP_CHECK((n_writers == 1),
-			"%s has more than one writer\n", p->name);
-	}
-}
-
-static void
-check_msgqs(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_msgq; i++) {
-		struct app_msgq_params *p = &app->msgq_params[i];
-		uint32_t n_readers = app_msgq_get_readers(app, p);
-		uint32_t n_writers = app_msgq_get_writers(app, p);
-		uint32_t msgq_req_pipeline, msgq_rsp_pipeline;
-		uint32_t msgq_req_core, msgq_rsp_core;
-
-		APP_CHECK((p->size > 0),
-			"%s size is 0\n", p->name);
-
-		APP_CHECK((rte_is_power_of_2(p->size)),
-			"%s size is not a power of 2\n", p->name);
-
-		msgq_req_pipeline = (strncmp(p->name, "MSGQ-REQ-PIPELINE",
-			strlen("MSGQ-REQ-PIPELINE")) == 0);
-
-		msgq_rsp_pipeline = (strncmp(p->name, "MSGQ-RSP-PIPELINE",
-			strlen("MSGQ-RSP-PIPELINE")) == 0);
-
-		msgq_req_core = (strncmp(p->name, "MSGQ-REQ-CORE",
-			strlen("MSGQ-REQ-CORE")) == 0);
-
-		msgq_rsp_core = (strncmp(p->name, "MSGQ-RSP-CORE",
-			strlen("MSGQ-RSP-CORE")) == 0);
-
-		if ((msgq_req_pipeline == 0) &&
-			(msgq_rsp_pipeline == 0) &&
-			(msgq_req_core == 0) &&
-			(msgq_rsp_core == 0)) {
-			APP_CHECK((n_readers != 0),
-				"%s has no reader\n", p->name);
-
-			APP_CHECK((n_readers == 1),
-				"%s has more than one reader\n", p->name);
-
-			APP_CHECK((n_writers != 0),
-				"%s has no writer\n", p->name);
-
-			APP_CHECK((n_writers == 1),
-				"%s has more than one writer\n", p->name);
-		}
-
-		if (msgq_req_pipeline) {
-			struct app_pipeline_params *pipeline;
-			uint32_t pipeline_id;
-
-			APP_PARAM_GET_ID(p, "MSGQ-REQ-PIPELINE", pipeline_id);
-
-			APP_PARAM_FIND_BY_ID(app->pipeline_params,
-				"PIPELINE",
-				pipeline_id,
-				pipeline);
-
-			APP_CHECK((pipeline != NULL),
-				"%s is not associated with a valid pipeline\n",
-				p->name);
-		}
-
-		if (msgq_rsp_pipeline) {
-			struct app_pipeline_params *pipeline;
-			uint32_t pipeline_id;
-
-			APP_PARAM_GET_ID(p, "MSGQ-RSP-PIPELINE", pipeline_id);
-
-			APP_PARAM_FIND_BY_ID(app->pipeline_params,
-				"PIPELINE",
-				pipeline_id,
-				pipeline);
-
-			APP_CHECK((pipeline != NULL),
-				"%s is not associated with a valid pipeline\n",
-				p->name);
-		}
-	}
-}
-
-static void
-check_pipelines(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-
-		APP_CHECK((p->n_msgq_in == p->n_msgq_out),
-			"%s number of input MSGQs does not match "
-			"the number of output MSGQs\n", p->name);
-	}
-}
-
-int
-app_config_check(struct app_params *app)
-{
-	check_mempools(app);
-	check_links(app);
-	check_rxqs(app);
-	check_txqs(app);
-	check_swqs(app);
-	check_tms(app);
-	check_taps(app);
-	check_knis(app);
-	check_sources(app);
-	check_sinks(app);
-	check_msgqs(app);
-	check_pipelines(app);
-
-	return 0;
-}
diff --git a/examples/ip_pipeline/config_parse.c b/examples/ip_pipeline/config_parse.c
deleted file mode 100644
index e90499e..0000000
--- a/examples/ip_pipeline/config_parse.c
+++ /dev/null
@@ -1,3395 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2016 Intel Corporation
- */
-
-#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 <libgen.h>
-#include <unistd.h>
-#include <sys/wait.h>
-
-#include <rte_errno.h>
-#include <rte_cfgfile.h>
-#include <rte_string_fns.h>
-
-#include "app.h"
-#include "parser.h"
-
-/**
- * Default config values
- **/
-
-static struct app_params app_params_default = {
-	.config_file = "./config/ip_pipeline.cfg",
-	.log_level = APP_LOG_LEVEL_HIGH,
-	.port_mask = 0,
-
-	.eal_params = {
-		.channels = 4,
-	},
-};
-
-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_q = 0,
-	.ip_local_q = 0,
-	.tcp_local_q = 0,
-	.udp_local_q = 0,
-	.sctp_local_q = 0,
-	.rss_qs = {0},
-	.n_rss_qs = 0,
-	.rss_proto_ipv4 = ETH_RSS_IPV4,
-	.rss_proto_ipv6 = ETH_RSS_IPV6,
-	.rss_proto_l2 = 0,
-	.state = 0,
-	.ip = 0,
-	.depth = 0,
-	.mac_addr = 0,
-	.pci_bdf = {0},
-
-	.conf = {
-		.link_speeds = 0,
-		.rxmode = {
-			.mq_mode = ETH_MQ_RX_NONE,
-
-			.ignore_offload_bitfield = 1,
-			.offloads = DEV_RX_OFFLOAD_CRC_STRIP,
-
-			.max_rx_pkt_len = 9000, /* Jumbo frame max packet len */
-			.split_hdr_size = 0, /* Header split buffer size */
-		},
-		.rx_adv_conf = {
-			.rss_conf = {
-				.rss_key = NULL,
-				.rss_key_len = 40,
-				.rss_hf = 0,
-			},
-		},
-		.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_IGNORE,
-		.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,
-	.ipv4_frag = 0,
-	.ipv6_frag = 0,
-	.ipv4_ras = 0,
-	.ipv6_ras = 0,
-	.mtu = 0,
-	.metadata_size = 0,
-	.mempool_direct_id = 0,
-	.mempool_indirect_id = 0,
-};
-
-struct app_pktq_tm_params default_tm_params = {
-	.parsed = 0,
-	.file_name = "./config/tm_profile.cfg",
-	.burst_read = 24,
-	.burst_write = 32,
-};
-
-struct app_pktq_tap_params default_tap_params = {
-	.parsed = 0,
-	.burst_read = 32,
-	.burst_write = 32,
-	.dropless = 0,
-	.n_retries = 0,
-	.mempool_id = 0,
-};
-
-struct app_pktq_kni_params default_kni_params = {
-	.parsed = 0,
-	.socket_id = 0,
-	.core_id = 0,
-	.hyper_th_id = 0,
-	.force_bind = 0,
-
-	.mempool_id = 0,
-	.burst_read = 32,
-	.burst_write = 32,
-	.dropless = 0,
-	.n_retries = 0,
-};
-
-struct app_pktq_source_params default_source_params = {
-	.parsed = 0,
-	.mempool_id = 0,
-	.burst = 32,
-	.file_name = "./config/packets.pcap",
-	.n_bytes_per_pkt = 0,
-};
-
-struct app_pktq_sink_params default_sink_params = {
-	.parsed = 0,
-	.file_name = NULL,
-	.n_pkts_to_dump = 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] "
-	"[-l LOG_LEVEL] [--preproc PREPROCESSOR] [--preproc-args ARGS]\n"
-	"\n"
-	"Arguments:\n"
-	"\t-f CONFIG_FILE: Default config file is %s\n"
-	"\t-p PORT_MASK: Mask of NIC port IDs in hex format (generated from "
-		"config file when not provided)\n"
-	"\t-s SCRIPT_FILE: No CLI script file is run when not specified\n"
-	"\t-l LOG_LEVEL: 0 = NONE, 1 = HIGH PRIO (default), 2 = LOW PRIO\n"
-	"\t--preproc PREPROCESSOR: Configuration file pre-processor\n"
-	"\t--preproc-args ARGS: Arguments to be passed to pre-processor\n"
-	"\n";
-
-static void
-app_print_usage(char *prgname)
-{
-	rte_exit(0, app_usage, prgname, app_params_default.config_file);
-}
-
-#define APP_PARAM_ADD(set, key)						\
-({									\
-	ssize_t pos = APP_PARAM_FIND(set, key);				\
-	ssize_t size = RTE_DIM(set);					\
-									\
-	if (pos < 0) {							\
-		for (pos = 0; pos < size; pos++) {			\
-			if (!APP_PARAM_VALID(&((set)[pos])))		\
-				break;					\
-		}							\
-									\
-		APP_CHECK((pos < size),					\
-			"Parse error: size of %s is limited to %u elements",\
-			#set, (uint32_t) size);				\
-									\
-		(set)[pos].name = strdup(key);				\
-		APP_CHECK(((set)[pos].name),				\
-			"Parse error: no free memory");			\
-	}								\
-	pos;								\
-})
-
-#define APP_PARAM_ADD_LINK_FOR_RXQ(app, rxq_name)			\
-({									\
-	char link_name[APP_PARAM_NAME_SIZE];				\
-	ssize_t link_param_pos;						\
-	uint32_t link_id, queue_id;				\
-									\
-	sscanf((rxq_name), "RXQ%" SCNu32 ".%" SCNu32, &link_id, &queue_id);\
-	sprintf(link_name, "LINK%" PRIu32, link_id);			\
-	link_param_pos = APP_PARAM_ADD((app)->link_params, link_name);	\
-	link_param_pos;							\
-})
-
-#define APP_PARAM_ADD_LINK_FOR_TXQ(app, txq_name)			\
-({									\
-	char link_name[APP_PARAM_NAME_SIZE];				\
-	ssize_t link_param_pos;						\
-	uint32_t link_id, queue_id;					\
-									\
-	sscanf((txq_name), "TXQ%" SCNu32 ".%" SCNu32, &link_id, &queue_id);\
-	sprintf(link_name, "LINK%" PRIu32, link_id);			\
-	link_param_pos = APP_PARAM_ADD((app)->link_params, link_name);	\
-	link_param_pos;							\
-})
-
-#define APP_PARAM_ADD_LINK_FOR_TM(app, tm_name)				\
-({									\
-	char link_name[APP_PARAM_NAME_SIZE];				\
-	ssize_t link_param_pos;						\
-	uint32_t link_id;						\
-									\
-	sscanf((tm_name), "TM%" SCNu32, &link_id);			\
-	sprintf(link_name, "LINK%" PRIu32, link_id);			\
-	link_param_pos = APP_PARAM_ADD((app)->link_params, link_name);	\
-	link_param_pos;							\
-})
-
-#define APP_PARAM_ADD_LINK_FOR_KNI(app, kni_name)			\
-({									\
-	char link_name[APP_PARAM_NAME_SIZE];				\
-	ssize_t link_param_pos;						\
-	uint32_t link_id;						\
-									\
-	sscanf((kni_name), "KNI%" SCNu32, &link_id);		\
-	sprintf(link_name, "LINK%" PRIu32, link_id);			\
-	link_param_pos = APP_PARAM_ADD((app)->link_params, link_name);	\
-	link_param_pos;							\
-})
-
-#define PARSE_CHECK_DUPLICATE_SECTION(obj)				\
-do {									\
-	APP_CHECK(((obj)->parsed == 0),					\
-		"Parse error: duplicate \"%s\" section", (obj)->name);	\
-	(obj)->parsed++;					\
-} while (0)
-
-#define PARSE_CHECK_DUPLICATE_SECTION_EAL(obj)				\
-do {									\
-	APP_CHECK(((obj)->parsed == 0),					\
-		"Parse error: duplicate \"%s\" section", "EAL");	\
-	(obj)->parsed++;					\
-} while (0)
-
-#define PARSE_ERROR(exp, section, entry)				\
-APP_CHECK(exp, "Parse error in section \"%s\": entry \"%s\"", section, entry)
-
-#define PARSE_ERROR_MESSAGE(exp, section, entry, message)		\
-APP_CHECK(exp, "Parse error in section \"%s\", entry \"%s\": %s",	\
-	section, entry, message)
-
-#define PARSE_ERROR_NO_ELEMENTS(exp, section, entry)			\
-APP_CHECK(exp, "Parse error in section \"%s\", entry \"%s\": "		\
-	"no elements detected",						\
-	section, entry)
-
-#define PARSE_ERROR_TOO_MANY_ELEMENTS(exp, section, entry, max)		\
-APP_CHECK(exp, "Parse error in section \"%s\", entry \"%s\": "		\
-	"maximum number of elements allowed is %u",			\
-	section, entry, max)
-
-#define PARSE_ERROR_INVALID_ELEMENT(exp, section, entry, value)		\
-APP_CHECK(exp, "Parse error in section \"%s\", entry \"%s\": "		\
-	"Invalid element value \"%s\"",					\
-	section, entry, value)
-
-#define PARSE_ERROR_MALLOC(exp)						\
-APP_CHECK(exp, "Parse error: no free memory")
-
-#define PARSE_ERROR_SECTION(exp, section)				\
-APP_CHECK(exp, "Parse error in section \"%s\"", section)
-
-#define PARSE_ERROR_SECTION_NO_ENTRIES(exp, section)			\
-APP_CHECK(exp, "Parse error in section \"%s\": no entries", section)
-
-#define PARSE_WARNING_IGNORED(exp, section, entry)			\
-do									\
-if (!(exp))								\
-	fprintf(stderr, "Parse warning in section \"%s\": "		\
-		"entry \"%s\" is ignored", section, entry);		\
-while (0)
-
-#define PARSE_ERROR_INVALID(exp, section, entry)			\
-APP_CHECK(exp, "Parse error in section \"%s\": unrecognized entry \"%s\"",\
-	section, entry)
-
-#define PARSE_ERROR_DUPLICATE(exp, section, entry)			\
-APP_CHECK(exp, "Parse error in section \"%s\": duplicate entry \"%s\"",	\
-	section, entry)
-
-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 void
-parse_eal(struct app_params *app,
-	const char *section_name,
-	struct rte_cfgfile *cfg)
-{
-	struct app_eal_params *p = &app->eal_params;
-	struct rte_cfgfile_entry *entries;
-	int n_entries, i;
-
-	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
-	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
-
-	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
-	PARSE_ERROR_MALLOC(entries != NULL);
-
-	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
-
-	PARSE_CHECK_DUPLICATE_SECTION_EAL(p);
-
-	for (i = 0; i < n_entries; i++) {
-		struct rte_cfgfile_entry *entry = &entries[i];
-
-		/* coremask */
-		if (strcmp(entry->name, "c") == 0) {
-			PARSE_WARNING_IGNORED(0, section_name, entry->name);
-			continue;
-		}
-
-		/* corelist */
-		if (strcmp(entry->name, "l") == 0) {
-			PARSE_WARNING_IGNORED(0, section_name, entry->name);
-			continue;
-		}
-
-		/* coremap */
-		if (strcmp(entry->name, "lcores") == 0) {
-			PARSE_ERROR_DUPLICATE((p->coremap == NULL),
-				section_name,
-				entry->name);
-			p->coremap = strdup(entry->value);
-			continue;
-		}
-
-		/* master_lcore */
-		if (strcmp(entry->name, "master_lcore") == 0) {
-			int status;
-
-			PARSE_ERROR_DUPLICATE((p->master_lcore_present == 0),
-				section_name,
-				entry->name);
-			p->master_lcore_present = 1;
-
-			status = parser_read_uint32(&p->master_lcore,
-				entry->value);
-			PARSE_ERROR((status == 0), section_name, entry->name);
-			continue;
-		}
-
-		/* channels */
-		if (strcmp(entry->name, "n") == 0) {
-			int status;
-
-			PARSE_ERROR_DUPLICATE((p->channels_present == 0),
-				section_name,
-				entry->name);
-			p->channels_present = 1;
-
-			status = parser_read_uint32(&p->channels, entry->value);
-			PARSE_ERROR((status == 0), section_name, entry->name);
-			continue;
-		}
-
-		/* memory */
-		if (strcmp(entry->name, "m") == 0) {
-			int status;
-
-			PARSE_ERROR_DUPLICATE((p->memory_present == 0),
-				section_name,
-				entry->name);
-			p->memory_present = 1;
-
-			status = parser_read_uint32(&p->memory, entry->value);
-			PARSE_ERROR((status == 0), section_name, entry->name);
-			continue;
-		}
-
-		/* ranks */
-		if (strcmp(entry->name, "r") == 0) {
-			int status;
-
-			PARSE_ERROR_DUPLICATE((p->ranks_present == 0),
-				section_name,
-				entry->name);
-			p->ranks_present = 1;
-
-			status = parser_read_uint32(&p->ranks, entry->value);
-			PARSE_ERROR((status == 0), section_name, entry->name);
-			continue;
-		}
-
-		/* pci_blacklist */
-		if ((strcmp(entry->name, "pci_blacklist") == 0) ||
-			(strcmp(entry->name, "b") == 0)) {
-			uint32_t i;
-
-			for (i = 0; i < APP_MAX_LINKS; i++) {
-				if (p->pci_blacklist[i])
-					continue;
-
-				p->pci_blacklist[i] =
-					strdup(entry->value);
-				PARSE_ERROR_MALLOC(p->pci_blacklist[i]);
-
-				break;
-			}
-
-			PARSE_ERROR_MESSAGE((i < APP_MAX_LINKS),
-				section_name, entry->name,
-				"too many elements");
-			continue;
-		}
-
-		/* pci_whitelist */
-		if ((strcmp(entry->name, "pci_whitelist") == 0) ||
-			(strcmp(entry->name, "w") == 0)) {
-			uint32_t i;
-
-			PARSE_ERROR_MESSAGE((app->port_mask != 0),
-				section_name, entry->name, "entry to be "
-				"generated by the application (port_mask "
-				"not provided)");
-
-			for (i = 0; i < APP_MAX_LINKS; i++) {
-				if (p->pci_whitelist[i])
-					continue;
-
-				p->pci_whitelist[i] = strdup(entry->value);
-				PARSE_ERROR_MALLOC(p->pci_whitelist[i]);
-
-				break;
-			}
-
-			PARSE_ERROR_MESSAGE((i < APP_MAX_LINKS),
-				section_name, entry->name,
-				"too many elements");
-			continue;
-		}
-
-		/* vdev */
-		if (strcmp(entry->name, "vdev") == 0) {
-			uint32_t i;
-
-			for (i = 0; i < APP_MAX_LINKS; i++) {
-				if (p->vdev[i])
-					continue;
-
-				p->vdev[i] = strdup(entry->value);
-				PARSE_ERROR_MALLOC(p->vdev[i]);
-
-				break;
-			}
-
-			PARSE_ERROR_MESSAGE((i < APP_MAX_LINKS),
-				section_name, entry->name,
-				"too many elements");
-			continue;
-		}
-
-		/* vmware_tsc_map */
-		if (strcmp(entry->name, "vmware_tsc_map") == 0) {
-			int val;
-
-			PARSE_ERROR_DUPLICATE((p->vmware_tsc_map_present == 0),
-				section_name,
-				entry->name);
-			p->vmware_tsc_map_present = 1;
-
-			val = parser_read_arg_bool(entry->value);
-			PARSE_ERROR((val >= 0), section_name, entry->name);
-			p->vmware_tsc_map = val;
-			continue;
-		}
-
-		/* proc_type */
-		if (strcmp(entry->name, "proc_type") == 0) {
-			PARSE_ERROR_DUPLICATE((p->proc_type == NULL),
-				section_name,
-				entry->name);
-			p->proc_type = strdup(entry->value);
-			continue;
-		}
-
-		/* syslog */
-		if (strcmp(entry->name, "syslog") == 0) {
-			PARSE_ERROR_DUPLICATE((p->syslog == NULL),
-				section_name,
-				entry->name);
-			p->syslog = strdup(entry->value);
-			continue;
-		}
-
-		/* log_level */
-		if (strcmp(entry->name, "log_level") == 0) {
-			int status;
-
-			PARSE_ERROR_DUPLICATE((p->log_level_present == 0),
-				section_name,
-				entry->name);
-			p->log_level_present = 1;
-
-			status = parser_read_uint32(&p->log_level,
-				entry->value);
-			PARSE_ERROR((status == 0), section_name, entry->name);
-			continue;
-		}
-
-		/* version */
-		if (strcmp(entry->name, "v") == 0) {
-			int val;
-
-			PARSE_ERROR_DUPLICATE((p->version_present == 0),
-				section_name,
-				entry->name);
-			p->version_present = 1;
-
-			val = parser_read_arg_bool(entry->value);
-			PARSE_ERROR((val >= 0), section_name, entry->name);
-			p->version = val;
-			continue;
-		}
-
-		/* help */
-		if ((strcmp(entry->name, "help") == 0) ||
-			(strcmp(entry->name, "h") == 0)) {
-			int val;
-
-			PARSE_ERROR_DUPLICATE((p->help_present == 0),
-				section_name,
-				entry->name);
-			p->help_present = 1;
-
-			val = parser_read_arg_bool(entry->value);
-			PARSE_ERROR((val >= 0), section_name, entry->name);
-			p->help = val;
-			continue;
-		}
-
-		/* no_huge */
-		if (strcmp(entry->name, "no_huge") == 0) {
-			int val;
-
-			PARSE_ERROR_DUPLICATE((p->no_huge_present == 0),
-				section_name,
-				entry->name);
-			p->no_huge_present = 1;
-
-			val = parser_read_arg_bool(entry->value);
-			PARSE_ERROR((val >= 0), section_name, entry->name);
-			p->no_huge = val;
-			continue;
-		}
-
-		/* no_pci */
-		if (strcmp(entry->name, "no_pci") == 0) {
-			int val;
-
-			PARSE_ERROR_DUPLICATE((p->no_pci_present == 0),
-				section_name,
-				entry->name);
-			p->no_pci_present = 1;
-
-			val = parser_read_arg_bool(entry->value);
-			PARSE_ERROR((val >= 0), section_name, entry->name);
-			p->no_pci = val;
-			continue;
-		}
-
-		/* no_hpet */
-		if (strcmp(entry->name, "no_hpet") == 0) {
-			int val;
-
-			PARSE_ERROR_DUPLICATE((p->no_hpet_present == 0),
-				section_name,
-				entry->name);
-			p->no_hpet_present = 1;
-
-			val = parser_read_arg_bool(entry->value);
-			PARSE_ERROR((val >= 0), section_name, entry->name);
-			p->no_hpet = val;
-			continue;
-		}
-
-		/* no_shconf */
-		if (strcmp(entry->name, "no_shconf") == 0) {
-			int val;
-
-			PARSE_ERROR_DUPLICATE((p->no_shconf_present == 0),
-				section_name,
-				entry->name);
-			p->no_shconf_present = 1;
-
-			val = parser_read_arg_bool(entry->value);
-			PARSE_ERROR((val >= 0), section_name, entry->name);
-			p->no_shconf = val;
-			continue;
-		}
-
-		/* add_driver */
-		if (strcmp(entry->name, "d") == 0) {
-			PARSE_ERROR_DUPLICATE((p->add_driver == NULL),
-				section_name,
-				entry->name);
-			p->add_driver = strdup(entry->value);
-			continue;
-		}
-
-		/* socket_mem */
-		if (strcmp(entry->name, "socket_mem") == 0) {
-			PARSE_ERROR_DUPLICATE((p->socket_mem == NULL),
-				section_name,
-				entry->name);
-			p->socket_mem = strdup(entry->value);
-			continue;
-		}
-
-		/* huge_dir */
-		if (strcmp(entry->name, "huge_dir") == 0) {
-			PARSE_ERROR_DUPLICATE((p->huge_dir == NULL),
-				section_name,
-				entry->name);
-			p->huge_dir = strdup(entry->value);
-			continue;
-		}
-
-		/* file_prefix */
-		if (strcmp(entry->name, "file_prefix") == 0) {
-			PARSE_ERROR_DUPLICATE((p->file_prefix == NULL),
-				section_name,
-				entry->name);
-			p->file_prefix = strdup(entry->value);
-			continue;
-		}
-
-		/* base_virtaddr */
-		if (strcmp(entry->name, "base_virtaddr") == 0) {
-			PARSE_ERROR_DUPLICATE((p->base_virtaddr == NULL),
-				section_name,
-				entry->name);
-			p->base_virtaddr = strdup(entry->value);
-			continue;
-		}
-
-		/* create_uio_dev */
-		if (strcmp(entry->name, "create_uio_dev") == 0) {
-			int val;
-
-			PARSE_ERROR_DUPLICATE((p->create_uio_dev_present == 0),
-				section_name,
-				entry->name);
-			p->create_uio_dev_present = 1;
-
-			val = parser_read_arg_bool(entry->value);
-			PARSE_ERROR((val >= 0), section_name, entry->name);
-			p->create_uio_dev = val;
-			continue;
-		}
-
-		/* vfio_intr */
-		if (strcmp(entry->name, "vfio_intr") == 0) {
-			PARSE_ERROR_DUPLICATE((p->vfio_intr == NULL),
-				section_name,
-				entry->name);
-			p->vfio_intr = strdup(entry->value);
-			continue;
-		}
-
-		/* unrecognized */
-		PARSE_ERROR_INVALID(0, section_name, entry->name);
-	}
-
-	free(entries);
-}
-
-static void
-parse_pipeline_pktq_in(struct app_params *app,
-	struct app_pipeline_params *p,
-	char *value)
-{
-	p->n_pktq_in = 0;
-
-	while (1) {
-		enum app_pktq_in_type type;
-		int id;
-		char *name = strtok_r(value, PARSE_DELIMITER, &value);
-
-		if (name == NULL)
-			break;
-
-		PARSE_ERROR_TOO_MANY_ELEMENTS(
-			(p->n_pktq_in < RTE_DIM(p->pktq_in)),
-			p->name, "pktq_in", (uint32_t)RTE_DIM(p->pktq_in));
-
-		if (validate_name(name, "RXQ", 2) == 0) {
-			type = APP_PKTQ_IN_HWQ;
-			id = APP_PARAM_ADD(app->hwq_in_params, name);
-			APP_PARAM_ADD_LINK_FOR_RXQ(app, 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);
-			APP_PARAM_ADD_LINK_FOR_TM(app, name);
-		} else if (validate_name(name, "TAP", 1) == 0) {
-			type = APP_PKTQ_IN_TAP;
-			id = APP_PARAM_ADD(app->tap_params, name);
-		} else if (validate_name(name, "KNI", 1) == 0) {
-			type = APP_PKTQ_IN_KNI;
-			id = APP_PARAM_ADD(app->kni_params, name);
-			APP_PARAM_ADD_LINK_FOR_KNI(app, name);
-		} else if (validate_name(name, "SOURCE", 1) == 0) {
-			type = APP_PKTQ_IN_SOURCE;
-			id = APP_PARAM_ADD(app->source_params, name);
-		} else
-			PARSE_ERROR_INVALID_ELEMENT(0,
-				p->name, "pktq_in", name);
-
-		p->pktq_in[p->n_pktq_in].type = type;
-		p->pktq_in[p->n_pktq_in].id = (uint32_t) id;
-		p->n_pktq_in++;
-	}
-
-	PARSE_ERROR_NO_ELEMENTS((p->n_pktq_in > 0), p->name, "pktq_in");
-}
-
-static void
-parse_pipeline_pktq_out(struct app_params *app,
-	struct app_pipeline_params *p,
-	char *value)
-{
-	p->n_pktq_out = 0;
-
-	while (1) {
-		enum app_pktq_out_type type;
-		int id;
-		char *name = strtok_r(value, PARSE_DELIMITER, &value);
-
-		if (name == NULL)
-			break;
-
-		PARSE_ERROR_TOO_MANY_ELEMENTS(
-			(p->n_pktq_out < RTE_DIM(p->pktq_out)),
-			p->name, "pktq_out", (uint32_t)RTE_DIM(p->pktq_out));
-
-		if (validate_name(name, "TXQ", 2) == 0) {
-			type = APP_PKTQ_OUT_HWQ;
-			id = APP_PARAM_ADD(app->hwq_out_params, name);
-			APP_PARAM_ADD_LINK_FOR_TXQ(app, 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);
-			APP_PARAM_ADD_LINK_FOR_TM(app, name);
-		} else if (validate_name(name, "TAP", 1) == 0) {
-			type = APP_PKTQ_OUT_TAP;
-			id = APP_PARAM_ADD(app->tap_params, name);
-		} else if (validate_name(name, "KNI", 1) == 0) {
-			type = APP_PKTQ_OUT_KNI;
-			id = APP_PARAM_ADD(app->kni_params, name);
-			APP_PARAM_ADD_LINK_FOR_KNI(app, name);
-		} else if (validate_name(name, "SINK", 1) == 0) {
-			type = APP_PKTQ_OUT_SINK;
-			id = APP_PARAM_ADD(app->sink_params, name);
-		} else
-			PARSE_ERROR_INVALID_ELEMENT(0,
-				p->name, "pktq_out", name);
-
-		p->pktq_out[p->n_pktq_out].type = type;
-		p->pktq_out[p->n_pktq_out].id = id;
-		p->n_pktq_out++;
-	}
-
-	PARSE_ERROR_NO_ELEMENTS((p->n_pktq_out > 0), p->name, "pktq_out");
-}
-
-static void
-parse_pipeline_msgq_in(struct app_params *app,
-	struct app_pipeline_params *p,
-	char *value)
-{
-	p->n_msgq_in = 0;
-
-	while (1) {
-		int idx;
-		char *name = strtok_r(value, PARSE_DELIMITER, &value);
-
-		if (name == NULL)
-			break;
-
-		PARSE_ERROR_TOO_MANY_ELEMENTS(
-			(p->n_msgq_in < RTE_DIM(p->msgq_in)),
-			p->name, "msgq_in", (uint32_t)(RTE_DIM(p->msgq_in)));
-
-		PARSE_ERROR_INVALID_ELEMENT(
-			(validate_name(name, "MSGQ", 1) == 0),
-			p->name, "msgq_in", name);
-
-		idx = APP_PARAM_ADD(app->msgq_params, name);
-		p->msgq_in[p->n_msgq_in] = idx;
-		p->n_msgq_in++;
-	}
-
-	PARSE_ERROR_NO_ELEMENTS((p->n_msgq_in > 0), p->name, "msgq_in");
-}
-
-static void
-parse_pipeline_msgq_out(struct app_params *app,
-	struct app_pipeline_params *p,
-	char *value)
-{
-	p->n_msgq_out = 0;
-
-	while (1) {
-		int idx;
-		char *name = strtok_r(value, PARSE_DELIMITER, &value);
-
-		if (name == NULL)
-			break;
-
-		PARSE_ERROR_TOO_MANY_ELEMENTS(
-			(p->n_msgq_out < RTE_DIM(p->msgq_out)),
-			p->name, "msgq_out", (uint32_t)RTE_DIM(p->msgq_out));
-
-		PARSE_ERROR_INVALID_ELEMENT(
-			(validate_name(name, "MSGQ", 1) == 0),
-			p->name, "msgq_out", name);
-
-		idx = APP_PARAM_ADD(app->msgq_params, name);
-		p->msgq_out[p->n_msgq_out] = idx;
-		p->n_msgq_out++;
-	}
-
-	PARSE_ERROR_NO_ELEMENTS((p->n_msgq_out > 0), p->name, "msgq_out");
-}
-
-static void
-parse_pipeline(struct app_params *app,
-	const char *section_name,
-	struct rte_cfgfile *cfg)
-{
-	char name[CFG_NAME_LEN];
-	struct app_pipeline_params *param;
-	struct rte_cfgfile_entry *entries;
-	ssize_t param_idx;
-	int n_entries, i;
-
-	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
-	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
-
-	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
-	PARSE_ERROR_MALLOC(entries != NULL);
-
-	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
-
-	param_idx = APP_PARAM_ADD(app->pipeline_params, section_name);
-	param = &app->pipeline_params[param_idx];
-	PARSE_CHECK_DUPLICATE_SECTION(param);
-
-	for (i = 0; i < n_entries; i++) {
-		struct rte_cfgfile_entry *ent = &entries[i];
-
-		if (strcmp(ent->name, "type") == 0) {
-			int w_size = snprintf(param->type, RTE_DIM(param->type),
-					"%s", ent->value);
-
-			PARSE_ERROR(((w_size > 0) &&
-				(w_size < (int)RTE_DIM(param->type))),
-				section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "core") == 0) {
-			int status = parse_pipeline_core(
-				&param->socket_id, &param->core_id,
-				&param->hyper_th_id, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "pktq_in") == 0) {
-			parse_pipeline_pktq_in(app, param, ent->value);
-
-			continue;
-		}
-
-		if (strcmp(ent->name, "pktq_out") == 0) {
-			parse_pipeline_pktq_out(app, param, ent->value);
-
-			continue;
-		}
-
-		if (strcmp(ent->name, "msgq_in") == 0) {
-			parse_pipeline_msgq_in(app, param, ent->value);
-
-			continue;
-		}
-
-		if (strcmp(ent->name, "msgq_out") == 0) {
-			parse_pipeline_msgq_out(app, param, ent->value);
-
-			continue;
-		}
-
-		if (strcmp(ent->name, "timer_period") == 0) {
-			int status = parser_read_uint32(
-				&param->timer_period,
-				ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		/* pipeline type specific items */
-		APP_CHECK((param->n_args < APP_MAX_PIPELINE_ARGS),
-			"Parse error in section \"%s\": too many "
-			"pipeline specified parameters", section_name);
-
-		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),
-			"Parse error: no free memory");
-
-		param->n_args++;
-	}
-
-	snprintf(name, sizeof(name), "MSGQ-REQ-%s", section_name);
-	param_idx = APP_PARAM_ADD(app->msgq_params, 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", section_name);
-	param_idx = APP_PARAM_ADD(app->msgq_params, 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);
-	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);
-	app->msgq_params[param_idx].cpu_socket_id = param->socket_id;
-
-	free(entries);
-}
-
-static void
-parse_mempool(struct app_params *app,
-	const char *section_name,
-	struct rte_cfgfile *cfg)
-{
-	struct app_mempool_params *param;
-	struct rte_cfgfile_entry *entries;
-	ssize_t param_idx;
-	int n_entries, i;
-
-	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
-	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
-
-	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
-	PARSE_ERROR_MALLOC(entries != NULL);
-
-	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
-
-	param_idx = APP_PARAM_ADD(app->mempool_params, section_name);
-	param = &app->mempool_params[param_idx];
-	PARSE_CHECK_DUPLICATE_SECTION(param);
-
-	for (i = 0; i < n_entries; i++) {
-		struct rte_cfgfile_entry *ent = &entries[i];
-
-		if (strcmp(ent->name, "buffer_size") == 0) {
-			int status = parser_read_uint32(
-				&param->buffer_size, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "pool_size") == 0) {
-			int status = parser_read_uint32(
-				&param->pool_size, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "cache_size") == 0) {
-			int status = parser_read_uint32(
-				&param->cache_size, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "cpu") == 0) {
-			int status = parser_read_uint32(
-				&param->cpu_socket_id, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		/* unrecognized */
-		PARSE_ERROR_INVALID(0, section_name, ent->name);
-	}
-
-	free(entries);
-}
-
-static int
-parse_link_rss_qs(struct app_link_params *p,
-	char *value)
-{
-	p->n_rss_qs = 0;
-
-	while (1) {
-		char *token = strtok_r(value, PARSE_DELIMITER, &value);
-
-		if (token == NULL)
-			break;
-
-		if (p->n_rss_qs == RTE_DIM(p->rss_qs))
-			return -ENOMEM;
-
-		if (parser_read_uint32(&p->rss_qs[p->n_rss_qs++], token))
-			return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int
-parse_link_rss_proto_ipv4(struct app_link_params *p,
-	char *value)
-{
-	uint64_t mask = 0;
-
-	while (1) {
-		char *token = strtok_r(value, PARSE_DELIMITER, &value);
-
-		if (token == NULL)
-			break;
-
-		if (strcmp(token, "IP") == 0) {
-			mask |= ETH_RSS_IPV4;
-			continue;
-		}
-		if (strcmp(token, "FRAG") == 0) {
-			mask |= ETH_RSS_FRAG_IPV4;
-			continue;
-		}
-		if (strcmp(token, "TCP") == 0) {
-			mask |= ETH_RSS_NONFRAG_IPV4_TCP;
-			continue;
-		}
-		if (strcmp(token, "UDP") == 0) {
-			mask |= ETH_RSS_NONFRAG_IPV4_UDP;
-			continue;
-		}
-		if (strcmp(token, "SCTP") == 0) {
-			mask |= ETH_RSS_NONFRAG_IPV4_SCTP;
-			continue;
-		}
-		if (strcmp(token, "OTHER") == 0) {
-			mask |= ETH_RSS_NONFRAG_IPV4_OTHER;
-			continue;
-		}
-		return -EINVAL;
-	}
-
-	p->rss_proto_ipv4 = mask;
-	return 0;
-}
-
-static int
-parse_link_rss_proto_ipv6(struct app_link_params *p,
-	char *value)
-{
-	uint64_t mask = 0;
-
-	while (1) {
-		char *token = strtok_r(value, PARSE_DELIMITER, &value);
-
-		if (token == NULL)
-			break;
-
-		if (strcmp(token, "IP") == 0) {
-			mask |= ETH_RSS_IPV6;
-			continue;
-		}
-		if (strcmp(token, "FRAG") == 0) {
-			mask |= ETH_RSS_FRAG_IPV6;
-			continue;
-		}
-		if (strcmp(token, "TCP") == 0) {
-			mask |= ETH_RSS_NONFRAG_IPV6_TCP;
-			continue;
-		}
-		if (strcmp(token, "UDP") == 0) {
-			mask |= ETH_RSS_NONFRAG_IPV6_UDP;
-			continue;
-		}
-		if (strcmp(token, "SCTP") == 0) {
-			mask |= ETH_RSS_NONFRAG_IPV6_SCTP;
-			continue;
-		}
-		if (strcmp(token, "OTHER") == 0) {
-			mask |= ETH_RSS_NONFRAG_IPV6_OTHER;
-			continue;
-		}
-		if (strcmp(token, "IP_EX") == 0) {
-			mask |= ETH_RSS_IPV6_EX;
-			continue;
-		}
-		if (strcmp(token, "TCP_EX") == 0) {
-			mask |= ETH_RSS_IPV6_TCP_EX;
-			continue;
-		}
-		if (strcmp(token, "UDP_EX") == 0) {
-			mask |= ETH_RSS_IPV6_UDP_EX;
-			continue;
-		}
-		return -EINVAL;
-	}
-
-	p->rss_proto_ipv6 = mask;
-	return 0;
-}
-
-static int
-parse_link_rss_proto_l2(struct app_link_params *p,
-	char *value)
-{
-	uint64_t mask = 0;
-
-	while (1) {
-		char *token = strtok_r(value, PARSE_DELIMITER, &value);
-
-		if (token == NULL)
-			break;
-
-		if (strcmp(token, "L2") == 0) {
-			mask |= ETH_RSS_L2_PAYLOAD;
-			continue;
-		}
-		return -EINVAL;
-	}
-
-	p->rss_proto_l2 = mask;
-	return 0;
-}
-
-static void
-parse_link(struct app_params *app,
-	const char *section_name,
-	struct rte_cfgfile *cfg)
-{
-	struct app_link_params *param;
-	struct rte_cfgfile_entry *entries;
-	int n_entries, i;
-	int rss_qs_present = 0;
-	int rss_proto_ipv4_present = 0;
-	int rss_proto_ipv6_present = 0;
-	int rss_proto_l2_present = 0;
-	int pci_bdf_present = 0;
-	ssize_t param_idx;
-
-	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
-	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
-
-	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
-	PARSE_ERROR_MALLOC(entries != NULL);
-
-	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
-
-	param_idx = APP_PARAM_ADD(app->link_params, section_name);
-	param = &app->link_params[param_idx];
-	PARSE_CHECK_DUPLICATE_SECTION(param);
-
-	for (i = 0; i < n_entries; i++) {
-		struct rte_cfgfile_entry *ent = &entries[i];
-
-		if (strcmp(ent->name, "promisc") == 0) {
-			int status = parser_read_arg_bool(ent->value);
-
-			PARSE_ERROR((status != -EINVAL), section_name,
-				ent->name);
-			param->promisc = status;
-			continue;
-		}
-
-		if (strcmp(ent->name, "arp_q") == 0) {
-			int status = parser_read_uint32(&param->arp_q,
-				ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "tcp_syn_q") == 0) {
-			int status = parser_read_uint32(
-				&param->tcp_syn_q, ent->value);
-
-			PARSE_ERROR((status == 0), section_name, ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "ip_local_q") == 0) {
-			int status = parser_read_uint32(
-				&param->ip_local_q, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "tcp_local_q") == 0) {
-			int status = parser_read_uint32(
-				&param->tcp_local_q, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "udp_local_q") == 0) {
-			int status = parser_read_uint32(
-				&param->udp_local_q, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "sctp_local_q") == 0) {
-			int status = parser_read_uint32(
-				&param->sctp_local_q, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "rss_qs") == 0) {
-			int status = parse_link_rss_qs(param, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			rss_qs_present = 1;
-			continue;
-		}
-
-		if (strcmp(ent->name, "rss_proto_ipv4") == 0) {
-			int status =
-				parse_link_rss_proto_ipv4(param, ent->value);
-
-			PARSE_ERROR((status != -EINVAL), section_name,
-				ent->name);
-			rss_proto_ipv4_present = 1;
-			continue;
-		}
-
-		if (strcmp(ent->name, "rss_proto_ipv6") == 0) {
-			int status =
-				parse_link_rss_proto_ipv6(param, ent->value);
-
-			PARSE_ERROR((status != -EINVAL), section_name,
-				ent->name);
-			rss_proto_ipv6_present = 1;
-			continue;
-		}
-
-		if (strcmp(ent->name, "rss_proto_l2") == 0) {
-			int status = parse_link_rss_proto_l2(param, ent->value);
-
-			PARSE_ERROR((status != -EINVAL), section_name,
-				ent->name);
-			rss_proto_l2_present = 1;
-			continue;
-		}
-
-		if (strcmp(ent->name, "pci_bdf") == 0) {
-			PARSE_ERROR_DUPLICATE((pci_bdf_present == 0),
-				section_name, ent->name);
-
-			snprintf(param->pci_bdf, APP_LINK_PCI_BDF_SIZE,
-				"%s", ent->value);
-			pci_bdf_present = 1;
-			continue;
-		}
-
-		/* unrecognized */
-		PARSE_ERROR_INVALID(0, section_name, ent->name);
-	}
-
-	/* Check for mandatory fields */
-	if (app->port_mask)
-		PARSE_ERROR_MESSAGE((pci_bdf_present == 0),
-			section_name, "pci_bdf",
-			"entry not allowed (port_mask is provided)");
-	else
-		PARSE_ERROR_MESSAGE((pci_bdf_present),
-			section_name, "pci_bdf",
-			"this entry is mandatory (port_mask is not "
-			"provided)");
-
-	if (rss_proto_ipv4_present)
-		PARSE_ERROR_MESSAGE((rss_qs_present),
-			section_name, "rss_proto_ipv4",
-			"entry not allowed (rss_qs entry is not provided)");
-	if (rss_proto_ipv6_present)
-		PARSE_ERROR_MESSAGE((rss_qs_present),
-			section_name, "rss_proto_ipv6",
-			"entry not allowed (rss_qs entry is not provided)");
-	if (rss_proto_l2_present)
-		PARSE_ERROR_MESSAGE((rss_qs_present),
-			section_name, "rss_proto_l2",
-			"entry not allowed (rss_qs entry is not provided)");
-	if (rss_proto_ipv4_present |
-		rss_proto_ipv6_present |
-		rss_proto_l2_present){
-		if (rss_proto_ipv4_present == 0)
-			param->rss_proto_ipv4 = 0;
-		if (rss_proto_ipv6_present == 0)
-			param->rss_proto_ipv6 = 0;
-		if (rss_proto_l2_present == 0)
-			param->rss_proto_l2 = 0;
-	}
-
-	free(entries);
-}
-
-static void
-parse_rxq(struct app_params *app,
-	const char *section_name,
-	struct rte_cfgfile *cfg)
-{
-	struct app_pktq_hwq_in_params *param;
-	struct rte_cfgfile_entry *entries;
-	int n_entries, i;
-	ssize_t param_idx;
-
-	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
-	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
-
-	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
-	PARSE_ERROR_MALLOC(entries != NULL);
-
-	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
-
-	param_idx = APP_PARAM_ADD(app->hwq_in_params, section_name);
-	param = &app->hwq_in_params[param_idx];
-	PARSE_CHECK_DUPLICATE_SECTION(param);
-
-	APP_PARAM_ADD_LINK_FOR_RXQ(app, section_name);
-
-	for (i = 0; i < n_entries; i++) {
-		struct rte_cfgfile_entry *ent = &entries[i];
-
-		if (strcmp(ent->name, "mempool") == 0) {
-			int status = validate_name(ent->value,
-				"MEMPOOL", 1);
-			ssize_t idx;
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-
-			idx = APP_PARAM_ADD(app->mempool_params, ent->value);
-			param->mempool_id = idx;
-			continue;
-		}
-
-		if (strcmp(ent->name, "size") == 0) {
-			int status = parser_read_uint32(&param->size,
-				ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "burst") == 0) {
-			int status = parser_read_uint32(&param->burst,
-				ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		/* unrecognized */
-		PARSE_ERROR_INVALID(0, section_name, ent->name);
-	}
-
-	free(entries);
-}
-
-static void
-parse_txq(struct app_params *app,
-	const char *section_name,
-	struct rte_cfgfile *cfg)
-{
-	struct app_pktq_hwq_out_params *param;
-	struct rte_cfgfile_entry *entries;
-	int n_entries, i;
-	ssize_t param_idx;
-
-	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
-	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
-
-	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
-	PARSE_ERROR_MALLOC(entries != NULL);
-
-	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
-
-	param_idx = APP_PARAM_ADD(app->hwq_out_params, section_name);
-	param = &app->hwq_out_params[param_idx];
-	PARSE_CHECK_DUPLICATE_SECTION(param);
-
-	APP_PARAM_ADD_LINK_FOR_TXQ(app, section_name);
-
-	for (i = 0; i < n_entries; i++) {
-		struct rte_cfgfile_entry *ent = &entries[i];
-
-		if (strcmp(ent->name, "size") == 0) {
-			int status = parser_read_uint32(&param->size,
-				ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "burst") == 0) {
-			int status = parser_read_uint32(&param->burst,
-				ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "dropless") == 0) {
-			int status = parser_read_arg_bool(ent->value);
-
-
-			PARSE_ERROR((status != -EINVAL), section_name,
-				ent->name);
-			param->dropless = status;
-			continue;
-		}
-
-		if (strcmp(ent->name, "n_retries") == 0) {
-			int status = parser_read_uint64(&param->n_retries,
-				ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		/* unrecognized */
-		PARSE_ERROR_INVALID(0, section_name, ent->name);
-	}
-
-	free(entries);
-}
-
-static void
-parse_swq(struct app_params *app,
-	const char *section_name,
-	struct rte_cfgfile *cfg)
-{
-	struct app_pktq_swq_params *param;
-	struct rte_cfgfile_entry *entries;
-	int n_entries, i;
-	uint32_t mtu_present = 0;
-	uint32_t metadata_size_present = 0;
-	uint32_t mempool_direct_present = 0;
-	uint32_t mempool_indirect_present = 0;
-
-	ssize_t param_idx;
-
-	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
-	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
-
-	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
-	PARSE_ERROR_MALLOC(entries != NULL);
-
-	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
-
-	param_idx = APP_PARAM_ADD(app->swq_params, section_name);
-	param = &app->swq_params[param_idx];
-	PARSE_CHECK_DUPLICATE_SECTION(param);
-
-	for (i = 0; i < n_entries; i++) {
-		struct rte_cfgfile_entry *ent = &entries[i];
-
-		if (strcmp(ent->name, "size") == 0) {
-			int status = parser_read_uint32(&param->size,
-				ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "burst_read") == 0) {
-			int status = parser_read_uint32(&
-				param->burst_read, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "burst_write") == 0) {
-			int status = parser_read_uint32(
-				&param->burst_write, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "dropless") == 0) {
-			int status = parser_read_arg_bool(ent->value);
-
-			PARSE_ERROR((status != -EINVAL), section_name,
-				ent->name);
-			param->dropless = status;
-			continue;
-		}
-
-		if (strcmp(ent->name, "n_retries") == 0) {
-			int status = parser_read_uint64(&param->n_retries,
-				ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "cpu") == 0) {
-			int status = parser_read_uint32(
-				&param->cpu_socket_id, ent->value);
-
-			PARSE_ERROR((status == 0), section_name, ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "ipv4_frag") == 0) {
-			int status = parser_read_arg_bool(ent->value);
-
-			PARSE_ERROR((status != -EINVAL), section_name,
-				ent->name);
-
-			param->ipv4_frag = status;
-			if (param->mtu == 0)
-				param->mtu = 1500;
-
-			continue;
-		}
-
-		if (strcmp(ent->name, "ipv6_frag") == 0) {
-			int status = parser_read_arg_bool(ent->value);
-
-			PARSE_ERROR((status != -EINVAL), section_name,
-				ent->name);
-			param->ipv6_frag = status;
-			if (param->mtu == 0)
-				param->mtu = 1320;
-			continue;
-		}
-
-		if (strcmp(ent->name, "ipv4_ras") == 0) {
-			int status = parser_read_arg_bool(ent->value);
-
-			PARSE_ERROR((status != -EINVAL), section_name,
-				ent->name);
-			param->ipv4_ras = status;
-			continue;
-		}
-
-		if (strcmp(ent->name, "ipv6_ras") == 0) {
-			int status = parser_read_arg_bool(ent->value);
-
-			PARSE_ERROR((status != -EINVAL), section_name,
-				ent->name);
-			param->ipv6_ras = status;
-			continue;
-		}
-
-		if (strcmp(ent->name, "mtu") == 0) {
-			int status = parser_read_uint32(&param->mtu,
-					ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			mtu_present = 1;
-			continue;
-		}
-
-		if (strcmp(ent->name, "metadata_size") == 0) {
-			int status = parser_read_uint32(
-				&param->metadata_size, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			metadata_size_present = 1;
-			continue;
-		}
-
-		if (strcmp(ent->name, "mempool_direct") == 0) {
-			int status = validate_name(ent->value,
-				"MEMPOOL", 1);
-			ssize_t idx;
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-
-			idx = APP_PARAM_ADD(app->mempool_params, ent->value);
-			param->mempool_direct_id = idx;
-
-			mempool_direct_present = 1;
-			continue;
-		}
-
-		if (strcmp(ent->name, "mempool_indirect") == 0) {
-			int status = validate_name(ent->value,
-				"MEMPOOL", 1);
-			ssize_t idx;
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-
-			idx = APP_PARAM_ADD(app->mempool_params, ent->value);
-			param->mempool_indirect_id = idx;
-
-			mempool_indirect_present = 1;
-			continue;
-		}
-
-		/* unrecognized */
-		PARSE_ERROR_INVALID(0, section_name, ent->name);
-	}
-
-	APP_CHECK(((mtu_present == 0) ||
-		((param->ipv4_frag == 1) || (param->ipv6_frag == 1))),
-		"Parse error in section \"%s\": IPv4/IPv6 fragmentation "
-		"is off, therefore entry \"mtu\" is not allowed",
-		section_name);
-
-	APP_CHECK(((metadata_size_present == 0) ||
-		((param->ipv4_frag == 1) || (param->ipv6_frag == 1))),
-		"Parse error in section \"%s\": IPv4/IPv6 fragmentation "
-		"is off, therefore entry \"metadata_size\" is "
-		"not allowed", section_name);
-
-	APP_CHECK(((mempool_direct_present == 0) ||
-		((param->ipv4_frag == 1) || (param->ipv6_frag == 1))),
-		"Parse error in section \"%s\": IPv4/IPv6 fragmentation "
-		"is off, therefore entry \"mempool_direct\" is "
-		"not allowed", section_name);
-
-	APP_CHECK(((mempool_indirect_present == 0) ||
-		((param->ipv4_frag == 1) || (param->ipv6_frag == 1))),
-		"Parse error in section \"%s\": IPv4/IPv6 fragmentation "
-		"is off, therefore entry \"mempool_indirect\" is "
-		"not allowed", section_name);
-
-	free(entries);
-}
-
-static void
-parse_tm(struct app_params *app,
-	const char *section_name,
-	struct rte_cfgfile *cfg)
-{
-	struct app_pktq_tm_params *param;
-	struct rte_cfgfile_entry *entries;
-	int n_entries, i;
-	ssize_t param_idx;
-
-	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
-	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
-
-	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
-	PARSE_ERROR_MALLOC(entries != NULL);
-
-	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
-
-	param_idx = APP_PARAM_ADD(app->tm_params, section_name);
-	param = &app->tm_params[param_idx];
-	PARSE_CHECK_DUPLICATE_SECTION(param);
-
-	APP_PARAM_ADD_LINK_FOR_TM(app, section_name);
-
-	for (i = 0; i < n_entries; i++) {
-		struct rte_cfgfile_entry *ent = &entries[i];
-
-		if (strcmp(ent->name, "cfg") == 0) {
-			param->file_name = strdup(ent->value);
-			PARSE_ERROR_MALLOC(param->file_name != NULL);
-			continue;
-		}
-
-		if (strcmp(ent->name, "burst_read") == 0) {
-			int status = parser_read_uint32(
-				&param->burst_read, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "burst_write") == 0) {
-			int status = parser_read_uint32(
-				&param->burst_write, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		/* unrecognized */
-		PARSE_ERROR_INVALID(0, section_name, ent->name);
-	}
-
-	free(entries);
-}
-
-static void
-parse_tap(struct app_params *app,
-	const char *section_name,
-	struct rte_cfgfile *cfg)
-{
-	struct app_pktq_tap_params *param;
-	struct rte_cfgfile_entry *entries;
-	int n_entries, i;
-	ssize_t param_idx;
-
-	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
-	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
-
-	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
-	PARSE_ERROR_MALLOC(entries != NULL);
-
-	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
-
-	param_idx = APP_PARAM_ADD(app->tap_params, section_name);
-	param = &app->tap_params[param_idx];
-	PARSE_CHECK_DUPLICATE_SECTION(param);
-
-	for (i = 0; i < n_entries; i++) {
-		struct rte_cfgfile_entry *ent = &entries[i];
-
-		if (strcmp(ent->name, "burst_read") == 0) {
-			int status = parser_read_uint32(
-				&param->burst_read, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "burst_write") == 0) {
-			int status = parser_read_uint32(
-				&param->burst_write, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "dropless") == 0) {
-			int status = parser_read_arg_bool(ent->value);
-
-			PARSE_ERROR((status != -EINVAL), section_name,
-				ent->name);
-			param->dropless = status;
-			continue;
-		}
-
-		if (strcmp(ent->name, "n_retries") == 0) {
-			int status = parser_read_uint64(&param->n_retries,
-				ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "mempool") == 0) {
-			int status = validate_name(ent->value,
-				"MEMPOOL", 1);
-			ssize_t idx;
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-
-			idx = APP_PARAM_ADD(app->mempool_params, ent->value);
-			param->mempool_id = idx;
-
-			continue;
-		}
-
-		/* unrecognized */
-		PARSE_ERROR_INVALID(0, section_name, ent->name);
-	}
-
-	free(entries);
-}
-
-static void
-parse_kni(struct app_params *app,
-		  const char *section_name,
-		  struct rte_cfgfile *cfg)
-{
-	struct app_pktq_kni_params *param;
-	struct rte_cfgfile_entry *entries;
-	int n_entries, i;
-	ssize_t param_idx;
-
-	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
-	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
-
-	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
-	PARSE_ERROR_MALLOC(entries != NULL);
-
-	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
-
-	param_idx = APP_PARAM_ADD(app->kni_params, section_name);
-	param = &app->kni_params[param_idx];
-	PARSE_CHECK_DUPLICATE_SECTION(param);
-
-	APP_PARAM_ADD_LINK_FOR_KNI(app, section_name);
-
-	for (i = 0; i < n_entries; i++) {
-		struct rte_cfgfile_entry *ent = &entries[i];
-
-		if (strcmp(ent->name, "core") == 0) {
-			int status = parse_pipeline_core(
-					&param->socket_id,
-					&param->core_id,
-					&param->hyper_th_id,
-					ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-						ent->name);
-			param->force_bind = 1;
-			continue;
-		}
-
-		if (strcmp(ent->name, "mempool") == 0) {
-			int status = validate_name(ent->value,
-				"MEMPOOL", 1);
-			ssize_t idx;
-
-			PARSE_ERROR((status == 0), section_name,
-						ent->name);
-
-			idx = APP_PARAM_ADD(app->mempool_params, ent->value);
-			param->mempool_id = idx;
-			continue;
-		}
-
-		if (strcmp(ent->name, "burst_read") == 0) {
-			int status = parser_read_uint32(&param->burst_read,
-						ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-						ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "burst_write") == 0) {
-			int status = parser_read_uint32(&param->burst_write,
-						ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-						ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "dropless") == 0) {
-			int status = parser_read_arg_bool(ent->value);
-
-			PARSE_ERROR((status != -EINVAL), section_name,
-						ent->name);
-			param->dropless = status;
-			continue;
-		}
-
-		if (strcmp(ent->name, "n_retries") == 0) {
-			int status = parser_read_uint64(&param->n_retries,
-						ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-						ent->name);
-			continue;
-		}
-
-		/* unrecognized */
-		PARSE_ERROR_INVALID(0, section_name, ent->name);
-	}
-
-	free(entries);
-}
-
-static void
-parse_source(struct app_params *app,
-	const char *section_name,
-	struct rte_cfgfile *cfg)
-{
-	struct app_pktq_source_params *param;
-	struct rte_cfgfile_entry *entries;
-	int n_entries, i;
-	ssize_t param_idx;
-	uint32_t pcap_file_present = 0;
-	uint32_t pcap_size_present = 0;
-
-	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
-	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
-
-	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
-	PARSE_ERROR_MALLOC(entries != NULL);
-
-	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
-
-	param_idx = APP_PARAM_ADD(app->source_params, section_name);
-	param = &app->source_params[param_idx];
-	PARSE_CHECK_DUPLICATE_SECTION(param);
-
-	for (i = 0; i < n_entries; i++) {
-		struct rte_cfgfile_entry *ent = &entries[i];
-
-		if (strcmp(ent->name, "mempool") == 0) {
-			int status = validate_name(ent->value,
-				"MEMPOOL", 1);
-			ssize_t idx;
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-
-			idx = APP_PARAM_ADD(app->mempool_params, ent->value);
-			param->mempool_id = idx;
-			continue;
-		}
-
-		if (strcmp(ent->name, "burst") == 0) {
-			int status = parser_read_uint32(&param->burst,
-				ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "pcap_file_rd") == 0) {
-			PARSE_ERROR_DUPLICATE((pcap_file_present == 0),
-				section_name, ent->name);
-
-			param->file_name = strdup(ent->value);
-
-			PARSE_ERROR_MALLOC(param->file_name != NULL);
-			pcap_file_present = 1;
-
-			continue;
-		}
-
-		if (strcmp(ent->name, "pcap_bytes_rd_per_pkt") == 0) {
-			int status;
-
-			PARSE_ERROR_DUPLICATE((pcap_size_present == 0),
-				section_name, ent->name);
-
-			status = parser_read_uint32(
-				&param->n_bytes_per_pkt, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			pcap_size_present = 1;
-
-			continue;
-		}
-
-		/* unrecognized */
-		PARSE_ERROR_INVALID(0, section_name, ent->name);
-	}
-
-	free(entries);
-}
-
-static void
-parse_sink(struct app_params *app,
-	const char *section_name,
-	struct rte_cfgfile *cfg)
-{
-	struct app_pktq_sink_params *param;
-	struct rte_cfgfile_entry *entries;
-	int n_entries, i;
-	ssize_t param_idx;
-	uint32_t pcap_file_present = 0;
-	uint32_t pcap_n_pkt_present = 0;
-
-	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
-	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
-
-	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
-	PARSE_ERROR_MALLOC(entries != NULL);
-
-	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
-
-	param_idx = APP_PARAM_ADD(app->sink_params, section_name);
-	param = &app->sink_params[param_idx];
-	PARSE_CHECK_DUPLICATE_SECTION(param);
-
-	for (i = 0; i < n_entries; i++) {
-		struct rte_cfgfile_entry *ent = &entries[i];
-
-		if (strcmp(ent->name, "pcap_file_wr") == 0) {
-			PARSE_ERROR_DUPLICATE((pcap_file_present == 0),
-				section_name, ent->name);
-
-			param->file_name = strdup(ent->value);
-
-			PARSE_ERROR_MALLOC((param->file_name != NULL));
-
-			continue;
-		}
-
-		if (strcmp(ent->name, "pcap_n_pkt_wr") == 0) {
-			int status;
-
-			PARSE_ERROR_DUPLICATE((pcap_n_pkt_present == 0),
-				section_name, ent->name);
-
-			status = parser_read_uint32(
-				&param->n_pkts_to_dump, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-
-			continue;
-		}
-
-		/* unrecognized */
-		PARSE_ERROR_INVALID(0, section_name, ent->name);
-	}
-
-	free(entries);
-}
-
-static void
-parse_msgq_req_pipeline(struct app_params *app,
-	const char *section_name,
-	struct rte_cfgfile *cfg)
-{
-	struct app_msgq_params *param;
-	struct rte_cfgfile_entry *entries;
-	int n_entries, i;
-	ssize_t param_idx;
-
-	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
-	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
-
-	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
-	PARSE_ERROR_MALLOC(entries != NULL);
-
-	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
-
-	param_idx = APP_PARAM_ADD(app->msgq_params, section_name);
-	param = &app->msgq_params[param_idx];
-	PARSE_CHECK_DUPLICATE_SECTION(param);
-
-	for (i = 0; i < n_entries; i++) {
-		struct rte_cfgfile_entry *ent = &entries[i];
-
-		if (strcmp(ent->name, "size") == 0) {
-			int status = parser_read_uint32(&param->size,
-				ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		/* unrecognized */
-		PARSE_ERROR_INVALID(0, section_name, ent->name);
-	}
-
-	free(entries);
-}
-
-static void
-parse_msgq_rsp_pipeline(struct app_params *app,
-	const char *section_name,
-	struct rte_cfgfile *cfg)
-{
-	struct app_msgq_params *param;
-	struct rte_cfgfile_entry *entries;
-	int n_entries, i;
-	ssize_t param_idx;
-
-	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
-	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
-
-	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
-	PARSE_ERROR_MALLOC(entries != NULL);
-
-	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
-
-	param_idx = APP_PARAM_ADD(app->msgq_params, section_name);
-	param = &app->msgq_params[param_idx];
-	PARSE_CHECK_DUPLICATE_SECTION(param);
-
-	for (i = 0; i < n_entries; i++) {
-		struct rte_cfgfile_entry *ent = &entries[i];
-
-		if (strcmp(ent->name, "size") == 0) {
-			int status = parser_read_uint32(&param->size,
-				ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		/* unrecognized */
-		PARSE_ERROR_INVALID(0, section_name, ent->name);
-	}
-
-	free(entries);
-}
-
-static void
-parse_msgq(struct app_params *app,
-	const char *section_name,
-	struct rte_cfgfile *cfg)
-{
-	struct app_msgq_params *param;
-	struct rte_cfgfile_entry *entries;
-	int n_entries, i;
-	ssize_t param_idx;
-
-	n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
-	PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
-
-	entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
-	PARSE_ERROR_MALLOC(entries != NULL);
-
-	rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
-
-	param_idx = APP_PARAM_ADD(app->msgq_params, section_name);
-	param = &app->msgq_params[param_idx];
-	PARSE_CHECK_DUPLICATE_SECTION(param);
-
-	for (i = 0; i < n_entries; i++) {
-		struct rte_cfgfile_entry *ent = &entries[i];
-
-		if (strcmp(ent->name, "size") == 0) {
-			int status = parser_read_uint32(&param->size,
-				ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		if (strcmp(ent->name, "cpu") == 0) {
-			int status = parser_read_uint32(
-				&param->cpu_socket_id, ent->value);
-
-			PARSE_ERROR((status == 0), section_name,
-				ent->name);
-			continue;
-		}
-
-		/* unrecognized */
-		PARSE_ERROR_INVALID(0, section_name, ent->name);
-	}
-
-	free(entries);
-}
-
-typedef void (*config_section_load)(struct app_params *p,
-	const char *section_name,
-	struct rte_cfgfile *cfg);
-
-struct config_section {
-	const char prefix[CFG_NAME_LEN];
-	int numbers;
-	config_section_load load;
-};
-
-static const struct config_section cfg_file_scheme[] = {
-	{"EAL", 0, parse_eal},
-	{"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},
-	{"TAP", 1, parse_tap},
-	{"KNI", 1, parse_kni},
-	{"SOURCE", 1, parse_source},
-	{"SINK", 1, parse_sink},
-	{"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)
-{
-	APP_PARAM_ADD(app->mempool_params, "MEMPOOL0");
-}
-
-static void
-create_implicit_links_from_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%" PRIu32, link_id);
-		idx = APP_PARAM_ADD(app->link_params, name);
-
-		app->link_params[idx].pmd_id = pmd_id;
-		link_id++;
-	}
-}
-
-static void
-assign_link_pmd_id_from_pci_bdf(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_links; i++) {
-		struct app_link_params *link = &app->link_params[i];
-
-		APP_CHECK((strlen(link->pci_bdf)),
-			"Parse error: %s pci_bdf is not configured "
-			"(port_mask is not provided)",
-			link->name);
-
-		link->pmd_id = i;
-	}
-}
-
-int
-app_config_parse(struct app_params *app, const char *file_name)
-{
-	struct rte_cfgfile *cfg;
-	char **section_names;
-	int i, j, sect_count;
-
-	/* Implicit mempools */
-	create_implicit_mempools(app);
-
-	/* Port mask */
-	if (app->port_mask)
-		create_implicit_links_from_port_mask(app, app->port_mask);
-
-	/* Load application configuration file */
-	cfg = rte_cfgfile_load(file_name, 0);
-	APP_CHECK((cfg != NULL), "Parse error: Unable to load config "
-		"file %s", file_name);
-
-	sect_count = rte_cfgfile_num_sections(cfg, NULL, 0);
-	APP_CHECK((sect_count > 0), "Parse error: number of sections "
-		"in file \"%s\" return %d", file_name,
-		sect_count);
-
-	section_names = malloc(sect_count * sizeof(char *));
-	PARSE_ERROR_MALLOC(section_names != NULL);
-
-	for (i = 0; i < sect_count; i++)
-		section_names[i] = malloc(CFG_NAME_LEN);
-
-	rte_cfgfile_sections(cfg, section_names, sect_count);
-
-	for (i = 0; i < sect_count; i++) {
-		const struct config_section *sch_s;
-		int len, cfg_name_len;
-
-		cfg_name_len = strlen(section_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,
-			 * for example: "ABC" should match section name
-			 * "ABC0.0", but it should not match section_name
-			 * "ABCDEF".
-			 */
-			if ((section_names[i][len] != '\0') &&
-				!isdigit(section_names[i][len]))
-				continue;
-
-			if (strncmp(sch_s->prefix, section_names[i], len) == 0)
-				break;
-		}
-
-		APP_CHECK(j < (int)RTE_DIM(cfg_file_scheme),
-			"Parse error: unknown section %s",
-			section_names[i]);
-
-		APP_CHECK(validate_name(section_names[i],
-			sch_s->prefix,
-			sch_s->numbers) == 0,
-			"Parse error: invalid section name \"%s\"",
-			section_names[i]);
-
-		sch_s->load(app, section_names[i], cfg);
-	}
-
-	for (i = 0; i < sect_count; i++)
-		free(section_names[i]);
-
-	free(section_names);
-
-	rte_cfgfile_close(cfg);
-
-	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->tap_params, app->n_pktq_tap);
-	APP_PARAM_COUNT(app->kni_params, app->n_pktq_kni);
-	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);
-
-	if (app->port_mask == 0)
-		assign_link_pmd_id_from_pci_bdf(app);
-
-	/* Save configuration to output file */
-	app_config_save(app, app->output_file);
-
-	/* Load TM configuration files */
-	app_config_parse_tm(app);
-
-	return 0;
-}
-
-static void
-save_eal_params(struct app_params *app, FILE *f)
-{
-	struct app_eal_params *p = &app->eal_params;
-	uint32_t i;
-
-	fprintf(f, "[EAL]\n");
-
-	if (p->coremap)
-		fprintf(f, "%s = %s\n", "lcores", p->coremap);
-
-	if (p->master_lcore_present)
-		fprintf(f, "%s = %" PRIu32 "\n",
-			"master_lcore", p->master_lcore);
-
-	fprintf(f, "%s = %" PRIu32 "\n", "n", p->channels);
-
-	if (p->memory_present)
-		fprintf(f, "%s = %" PRIu32 "\n", "m", p->memory);
-
-	if (p->ranks_present)
-		fprintf(f, "%s = %" PRIu32 "\n", "r", p->ranks);
-
-	for (i = 0; i < APP_MAX_LINKS; i++) {
-		if (p->pci_blacklist[i] == NULL)
-			break;
-
-		fprintf(f, "%s = %s\n", "pci_blacklist",
-			p->pci_blacklist[i]);
-	}
-
-	for (i = 0; i < APP_MAX_LINKS; i++) {
-		if (p->pci_whitelist[i] == NULL)
-			break;
-
-		fprintf(f, "%s = %s\n", "pci_whitelist",
-			p->pci_whitelist[i]);
-	}
-
-	for (i = 0; i < APP_MAX_LINKS; i++) {
-		if (p->vdev[i] == NULL)
-			break;
-
-		fprintf(f, "%s = %s\n", "vdev",
-			p->vdev[i]);
-	}
-
-	if (p->vmware_tsc_map_present)
-		fprintf(f, "%s = %s\n", "vmware_tsc_map",
-			(p->vmware_tsc_map) ? "yes" : "no");
-
-	if (p->proc_type)
-		fprintf(f, "%s = %s\n", "proc_type", p->proc_type);
-
-	if (p->syslog)
-		fprintf(f, "%s = %s\n", "syslog", p->syslog);
-
-	if (p->log_level_present)
-		fprintf(f, "%s = %" PRIu32 "\n", "log_level", p->log_level);
-
-	if (p->version_present)
-		fprintf(f, "%s = %s\n",	"v", (p->version) ? "yes" : "no");
-
-	if (p->help_present)
-		fprintf(f, "%s = %s\n",	"help", (p->help) ? "yes" : "no");
-
-	if (p->no_huge_present)
-		fprintf(f, "%s = %s\n",	"no_huge", (p->no_huge) ? "yes" : "no");
-
-	if (p->no_pci_present)
-		fprintf(f, "%s = %s\n",	"no_pci", (p->no_pci) ? "yes" : "no");
-
-	if (p->no_hpet_present)
-		fprintf(f, "%s = %s\n",	"no_hpet", (p->no_hpet) ? "yes" : "no");
-
-	if (p->no_shconf_present)
-		fprintf(f, "%s = %s\n", "no_shconf",
-			(p->no_shconf) ? "yes" : "no");
-
-	if (p->add_driver)
-		fprintf(f, "%s = %s\n",	"d", p->add_driver);
-
-	if (p->socket_mem)
-		fprintf(f, "%s = %s\n",	"socket_mem", p->socket_mem);
-
-	if (p->huge_dir)
-		fprintf(f, "%s = %s\n", "huge_dir", p->huge_dir);
-
-	if (p->file_prefix)
-		fprintf(f, "%s = %s\n", "file_prefix", p->file_prefix);
-
-	if (p->base_virtaddr)
-		fprintf(f, "%s = %s\n",	"base_virtaddr", p->base_virtaddr);
-
-	if (p->create_uio_dev_present)
-		fprintf(f, "%s = %s\n", "create_uio_dev",
-			(p->create_uio_dev) ? "yes" : "no");
-
-	if (p->vfio_intr)
-		fprintf(f, "%s = %s\n", "vfio_intr", p->vfio_intr);
-
-	fputc('\n', f);
-}
-
-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 = %s\n", "promisc", p->promisc ? "yes" : "no");
-		fprintf(f, "%s = %" PRIu32 "\n", "arp_q", p->arp_q);
-		fprintf(f, "%s = %" PRIu32 "\n", "tcp_syn_q",
-			p->tcp_syn_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);
-
-		if (p->n_rss_qs) {
-			uint32_t j;
-
-			/* rss_qs */
-			fprintf(f, "rss_qs = ");
-			for (j = 0; j < p->n_rss_qs; j++)
-				fprintf(f, "%" PRIu32 " ",	p->rss_qs[j]);
-			fputc('\n', f);
-
-			/* rss_proto_ipv4 */
-			if (p->rss_proto_ipv4) {
-				fprintf(f, "rss_proto_ipv4 = ");
-				if (p->rss_proto_ipv4 & ETH_RSS_IPV4)
-					fprintf(f, "IP ");
-				if (p->rss_proto_ipv4 & ETH_RSS_FRAG_IPV4)
-					fprintf(f, "FRAG ");
-				if (p->rss_proto_ipv4 &
-					ETH_RSS_NONFRAG_IPV4_TCP)
-					fprintf(f, "TCP ");
-				if (p->rss_proto_ipv4 &
-					ETH_RSS_NONFRAG_IPV4_UDP)
-					fprintf(f, "UDP ");
-				if (p->rss_proto_ipv4 &
-					ETH_RSS_NONFRAG_IPV4_SCTP)
-					fprintf(f, "SCTP ");
-				if (p->rss_proto_ipv4 &
-					ETH_RSS_NONFRAG_IPV4_OTHER)
-					fprintf(f, "OTHER ");
-				fprintf(f, "\n");
-			} else
-				fprintf(f, "; rss_proto_ipv4 = <NONE>\n");
-
-			/* rss_proto_ipv6 */
-			if (p->rss_proto_ipv6) {
-				fprintf(f, "rss_proto_ipv6 = ");
-				if (p->rss_proto_ipv6 & ETH_RSS_IPV6)
-					fprintf(f, "IP ");
-				if (p->rss_proto_ipv6 & ETH_RSS_FRAG_IPV6)
-					fprintf(f, "FRAG ");
-				if (p->rss_proto_ipv6 &
-					ETH_RSS_NONFRAG_IPV6_TCP)
-					fprintf(f, "TCP ");
-				if (p->rss_proto_ipv6 &
-					ETH_RSS_NONFRAG_IPV6_UDP)
-					fprintf(f, "UDP ");
-				if (p->rss_proto_ipv6 &
-					ETH_RSS_NONFRAG_IPV6_SCTP)
-					fprintf(f, "SCTP ");
-				if (p->rss_proto_ipv6 &
-					ETH_RSS_NONFRAG_IPV6_OTHER)
-					fprintf(f, "OTHER ");
-				if (p->rss_proto_ipv6 & ETH_RSS_IPV6_EX)
-					fprintf(f, "IP_EX ");
-				if (p->rss_proto_ipv6 &
-					ETH_RSS_IPV6_TCP_EX)
-					fprintf(f, "TCP_EX ");
-				if (p->rss_proto_ipv6 &
-					ETH_RSS_IPV6_UDP_EX)
-					fprintf(f, "UDP_EX ");
-				fprintf(f, "\n");
-			} else
-				fprintf(f, "; rss_proto_ipv6 = <NONE>\n");
-
-			/* rss_proto_l2 */
-			if (p->rss_proto_l2) {
-				fprintf(f, "rss_proto_l2 = ");
-				if (p->rss_proto_l2 & ETH_RSS_L2_PAYLOAD)
-					fprintf(f, "L2 ");
-				fprintf(f, "\n");
-			} else
-				fprintf(f, "; rss_proto_l2 = <NONE>\n");
-		} else {
-			fprintf(f, "; rss_qs = <NONE>\n");
-			fprintf(f, "; rss_proto_ipv4 = <NONE>\n");
-			fprintf(f, "; rss_proto_ipv6 = <NONE>\n");
-			fprintf(f, "; rss_proto_l2 = <NONE>\n");
-		}
-
-		if (strlen(p->pci_bdf))
-			fprintf(f, "%s = %s\n", "pci_bdf", p->pci_bdf);
-
-		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");
-		fprintf(f, "%s = %" PRIu64 "\n", "n_retries", p->n_retries);
-
-		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);
-		fprintf(f, "%s = %s\n", "ipv4_frag", p->ipv4_frag ? "yes" : "no");
-		fprintf(f, "%s = %s\n", "ipv6_frag", p->ipv6_frag ? "yes" : "no");
-		fprintf(f, "%s = %s\n", "ipv4_ras", p->ipv4_ras ? "yes" : "no");
-		fprintf(f, "%s = %s\n", "ipv6_ras", p->ipv6_ras ? "yes" : "no");
-		if ((p->ipv4_frag == 1) || (p->ipv6_frag == 1)) {
-			fprintf(f, "%s = %" PRIu32 "\n", "mtu", p->mtu);
-			fprintf(f, "%s = %" PRIu32 "\n", "metadata_size", p->metadata_size);
-			fprintf(f, "%s = %s\n",
-				"mempool_direct",
-				app->mempool_params[p->mempool_direct_id].name);
-			fprintf(f, "%s = %s\n",
-				"mempool_indirect",
-				app->mempool_params[p->mempool_indirect_id].name);
-		}
-
-		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 = %" PRIu32 "\n", "burst_read", p->burst_read);
-		fprintf(f, "%s = %" PRIu32 "\n", "burst_write", p->burst_write);
-
-		fputc('\n', f);
-	}
-}
-
-static void
-save_tap_params(struct app_params *app, FILE *f)
-{
-	struct app_pktq_tap_params *p;
-	size_t i, count;
-
-	count = RTE_DIM(app->tap_params);
-	for (i = 0; i < count; i++) {
-		p = &app->tap_params[i];
-		if (!APP_PARAM_VALID(p))
-			continue;
-
-		fprintf(f, "[%s]\n", p->name);
-		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 = %s\n", "mempool",
-			app->mempool_params[p->mempool_id].name);
-
-		fputc('\n', f);
-	}
-}
-
-static void
-save_kni_params(struct app_params *app, FILE *f)
-{
-	struct app_pktq_kni_params *p;
-	size_t i, count;
-
-	count = RTE_DIM(app->kni_params);
-	for (i = 0; i < count; i++) {
-		p = &app->kni_params[i];
-		if (!APP_PARAM_VALID(p))
-			continue;
-
-		/* section name */
-		fprintf(f, "[%s]\n", p->name);
-
-		/* core */
-		if (p->force_bind) {
-			fprintf(f, "; force_bind = 1\n");
-			fprintf(f, "core = s%" PRIu32 "c%" PRIu32 "%s\n",
-					p->socket_id,
-					p->core_id,
-					(p->hyper_th_id) ? "h" : "");
-		} else
-			fprintf(f, "; force_bind = 0\n");
-
-		/* mempool */
-		fprintf(f, "%s = %s\n", "mempool",
-				app->mempool_params[p->mempool_id].name);
-
-		/* burst_read */
-		fprintf(f, "%s = %" PRIu32 "\n", "burst_read", p->burst_read);
-
-		/* burst_write */
-		fprintf(f, "%s = %" PRIu32 "\n", "burst_write", p->burst_write);
-
-		/* dropless */
-		fprintf(f, "%s = %s\n",
-				"dropless",
-				p->dropless ? "yes" : "no");
-
-		/* n_retries */
-		fprintf(f, "%s = %" PRIu64 "\n", "n_retries", p->n_retries);
-
-		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 = %" PRIu32 "\n", "burst", p->burst);
-		fprintf(f, "%s = %s\n", "pcap_file_rd", p->file_name);
-		fprintf(f, "%s = %" PRIu32 "\n", "pcap_bytes_rd_per_pkt",
-			p->n_bytes_per_pkt);
-		fputc('\n', f);
-	}
-}
-
-static void
-save_sink_params(struct app_params *app, FILE *f)
-{
-	struct app_pktq_sink_params *p;
-	size_t i, count;
-
-	count = RTE_DIM(app->sink_params);
-	for (i = 0; i < count; i++) {
-		p = &app->sink_params[i];
-		if (!APP_PARAM_VALID(p))
-			continue;
-
-		fprintf(f, "[%s]\n", p->name);
-		fprintf(f, "%s = %s\n", "pcap_file_wr", p->file_name);
-		fprintf(f, "%s = %" PRIu32 "\n",
-				"pcap_n_pkt_wr", p->n_pkts_to_dump);
-		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%" PRIu32 "c%" PRIu32 "%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_TAP:
-					name = app->tap_params[pp->id].name;
-					break;
-				case APP_PKTQ_IN_KNI:
-					name = app->kni_params[pp->id].name;
-					break;
-				case APP_PKTQ_IN_SOURCE:
-					name = app->source_params[pp->id].name;
-					break;
-				default:
-					APP_CHECK(0, "System error "
-						"occurred while saving "
-						"parameter to file");
-				}
-
-				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_TAP:
-					name = app->tap_params[pp->id].name;
-					break;
-				case APP_PKTQ_OUT_KNI:
-					name = app->kni_params[pp->id].name;
-					break;
-				case APP_PKTQ_OUT_SINK:
-					name = app->sink_params[pp->id].name;
-					break;
-				default:
-					APP_CHECK(0, "System error "
-						"occurred while saving "
-						"parameter to file");
-				}
-
-				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_out) {
-			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 = %" PRIu32 "\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;
-	char *name, *dir_name;
-	int status;
-
-	name = strdup(file_name);
-	dir_name = dirname(name);
-	status = access(dir_name, W_OK);
-	APP_CHECK((status == 0),
-		"Error: need write access privilege to directory "
-		"\"%s\" to save configuration\n", dir_name);
-
-	file = fopen(file_name, "w");
-	APP_CHECK((file != NULL),
-		"Error: failed to save configuration to file \"%s\"",
-		file_name);
-
-	save_eal_params(app, file);
-	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_tap_params(app, file);
-	save_kni_params(app, file);
-	save_source_params(app, file);
-	save_sink_params(app, file);
-	save_msgq_params(app, file);
-
-	fclose(file);
-	free(name);
-}
-
-int
-app_config_init(struct app_params *app)
-{
-	size_t i;
-
-	memcpy(app, &app_params_default, sizeof(struct app_params));
-
-	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->tap_params); i++)
-		memcpy(&app->tap_params[i],
-			&default_tap_params,
-			sizeof(default_tap_params));
-
-	for (i = 0; i < RTE_DIM(app->kni_params); i++)
-		memcpy(&app->kni_params[i],
-			   &default_kni_params,
-			   sizeof(default_kni_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;
-}
-
-static char *
-filenamedup(const char *filename, const char *suffix)
-{
-	char *s = malloc(strlen(filename) + strlen(suffix) + 1);
-
-	if (!s)
-		return NULL;
-
-	sprintf(s, "%s%s", filename, suffix);
-	return s;
-}
-
-int
-app_config_args(struct app_params *app, int argc, char **argv)
-{
-	const char *optname;
-	int opt, option_index;
-	int f_present, s_present, p_present, l_present;
-	int preproc_present, preproc_params_present;
-	int scaned = 0;
-
-	static struct option lgopts[] = {
-		{ "preproc", 1, 0, 0 },
-		{ "preproc-args", 1, 0, 0 },
-		{ NULL,  0, 0, 0 }
-	};
-
-	/* Copy application name */
-	strncpy(app->app_name, argv[0], APP_APPNAME_SIZE - 1);
-
-	f_present = 0;
-	s_present = 0;
-	p_present = 0;
-	l_present = 0;
-	preproc_present = 0;
-	preproc_params_present = 0;
-
-	while ((opt = getopt_long(argc, argv, "f:s:p:l:", lgopts,
-			&option_index)) != EOF)
-		switch (opt) {
-		case 'f':
-			if (f_present)
-				rte_panic("Error: Config file is provided "
-					"more than once\n");
-			f_present = 1;
-
-			if (!strlen(optarg))
-				rte_panic("Error: Config file name is null\n");
-
-			app->config_file = strdup(optarg);
-			if (app->config_file == NULL)
-				rte_panic("Error: Memory allocation failure\n");
-
-			break;
-
-		case 's':
-			if (s_present)
-				rte_panic("Error: Script file is provided "
-					"more than once\n");
-			s_present = 1;
-
-			if (!strlen(optarg))
-				rte_panic("Error: Script file name is null\n");
-
-			app->script_file = strdup(optarg);
-			if (app->script_file == NULL)
-				rte_panic("Error: Memory allocation failure\n");
-
-			break;
-
-		case 'p':
-			if (p_present)
-				rte_panic("Error: PORT_MASK is provided "
-					"more than once\n");
-			p_present = 1;
-
-			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");
-
-			break;
-
-		case 'l':
-			if (l_present)
-				rte_panic("Error: LOG_LEVEL is provided "
-					"more than once\n");
-			l_present = 1;
-
-			if ((sscanf(optarg, "%" SCNu32 "%n", &app->log_level,
-				&scaned) != 1) ||
-				((size_t) scaned != strlen(optarg)) ||
-				(app->log_level >= APP_LOG_LEVELS))
-				rte_panic("Error: LOG_LEVEL invalid value\n");
-
-			break;
-
-		case 0:
-			optname = lgopts[option_index].name;
-
-			if (strcmp(optname, "preproc") == 0) {
-				if (preproc_present)
-					rte_panic("Error: Preprocessor argument "
-						"is provided more than once\n");
-				preproc_present = 1;
-
-				app->preproc = strdup(optarg);
-				break;
-			}
-
-			if (strcmp(optname, "preproc-args") == 0) {
-				if (preproc_params_present)
-					rte_panic("Error: Preprocessor args "
-						"are provided more than once\n");
-				preproc_params_present = 1;
-
-				app->preproc_args = strdup(optarg);
-				break;
-			}
-
-			app_print_usage(argv[0]);
-			break;
-
-		default:
-			app_print_usage(argv[0]);
-		}
-
-	optind = 1; /* reset getopt lib */
-
-	/* Check dependencies between args */
-	if (preproc_params_present && (preproc_present == 0))
-		rte_panic("Error: Preprocessor args specified while "
-			"preprocessor is not defined\n");
-
-	app->parser_file = preproc_present ?
-		filenamedup(app->config_file, ".preproc") :
-		strdup(app->config_file);
-	app->output_file = filenamedup(app->config_file, ".out");
-
-	return 0;
-}
-
-int
-app_config_preproc(struct app_params *app)
-{
-	char buffer[256];
-	int status;
-
-	if (app->preproc == NULL)
-		return 0;
-
-	status = access(app->config_file, F_OK | R_OK);
-	APP_CHECK((status == 0), "Error: Unable to open file %s",
-		app->config_file);
-
-	snprintf(buffer, sizeof(buffer), "%s %s %s > %s",
-		app->preproc,
-		app->preproc_args ? app->preproc_args : "",
-		app->config_file,
-		app->parser_file);
-
-	status = system(buffer);
-	APP_CHECK((WIFEXITED(status) && (WEXITSTATUS(status) == 0)),
-		"Error occurred while pre-processing file \"%s\"\n",
-		app->config_file);
-
-	return status;
-}
diff --git a/examples/ip_pipeline/config_parse_tm.c b/examples/ip_pipeline/config_parse_tm.c
deleted file mode 100644
index 6edd2ca..0000000
--- a/examples/ip_pipeline/config_parse_tm.c
+++ /dev/null
@@ -1,419 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-#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 <libgen.h>
-#include <unistd.h>
-
-#include <rte_errno.h>
-#include <rte_cfgfile.h>
-#include <rte_string_fns.h>
-
-#include "app.h"
-
-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", "mtu");
-	if (entry)
-		port_params->mtu = (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 %" PRId32 " 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 %" PRId32 " 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 %" PRId32 " 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 %" PRId32 " 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 %" PRId32, 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 %" PRId32, 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);
-			struct rte_cfgfile_entry entries[n_entries];
-
-			rte_cfgfile_section_entries(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 + 1];
-
-					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 %" PRId32,
-							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 i;
-
-	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_port_params));
-	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];
-
-	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;
-}
-
-int
-app_config_parse_tm(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < RTE_DIM(app->tm_params); i++) {
-		struct app_pktq_tm_params *p = &app->tm_params[i];
-		int status;
-
-		if (!APP_PARAM_VALID(p))
-			break;
-
-		status = tm_cfgfile_load(p);
-		APP_CHECK(status == 0,
-			"Parse error for %s configuration file \"%s\"\n",
-			p->name,
-			p->file_name);
-	}
-
-	return 0;
-}
diff --git a/examples/ip_pipeline/cpu_core_map.c b/examples/ip_pipeline/cpu_core_map.c
deleted file mode 100644
index 231f38e..0000000
--- a/examples/ip_pipeline/cpu_core_map.c
+++ /dev/null
@@ -1,471 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#include <inttypes.h>
-#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%" PRIu32 "/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%" PRIu32 "/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 !defined(RTE_ARCH_PPC_64)
-			if (lcore_socket_id < 0)
-				return -1;
-#endif
-
-			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 !defined(RTE_ARCH_PPC_64)
-				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;
-#endif
-
-#if !defined(RTE_ARCH_PPC_64)
-				if (((uint32_t) lcore_socket_id == socket_id) &&
-					((uint32_t) lcore_core_id == core_id)) {
-#else
-				if (((uint32_t) lcore_socket_id == socket_id)) {
-#endif
-					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)
-{
-	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 %" PRIu32 ":\n", socket_id);
-
-		for (core_id = 0;
-			core_id < map->n_cores_per_socket;
-			core_id++) {
-			printf("[%" PRIu32 "] = [", 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 =
-					cpu_core_map_get_core_id_linux(
-						lcore_id);
-
-				printf(" %" PRId32 " (%" PRIu32 ") ",
-					lcore_id,
-					core_id_noncontig);
-			}
-
-			printf("]\n");
-		}
-	}
-}
-
-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)
-{
-	free(map);
-}
diff --git a/examples/ip_pipeline/cpu_core_map.h b/examples/ip_pipeline/cpu_core_map.h
deleted file mode 100644
index 5e50f6e..0000000
--- a/examples/ip_pipeline/cpu_core_map.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#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/init.c b/examples/ip_pipeline/init.c
deleted file mode 100644
index 9430809..0000000
--- a/examples/ip_pipeline/init.c
+++ /dev/null
@@ -1,1343 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2016 Intel Corporation
- */
-
-#include <inttypes.h>
-#include <stdio.h>
-#include <string.h>
-#include <netinet/in.h>
-#ifdef RTE_EXEC_ENV_LINUXAPP
-#include <linux/if.h>
-#include <linux/if_tun.h>
-#endif
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <unistd.h>
-
-#include <rte_cycles.h>
-#include <rte_ethdev.h>
-#include <rte_ether.h>
-#include <rte_ip.h>
-#include <rte_eal.h>
-#include <rte_malloc.h>
-#include <rte_bus_pci.h>
-
-#include "app.h"
-#include "pipeline.h"
-
-#define APP_NAME_SIZE	32
-
-#define APP_RETA_SIZE_MAX     (ETH_RSS_RETA_SIZE_512 / RTE_RETA_GROUP_SIZE)
-
-static void
-app_init_core_map(struct app_params *app)
-{
-	APP_LOG(app, HIGH, "Initializing CPU core map ...");
-	app->core_map = cpu_core_map_init(RTE_MAX_NUMA_NODES, RTE_MAX_LCORE,
-				4, 0);
-
-	if (app->core_map == NULL)
-		rte_panic("Cannot create CPU core map\n");
-
-	if (app->log_level >= APP_LOG_LEVEL_LOW)
-		cpu_core_map_print(app->core_map);
-}
-
-/* Core Mask String in Hex Representation */
-#define APP_CORE_MASK_STRING_SIZE ((64 * APP_CORE_MASK_SIZE) / 8 * 2 + 1)
-
-static void
-app_init_core_mask(struct app_params *app)
-{
-	uint32_t i;
-	char core_mask_str[APP_CORE_MASK_STRING_SIZE];
-
-	for (i = 0; i < app->n_pipelines; i++) {
-		struct app_pipeline_params *p = &app->pipeline_params[i];
-		int lcore_id;
-
-		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");
-
-		app_core_enable_in_core_mask(app, lcore_id);
-	}
-
-	app_core_build_core_mask_string(app, core_mask_str);
-	APP_LOG(app, HIGH, "CPU core mask = 0x%s", core_mask_str);
-}
-
-static void
-app_init_eal(struct app_params *app)
-{
-	char buffer[256];
-	char core_mask_str[APP_CORE_MASK_STRING_SIZE];
-	struct app_eal_params *p = &app->eal_params;
-	uint32_t n_args = 0;
-	uint32_t i;
-	int status;
-
-	app->eal_argv[n_args++] = strdup(app->app_name);
-
-	app_core_build_core_mask_string(app, core_mask_str);
-	snprintf(buffer, sizeof(buffer), "-c%s", core_mask_str);
-	app->eal_argv[n_args++] = strdup(buffer);
-
-	if (p->coremap) {
-		snprintf(buffer, sizeof(buffer), "--lcores=%s", p->coremap);
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if (p->master_lcore_present) {
-		snprintf(buffer,
-			sizeof(buffer),
-			"--master-lcore=%" PRIu32,
-			p->master_lcore);
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	snprintf(buffer, sizeof(buffer), "-n%" PRIu32, p->channels);
-	app->eal_argv[n_args++] = strdup(buffer);
-
-	if (p->memory_present) {
-		snprintf(buffer, sizeof(buffer), "-m%" PRIu32, p->memory);
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if (p->ranks_present) {
-		snprintf(buffer, sizeof(buffer), "-r%" PRIu32, p->ranks);
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	for (i = 0; i < APP_MAX_LINKS; i++) {
-		if (p->pci_blacklist[i] == NULL)
-			break;
-
-		snprintf(buffer,
-			sizeof(buffer),
-			"--pci-blacklist=%s",
-			p->pci_blacklist[i]);
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if (app->port_mask != 0)
-		for (i = 0; i < APP_MAX_LINKS; i++) {
-			if (p->pci_whitelist[i] == NULL)
-				break;
-
-			snprintf(buffer,
-				sizeof(buffer),
-				"--pci-whitelist=%s",
-				p->pci_whitelist[i]);
-			app->eal_argv[n_args++] = strdup(buffer);
-		}
-	else
-		for (i = 0; i < app->n_links; i++) {
-			char *pci_bdf = app->link_params[i].pci_bdf;
-
-			snprintf(buffer,
-				sizeof(buffer),
-				"--pci-whitelist=%s",
-				pci_bdf);
-			app->eal_argv[n_args++] = strdup(buffer);
-		}
-
-	for (i = 0; i < APP_MAX_LINKS; i++) {
-		if (p->vdev[i] == NULL)
-			break;
-
-		snprintf(buffer,
-			sizeof(buffer),
-			"--vdev=%s",
-			p->vdev[i]);
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if ((p->vmware_tsc_map_present) && p->vmware_tsc_map) {
-		snprintf(buffer, sizeof(buffer), "--vmware-tsc-map");
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if (p->proc_type) {
-		snprintf(buffer,
-			sizeof(buffer),
-			"--proc-type=%s",
-			p->proc_type);
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if (p->syslog) {
-		snprintf(buffer, sizeof(buffer), "--syslog=%s", p->syslog);
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if (p->log_level_present) {
-		snprintf(buffer,
-			sizeof(buffer),
-			"--log-level=%" PRIu32,
-			p->log_level);
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if ((p->version_present) && p->version) {
-		snprintf(buffer, sizeof(buffer), "-v");
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if ((p->help_present) && p->help) {
-		snprintf(buffer, sizeof(buffer), "--help");
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if ((p->no_huge_present) && p->no_huge) {
-		snprintf(buffer, sizeof(buffer), "--no-huge");
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if ((p->no_pci_present) && p->no_pci) {
-		snprintf(buffer, sizeof(buffer), "--no-pci");
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if ((p->no_hpet_present) && p->no_hpet) {
-		snprintf(buffer, sizeof(buffer), "--no-hpet");
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if ((p->no_shconf_present) && p->no_shconf) {
-		snprintf(buffer, sizeof(buffer), "--no-shconf");
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if (p->add_driver) {
-		snprintf(buffer, sizeof(buffer), "-d%s", p->add_driver);
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if (p->socket_mem) {
-		snprintf(buffer,
-			sizeof(buffer),
-			"--socket-mem=%s",
-			p->socket_mem);
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if (p->huge_dir) {
-		snprintf(buffer, sizeof(buffer), "--huge-dir=%s", p->huge_dir);
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if (p->file_prefix) {
-		snprintf(buffer,
-			sizeof(buffer),
-			"--file-prefix=%s",
-			p->file_prefix);
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if (p->base_virtaddr) {
-		snprintf(buffer,
-			sizeof(buffer),
-			"--base-virtaddr=%s",
-			p->base_virtaddr);
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if ((p->create_uio_dev_present) && p->create_uio_dev) {
-		snprintf(buffer, sizeof(buffer), "--create-uio-dev");
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	if (p->vfio_intr) {
-		snprintf(buffer,
-			sizeof(buffer),
-			"--vfio-intr=%s",
-			p->vfio_intr);
-		app->eal_argv[n_args++] = strdup(buffer);
-	}
-
-	snprintf(buffer, sizeof(buffer), "--");
-	app->eal_argv[n_args++] = strdup(buffer);
-
-	app->eal_argc = n_args;
-
-	APP_LOG(app, HIGH, "Initializing EAL ...");
-	if (app->log_level >= APP_LOG_LEVEL_LOW) {
-		int i;
-
-		fprintf(stdout, "[APP] EAL arguments: \"");
-		for (i = 1; i < app->eal_argc; i++)
-			fprintf(stdout, "%s ", app->eal_argv[i]);
-		fprintf(stdout, "\"\n");
-	}
-
-	status = rte_eal_init(app->eal_argc, app->eal_argv);
-	if (status < 0)
-		rte_panic("EAL init error\n");
-}
-
-static void
-app_init_mempool(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_mempools; i++) {
-		struct app_mempool_params *p = &app->mempool_params[i];
-
-		APP_LOG(app, HIGH, "Initializing %s ...", p->name);
-		app->mempool[i] = rte_pktmbuf_pool_create(
-			p->name,
-			p->pool_size,
-			p->cache_size,
-			0, /* priv_size */
-			p->buffer_size -
-				sizeof(struct rte_mbuf), /* mbuf data size */
-			p->cpu_socket_id);
-
-		if (app->mempool[i] == NULL)
-			rte_panic("%s init error\n", p->name);
-	}
-}
-
-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 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_q,
-	};
-
-	return rte_eth_dev_filter_ctrl(link->pmd_id,
-		RTE_ETH_FILTER_SYN,
-		RTE_ETH_FILTER_ADD,
-		&filter);
-}
-
-static inline int
-app_link_filter_ip_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 = UINT32_MAX, /* Enable */
-		.src_ip = 0,
-		.src_ip_mask = 0, /* Disable */
-		.dst_port = 0,
-		.dst_port_mask = 0, /* Disable */
-		.src_port = 0,
-		.src_port_mask = 0, /* Disable */
-		.proto = 0,
-		.proto_mask = 0, /* 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);
-}
-
-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 = UINT32_MAX, /* Enable */
-		.src_ip = 0,
-		.src_ip_mask = 0, /* Disable */
-		.dst_port = 0,
-		.dst_port_mask = 0, /* Disable */
-		.src_port = 0,
-		.src_port_mask = 0, /* Disable */
-		.proto = 0,
-		.proto_mask = 0, /* 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);
-}
-
-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 = UINT32_MAX, /* Enable */
-		.src_ip = 0,
-		.src_ip_mask = 0, /* Disable */
-		.dst_port = 0,
-		.dst_port_mask = 0, /* Disable */
-		.src_port = 0,
-		.src_port_mask = 0, /* Disable */
-		.proto = IPPROTO_TCP,
-		.proto_mask = UINT8_MAX, /* 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);
-}
-
-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 = UINT32_MAX, /* Enable */
-		.src_ip = 0,
-		.src_ip_mask = 0, /* Disable */
-		.dst_port = 0,
-		.dst_port_mask = 0, /* Disable */
-		.src_port = 0,
-		.src_port_mask = 0, /* Disable */
-		.proto = IPPROTO_TCP,
-		.proto_mask = UINT8_MAX, /* 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);
-}
-
-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 = UINT32_MAX, /* Enable */
-		.src_ip = 0,
-		.src_ip_mask = 0, /* Disable */
-		.dst_port = 0,
-		.dst_port_mask = 0, /* Disable */
-		.src_port = 0,
-		.src_port_mask = 0, /* Disable */
-		.proto = IPPROTO_UDP,
-		.proto_mask = UINT8_MAX, /* 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 = UINT32_MAX, /* Enable */
-		.src_ip = 0,
-		.src_ip_mask = 0, /* Disable */
-		.dst_port = 0,
-		.dst_port_mask = 0, /* Disable */
-		.src_port = 0,
-		.src_port_mask = 0, /* Disable */
-		.proto = IPPROTO_UDP,
-		.proto_mask = UINT8_MAX, /* 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 = UINT32_MAX, /* Enable */
-		.src_ip = 0,
-		.src_ip_mask = 0, /* Disable */
-		.dst_port = 0,
-		.dst_port_mask = 0, /* Disable */
-		.src_port = 0,
-		.src_port_mask = 0, /* Disable */
-		.proto = IPPROTO_SCTP,
-		.proto_mask = UINT8_MAX, /* 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 = UINT32_MAX, /* Enable */
-		.src_ip = 0,
-		.src_ip_mask = 0, /* Disable */
-		.dst_port = 0,
-		.dst_port_mask = 0, /* Disable */
-		.src_port = 0,
-		.src_port_mask = 0, /* Disable */
-		.proto = IPPROTO_SCTP,
-		.proto_mask = UINT8_MAX, /* 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);
-}
-
-static void
-app_link_set_arp_filter(struct app_params *app, struct app_link_params *cp)
-{
-	if (cp->arp_q != 0) {
-		int status = app_link_filter_arp_add(cp);
-
-		APP_LOG(app, LOW, "%s (%" PRIu32 "): "
-			"Adding ARP filter (queue = %" PRIu32 ")",
-			cp->name, cp->pmd_id, cp->arp_q);
-
-		if (status)
-			rte_panic("%s (%" PRIu32 "): "
-				"Error adding ARP filter "
-				"(queue = %" PRIu32 ") (%" PRId32 ")\n",
-				cp->name, cp->pmd_id, cp->arp_q, status);
-	}
-}
-
-static void
-app_link_set_tcp_syn_filter(struct app_params *app, struct app_link_params *cp)
-{
-	if (cp->tcp_syn_q != 0) {
-		int status = app_link_filter_tcp_syn_add(cp);
-
-		APP_LOG(app, LOW, "%s (%" PRIu32 "): "
-			"Adding TCP SYN filter (queue = %" PRIu32 ")",
-			cp->name, cp->pmd_id, cp->tcp_syn_q);
-
-		if (status)
-			rte_panic("%s (%" PRIu32 "): "
-				"Error adding TCP SYN filter "
-				"(queue = %" PRIu32 ") (%" PRId32 ")\n",
-				cp->name, cp->pmd_id, cp->tcp_syn_q,
-				status);
-	}
-}
-
-void
-app_link_up_internal(struct app_params *app, struct app_link_params *cp)
-{
-	uint32_t i;
-	int status;
-
-	/* For each link, add filters for IP of current link */
-	if (cp->ip != 0) {
-		for (i = 0; i < app->n_links; i++) {
-			struct app_link_params *p = &app->link_params[i];
-
-			/* IP */
-			if (p->ip_local_q != 0) {
-				int status = app_link_filter_ip_add(p, cp);
-
-				APP_LOG(app, LOW, "%s (%" PRIu32 "): "
-					"Adding IP filter (queue= %" PRIu32
-					", IP = 0x%08" PRIx32 ")",
-					p->name, p->pmd_id, p->ip_local_q,
-					cp->ip);
-
-				if (status)
-					rte_panic("%s (%" PRIu32 "): "
-						"Error adding IP "
-						"filter (queue= %" PRIu32 ", "
-						"IP = 0x%08" PRIx32
-						") (%" PRId32 ")\n",
-						p->name, p->pmd_id,
-						p->ip_local_q, cp->ip, status);
-			}
-
-			/* TCP */
-			if (p->tcp_local_q != 0) {
-				int status = app_link_filter_tcp_add(p, cp);
-
-				APP_LOG(app, LOW, "%s (%" PRIu32 "): "
-					"Adding TCP filter "
-					"(queue = %" PRIu32
-					", IP = 0x%08" PRIx32 ")",
-					p->name, p->pmd_id, p->tcp_local_q,
-					cp->ip);
-
-				if (status)
-					rte_panic("%s (%" PRIu32 "): "
-						"Error adding TCP "
-						"filter (queue = %" PRIu32 ", "
-						"IP = 0x%08" PRIx32
-						") (%" PRId32 ")\n",
-						p->name, p->pmd_id,
-						p->tcp_local_q, cp->ip, status);
-			}
-
-			/* UDP */
-			if (p->udp_local_q != 0) {
-				int status = app_link_filter_udp_add(p, cp);
-
-				APP_LOG(app, LOW, "%s (%" PRIu32 "): "
-					"Adding UDP filter "
-					"(queue = %" PRIu32
-					", IP = 0x%08" PRIx32 ")",
-					p->name, p->pmd_id, p->udp_local_q,
-					cp->ip);
-
-				if (status)
-					rte_panic("%s (%" PRIu32 "): "
-						"Error adding UDP "
-						"filter (queue = %" PRIu32 ", "
-						"IP = 0x%08" PRIx32
-						") (%" PRId32 ")\n",
-						p->name, p->pmd_id,
-						p->udp_local_q, cp->ip, status);
-			}
-
-			/* SCTP */
-			if (p->sctp_local_q != 0) {
-				int status = app_link_filter_sctp_add(p, cp);
-
-				APP_LOG(app, LOW, "%s (%" PRIu32
-					"): Adding SCTP filter "
-					"(queue = %" PRIu32
-					", IP = 0x%08" PRIx32 ")",
-					p->name, p->pmd_id, p->sctp_local_q,
-					cp->ip);
-
-				if (status)
-					rte_panic("%s (%" PRIu32 "): "
-						"Error adding SCTP "
-						"filter (queue = %" PRIu32 ", "
-						"IP = 0x%08" PRIx32
-						") (%" PRId32 ")\n",
-						p->name, p->pmd_id,
-						p->sctp_local_q, cp->ip,
-						status);
-			}
-		}
-	}
-
-	/* PMD link up */
-	status = rte_eth_dev_set_link_up(cp->pmd_id);
-	/* Do not panic if PMD does not provide link up functionality */
-	if (status < 0 && status != -ENOTSUP)
-		rte_panic("%s (%" PRIu32 "): PMD set link up error %"
-			PRId32 "\n", cp->name, cp->pmd_id, status);
-
-	/* Mark link as UP */
-	cp->state = 1;
-}
-
-void
-app_link_down_internal(struct app_params *app, struct app_link_params *cp)
-{
-	uint32_t i;
-	int status;
-
-	/* PMD link down */
-	status = rte_eth_dev_set_link_down(cp->pmd_id);
-	/* Do not panic if PMD does not provide link down functionality */
-	if (status < 0 && status != -ENOTSUP)
-		rte_panic("%s (%" PRIu32 "): PMD set link down error %"
-			PRId32 "\n", cp->name, cp->pmd_id, status);
-
-	/* Mark link as DOWN */
-	cp->state = 0;
-
-	/* Return if current link IP is not valid */
-	if (cp->ip == 0)
-		return;
-
-	/* For each link, remove filters for IP of current link */
-	for (i = 0; i < app->n_links; i++) {
-		struct app_link_params *p = &app->link_params[i];
-
-		/* IP */
-		if (p->ip_local_q != 0) {
-			int status = app_link_filter_ip_del(p, cp);
-
-			APP_LOG(app, LOW, "%s (%" PRIu32
-				"): Deleting IP filter "
-				"(queue = %" PRIu32 ", IP = 0x%" PRIx32 ")",
-				p->name, p->pmd_id, p->ip_local_q, cp->ip);
-
-			if (status)
-				rte_panic("%s (%" PRIu32
-					"): Error deleting IP filter "
-					"(queue = %" PRIu32
-					", IP = 0x%" PRIx32
-					") (%" PRId32 ")\n",
-					p->name, p->pmd_id, p->ip_local_q,
-					cp->ip, status);
-		}
-
-		/* TCP */
-		if (p->tcp_local_q != 0) {
-			int status = app_link_filter_tcp_del(p, cp);
-
-			APP_LOG(app, LOW, "%s (%" PRIu32
-				"): Deleting TCP filter "
-				"(queue = %" PRIu32
-				", IP = 0x%" PRIx32 ")",
-				p->name, p->pmd_id, p->tcp_local_q, cp->ip);
-
-			if (status)
-				rte_panic("%s (%" PRIu32
-					"): Error deleting TCP filter "
-					"(queue = %" PRIu32
-					", IP = 0x%" PRIx32
-					") (%" PRId32 ")\n",
-					p->name, p->pmd_id, p->tcp_local_q,
-					cp->ip, status);
-		}
-
-		/* UDP */
-		if (p->udp_local_q != 0) {
-			int status = app_link_filter_udp_del(p, cp);
-
-			APP_LOG(app, LOW, "%s (%" PRIu32
-				"): Deleting UDP filter "
-				"(queue = %" PRIu32 ", IP = 0x%" PRIx32 ")",
-				p->name, p->pmd_id, p->udp_local_q, cp->ip);
-
-			if (status)
-				rte_panic("%s (%" PRIu32
-					"): Error deleting UDP filter "
-					"(queue = %" PRIu32
-					", IP = 0x%" PRIx32
-					") (%" PRId32 ")\n",
-					p->name, p->pmd_id, p->udp_local_q,
-					cp->ip, status);
-		}
-
-		/* SCTP */
-		if (p->sctp_local_q != 0) {
-			int status = app_link_filter_sctp_del(p, cp);
-
-			APP_LOG(app, LOW, "%s (%" PRIu32
-				"): Deleting SCTP filter "
-				"(queue = %" PRIu32
-				", IP = 0x%" PRIx32 ")",
-				p->name, p->pmd_id, p->sctp_local_q, cp->ip);
-
-			if (status)
-				rte_panic("%s (%" PRIu32
-					"): Error deleting SCTP filter "
-					"(queue = %" PRIu32
-					", IP = 0x%" PRIx32
-					") (%" PRId32 ")\n",
-					p->name, p->pmd_id, p->sctp_local_q,
-					cp->ip, status);
-		}
-	}
-}
-
-static void
-app_check_link(struct app_params *app)
-{
-	uint32_t all_links_up, i;
-
-	all_links_up = 1;
-
-	for (i = 0; i < app->n_links; i++) {
-		struct app_link_params *p = &app->link_params[i];
-		struct rte_eth_link link_params;
-
-		memset(&link_params, 0, sizeof(link_params));
-		rte_eth_link_get(p->pmd_id, &link_params);
-
-		APP_LOG(app, HIGH, "%s (%" PRIu32 ") (%" PRIu32 " Gbps) %s",
-			p->name,
-			p->pmd_id,
-			link_params.link_speed / 1000,
-			link_params.link_status ? "UP" : "DOWN");
-
-		if (link_params.link_status == ETH_LINK_DOWN)
-			all_links_up = 0;
-	}
-
-	if (all_links_up == 0)
-		rte_panic("Some links are DOWN\n");
-}
-
-static uint32_t
-is_any_swq_frag_or_ras(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_pktq_swq; i++) {
-		struct app_pktq_swq_params *p = &app->swq_params[i];
-
-		if ((p->ipv4_frag == 1) || (p->ipv6_frag == 1) ||
-			(p->ipv4_ras == 1) || (p->ipv6_ras == 1))
-			return 1;
-	}
-
-	return 0;
-}
-
-static void
-app_init_link_frag_ras(struct app_params *app)
-{
-	uint32_t i;
-
-	if (is_any_swq_frag_or_ras(app)) {
-		for (i = 0; i < app->n_links; i++) {
-			struct app_link_params *p_link = &app->link_params[i];
-				p_link->conf.txmode.offloads |=
-						DEV_TX_OFFLOAD_MULTI_SEGS;
-		}
-	}
-}
-
-static inline int
-app_get_cpu_socket_id(uint32_t pmd_id)
-{
-	int status = rte_eth_dev_socket_id(pmd_id);
-
-	return (status != SOCKET_ID_ANY) ? status : 0;
-}
-
-static inline int
-app_link_rss_enabled(struct app_link_params *cp)
-{
-	return (cp->n_rss_qs) ? 1 : 0;
-}
-
-static void
-app_link_rss_setup(struct app_link_params *cp)
-{
-	struct rte_eth_dev_info dev_info;
-	struct rte_eth_rss_reta_entry64 reta_conf[APP_RETA_SIZE_MAX];
-	uint32_t i;
-	int status;
-
-    /* Get RETA size */
-	memset(&dev_info, 0, sizeof(dev_info));
-	rte_eth_dev_info_get(cp->pmd_id, &dev_info);
-
-	if (dev_info.reta_size == 0)
-		rte_panic("%s (%u): RSS setup error (null RETA size)\n",
-			cp->name, cp->pmd_id);
-
-	if (dev_info.reta_size > ETH_RSS_RETA_SIZE_512)
-		rte_panic("%s (%u): RSS setup error (RETA size too big)\n",
-			cp->name, cp->pmd_id);
-
-	/* Setup RETA contents */
-	memset(reta_conf, 0, sizeof(reta_conf));
-
-	for (i = 0; i < dev_info.reta_size; i++)
-		reta_conf[i / RTE_RETA_GROUP_SIZE].mask = UINT64_MAX;
-
-	for (i = 0; i < dev_info.reta_size; i++) {
-		uint32_t reta_id = i / RTE_RETA_GROUP_SIZE;
-		uint32_t reta_pos = i % RTE_RETA_GROUP_SIZE;
-		uint32_t rss_qs_pos = i % cp->n_rss_qs;
-
-		reta_conf[reta_id].reta[reta_pos] =
-			(uint16_t) cp->rss_qs[rss_qs_pos];
-	}
-
-	/* RETA update */
-	status = rte_eth_dev_rss_reta_update(cp->pmd_id,
-		reta_conf,
-		dev_info.reta_size);
-	if (status != 0)
-		rte_panic("%s (%u): RSS setup error (RETA update failed)\n",
-			cp->name, cp->pmd_id);
-}
-
-static void
-app_init_link_set_config(struct app_link_params *p)
-{
-	if (p->n_rss_qs) {
-		p->conf.rxmode.mq_mode = ETH_MQ_RX_RSS;
-		p->conf.rx_adv_conf.rss_conf.rss_hf = p->rss_proto_ipv4 |
-			p->rss_proto_ipv6 |
-			p->rss_proto_l2;
-	}
-}
-
-static void
-app_init_link(struct app_params *app)
-{
-	uint32_t i;
-
-	app_init_link_frag_ras(app);
-
-	for (i = 0; i < app->n_links; i++) {
-		struct app_link_params *p_link = &app->link_params[i];
-		struct rte_eth_dev_info dev_info;
-		uint32_t link_id, n_hwq_in, n_hwq_out, j;
-		int status;
-
-		sscanf(p_link->name, "LINK%" PRIu32, &link_id);
-		n_hwq_in = app_link_get_n_rxq(app, p_link);
-		n_hwq_out = app_link_get_n_txq(app, p_link);
-		app_init_link_set_config(p_link);
-
-		APP_LOG(app, HIGH, "Initializing %s (%" PRIu32") "
-			"(%" PRIu32 " RXQ, %" PRIu32 " TXQ) ...",
-			p_link->name,
-			p_link->pmd_id,
-			n_hwq_in,
-			n_hwq_out);
-
-		/* LINK */
-		rte_eth_dev_info_get(p_link->pmd_id, &dev_info);
-		if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE)
-			p_link->conf.txmode.offloads |=
-				DEV_TX_OFFLOAD_MBUF_FAST_FREE;
-		status = rte_eth_dev_configure(
-			p_link->pmd_id,
-			n_hwq_in,
-			n_hwq_out,
-			&p_link->conf);
-		if (status < 0)
-			rte_panic("%s (%" PRId32 "): "
-				"init error (%" PRId32 ")\n",
-				p_link->name, p_link->pmd_id, status);
-
-		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->n_pktq_hwq_in; j++) {
-			struct app_pktq_hwq_in_params *p_rxq =
-				&app->hwq_in_params[j];
-			uint32_t rxq_link_id, rxq_queue_id;
-			uint16_t nb_rxd = p_rxq->size;
-
-			sscanf(p_rxq->name, "RXQ%" PRIu32 ".%" PRIu32,
-				&rxq_link_id, &rxq_queue_id);
-			if (rxq_link_id != link_id)
-				continue;
-
-			status = rte_eth_dev_adjust_nb_rx_tx_desc(
-				p_link->pmd_id,
-				&nb_rxd,
-				NULL);
-			if (status < 0)
-				rte_panic("%s (%" PRIu32 "): "
-					"%s adjust number of Rx descriptors "
-					"error (%" PRId32 ")\n",
-					p_link->name,
-					p_link->pmd_id,
-					p_rxq->name,
-					status);
-
-			p_rxq->conf.offloads = p_link->conf.rxmode.offloads;
-			status = rte_eth_rx_queue_setup(
-				p_link->pmd_id,
-				rxq_queue_id,
-				nb_rxd,
-				app_get_cpu_socket_id(p_link->pmd_id),
-				&p_rxq->conf,
-				app->mempool[p_rxq->mempool_id]);
-			if (status < 0)
-				rte_panic("%s (%" PRIu32 "): "
-					"%s init error (%" PRId32 ")\n",
-					p_link->name,
-					p_link->pmd_id,
-					p_rxq->name,
-					status);
-		}
-
-		/* TXQ */
-		for (j = 0; j < app->n_pktq_hwq_out; j++) {
-			struct app_pktq_hwq_out_params *p_txq =
-				&app->hwq_out_params[j];
-			uint32_t txq_link_id, txq_queue_id;
-			uint16_t nb_txd = p_txq->size;
-
-			sscanf(p_txq->name, "TXQ%" PRIu32 ".%" PRIu32,
-				&txq_link_id, &txq_queue_id);
-			if (txq_link_id != link_id)
-				continue;
-
-			status = rte_eth_dev_adjust_nb_rx_tx_desc(
-				p_link->pmd_id,
-				NULL,
-				&nb_txd);
-			if (status < 0)
-				rte_panic("%s (%" PRIu32 "): "
-					"%s adjust number of Tx descriptors "
-					"error (%" PRId32 ")\n",
-					p_link->name,
-					p_link->pmd_id,
-					p_txq->name,
-					status);
-
-			p_txq->conf.offloads = p_link->conf.txmode.offloads;
-			status = rte_eth_tx_queue_setup(
-				p_link->pmd_id,
-				txq_queue_id,
-				nb_txd,
-				app_get_cpu_socket_id(p_link->pmd_id),
-				&p_txq->conf);
-			if (status < 0)
-				rte_panic("%s (%" PRIu32 "): "
-					"%s init error (%" PRId32 ")\n",
-					p_link->name,
-					p_link->pmd_id,
-					p_txq->name,
-					status);
-		}
-
-		/* LINK START */
-		status = rte_eth_dev_start(p_link->pmd_id);
-		if (status < 0)
-			rte_panic("Cannot start %s (error %" PRId32 ")\n",
-				p_link->name, status);
-
-		/* LINK FILTERS */
-		app_link_set_arp_filter(app, p_link);
-		app_link_set_tcp_syn_filter(app, p_link);
-		if (app_link_rss_enabled(p_link))
-			app_link_rss_setup(p_link);
-
-		/* LINK UP */
-		app_link_up_internal(app, p_link);
-	}
-
-	app_check_link(app);
-}
-
-static void
-app_init_swq(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_pktq_swq; i++) {
-		struct app_pktq_swq_params *p = &app->swq_params[i];
-		unsigned flags = 0;
-
-		if (app_swq_get_readers(app, p) == 1)
-			flags |= RING_F_SC_DEQ;
-		if (app_swq_get_writers(app, p) == 1)
-			flags |= RING_F_SP_ENQ;
-
-		APP_LOG(app, HIGH, "Initializing %s...", p->name);
-		app->swq[i] = rte_ring_create(
-				p->name,
-				p->size,
-				p->cpu_socket_id,
-				flags);
-
-		if (app->swq[i] == NULL)
-			rte_panic("%s init error\n", p->name);
-	}
-}
-
-static void
-app_init_tm(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_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;
-
-		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 =
-			app_get_cpu_socket_id(p_link->pmd_id);
-		p_tm->sched_port_params.rate =
-			(uint64_t) link_eth_params.link_speed * 1000 * 1000 / 8;
-
-		APP_LOG(app, HIGH, "Initializing %s ...", p_tm->name);
-		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 %" PRIu32
-					" init error (%" PRId32 ")\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 %" PRIu32
-						" pipe %" PRIu32
-						" (profile %" PRId32 ") "
-						"init error (% " PRId32 ")\n",
-						p_tm->name, subport_id, pipe_id,
-						profile_id, status);
-			}
-		}
-	}
-}
-
-#ifndef RTE_EXEC_ENV_LINUXAPP
-static void
-app_init_tap(struct app_params *app) {
-	if (app->n_pktq_tap == 0)
-		return;
-
-	rte_panic("TAP device not supported.\n");
-}
-#else
-static void
-app_init_tap(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_pktq_tap; i++) {
-		struct app_pktq_tap_params *p_tap = &app->tap_params[i];
-		struct ifreq ifr;
-		int fd, status;
-
-		APP_LOG(app, HIGH, "Initializing %s ...", p_tap->name);
-
-		fd = open("/dev/net/tun", O_RDWR | O_NONBLOCK);
-		if (fd < 0)
-			rte_panic("Cannot open file /dev/net/tun\n");
-
-		memset(&ifr, 0, sizeof(ifr));
-		ifr.ifr_flags = IFF_TAP | IFF_NO_PI; /* No packet information */
-		snprintf(ifr.ifr_name, IFNAMSIZ, "%s", p_tap->name);
-
-		status = ioctl(fd, TUNSETIFF, (void *) &ifr);
-		if (status < 0)
-			rte_panic("TAP setup error\n");
-
-		app->tap[i] = fd;
-	}
-}
-#endif
-
-#ifdef RTE_LIBRTE_KNI
-static int
-kni_config_network_interface(uint16_t port_id, uint8_t if_up) {
-	int ret = 0;
-
-	if (port_id >= rte_eth_dev_count())
-		return -EINVAL;
-
-	ret = (if_up) ?
-		rte_eth_dev_set_link_up(port_id) :
-		rte_eth_dev_set_link_down(port_id);
-
-	return ret;
-}
-
-static int
-kni_change_mtu(uint16_t port_id, unsigned int new_mtu) {
-	int ret;
-
-	if (port_id >= rte_eth_dev_count())
-		return -EINVAL;
-
-	if (new_mtu > ETHER_MAX_LEN)
-		return -EINVAL;
-
-	/* Set new MTU */
-	ret = rte_eth_dev_set_mtu(port_id, new_mtu);
-	if (ret < 0)
-		return ret;
-
-	return 0;
-}
-#endif /* RTE_LIBRTE_KNI */
-
-#ifndef RTE_LIBRTE_KNI
-static void
-app_init_kni(struct app_params *app) {
-	if (app->n_pktq_kni == 0)
-		return;
-
-	rte_panic("Can not init KNI without librte_kni support.\n");
-}
-#else
-static void
-app_init_kni(struct app_params *app) {
-	uint32_t i;
-
-	if (app->n_pktq_kni == 0)
-		return;
-
-	rte_kni_init(app->n_pktq_kni);
-
-	for (i = 0; i < app->n_pktq_kni; i++) {
-		struct app_pktq_kni_params *p_kni = &app->kni_params[i];
-		struct app_link_params *p_link;
-		struct rte_eth_dev_info dev_info;
-		struct app_mempool_params *mempool_params;
-		struct rte_mempool *mempool;
-		struct rte_kni_conf conf;
-		struct rte_kni_ops ops;
-
-		/* LINK */
-		p_link = app_get_link_for_kni(app, p_kni);
-		memset(&dev_info, 0, sizeof(dev_info));
-		rte_eth_dev_info_get(p_link->pmd_id, &dev_info);
-
-		/* MEMPOOL */
-		mempool_params = &app->mempool_params[p_kni->mempool_id];
-		mempool = app->mempool[p_kni->mempool_id];
-
-		/* KNI */
-		memset(&conf, 0, sizeof(conf));
-		snprintf(conf.name, RTE_KNI_NAMESIZE, "%s", p_kni->name);
-		conf.force_bind = p_kni->force_bind;
-		if (conf.force_bind) {
-			int lcore_id;
-
-			lcore_id = cpu_core_map_get_lcore_id(app->core_map,
-				p_kni->socket_id,
-				p_kni->core_id,
-				p_kni->hyper_th_id);
-
-			if (lcore_id < 0)
-				rte_panic("%s invalid CPU core\n", p_kni->name);
-
-			conf.core_id = (uint32_t) lcore_id;
-		}
-		conf.group_id = p_link->pmd_id;
-		conf.mbuf_size = mempool_params->buffer_size;
-		conf.addr = dev_info.pci_dev->addr;
-		conf.id = dev_info.pci_dev->id;
-
-		memset(&ops, 0, sizeof(ops));
-		ops.port_id = (uint8_t) p_link->pmd_id;
-		ops.change_mtu = kni_change_mtu;
-		ops.config_network_if = kni_config_network_interface;
-
-		APP_LOG(app, HIGH, "Initializing %s ...", p_kni->name);
-		app->kni[i] = rte_kni_alloc(mempool, &conf, &ops);
-		if (!app->kni[i])
-			rte_panic("%s init error\n", p_kni->name);
-	}
-}
-#endif /* RTE_LIBRTE_KNI */
-
-static void
-app_init_msgq(struct app_params *app)
-{
-	uint32_t i;
-
-	for (i = 0; i < app->n_msgq; i++) {
-		struct app_msgq_params *p = &app->msgq_params[i];
-
-		APP_LOG(app, HIGH, "Initializing %s ...", 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);
-	}
-}
-
-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_tap(app);
-	app_init_kni(app);
-	app_init_msgq(app);
-
-	return 0;
-}
diff --git a/examples/ip_pipeline/main.c b/examples/ip_pipeline/main.c
index a44cf9a..1696e36 100644
--- a/examples/ip_pipeline/main.c
+++ b/examples/ip_pipeline/main.c
@@ -2,34 +2,24 @@
  * Copyright(c) 2010-2015 Intel Corporation
  */
 
-#include "app.h"
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <getopt.h>
 
-static struct app_params app;
+#include <rte_eal.h>
 
 int
 main(int argc, char **argv)
 {
-	rte_openlog_stream(stderr);
+	int status;
 
-	/* Config */
-	app_config_init(&app);
+	/* EAL */
+	status = rte_eal_init(argc, argv);
+	if (status < 0) {
+		printf("Error: EAL initialization failed (%d)\n", status);
+		return status;
+	};
 
-	app_config_args(&app, argc, argv);
-
-	app_config_preproc(&app);
-
-	app_config_parse(&app, app.parser_file);
-
-	app_config_check(&app);
-
-	/* 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/meson.build b/examples/ip_pipeline/meson.build
index be3f3e5..063865c 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -1,19 +1,13 @@
 # SPDX-License-Identifier: BSD-3-Clause
-# Copyright(c) 2017 Intel Corporation
+# Copyright(c) 2017-2018 Intel Corporation
 
 # meson file, for building this example as part of a main DPDK build.
 #
 # To build this example as a standalone application with an already-installed
 # DPDK instance, use 'make'
 
-deps += ['cfgfile', 'bus_pci']
+deps += ['pipeline', 'bus_pci']
 sources = files(
-	'config_check.c',
-	'config_parse.c',
-	'config_parse_tm.c',
-	'cpu_core_map.c',
-	'init.c',
 	'main.c',
 	'parser.c',
-	'thread.c',
 )
diff --git a/examples/ip_pipeline/parser.c b/examples/ip_pipeline/parser.c
index 0901e9c..0ae3d1d 100644
--- a/examples/ip_pipeline/parser.c
+++ b/examples/ip_pipeline/parser.c
@@ -39,7 +39,6 @@
 #include <rte_cfgfile.h>
 #include <rte_string_fns.h>
 
-#include "app.h"
 #include "parser.h"
 
 static uint32_t
@@ -596,10 +595,8 @@ parse_mac_addr(const char *token, struct ether_addr *addr)
 }
 
 int
-parse_pipeline_core(uint32_t *socket,
-	uint32_t *core,
-	uint32_t *ht,
-	const char *entry)
+parse_cpu_core(const char *entry,
+	struct cpu_core_params *p)
 {
 	size_t num_len;
 	char num[8];
@@ -609,6 +606,9 @@ parse_pipeline_core(uint32_t *socket,
 	const char *next = skip_white_spaces(entry);
 	char type;
 
+	if (p == NULL)
+		return -EINVAL;
+
 	/* Expect <CORE> or [sX][cY][h]. At least one parameter is required. */
 	while (*next != '\0') {
 		/* If everything parsed nothing should left */
@@ -682,8 +682,8 @@ parse_pipeline_core(uint32_t *socket,
 		}
 	}
 
-	*socket = s;
-	*core = c;
-	*ht = h;
+	p->socket_id = s;
+	p->core_id = c;
+	p->thread_id = h;
 	return 0;
 }
diff --git a/examples/ip_pipeline/parser.h b/examples/ip_pipeline/parser.h
index 5c421d2..261a8c8 100644
--- a/examples/ip_pipeline/parser.h
+++ b/examples/ip_pipeline/parser.h
@@ -50,6 +50,14 @@ int parse_ipv6_addr(const char *token, struct in6_addr *ipv6);
 int parse_mac_addr(const char *token, struct ether_addr *addr);
 int parse_mpls_labels(char *string, uint32_t *labels, uint32_t *n_labels);
 
+struct cpu_core_params {
+	uint32_t socket_id;
+	uint32_t core_id;
+	uint32_t thread_id;
+};
+
+int parse_cpu_core(const char *entry, struct cpu_core_params *p);
+
 int parse_tokenize_string(char *string, char *tokens[], uint32_t *n_tokens);
 
 #endif
diff --git a/examples/ip_pipeline/pipeline.h b/examples/ip_pipeline/pipeline.h
deleted file mode 100644
index 7ca9cad..0000000
--- a/examples/ip_pipeline/pipeline.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#ifndef __INCLUDE_PIPELINE_H__
-#define __INCLUDE_PIPELINE_H__
-
-#include <cmdline_parse.h>
-
-#include "pipeline_be.h"
-
-/*
- * Pipeline type front-end operations
- */
-
-typedef void* (*pipeline_fe_op_init)(struct pipeline_params *params,
-	void *arg);
-
-typedef int (*pipeline_fe_op_post_init)(void *pipeline);
-
-typedef int (*pipeline_fe_op_free)(void *pipeline);
-
-typedef int (*pipeline_fe_op_track)(struct pipeline_params *params,
-	uint32_t port_in,
-	uint32_t *port_out);
-
-struct pipeline_fe_ops {
-	pipeline_fe_op_init f_init;
-	pipeline_fe_op_post_init f_post_init;
-	pipeline_fe_op_free f_free;
-	pipeline_fe_op_track f_track;
-	cmdline_parse_ctx_t *cmds;
-};
-
-/*
- * Pipeline type
- */
-
-struct pipeline_type {
-	const char *name;
-
-	/* pipeline back-end */
-	struct pipeline_be_ops *be_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;
-}
-
-int
-parse_pipeline_core(uint32_t *socket,
-	uint32_t *core,
-	uint32_t *ht,
-	const char *entry);
-
-#endif
diff --git a/examples/ip_pipeline/pipeline_be.h b/examples/ip_pipeline/pipeline_be.h
deleted file mode 100644
index 6c0c97a..0000000
--- a/examples/ip_pipeline/pipeline_be.h
+++ /dev/null
@@ -1,322 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2016 Intel Corporation
- */
-
-#ifndef __INCLUDE_PIPELINE_BE_H__
-#define __INCLUDE_PIPELINE_BE_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_fd.h>
-#include <rte_port_source_sink.h>
-#ifdef RTE_LIBRTE_KNI
-#include <rte_port_kni.h>
-#endif
-#include <rte_pipeline.h>
-
-enum pipeline_port_in_type {
-	PIPELINE_PORT_IN_ETHDEV_READER,
-	PIPELINE_PORT_IN_RING_READER,
-	PIPELINE_PORT_IN_RING_MULTI_READER,
-	PIPELINE_PORT_IN_RING_READER_IPV4_FRAG,
-	PIPELINE_PORT_IN_RING_READER_IPV6_FRAG,
-	PIPELINE_PORT_IN_SCHED_READER,
-	PIPELINE_PORT_IN_FD_READER,
-	PIPELINE_PORT_IN_KNI_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_multi_reader_params ring_multi;
-		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_fd_reader_params fd;
-#ifdef RTE_LIBRTE_KNI
-		struct rte_port_kni_reader_params kni;
-#endif
-		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_MULTI_READER:
-		return (void *) &p->params.ring_multi;
-	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_FD_READER:
-		return (void *) &p->params.fd;
-#ifdef RTE_LIBRTE_KNI
-	case PIPELINE_PORT_IN_KNI_READER:
-		return (void *) &p->params.kni;
-#endif
-	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_MULTI_READER:
-		return &rte_port_ring_multi_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_FD_READER:
-		return &rte_port_fd_reader_ops;
-#ifdef RTE_LIBRTE_KNI
-	case PIPELINE_PORT_IN_KNI_READER:
-		return &rte_port_kni_reader_ops;
-#endif
-	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_MULTI_WRITER,
-	PIPELINE_PORT_OUT_RING_WRITER_NODROP,
-	PIPELINE_PORT_OUT_RING_MULTI_WRITER_NODROP,
-	PIPELINE_PORT_OUT_RING_WRITER_IPV4_RAS,
-	PIPELINE_PORT_OUT_RING_WRITER_IPV6_RAS,
-	PIPELINE_PORT_OUT_SCHED_WRITER,
-	PIPELINE_PORT_OUT_FD_WRITER,
-	PIPELINE_PORT_OUT_KNI_WRITER,
-	PIPELINE_PORT_OUT_KNI_WRITER_NODROP,
-	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_multi_writer_params ring_multi;
-		struct rte_port_ring_writer_nodrop_params ring_nodrop;
-		struct rte_port_ring_multi_writer_nodrop_params ring_multi_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;
-		struct rte_port_fd_writer_params fd;
-#ifdef RTE_LIBRTE_KNI
-		struct rte_port_kni_writer_params kni;
-		struct rte_port_kni_writer_nodrop_params kni_nodrop;
-#endif
-		struct rte_port_sink_params sink;
-	} 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_MULTI_WRITER:
-		return (void *) &p->params.ring_multi;
-	case PIPELINE_PORT_OUT_RING_WRITER_NODROP:
-		return (void *) &p->params.ring_nodrop;
-	case PIPELINE_PORT_OUT_RING_MULTI_WRITER_NODROP:
-		return (void *) &p->params.ring_multi_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_FD_WRITER:
-		return (void *) &p->params.fd;
-#ifdef RTE_LIBRTE_KNI
-	case PIPELINE_PORT_OUT_KNI_WRITER:
-		return (void *) &p->params.kni;
-	case PIPELINE_PORT_OUT_KNI_WRITER_NODROP:
-		return (void *) &p->params.kni_nodrop;
-#endif
-	case PIPELINE_PORT_OUT_SINK:
-		return (void *) &p->params.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_MULTI_WRITER:
-		return &rte_port_ring_multi_writer_ops;
-	case PIPELINE_PORT_OUT_RING_WRITER_NODROP:
-		return &rte_port_ring_writer_nodrop_ops;
-	case PIPELINE_PORT_OUT_RING_MULTI_WRITER_NODROP:
-		return &rte_port_ring_multi_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_FD_WRITER:
-		return &rte_port_fd_writer_ops;
-#ifdef RTE_LIBRTE_KNI
-	case PIPELINE_PORT_OUT_KNI_WRITER:
-		return &rte_port_kni_writer_ops;
-	case PIPELINE_PORT_OUT_KNI_WRITER_NODROP:
-		return &rte_port_kni_writer_nodrop_ops;
-#endif
-	case PIPELINE_PORT_OUT_SINK:
-		return &rte_port_sink_ops;
-	default:
-		return NULL;
-	}
-}
-
-#ifndef PIPELINE_NAME_SIZE
-#define PIPELINE_NAME_SIZE                       64
-#endif
-
-#ifndef PIPELINE_TYPE_SIZE
-#define PIPELINE_TYPE_SIZE                       64
-#endif
-
-#ifndef PIPELINE_MAX_PORT_IN
-#define PIPELINE_MAX_PORT_IN                     64
-#endif
-
-#ifndef PIPELINE_MAX_PORT_OUT
-#define PIPELINE_MAX_PORT_OUT                    64
-#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                        64
-#endif
-
-struct pipeline_params {
-	char name[PIPELINE_NAME_SIZE];
-	char type[PIPELINE_TYPE_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;
-
-	uint32_t log_level;
-};
-
-/*
- * Pipeline type back-end operations
- */
-
-typedef void* (*pipeline_be_op_init)(struct pipeline_params *params,
-	void *arg);
-
-typedef int (*pipeline_be_op_free)(void *pipeline);
-
-typedef int (*pipeline_be_op_run)(void *pipeline);
-
-typedef int (*pipeline_be_op_timer)(void *pipeline);
-
-struct pipeline_be_ops {
-	pipeline_be_op_init f_init;
-	pipeline_be_op_free f_free;
-	pipeline_be_op_run f_run;
-	pipeline_be_op_timer f_timer;
-};
-
-/* Pipeline specific config parse error messages */
-#define PIPELINE_ARG_CHECK(exp, fmt, ...)				\
-do {									\
-	if (!(exp)) {							\
-		fprintf(stderr, fmt "\n", ## __VA_ARGS__);		\
-		return -1;						\
-	}								\
-} while (0)
-
-#define PIPELINE_PARSE_ERR_INV_VAL(exp, section, entry, val)		\
-PIPELINE_ARG_CHECK(exp, "Parse error in section \"%s\": entry \"%s\" "	\
-	"has invalid value (\"%s\")", section, entry, val)
-
-#define PIPELINE_PARSE_ERR_OUT_RNG(exp, section, entry, val)		\
-PIPELINE_ARG_CHECK(exp, "Parse error in section \"%s\": entry \"%s\" "	\
-	"value is out of range (\"%s\")", section, entry, val)
-
-#define PIPELINE_PARSE_ERR_DUPLICATE(exp, section, entry)		\
-PIPELINE_ARG_CHECK(exp, "Parse error in section \"%s\": duplicated "	\
-	"entry \"%s\"", section, entry)
-
-#define PIPELINE_PARSE_ERR_INV_ENT(exp, section, entry)			\
-PIPELINE_ARG_CHECK(exp, "Parse error in section \"%s\": invalid entry "	\
-	"\"%s\"", section, entry)
-
-#define PIPELINE_PARSE_ERR_MANDATORY(exp, section, entry)		\
-PIPELINE_ARG_CHECK(exp, "Parse error in section \"%s\": mandatory "	\
-	"entry \"%s\" is missing", section, entry)
-
-#endif
diff --git a/examples/ip_pipeline/thread.c b/examples/ip_pipeline/thread.c
deleted file mode 100644
index a36bf92..0000000
--- a/examples/ip_pipeline/thread.c
+++ /dev/null
@@ -1,240 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#include <rte_common.h>
-#include <rte_cycles.h>
-#include <rte_pipeline.h>
-
-#include "app.h"
-#include "thread.h"
-
-static inline void *
-thread_msg_recv(struct rte_ring *r)
-{
-	void *msg;
-	int status = rte_ring_sc_dequeue(r, &msg);
-
-	if (status != 0)
-		return NULL;
-
-	return msg;
-}
-
-static inline void
-thread_msg_send(struct rte_ring *r,
-	void *msg)
-{
-	int status;
-
-	do {
-		status = rte_ring_sp_enqueue(r, msg);
-	} while (status == -ENOBUFS);
-}
-
-static int
-thread_pipeline_enable(struct app_thread_data *t,
-		struct thread_pipeline_enable_msg_req *req)
-{
-	struct app_thread_pipeline_data *p;
-
-	if (req->f_run == NULL) {
-		if (t->n_regular >= APP_MAX_THREAD_PIPELINES)
-			return -1;
-	} else {
-		if (t->n_custom >= APP_MAX_THREAD_PIPELINES)
-			return -1;
-	}
-
-	p = (req->f_run == NULL) ?
-		&t->regular[t->n_regular] :
-		&t->custom[t->n_custom];
-
-	p->pipeline_id = req->pipeline_id;
-	p->be = req->be;
-	p->f_run = req->f_run;
-	p->f_timer = req->f_timer;
-	p->timer_period = req->timer_period;
-	p->deadline = 0;
-
-	if (req->f_run == NULL)
-		t->n_regular++;
-	else
-		t->n_custom++;
-
-	return 0;
-}
-
-static int
-thread_pipeline_disable(struct app_thread_data *t,
-		struct thread_pipeline_disable_msg_req *req)
-{
-	uint32_t n_regular = RTE_MIN(t->n_regular, RTE_DIM(t->regular));
-	uint32_t n_custom = RTE_MIN(t->n_custom, RTE_DIM(t->custom));
-	uint32_t i;
-
-	/* search regular pipelines of current thread */
-	for (i = 0; i < n_regular; i++) {
-		if (t->regular[i].pipeline_id != req->pipeline_id)
-			continue;
-
-		if (i < n_regular - 1)
-			memcpy(&t->regular[i],
-			  &t->regular[i+1],
-			  (n_regular - 1 - i) * sizeof(struct app_thread_pipeline_data));
-
-		n_regular--;
-		t->n_regular = n_regular;
-
-		return 0;
-	}
-
-	/* search custom pipelines of current thread */
-	for (i = 0; i < n_custom; i++) {
-		if (t->custom[i].pipeline_id != req->pipeline_id)
-			continue;
-
-		if (i < n_custom - 1)
-			memcpy(&t->custom[i],
-			  &t->custom[i+1],
-			  (n_custom - 1 - i) * sizeof(struct app_thread_pipeline_data));
-
-		n_custom--;
-		t->n_custom = n_custom;
-
-		return 0;
-	}
-
-	/* return if pipeline not found */
-	return -1;
-}
-
-static int
-thread_msg_req_handle(struct app_thread_data *t)
-{
-	void *msg_ptr;
-	struct thread_msg_req *req;
-	struct thread_msg_rsp *rsp;
-
-	msg_ptr = thread_msg_recv(t->msgq_in);
-	req = msg_ptr;
-	rsp = msg_ptr;
-
-	if (req != NULL)
-		switch (req->type) {
-		case THREAD_MSG_REQ_PIPELINE_ENABLE: {
-			rsp->status = thread_pipeline_enable(t,
-					(struct thread_pipeline_enable_msg_req *) req);
-			thread_msg_send(t->msgq_out, rsp);
-			break;
-		}
-
-		case THREAD_MSG_REQ_PIPELINE_DISABLE: {
-			rsp->status = thread_pipeline_disable(t,
-					(struct thread_pipeline_disable_msg_req *) req);
-			thread_msg_send(t->msgq_out, rsp);
-			break;
-		}
-
-		case THREAD_MSG_REQ_HEADROOM_READ: {
-			struct thread_headroom_read_msg_rsp *rsp =
-				(struct thread_headroom_read_msg_rsp *)
-				req;
-
-			rsp->headroom_ratio = t->headroom_ratio;
-			rsp->status = 0;
-			thread_msg_send(t->msgq_out, rsp);
-			break;
-		}
-		default:
-			break;
-		}
-
-	return 0;
-}
-
-static void
-thread_headroom_update(struct app_thread_data *t, uint64_t time)
-{
-	uint64_t time_diff = time - t->headroom_time;
-
-	t->headroom_ratio =
-		((double) t->headroom_cycles) / ((double) time_diff);
-
-	t->headroom_cycles = 0;
-	t->headroom_time = rte_rdtsc_precise();
-}
-
-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++) {
-		uint32_t n_regular = RTE_MIN(t->n_regular, RTE_DIM(t->regular));
-		uint32_t n_custom = RTE_MIN(t->n_custom, RTE_DIM(t->custom));
-
-		/* 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 < 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 < 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;
-			}
-
-			/* Timer for thread message request */
-			{
-				uint64_t deadline = t->thread_req_deadline;
-
-				if (deadline <= time) {
-					thread_msg_req_handle(t);
-					thread_headroom_update(t, time);
-					deadline = time + t->timer_period;
-					t->thread_req_deadline = deadline;
-				}
-
-				if (deadline < t_deadline)
-					t_deadline = deadline;
-			}
-
-
-			t->deadline = t_deadline;
-		}
-	}
-
-	return 0;
-}
diff --git a/examples/ip_pipeline/thread.h b/examples/ip_pipeline/thread.h
deleted file mode 100644
index 2c4fb6a..0000000
--- a/examples/ip_pipeline/thread.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
- */
-
-#ifndef THREAD_H_
-#define THREAD_H_
-
-#include "app.h"
-#include "pipeline_be.h"
-
-enum thread_msg_req_type {
-	THREAD_MSG_REQ_PIPELINE_ENABLE = 0,
-	THREAD_MSG_REQ_PIPELINE_DISABLE,
-	THREAD_MSG_REQ_HEADROOM_READ,
-	THREAD_MSG_REQS
-};
-
-struct thread_msg_req {
-	enum thread_msg_req_type type;
-};
-
-struct thread_msg_rsp {
-	int status;
-};
-
-/*
- * PIPELINE ENABLE
- */
-struct thread_pipeline_enable_msg_req {
-	enum thread_msg_req_type type;
-
-	uint32_t pipeline_id;
-	void *be;
-	pipeline_be_op_run f_run;
-	pipeline_be_op_timer f_timer;
-	uint64_t timer_period;
-};
-
-struct thread_pipeline_enable_msg_rsp {
-	int status;
-};
-
-/*
- * PIPELINE DISABLE
- */
-struct thread_pipeline_disable_msg_req {
-	enum thread_msg_req_type type;
-
-	uint32_t pipeline_id;
-};
-
-struct thread_pipeline_disable_msg_rsp {
-	int status;
-};
-
-/*
- * THREAD HEADROOM
- */
-struct thread_headroom_read_msg_req {
-	enum thread_msg_req_type type;
-};
-
-struct thread_headroom_read_msg_rsp {
-	int status;
-
-	double headroom_ratio;
-};
-
-#endif /* THREAD_H_ */
-- 
2.9.3

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

* [dpdk-dev] [PATCH v4 21/49] ip_pipeline: add cli interface
  2018-03-29 18:31           ` [dpdk-dev] [PATCH v4 00/49] ip_pipeline: refactoring Jasvinder Singh
                               ` (19 preceding siblings ...)
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 20/49] ip_pipeline: rework and improvements Jasvinder Singh
@ 2018-03-29 18:31             ` Jasvinder Singh
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 22/49] ip_pipeline: add mempool object for pipeline Jasvinder Singh
                               ` (28 subsequent siblings)
  49 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-29 18:31 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

CLI interface allowing connectivity with external agent(e.g. telnet,
netcat, Python script, etc) is added to the application.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/Makefile    |   4 +-
 examples/ip_pipeline/cli.c       |  86 +++++++++++
 examples/ip_pipeline/cli.h       |  18 +++
 examples/ip_pipeline/conn.c      | 326 +++++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/conn.h      |  47 ++++++
 examples/ip_pipeline/main.c      | 151 +++++++++++++++++-
 examples/ip_pipeline/meson.build |   2 +
 7 files changed, 632 insertions(+), 2 deletions(-)
 create mode 100644 examples/ip_pipeline/cli.c
 create mode 100644 examples/ip_pipeline/cli.h
 create mode 100644 examples/ip_pipeline/conn.c
 create mode 100644 examples/ip_pipeline/conn.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index 981c4f7..0c5b6b1 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -5,7 +5,9 @@
 APP = ip_pipeline
 
 # all source are stored in SRCS-y
-SRCS-y := main.c
+SRCS-y := cli.c
+SRCS-y += conn.c
+SRCS-y += main.c
 SRCS-y += parser.c
 #SRCS-y += thread.c
 
diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
new file mode 100644
index 0000000..34ada83
--- /dev/null
+++ b/examples/ip_pipeline/cli.c
@@ -0,0 +1,86 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <rte_common.h>
+
+#include "cli.h"
+
+static int
+is_comment(char *in)
+{
+	if ((strlen(in) && index("!#%;", in[0])) ||
+		(strncmp(in, "//", 2) == 0) ||
+		(strncmp(in, "--", 2) == 0))
+		return 1;
+
+	return 0;
+}
+
+void
+cli_process(char *in, char *out __rte_unused, size_t out_size __rte_unused)
+{
+	if (is_comment(in))
+		return;
+
+}
+
+int
+cli_script_process(const char *file_name,
+	size_t msg_in_len_max,
+	size_t msg_out_len_max)
+{
+	char *msg_in = NULL, *msg_out = NULL;
+	FILE *f = NULL;
+
+	/* Check input arguments */
+	if ((file_name == NULL) ||
+		(strlen(file_name) == 0) ||
+		(msg_in_len_max == 0) ||
+		(msg_out_len_max == 0))
+		return -EINVAL;
+
+	msg_in = malloc(msg_in_len_max + 1);
+	msg_out = malloc(msg_out_len_max + 1);
+	if ((msg_in == NULL) ||
+		(msg_out == NULL)) {
+		free(msg_out);
+		free(msg_in);
+		return -ENOMEM;
+	}
+
+	/* Open input file */
+	f = fopen(file_name, "r");
+	if (f == NULL) {
+		free(msg_out);
+		free(msg_in);
+		return -EIO;
+	}
+
+	/* Read file */
+	for ( ; ; ) {
+		if (fgets(msg_in, msg_in_len_max + 1, f) == NULL)
+			break;
+
+		printf("%s", msg_in);
+		msg_out[0] = 0;
+
+		cli_process(msg_in,
+			msg_out,
+			msg_out_len_max);
+
+		if (strlen(msg_out))
+			printf("%s", msg_out);
+	}
+
+	/* Close file */
+	fclose(f);
+	free(msg_out);
+	free(msg_in);
+	return 0;
+}
diff --git a/examples/ip_pipeline/cli.h b/examples/ip_pipeline/cli.h
new file mode 100644
index 0000000..992e4c3
--- /dev/null
+++ b/examples/ip_pipeline/cli.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#ifndef __INCLUDE_CLI_H__
+#define __INCLUDE_CLI_H__
+
+#include <stddef.h>
+
+void
+cli_process(char *in, char *out, size_t out_size);
+
+int
+cli_script_process(const char *file_name,
+	size_t msg_in_len_max,
+	size_t msg_out_len_max);
+
+#endif
diff --git a/examples/ip_pipeline/conn.c b/examples/ip_pipeline/conn.c
new file mode 100644
index 0000000..2a9fa15
--- /dev/null
+++ b/examples/ip_pipeline/conn.c
@@ -0,0 +1,326 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+#define __USE_GNU
+#include <sys/socket.h>
+
+#include <sys/epoll.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <errno.h>
+
+#include "conn.h"
+
+#define MSG_CMD_TOO_LONG "Command too long."
+
+struct conn {
+	char *welcome;
+	char *prompt;
+	char *buf;
+	char *msg_in;
+	char *msg_out;
+	size_t buf_size;
+	size_t msg_in_len_max;
+	size_t msg_out_len_max;
+	size_t msg_in_len;
+	int fd_server;
+	int fd_client_group;
+	conn_msg_handle_t msg_handle;
+};
+
+struct conn *
+conn_init(struct conn_params *p)
+{
+	struct sockaddr_in server_address;
+	struct conn *conn;
+	int fd_server, fd_client_group, status;
+
+	memset(&server_address, 0, sizeof(server_address));
+
+	/* Check input arguments */
+	if ((p == NULL) ||
+		(p->welcome == NULL) ||
+		(p->prompt == NULL) ||
+		(p->addr == NULL) ||
+		(p->buf_size == 0) ||
+		(p->msg_in_len_max == 0) ||
+		(p->msg_out_len_max == 0) ||
+		(p->msg_handle == NULL))
+		return NULL;
+
+	status = inet_aton(p->addr, &server_address.sin_addr);
+	if (status == 0)
+		return NULL;
+
+	/* Memory allocation */
+	conn = calloc(1, sizeof(struct conn));
+	if (conn == NULL)
+		return NULL;
+
+	conn->welcome = calloc(1, CONN_WELCOME_LEN_MAX + 1);
+	conn->prompt = calloc(1, CONN_PROMPT_LEN_MAX + 1);
+	conn->buf = calloc(1, p->buf_size);
+	conn->msg_in = calloc(1, p->msg_in_len_max + 1);
+	conn->msg_out = calloc(1, p->msg_out_len_max + 1);
+
+	if ((conn->welcome == NULL) ||
+		(conn->prompt == NULL) ||
+		(conn->buf == NULL) ||
+		(conn->msg_in == NULL) ||
+		(conn->msg_out == NULL)) {
+		conn_free(conn);
+		return NULL;
+	}
+
+	/* Server socket */
+	server_address.sin_family = AF_INET;
+	server_address.sin_port = htons(p->port);
+
+	fd_server = socket(AF_INET,
+		SOCK_STREAM | SOCK_NONBLOCK,
+		0);
+	if (fd_server == -1) {
+		conn_free(conn);
+		return NULL;
+	}
+
+	status = bind(fd_server,
+		(struct sockaddr *) &server_address,
+		sizeof(server_address));
+	if (status == -1) {
+		conn_free(conn);
+		return NULL;
+	}
+
+	status = listen(fd_server, 16);
+	if (status == -1) {
+		conn_free(conn);
+		return NULL;
+	}
+
+	/* Client group */
+	fd_client_group = epoll_create(1);
+	if (fd_client_group == -1) {
+		conn_free(conn);
+		return NULL;
+	}
+
+	/* Fill in */
+	strncpy(conn->welcome, p->welcome, CONN_WELCOME_LEN_MAX);
+	strncpy(conn->prompt, p->prompt, CONN_PROMPT_LEN_MAX);
+	conn->buf_size = p->buf_size;
+	conn->msg_in_len_max = p->msg_in_len_max;
+	conn->msg_out_len_max = p->msg_out_len_max;
+	conn->msg_in_len = 0;
+	conn->fd_server = fd_server;
+	conn->fd_client_group = fd_client_group;
+	conn->msg_handle = p->msg_handle;
+
+	return conn;
+}
+
+void
+conn_free(struct conn *conn)
+{
+	if (conn == NULL)
+		return;
+
+	if (conn->fd_client_group)
+		close(conn->fd_client_group);
+
+	if (conn->fd_server)
+		close(conn->fd_server);
+
+	free(conn->msg_out);
+	free(conn->msg_in);
+	free(conn->prompt);
+	free(conn->welcome);
+	free(conn);
+}
+
+int
+conn_poll_for_conn(struct conn *conn)
+{
+	struct sockaddr_in client_address;
+	struct epoll_event event;
+	socklen_t client_address_length;
+	int fd_client, status;
+
+	/* Check input arguments */
+	if (conn == NULL)
+		return -1;
+
+	/* Server socket */
+	client_address_length = sizeof(client_address);
+	fd_client = accept4(conn->fd_server,
+		(struct sockaddr *) &client_address,
+		&client_address_length,
+		SOCK_NONBLOCK);
+	if (fd_client == -1) {
+		if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
+			return 0;
+
+		return -1;
+	}
+
+	/* Client group */
+	event.events = EPOLLIN | EPOLLRDHUP | EPOLLHUP;
+	event.data.fd = fd_client;
+
+	status = epoll_ctl(conn->fd_client_group,
+		EPOLL_CTL_ADD,
+		fd_client,
+		&event);
+	if (status == -1) {
+		close(fd_client);
+		return -1;
+	}
+
+	/* Client */
+	status = write(fd_client,
+		conn->welcome,
+		strlen(conn->welcome));
+	if (status == -1) {
+		close(fd_client);
+		return -1;
+	}
+
+	status = write(fd_client,
+		conn->prompt,
+		strlen(conn->prompt));
+	if (status == -1) {
+		close(fd_client);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+data_event_handle(struct conn *conn,
+	int fd_client)
+{
+	ssize_t len, i, status;
+
+	/* Read input message */
+
+	len = read(fd_client,
+		conn->buf,
+		conn->buf_size);
+	if (len == -1) {
+		if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
+			return 0;
+
+		return -1;
+	}
+	if (len == 0)
+		return 0;
+
+	/* Handle input messages */
+	for (i = 0; i < len; i++) {
+		if (conn->buf[i] == '\n') {
+			size_t n;
+
+			conn->msg_in[conn->msg_in_len] = 0;
+			conn->msg_out[0] = 0;
+
+			conn->msg_handle(conn->msg_in,
+				conn->msg_out,
+				conn->msg_out_len_max);
+
+			n = strlen(conn->msg_out);
+			if (n) {
+				status = write(fd_client,
+					conn->msg_out,
+					n);
+				if (status == -1)
+					return status;
+			}
+
+			conn->msg_in_len = 0;
+		} else if (conn->msg_in_len < conn->msg_in_len_max) {
+			conn->msg_in[conn->msg_in_len] = conn->buf[i];
+			conn->msg_in_len++;
+		} else {
+			status = write(fd_client,
+				MSG_CMD_TOO_LONG,
+				strlen(MSG_CMD_TOO_LONG));
+			if (status == -1)
+				return status;
+
+			conn->msg_in_len = 0;
+		}
+	}
+
+	/* Write prompt */
+	status = write(fd_client,
+		conn->prompt,
+		strlen(conn->prompt));
+	if (status == -1)
+		return status;
+
+	return 0;
+}
+
+static int
+control_event_handle(struct conn *conn,
+	int fd_client)
+{
+	int status;
+
+	status = epoll_ctl(conn->fd_client_group,
+		EPOLL_CTL_DEL,
+		fd_client,
+		NULL);
+	if (status == -1)
+		return -1;
+
+	status = close(fd_client);
+	if (status == -1)
+		return -1;
+
+	return 0;
+}
+
+int
+conn_poll_for_msg(struct conn *conn)
+{
+	struct epoll_event event;
+	int fd_client, status, status_data, status_control;
+
+	/* Check input arguments */
+	if (conn == NULL)
+		return -1;
+
+	/* Client group */
+	status = epoll_wait(conn->fd_client_group,
+		&event,
+		1,
+		0);
+	if (status == -1)
+		return -1;
+	if (status == 0)
+		return 0;
+
+	fd_client = event.data.fd;
+
+	/* Data available */
+	if (event.events & EPOLLIN)
+		status_data = data_event_handle(conn, fd_client);
+
+	/* Control events */
+	if (event.events & (EPOLLRDHUP | EPOLLERR | EPOLLHUP))
+		status_control = control_event_handle(conn, fd_client);
+
+	if (status_data || status_control)
+		return -1;
+
+	return 0;
+}
diff --git a/examples/ip_pipeline/conn.h b/examples/ip_pipeline/conn.h
new file mode 100644
index 0000000..46f9f95
--- /dev/null
+++ b/examples/ip_pipeline/conn.h
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#ifndef __INCLUDE_CONN_H__
+#define __INCLUDE_CONN_H__
+
+#include <stdint.h>
+
+struct conn;
+
+#ifndef CONN_WELCOME_LEN_MAX
+#define CONN_WELCOME_LEN_MAX                               1024
+#endif
+
+#ifndef CONN_PROMPT_LEN_MAX
+#define CONN_PROMPT_LEN_MAX                                16
+#endif
+
+typedef void (*conn_msg_handle_t)(char *msg_in,
+	char *msg_out,
+	size_t msg_out_len_max);
+
+struct conn_params {
+	const char *welcome;
+	const char *prompt;
+	const char *addr;
+	uint16_t port;
+	size_t buf_size;
+	size_t msg_in_len_max;
+	size_t msg_out_len_max;
+	conn_msg_handle_t msg_handle;
+};
+
+struct conn *
+conn_init(struct conn_params *p);
+
+void
+conn_free(struct conn *conn);
+
+int
+conn_poll_for_conn(struct conn *conn);
+
+int
+conn_poll_for_msg(struct conn *conn);
+
+#endif
diff --git a/examples/ip_pipeline/main.c b/examples/ip_pipeline/main.c
index 1696e36..60936f4 100644
--- a/examples/ip_pipeline/main.c
+++ b/examples/ip_pipeline/main.c
@@ -1,5 +1,5 @@
 /* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2015 Intel Corporation
+ * Copyright(c) 2010-2018 Intel Corporation
  */
 
 #include <stdio.h>
@@ -10,11 +10,140 @@
 
 #include <rte_eal.h>
 
+#include "cli.h"
+#include "conn.h"
+
+static const char usage[] =
+	"%s EAL_ARGS -- [-h HOST] [-p PORT] [-s SCRIPT]\n";
+
+static const char welcome[] =
+	"\n"
+	"Welcome to IP Pipeline!\n"
+	"\n";
+
+static const char prompt[] = "pipeline> ";
+
+static struct app_params {
+	struct conn_params conn;
+	char *script_name;
+} app = {
+	.conn = {
+		.welcome = welcome,
+		.prompt = prompt,
+		.addr = "0.0.0.0",
+		.port = 8086,
+		.buf_size = 1024 * 1024,
+		.msg_in_len_max = 1024,
+		.msg_out_len_max = 1024 * 1024,
+		.msg_handle = cli_process,
+	},
+	.script_name = NULL,
+};
+
+static int
+parse_args(int argc, char **argv)
+{
+	char *app_name = argv[0];
+	struct option lgopts[] = {
+		{ NULL,  0, 0, 0 }
+	};
+	int opt, option_index;
+	int h_present, p_present, s_present, n_args, i;
+
+	/* Skip EAL input args */
+	n_args = argc;
+	for (i = 0; i < n_args; i++)
+		if (strcmp(argv[i], "--") == 0) {
+			argc -= i;
+			argv += i;
+			break;
+		}
+
+	if (i == n_args)
+		return 0;
+
+	/* Parse args */
+	h_present = 0;
+	p_present = 0;
+	s_present = 0;
+
+	while ((opt = getopt_long(argc, argv, "h:p:s:", lgopts, &option_index))
+			!= EOF)
+		switch (opt) {
+		case 'h':
+			if (h_present) {
+				printf("Error: Multiple -h arguments\n");
+				return -1;
+			}
+			h_present = 1;
+
+			if (!strlen(optarg)) {
+				printf("Error: Argument for -h not provided\n");
+				return -1;
+			}
+
+			app.conn.addr = strdup(optarg);
+			if (app.conn.addr == NULL) {
+				printf("Error: Not enough memory\n");
+				return -1;
+			}
+			break;
+
+		case 'p':
+			if (p_present) {
+				printf("Error: Multiple -p arguments\n");
+				return -1;
+			}
+			p_present = 1;
+
+			if (!strlen(optarg)) {
+				printf("Error: Argument for -p not provided\n");
+				return -1;
+			}
+
+			app.conn.port = (uint16_t) atoi(optarg);
+			break;
+
+		case 's':
+			if (s_present) {
+				printf("Error: Multiple -s arguments\n");
+				return -1;
+			}
+			s_present = 1;
+
+			if (!strlen(optarg)) {
+				printf("Error: Argument for -s not provided\n");
+				return -1;
+			}
+
+			app.script_name = strdup(optarg);
+			if (app.script_name == NULL) {
+				printf("Error: Not enough memory\n");
+				return -1;
+			}
+			break;
+
+		default:
+			printf(usage, app_name);
+			return -1;
+		}
+
+	optind = 1; /* reset getopt lib */
+
+	return 0;
+}
+
 int
 main(int argc, char **argv)
 {
+	struct conn *conn;
 	int status;
 
+	/* Parse application arguments */
+	status = parse_args(argc, argv);
+	if (status < 0)
+		return status;
+
 	/* EAL */
 	status = rte_eal_init(argc, argv);
 	if (status < 0) {
@@ -22,4 +151,24 @@ main(int argc, char **argv)
 		return status;
 	};
 
+	/* Connectivity */
+	conn = conn_init(&app.conn);
+	if (conn == NULL) {
+		printf("Error: Connectivity initialization failed (%d)\n",
+			status);
+		return status;
+	};
+
+	/* Script */
+	if (app.script_name)
+		cli_script_process(app.script_name,
+			app.conn.msg_in_len_max,
+			app.conn.msg_out_len_max);
+
+	/* Dispatch loop */
+	for ( ; ; ) {
+		conn_poll_for_conn(conn);
+
+		conn_poll_for_msg(conn);
+	}
 }
diff --git a/examples/ip_pipeline/meson.build b/examples/ip_pipeline/meson.build
index 063865c..a89cb30 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -8,6 +8,8 @@
 
 deps += ['pipeline', 'bus_pci']
 sources = files(
+	'cli.c',
+	'conn.c',
 	'main.c',
 	'parser.c',
 )
-- 
2.9.3

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

* [dpdk-dev] [PATCH v4 22/49] ip_pipeline: add mempool object for pipeline
  2018-03-29 18:31           ` [dpdk-dev] [PATCH v4 00/49] ip_pipeline: refactoring Jasvinder Singh
                               ` (20 preceding siblings ...)
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 21/49] ip_pipeline: add cli interface Jasvinder Singh
@ 2018-03-29 18:31             ` Jasvinder Singh
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 23/49] ip_pipeline: add link object Jasvinder Singh
                               ` (27 subsequent siblings)
  49 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-29 18:31 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Fan Zhang

Add mempool object implementation to the application.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Fan Zhang <roy.fan.zhang@intel.com>
---
 examples/ip_pipeline/Makefile    |   1 +
 examples/ip_pipeline/cli.c       | 109 ++++++++++++++++++++++++++++++++++++++-
 examples/ip_pipeline/common.h    |  12 +++++
 examples/ip_pipeline/main.c      |   8 +++
 examples/ip_pipeline/mempool.c   |  81 +++++++++++++++++++++++++++++
 examples/ip_pipeline/mempool.h   |  40 ++++++++++++++
 examples/ip_pipeline/meson.build |   1 +
 7 files changed, 251 insertions(+), 1 deletion(-)
 create mode 100644 examples/ip_pipeline/common.h
 create mode 100644 examples/ip_pipeline/mempool.c
 create mode 100644 examples/ip_pipeline/mempool.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index 0c5b6b1..fca28c5 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -8,6 +8,7 @@ APP = ip_pipeline
 SRCS-y := cli.c
 SRCS-y += conn.c
 SRCS-y += main.c
+SRCS-y += mempool.c
 SRCS-y += parser.c
 #SRCS-y += thread.c
 
diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index 34ada83..b0d8345 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -10,6 +10,23 @@
 #include <rte_common.h>
 
 #include "cli.h"
+#include "mempool.h"
+#include "parser.h"
+
+#ifndef CMD_MAX_TOKENS
+#define CMD_MAX_TOKENS     256
+#endif
+
+#define MSG_OUT_OF_MEMORY  "Not enough memory.\n"
+#define MSG_CMD_UNKNOWN    "Unknown command \"%s\".\n"
+#define MSG_CMD_UNIMPLEM   "Command \"%s\" not implemented.\n"
+#define MSG_ARG_NOT_ENOUGH "Not enough arguments for command \"%s\".\n"
+#define MSG_ARG_TOO_MANY   "Too many arguments for command \"%s\".\n"
+#define MSG_ARG_MISMATCH   "Wrong number of arguments for command \"%s\".\n"
+#define MSG_ARG_NOT_FOUND  "Argument \"%s\" not found.\n"
+#define MSG_ARG_INVALID    "Invalid value for argument \"%s\".\n"
+#define MSG_FILE_ERR       "Error in file \"%s\" at line %u.\n"
+#define MSG_CMD_FAIL       "Command \"%s\" failed.\n"
 
 static int
 is_comment(char *in)
@@ -22,12 +39,102 @@ is_comment(char *in)
 	return 0;
 }
 
+/**
+ * mempool <mempool_name>
+ *  buffer <buffer_size>
+ *  pool <pool_size>
+ *  cache <cache_size>
+ *  cpu <cpu_id>
+ */
+static void
+cmd_mempool(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct mempool_params p;
+	char *name;
+	struct mempool *mempool;
+
+	if (n_tokens != 10) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	name = tokens[1];
+
+	if (strcmp(tokens[2], "buffer") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "buffer");
+		return;
+	}
+
+	if (parser_read_uint32(&p.buffer_size, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "buffer_size");
+		return;
+	}
+
+	if (strcmp(tokens[4], "pool") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pool");
+		return;
+	}
+
+	if (parser_read_uint32(&p.pool_size, tokens[5]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "pool_size");
+		return;
+	}
+
+	if (strcmp(tokens[6], "cache") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cache");
+		return;
+	}
+
+	if (parser_read_uint32(&p.cache_size, tokens[7]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "cache_size");
+		return;
+	}
+
+	if (strcmp(tokens[8], "cpu") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu");
+		return;
+	}
+
+	if (parser_read_uint32(&p.cpu_id, tokens[9]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id");
+		return;
+	}
+
+	mempool = mempool_create(name, &p);
+	if (mempool == NULL) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
 void
-cli_process(char *in, char *out __rte_unused, size_t out_size __rte_unused)
+cli_process(char *in, char *out, size_t out_size)
 {
+	char *tokens[CMD_MAX_TOKENS];
+	uint32_t n_tokens = RTE_DIM(tokens);
+	int status;
+
 	if (is_comment(in))
 		return;
 
+	status = parse_tokenize_string(in, tokens, &n_tokens);
+	if (status) {
+		snprintf(out, out_size, MSG_ARG_TOO_MANY, "");
+		return;
+	}
+
+	if (n_tokens == 0)
+		return;
+
+	if (strcmp(tokens[0], "mempool") == 0) {
+		cmd_mempool(tokens, n_tokens, out, out_size);
+		return;
+	}
+
+	snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
 }
 
 int
diff --git a/examples/ip_pipeline/common.h b/examples/ip_pipeline/common.h
new file mode 100644
index 0000000..0886dfb
--- /dev/null
+++ b/examples/ip_pipeline/common.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#ifndef _INCLUDE_COMMON_H_
+#define _INCLUDE_COMMON_H_
+
+#ifndef NAME_SIZE
+#define NAME_SIZE                                            64
+#endif
+
+#endif /* _INCLUDE_COMMON_H_ */
diff --git a/examples/ip_pipeline/main.c b/examples/ip_pipeline/main.c
index 60936f4..b53f623 100644
--- a/examples/ip_pipeline/main.c
+++ b/examples/ip_pipeline/main.c
@@ -12,6 +12,7 @@
 
 #include "cli.h"
 #include "conn.h"
+#include "mempool.h"
 
 static const char usage[] =
 	"%s EAL_ARGS -- [-h HOST] [-p PORT] [-s SCRIPT]\n";
@@ -159,6 +160,13 @@ main(int argc, char **argv)
 		return status;
 	};
 
+	/* Mempool */
+	status = mempool_init();
+	if (status) {
+		printf("Error: Mempool initialization failed (%d)\n", status);
+		return status;
+	}
+
 	/* Script */
 	if (app.script_name)
 		cli_script_process(app.script_name,
diff --git a/examples/ip_pipeline/mempool.c b/examples/ip_pipeline/mempool.c
new file mode 100644
index 0000000..33b9243
--- /dev/null
+++ b/examples/ip_pipeline/mempool.c
@@ -0,0 +1,81 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <rte_mbuf.h>
+
+#include "mempool.h"
+
+#define BUFFER_SIZE_MIN        (sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM)
+
+static struct mempool_list mempool_list;
+
+int
+mempool_init(void)
+{
+	TAILQ_INIT(&mempool_list);
+
+	return 0;
+}
+
+struct mempool *
+mempool_find(const char *name)
+{
+	struct mempool *mempool;
+
+	if (name == NULL)
+		return NULL;
+
+	TAILQ_FOREACH(mempool, &mempool_list, node)
+		if (strcmp(mempool->name, name) == 0)
+			return mempool;
+
+	return NULL;
+}
+
+struct mempool *
+mempool_create(const char *name, struct mempool_params *params)
+{
+	struct mempool *mempool;
+	struct rte_mempool *m;
+
+	/* Check input params */
+	if ((name == NULL) ||
+		mempool_find(name) ||
+		(params == NULL) ||
+		(params->buffer_size < BUFFER_SIZE_MIN) ||
+		(params->pool_size == 0))
+		return NULL;
+
+	/* Resource create */
+	m = rte_pktmbuf_pool_create(
+		name,
+		params->pool_size,
+		params->cache_size,
+		0,
+		params->buffer_size - sizeof(struct rte_mbuf),
+		params->cpu_id);
+
+	if (m == NULL)
+		return NULL;
+
+	/* Node allocation */
+	mempool = calloc(1, sizeof(struct mempool));
+	if (mempool == NULL) {
+		rte_mempool_free(m);
+		return NULL;
+	}
+
+	/* Node fill in */
+	strncpy(mempool->name, name, sizeof(mempool->name));
+	mempool->m = m;
+	mempool->buffer_size = params->buffer_size;
+
+	/* Node add to list */
+	TAILQ_INSERT_TAIL(&mempool_list, mempool, node);
+
+	return mempool;
+}
diff --git a/examples/ip_pipeline/mempool.h b/examples/ip_pipeline/mempool.h
new file mode 100644
index 0000000..bd46a11
--- /dev/null
+++ b/examples/ip_pipeline/mempool.h
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#ifndef _INCLUDE_MEMPOOL_H_
+#define _INCLUDE_MEMPOOL_H_
+
+#include <stdint.h>
+#include <sys/queue.h>
+
+#include <rte_mempool.h>
+
+#include "common.h"
+
+struct mempool {
+	TAILQ_ENTRY(mempool) node;
+	char name[NAME_SIZE];
+	struct rte_mempool *m;
+	uint32_t buffer_size;
+};
+
+TAILQ_HEAD(mempool_list, mempool);
+
+int
+mempool_init(void);
+
+struct mempool *
+mempool_find(const char *name);
+
+struct mempool_params {
+	uint32_t buffer_size;
+	uint32_t pool_size;
+	uint32_t cache_size;
+	uint32_t cpu_id;
+};
+
+struct mempool *
+mempool_create(const char *name, struct mempool_params *params);
+
+#endif /* _INCLUDE_MEMPOOL_H_ */
diff --git a/examples/ip_pipeline/meson.build b/examples/ip_pipeline/meson.build
index a89cb30..f8a450f 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -11,5 +11,6 @@ sources = files(
 	'cli.c',
 	'conn.c',
 	'main.c',
+	'mempool.c',
 	'parser.c',
 )
-- 
2.9.3

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

* [dpdk-dev] [PATCH v4 23/49] ip_pipeline: add link object
  2018-03-29 18:31           ` [dpdk-dev] [PATCH v4 00/49] ip_pipeline: refactoring Jasvinder Singh
                               ` (21 preceding siblings ...)
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 22/49] ip_pipeline: add mempool object for pipeline Jasvinder Singh
@ 2018-03-29 18:31             ` Jasvinder Singh
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 24/49] ip_pipeline: add software queue object Jasvinder Singh
                               ` (26 subsequent siblings)
  49 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-29 18:31 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Fan Zhang

Add link object implementation to the application.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Fan Zhang <roy.fan.zhang@intel.com>
---
 examples/ip_pipeline/Makefile    |   1 +
 examples/ip_pipeline/cli.c       | 122 ++++++++++++++++++
 examples/ip_pipeline/link.c      | 268 +++++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/link.h      |  63 +++++++++
 examples/ip_pipeline/main.c      |   8 ++
 examples/ip_pipeline/meson.build |   1 +
 6 files changed, 463 insertions(+)
 create mode 100644 examples/ip_pipeline/link.c
 create mode 100644 examples/ip_pipeline/link.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index fca28c5..3dab932 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -7,6 +7,7 @@ APP = ip_pipeline
 # all source are stored in SRCS-y
 SRCS-y := cli.c
 SRCS-y += conn.c
+SRCS-y += link.c
 SRCS-y += main.c
 SRCS-y += mempool.c
 SRCS-y += parser.c
diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index b0d8345..803e61e 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -10,6 +10,7 @@
 #include <rte_common.h>
 
 #include "cli.h"
+#include "link.h"
 #include "mempool.h"
 #include "parser.h"
 
@@ -110,6 +111,122 @@ cmd_mempool(char **tokens,
 	}
 }
 
+/**
+ * link <link_name>
+ *  dev <device_name> | port <port_id>
+ *  rxq <n_queues> <queue_size> <mempool_name>
+ *  txq <n_queues> <queue_size>
+ *  promiscuous on | off
+ *  [rss <qid_0> ... <qid_n>]
+ */
+static void
+cmd_link(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct link_params p;
+	struct link_params_rss rss;
+	struct link *link;
+	char *name;
+
+	if ((n_tokens < 13) || (n_tokens > 14 + LINK_RXQ_RSS_MAX)) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+	name = tokens[1];
+
+	if (strcmp(tokens[2], "dev") == 0)
+		p.dev_name = tokens[3];
+	else if (strcmp(tokens[2], "port") == 0) {
+		p.dev_name = NULL;
+
+		if (parser_read_uint16(&p.port_id, tokens[3]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
+			return;
+		}
+	} else {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "dev or port");
+		return;
+	}
+
+	if (strcmp(tokens[4], "rxq") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rxq");
+		return;
+	}
+
+	if (parser_read_uint32(&p.rx.n_queues, tokens[5]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "n_queues");
+		return;
+	}
+	if (parser_read_uint32(&p.rx.queue_size, tokens[6]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "queue_size");
+		return;
+	}
+
+	p.rx.mempool_name = tokens[7];
+
+	if (strcmp(tokens[8], "txq") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "txq");
+		return;
+	}
+
+	if (parser_read_uint32(&p.tx.n_queues, tokens[9]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "n_queues");
+		return;
+	}
+
+	if (parser_read_uint32(&p.tx.queue_size, tokens[10]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "queue_size");
+		return;
+	}
+
+	if (strcmp(tokens[11], "promiscuous") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "promiscuous");
+		return;
+	}
+
+	if (strcmp(tokens[12], "on") == 0)
+		p.promiscuous = 1;
+	else if (strcmp(tokens[12], "off") == 0)
+		p.promiscuous = 0;
+	else {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "on or off");
+		return;
+	}
+
+	/* RSS */
+	p.rx.rss = NULL;
+	if (n_tokens > 13) {
+		uint32_t queue_id, i;
+
+		if (strcmp(tokens[13], "rss") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rss");
+			return;
+		}
+
+		p.rx.rss = &rss;
+
+		rss.n_queues = 0;
+		for (i = 14; i < n_tokens; i++) {
+			if (parser_read_uint32(&queue_id, tokens[i]) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID,
+					"queue_id");
+				return;
+			}
+
+			rss.queue_id[rss.n_queues] = queue_id;
+			rss.n_queues++;
+		}
+	}
+
+	link = link_create(name, &p);
+	if (link == NULL) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
 void
 cli_process(char *in, char *out, size_t out_size)
 {
@@ -134,6 +251,11 @@ cli_process(char *in, char *out, size_t out_size)
 		return;
 	}
 
+	if (strcmp(tokens[0], "link") == 0) {
+		cmd_link(tokens, n_tokens, out, out_size);
+		return;
+	}
+
 	snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
 }
 
diff --git a/examples/ip_pipeline/link.c b/examples/ip_pipeline/link.c
new file mode 100644
index 0000000..26ff41b
--- /dev/null
+++ b/examples/ip_pipeline/link.c
@@ -0,0 +1,268 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <rte_ethdev.h>
+
+#include "link.h"
+#include "mempool.h"
+
+static struct link_list link_list;
+
+int
+link_init(void)
+{
+	TAILQ_INIT(&link_list);
+
+	return 0;
+}
+
+struct link *
+link_find(const char *name)
+{
+	struct link *link;
+
+	if (name == NULL)
+		return NULL;
+
+	TAILQ_FOREACH(link, &link_list, node)
+		if (strcmp(link->name, name) == 0)
+			return link;
+
+	return NULL;
+}
+
+static struct rte_eth_conf port_conf_default = {
+	.link_speeds = 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   = 1, /* CRC strip by HW */
+		.enable_scatter = 0, /* Scattered packets RX handler */
+
+		.max_rx_pkt_len = 9000, /* Jumbo frame max packet len */
+		.split_hdr_size = 0, /* Header split buffer size */
+	},
+	.rx_adv_conf = {
+		.rss_conf = {
+			.rss_key = NULL,
+			.rss_key_len = 40,
+			.rss_hf = 0,
+		},
+	},
+	.txmode = {
+		.mq_mode = ETH_MQ_TX_NONE,
+	},
+	.lpbk_mode = 0,
+};
+
+#define RETA_CONF_SIZE     (ETH_RSS_RETA_SIZE_512 / RTE_RETA_GROUP_SIZE)
+
+static int
+rss_setup(uint16_t port_id,
+	uint16_t reta_size,
+	struct link_params_rss *rss)
+{
+	struct rte_eth_rss_reta_entry64 reta_conf[RETA_CONF_SIZE];
+	uint32_t i;
+	int status;
+
+	/* RETA setting */
+	memset(reta_conf, 0, sizeof(reta_conf));
+
+	for (i = 0; i < reta_size; i++)
+		reta_conf[i / RTE_RETA_GROUP_SIZE].mask = UINT64_MAX;
+
+	for (i = 0; i < reta_size; i++) {
+		uint32_t reta_id = i / RTE_RETA_GROUP_SIZE;
+		uint32_t reta_pos = i % RTE_RETA_GROUP_SIZE;
+		uint32_t rss_qs_pos = i % rss->n_queues;
+
+		reta_conf[reta_id].reta[reta_pos] =
+			(uint16_t) rss->queue_id[rss_qs_pos];
+	}
+
+	/* RETA update */
+	status = rte_eth_dev_rss_reta_update(port_id,
+		reta_conf,
+		reta_size);
+
+	return status;
+}
+
+struct link *
+link_create(const char *name, struct link_params *params)
+{
+	struct rte_eth_dev_info port_info;
+	struct rte_eth_conf port_conf;
+	struct link *link;
+	struct link_params_rss *rss;
+	struct mempool *mempool;
+	uint32_t cpu_id, i;
+	int status;
+	uint16_t port_id;
+
+	/* Check input params */
+	if ((name == NULL) ||
+		link_find(name) ||
+		(params == NULL) ||
+		(params->rx.n_queues == 0) ||
+		(params->rx.queue_size == 0) ||
+		(params->tx.n_queues == 0) ||
+		(params->tx.queue_size == 0))
+		return NULL;
+
+	port_id = params->port_id;
+	if (params->dev_name) {
+		status = rte_eth_dev_get_port_by_name(params->dev_name,
+			&port_id);
+
+		if (status)
+			return NULL;
+	} else
+		if (!rte_eth_dev_is_valid_port(port_id))
+			return NULL;
+
+	rte_eth_dev_info_get(port_id, &port_info);
+
+	mempool = mempool_find(params->rx.mempool_name);
+	if (mempool == NULL)
+		return NULL;
+
+	rss = params->rx.rss;
+	if (rss) {
+		if ((port_info.reta_size == 0) ||
+			(port_info.reta_size > ETH_RSS_RETA_SIZE_512))
+			return NULL;
+
+		if ((rss->n_queues == 0) ||
+			(rss->n_queues >= LINK_RXQ_RSS_MAX))
+			return NULL;
+
+		for (i = 0; i < rss->n_queues; i++)
+			if (rss->queue_id[i] >= port_info.max_rx_queues)
+				return NULL;
+	}
+
+	/**
+	 * Resource create
+	 */
+	/* Port */
+	memcpy(&port_conf, &port_conf_default, sizeof(port_conf));
+	if (rss) {
+		port_conf.rxmode.mq_mode = ETH_MQ_RX_RSS;
+		port_conf.rx_adv_conf.rss_conf.rss_hf =
+			ETH_RSS_IPV4 | ETH_RSS_IPV6;
+	}
+
+	cpu_id = (uint32_t) rte_eth_dev_socket_id(port_id);
+	if (cpu_id == (uint32_t) SOCKET_ID_ANY)
+		cpu_id = 0;
+
+	status = rte_eth_dev_configure(
+		port_id,
+		params->rx.n_queues,
+		params->tx.n_queues,
+		&port_conf);
+
+	if (status < 0)
+		return NULL;
+
+	if (params->promiscuous)
+		rte_eth_promiscuous_enable(port_id);
+
+	/* Port RX */
+	for (i = 0; i < params->rx.n_queues; i++) {
+		status = rte_eth_rx_queue_setup(
+			port_id,
+			i,
+			params->rx.queue_size,
+			cpu_id,
+			NULL,
+			mempool->m);
+
+		if (status < 0)
+			return NULL;
+	}
+
+	/* Port TX */
+	for (i = 0; i < params->tx.n_queues; i++) {
+		status = rte_eth_tx_queue_setup(
+			port_id,
+			i,
+			params->tx.queue_size,
+			cpu_id,
+			NULL);
+
+		if (status < 0)
+			return NULL;
+	}
+
+	/* Port start */
+	status = rte_eth_dev_start(port_id);
+	if (status < 0)
+		return NULL;
+
+	if (rss) {
+		status = rss_setup(port_id, port_info.reta_size, rss);
+
+		if (status) {
+			rte_eth_dev_stop(port_id);
+			return NULL;
+		}
+	}
+
+	/* Port link up */
+	status = rte_eth_dev_set_link_up(port_id);
+	if ((status < 0) && (status != -ENOTSUP)) {
+		rte_eth_dev_stop(port_id);
+		return NULL;
+	}
+
+	/* Node allocation */
+	link = calloc(1, sizeof(struct link));
+	if (link == NULL) {
+		rte_eth_dev_stop(port_id);
+		return NULL;
+	}
+
+	/* Node fill in */
+	strncpy(link->name, name, sizeof(link->name));
+	link->port_id = port_id;
+	link->n_rxq = params->rx.n_queues;
+	link->n_txq = params->tx.n_queues;
+
+	/* Node add to list */
+	TAILQ_INSERT_TAIL(&link_list, link, node);
+
+	return link;
+}
+
+int
+link_is_up(const char *name)
+{
+	struct rte_eth_link link_params;
+	struct link *link;
+
+	/* Check input params */
+	if (name == NULL)
+		return 0;
+
+	link = link_find(name);
+	if (link == NULL)
+		return 0;
+
+	/* Resource */
+	rte_eth_link_get(link->port_id, &link_params);
+
+	return (link_params.link_status == ETH_LINK_DOWN) ? 0 : 1;
+}
diff --git a/examples/ip_pipeline/link.h b/examples/ip_pipeline/link.h
new file mode 100644
index 0000000..37d3dc4
--- /dev/null
+++ b/examples/ip_pipeline/link.h
@@ -0,0 +1,63 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#ifndef _INCLUDE_LINK_H_
+#define _INCLUDE_LINK_H_
+
+#include <stdint.h>
+#include <sys/queue.h>
+
+#include "common.h"
+
+#ifndef LINK_RXQ_RSS_MAX
+#define LINK_RXQ_RSS_MAX                                   16
+#endif
+
+struct link {
+	TAILQ_ENTRY(link) node;
+	char name[NAME_SIZE];
+	uint16_t port_id;
+	uint32_t n_rxq;
+	uint32_t n_txq;
+};
+
+TAILQ_HEAD(link_list, link);
+
+int
+link_init(void);
+
+struct link *
+link_find(const char *name);
+
+struct link_params_rss {
+	uint32_t queue_id[LINK_RXQ_RSS_MAX];
+	uint32_t n_queues;
+};
+
+struct link_params {
+	const char *dev_name;
+	uint16_t port_id; /**< Valid only when *dev_name* is NULL. */
+
+	struct {
+		uint32_t n_queues;
+		uint32_t queue_size;
+		const char *mempool_name;
+		struct link_params_rss *rss;
+	} rx;
+
+	struct {
+		uint32_t n_queues;
+		uint32_t queue_size;
+	} tx;
+
+	int promiscuous;
+};
+
+struct link *
+link_create(const char *name, struct link_params *params);
+
+int
+link_is_up(const char *name);
+
+#endif /* _INCLUDE_LINK_H_ */
diff --git a/examples/ip_pipeline/main.c b/examples/ip_pipeline/main.c
index b53f623..edfb523 100644
--- a/examples/ip_pipeline/main.c
+++ b/examples/ip_pipeline/main.c
@@ -12,6 +12,7 @@
 
 #include "cli.h"
 #include "conn.h"
+#include "link.h"
 #include "mempool.h"
 
 static const char usage[] =
@@ -167,6 +168,13 @@ main(int argc, char **argv)
 		return status;
 	}
 
+	/* Link */
+	status = link_init();
+	if (status) {
+		printf("Error: Link initialization failed (%d)\n", status);
+		return status;
+	}
+
 	/* Script */
 	if (app.script_name)
 		cli_script_process(app.script_name,
diff --git a/examples/ip_pipeline/meson.build b/examples/ip_pipeline/meson.build
index f8a450f..a2f9bb6 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -10,6 +10,7 @@ deps += ['pipeline', 'bus_pci']
 sources = files(
 	'cli.c',
 	'conn.c',
+	'link.c',
 	'main.c',
 	'mempool.c',
 	'parser.c',
-- 
2.9.3

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

* [dpdk-dev] [PATCH v4 24/49] ip_pipeline: add software queue object
  2018-03-29 18:31           ` [dpdk-dev] [PATCH v4 00/49] ip_pipeline: refactoring Jasvinder Singh
                               ` (22 preceding siblings ...)
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 23/49] ip_pipeline: add link object Jasvinder Singh
@ 2018-03-29 18:31             ` Jasvinder Singh
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 25/49] ip_pipeline: add traffic manager object Jasvinder Singh
                               ` (25 subsequent siblings)
  49 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-29 18:31 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Kevin Laatz

Add swq object implementation to the application.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
---
 examples/ip_pipeline/Makefile    |  1 +
 examples/ip_pipeline/cli.c       | 55 +++++++++++++++++++++++++++++
 examples/ip_pipeline/main.c      |  8 +++++
 examples/ip_pipeline/meson.build |  1 +
 examples/ip_pipeline/swq.c       | 74 ++++++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/swq.h       | 37 ++++++++++++++++++++
 6 files changed, 176 insertions(+)
 create mode 100644 examples/ip_pipeline/swq.c
 create mode 100644 examples/ip_pipeline/swq.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index 3dab932..0dc8442 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -11,6 +11,7 @@ SRCS-y += link.c
 SRCS-y += main.c
 SRCS-y += mempool.c
 SRCS-y += parser.c
+SRCS-y += swq.c
 #SRCS-y += thread.c
 
 # Build using pkg-config variables if possible
diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index 803e61e..6aa10a2 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -13,6 +13,7 @@
 #include "link.h"
 #include "mempool.h"
 #include "parser.h"
+#include "swq.h"
 
 #ifndef CMD_MAX_TOKENS
 #define CMD_MAX_TOKENS     256
@@ -227,6 +228,55 @@ cmd_link(char **tokens,
 	}
 }
 
+/**
+ * swq <swq_name>
+ *  size <size>
+ *  cpu <cpu_id>
+ */
+static void
+cmd_swq(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct swq_params p;
+	char *name;
+	struct swq *swq;
+
+	if (n_tokens != 6) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	name = tokens[1];
+
+	if (strcmp(tokens[2], "size") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
+		return;
+	}
+
+	if (parser_read_uint32(&p.size, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "size");
+		return;
+	}
+
+	if (strcmp(tokens[4], "cpu") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu");
+		return;
+	}
+
+	if (parser_read_uint32(&p.cpu_id, tokens[5]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id");
+		return;
+	}
+
+	swq = swq_create(name, &p);
+	if (swq == NULL) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
 void
 cli_process(char *in, char *out, size_t out_size)
 {
@@ -256,6 +306,11 @@ cli_process(char *in, char *out, size_t out_size)
 		return;
 	}
 
+	if (strcmp(tokens[0], "swq") == 0) {
+		cmd_swq(tokens, n_tokens, out, out_size);
+		return;
+	}
+
 	snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
 }
 
diff --git a/examples/ip_pipeline/main.c b/examples/ip_pipeline/main.c
index edfb523..456f016 100644
--- a/examples/ip_pipeline/main.c
+++ b/examples/ip_pipeline/main.c
@@ -14,6 +14,7 @@
 #include "conn.h"
 #include "link.h"
 #include "mempool.h"
+#include "swq.h"
 
 static const char usage[] =
 	"%s EAL_ARGS -- [-h HOST] [-p PORT] [-s SCRIPT]\n";
@@ -175,6 +176,13 @@ main(int argc, char **argv)
 		return status;
 	}
 
+	/* SWQ */
+	status = swq_init();
+	if (status) {
+		printf("Error: SWQ initialization failed (%d)\n", status);
+		return status;
+	}
+
 	/* Script */
 	if (app.script_name)
 		cli_script_process(app.script_name,
diff --git a/examples/ip_pipeline/meson.build b/examples/ip_pipeline/meson.build
index a2f9bb6..442f3e3 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -14,4 +14,5 @@ sources = files(
 	'main.c',
 	'mempool.c',
 	'parser.c',
+	'swq.c',
 )
diff --git a/examples/ip_pipeline/swq.c b/examples/ip_pipeline/swq.c
new file mode 100644
index 0000000..c11bbf2
--- /dev/null
+++ b/examples/ip_pipeline/swq.c
@@ -0,0 +1,74 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "swq.h"
+
+static struct swq_list swq_list;
+
+int
+swq_init(void)
+{
+	TAILQ_INIT(&swq_list);
+
+	return 0;
+}
+
+struct swq *
+swq_find(const char *name)
+{
+	struct swq *swq;
+
+	if (name == NULL)
+		return NULL;
+
+	TAILQ_FOREACH(swq, &swq_list, node)
+		if (strcmp(swq->name, name) == 0)
+			return swq;
+
+	return NULL;
+}
+
+struct swq *
+swq_create(const char *name, struct swq_params *params)
+{
+	struct swq *swq;
+	struct rte_ring *r;
+	unsigned int flags = RING_F_SP_ENQ | RING_F_SC_DEQ;
+
+	/* Check input params */
+	if ((name == NULL) ||
+		swq_find(name) ||
+		(params == NULL) ||
+		(params->size == 0))
+		return NULL;
+
+	/* Resource create */
+	r = rte_ring_create(
+		name,
+		params->size,
+		params->cpu_id,
+		flags);
+
+	if (r == NULL)
+		return NULL;
+
+	/* Node allocation */
+	swq = calloc(1, sizeof(struct swq));
+	if (swq == NULL) {
+		rte_ring_free(r);
+		return NULL;
+	}
+
+	/* Node fill in */
+	strncpy(swq->name, name, sizeof(swq->name));
+	swq->r = r;
+
+	/* Node add to list */
+	TAILQ_INSERT_TAIL(&swq_list, swq, node);
+
+	return swq;
+}
diff --git a/examples/ip_pipeline/swq.h b/examples/ip_pipeline/swq.h
new file mode 100644
index 0000000..c8440ee
--- /dev/null
+++ b/examples/ip_pipeline/swq.h
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#ifndef _INCLUDE_SWQ_H_
+#define _INCLUDE_SWQ_H_
+
+#include <stdint.h>
+#include <sys/queue.h>
+
+#include <rte_ring.h>
+
+#include "common.h"
+
+struct swq {
+	TAILQ_ENTRY(swq) node;
+	char name[NAME_SIZE];
+	struct rte_ring *r;
+};
+
+TAILQ_HEAD(swq_list, swq);
+
+int
+swq_init(void);
+
+struct swq *
+swq_find(const char *name);
+
+struct swq_params {
+	uint32_t size;
+	uint32_t cpu_id;
+};
+
+struct swq *
+swq_create(const char *name, struct swq_params *params);
+
+#endif /* _INCLUDE_SWQ_H_ */
-- 
2.9.3

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

* [dpdk-dev] [PATCH v4 25/49] ip_pipeline: add traffic manager object
  2018-03-29 18:31           ` [dpdk-dev] [PATCH v4 00/49] ip_pipeline: refactoring Jasvinder Singh
                               ` (23 preceding siblings ...)
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 24/49] ip_pipeline: add software queue object Jasvinder Singh
@ 2018-03-29 18:31             ` Jasvinder Singh
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 26/49] ip_pipeline: add tap object Jasvinder Singh
                               ` (24 subsequent siblings)
  49 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-29 18:31 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add traffic manager object implementation to the application.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/Makefile    |   1 +
 examples/ip_pipeline/cli.c       | 360 +++++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/main.c      |   8 +
 examples/ip_pipeline/meson.build |   1 +
 examples/ip_pipeline/tmgr.c      | 227 ++++++++++++++++++++++++
 examples/ip_pipeline/tmgr.h      |  70 ++++++++
 6 files changed, 667 insertions(+)
 create mode 100644 examples/ip_pipeline/tmgr.c
 create mode 100644 examples/ip_pipeline/tmgr.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index 0dc8442..35e4302 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -12,6 +12,7 @@ SRCS-y += main.c
 SRCS-y += mempool.c
 SRCS-y += parser.c
 SRCS-y += swq.c
+SRCS-y += tmgr.c
 #SRCS-y += thread.c
 
 # Build using pkg-config variables if possible
diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index 6aa10a2..fd80ba5 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -14,6 +14,7 @@
 #include "mempool.h"
 #include "parser.h"
 #include "swq.h"
+#include "tmgr.h"
 
 #ifndef CMD_MAX_TOKENS
 #define CMD_MAX_TOKENS     256
@@ -277,6 +278,331 @@ cmd_swq(char **tokens,
 	}
 }
 
+/**
+ * tmgr subport profile
+ *  <tb_rate> <tb_size>
+ *  <tc0_rate> <tc1_rate> <tc2_rate> <tc3_rate>
+ *  <tc_period>
+ */
+static void
+cmd_tmgr_subport_profile(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct rte_sched_subport_params p;
+	int status, i;
+
+	if (n_tokens != 10) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	if (parser_read_uint32(&p.tb_rate, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "tb_rate");
+		return;
+	}
+
+	if (parser_read_uint32(&p.tb_size, tokens[4]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "tb_size");
+		return;
+	}
+
+	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
+		if (parser_read_uint32(&p.tc_rate[i], tokens[5 + i]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "tc_rate");
+			return;
+		}
+
+	if (parser_read_uint32(&p.tc_period, tokens[9]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "tc_period");
+		return;
+	}
+
+	status = tmgr_subport_profile_add(&p);
+	if (status != 0) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
+ * tmgr pipe profile
+ *  <tb_rate> <tb_size>
+ *  <tc0_rate> <tc1_rate> <tc2_rate> <tc3_rate>
+ *  <tc_period>
+ *  <tc_ov_weight>
+ *  <wrr_weight0..15>
+ */
+static void
+cmd_tmgr_pipe_profile(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct rte_sched_pipe_params p;
+	int status, i;
+
+	if (n_tokens != 27) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	if (parser_read_uint32(&p.tb_rate, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "tb_rate");
+		return;
+	}
+
+	if (parser_read_uint32(&p.tb_size, tokens[4]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "tb_size");
+		return;
+	}
+
+	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
+		if (parser_read_uint32(&p.tc_rate[i], tokens[5 + i]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "tc_rate");
+			return;
+		}
+
+	if (parser_read_uint32(&p.tc_period, tokens[9]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "tc_period");
+		return;
+	}
+
+#ifdef RTE_SCHED_SUBPORT_TC_OV
+	if (parser_read_uint32(&p.tc_ov_weight, tokens[10]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "tc_ov_weight");
+		return;
+	}
+#endif
+
+	for (i = 0; i < RTE_SCHED_QUEUES_PER_PIPE; i++)
+		if (parser_read_uint8(&p.wrr_weights[i], tokens[11 + i]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "wrr_weights");
+			return;
+		}
+
+	status = tmgr_pipe_profile_add(&p);
+	if (status != 0) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
+ * tmgr <tmgr_name>
+ *  rate <rate>
+ *  spp <n_subports_per_port>
+ *  pps <n_pipes_per_subport>
+ *  qsize <qsize_tc0> <qsize_tc1> <qsize_tc2> <qsize_tc3>
+ *  fo <frame_overhead>
+ *  mtu <mtu>
+ *  cpu <cpu_id>
+ */
+static void
+cmd_tmgr(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct tmgr_port_params p;
+	char *name;
+	struct tmgr_port *tmgr_port;
+	int i;
+
+	if (n_tokens != 19) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	name = tokens[1];
+
+	if (strcmp(tokens[2], "rate") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rate");
+		return;
+	}
+
+	if (parser_read_uint32(&p.rate, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "rate");
+		return;
+	}
+
+	if (strcmp(tokens[4], "spp") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "spp");
+		return;
+	}
+
+	if (parser_read_uint32(&p.n_subports_per_port, tokens[5]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "n_subports_per_port");
+		return;
+	}
+
+	if (strcmp(tokens[6], "pps") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pps");
+		return;
+	}
+
+	if (parser_read_uint32(&p.n_pipes_per_subport, tokens[7]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "n_pipes_per_subport");
+		return;
+	}
+
+	if (strcmp(tokens[8], "qsize") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "qsize");
+		return;
+	}
+
+	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
+		if (parser_read_uint16(&p.qsize[i], tokens[9 + i]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "qsize");
+			return;
+		}
+
+	if (strcmp(tokens[13], "fo") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "fo");
+		return;
+	}
+
+	if (parser_read_uint32(&p.frame_overhead, tokens[14]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "frame_overhead");
+		return;
+	}
+
+	if (strcmp(tokens[15], "mtu") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mtu");
+		return;
+	}
+
+	if (parser_read_uint32(&p.mtu, tokens[16]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "mtu");
+		return;
+	}
+
+	if (strcmp(tokens[17], "cpu") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu");
+		return;
+	}
+
+	if (parser_read_uint32(&p.cpu_id, tokens[18]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id");
+		return;
+	}
+
+	tmgr_port = tmgr_port_create(name, &p);
+	if (tmgr_port == NULL) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
+ * tmgr <tmgr_name> subport <subport_id>
+ *  profile <subport_profile_id>
+ */
+static void
+cmd_tmgr_subport(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	uint32_t subport_id, subport_profile_id;
+	int status;
+	char *name;
+
+	if (n_tokens != 6) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	name = tokens[1];
+
+	if (parser_read_uint32(&subport_id, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "subport_id");
+		return;
+	}
+
+	if (parser_read_uint32(&subport_profile_id, tokens[5]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "subport_profile_id");
+		return;
+	}
+
+	status = tmgr_subport_config(name, subport_id, subport_profile_id);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
+ * tmgr <tmgr_name> subport <subport_id> pipe
+ *  from <pipe_id_first> to <pipe_id_last>
+ *  profile <pipe_profile_id>
+ */
+static void
+cmd_tmgr_subport_pipe(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	uint32_t subport_id, pipe_id_first, pipe_id_last, pipe_profile_id;
+	int status;
+	char *name;
+
+	if (n_tokens != 11) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	name = tokens[1];
+
+	if (parser_read_uint32(&subport_id, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "subport_id");
+		return;
+	}
+
+	if (strcmp(tokens[4], "pipe") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipe");
+		return;
+	}
+
+	if (strcmp(tokens[5], "from") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "from");
+		return;
+	}
+
+	if (parser_read_uint32(&pipe_id_first, tokens[6]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "pipe_id_first");
+		return;
+	}
+
+	if (strcmp(tokens[7], "to") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "to");
+		return;
+	}
+
+	if (parser_read_uint32(&pipe_id_last, tokens[8]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "pipe_id_last");
+		return;
+	}
+
+	if (strcmp(tokens[9], "profile") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
+		return;
+	}
+
+	if (parser_read_uint32(&pipe_profile_id, tokens[10]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "pipe_profile_id");
+		return;
+	}
+
+	status = tmgr_pipe_config(name, subport_id, pipe_id_first,
+			pipe_id_last, pipe_profile_id);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
 void
 cli_process(char *in, char *out, size_t out_size)
 {
@@ -311,6 +637,40 @@ cli_process(char *in, char *out, size_t out_size)
 		return;
 	}
 
+	if (strcmp(tokens[0], "tmgr") == 0) {
+		if ((n_tokens >= 3) &&
+			(strcmp(tokens[1], "subport") == 0) &&
+			(strcmp(tokens[2], "profile") == 0)) {
+			cmd_tmgr_subport_profile(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
+
+		if ((n_tokens >= 3) &&
+			(strcmp(tokens[1], "pipe") == 0) &&
+			(strcmp(tokens[2], "profile") == 0)) {
+			cmd_tmgr_pipe_profile(tokens, n_tokens, out, out_size);
+			return;
+		}
+
+		if ((n_tokens >= 5) &&
+			(strcmp(tokens[2], "subport") == 0) &&
+			(strcmp(tokens[4], "profile") == 0)) {
+			cmd_tmgr_subport(tokens, n_tokens, out, out_size);
+			return;
+		}
+
+		if ((n_tokens >= 5) &&
+			(strcmp(tokens[2], "subport") == 0) &&
+			(strcmp(tokens[4], "pipe") == 0)) {
+			cmd_tmgr_subport_pipe(tokens, n_tokens, out, out_size);
+			return;
+		}
+
+		cmd_tmgr(tokens, n_tokens, out, out_size);
+		return;
+	}
+
 	snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
 }
 
diff --git a/examples/ip_pipeline/main.c b/examples/ip_pipeline/main.c
index 456f016..490991f 100644
--- a/examples/ip_pipeline/main.c
+++ b/examples/ip_pipeline/main.c
@@ -15,6 +15,7 @@
 #include "link.h"
 #include "mempool.h"
 #include "swq.h"
+#include "tmgr.h"
 
 static const char usage[] =
 	"%s EAL_ARGS -- [-h HOST] [-p PORT] [-s SCRIPT]\n";
@@ -183,6 +184,13 @@ main(int argc, char **argv)
 		return status;
 	}
 
+	/* Traffic Manager */
+	status = tmgr_init();
+	if (status) {
+		printf("Error: TMGR initialization failed (%d)\n", status);
+		return status;
+	}
+
 	/* Script */
 	if (app.script_name)
 		cli_script_process(app.script_name,
diff --git a/examples/ip_pipeline/meson.build b/examples/ip_pipeline/meson.build
index 442f3e3..cb2154c 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -15,4 +15,5 @@ sources = files(
 	'mempool.c',
 	'parser.c',
 	'swq.c',
+	'tmgr.c'
 )
diff --git a/examples/ip_pipeline/tmgr.c b/examples/ip_pipeline/tmgr.c
new file mode 100644
index 0000000..b46ca96
--- /dev/null
+++ b/examples/ip_pipeline/tmgr.c
@@ -0,0 +1,227 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#include <stdlib.h>
+
+#include "tmgr.h"
+
+static struct rte_sched_subport_params
+	subport_profile[TMGR_SUBPORT_PROFILE_MAX];
+
+static uint32_t n_subport_profiles;
+
+static struct rte_sched_pipe_params
+	pipe_profile[TMGR_PIPE_PROFILE_MAX];
+
+static uint32_t n_pipe_profiles;
+
+static struct tmgr_port_list tmgr_port_list;
+
+int
+tmgr_init(void)
+{
+	TAILQ_INIT(&tmgr_port_list);
+
+	return 0;
+}
+
+struct tmgr_port *
+tmgr_port_find(const char *name)
+{
+	struct tmgr_port *tmgr_port;
+
+	if (name == NULL)
+		return NULL;
+
+	TAILQ_FOREACH(tmgr_port, &tmgr_port_list, node)
+		if (strcmp(tmgr_port->name, name) == 0)
+			return tmgr_port;
+
+	return NULL;
+}
+
+int
+tmgr_subport_profile_add(struct rte_sched_subport_params *p)
+{
+	/* Check input params */
+	if (p == NULL)
+		return -1;
+
+	/* Save profile */
+	memcpy(&subport_profile[n_subport_profiles],
+		p,
+		sizeof(*p));
+
+	n_subport_profiles++;
+
+	return 0;
+}
+
+int
+tmgr_pipe_profile_add(struct rte_sched_pipe_params *p)
+{
+	/* Check input params */
+	if (p == NULL)
+		return -1;
+
+	/* Save profile */
+	memcpy(&pipe_profile[n_pipe_profiles],
+		p,
+		sizeof(*p));
+
+	n_pipe_profiles++;
+
+	return 0;
+}
+
+struct tmgr_port *
+tmgr_port_create(const char *name, struct tmgr_port_params *params)
+{
+	struct rte_sched_port_params p;
+	struct tmgr_port *tmgr_port;
+	struct rte_sched_port *s;
+	uint32_t i, j;
+
+	/* Check input params */
+	if ((name == NULL) ||
+		tmgr_port_find(name) ||
+		(params == NULL) ||
+		(params->n_subports_per_port == 0) ||
+		(params->n_pipes_per_subport == 0) ||
+		(params->cpu_id >= RTE_MAX_NUMA_NODES) ||
+		(n_subport_profiles == 0) ||
+		(n_pipe_profiles == 0))
+		return NULL;
+
+	/* Resource create */
+	p.name = name;
+	p.socket = (int) params->cpu_id;
+	p.rate = params->rate;
+	p.mtu = params->mtu;
+	p.frame_overhead = params->frame_overhead;
+	p.n_subports_per_port = params->n_subports_per_port;
+	p.n_pipes_per_subport = params->n_pipes_per_subport;
+
+	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
+		p.qsize[i] = params->qsize[i];
+
+	p.pipe_profiles = pipe_profile;
+	p.n_pipe_profiles = n_pipe_profiles;
+
+	s = rte_sched_port_config(&p);
+	if (s == NULL)
+		return NULL;
+
+	for (i = 0; i < params->n_subports_per_port; i++) {
+		int status;
+
+		status = rte_sched_subport_config(
+			s,
+			i,
+			&subport_profile[0]);
+
+		if (status) {
+			rte_sched_port_free(s);
+			return NULL;
+		}
+
+		for (j = 0; j < params->n_pipes_per_subport; j++) {
+			status = rte_sched_pipe_config(
+				s,
+				i,
+				j,
+				0);
+
+			if (status) {
+				rte_sched_port_free(s);
+				return NULL;
+			}
+		}
+	}
+
+	/* Node allocation */
+	tmgr_port = calloc(1, sizeof(struct tmgr_port));
+	if (tmgr_port == NULL) {
+		rte_sched_port_free(s);
+		return NULL;
+	}
+
+	/* Node fill in */
+	strncpy(tmgr_port->name, name, sizeof(tmgr_port->name));
+	tmgr_port->s = s;
+	tmgr_port->n_subports_per_port = params->n_subports_per_port;
+	tmgr_port->n_pipes_per_subport = params->n_pipes_per_subport;
+
+	/* Node add to list */
+	TAILQ_INSERT_TAIL(&tmgr_port_list, tmgr_port, node);
+
+	return tmgr_port;
+}
+
+int
+tmgr_subport_config(const char *port_name,
+	uint32_t subport_id,
+	uint32_t subport_profile_id)
+{
+	struct tmgr_port *port;
+	int status;
+
+	/* Check input params */
+	if (port_name == NULL)
+		return -1;
+
+	port = tmgr_port_find(port_name);
+	if ((port == NULL) ||
+		(subport_id >= port->n_subports_per_port) ||
+		(subport_profile_id >= n_subport_profiles))
+		return -1;
+
+	/* Resource config */
+	status = rte_sched_subport_config(
+		port->s,
+		subport_id,
+		&subport_profile[subport_profile_id]);
+
+	return status;
+}
+
+int
+tmgr_pipe_config(const char *port_name,
+	uint32_t subport_id,
+	uint32_t pipe_id_first,
+	uint32_t pipe_id_last,
+	uint32_t pipe_profile_id)
+{
+	struct tmgr_port *port;
+	uint32_t i;
+
+	/* Check input params */
+	if (port_name == NULL)
+		return -1;
+
+	port = tmgr_port_find(port_name);
+	if ((port == NULL) ||
+		(subport_id >= port->n_subports_per_port) ||
+		(pipe_id_first >= port->n_pipes_per_subport) ||
+		(pipe_id_last >= port->n_pipes_per_subport) ||
+		(pipe_id_first > pipe_id_last) ||
+		(pipe_profile_id >= n_pipe_profiles))
+		return -1;
+
+	/* Resource config */
+	for (i = pipe_id_first; i <= pipe_id_last; i++) {
+		int status;
+
+		status = rte_sched_pipe_config(
+			port->s,
+			subport_id,
+			i,
+			(int) pipe_profile_id);
+
+		if (status)
+			return status;
+	}
+
+	return 0;
+}
diff --git a/examples/ip_pipeline/tmgr.h b/examples/ip_pipeline/tmgr.h
new file mode 100644
index 0000000..0b497e7
--- /dev/null
+++ b/examples/ip_pipeline/tmgr.h
@@ -0,0 +1,70 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#ifndef _INCLUDE_TMGR_H_
+#define _INCLUDE_TMGR_H_
+
+#include <stdint.h>
+#include <sys/queue.h>
+
+#include <rte_sched.h>
+
+#include "common.h"
+
+#ifndef TMGR_SUBPORT_PROFILE_MAX
+#define TMGR_SUBPORT_PROFILE_MAX                           256
+#endif
+
+#ifndef TMGR_PIPE_PROFILE_MAX
+#define TMGR_PIPE_PROFILE_MAX                              256
+#endif
+
+struct tmgr_port {
+	TAILQ_ENTRY(tmgr_port) node;
+	char name[NAME_SIZE];
+	struct rte_sched_port *s;
+	uint32_t n_subports_per_port;
+	uint32_t n_pipes_per_subport;
+};
+
+TAILQ_HEAD(tmgr_port_list, tmgr_port);
+
+int
+tmgr_init(void);
+
+struct tmgr_port *
+tmgr_port_find(const char *name);
+
+struct tmgr_port_params {
+	uint32_t rate;
+	uint32_t n_subports_per_port;
+	uint32_t n_pipes_per_subport;
+	uint16_t qsize[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
+	uint32_t frame_overhead;
+	uint32_t mtu;
+	uint32_t cpu_id;
+};
+
+int
+tmgr_subport_profile_add(struct rte_sched_subport_params *p);
+
+int
+tmgr_pipe_profile_add(struct rte_sched_pipe_params *p);
+
+struct tmgr_port *
+tmgr_port_create(const char *name, struct tmgr_port_params *params);
+
+int
+tmgr_subport_config(const char *port_name,
+	uint32_t subport_id,
+	uint32_t subport_profile_id);
+
+int
+tmgr_pipe_config(const char *port_name,
+	uint32_t subport_id,
+	uint32_t pipe_id_first,
+	uint32_t pipe_id_last,
+	uint32_t pipe_profile_id);
+
+#endif /* _INCLUDE_TMGR_H_ */
-- 
2.9.3

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

* [dpdk-dev] [PATCH v4 26/49] ip_pipeline: add tap object
  2018-03-29 18:31           ` [dpdk-dev] [PATCH v4 00/49] ip_pipeline: refactoring Jasvinder Singh
                               ` (24 preceding siblings ...)
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 25/49] ip_pipeline: add traffic manager object Jasvinder Singh
@ 2018-03-29 18:31             ` Jasvinder Singh
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 27/49] ip_pipeline: add kni object Jasvinder Singh
                               ` (23 subsequent siblings)
  49 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-29 18:31 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Kevin Laatz

Add tap object implementation to the application

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
---
 examples/ip_pipeline/Makefile    |  1 +
 examples/ip_pipeline/cli.c       | 32 +++++++++++++
 examples/ip_pipeline/main.c      |  8 ++++
 examples/ip_pipeline/meson.build |  1 +
 examples/ip_pipeline/tap.c       | 97 ++++++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/tap.h       | 29 ++++++++++++
 6 files changed, 168 insertions(+)
 create mode 100644 examples/ip_pipeline/tap.c
 create mode 100644 examples/ip_pipeline/tap.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index 35e4302..0f6bb78 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -12,6 +12,7 @@ SRCS-y += main.c
 SRCS-y += mempool.c
 SRCS-y += parser.c
 SRCS-y += swq.c
+SRCS-y += tap.c
 SRCS-y += tmgr.c
 #SRCS-y += thread.c
 
diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index fd80ba5..bcc87f2 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -14,6 +14,7 @@
 #include "mempool.h"
 #include "parser.h"
 #include "swq.h"
+#include "tap.h"
 #include "tmgr.h"
 
 #ifndef CMD_MAX_TOKENS
@@ -603,6 +604,32 @@ cmd_tmgr_subport_pipe(char **tokens,
 	}
 }
 
+/**
+ * tap <tap_name>
+ */
+static void
+cmd_tap(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	char *name;
+	struct tap *tap;
+
+	if (n_tokens != 2) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	name = tokens[1];
+
+	tap = tap_create(name);
+	if (tap == NULL) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
 void
 cli_process(char *in, char *out, size_t out_size)
 {
@@ -671,6 +698,11 @@ cli_process(char *in, char *out, size_t out_size)
 		return;
 	}
 
+	if (strcmp(tokens[0], "tap") == 0) {
+		cmd_tap(tokens, n_tokens, out, out_size);
+		return;
+	}
+
 	snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
 }
 
diff --git a/examples/ip_pipeline/main.c b/examples/ip_pipeline/main.c
index 490991f..33c3354 100644
--- a/examples/ip_pipeline/main.c
+++ b/examples/ip_pipeline/main.c
@@ -15,6 +15,7 @@
 #include "link.h"
 #include "mempool.h"
 #include "swq.h"
+#include "tap.h"
 #include "tmgr.h"
 
 static const char usage[] =
@@ -191,6 +192,13 @@ main(int argc, char **argv)
 		return status;
 	}
 
+	/* TAP */
+	status = tap_init();
+	if (status) {
+		printf("Error: TAP initialization failed (%d)\n", status);
+		return status;
+	}
+
 	/* Script */
 	if (app.script_name)
 		cli_script_process(app.script_name,
diff --git a/examples/ip_pipeline/meson.build b/examples/ip_pipeline/meson.build
index cb2154c..e875811 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -15,5 +15,6 @@ sources = files(
 	'mempool.c',
 	'parser.c',
 	'swq.c',
+	'tap.c',
 	'tmgr.c'
 )
diff --git a/examples/ip_pipeline/tap.c b/examples/ip_pipeline/tap.c
new file mode 100644
index 0000000..5b34032
--- /dev/null
+++ b/examples/ip_pipeline/tap.c
@@ -0,0 +1,97 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#include <netinet/in.h>
+#ifdef RTE_EXEC_ENV_LINUXAPP
+#include <linux/if.h>
+#include <linux/if_tun.h>
+#endif
+#include <sys/ioctl.h>
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "tap.h"
+
+#define TAP_DEV                                            "/dev/net/tun"
+
+static struct tap_list tap_list;
+
+int
+tap_init(void)
+{
+	TAILQ_INIT(&tap_list);
+
+	return 0;
+}
+
+struct tap *
+tap_find(const char *name)
+{
+	struct tap *tap;
+
+	if (name == NULL)
+		return NULL;
+
+	TAILQ_FOREACH(tap, &tap_list, node)
+		if (strcmp(tap->name, name) == 0)
+			return tap;
+
+	return NULL;
+}
+
+#ifndef RTE_EXEC_ENV_LINUXAPP
+
+struct tap *
+tap_create(const char *name __rte_unused)
+{
+	return NULL;
+}
+
+#else
+
+struct tap *
+tap_create(const char *name)
+{
+	struct tap *tap;
+	struct ifreq ifr;
+	int fd, status;
+
+	/* Check input params */
+	if ((name == NULL) ||
+		tap_find(name))
+		return NULL;
+
+	/* Resource create */
+	fd = open(TAP_DEV, O_RDWR | O_NONBLOCK);
+	if (fd < 0)
+		return NULL;
+
+	memset(&ifr, 0, sizeof(ifr));
+	ifr.ifr_flags = IFF_TAP | IFF_NO_PI; /* No packet information */
+	snprintf(ifr.ifr_name, IFNAMSIZ, "%s", name);
+
+	status = ioctl(fd, TUNSETIFF, (void *) &ifr);
+	if (status < 0)
+		return NULL;
+
+	/* Node allocation */
+	tap = calloc(1, sizeof(struct tap));
+	if (tap == NULL)
+		return NULL;
+
+	/* Node fill in */
+	strncpy(tap->name, name, sizeof(tap->name));
+	tap->fd = fd;
+
+	/* Node add to list */
+	TAILQ_INSERT_TAIL(&tap_list, tap, node);
+
+	return tap;
+}
+
+#endif
diff --git a/examples/ip_pipeline/tap.h b/examples/ip_pipeline/tap.h
new file mode 100644
index 0000000..0dce72f
--- /dev/null
+++ b/examples/ip_pipeline/tap.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#ifndef _INCLUDE_TAP_H_
+#define _INCLUDE_TAP_H_
+
+#include <sys/queue.h>
+
+#include "common.h"
+
+struct tap {
+	TAILQ_ENTRY(tap) node;
+	char name[NAME_SIZE];
+	int fd;
+};
+
+TAILQ_HEAD(tap_list, tap);
+
+int
+tap_init(void);
+
+struct tap *
+tap_find(const char *name);
+
+struct tap *
+tap_create(const char *name);
+
+#endif /* _INCLUDE_TAP_H_ */
-- 
2.9.3

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

* [dpdk-dev] [PATCH v4 27/49] ip_pipeline: add kni object
  2018-03-29 18:31           ` [dpdk-dev] [PATCH v4 00/49] ip_pipeline: refactoring Jasvinder Singh
                               ` (25 preceding siblings ...)
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 26/49] ip_pipeline: add tap object Jasvinder Singh
@ 2018-03-29 18:31             ` Jasvinder Singh
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 28/49] ip_pipeline: add action profile object Jasvinder Singh
                               ` (22 subsequent siblings)
  49 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-29 18:31 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Kevin Laatz

Add kni object implementation to the application.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
---
 examples/ip_pipeline/Makefile    |   1 +
 examples/ip_pipeline/cli.c       |  65 +++++++++++++++
 examples/ip_pipeline/kni.c       | 167 +++++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/kni.h       |  44 +++++++++++
 examples/ip_pipeline/main.c      |  10 +++
 examples/ip_pipeline/meson.build |   1 +
 6 files changed, 288 insertions(+)
 create mode 100644 examples/ip_pipeline/kni.c
 create mode 100644 examples/ip_pipeline/kni.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index 0f6bb78..dc56ebf 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -7,6 +7,7 @@ APP = ip_pipeline
 # all source are stored in SRCS-y
 SRCS-y := cli.c
 SRCS-y += conn.c
+SRCS-y += kni.c
 SRCS-y += link.c
 SRCS-y += main.c
 SRCS-y += mempool.c
diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index bcc87f2..f481e2c 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -10,6 +10,7 @@
 #include <rte_common.h>
 
 #include "cli.h"
+#include "kni.h"
 #include "link.h"
 #include "mempool.h"
 #include "parser.h"
@@ -630,6 +631,65 @@ cmd_tap(char **tokens,
 	}
 }
 
+/**
+ * kni <kni_name>
+ *  link <link_name>
+ *  mempool <mempool_name>
+ *  [thread <thread_id>]
+ */
+static void
+cmd_kni(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct kni_params p;
+	char *name;
+	struct kni *kni;
+
+	if ((n_tokens != 6) && (n_tokens != 8)) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	name = tokens[1];
+
+	if (strcmp(tokens[2], "link") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "link");
+		return;
+	}
+
+	p.link_name = tokens[3];
+
+	if (strcmp(tokens[4], "mempool") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mempool");
+		return;
+	}
+
+	p.mempool_name = tokens[5];
+
+	if (n_tokens == 8) {
+		if (strcmp(tokens[6], "thread") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "thread");
+			return;
+		}
+
+		if (parser_read_uint32(&p.thread_id, tokens[7]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
+			return;
+		}
+
+		p.force_bind = 1;
+	} else
+		p.force_bind = 0;
+
+	kni = kni_create(name, &p);
+	if (kni == NULL) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
 void
 cli_process(char *in, char *out, size_t out_size)
 {
@@ -703,6 +763,11 @@ cli_process(char *in, char *out, size_t out_size)
 		return;
 	}
 
+	if (strcmp(tokens[0], "kni") == 0) {
+		cmd_kni(tokens, n_tokens, out, out_size);
+		return;
+	}
+
 	snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
 }
 
diff --git a/examples/ip_pipeline/kni.c b/examples/ip_pipeline/kni.c
new file mode 100644
index 0000000..c8a9fbe
--- /dev/null
+++ b/examples/ip_pipeline/kni.c
@@ -0,0 +1,167 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <rte_ethdev.h>
+#include <rte_bus_pci.h>
+
+#include "kni.h"
+#include "mempool.h"
+#include "link.h"
+
+static struct kni_list kni_list;
+
+#ifndef KNI_MAX
+#define KNI_MAX                                            16
+#endif
+
+int
+kni_init(void)
+{
+	TAILQ_INIT(&kni_list);
+
+#ifdef RTE_LIBRTE_KNI
+	rte_kni_init(KNI_MAX);
+#endif
+
+	return 0;
+}
+
+struct kni *
+kni_find(const char *name)
+{
+	struct kni *kni;
+
+	if (name == NULL)
+		return NULL;
+
+	TAILQ_FOREACH(kni, &kni_list, node)
+		if (strcmp(kni->name, name) == 0)
+			return kni;
+
+	return NULL;
+}
+
+#ifndef RTE_LIBRTE_KNI
+
+struct kni *
+kni_create(const char *name __rte_unused,
+	struct kni_params *params __rte_unused)
+{
+	return NULL;
+}
+
+void
+kni_handle_request(void)
+{
+	return 0;
+}
+
+#else
+
+static int
+kni_config_network_interface(uint16_t port_id, uint8_t if_up)
+{
+	int ret = 0;
+
+	if (port_id >= rte_eth_dev_count())
+		return -EINVAL;
+
+	ret = (if_up) ?
+		rte_eth_dev_set_link_up(port_id) :
+		rte_eth_dev_set_link_down(port_id);
+
+	return ret;
+}
+
+static int
+kni_change_mtu(uint16_t port_id, unsigned int new_mtu)
+{
+	int ret;
+
+	if (port_id >= rte_eth_dev_count())
+		return -EINVAL;
+
+	if (new_mtu > ETHER_MAX_LEN)
+		return -EINVAL;
+
+	/* Set new MTU */
+	ret = rte_eth_dev_set_mtu(port_id, new_mtu);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+struct kni *
+kni_create(const char *name, struct kni_params *params)
+{
+	struct rte_eth_dev_info dev_info;
+	struct rte_kni_conf kni_conf;
+	struct rte_kni_ops kni_ops;
+	struct kni *kni;
+	struct mempool *mempool;
+	struct link *link;
+	struct rte_kni *k;
+
+	/* Check input params */
+	if ((name == NULL) ||
+		kni_find(name) ||
+		(params == NULL))
+		return NULL;
+
+	mempool = mempool_find(params->mempool_name);
+	link = link_find(params->link_name);
+	if ((mempool == NULL) ||
+		(link == NULL))
+		return NULL;
+
+	/* Resource create */
+	rte_eth_dev_info_get(link->port_id, &dev_info);
+
+	memset(&kni_conf, 0, sizeof(kni_conf));
+	snprintf(kni_conf.name, RTE_KNI_NAMESIZE, "%s", name);
+	kni_conf.force_bind = params->force_bind;
+	kni_conf.core_id = params->thread_id;
+	kni_conf.group_id = link->port_id;
+	kni_conf.mbuf_size = mempool->buffer_size;
+	kni_conf.addr = dev_info.pci_dev->addr;
+	kni_conf.id = dev_info.pci_dev->id;
+
+	memset(&kni_ops, 0, sizeof(kni_ops));
+	kni_ops.port_id = link->port_id;
+	kni_ops.config_network_if = kni_config_network_interface;
+	kni_ops.change_mtu = kni_change_mtu;
+
+	k = rte_kni_alloc(mempool->m, &kni_conf, &kni_ops);
+	if (k == NULL)
+		return NULL;
+
+	/* Node allocation */
+	kni = calloc(1, sizeof(struct kni));
+	if (kni == NULL)
+		return NULL;
+
+	/* Node fill in */
+	strncpy(kni->name, name, sizeof(kni->name));
+	kni->k = k;
+
+	/* Node add to list */
+	TAILQ_INSERT_TAIL(&kni_list, kni, node);
+
+	return kni;
+}
+
+void
+kni_handle_request(void)
+{
+	struct kni *kni;
+
+	TAILQ_FOREACH(kni, &kni_list, node)
+		rte_kni_handle_request(kni->k);
+}
+
+#endif
diff --git a/examples/ip_pipeline/kni.h b/examples/ip_pipeline/kni.h
new file mode 100644
index 0000000..e53de12
--- /dev/null
+++ b/examples/ip_pipeline/kni.h
@@ -0,0 +1,44 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#ifndef _INCLUDE_KNI_H_
+#define _INCLUDE_KNI_H_
+
+#include <stdint.h>
+#include <sys/queue.h>
+
+#ifdef RTE_LIBRTE_KNI
+#include <rte_kni.h>
+#endif
+
+#include "common.h"
+
+struct kni {
+	TAILQ_ENTRY(kni) node;
+	char name[NAME_SIZE];
+	struct rte_kni *k;
+};
+
+TAILQ_HEAD(kni_list, kni);
+
+int
+kni_init(void);
+
+struct kni *
+kni_find(const char *name);
+
+struct kni_params {
+	const char *link_name;
+	const char *mempool_name;
+	int force_bind;
+	uint32_t thread_id;
+};
+
+struct kni *
+kni_create(const char *name, struct kni_params *params);
+
+void
+kni_handle_request(void);
+
+#endif /* _INCLUDE_KNI_H_ */
diff --git a/examples/ip_pipeline/main.c b/examples/ip_pipeline/main.c
index 33c3354..b65762e 100644
--- a/examples/ip_pipeline/main.c
+++ b/examples/ip_pipeline/main.c
@@ -12,6 +12,7 @@
 
 #include "cli.h"
 #include "conn.h"
+#include "kni.h"
 #include "link.h"
 #include "mempool.h"
 #include "swq.h"
@@ -199,6 +200,13 @@ main(int argc, char **argv)
 		return status;
 	}
 
+	/* KNI */
+	status = kni_init();
+	if (status) {
+		printf("Error: KNI initialization failed (%d)\n", status);
+		return status;
+	}
+
 	/* Script */
 	if (app.script_name)
 		cli_script_process(app.script_name,
@@ -210,5 +218,7 @@ main(int argc, char **argv)
 		conn_poll_for_conn(conn);
 
 		conn_poll_for_msg(conn);
+
+		kni_handle_request();
 	}
 }
diff --git a/examples/ip_pipeline/meson.build b/examples/ip_pipeline/meson.build
index e875811..5ad79b2 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -10,6 +10,7 @@ deps += ['pipeline', 'bus_pci']
 sources = files(
 	'cli.c',
 	'conn.c',
+	'kni.c',
 	'link.c',
 	'main.c',
 	'mempool.c',
-- 
2.9.3

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

* [dpdk-dev] [PATCH v4 28/49] ip_pipeline: add action profile object
  2018-03-29 18:31           ` [dpdk-dev] [PATCH v4 00/49] ip_pipeline: refactoring Jasvinder Singh
                               ` (26 preceding siblings ...)
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 27/49] ip_pipeline: add kni object Jasvinder Singh
@ 2018-03-29 18:31             ` Jasvinder Singh
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 29/49] ip_pipeline: add pipeline object Jasvinder Singh
                               ` (21 subsequent siblings)
  49 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-29 18:31 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Fan Zhang

Add action profile object implementation to the application.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Fan Zhang <roy.fan.zhang@intel.com>
---
 examples/ip_pipeline/Makefile    |   4 +-
 examples/ip_pipeline/action.c    | 278 +++++++++++++++++++++++
 examples/ip_pipeline/action.h    |  76 +++++++
 examples/ip_pipeline/cli.c       | 477 +++++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/cli.h       |   2 +
 examples/ip_pipeline/main.c      |  14 ++
 examples/ip_pipeline/meson.build |   2 +
 7 files changed, 852 insertions(+), 1 deletion(-)
 create mode 100644 examples/ip_pipeline/action.c
 create mode 100644 examples/ip_pipeline/action.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index dc56ebf..d9c8d86 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -5,7 +5,8 @@
 APP = ip_pipeline
 
 # all source are stored in SRCS-y
-SRCS-y := cli.c
+SRCS-y := action.c
+SRCS-y += cli.c
 SRCS-y += conn.c
 SRCS-y += kni.c
 SRCS-y += link.c
@@ -69,6 +70,7 @@ INC += $(sort $(wildcard *.h))
 
 SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) := $(SRCS-y)
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -I$(SRCDIR)
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
diff --git a/examples/ip_pipeline/action.c b/examples/ip_pipeline/action.c
new file mode 100644
index 0000000..9db6dba
--- /dev/null
+++ b/examples/ip_pipeline/action.c
@@ -0,0 +1,278 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "action.h"
+#include "hash_func.h"
+
+/**
+ * Input port
+ */
+static struct port_in_action_profile_list port_in_action_profile_list;
+
+int
+port_in_action_profile_init(void)
+{
+	TAILQ_INIT(&port_in_action_profile_list);
+
+	return 0;
+}
+
+struct port_in_action_profile *
+port_in_action_profile_find(const char *name)
+{
+	struct port_in_action_profile *profile;
+
+	if (name == NULL)
+		return NULL;
+
+	TAILQ_FOREACH(profile, &port_in_action_profile_list, node)
+		if (strcmp(profile->name, name) == 0)
+			return profile;
+
+	return NULL;
+}
+
+struct port_in_action_profile *
+port_in_action_profile_create(const char *name,
+	struct port_in_action_profile_params *params)
+{
+	struct port_in_action_profile *profile;
+	struct rte_port_in_action_profile *ap;
+	int status;
+
+	/* Check input params */
+	if ((name == NULL) ||
+		port_in_action_profile_find(name) ||
+		(params == NULL))
+		return NULL;
+
+	if ((params->action_mask & (1LLU << RTE_PORT_IN_ACTION_LB)) &&
+		(params->lb.f_hash == NULL)) {
+		switch (params->lb.key_size) {
+		case  8: params->lb.f_hash = hash_default_key8; break;
+		case 16: params->lb.f_hash = hash_default_key16; break;
+		case 24: params->lb.f_hash = hash_default_key24; break;
+		case 32: params->lb.f_hash = hash_default_key32; break;
+		case 40: params->lb.f_hash = hash_default_key40; break;
+		case 48: params->lb.f_hash = hash_default_key48; break;
+		case 56: params->lb.f_hash = hash_default_key56; break;
+		case 64: params->lb.f_hash = hash_default_key64; break;
+		default: return NULL;
+		}
+
+		params->lb.seed = 0;
+	}
+	/* Resource */
+	ap = rte_port_in_action_profile_create(0);
+	if(ap == NULL)
+		return NULL;
+
+	if (params->action_mask & (1LLU << RTE_PORT_IN_ACTION_FLTR)) {
+		status = rte_port_in_action_profile_action_register(ap,
+			RTE_PORT_IN_ACTION_FLTR,
+			&params->fltr);
+
+		if (status) {
+			rte_port_in_action_profile_free(ap);
+			return NULL;
+		}
+	}
+
+	if (params->action_mask & (1LLU << RTE_PORT_IN_ACTION_LB)) {
+		status = rte_port_in_action_profile_action_register(ap,
+			RTE_PORT_IN_ACTION_LB,
+			&params->lb);
+
+		if (status) {
+			rte_port_in_action_profile_free(ap);
+			return NULL;
+		}
+	}
+
+	status = rte_port_in_action_profile_freeze(ap);
+	if (status) {
+		rte_port_in_action_profile_free(ap);
+		return NULL;
+	}
+
+	/* Node allocation */
+	profile = calloc(1, sizeof(struct port_in_action_profile));
+	if (profile == NULL) {
+		rte_port_in_action_profile_free(ap);
+		return NULL;
+	}
+
+	/* Node fill in */
+	strncpy(profile->name, name, sizeof(profile->name));
+	memcpy(&profile->params, params, sizeof(*params));
+	profile->ap = ap;
+
+	/* Node add to list */
+	TAILQ_INSERT_TAIL(&port_in_action_profile_list, profile, node);
+
+	return profile;
+}
+
+/**
+ * Table
+ */
+static struct table_action_profile_list table_action_profile_list;
+
+int
+table_action_profile_init(void)
+{
+	TAILQ_INIT(&table_action_profile_list);
+
+	return 0;
+}
+
+struct table_action_profile *
+table_action_profile_find(const char *name)
+{
+	struct table_action_profile *profile;
+
+	if (name == NULL)
+		return NULL;
+
+	TAILQ_FOREACH(profile, &table_action_profile_list, node)
+		if (strcmp(profile->name, name) == 0)
+			return profile;
+
+	return NULL;
+}
+
+struct table_action_profile *
+table_action_profile_create(const char *name,
+	struct table_action_profile_params *params)
+{
+	struct table_action_profile *profile;
+	struct rte_table_action_profile *ap;
+	int status;
+
+	/* Check input params */
+	if ((name == NULL) ||
+		table_action_profile_find(name) ||
+		(params == NULL) ||
+		((params->action_mask & (1LLU << RTE_TABLE_ACTION_FWD)) == 0))
+		return NULL;
+
+	/* Resource */
+	ap = rte_table_action_profile_create(&params->common);
+	if (ap == NULL)
+		return NULL;
+
+	if (params->action_mask & (1LLU << RTE_TABLE_ACTION_FWD)) {
+		status = rte_table_action_profile_action_register(ap,
+			RTE_TABLE_ACTION_FWD,
+			NULL);
+
+		if (status) {
+			rte_table_action_profile_free(ap);
+			return NULL;
+		}
+	}
+
+	if (params->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) {
+		status = rte_table_action_profile_action_register(ap,
+			RTE_TABLE_ACTION_MTR,
+			&params->mtr);
+
+		if (status) {
+			rte_table_action_profile_free(ap);
+			return NULL;
+		}
+	}
+
+	if (params->action_mask & (1LLU << RTE_TABLE_ACTION_TM)) {
+		status = rte_table_action_profile_action_register(ap,
+			RTE_TABLE_ACTION_TM,
+			&params->tm);
+
+		if (status) {
+			rte_table_action_profile_free(ap);
+			return NULL;
+		}
+	}
+
+	if (params->action_mask & (1LLU << RTE_TABLE_ACTION_ENCAP)) {
+		status = rte_table_action_profile_action_register(ap,
+			RTE_TABLE_ACTION_ENCAP,
+			&params->encap);
+
+		if (status) {
+			rte_table_action_profile_free(ap);
+			return NULL;
+		}
+	}
+
+	if (params->action_mask & (1LLU << RTE_TABLE_ACTION_NAT)) {
+		status = rte_table_action_profile_action_register(ap,
+			RTE_TABLE_ACTION_NAT,
+			&params->nat);
+
+		if (status) {
+			rte_table_action_profile_free(ap);
+			return NULL;
+		}
+	}
+
+	if (params->action_mask & (1LLU << RTE_TABLE_ACTION_TTL)) {
+		status = rte_table_action_profile_action_register(ap,
+			RTE_TABLE_ACTION_TTL,
+			&params->ttl);
+
+		if (status) {
+			rte_table_action_profile_free(ap);
+			return NULL;
+		}
+	}
+
+	if (params->action_mask & (1LLU << RTE_TABLE_ACTION_STATS)) {
+		status = rte_table_action_profile_action_register(ap,
+			RTE_TABLE_ACTION_STATS,
+			&params->stats);
+
+		if (status) {
+			rte_table_action_profile_free(ap);
+			return NULL;
+		}
+	}
+	if (params->action_mask & (1LLU << RTE_TABLE_ACTION_TIME)) {
+		status = rte_table_action_profile_action_register(ap,
+			RTE_TABLE_ACTION_TIME,
+			NULL);
+
+		if (status) {
+			rte_table_action_profile_free(ap);
+			return NULL;
+		}
+	}
+
+	status = rte_table_action_profile_freeze(ap);
+	if (status) {
+		rte_table_action_profile_free(ap);
+		return NULL;
+	}
+
+	/* Node allocation */
+	profile = calloc(1, sizeof(struct table_action_profile));
+	if (profile == NULL) {
+		rte_table_action_profile_free(ap);
+		return NULL;
+	}
+
+	/* Node fill in */
+	strncpy(profile->name, name, sizeof(profile->name));
+	memcpy(&profile->params, params, sizeof(*params));
+	profile->ap = ap;
+
+	/* Node add to list */
+	TAILQ_INSERT_TAIL(&table_action_profile_list, profile, node);
+
+	return profile;
+}
diff --git a/examples/ip_pipeline/action.h b/examples/ip_pipeline/action.h
new file mode 100644
index 0000000..98b5032
--- /dev/null
+++ b/examples/ip_pipeline/action.h
@@ -0,0 +1,76 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#ifndef _INCLUDE_ACTION_H_
+#define _INCLUDE_ACTION_H_
+
+#include <sys/queue.h>
+
+#include <rte_port_in_action.h>
+#include <rte_table_action.h>
+
+#include "common.h"
+
+/**
+ * Input port action
+ */
+struct port_in_action_profile_params {
+	uint64_t action_mask;
+	struct rte_port_in_action_fltr_config fltr;
+	struct rte_port_in_action_lb_config lb;
+};
+
+struct port_in_action_profile {
+	TAILQ_ENTRY(port_in_action_profile) node;
+	char name[NAME_SIZE];
+	struct port_in_action_profile_params params;
+	struct rte_port_in_action_profile *ap;
+};
+
+TAILQ_HEAD(port_in_action_profile_list, port_in_action_profile);
+
+int
+port_in_action_profile_init(void);
+
+struct port_in_action_profile *
+port_in_action_profile_find(const char *name);
+
+struct port_in_action_profile *
+port_in_action_profile_create(const char *name,
+	struct port_in_action_profile_params *params);
+
+/**
+ * Table action
+ */
+struct table_action_profile_params {
+	uint64_t action_mask;
+	struct rte_table_action_common_config common;
+	struct rte_table_action_mtr_config mtr;
+	struct rte_table_action_tm_config tm;
+	struct rte_table_action_encap_config encap;
+	struct rte_table_action_nat_config nat;
+	struct rte_table_action_ttl_config ttl;
+	struct rte_table_action_stats_config stats;
+};
+
+struct table_action_profile {
+	TAILQ_ENTRY(table_action_profile) node;
+	char name[NAME_SIZE];
+	struct table_action_profile_params params;
+	struct rte_table_action_profile *ap;
+};
+
+TAILQ_HEAD(table_action_profile_list, table_action_profile);
+
+int
+table_action_profile_init(void);
+
+struct table_action_profile *
+table_action_profile_find(const char *name);
+
+struct table_action_profile *
+table_action_profile_create(const char *name,
+	struct table_action_profile_params *params);
+
+#endif /* _INCLUDE_ACTION_H_ */
diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index f481e2c..9f42d8f 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -690,6 +690,473 @@ cmd_kni(char **tokens,
 	}
 }
 
+/**
+ * port in action profile <profile_name>
+ *  [filter match | mismatch offset <key_offset> mask <key_mask> key <key_value> port <port_id>]
+ *  [balance offset <key_offset> mask <key_mask> port <port_id0> ... <port_id15>]
+ */
+static void
+cmd_port_in_action_profile(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct port_in_action_profile_params p;
+	struct port_in_action_profile *ap;
+	char *name;
+	uint32_t t0;
+
+	memset(&p, 0, sizeof(p));
+
+	if (n_tokens < 5) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	if (strcmp(tokens[1], "in") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
+		return;
+	}
+
+	if (strcmp(tokens[2], "action") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "action");
+		return;
+	}
+
+	if (strcmp(tokens[3], "profile") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
+		return;
+	}
+
+	name = tokens[4];
+
+	t0 = 5;
+
+	if ((t0 < n_tokens) && (strcmp(tokens[t0], "filter") == 0)) {
+		uint32_t size;
+
+		if (n_tokens < t0 + 10) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH, "port in action profile filter");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 1], "match") == 0)
+			p.fltr.filter_on_match = 1;
+		else if (strcmp(tokens[t0 + 1], "mismatch") == 0)
+			p.fltr.filter_on_match = 0;
+		else {
+			snprintf(out, out_size, MSG_ARG_INVALID, "match or mismatch");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 2], "offset") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
+			return;
+		}
+
+		if (parser_read_uint32(&p.fltr.key_offset, tokens[t0 + 3]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 4], "mask") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask");
+			return;
+		}
+
+		size = RTE_PORT_IN_ACTION_FLTR_KEY_SIZE;
+		if ((parse_hex_string(tokens[t0 + 5], p.fltr.key_mask, &size) != 0) ||
+			(size != RTE_PORT_IN_ACTION_FLTR_KEY_SIZE)) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "key_mask");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 6], "key") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "key");
+			return;
+		}
+
+		size = RTE_PORT_IN_ACTION_FLTR_KEY_SIZE;
+		if ((parse_hex_string(tokens[t0 + 7], p.fltr.key, &size) != 0) ||
+			(size != RTE_PORT_IN_ACTION_FLTR_KEY_SIZE)) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "key_value");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 8], "port") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
+			return;
+		}
+
+		if (parser_read_uint32(&p.fltr.port_id, tokens[t0 + 9]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
+			return;
+		}
+
+		p.action_mask |= 1LLU << RTE_PORT_IN_ACTION_FLTR;
+		t0 += 10;
+	} /* filter */
+
+	if ((t0 < n_tokens) && (strcmp(tokens[t0], "balance") == 0)) {
+		uint32_t i;
+
+		if (n_tokens < t0 + 22) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH, "port in action profile balance");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 1], "offset") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
+			return;
+		}
+
+		if (parser_read_uint32(&p.lb.key_offset, tokens[t0 + 2]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 3], "mask") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask");
+			return;
+		}
+
+		p.lb.key_size = RTE_PORT_IN_ACTION_LB_KEY_SIZE_MAX;
+		if (parse_hex_string(tokens[t0 + 4], p.lb.key_mask, &p.lb.key_size) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "key_mask");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 5], "port") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
+			return;
+		}
+
+		for (i = 0; i < 16; i++)
+			if (parser_read_uint32(&p.lb.port_id[i], tokens[t0 + 6 + i]) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
+				return;
+			}
+
+		p.action_mask |= 1LLU << RTE_PORT_IN_ACTION_LB;
+		t0 += 22;
+	} /* balance */
+
+	if (t0 < n_tokens) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	ap = port_in_action_profile_create(name, &p);
+	if (ap == NULL) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
+ * table action profile <profile_name>
+ *  ipv4 | ipv6
+ *  offset <ip_offset>
+ *  fwd
+ *  [meter srtcm | trtcm
+ *      tc <n_tc>
+ *      stats none | pkts | bytes | both]
+ *  [tm spp <n_subports_per_port> pps <n_pipes_per_subport>]
+ *  [encap ether | vlan | qinq | mpls | pppoe]
+ *  [nat src | dst
+ *      proto udp | tcp]
+ *  [ttl drop | fwd
+ *      stats none | pkts]
+ *  [stats pkts | bytes | both]
+ *  [time]
+ */
+static void
+cmd_table_action_profile(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct table_action_profile_params p;
+	struct table_action_profile *ap;
+	char *name;
+	uint32_t t0;
+
+	memset(&p, 0, sizeof(p));
+
+	if (n_tokens < 8) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	if (strcmp(tokens[1], "action") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "action");
+		return;
+	}
+
+	if (strcmp(tokens[2], "profile") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
+		return;
+	}
+
+	name = tokens[3];
+
+	if (strcmp(tokens[4], "ipv4") == 0)
+		p.common.ip_version = 1;
+	else if (strcmp(tokens[4], "ipv6") == 0)
+		p.common.ip_version = 0;
+	else {
+		snprintf(out, out_size, MSG_ARG_INVALID, "ipv4 or ipv6");
+		return;
+	}
+
+	if (strcmp(tokens[5], "offset") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
+		return;
+	}
+
+	if (parser_read_uint32(&p.common.ip_offset, tokens[6]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "ip_offset");
+		return;
+	}
+
+	if (strcmp(tokens[7], "fwd") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "fwd");
+		return;
+	}
+
+	p.action_mask |= 1LLU << RTE_TABLE_ACTION_FWD;
+
+	t0 = 8;
+	if ((t0 < n_tokens) && (strcmp(tokens[t0], "meter") == 0)) {
+		if (n_tokens < t0 + 6) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"table action profile meter");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 1], "srtcm") == 0)
+			p.mtr.alg = RTE_TABLE_ACTION_METER_SRTCM;
+		else if (strcmp(tokens[t0 + 1], "trtcm") == 0)
+			p.mtr.alg = RTE_TABLE_ACTION_METER_TRTCM;
+		else {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+				"srtcm or trtcm");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 2], "tc") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc");
+			return;
+		}
+
+		if (parser_read_uint32(&p.mtr.n_tc, tokens[t0 + 3]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "n_tc");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 4], "stats") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 5], "none") == 0) {
+			p.mtr.n_packets_enabled = 0;
+			p.mtr.n_bytes_enabled = 0;
+		} else if (strcmp(tokens[t0 + 5], "pkts") == 0) {
+			p.mtr.n_packets_enabled = 1;
+			p.mtr.n_bytes_enabled = 0;
+		} else if (strcmp(tokens[t0 + 5], "bytes") == 0) {
+			p.mtr.n_packets_enabled = 0;
+			p.mtr.n_bytes_enabled = 1;
+		} else if (strcmp(tokens[t0 + 5], "both") == 0) {
+			p.mtr.n_packets_enabled = 1;
+			p.mtr.n_bytes_enabled = 1;
+		} else {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+				"none or pkts or bytes or both");
+			return;
+		}
+
+		p.action_mask |= 1LLU << RTE_TABLE_ACTION_MTR;
+		t0 += 6;
+	} /* meter */
+
+	if ((t0 < n_tokens) && (strcmp(tokens[t0], "tm") == 0)) {
+		if (n_tokens < t0 + 5) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"table action profile tm");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 1], "spp") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "spp");
+			return;
+		}
+
+		if (parser_read_uint32(&p.tm.n_subports_per_port,
+			tokens[t0 + 2]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID,
+				"n_subports_per_port");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 3], "pps") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pps");
+			return;
+		}
+
+		if (parser_read_uint32(&p.tm.n_pipes_per_subport,
+			tokens[t0 + 4]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID,
+				"n_pipes_per_subport");
+			return;
+		}
+
+		p.action_mask |= 1LLU << RTE_TABLE_ACTION_TM;
+		t0 += 5;
+	} /* tm */
+
+	if ((t0 < n_tokens) && (strcmp(tokens[t0], "encap") == 0)) {
+		if (n_tokens < t0 + 2) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"action profile encap");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 1], "ether") == 0)
+			p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_ETHER;
+		else if (strcmp(tokens[t0 + 1], "vlan") == 0)
+			p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_VLAN;
+		else if (strcmp(tokens[t0 + 1], "qinq") == 0)
+			p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_QINQ;
+		else if (strcmp(tokens[t0 + 1], "mpls") == 0)
+			p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_MPLS;
+		else if (strcmp(tokens[t0 + 1], "pppoe") == 0)
+			p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_PPPOE;
+		else {
+			snprintf(out, out_size, MSG_ARG_MISMATCH, "encap");
+			return;
+		}
+
+		p.action_mask |= 1LLU << RTE_TABLE_ACTION_ENCAP;
+		t0 += 2;
+	} /* encap */
+
+	if ((t0 < n_tokens) && (strcmp(tokens[t0], "nat") == 0)) {
+		if (n_tokens < t0 + 4) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"table action profile nat");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 1], "src") == 0)
+			p.nat.source_nat = 1;
+		else if (strcmp(tokens[t0 + 1], "dst") == 0)
+			p.nat.source_nat = 0;
+		else {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+				"src or dst");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 2], "proto") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "proto");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 3], "tcp") == 0)
+			p.nat.proto = 0x06;
+		else if (strcmp(tokens[t0 + 3], "udp") == 0)
+			p.nat.proto = 0x11;
+		else {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+				"tcp or udp");
+			return;
+		}
+
+		p.action_mask |= 1LLU << RTE_TABLE_ACTION_NAT;
+		t0 += 4;
+	} /* nat */
+
+	if ((t0 < n_tokens) && (strcmp(tokens[t0], "ttl") == 0)) {
+		if (n_tokens < t0 + 4) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"table action profile ttl");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 1], "drop") == 0)
+			p.ttl.drop = 1;
+		else if (strcmp(tokens[t0 + 1], "fwd") == 0)
+			p.ttl.drop = 0;
+		else {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+				"drop or fwd");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 2], "stats") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 3], "none") == 0)
+			p.ttl.n_packets_enabled = 0;
+		else if (strcmp(tokens[t0 + 3], "pkts") == 0)
+			p.ttl.n_packets_enabled = 1;
+		else {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+				"none or pkts");
+			return;
+		}
+
+		p.action_mask |= 1LLU << RTE_TABLE_ACTION_TTL;
+		t0 += 4;
+	} /* ttl */
+
+	if ((t0 < n_tokens) && (strcmp(tokens[t0], "stats") == 0)) {
+		if (n_tokens < t0 + 2) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"table action profile stats");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 1], "pkts") == 0) {
+			p.stats.n_packets_enabled = 1;
+			p.stats.n_bytes_enabled = 0;
+		} else if (strcmp(tokens[t0 + 1], "bytes") == 0) {
+			p.stats.n_packets_enabled = 0;
+			p.stats.n_bytes_enabled = 1;
+		} else if (strcmp(tokens[t0 + 1], "both") == 0) {
+			p.stats.n_packets_enabled = 1;
+			p.stats.n_bytes_enabled = 1;
+		} else {
+			snprintf(out, out_size,	MSG_ARG_NOT_FOUND,
+				"pkts or bytes or both");
+			return;
+		}
+
+		p.action_mask |= 1LLU << RTE_TABLE_ACTION_STATS;
+		t0 += 2;
+	} /* stats */
+
+	if ((t0 < n_tokens) && (strcmp(tokens[t0], "time") == 0)) {
+		p.action_mask |= 1LLU << RTE_TABLE_ACTION_TIME;
+		t0 += 1;
+	} /* time */
+
+	if (t0 < n_tokens) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	ap = table_action_profile_create(name, &p);
+	if (ap == NULL) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
 void
 cli_process(char *in, char *out, size_t out_size)
 {
@@ -768,6 +1235,16 @@ cli_process(char *in, char *out, size_t out_size)
 		return;
 	}
 
+	if (strcmp(tokens[0], "port") == 0) {
+		cmd_port_in_action_profile(tokens, n_tokens, out, out_size);
+		return;
+	}
+
+	if (strcmp(tokens[0], "table") == 0) {
+		cmd_table_action_profile(tokens, n_tokens, out, out_size);
+		return;
+	}
+
 	snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
 }
 
diff --git a/examples/ip_pipeline/cli.h b/examples/ip_pipeline/cli.h
index 992e4c3..02564a6 100644
--- a/examples/ip_pipeline/cli.h
+++ b/examples/ip_pipeline/cli.h
@@ -7,6 +7,8 @@
 
 #include <stddef.h>
 
+#include "action.h"
+
 void
 cli_process(char *in, char *out, size_t out_size);
 
diff --git a/examples/ip_pipeline/main.c b/examples/ip_pipeline/main.c
index b65762e..01cb29b 100644
--- a/examples/ip_pipeline/main.c
+++ b/examples/ip_pipeline/main.c
@@ -207,6 +207,20 @@ main(int argc, char **argv)
 		return status;
 	}
 
+	/* Action */
+	status = port_in_action_profile_init();
+	if (status) {
+		printf("Error: Input port action profile initialization failed (%d)\n", status);
+		return status;
+	}
+
+	status = table_action_profile_init();
+	if (status) {
+		printf("Error: Action profile initialization failed (%d)\n",
+			status);
+		return status;
+	}
+
 	/* Script */
 	if (app.script_name)
 		cli_script_process(app.script_name,
diff --git a/examples/ip_pipeline/meson.build b/examples/ip_pipeline/meson.build
index 5ad79b2..fb1b61d 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -7,7 +7,9 @@
 # DPDK instance, use 'make'
 
 deps += ['pipeline', 'bus_pci']
+allow_experimental_apis = true
 sources = files(
+	'action.c',
 	'cli.c',
 	'conn.c',
 	'kni.c',
-- 
2.9.3

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

* [dpdk-dev] [PATCH v4 29/49] ip_pipeline: add pipeline object
  2018-03-29 18:31           ` [dpdk-dev] [PATCH v4 00/49] ip_pipeline: refactoring Jasvinder Singh
                               ` (27 preceding siblings ...)
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 28/49] ip_pipeline: add action profile object Jasvinder Singh
@ 2018-03-29 18:31             ` Jasvinder Singh
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 30/49] ip_pipeline: add threads Jasvinder Singh
                               ` (20 subsequent siblings)
  49 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-29 18:31 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add pipeline object implementation to the application.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/Makefile    |   1 +
 examples/ip_pipeline/cli.c       | 819 ++++++++++++++++++++++++++++++++
 examples/ip_pipeline/cli.h       |   2 -
 examples/ip_pipeline/main.c      |   8 +
 examples/ip_pipeline/meson.build |   1 +
 examples/ip_pipeline/pipeline.c  | 973 +++++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/pipeline.h  | 272 +++++++++++
 7 files changed, 2074 insertions(+), 2 deletions(-)
 create mode 100644 examples/ip_pipeline/pipeline.c
 create mode 100644 examples/ip_pipeline/pipeline.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index d9c8d86..033319d 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -13,6 +13,7 @@ SRCS-y += link.c
 SRCS-y += main.c
 SRCS-y += mempool.c
 SRCS-y += parser.c
+SRCS-y += pipeline.c
 SRCS-y += swq.c
 SRCS-y += tap.c
 SRCS-y += tmgr.c
diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index 9f42d8f..ec2d01f 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -14,6 +14,7 @@
 #include "link.h"
 #include "mempool.h"
 #include "parser.h"
+#include "pipeline.h"
 #include "swq.h"
 #include "tap.h"
 #include "tmgr.h"
@@ -1157,6 +1158,784 @@ cmd_table_action_profile(char **tokens,
 	}
 }
 
+/**
+ * pipeline <pipeline_name>
+ *  period <timer_period_ms>
+ *  offset_port_id <offset_port_id>
+ *  cpu <cpu_id>
+ */
+static void
+cmd_pipeline(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct pipeline_params p;
+	char *name;
+	struct pipeline *pipeline;
+
+	if (n_tokens != 8) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	name = tokens[1];
+
+	if (strcmp(tokens[2], "period") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "period");
+		return;
+	}
+
+	if (parser_read_uint32(&p.timer_period_ms, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "timer_period_ms");
+		return;
+	}
+
+	if (strcmp(tokens[4], "offset_port_id") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset_port_id");
+		return;
+	}
+
+	if (parser_read_uint32(&p.offset_port_id, tokens[5]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "offset_port_id");
+		return;
+	}
+
+	if (strcmp(tokens[6], "cpu") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu");
+		return;
+	}
+
+	if (parser_read_uint32(&p.cpu_id, tokens[7]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id");
+		return;
+	}
+
+	pipeline = pipeline_create(name, &p);
+	if (pipeline == NULL) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
+ * pipeline <pipeline_name> port in
+ *  bsz <burst_size>
+ *  link <link_name> rxq <queue_id>
+ *  | swq <swq_name>
+ *  | tmgr <tmgr_name>
+ *  | tap <tap_name> mempool <mempool_name> mtu <mtu>
+ *  | kni <kni_name>
+ *  | source mempool <mempool_name> file <file_name> bpp <n_bytes_per_pkt>
+ *  [action <port_in_action_profile_name>]
+ *  [disabled]
+ */
+static void
+cmd_pipeline_port_in(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct port_in_params p;
+	char *pipeline_name;
+	uint32_t t0;
+	int enabled, status;
+
+	if (n_tokens < 7) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "port") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
+		return;
+	}
+
+	if (strcmp(tokens[3], "in") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
+		return;
+	}
+
+	if (strcmp(tokens[4], "bsz") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
+		return;
+	}
+
+	if (parser_read_uint32(&p.burst_size, tokens[5]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "burst_size");
+		return;
+	}
+
+	t0 = 6;
+
+	if (strcmp(tokens[t0], "link") == 0) {
+		if (n_tokens < t0 + 4) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline port in link");
+			return;
+		}
+
+		p.type = PORT_IN_RXQ;
+
+		p.dev_name = tokens[t0 + 1];
+
+		if (strcmp(tokens[t0 + 2], "rxq") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rxq");
+			return;
+		}
+
+		if (parser_read_uint16(&p.rxq.queue_id, tokens[t0 + 3]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID,
+				"queue_id");
+			return;
+		}
+		t0 += 4;
+	} else if (strcmp(tokens[t0], "swq") == 0) {
+		if (n_tokens < t0 + 2) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline port in swq");
+			return;
+		}
+
+		p.type = PORT_IN_SWQ;
+
+		p.dev_name = tokens[t0 + 1];
+
+		t0 += 2;
+	} else if (strcmp(tokens[t0], "tmgr") == 0) {
+		if (n_tokens < t0 + 2) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline port in tmgr");
+			return;
+		}
+
+		p.type = PORT_IN_TMGR;
+
+		p.dev_name = tokens[t0 + 1];
+
+		t0 += 2;
+	} else if (strcmp(tokens[t0], "tap") == 0) {
+		if (n_tokens < t0 + 6) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline port in tap");
+			return;
+		}
+
+		p.type = PORT_IN_TAP;
+
+		p.dev_name = tokens[t0 + 1];
+
+		if (strcmp(tokens[t0 + 2], "mempool") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+				"mempool");
+			return;
+		}
+
+		p.tap.mempool_name = tokens[t0 + 3];
+
+		if (strcmp(tokens[t0 + 4], "mtu") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+				"mtu");
+			return;
+		}
+
+		if (parser_read_uint32(&p.tap.mtu, tokens[t0 + 5]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "mtu");
+			return;
+		}
+
+		t0 += 6;
+	} else if (strcmp(tokens[t0], "kni") == 0) {
+		if (n_tokens < t0 + 2) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline port in kni");
+			return;
+		}
+
+		p.type = PORT_IN_KNI;
+
+		p.dev_name = tokens[t0 + 1];
+
+		t0 += 2;
+	} else if (strcmp(tokens[t0], "source") == 0) {
+		if (n_tokens < t0 + 6) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline port in source");
+			return;
+		}
+
+		p.type = PORT_IN_SOURCE;
+
+		p.dev_name = NULL;
+
+		if (strcmp(tokens[t0 + 1], "mempool") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+				"mempool");
+			return;
+		}
+
+		p.source.mempool_name = tokens[t0 + 2];
+
+		if (strcmp(tokens[t0 + 3], "file") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+				"file");
+			return;
+		}
+
+		p.source.file_name = tokens[t0 + 4];
+
+		if (strcmp(tokens[t0 + 5], "bpp") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+				"bpp");
+			return;
+		}
+
+		if (parser_read_uint32(&p.source.n_bytes_per_pkt, tokens[t0 + 6]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID,
+				"n_bytes_per_pkt");
+			return;
+		}
+
+		t0 += 7;
+	} else {
+		snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
+		return;
+	}
+
+	p.action_profile_name = NULL;
+	if ((n_tokens > t0) && (strcmp(tokens[t0], "action") == 0)) {
+		if (n_tokens < t0 + 2) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH, "action");
+			return;
+		}
+
+		p.action_profile_name = tokens[t0 + 1];
+
+		t0 += 2;
+	}
+
+	enabled = 1;
+	if ((n_tokens > t0) &&
+		(strcmp(tokens[t0], "disabled") == 0)) {
+		enabled = 0;
+
+		t0 += 1;
+	}
+
+	if (n_tokens != t0) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	status = pipeline_port_in_create(pipeline_name,
+		&p, enabled);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
+ * pipeline <pipeline_name> port out
+ *  bsz <burst_size>
+ *  link <link_name> txq <txq_id>
+ *  | swq <swq_name>
+ *  | tmgr <tmgr_name>
+ *  | tap <tap_name>
+ *  | kni <kni_name>
+ *  | sink [file <file_name> pkts <max_n_pkts>]
+ */
+static void
+cmd_pipeline_port_out(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct port_out_params p;
+	char *pipeline_name;
+	int status;
+
+	memset(&p, 0, sizeof(p));
+
+	if (n_tokens < 7) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "port") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
+		return;
+	}
+
+	if (strcmp(tokens[3], "out") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "out");
+		return;
+	}
+
+	if (strcmp(tokens[4], "bsz") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz");
+		return;
+	}
+
+	if (parser_read_uint32(&p.burst_size, tokens[5]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "burst_size");
+		return;
+	}
+
+	if (strcmp(tokens[6], "link") == 0) {
+		if (n_tokens != 10) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline port out link");
+			return;
+		}
+
+		p.type = PORT_OUT_TXQ;
+
+		p.dev_name = tokens[7];
+
+		if (strcmp(tokens[8], "txq") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "txq");
+			return;
+		}
+
+		if (parser_read_uint16(&p.txq.queue_id, tokens[9]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "queue_id");
+			return;
+		}
+	} else if (strcmp(tokens[6], "swq") == 0) {
+		if (n_tokens != 8) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline port out swq");
+			return;
+		}
+
+		p.type = PORT_OUT_SWQ;
+
+		p.dev_name = tokens[7];
+	} else if (strcmp(tokens[6], "tmgr") == 0) {
+		if (n_tokens != 8) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline port out tmgr");
+			return;
+		}
+
+		p.type = PORT_OUT_TMGR;
+
+		p.dev_name = tokens[7];
+	} else if (strcmp(tokens[6], "tap") == 0) {
+		if (n_tokens != 8) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline port out tap");
+			return;
+		}
+
+		p.type = PORT_OUT_TAP;
+
+		p.dev_name = tokens[7];
+	} else if (strcmp(tokens[6], "kni") == 0) {
+		if (n_tokens != 8) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline port out kni");
+			return;
+		}
+
+		p.type = PORT_OUT_KNI;
+
+		p.dev_name = tokens[7];
+	} else if (strcmp(tokens[6], "sink") == 0) {
+		if ((n_tokens != 7) && (n_tokens != 11)) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline port out sink");
+			return;
+		}
+
+		p.type = PORT_OUT_SINK;
+
+		p.dev_name = NULL;
+
+		if (n_tokens == 7) {
+			p.sink.file_name = NULL;
+			p.sink.max_n_pkts = 0;
+		} else {
+			if (strcmp(tokens[7], "file") != 0) {
+				snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+					"file");
+				return;
+			}
+
+			p.sink.file_name = tokens[8];
+
+			if (strcmp(tokens[9], "pkts") != 0) {
+				snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pkts");
+				return;
+			}
+
+			if (parser_read_uint32(&p.sink.max_n_pkts, tokens[10]) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID, "max_n_pkts");
+				return;
+			}
+		}
+	} else {
+		snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
+		return;
+	}
+
+	status = pipeline_port_out_create(pipeline_name, &p);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
+ * pipeline <pipeline_name> table
+ *      match
+ *      acl
+ *          ipv4 | ipv6
+ *          offset <ip_header_offset>
+ *          size <n_rules>
+ *      | array
+ *          offset <key_offset>
+ *          size <n_keys>
+ *      | hash
+ *          ext | lru
+ *          key <key_size>
+ *          mask <key_mask>
+ *          offset <key_offset>
+ *          buckets <n_buckets>
+ *          size <n_keys>
+ *      | lpm
+ *          ipv4 | ipv6
+ *          offset <ip_header_offset>
+ *          size <n_rules>
+ *      | stub
+ *  [action <table_action_profile_name>]
+ */
+static void
+cmd_pipeline_table(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	uint8_t key_mask[TABLE_RULE_MATCH_SIZE_MAX];
+	struct table_params p;
+	char *pipeline_name;
+	uint32_t t0;
+	int status;
+
+	if (n_tokens < 5) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "table") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
+		return;
+	}
+
+	if (strcmp(tokens[3], "match") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match");
+		return;
+	}
+
+	t0 = 4;
+	if (strcmp(tokens[t0], "acl") == 0) {
+		if (n_tokens < t0 + 6) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline table acl");
+			return;
+		}
+
+		p.match_type = TABLE_ACL;
+
+		if (strcmp(tokens[t0 + 1], "ipv4") == 0)
+			p.match.acl.ip_version = 1;
+		else if (strcmp(tokens[t0 + 1], "ipv6") == 0)
+			p.match.acl.ip_version = 0;
+		else {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+				"ipv4 or ipv6");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 2], "offset") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
+			return;
+		}
+
+		if (parser_read_uint32(&p.match.acl.ip_header_offset,
+			tokens[t0 + 3]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID,
+				"ip_header_offset");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 4], "size") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
+			return;
+		}
+
+		if (parser_read_uint32(&p.match.acl.n_rules,
+			tokens[t0 + 5]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "n_rules");
+			return;
+		}
+
+		t0 += 6;
+	} else if (strcmp(tokens[t0], "array") == 0) {
+		if (n_tokens < t0 + 5) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline table array");
+			return;
+		}
+
+		p.match_type = TABLE_ARRAY;
+
+		if (strcmp(tokens[t0 + 1], "offset") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
+			return;
+		}
+
+		if (parser_read_uint32(&p.match.array.key_offset,
+			tokens[t0 + 2]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 3], "size") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
+			return;
+		}
+
+		if (parser_read_uint32(&p.match.array.n_keys,
+			tokens[t0 + 4]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "n_keys");
+			return;
+		}
+
+		t0 += 5;
+	} else if (strcmp(tokens[t0], "hash") == 0) {
+		uint32_t key_mask_size = TABLE_RULE_MATCH_SIZE_MAX;
+
+		if (n_tokens < t0 + 12) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline table hash");
+			return;
+		}
+
+		p.match_type = TABLE_HASH;
+
+		if (strcmp(tokens[t0 + 1], "ext") == 0)
+			p.match.hash.extendable_bucket = 1;
+		else if (strcmp(tokens[t0 + 1], "lru") == 0)
+			p.match.hash.extendable_bucket = 0;
+		else {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+				"ext or lru");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 2], "key") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "key");
+			return;
+		}
+
+		if ((parser_read_uint32(&p.match.hash.key_size,
+			tokens[t0 + 3]) != 0) ||
+			(p.match.hash.key_size == 0) ||
+			(p.match.hash.key_size > TABLE_RULE_MATCH_SIZE_MAX)) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "key_size");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 4], "mask") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask");
+			return;
+		}
+
+		if ((parse_hex_string(tokens[t0 + 5],
+			key_mask, &key_mask_size) != 0) ||
+			(key_mask_size != p.match.hash.key_size)) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "key_mask");
+			return;
+		}
+		p.match.hash.key_mask = key_mask;
+
+		if (strcmp(tokens[t0 + 6], "offset") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
+			return;
+		}
+
+		if (parser_read_uint32(&p.match.hash.key_offset,
+			tokens[t0 + 7]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 8], "buckets") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "buckets");
+			return;
+		}
+
+		if (parser_read_uint32(&p.match.hash.n_buckets,
+			tokens[t0 + 9]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "n_buckets");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 10], "size") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
+			return;
+		}
+
+		if (parser_read_uint32(&p.match.hash.n_keys,
+			tokens[t0 + 11]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "n_keys");
+			return;
+		}
+
+		t0 += 12;
+	} else if (strcmp(tokens[t0], "lpm") == 0) {
+		if (n_tokens < t0 + 6) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline table lpm");
+			return;
+		}
+
+		p.match_type = TABLE_LPM;
+
+		if (strcmp(tokens[t0 + 1], "ipv4") == 0)
+			p.match.lpm.key_size = 4;
+		else if (strcmp(tokens[t0 + 1], "ipv6") == 0)
+			p.match.lpm.key_size = 16;
+		else {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+				"ipv4 or ipv6");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 2], "offset") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
+			return;
+		}
+
+		if (parser_read_uint32(&p.match.lpm.key_offset,
+			tokens[t0 + 3]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 4], "size") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size");
+			return;
+		}
+
+		if (parser_read_uint32(&p.match.lpm.n_rules,
+			tokens[t0 + 5]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "n_rules");
+			return;
+		}
+
+		t0 += 6;
+	} else if (strcmp(tokens[t0], "stub") == 0) {
+		if (n_tokens < t0 + 1) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"pipeline table stub");
+			return;
+		}
+
+		p.match_type = TABLE_STUB;
+
+		t0 += 1;
+	} else {
+		snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
+		return;
+	}
+
+	p.action_profile_name = NULL;
+	if ((n_tokens > t0) && (strcmp(tokens[t0], "action") == 0)) {
+		if (n_tokens < t0 + 2) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH, "action");
+			return;
+		}
+
+		p.action_profile_name = tokens[t0 + 1];
+
+		t0 += 2;
+	}
+
+	if (n_tokens > t0) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	status = pipeline_table_create(pipeline_name, &p);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
+ * pipeline <pipeline_name> port in <port_id> table <table_id>
+ */
+static void
+cmd_pipeline_port_in_table(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	char *pipeline_name;
+	uint32_t port_id, table_id;
+	int status;
+
+	if (n_tokens != 7) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "port") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
+		return;
+	}
+
+	if (strcmp(tokens[3], "in") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
+		return;
+	}
+
+	if (parser_read_uint32(&port_id, tokens[4]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
+		return;
+	}
+
+	if (strcmp(tokens[5], "table") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
+		return;
+	}
+
+	if (parser_read_uint32(&table_id, tokens[6]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
+		return;
+	}
+
+	status = pipeline_port_in_connect_to_table(pipeline_name,
+		port_id,
+		table_id);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
 void
 cli_process(char *in, char *out, size_t out_size)
 {
@@ -1245,6 +2024,46 @@ cli_process(char *in, char *out, size_t out_size)
 		return;
 	}
 
+	if (strcmp(tokens[0], "pipeline") == 0) {
+		if ((n_tokens >= 3) &&
+			(strcmp(tokens[2], "period") == 0)) {
+			cmd_pipeline(tokens, n_tokens, out, out_size);
+			return;
+		}
+
+		if ((n_tokens >= 5) &&
+			(strcmp(tokens[2], "port") == 0) &&
+			(strcmp(tokens[3], "in") == 0) &&
+			(strcmp(tokens[4], "bsz") == 0)) {
+			cmd_pipeline_port_in(tokens, n_tokens, out, out_size);
+			return;
+		}
+
+		if ((n_tokens >= 5) &&
+			(strcmp(tokens[2], "port") == 0) &&
+			(strcmp(tokens[3], "out") == 0) &&
+			(strcmp(tokens[4], "bsz") == 0)) {
+			cmd_pipeline_port_out(tokens, n_tokens, out, out_size);
+			return;
+		}
+
+		if ((n_tokens >= 4) &&
+			(strcmp(tokens[2], "table") == 0) &&
+			(strcmp(tokens[3], "match") == 0)) {
+			cmd_pipeline_table(tokens, n_tokens, out, out_size);
+			return;
+		}
+
+		if ((n_tokens >= 6) &&
+			(strcmp(tokens[2], "port") == 0) &&
+			(strcmp(tokens[3], "in") == 0) &&
+			(strcmp(tokens[5], "table") == 0)) {
+			cmd_pipeline_port_in_table(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
+	}
+
 	snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
 }
 
diff --git a/examples/ip_pipeline/cli.h b/examples/ip_pipeline/cli.h
index 02564a6..992e4c3 100644
--- a/examples/ip_pipeline/cli.h
+++ b/examples/ip_pipeline/cli.h
@@ -7,8 +7,6 @@
 
 #include <stddef.h>
 
-#include "action.h"
-
 void
 cli_process(char *in, char *out, size_t out_size);
 
diff --git a/examples/ip_pipeline/main.c b/examples/ip_pipeline/main.c
index 01cb29b..ab8e2b9 100644
--- a/examples/ip_pipeline/main.c
+++ b/examples/ip_pipeline/main.c
@@ -15,6 +15,7 @@
 #include "kni.h"
 #include "link.h"
 #include "mempool.h"
+#include "pipeline.h"
 #include "swq.h"
 #include "tap.h"
 #include "tmgr.h"
@@ -221,6 +222,13 @@ main(int argc, char **argv)
 		return status;
 	}
 
+	/* Pipeline */
+	status = pipeline_init();
+	if (status) {
+		printf("Error: Pipeline initialization failed (%d)\n", status);
+		return status;
+	}
+
 	/* Script */
 	if (app.script_name)
 		cli_script_process(app.script_name,
diff --git a/examples/ip_pipeline/meson.build b/examples/ip_pipeline/meson.build
index fb1b61d..2366242 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -17,6 +17,7 @@ sources = files(
 	'main.c',
 	'mempool.c',
 	'parser.c',
+	'pipeline.c',
 	'swq.c',
 	'tap.c',
 	'tmgr.c'
diff --git a/examples/ip_pipeline/pipeline.c b/examples/ip_pipeline/pipeline.c
new file mode 100644
index 0000000..817c39f
--- /dev/null
+++ b/examples/ip_pipeline/pipeline.c
@@ -0,0 +1,973 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <rte_common.h>
+#include <rte_ip.h>
+#include <rte_tcp.h>
+
+#include <rte_port_ethdev.h>
+#include <rte_port_kni.h>
+#include <rte_port_ring.h>
+#include <rte_port_source_sink.h>
+#include <rte_port_fd.h>
+#include <rte_port_sched.h>
+
+#include <rte_table_acl.h>
+#include <rte_table_array.h>
+#include <rte_table_hash.h>
+#include <rte_table_lpm.h>
+#include <rte_table_lpm_ipv6.h>
+#include <rte_table_stub.h>
+
+#include "kni.h"
+#include "link.h"
+#include "mempool.h"
+#include "pipeline.h"
+#include "tap.h"
+#include "tmgr.h"
+#include "swq.h"
+
+#include "hash_func.h"
+
+#ifndef PIPELINE_MSGQ_SIZE
+#define PIPELINE_MSGQ_SIZE                                 64
+#endif
+
+#ifndef TABLE_LPM_NUMBER_TBL8
+#define TABLE_LPM_NUMBER_TBL8                              256
+#endif
+
+static struct pipeline_list pipeline_list;
+
+int
+pipeline_init(void)
+{
+	TAILQ_INIT(&pipeline_list);
+
+	return 0;
+}
+
+struct pipeline *
+pipeline_find(const char *name)
+{
+	struct pipeline *pipeline;
+
+	if (name == NULL)
+		return NULL;
+
+	TAILQ_FOREACH(pipeline, &pipeline_list, node)
+		if (strcmp(name, pipeline->name) == 0)
+			return pipeline;
+
+	return NULL;
+}
+
+struct pipeline *
+pipeline_create(const char *name, struct pipeline_params *params)
+{
+	char msgq_name[NAME_MAX];
+	struct rte_pipeline_params pp;
+	struct pipeline *pipeline;
+	struct rte_pipeline *p;
+	struct rte_ring *msgq_req;
+	struct rte_ring *msgq_rsp;
+
+	/* Check input params */
+	if ((name == NULL) ||
+		pipeline_find(name) ||
+		(params == NULL) ||
+		(params->timer_period_ms == 0))
+		return NULL;
+
+	/* Resource create */
+	snprintf(msgq_name, sizeof(msgq_name), "%s-MSGQ-REQ", name);
+
+	msgq_req = rte_ring_create(msgq_name,
+		PIPELINE_MSGQ_SIZE,
+		params->cpu_id,
+		RING_F_SP_ENQ | RING_F_SC_DEQ);
+	if (msgq_req == NULL)
+		return NULL;
+
+	snprintf(msgq_name, sizeof(msgq_name), "%s-MSGQ-RSP", name);
+
+	msgq_rsp = rte_ring_create(msgq_name,
+		PIPELINE_MSGQ_SIZE,
+		params->cpu_id,
+		RING_F_SP_ENQ | RING_F_SC_DEQ);
+	if (msgq_rsp == NULL) {
+		rte_ring_free(msgq_req);
+		return NULL;
+	}
+
+	pp.name = name;
+	pp.socket_id = (int) params->cpu_id;
+	pp.offset_port_id = params->offset_port_id;
+
+	p = rte_pipeline_create(&pp);
+	if (p == NULL) {
+		rte_ring_free(msgq_rsp);
+		rte_ring_free(msgq_req);
+		return NULL;
+	}
+
+	/* Node allocation */
+	pipeline = calloc(1, sizeof(struct pipeline));
+	if (pipeline == NULL) {
+		rte_pipeline_free(p);
+		rte_ring_free(msgq_rsp);
+		rte_ring_free(msgq_req);
+		return NULL;
+	}
+
+	/* Node fill in */
+	strncpy(pipeline->name, name, sizeof(pipeline->name));
+	pipeline->p = p;
+	pipeline->n_ports_in = 0;
+	pipeline->n_ports_out = 0;
+	pipeline->n_tables = 0;
+	pipeline->msgq_req = msgq_req;
+	pipeline->msgq_rsp = msgq_rsp;
+	pipeline->timer_period_ms = params->timer_period_ms;
+	pipeline->enabled = 0;
+	pipeline->cpu_id = params->cpu_id;
+
+	/* Node add to list */
+	TAILQ_INSERT_TAIL(&pipeline_list, pipeline, node);
+
+	return pipeline;
+}
+
+int
+pipeline_port_in_create(const char *pipeline_name,
+	struct port_in_params *params,
+	int enabled)
+{
+	struct rte_pipeline_port_in_params p;
+
+	union {
+		struct rte_port_ethdev_reader_params ethdev;
+		struct rte_port_ring_reader_params ring;
+		struct rte_port_sched_reader_params sched;
+		struct rte_port_fd_reader_params fd;
+		struct rte_port_kni_reader_params kni;
+		struct rte_port_source_params source;
+	} pp;
+
+	struct pipeline *pipeline;
+	struct port_in *port_in;
+	struct port_in_action_profile *ap;
+	struct rte_port_in_action *action;
+	uint32_t port_id;
+	int status;
+
+	memset(&p, 0, sizeof(p));
+	memset(&pp, 0, sizeof(pp));
+
+	/* Check input params */
+	if ((pipeline_name == NULL) ||
+		(params == NULL) ||
+		(params->burst_size == 0) ||
+		(params->burst_size > RTE_PORT_IN_BURST_SIZE_MAX))
+		return -1;
+
+	pipeline = pipeline_find(pipeline_name);
+	if (pipeline == NULL)
+		return -1;
+
+	ap = NULL;
+	if (params->action_profile_name) {
+		ap = port_in_action_profile_find(params->action_profile_name);
+		if (ap == NULL)
+			return -1;
+	}
+
+	switch (params->type) {
+	case PORT_IN_RXQ:
+	{
+		struct link *link;
+
+		link = link_find(params->dev_name);
+		if (link == NULL)
+			return -1;
+
+		if (params->rxq.queue_id >= link->n_rxq)
+			return -1;
+
+		pp.ethdev.port_id = link->port_id;
+		pp.ethdev.queue_id = params->rxq.queue_id;
+
+		p.ops = &rte_port_ethdev_reader_ops;
+		p.arg_create = &pp.ethdev;
+		break;
+	}
+
+	case PORT_IN_SWQ:
+	{
+		struct swq *swq;
+
+		swq = swq_find(params->dev_name);
+		if (swq == NULL)
+			return -1;
+
+		pp.ring.ring = swq->r;
+
+		p.ops = &rte_port_ring_reader_ops;
+		p.arg_create = &pp.ring;
+		break;
+	}
+
+	case PORT_IN_TMGR:
+	{
+		struct tmgr_port *tmgr_port;
+
+		tmgr_port = tmgr_port_find(params->dev_name);
+		if (tmgr_port == NULL)
+			return -1;
+
+		pp.sched.sched = tmgr_port->s;
+
+		p.ops = &rte_port_sched_reader_ops;
+		p.arg_create = &pp.sched;
+		break;
+	}
+
+	case PORT_IN_TAP:
+	{
+		struct tap *tap;
+		struct mempool *mempool;
+
+		tap = tap_find(params->dev_name);
+		mempool = mempool_find(params->tap.mempool_name);
+		if ((tap == NULL) || (mempool == NULL))
+			return -1;
+
+		pp.fd.fd = tap->fd;
+		pp.fd.mempool = mempool->m;
+		pp.fd.mtu = params->tap.mtu;
+
+		p.ops = &rte_port_fd_reader_ops;
+		p.arg_create = &pp.fd;
+		break;
+	}
+
+	case PORT_IN_KNI:
+	{
+		struct kni *kni;
+
+		kni = kni_find(params->dev_name);
+		if (kni == NULL)
+			return -1;
+
+		pp.kni.kni = kni->k;
+
+		p.ops = &rte_port_kni_reader_ops;
+		p.arg_create = &pp.kni;
+		break;
+	}
+
+	case PORT_IN_SOURCE:
+	{
+		struct mempool *mempool;
+
+		mempool = mempool_find(params->source.mempool_name);
+		if (mempool == NULL)
+			return -1;
+
+		pp.source.mempool = mempool->m;
+		pp.source.file_name = params->source.file_name;
+		pp.source.n_bytes_per_pkt = params->source.n_bytes_per_pkt;
+
+		p.ops = &rte_port_source_ops;
+		p.arg_create = &pp.source;
+		break;
+	}
+
+	default:
+		return -1;
+	}
+
+	p.burst_size = params->burst_size;
+
+	/* Resource create */
+	action = NULL;
+	p.f_action = NULL;
+	p.arg_ah = NULL;
+
+	if (ap) {
+		action = rte_port_in_action_create(ap->ap,
+			pipeline->cpu_id);
+		if (action == NULL)
+			return -1;
+
+		status = rte_port_in_action_params_get(
+			action,
+			&p);
+		if (status) {
+			rte_port_in_action_free(action);
+			return -1;
+		}
+	}
+
+	status = rte_pipeline_port_in_create(pipeline->p,
+		&p,
+		&port_id);
+	if (status) {
+		rte_port_in_action_free(action);
+		return -1;
+	}
+
+	if (enabled)
+		rte_pipeline_port_in_enable(pipeline->p, port_id);
+
+	/* Pipeline */
+	port_in = &pipeline->port_in[pipeline->n_ports_in];
+	memcpy(&port_in->params, params, sizeof(*params));
+	port_in->ap = ap;
+	port_in->a = action;
+	pipeline->n_ports_in++;
+
+	return 0;
+}
+
+int
+pipeline_port_in_connect_to_table(const char *pipeline_name,
+	uint32_t port_id,
+	uint32_t table_id)
+{
+	struct pipeline *pipeline;
+	int status;
+
+	/* Check input params */
+	if (pipeline_name == NULL)
+		return -1;
+
+	pipeline = pipeline_find(pipeline_name);
+	if ((pipeline == NULL) ||
+		(port_id >= pipeline->n_ports_in) ||
+		(table_id >= pipeline->n_tables))
+		return -1;
+
+	/* Resource */
+	status = rte_pipeline_port_in_connect_to_table(pipeline->p,
+		port_id,
+		table_id);
+
+	return status;
+
+}
+
+int
+pipeline_port_out_create(const char *pipeline_name,
+	struct port_out_params *params)
+{
+	struct rte_pipeline_port_out_params p;
+
+	union {
+		struct rte_port_ethdev_writer_params ethdev;
+		struct rte_port_ring_writer_params ring;
+		struct rte_port_sched_writer_params sched;
+		struct rte_port_fd_writer_params fd;
+		struct rte_port_kni_writer_params kni;
+		struct rte_port_sink_params sink;
+	} pp;
+
+	union {
+		struct rte_port_ethdev_writer_nodrop_params ethdev;
+		struct rte_port_ring_writer_nodrop_params ring;
+		struct rte_port_fd_writer_nodrop_params fd;
+		struct rte_port_kni_writer_nodrop_params kni;
+	} pp_nodrop;
+
+	struct pipeline *pipeline;
+	uint32_t port_id;
+	int status;
+
+	memset(&p, 0, sizeof(p));
+	memset(&pp, 0, sizeof(pp));
+	memset(&pp_nodrop, 0, sizeof(pp_nodrop));
+
+	/* Check input params */
+	if ((pipeline_name == NULL) ||
+		(params == NULL) ||
+		(params->burst_size == 0) ||
+		(params->burst_size > RTE_PORT_IN_BURST_SIZE_MAX))
+		return -1;
+
+	pipeline = pipeline_find(pipeline_name);
+	if (pipeline == NULL)
+		return -1;
+
+	switch (params->type) {
+	case PORT_OUT_TXQ:
+	{
+		struct link *link;
+
+		link = link_find(params->dev_name);
+		if (link == NULL)
+			return -1;
+
+		if (params->txq.queue_id >= link->n_txq)
+			return -1;
+
+		pp.ethdev.port_id = link->port_id;
+		pp.ethdev.queue_id = params->txq.queue_id;
+		pp.ethdev.tx_burst_sz = params->burst_size;
+
+		pp_nodrop.ethdev.port_id = link->port_id;
+		pp_nodrop.ethdev.queue_id = params->txq.queue_id;
+		pp_nodrop.ethdev.tx_burst_sz = params->burst_size;
+		pp_nodrop.ethdev.n_retries = params->n_retries;
+
+		if (params->retry == 0) {
+			p.ops = &rte_port_ethdev_writer_ops;
+			p.arg_create = &pp.ethdev;
+		} else {
+			p.ops = &rte_port_ethdev_writer_nodrop_ops;
+			p.arg_create = &pp_nodrop.ethdev;
+		}
+		break;
+	}
+
+	case PORT_OUT_SWQ:
+	{
+		struct swq *swq;
+
+		swq = swq_find(params->dev_name);
+		if (swq == NULL)
+			return -1;
+
+		pp.ring.ring = swq->r;
+		pp.ring.tx_burst_sz = params->burst_size;
+
+		pp_nodrop.ring.ring = swq->r;
+		pp_nodrop.ring.tx_burst_sz = params->burst_size;
+		pp_nodrop.ring.n_retries = params->n_retries;
+
+		if (params->retry == 0) {
+			p.ops = &rte_port_ring_writer_ops;
+			p.arg_create = &pp.ring;
+		} else {
+			p.ops = &rte_port_ring_writer_nodrop_ops;
+			p.arg_create = &pp_nodrop.ring;
+		}
+		break;
+	}
+
+	case PORT_OUT_TMGR:
+	{
+		struct tmgr_port *tmgr_port;
+
+		tmgr_port = tmgr_port_find(params->dev_name);
+		if (tmgr_port == NULL)
+			return -1;
+
+		pp.sched.sched = tmgr_port->s;
+		pp.sched.tx_burst_sz = params->burst_size;
+
+		p.ops = &rte_port_sched_writer_ops;
+		p.arg_create = &pp.sched;
+		break;
+	}
+
+	case PORT_OUT_TAP:
+	{
+		struct tap *tap;
+
+		tap = tap_find(params->dev_name);
+		if (tap == NULL)
+			return -1;
+
+		pp.fd.fd = tap->fd;
+		pp.fd.tx_burst_sz = params->burst_size;
+
+		pp_nodrop.fd.fd = tap->fd;
+		pp_nodrop.fd.tx_burst_sz = params->burst_size;
+		pp_nodrop.fd.n_retries = params->n_retries;
+
+		if (params->retry == 0) {
+			p.ops = &rte_port_fd_writer_ops;
+			p.arg_create = &pp.fd;
+		} else {
+			p.ops = &rte_port_fd_writer_nodrop_ops;
+			p.arg_create = &pp_nodrop.fd;
+		}
+		break;
+	}
+
+	case PORT_OUT_KNI:
+	{
+		struct kni *kni;
+
+		kni = kni_find(params->dev_name);
+		if (kni == NULL)
+			return -1;
+
+		pp.kni.kni = kni->k;
+		pp.kni.tx_burst_sz = params->burst_size;
+
+		pp_nodrop.kni.kni = kni->k;
+		pp_nodrop.kni.tx_burst_sz = params->burst_size;
+		pp_nodrop.kni.n_retries = params->n_retries;
+
+		if (params->retry == 0) {
+			p.ops = &rte_port_kni_writer_ops;
+			p.arg_create = &pp.kni;
+		} else {
+			p.ops = &rte_port_kni_writer_nodrop_ops;
+			p.arg_create = &pp_nodrop.kni;
+		}
+		break;
+	}
+
+	case PORT_OUT_SINK:
+	{
+		pp.sink.file_name = params->sink.file_name;
+		pp.sink.max_n_pkts = params->sink.max_n_pkts;
+
+		p.ops = &rte_port_sink_ops;
+		p.arg_create = &pp.sink;
+		break;
+	}
+
+	default:
+		return -1;
+	}
+
+	p.f_action = NULL;
+	p.arg_ah = NULL;
+
+	/* Resource create */
+	status = rte_pipeline_port_out_create(pipeline->p,
+		&p,
+		&port_id);
+
+	if (status)
+		return -1;
+
+	/* Pipeline */
+	pipeline->n_ports_out++;
+
+	return 0;
+}
+
+static const struct rte_acl_field_def table_acl_field_format_ipv4[] = {
+	/* Protocol */
+	[0] = {
+		.type = RTE_ACL_FIELD_TYPE_BITMASK,
+		.size = sizeof(uint8_t),
+		.field_index = 0,
+		.input_index = 0,
+		.offset = offsetof(struct ipv4_hdr, next_proto_id),
+	},
+
+	/* Source IP address (IPv4) */
+	[1] = {
+		.type = RTE_ACL_FIELD_TYPE_MASK,
+		.size = sizeof(uint32_t),
+		.field_index = 1,
+		.input_index = 1,
+		.offset = offsetof(struct ipv4_hdr, src_addr),
+	},
+
+	/* Destination IP address (IPv4) */
+	[2] = {
+		.type = RTE_ACL_FIELD_TYPE_MASK,
+		.size = sizeof(uint32_t),
+		.field_index = 2,
+		.input_index = 2,
+		.offset = offsetof(struct ipv4_hdr, dst_addr),
+	},
+
+	/* Source Port */
+	[3] = {
+		.type = RTE_ACL_FIELD_TYPE_RANGE,
+		.size = sizeof(uint16_t),
+		.field_index = 3,
+		.input_index = 3,
+		.offset = sizeof(struct ipv4_hdr) +
+			offsetof(struct tcp_hdr, src_port),
+	},
+
+	/* Destination Port */
+	[4] = {
+		.type = RTE_ACL_FIELD_TYPE_RANGE,
+		.size = sizeof(uint16_t),
+		.field_index = 4,
+		.input_index = 3,
+		.offset = sizeof(struct ipv4_hdr) +
+			offsetof(struct tcp_hdr, dst_port),
+	},
+};
+
+static const struct rte_acl_field_def table_acl_field_format_ipv6[] = {
+	/* Protocol */
+	[0] = {
+		.type = RTE_ACL_FIELD_TYPE_BITMASK,
+		.size = sizeof(uint8_t),
+		.field_index = 0,
+		.input_index = 0,
+		.offset = offsetof(struct ipv6_hdr, proto),
+	},
+
+	/* Source IP address (IPv6) */
+	[1] = {
+		.type = RTE_ACL_FIELD_TYPE_MASK,
+		.size = sizeof(uint32_t),
+		.field_index = 1,
+		.input_index = 1,
+		.offset = offsetof(struct ipv6_hdr, src_addr[0]),
+	},
+
+	[2] = {
+		.type = RTE_ACL_FIELD_TYPE_MASK,
+		.size = sizeof(uint32_t),
+		.field_index = 2,
+		.input_index = 2,
+		.offset = offsetof(struct ipv6_hdr, src_addr[4]),
+	},
+
+	[3] = {
+		.type = RTE_ACL_FIELD_TYPE_MASK,
+		.size = sizeof(uint32_t),
+		.field_index = 3,
+		.input_index = 3,
+		.offset = offsetof(struct ipv6_hdr, src_addr[8]),
+	},
+
+	[4] = {
+		.type = RTE_ACL_FIELD_TYPE_MASK,
+		.size = sizeof(uint32_t),
+		.field_index = 4,
+		.input_index = 4,
+		.offset = offsetof(struct ipv6_hdr, src_addr[12]),
+	},
+
+	/* Destination IP address (IPv6) */
+	[5] = {
+		.type = RTE_ACL_FIELD_TYPE_MASK,
+		.size = sizeof(uint32_t),
+		.field_index = 5,
+		.input_index = 5,
+		.offset = offsetof(struct ipv6_hdr, dst_addr[0]),
+	},
+
+	[6] = {
+		.type = RTE_ACL_FIELD_TYPE_MASK,
+		.size = sizeof(uint32_t),
+		.field_index = 6,
+		.input_index = 6,
+		.offset = offsetof(struct ipv6_hdr, dst_addr[4]),
+	},
+
+	[7] = {
+		.type = RTE_ACL_FIELD_TYPE_MASK,
+		.size = sizeof(uint32_t),
+		.field_index = 7,
+		.input_index = 7,
+		.offset = offsetof(struct ipv6_hdr, dst_addr[8]),
+	},
+
+	[8] = {
+		.type = RTE_ACL_FIELD_TYPE_MASK,
+		.size = sizeof(uint32_t),
+		.field_index = 8,
+		.input_index = 8,
+		.offset = offsetof(struct ipv6_hdr, dst_addr[12]),
+	},
+
+	/* Source Port */
+	[9] = {
+		.type = RTE_ACL_FIELD_TYPE_RANGE,
+		.size = sizeof(uint16_t),
+		.field_index = 9,
+		.input_index = 9,
+		.offset = sizeof(struct ipv6_hdr) +
+			offsetof(struct tcp_hdr, src_port),
+	},
+
+	/* Destination Port */
+	[10] = {
+		.type = RTE_ACL_FIELD_TYPE_RANGE,
+		.size = sizeof(uint16_t),
+		.field_index = 10,
+		.input_index = 9,
+		.offset = sizeof(struct ipv6_hdr) +
+			offsetof(struct tcp_hdr, dst_port),
+	},
+};
+
+int
+pipeline_table_create(const char *pipeline_name,
+	struct table_params *params)
+{
+	char name[NAME_MAX];
+	struct rte_pipeline_table_params p;
+
+	union {
+		struct rte_table_acl_params acl;
+		struct rte_table_array_params array;
+		struct rte_table_hash_params hash;
+		struct rte_table_lpm_params lpm;
+		struct rte_table_lpm_ipv6_params lpm_ipv6;
+	} pp;
+
+	struct pipeline *pipeline;
+	struct table *table;
+	struct table_action_profile *ap;
+	struct rte_table_action *action;
+	uint32_t table_id;
+	int status;
+
+	memset(&p, 0, sizeof(p));
+	memset(&pp, 0, sizeof(pp));
+
+	/* Check input params */
+	if ((pipeline_name == NULL) ||
+		(params == NULL))
+		return -1;
+
+	pipeline = pipeline_find(pipeline_name);
+	if ((pipeline == NULL) ||
+		(pipeline->n_tables >= RTE_PIPELINE_TABLE_MAX))
+		return -1;
+
+	ap = NULL;
+	if (params->action_profile_name) {
+		ap = table_action_profile_find(params->action_profile_name);
+		if (ap == NULL)
+			return -1;
+	}
+
+	snprintf(name, NAME_MAX, "%s_table%u",
+		pipeline_name, pipeline->n_tables);
+
+	switch (params->match_type) {
+	case TABLE_ACL:
+	{
+		uint32_t ip_header_offset = params->match.acl.ip_header_offset -
+			(sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM);
+		uint32_t i;
+
+		if (params->match.acl.n_rules == 0)
+			return -1;
+
+		pp.acl.name = name;
+		pp.acl.n_rules = params->match.acl.n_rules;
+		if (params->match.acl.ip_version) {
+			memcpy(&pp.acl.field_format,
+				&table_acl_field_format_ipv4,
+				sizeof(table_acl_field_format_ipv4));
+			pp.acl.n_rule_fields =
+				RTE_DIM(table_acl_field_format_ipv4);
+		} else {
+			memcpy(&pp.acl.field_format,
+				&table_acl_field_format_ipv6,
+				sizeof(table_acl_field_format_ipv6));
+			pp.acl.n_rule_fields =
+				RTE_DIM(table_acl_field_format_ipv6);
+		}
+
+		for (i = 0; i < pp.acl.n_rule_fields; i++)
+			pp.acl.field_format[i].offset += ip_header_offset;
+
+		p.ops = &rte_table_acl_ops;
+		p.arg_create = &pp.acl;
+		break;
+	}
+
+	case TABLE_ARRAY:
+	{
+		if (params->match.array.n_keys == 0)
+			return -1;
+
+		pp.array.n_entries = params->match.array.n_keys;
+		pp.array.offset = params->match.array.key_offset;
+
+		p.ops = &rte_table_array_ops;
+		p.arg_create = &pp.array;
+		break;
+	}
+
+	case TABLE_HASH:
+	{
+		struct rte_table_ops *ops;
+		rte_table_hash_op_hash f_hash;
+
+		if (params->match.hash.n_keys == 0)
+			return -1;
+
+		switch (params->match.hash.key_size) {
+		case  8:
+			f_hash = hash_default_key8;
+			break;
+		case 16:
+			f_hash = hash_default_key16;
+			break;
+		case 24:
+			f_hash = hash_default_key24;
+			break;
+		case 32:
+			f_hash = hash_default_key32;
+			break;
+		case 40:
+			f_hash = hash_default_key40;
+			break;
+		case 48:
+			f_hash = hash_default_key48;
+			break;
+		case 56:
+			f_hash = hash_default_key56;
+			break;
+		case 64:
+			f_hash = hash_default_key64;
+			break;
+		default:
+			return -1;
+		}
+
+		pp.hash.name = name;
+		pp.hash.key_size = params->match.hash.key_size;
+		pp.hash.key_offset = params->match.hash.key_offset;
+		pp.hash.key_mask = params->match.hash.key_mask;
+		pp.hash.n_keys = params->match.hash.n_keys;
+		pp.hash.n_buckets = params->match.hash.n_buckets;
+		pp.hash.f_hash = f_hash;
+		pp.hash.seed = 0;
+
+		if (params->match.hash.extendable_bucket)
+			switch (params->match.hash.key_size) {
+			case  8:
+				ops = &rte_table_hash_key8_ext_ops;
+				break;
+			case 16:
+				ops = &rte_table_hash_key16_ext_ops;
+				break;
+			default:
+				ops = &rte_table_hash_ext_ops;
+			}
+		else
+			switch (params->match.hash.key_size) {
+			case  8:
+				ops = &rte_table_hash_key8_lru_ops;
+				break;
+			case 16:
+				ops = &rte_table_hash_key16_lru_ops;
+				break;
+			default:
+				ops = &rte_table_hash_lru_ops;
+			}
+
+		p.ops = ops;
+		p.arg_create = &pp.hash;
+		break;
+	}
+
+	case TABLE_LPM:
+	{
+		if (params->match.lpm.n_rules == 0)
+			return -1;
+
+		switch (params->match.lpm.key_size) {
+		case 4:
+		{
+			pp.lpm.name = name;
+			pp.lpm.n_rules = params->match.lpm.n_rules;
+			pp.lpm.number_tbl8s = TABLE_LPM_NUMBER_TBL8;
+			pp.lpm.flags = 0;
+			pp.lpm.entry_unique_size = p.action_data_size +
+				sizeof(struct rte_pipeline_table_entry);
+			pp.lpm.offset = params->match.lpm.key_offset;
+
+			p.ops = &rte_table_lpm_ops;
+			p.arg_create = &pp.lpm;
+			break;
+		}
+
+		case 16:
+		{
+			pp.lpm_ipv6.name = name;
+			pp.lpm_ipv6.n_rules = params->match.lpm.n_rules;
+			pp.lpm_ipv6.number_tbl8s = TABLE_LPM_NUMBER_TBL8;
+			pp.lpm_ipv6.entry_unique_size = p.action_data_size +
+				sizeof(struct rte_pipeline_table_entry);
+			pp.lpm_ipv6.offset = params->match.lpm.key_offset;
+
+			p.ops = &rte_table_lpm_ipv6_ops;
+			p.arg_create = &pp.lpm_ipv6;
+			break;
+		}
+
+		default:
+			return -1;
+		}
+
+		break;
+	}
+
+	case TABLE_STUB:
+	{
+		p.ops = &rte_table_stub_ops;
+		p.arg_create = NULL;
+		break;
+	}
+
+	default:
+		return -1;
+	}
+
+	/* Resource create */
+	action = NULL;
+	p.f_action_hit = NULL;
+	p.f_action_miss = NULL;
+	p.arg_ah = NULL;
+
+	if (ap) {
+		action = rte_table_action_create(ap->ap,
+			pipeline->cpu_id);
+		if (action == NULL)
+			return -1;
+
+		status = rte_table_action_table_params_get(
+			action,
+			&p);
+		if (status ||
+			((p.action_data_size +
+			sizeof(struct rte_pipeline_table_entry)) >
+			TABLE_RULE_ACTION_SIZE_MAX)) {
+			rte_table_action_free(action);
+			return -1;
+		}
+	}
+
+	if (params->match_type == TABLE_LPM) {
+		if (params->match.lpm.key_size == 4)
+			pp.lpm.entry_unique_size = p.action_data_size +
+				sizeof(struct rte_pipeline_table_entry);
+
+		if (params->match.lpm.key_size == 16)
+			pp.lpm_ipv6.entry_unique_size = p.action_data_size +
+				sizeof(struct rte_pipeline_table_entry);
+	}
+
+	status = rte_pipeline_table_create(pipeline->p,
+		&p,
+		&table_id);
+	if (status) {
+		rte_table_action_free(action);
+		return -1;
+	}
+
+	/* Pipeline */
+	table = &pipeline->table[pipeline->n_tables];
+	memcpy(&table->params, params, sizeof(*params));
+	table->ap = ap;
+	table->a = action;
+	pipeline->n_tables++;
+
+	return 0;
+}
diff --git a/examples/ip_pipeline/pipeline.h b/examples/ip_pipeline/pipeline.h
new file mode 100644
index 0000000..39e1008
--- /dev/null
+++ b/examples/ip_pipeline/pipeline.h
@@ -0,0 +1,272 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#ifndef _INCLUDE_PIPELINE_H_
+#define _INCLUDE_PIPELINE_H_
+
+#include <stdint.h>
+#include <sys/queue.h>
+
+#include <rte_pipeline.h>
+#include <rte_table_action.h>
+
+#include "common.h"
+#include "action.h"
+
+struct pipeline_params {
+	uint32_t timer_period_ms;
+	uint32_t offset_port_id;
+	uint32_t cpu_id;
+};
+
+enum port_in_type {
+	PORT_IN_RXQ,
+	PORT_IN_SWQ,
+	PORT_IN_TMGR,
+	PORT_IN_TAP,
+	PORT_IN_KNI,
+	PORT_IN_SOURCE,
+};
+
+struct port_in_params {
+	/* Read */
+	enum port_in_type type;
+	const char *dev_name;
+	union {
+		struct {
+			uint16_t queue_id;
+		} rxq;
+
+		struct {
+			const char *mempool_name;
+			uint32_t mtu;
+		} tap;
+
+		struct {
+			const char *mempool_name;
+			const char *file_name;
+			uint32_t n_bytes_per_pkt;
+		} source;
+	};
+	uint32_t burst_size;
+
+	/* Action */
+	const char *action_profile_name;
+};
+
+enum port_out_type {
+	PORT_OUT_TXQ,
+	PORT_OUT_SWQ,
+	PORT_OUT_TMGR,
+	PORT_OUT_TAP,
+	PORT_OUT_KNI,
+	PORT_OUT_SINK,
+};
+
+struct port_out_params {
+	enum port_out_type type;
+	const char *dev_name;
+	union {
+		struct {
+			uint16_t queue_id;
+		} txq;
+
+		struct {
+			const char *file_name;
+			uint32_t max_n_pkts;
+		} sink;
+	};
+	uint32_t burst_size;
+	int retry;
+	uint32_t n_retries;
+};
+
+enum table_type {
+	TABLE_ACL,
+	TABLE_ARRAY,
+	TABLE_HASH,
+	TABLE_LPM,
+	TABLE_STUB,
+};
+
+struct table_acl_params {
+	uint32_t n_rules;
+	uint32_t ip_header_offset;
+	int ip_version;
+};
+
+struct table_array_params {
+	uint32_t n_keys;
+	uint32_t key_offset;
+};
+
+struct table_hash_params {
+	uint32_t n_keys;
+	uint32_t key_offset;
+	uint32_t key_size;
+	uint8_t *key_mask;
+	uint32_t n_buckets;
+	int extendable_bucket;
+};
+
+struct table_lpm_params {
+	uint32_t n_rules;
+	uint32_t key_offset;
+	uint32_t key_size;
+};
+
+struct table_params {
+	/* Match */
+	enum table_type match_type;
+	union {
+		struct table_acl_params acl;
+		struct table_array_params array;
+		struct table_hash_params hash;
+		struct table_lpm_params lpm;
+	} match;
+
+	/* Action */
+	const char *action_profile_name;
+};
+
+struct port_in {
+	struct port_in_params params;
+	struct port_in_action_profile *ap;
+	struct rte_port_in_action *a;
+};
+
+struct table {
+	struct table_params params;
+	struct table_action_profile *ap;
+	struct rte_table_action *a;
+};
+
+struct pipeline {
+	TAILQ_ENTRY(pipeline) node;
+	char name[NAME_SIZE];
+
+	struct rte_pipeline *p;
+	struct port_in port_in[RTE_PIPELINE_PORT_IN_MAX];
+	struct table table[RTE_PIPELINE_TABLE_MAX];
+	uint32_t n_ports_in;
+	uint32_t n_ports_out;
+	uint32_t n_tables;
+
+	struct rte_ring *msgq_req;
+	struct rte_ring *msgq_rsp;
+	uint32_t timer_period_ms;
+
+	int enabled;
+	uint32_t thread_id;
+	uint32_t cpu_id;
+};
+
+TAILQ_HEAD(pipeline_list, pipeline);
+
+int
+pipeline_init(void);
+
+struct pipeline *
+pipeline_find(const char *name);
+
+struct pipeline *
+pipeline_create(const char *name, struct pipeline_params *params);
+
+int
+pipeline_port_in_create(const char *pipeline_name,
+	struct port_in_params *params,
+	int enabled);
+
+int
+pipeline_port_in_connect_to_table(const char *pipeline_name,
+	uint32_t port_id,
+	uint32_t table_id);
+
+int
+pipeline_port_out_create(const char *pipeline_name,
+	struct port_out_params *params);
+
+int
+pipeline_table_create(const char *pipeline_name,
+	struct table_params *params);
+
+struct table_rule_match_acl {
+	int ip_version;
+
+	RTE_STD_C11
+	union {
+		struct {
+			uint32_t sa;
+			uint32_t da;
+		} ipv4;
+
+		struct {
+			uint8_t sa[16];
+			uint8_t da[16];
+		} ipv6;
+	};
+
+	uint32_t sa_depth;
+	uint32_t da_depth;
+	uint16_t sp0;
+	uint16_t sp1;
+	uint16_t dp0;
+	uint16_t dp1;
+	uint8_t proto;
+	uint8_t proto_mask;
+	uint32_t priority;
+};
+
+struct table_rule_match_array {
+	uint32_t pos;
+};
+
+#ifndef TABLE_RULE_MATCH_SIZE_MAX
+#define TABLE_RULE_MATCH_SIZE_MAX                          256
+#endif
+
+#ifndef TABLE_RULE_ACTION_SIZE_MAX
+#define TABLE_RULE_ACTION_SIZE_MAX                         2048
+#endif
+
+struct table_rule_match_hash {
+	uint8_t key[TABLE_RULE_MATCH_SIZE_MAX];
+};
+
+struct table_rule_match_lpm {
+	int ip_version;
+
+	RTE_STD_C11
+	union {
+		uint32_t ipv4;
+		uint8_t ipv6[16];
+	};
+
+	uint8_t depth;
+};
+
+struct table_rule_match {
+	enum table_type match_type;
+
+	union {
+		struct table_rule_match_acl acl;
+		struct table_rule_match_array array;
+		struct table_rule_match_hash hash;
+		struct table_rule_match_lpm lpm;
+	} match;
+};
+
+struct table_rule_action {
+	uint64_t action_mask;
+	struct rte_table_action_fwd_params fwd;
+	struct rte_table_action_mtr_params mtr;
+	struct rte_table_action_tm_params tm;
+	struct rte_table_action_encap_params encap;
+	struct rte_table_action_nat_params nat;
+	struct rte_table_action_ttl_params ttl;
+	struct rte_table_action_stats_params stats;
+	struct rte_table_action_time_params time;
+};
+
+#endif /* _INCLUDE_PIPELINE_H_ */
-- 
2.9.3

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

* [dpdk-dev] [PATCH v4 30/49] ip_pipeline: add threads
  2018-03-29 18:31           ` [dpdk-dev] [PATCH v4 00/49] ip_pipeline: refactoring Jasvinder Singh
                               ` (28 preceding siblings ...)
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 29/49] ip_pipeline: add pipeline object Jasvinder Singh
@ 2018-03-29 18:31             ` Jasvinder Singh
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 31/49] ip_pipeline: add thread runtime Jasvinder Singh
                               ` (19 subsequent siblings)
  49 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-29 18:31 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add threads data structure and initialisation functions to run
the pipeline.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/Makefile    |   2 +-
 examples/ip_pipeline/main.c      |   8 ++
 examples/ip_pipeline/meson.build |   1 +
 examples/ip_pipeline/thread.c    | 156 +++++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/thread.h    |  13 ++++
 5 files changed, 179 insertions(+), 1 deletion(-)
 create mode 100644 examples/ip_pipeline/thread.c
 create mode 100644 examples/ip_pipeline/thread.h

diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index 033319d..c936d1e 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/Makefile
@@ -16,8 +16,8 @@ SRCS-y += parser.c
 SRCS-y += pipeline.c
 SRCS-y += swq.c
 SRCS-y += tap.c
+SRCS-y += thread.c
 SRCS-y += tmgr.c
-#SRCS-y += thread.c
 
 # Build using pkg-config variables if possible
 $(shell pkg-config --exists libdpdk)
diff --git a/examples/ip_pipeline/main.c b/examples/ip_pipeline/main.c
index ab8e2b9..45f0739 100644
--- a/examples/ip_pipeline/main.c
+++ b/examples/ip_pipeline/main.c
@@ -18,6 +18,7 @@
 #include "pipeline.h"
 #include "swq.h"
 #include "tap.h"
+#include "thread.h"
 #include "tmgr.h"
 
 static const char usage[] =
@@ -229,6 +230,13 @@ main(int argc, char **argv)
 		return status;
 	}
 
+	/* Thread */
+	status = thread_init();
+	if (status) {
+		printf("Error: Thread initialization failed (%d)\n", status);
+		return status;
+	}
+
 	/* Script */
 	if (app.script_name)
 		cli_script_process(app.script_name,
diff --git a/examples/ip_pipeline/meson.build b/examples/ip_pipeline/meson.build
index 2366242..a9f2ea4 100644
--- a/examples/ip_pipeline/meson.build
+++ b/examples/ip_pipeline/meson.build
@@ -20,5 +20,6 @@ sources = files(
 	'pipeline.c',
 	'swq.c',
 	'tap.c',
+	'thread.c',
 	'tmgr.c'
 )
diff --git a/examples/ip_pipeline/thread.c b/examples/ip_pipeline/thread.c
new file mode 100644
index 0000000..2c8f84c
--- /dev/null
+++ b/examples/ip_pipeline/thread.c
@@ -0,0 +1,156 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#include <stdlib.h>
+
+#include <rte_common.h>
+#include <rte_cycles.h>
+#include <rte_lcore.h>
+#include <rte_ring.h>
+
+#include <rte_table_acl.h>
+#include <rte_table_array.h>
+#include <rte_table_hash.h>
+#include <rte_table_lpm.h>
+#include <rte_table_lpm_ipv6.h>
+
+#include "common.h"
+#include "thread.h"
+#include "pipeline.h"
+
+#ifndef THREAD_PIPELINES_MAX
+#define THREAD_PIPELINES_MAX                               256
+#endif
+
+#ifndef THREAD_MSGQ_SIZE
+#define THREAD_MSGQ_SIZE                                   64
+#endif
+
+#ifndef THREAD_TIMER_PERIOD_MS
+#define THREAD_TIMER_PERIOD_MS                             100
+#endif
+
+/**
+ * Master thead: data plane thread context
+ */
+struct thread {
+	struct rte_ring *msgq_req;
+	struct rte_ring *msgq_rsp;
+
+	uint32_t enabled;
+};
+
+static struct thread thread[RTE_MAX_LCORE];
+
+/**
+ * Data plane threads: context
+ */
+struct table_data {
+	struct rte_table_action *a;
+};
+
+struct pipeline_data {
+	struct rte_pipeline *p;
+	struct table_data table_data[RTE_PIPELINE_TABLE_MAX];
+	uint32_t n_tables;
+
+	struct rte_ring *msgq_req;
+	struct rte_ring *msgq_rsp;
+	uint64_t timer_period; /* Measured in CPU cycles. */
+	uint64_t time_next;
+
+	uint8_t buffer[TABLE_RULE_ACTION_SIZE_MAX];
+};
+
+struct thread_data {
+	struct rte_pipeline *p[THREAD_PIPELINES_MAX];
+	uint32_t n_pipelines;
+
+	struct pipeline_data pipeline_data[THREAD_PIPELINES_MAX];
+	struct rte_ring *msgq_req;
+	struct rte_ring *msgq_rsp;
+	uint64_t timer_period; /* Measured in CPU cycles. */
+	uint64_t time_next;
+	uint64_t time_next_min;
+} __rte_cache_aligned;
+
+static struct thread_data thread_data[RTE_MAX_LCORE];
+
+/**
+ * Master thread: data plane thread init
+ */
+static void
+thread_free(void)
+{
+	uint32_t i;
+
+	for (i = 0; i < RTE_MAX_LCORE; i++) {
+		struct thread *t = &thread[i];
+
+		if (!rte_lcore_is_enabled(i))
+			continue;
+
+		/* MSGQs */
+		if (t->msgq_req)
+			rte_ring_free(t->msgq_req);
+
+		if (t->msgq_rsp)
+			rte_ring_free(t->msgq_rsp);
+	}
+}
+
+int
+thread_init(void)
+{
+	uint32_t i;
+
+	RTE_LCORE_FOREACH_SLAVE(i) {
+		char name[NAME_MAX];
+		struct rte_ring *msgq_req, *msgq_rsp;
+		struct thread *t = &thread[i];
+		struct thread_data *t_data = &thread_data[i];
+		uint32_t cpu_id = rte_lcore_to_socket_id(i);
+
+		/* MSGQs */
+		snprintf(name, sizeof(name), "THREAD-%04x-MSGQ-REQ", i);
+
+		msgq_req = rte_ring_create(name,
+			THREAD_MSGQ_SIZE,
+			cpu_id,
+			RING_F_SP_ENQ | RING_F_SC_DEQ);
+
+		if (msgq_req == NULL) {
+			thread_free();
+			return -1;
+		}
+
+		snprintf(name, sizeof(name), "THREAD-%04x-MSGQ-RSP", i);
+
+		msgq_rsp = rte_ring_create(name,
+			THREAD_MSGQ_SIZE,
+			cpu_id,
+			RING_F_SP_ENQ | RING_F_SC_DEQ);
+
+		if (msgq_rsp == NULL) {
+			thread_free();
+			return -1;
+		}
+
+		/* Master thread records */
+		t->msgq_req = msgq_req;
+		t->msgq_rsp = msgq_rsp;
+		t->enabled = 1;
+
+		/* Data plane thread records */
+		t_data->n_pipelines = 0;
+		t_data->msgq_req = msgq_req;
+		t_data->msgq_rsp = msgq_rsp;
+		t_data->timer_period =
+			(rte_get_tsc_hz() * THREAD_TIMER_PERIOD_MS) / 1000;
+		t_data->time_next = rte_get_tsc_cycles() + t_data->timer_period;
+		t_data->time_next_min = t_data->time_next;
+	}
+
+	return 0;
+}
diff --git a/examples/ip_pipeline/thread.h b/examples/ip_pipeline/thread.h
new file mode 100644
index 0000000..39c0d89
--- /dev/null
+++ b/examples/ip_pipeline/thread.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+#ifndef _INCLUDE_THREAD_H_
+#define _INCLUDE_THREAD_H_
+
+#include <stdint.h>
+
+int
+thread_init(void);
+
+#endif /* _INCLUDE_THREAD_H_ */
-- 
2.9.3

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

* [dpdk-dev] [PATCH v4 31/49] ip_pipeline: add thread runtime
  2018-03-29 18:31           ` [dpdk-dev] [PATCH v4 00/49] ip_pipeline: refactoring Jasvinder Singh
                               ` (29 preceding siblings ...)
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 30/49] ip_pipeline: add threads Jasvinder Singh
@ 2018-03-29 18:31             ` Jasvinder Singh
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 32/49] ip_pipeline: add cli to enable and disable pipeline Jasvinder Singh
                               ` (18 subsequent siblings)
  49 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-29 18:31 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add runtime thread functions for the pipeline.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/main.c   |   6 ++
 examples/ip_pipeline/thread.c | 193 ++++++++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/thread.h |   3 +
 3 files changed, 202 insertions(+)

diff --git a/examples/ip_pipeline/main.c b/examples/ip_pipeline/main.c
index 45f0739..a69face 100644
--- a/examples/ip_pipeline/main.c
+++ b/examples/ip_pipeline/main.c
@@ -8,6 +8,7 @@
 #include <unistd.h>
 #include <getopt.h>
 
+#include <rte_launch.h>
 #include <rte_eal.h>
 
 #include "cli.h"
@@ -237,6 +238,11 @@ main(int argc, char **argv)
 		return status;
 	}
 
+	rte_eal_mp_remote_launch(
+		thread_main,
+		NULL,
+		SKIP_MASTER);
+
 	/* Script */
 	if (app.script_name)
 		cli_script_process(app.script_name,
diff --git a/examples/ip_pipeline/thread.c b/examples/ip_pipeline/thread.c
index 2c8f84c..805a2ae 100644
--- a/examples/ip_pipeline/thread.c
+++ b/examples/ip_pipeline/thread.c
@@ -154,3 +154,196 @@ thread_init(void)
 
 	return 0;
 }
+
+/**
+ * Master thread & data plane threads: message passing
+ */
+enum thread_req_type {
+	THREAD_REQ_MAX
+};
+
+struct thread_msg_req {
+	enum thread_req_type type;
+};
+
+struct thread_msg_rsp {
+	int status;
+};
+
+/**
+ * Data plane threads: message handling
+ */
+static inline struct thread_msg_req *
+thread_msg_recv(struct rte_ring *msgq_req)
+{
+	struct thread_msg_req *req;
+
+	int status = rte_ring_sc_dequeue(msgq_req, (void **) &req);
+
+	if (status != 0)
+		return NULL;
+
+	return req;
+}
+
+static inline void
+thread_msg_send(struct rte_ring *msgq_rsp,
+	struct thread_msg_rsp *rsp)
+{
+	int status;
+
+	do {
+		status = rte_ring_sp_enqueue(msgq_rsp, rsp);
+	} while (status == -ENOBUFS);
+}
+
+static void
+thread_msg_handle(struct thread_data *t)
+{
+	for ( ; ; ) {
+		struct thread_msg_req *req;
+		struct thread_msg_rsp *rsp;
+
+		req = thread_msg_recv(t->msgq_req);
+		if (req == NULL)
+			break;
+
+		switch (req->type) {
+		default:
+			rsp = (struct thread_msg_rsp *) req;
+			rsp->status = -1;
+		}
+
+		thread_msg_send(t->msgq_rsp, rsp);
+	}
+}
+
+/**
+ * Master thread & data plane threads: message passing
+ */
+
+enum pipeline_req_type {
+	PIPELINE_REQ_MAX
+};
+
+struct pipeline_msg_req {
+	enum pipeline_req_type type;
+};
+
+struct pipeline_msg_rsp {
+	int status;
+};
+
+/**
+ * Data plane threads: message handling
+ */
+static inline struct pipeline_msg_req *
+pipeline_msg_recv(struct rte_ring *msgq_req)
+{
+	struct pipeline_msg_req *req;
+
+	int status = rte_ring_sc_dequeue(msgq_req, (void **) &req);
+
+	if (status != 0)
+		return NULL;
+
+	return req;
+}
+
+static inline void
+pipeline_msg_send(struct rte_ring *msgq_rsp,
+	struct pipeline_msg_rsp *rsp)
+{
+	int status;
+
+	do {
+		status = rte_ring_sp_enqueue(msgq_rsp, rsp);
+	} while (status == -ENOBUFS);
+}
+
+static void
+pipeline_msg_handle(struct pipeline_data *p)
+{
+	for ( ; ; ) {
+		struct pipeline_msg_req *req;
+		struct pipeline_msg_rsp *rsp;
+
+		req = pipeline_msg_recv(p->msgq_req);
+		if (req == NULL)
+			break;
+
+		switch (req->type) {
+		default:
+			rsp = (struct pipeline_msg_rsp *) req;
+			rsp->status = -1;
+		}
+
+		pipeline_msg_send(p->msgq_rsp, rsp);
+	}
+}
+
+/**
+ * Data plane threads: main
+ */
+int
+thread_main(void *arg __rte_unused)
+{
+	struct thread_data *t;
+	uint32_t thread_id, i;
+
+	thread_id = rte_lcore_id();
+	t = &thread_data[thread_id];
+
+	/* Dispatch loop */
+	for (i = 0; ; i++) {
+		uint32_t j;
+
+		/* Data Plane */
+		for (j = 0; j < t->n_pipelines; j++)
+			rte_pipeline_run(t->p[j]);
+
+		/* Control Plane */
+		if ((i & 0xF) == 0) {
+			uint64_t time = rte_get_tsc_cycles();
+			uint64_t time_next_min = UINT64_MAX;
+
+			if (time < t->time_next_min)
+				continue;
+
+			/* Pipeline message queues */
+			for (j = 0; j < t->n_pipelines; j++) {
+				struct pipeline_data *p =
+					&t->pipeline_data[j];
+				uint64_t time_next = p->time_next;
+
+				if (time_next <= time) {
+					pipeline_msg_handle(p);
+					rte_pipeline_flush(p->p);
+					time_next = time + p->timer_period;
+					p->time_next = time_next;
+				}
+
+				if (time_next < time_next_min)
+					time_next_min = time_next;
+			}
+
+			/* Thread message queues */
+			{
+				uint64_t time_next = t->time_next;
+
+				if (time_next <= time) {
+					thread_msg_handle(t);
+					time_next = time + t->timer_period;
+					t->time_next = time_next;
+				}
+
+				if (time_next < time_next_min)
+					time_next_min = time_next;
+			}
+
+			t->time_next_min = time_next_min;
+		}
+	}
+
+	return 0;
+}
diff --git a/examples/ip_pipeline/thread.h b/examples/ip_pipeline/thread.h
index 39c0d89..47db428 100644
--- a/examples/ip_pipeline/thread.h
+++ b/examples/ip_pipeline/thread.h
@@ -10,4 +10,7 @@
 int
 thread_init(void);
 
+int
+thread_main(void *arg);
+
 #endif /* _INCLUDE_THREAD_H_ */
-- 
2.9.3

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

* [dpdk-dev] [PATCH v4 32/49] ip_pipeline: add cli to enable and disable pipeline
  2018-03-29 18:31           ` [dpdk-dev] [PATCH v4 00/49] ip_pipeline: refactoring Jasvinder Singh
                               ` (30 preceding siblings ...)
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 31/49] ip_pipeline: add thread runtime Jasvinder Singh
@ 2018-03-29 18:31             ` Jasvinder Singh
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 33/49] ip_pipeline: add cli to enable and disable pipeline port Jasvinder Singh
                               ` (17 subsequent siblings)
  49 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-29 18:31 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Fan Zhang

Add commands to enable and disable the pipeline on the thread.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Fan Zhang <roy.fan.zhang@intel.com>
---
 examples/ip_pipeline/cli.c    | 102 +++++++++++++++++
 examples/ip_pipeline/thread.c | 256 ++++++++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/thread.h |   8 ++
 3 files changed, 366 insertions(+)

diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index ec2d01f..c6ef661 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -17,6 +17,7 @@
 #include "pipeline.h"
 #include "swq.h"
 #include "tap.h"
+#include "thread.h"
 #include "tmgr.h"
 
 #ifndef CMD_MAX_TOKENS
@@ -1936,6 +1937,91 @@ cmd_pipeline_port_in_table(char **tokens,
 	}
 }
 
+/**
+ * thread <thread_id> pipeline <pipeline_name> enable
+ */
+static void
+cmd_thread_pipeline_enable(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	char *pipeline_name;
+	uint32_t thread_id;
+	int status;
+
+	if (n_tokens != 5) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	if (parser_read_uint32(&thread_id, tokens[1]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
+		return;
+	}
+
+	if (strcmp(tokens[2], "pipeline") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
+		return;
+	}
+
+	pipeline_name = tokens[3];
+
+	if (strcmp(tokens[4], "enable") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable");
+		return;
+	}
+
+	status = thread_pipeline_enable(thread_id, pipeline_name);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, "thread pipeline enable");
+		return;
+	}
+}
+
+/**
+ * thread <thread_id> pipeline <pipeline_name> disable
+ */
+static void
+cmd_thread_pipeline_disable(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	char *pipeline_name;
+	uint32_t thread_id;
+	int status;
+
+	if (n_tokens != 5) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	if (parser_read_uint32(&thread_id, tokens[1]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "thread_id");
+		return;
+	}
+
+	if (strcmp(tokens[2], "pipeline") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline");
+		return;
+	}
+
+	pipeline_name = tokens[3];
+
+	if (strcmp(tokens[4], "disable") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable");
+		return;
+	}
+
+	status = thread_pipeline_disable(thread_id, pipeline_name);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL,
+			"thread pipeline disable");
+		return;
+	}
+}
+
 void
 cli_process(char *in, char *out, size_t out_size)
 {
@@ -2064,6 +2150,22 @@ cli_process(char *in, char *out, size_t out_size)
 		}
 	}
 
+	if (strcmp(tokens[0], "thread") == 0) {
+		if ((n_tokens >= 5) &&
+			(strcmp(tokens[4], "enable") == 0)) {
+			cmd_thread_pipeline_enable(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
+
+		if ((n_tokens >= 5) &&
+			(strcmp(tokens[4], "disable") == 0)) {
+			cmd_thread_pipeline_disable(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
+	}
+
 	snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]);
 }
 
diff --git a/examples/ip_pipeline/thread.c b/examples/ip_pipeline/thread.c
index 805a2ae..6c555dc 100644
--- a/examples/ip_pipeline/thread.c
+++ b/examples/ip_pipeline/thread.c
@@ -159,11 +159,30 @@ thread_init(void)
  * Master thread & data plane threads: message passing
  */
 enum thread_req_type {
+	THREAD_REQ_PIPELINE_ENABLE = 0,
+	THREAD_REQ_PIPELINE_DISABLE,
 	THREAD_REQ_MAX
 };
 
 struct thread_msg_req {
 	enum thread_req_type type;
+
+	union {
+		struct {
+			struct rte_pipeline *p;
+			struct {
+				struct rte_table_action *a;
+			} table[RTE_PIPELINE_TABLE_MAX];
+			struct rte_ring *msgq_req;
+			struct rte_ring *msgq_rsp;
+			uint32_t timer_period_ms;
+			uint32_t n_tables;
+		} pipeline_enable;
+
+		struct {
+			struct rte_pipeline *p;
+		} pipeline_disable;
+	};
 };
 
 struct thread_msg_rsp {
@@ -171,6 +190,162 @@ struct thread_msg_rsp {
 };
 
 /**
+ * Master thread
+ */
+static struct thread_msg_req *
+thread_msg_alloc(void)
+{
+	size_t size = RTE_MAX(sizeof(struct thread_msg_req),
+		sizeof(struct thread_msg_rsp));
+
+	return calloc(1, size);
+}
+
+static void
+thread_msg_free(struct thread_msg_rsp *rsp)
+{
+	free(rsp);
+}
+
+static struct thread_msg_rsp *
+thread_msg_send_recv(uint32_t thread_id,
+	struct thread_msg_req *req)
+{
+	struct thread *t = &thread[thread_id];
+	struct rte_ring *msgq_req = t->msgq_req;
+	struct rte_ring *msgq_rsp = t->msgq_rsp;
+	struct thread_msg_rsp *rsp;
+	int status;
+
+	/* send */
+	do {
+		status = rte_ring_sp_enqueue(msgq_req, req);
+	} while (status == -ENOBUFS);
+
+	/* recv */
+	do {
+		status = rte_ring_sc_dequeue(msgq_rsp, (void **) &rsp);
+	} while (status != 0);
+
+	return rsp;
+}
+
+int
+thread_pipeline_enable(uint32_t thread_id,
+	const char *pipeline_name)
+{
+	struct pipeline *p = pipeline_find(pipeline_name);
+	struct thread *t;
+	struct thread_msg_req *req;
+	struct thread_msg_rsp *rsp;
+	uint32_t i;
+	int status;
+
+	/* Check input params */
+	if ((thread_id >= RTE_MAX_LCORE) ||
+		(p == NULL) ||
+		(p->n_ports_in == 0) ||
+		(p->n_ports_out == 0) ||
+		(p->n_tables == 0))
+		return -1;
+
+	t = &thread[thread_id];
+	if ((t->enabled == 0) ||
+		p->enabled)
+		return -1;
+
+	/* Allocate request */
+	req = thread_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = THREAD_REQ_PIPELINE_ENABLE;
+	req->pipeline_enable.p = p->p;
+	for (i = 0; i < p->n_tables; i++)
+		req->pipeline_enable.table[i].a =
+			p->table[i].a;
+	req->pipeline_enable.msgq_req = p->msgq_req;
+	req->pipeline_enable.msgq_rsp = p->msgq_rsp;
+	req->pipeline_enable.timer_period_ms = p->timer_period_ms;
+	req->pipeline_enable.n_tables = p->n_tables;
+
+	/* Send request and wait for response */
+	rsp = thread_msg_send_recv(thread_id, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+
+	/* Free response */
+	thread_msg_free(rsp);
+
+	/* Request completion */
+	if (status)
+		return status;
+
+	p->thread_id = thread_id;
+	p->enabled = 1;
+
+	return 0;
+}
+
+int
+thread_pipeline_disable(uint32_t thread_id,
+	const char *pipeline_name)
+{
+	struct pipeline *p = pipeline_find(pipeline_name);
+	struct thread *t;
+	struct thread_msg_req *req;
+	struct thread_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if ((thread_id >= RTE_MAX_LCORE) ||
+		(p == NULL))
+		return -1;
+
+	t = &thread[thread_id];
+	if (t->enabled == 0)
+		return -1;
+
+	if (p->enabled == 0)
+		return 0;
+
+	if (p->thread_id != thread_id)
+		return -1;
+
+	/* Allocate request */
+	req = thread_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = THREAD_REQ_PIPELINE_DISABLE;
+	req->pipeline_disable.p = p->p;
+
+	/* Send request and wait for response */
+	rsp = thread_msg_send_recv(thread_id, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+
+	/* Free response */
+	thread_msg_free(rsp);
+
+	/* Request completion */
+	if (status)
+		return status;
+
+	p->enabled = 0;
+
+	return 0;
+}
+
+/**
  * Data plane threads: message handling
  */
 static inline struct thread_msg_req *
@@ -197,6 +372,79 @@ thread_msg_send(struct rte_ring *msgq_rsp,
 	} while (status == -ENOBUFS);
 }
 
+static struct thread_msg_rsp *
+thread_msg_handle_pipeline_enable(struct thread_data *t,
+	struct thread_msg_req *req)
+{
+	struct thread_msg_rsp *rsp = (struct thread_msg_rsp *) req;
+	struct pipeline_data *p = &t->pipeline_data[t->n_pipelines];
+	uint32_t i;
+
+	/* Request */
+	if (t->n_pipelines >= THREAD_PIPELINES_MAX) {
+		rsp->status = -1;
+		return rsp;
+	}
+
+	t->p[t->n_pipelines] = req->pipeline_enable.p;
+
+	p->p = req->pipeline_enable.p;
+	for (i = 0; i < req->pipeline_enable.n_tables; i++)
+		p->table_data[i].a =
+			req->pipeline_enable.table[i].a;
+
+	p->n_tables = req->pipeline_enable.n_tables;
+
+	p->msgq_req = req->pipeline_enable.msgq_req;
+	p->msgq_rsp = req->pipeline_enable.msgq_rsp;
+	p->timer_period =
+		(rte_get_tsc_hz() * req->pipeline_enable.timer_period_ms) / 1000;
+	p->time_next = rte_get_tsc_cycles() + p->timer_period;
+
+	t->n_pipelines++;
+
+	/* Response */
+	rsp->status = 0;
+	return rsp;
+}
+
+static struct thread_msg_rsp *
+thread_msg_handle_pipeline_disable(struct thread_data *t,
+	struct thread_msg_req *req)
+{
+	struct thread_msg_rsp *rsp = (struct thread_msg_rsp *) req;
+	uint32_t n_pipelines = t->n_pipelines;
+	struct rte_pipeline *pipeline = req->pipeline_disable.p;
+	uint32_t i;
+
+	/* find pipeline */
+	for (i = 0; i < n_pipelines; i++) {
+		struct pipeline_data *p = &t->pipeline_data[i];
+
+		if (p->p != pipeline)
+			continue;
+
+		if (i < n_pipelines - 1) {
+			struct rte_pipeline *pipeline_last =
+				t->p[n_pipelines - 1];
+			struct pipeline_data *p_last =
+				&t->pipeline_data[n_pipelines - 1];
+
+			t->p[i] = pipeline_last;
+			memcpy(p, p_last, sizeof(*p));
+		}
+
+		t->n_pipelines--;
+
+		rsp->status = 0;
+		return rsp;
+	}
+
+	/* should not get here */
+	rsp->status = 0;
+	return rsp;
+}
+
 static void
 thread_msg_handle(struct thread_data *t)
 {
@@ -209,6 +457,14 @@ thread_msg_handle(struct thread_data *t)
 			break;
 
 		switch (req->type) {
+		case THREAD_REQ_PIPELINE_ENABLE:
+			rsp = thread_msg_handle_pipeline_enable(t, req);
+			break;
+
+		case THREAD_REQ_PIPELINE_DISABLE:
+			rsp = thread_msg_handle_pipeline_disable(t, req);
+			break;
+
 		default:
 			rsp = (struct thread_msg_rsp *) req;
 			rsp->status = -1;
diff --git a/examples/ip_pipeline/thread.h b/examples/ip_pipeline/thread.h
index 47db428..facdf00 100644
--- a/examples/ip_pipeline/thread.h
+++ b/examples/ip_pipeline/thread.h
@@ -8,6 +8,14 @@
 #include <stdint.h>
 
 int
+thread_pipeline_enable(uint32_t thread_id,
+	const char *pipeline_name);
+
+int
+thread_pipeline_disable(uint32_t thread_id,
+	const char *pipeline_name);
+
+int
 thread_init(void);
 
 int
-- 
2.9.3

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

* [dpdk-dev] [PATCH v4 33/49] ip_pipeline: add cli to enable and disable pipeline port
  2018-03-29 18:31           ` [dpdk-dev] [PATCH v4 00/49] ip_pipeline: refactoring Jasvinder Singh
                               ` (31 preceding siblings ...)
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 32/49] ip_pipeline: add cli to enable and disable pipeline Jasvinder Singh
@ 2018-03-29 18:31             ` Jasvinder Singh
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 34/49] ip_pipeline: add cli to read pipeline port and table stats Jasvinder Singh
                               ` (16 subsequent siblings)
  49 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-29 18:31 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Fan Zhang

Add commands to enable and disable the pipeline ports.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Fan Zhang <roy.fan.zhang@intel.com>
---
 examples/ip_pipeline/cli.c      | 112 +++++++++++++++++++++++++++
 examples/ip_pipeline/pipeline.h |   8 ++
 examples/ip_pipeline/thread.c   | 165 +++++++++++++++++++++++++++++++++++++++-
 3 files changed, 284 insertions(+), 1 deletion(-)

diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index c6ef661..20eb781 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -1938,6 +1938,100 @@ cmd_pipeline_port_in_table(char **tokens,
 }
 
 /**
+ * pipeline <pipeline_name> port in <port_id> enable
+ */
+static void
+cmd_pipeline_port_in_enable(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	char *pipeline_name;
+	uint32_t port_id;
+	int status;
+
+	if (n_tokens != 6) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "port") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
+		return;
+	}
+
+	if (strcmp(tokens[3], "in") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
+		return;
+	}
+
+	if (parser_read_uint32(&port_id, tokens[4]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
+		return;
+	}
+
+	if (strcmp(tokens[5], "enable") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable");
+		return;
+	}
+
+	status = pipeline_port_in_enable(pipeline_name, port_id);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
+ * pipeline <pipeline_name> port in <port_id> disable
+ */
+static void
+cmd_pipeline_port_in_disable(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	char *pipeline_name;
+	uint32_t port_id;
+	int status;
+
+	if (n_tokens != 6) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "port") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
+		return;
+	}
+
+	if (strcmp(tokens[3], "in") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
+		return;
+	}
+
+	if (parser_read_uint32(&port_id, tokens[4]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
+		return;
+	}
+
+	if (strcmp(tokens[5], "disable") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable");
+		return;
+	}
+
+	status = pipeline_port_in_disable(pipeline_name, port_id);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
  * thread <thread_id> pipeline <pipeline_name> enable
  */
 static void
@@ -2148,6 +2242,24 @@ cli_process(char *in, char *out, size_t out_size)
 				out, out_size);
 			return;
 		}
+
+		if ((n_tokens >= 6) &&
+			(strcmp(tokens[2], "port") == 0) &&
+			(strcmp(tokens[3], "in") == 0) &&
+			(strcmp(tokens[5], "enable") == 0)) {
+			cmd_pipeline_port_in_enable(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
+
+		if ((n_tokens >= 6) &&
+			(strcmp(tokens[2], "port") == 0) &&
+			(strcmp(tokens[3], "in") == 0) &&
+			(strcmp(tokens[5], "disable") == 0)) {
+			cmd_pipeline_port_in_disable(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
 	}
 
 	if (strcmp(tokens[0], "thread") == 0) {
diff --git a/examples/ip_pipeline/pipeline.h b/examples/ip_pipeline/pipeline.h
index 39e1008..08b2555 100644
--- a/examples/ip_pipeline/pipeline.h
+++ b/examples/ip_pipeline/pipeline.h
@@ -269,4 +269,12 @@ struct table_rule_action {
 	struct rte_table_action_time_params time;
 };
 
+int
+pipeline_port_in_enable(const char *pipeline_name,
+	uint32_t port_id);
+
+int
+pipeline_port_in_disable(const char *pipeline_name,
+	uint32_t port_id);
+
 #endif /* _INCLUDE_PIPELINE_H_ */
diff --git a/examples/ip_pipeline/thread.c b/examples/ip_pipeline/thread.c
index 6c555dc..35c4de3 100644
--- a/examples/ip_pipeline/thread.c
+++ b/examples/ip_pipeline/thread.c
@@ -477,13 +477,17 @@ thread_msg_handle(struct thread_data *t)
 /**
  * Master thread & data plane threads: message passing
  */
-
 enum pipeline_req_type {
+	/* Port IN */
+	PIPELINE_REQ_PORT_IN_ENABLE,
+	PIPELINE_REQ_PORT_IN_DISABLE,
+
 	PIPELINE_REQ_MAX
 };
 
 struct pipeline_msg_req {
 	enum pipeline_req_type type;
+	uint32_t id; /* Port IN, port OUT or table ID */
 };
 
 struct pipeline_msg_rsp {
@@ -491,6 +495,131 @@ struct pipeline_msg_rsp {
 };
 
 /**
+ * Master thread
+ */
+static struct pipeline_msg_req *
+pipeline_msg_alloc(void)
+{
+	size_t size = RTE_MAX(sizeof(struct pipeline_msg_req),
+		sizeof(struct pipeline_msg_rsp));
+
+	return calloc(1, size);
+}
+
+static void
+pipeline_msg_free(struct pipeline_msg_rsp *rsp)
+{
+	free(rsp);
+}
+
+static struct pipeline_msg_rsp *
+pipeline_msg_send_recv(struct pipeline *p,
+	struct pipeline_msg_req *req)
+{
+	struct rte_ring *msgq_req = p->msgq_req;
+	struct rte_ring *msgq_rsp = p->msgq_rsp;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* send */
+	do {
+		status = rte_ring_sp_enqueue(msgq_req, req);
+	} while (status == -ENOBUFS);
+
+	/* recv */
+	do {
+		status = rte_ring_sc_dequeue(msgq_rsp, (void **) &rsp);
+	} while (status != 0);
+
+	return rsp;
+}
+
+int
+pipeline_port_in_enable(const char *pipeline_name,
+	uint32_t port_id)
+{
+	struct pipeline *p;
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if (pipeline_name == NULL)
+		return -1;
+
+	p = pipeline_find(pipeline_name);
+	if ((p == NULL) ||
+		(p->enabled == 0) ||
+		(port_id >= p->n_ports_in))
+		return -1;
+
+	/* Allocate request */
+	req = pipeline_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = PIPELINE_REQ_PORT_IN_ENABLE;
+	req->id = port_id;
+
+	/* Send request and wait for response */
+	rsp = pipeline_msg_send_recv(p, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+
+	/* Free response */
+	pipeline_msg_free(rsp);
+
+	return status;
+}
+
+int
+pipeline_port_in_disable(const char *pipeline_name,
+	uint32_t port_id)
+{
+	struct pipeline *p;
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if (pipeline_name == NULL)
+		return -1;
+
+	p = pipeline_find(pipeline_name);
+	if ((p == NULL) ||
+		(p->enabled == 0) ||
+		(port_id >= p->n_ports_in))
+		return -1;
+
+	/* Allocate request */
+	req = pipeline_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = PIPELINE_REQ_PORT_IN_DISABLE;
+	req->id = port_id;
+
+	/* Send request and wait for response */
+	rsp = pipeline_msg_send_recv(p, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+
+	/* Free response */
+	pipeline_msg_free(rsp);
+
+	return status;
+}
+
+
+/**
  * Data plane threads: message handling
  */
 static inline struct pipeline_msg_req *
@@ -517,6 +646,32 @@ pipeline_msg_send(struct rte_ring *msgq_rsp,
 	} while (status == -ENOBUFS);
 }
 
+static struct pipeline_msg_rsp *
+pipeline_msg_handle_port_in_enable(struct pipeline_data *p,
+	struct pipeline_msg_req *req)
+{
+	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+	uint32_t port_id = req->id;
+
+	rsp->status = rte_pipeline_port_in_enable(p->p,
+		port_id);
+
+	return rsp;
+}
+
+static struct pipeline_msg_rsp *
+pipeline_msg_handle_port_in_disable(struct pipeline_data *p,
+	struct pipeline_msg_req *req)
+{
+	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+	uint32_t port_id = req->id;
+
+	rsp->status = rte_pipeline_port_in_disable(p->p,
+		port_id);
+
+	return rsp;
+}
+
 static void
 pipeline_msg_handle(struct pipeline_data *p)
 {
@@ -529,6 +684,14 @@ pipeline_msg_handle(struct pipeline_data *p)
 			break;
 
 		switch (req->type) {
+		case PIPELINE_REQ_PORT_IN_ENABLE:
+			rsp = pipeline_msg_handle_port_in_enable(p, req);
+			break;
+
+		case PIPELINE_REQ_PORT_IN_DISABLE:
+			rsp = pipeline_msg_handle_port_in_disable(p, req);
+			break;
+
 		default:
 			rsp = (struct pipeline_msg_rsp *) req;
 			rsp->status = -1;
-- 
2.9.3

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

* [dpdk-dev] [PATCH v4 34/49] ip_pipeline: add cli to read pipeline port and table stats
  2018-03-29 18:31           ` [dpdk-dev] [PATCH v4 00/49] ip_pipeline: refactoring Jasvinder Singh
                               ` (32 preceding siblings ...)
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 33/49] ip_pipeline: add cli to enable and disable pipeline port Jasvinder Singh
@ 2018-03-29 18:31             ` Jasvinder Singh
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 35/49] ip_pipeline: add cli for pipeline table entry Jasvinder Singh
                               ` (15 subsequent siblings)
  49 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-29 18:31 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Fan Zhang

Add commands to read the pipeline  port in, port out
and table stats.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Fan Zhang <roy.fan.zhang@intel.com>
---
 examples/ip_pipeline/cli.c      | 256 ++++++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/pipeline.h |  18 +++
 examples/ip_pipeline/thread.c   | 249 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 523 insertions(+)

diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index 20eb781..02ff73a 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -1938,6 +1938,83 @@ cmd_pipeline_port_in_table(char **tokens,
 }
 
 /**
+ * pipeline <pipeline_name> port in <port_id> stats read [clear]
+ */
+
+#define MSG_PIPELINE_PORT_IN_STATS                         \
+	"Pkts in: %" PRIu64 "\n"                           \
+	"Pkts dropped by AH: %" PRIu64 "\n"                \
+	"Pkts dropped by other: %" PRIu64 "\n"
+
+static void
+cmd_pipeline_port_in_stats(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct rte_pipeline_port_in_stats stats;
+	char *pipeline_name;
+	uint32_t port_id;
+	int clear, status;
+
+	if ((n_tokens != 7) && (n_tokens != 8)) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "port") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
+		return;
+	}
+
+	if (strcmp(tokens[3], "in") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in");
+		return;
+	}
+
+	if (parser_read_uint32(&port_id, tokens[4]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
+		return;
+	}
+
+	if (strcmp(tokens[5], "stats") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
+		return;
+	}
+
+	if (strcmp(tokens[6], "read") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read");
+		return;
+	}
+
+	clear = 0;
+	if (n_tokens == 8) {
+		if (strcmp(tokens[7], "clear") != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "clear");
+			return;
+		}
+
+		clear = 1;
+	}
+
+	status = pipeline_port_in_stats_read(pipeline_name,
+		port_id,
+		&stats,
+		clear);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+
+	snprintf(out, out_size, MSG_PIPELINE_PORT_IN_STATS,
+		stats.stats.n_pkts_in,
+		stats.n_pkts_dropped_by_ah,
+		stats.stats.n_pkts_drop);
+}
+
+/**
  * pipeline <pipeline_name> port in <port_id> enable
  */
 static void
@@ -2032,6 +2109,159 @@ cmd_pipeline_port_in_disable(char **tokens,
 }
 
 /**
+ * pipeline <pipeline_name> port out <port_id> stats read [clear]
+ */
+#define MSG_PIPELINE_PORT_OUT_STATS                        \
+	"Pkts in: %" PRIu64 "\n"                           \
+	"Pkts dropped by AH: %" PRIu64 "\n"                \
+	"Pkts dropped by other: %" PRIu64 "\n"
+
+static void
+cmd_pipeline_port_out_stats(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct rte_pipeline_port_out_stats stats;
+	char *pipeline_name;
+	uint32_t port_id;
+	int clear, status;
+
+	if ((n_tokens != 7) && (n_tokens != 8)) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "port") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
+		return;
+	}
+
+	if (strcmp(tokens[3], "out") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "out");
+		return;
+	}
+
+	if (parser_read_uint32(&port_id, tokens[4]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
+		return;
+	}
+
+	if (strcmp(tokens[5], "stats") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
+		return;
+	}
+
+	if (strcmp(tokens[6], "read") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read");
+		return;
+	}
+
+	clear = 0;
+	if (n_tokens == 8) {
+		if (strcmp(tokens[7], "clear") != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "clear");
+			return;
+		}
+
+		clear = 1;
+	}
+
+	status = pipeline_port_out_stats_read(pipeline_name,
+		port_id,
+		&stats,
+		clear);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+
+	snprintf(out, out_size, MSG_PIPELINE_PORT_OUT_STATS,
+		stats.stats.n_pkts_in,
+		stats.n_pkts_dropped_by_ah,
+		stats.stats.n_pkts_drop);
+}
+
+/**
+ * pipeline <pipeline_name> table <table_id> stats read [clear]
+ */
+#define MSG_PIPELINE_TABLE_STATS                                     \
+	"Pkts in: %" PRIu64 "\n"                                     \
+	"Pkts in with lookup miss: %" PRIu64 "\n"                    \
+	"Pkts in with lookup hit dropped by AH: %" PRIu64 "\n"       \
+	"Pkts in with lookup hit dropped by others: %" PRIu64 "\n"   \
+	"Pkts in with lookup miss dropped by AH: %" PRIu64 "\n"      \
+	"Pkts in with lookup miss dropped by others: %" PRIu64 "\n"
+
+static void
+cmd_pipeline_table_stats(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct rte_pipeline_table_stats stats;
+	char *pipeline_name;
+	uint32_t table_id;
+	int clear, status;
+
+	if ((n_tokens != 6) && (n_tokens != 7)) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "table") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
+		return;
+	}
+
+	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
+		return;
+	}
+
+	if (strcmp(tokens[4], "stats") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats");
+		return;
+	}
+
+	if (strcmp(tokens[5], "read") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read");
+		return;
+	}
+
+	clear = 0;
+	if (n_tokens == 7) {
+		if (strcmp(tokens[6], "clear") != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "clear");
+			return;
+		}
+
+		clear = 1;
+	}
+
+	status = pipeline_table_stats_read(pipeline_name,
+		table_id,
+		&stats,
+		clear);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+
+	snprintf(out, out_size, MSG_PIPELINE_TABLE_STATS,
+		stats.stats.n_pkts_in,
+		stats.stats.n_pkts_lookup_miss,
+		stats.n_pkts_dropped_by_lkp_hit_ah,
+		stats.n_pkts_dropped_lkp_hit,
+		stats.n_pkts_dropped_by_lkp_miss_ah,
+		stats.n_pkts_dropped_lkp_miss);
+}
+
+/**
  * thread <thread_id> pipeline <pipeline_name> enable
  */
 static void
@@ -2246,6 +2476,15 @@ cli_process(char *in, char *out, size_t out_size)
 		if ((n_tokens >= 6) &&
 			(strcmp(tokens[2], "port") == 0) &&
 			(strcmp(tokens[3], "in") == 0) &&
+			(strcmp(tokens[5], "stats") == 0)) {
+			cmd_pipeline_port_in_stats(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
+
+		if ((n_tokens >= 6) &&
+			(strcmp(tokens[2], "port") == 0) &&
+			(strcmp(tokens[3], "in") == 0) &&
 			(strcmp(tokens[5], "enable") == 0)) {
 			cmd_pipeline_port_in_enable(tokens, n_tokens,
 				out, out_size);
@@ -2260,6 +2499,23 @@ cli_process(char *in, char *out, size_t out_size)
 				out, out_size);
 			return;
 		}
+
+		if ((n_tokens >= 6) &&
+			(strcmp(tokens[2], "port") == 0) &&
+			(strcmp(tokens[3], "out") == 0) &&
+			(strcmp(tokens[5], "stats") == 0)) {
+			cmd_pipeline_port_out_stats(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
+
+		if ((n_tokens >= 5) &&
+			(strcmp(tokens[2], "table") == 0) &&
+			(strcmp(tokens[4], "stats") == 0)) {
+			cmd_pipeline_table_stats(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
 	}
 
 	if (strcmp(tokens[0], "thread") == 0) {
diff --git a/examples/ip_pipeline/pipeline.h b/examples/ip_pipeline/pipeline.h
index 08b2555..5757eb5 100644
--- a/examples/ip_pipeline/pipeline.h
+++ b/examples/ip_pipeline/pipeline.h
@@ -270,6 +270,12 @@ struct table_rule_action {
 };
 
 int
+pipeline_port_in_stats_read(const char *pipeline_name,
+	uint32_t port_id,
+	struct rte_pipeline_port_in_stats *stats,
+	int clear);
+
+int
 pipeline_port_in_enable(const char *pipeline_name,
 	uint32_t port_id);
 
@@ -277,4 +283,16 @@ int
 pipeline_port_in_disable(const char *pipeline_name,
 	uint32_t port_id);
 
+int
+pipeline_port_out_stats_read(const char *pipeline_name,
+	uint32_t port_id,
+	struct rte_pipeline_port_out_stats *stats,
+	int clear);
+
+int
+pipeline_table_stats_read(const char *pipeline_name,
+	uint32_t table_id,
+	struct rte_pipeline_table_stats *stats,
+	int clear);
+
 #endif /* _INCLUDE_PIPELINE_H_ */
diff --git a/examples/ip_pipeline/thread.c b/examples/ip_pipeline/thread.c
index 35c4de3..b1a2926 100644
--- a/examples/ip_pipeline/thread.c
+++ b/examples/ip_pipeline/thread.c
@@ -479,19 +479,64 @@ thread_msg_handle(struct thread_data *t)
  */
 enum pipeline_req_type {
 	/* Port IN */
+	PIPELINE_REQ_PORT_IN_STATS_READ,
 	PIPELINE_REQ_PORT_IN_ENABLE,
 	PIPELINE_REQ_PORT_IN_DISABLE,
 
+	/* Port OUT */
+	PIPELINE_REQ_PORT_OUT_STATS_READ,
+
+	/* Table */
+	PIPELINE_REQ_TABLE_STATS_READ,
+
 	PIPELINE_REQ_MAX
 };
 
+struct pipeline_msg_req_port_in_stats_read {
+	int clear;
+};
+
+struct pipeline_msg_req_port_out_stats_read {
+	int clear;
+};
+
+struct pipeline_msg_req_table_stats_read {
+	int clear;
+};
+
 struct pipeline_msg_req {
 	enum pipeline_req_type type;
 	uint32_t id; /* Port IN, port OUT or table ID */
+
+	RTE_STD_C11
+	union {
+		struct pipeline_msg_req_port_in_stats_read port_in_stats_read;
+		struct pipeline_msg_req_port_out_stats_read port_out_stats_read;
+		struct pipeline_msg_req_table_stats_read table_stats_read;
+	};
+};
+
+struct pipeline_msg_rsp_port_in_stats_read {
+	struct rte_pipeline_port_in_stats stats;
+};
+
+struct pipeline_msg_rsp_port_out_stats_read {
+	struct rte_pipeline_port_out_stats stats;
+};
+
+struct pipeline_msg_rsp_table_stats_read {
+	struct rte_pipeline_table_stats stats;
 };
 
 struct pipeline_msg_rsp {
 	int status;
+
+	RTE_STD_C11
+	union {
+		struct pipeline_msg_rsp_port_in_stats_read port_in_stats_read;
+		struct pipeline_msg_rsp_port_out_stats_read port_out_stats_read;
+		struct pipeline_msg_rsp_table_stats_read table_stats_read;
+	};
 };
 
 /**
@@ -535,6 +580,54 @@ pipeline_msg_send_recv(struct pipeline *p,
 }
 
 int
+pipeline_port_in_stats_read(const char *pipeline_name,
+	uint32_t port_id,
+	struct rte_pipeline_port_in_stats *stats,
+	int clear)
+{
+	struct pipeline *p;
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if ((pipeline_name == NULL) ||
+		(stats == NULL))
+		return -1;
+
+	p = pipeline_find(pipeline_name);
+	if ((p == NULL) ||
+		(p->enabled == 0) ||
+		(port_id >= p->n_ports_in))
+		return -1;
+
+	/* Allocate request */
+	req = pipeline_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = PIPELINE_REQ_PORT_IN_STATS_READ;
+	req->id = port_id;
+	req->port_in_stats_read.clear = clear;
+
+	/* Send request and wait for response */
+	rsp = pipeline_msg_send_recv(p, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+	if (status)
+		memcpy(stats, &rsp->port_in_stats_read.stats, sizeof(*stats));
+
+	/* Free response */
+	pipeline_msg_free(rsp);
+
+	return status;
+}
+
+int
 pipeline_port_in_enable(const char *pipeline_name,
 	uint32_t port_id)
 {
@@ -618,6 +711,101 @@ pipeline_port_in_disable(const char *pipeline_name,
 	return status;
 }
 
+int
+pipeline_port_out_stats_read(const char *pipeline_name,
+	uint32_t port_id,
+	struct rte_pipeline_port_out_stats *stats,
+	int clear)
+{
+	struct pipeline *p;
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if ((pipeline_name == NULL) ||
+		(stats == NULL))
+		return -1;
+
+	p = pipeline_find(pipeline_name);
+	if ((p == NULL) ||
+		(p->enabled == 0) ||
+		(port_id >= p->n_ports_out))
+		return -1;
+
+	/* Allocate request */
+	req = pipeline_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = PIPELINE_REQ_PORT_OUT_STATS_READ;
+	req->id = port_id;
+	req->port_out_stats_read.clear = clear;
+
+	/* Send request and wait for response */
+	rsp = pipeline_msg_send_recv(p, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+	if (status)
+		memcpy(stats, &rsp->port_out_stats_read.stats, sizeof(*stats));
+
+	/* Free response */
+	pipeline_msg_free(rsp);
+
+	return status;
+}
+
+int
+pipeline_table_stats_read(const char *pipeline_name,
+	uint32_t table_id,
+	struct rte_pipeline_table_stats *stats,
+	int clear)
+{
+	struct pipeline *p;
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if ((pipeline_name == NULL) ||
+		(stats == NULL))
+		return -1;
+
+	p = pipeline_find(pipeline_name);
+	if ((p == NULL) ||
+		(p->enabled == 0) ||
+		(table_id >= p->n_tables))
+		return -1;
+
+	/* Allocate request */
+	req = pipeline_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = PIPELINE_REQ_TABLE_STATS_READ;
+	req->id = table_id;
+	req->table_stats_read.clear = clear;
+
+	/* Send request and wait for response */
+	rsp = pipeline_msg_send_recv(p, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+	if (status)
+		memcpy(stats, &rsp->table_stats_read.stats, sizeof(*stats));
+
+	/* Free response */
+	pipeline_msg_free(rsp);
+
+	return status;
+}
 
 /**
  * Data plane threads: message handling
@@ -647,6 +835,22 @@ pipeline_msg_send(struct rte_ring *msgq_rsp,
 }
 
 static struct pipeline_msg_rsp *
+pipeline_msg_handle_port_in_stats_read(struct pipeline_data *p,
+	struct pipeline_msg_req *req)
+{
+	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+	uint32_t port_id = req->id;
+	int clear = req->port_in_stats_read.clear;
+
+	rsp->status = rte_pipeline_port_in_stats_read(p->p,
+		port_id,
+		&rsp->port_in_stats_read.stats,
+		clear);
+
+	return rsp;
+}
+
+static struct pipeline_msg_rsp *
 pipeline_msg_handle_port_in_enable(struct pipeline_data *p,
 	struct pipeline_msg_req *req)
 {
@@ -672,6 +876,38 @@ pipeline_msg_handle_port_in_disable(struct pipeline_data *p,
 	return rsp;
 }
 
+static struct pipeline_msg_rsp *
+pipeline_msg_handle_port_out_stats_read(struct pipeline_data *p,
+	struct pipeline_msg_req *req)
+{
+	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+	uint32_t port_id = req->id;
+	int clear = req->port_out_stats_read.clear;
+
+	rsp->status = rte_pipeline_port_out_stats_read(p->p,
+		port_id,
+		&rsp->port_out_stats_read.stats,
+		clear);
+
+	return rsp;
+}
+
+static struct pipeline_msg_rsp *
+pipeline_msg_handle_table_stats_read(struct pipeline_data *p,
+	struct pipeline_msg_req *req)
+{
+	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+	uint32_t port_id = req->id;
+	int clear = req->table_stats_read.clear;
+
+	rsp->status = rte_pipeline_table_stats_read(p->p,
+		port_id,
+		&rsp->table_stats_read.stats,
+		clear);
+
+	return rsp;
+}
+
 static void
 pipeline_msg_handle(struct pipeline_data *p)
 {
@@ -684,6 +920,10 @@ pipeline_msg_handle(struct pipeline_data *p)
 			break;
 
 		switch (req->type) {
+		case PIPELINE_REQ_PORT_IN_STATS_READ:
+			rsp = pipeline_msg_handle_port_in_stats_read(p, req);
+			break;
+
 		case PIPELINE_REQ_PORT_IN_ENABLE:
 			rsp = pipeline_msg_handle_port_in_enable(p, req);
 			break;
@@ -692,6 +932,15 @@ pipeline_msg_handle(struct pipeline_data *p)
 			rsp = pipeline_msg_handle_port_in_disable(p, req);
 			break;
 
+		case PIPELINE_REQ_PORT_OUT_STATS_READ:
+			rsp = pipeline_msg_handle_port_out_stats_read(p, req);
+			break;
+
+		case PIPELINE_REQ_TABLE_STATS_READ:
+			rsp = pipeline_msg_handle_table_stats_read(p, req);
+			break;
+
+
 		default:
 			rsp = (struct pipeline_msg_rsp *) req;
 			rsp->status = -1;
-- 
2.9.3

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

* [dpdk-dev] [PATCH v4 35/49] ip_pipeline: add cli for pipeline table entry
  2018-03-29 18:31           ` [dpdk-dev] [PATCH v4 00/49] ip_pipeline: refactoring Jasvinder Singh
                               ` (33 preceding siblings ...)
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 34/49] ip_pipeline: add cli to read pipeline port and table stats Jasvinder Singh
@ 2018-03-29 18:31             ` Jasvinder Singh
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 36/49] ip_pipeline: add cli to delete " Jasvinder Singh
                               ` (14 subsequent siblings)
  49 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-29 18:31 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Kevin Laatz

Add commands to add pipeline table entries which contains match and
action part.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
---
 examples/ip_pipeline/cli.c      | 1295 +++++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/pipeline.h |   13 +
 examples/ip_pipeline/thread.c   |  751 +++++++++++++++++++++++
 3 files changed, 2059 insertions(+)

diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index 02ff73a..b6a2177 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -8,6 +8,7 @@
 #include <string.h>
 
 #include <rte_common.h>
+#include <rte_cycles.h>
 
 #include "cli.h"
 #include "kni.h"
@@ -2262,6 +2263,1283 @@ cmd_pipeline_table_stats(char **tokens,
 }
 
 /**
+ * <match> ::=
+ *
+ * match
+ *    acl
+ *       priority <priority>
+ *       ipv4 | ipv6 <sa> <sa_depth> <da> <da_depth>
+ *       <sp0> <sp1> <dp0> <dp1> <proto>
+ *    | array
+ *       pos
+ *    | hash
+ *       raw <key>
+ *       | ipv4_5tuple <sa> <da> <sp> <dp> <proto>
+ *       | ipv6_5tuple <sa> <da> <sp> <dp> <proto>
+ *       | ipv4_addr <addr>
+ *       | ipv6_addr <addr>
+ *       | qinq <svlan> <cvlan>
+ *    | lpm
+ *       ipv4 | ipv6 <addr> <depth>
+ */
+struct pkt_key_qinq {
+	uint16_t ethertype_svlan;
+	uint16_t svlan;
+	uint16_t ethertype_cvlan;
+	uint16_t cvlan;
+} __attribute__((__packed__));
+
+struct pkt_key_ipv4_5tuple {
+	uint8_t time_to_live;
+	uint8_t proto;
+	uint16_t hdr_checksum;
+	uint32_t sa;
+	uint32_t da;
+	uint16_t sp;
+	uint16_t dp;
+} __attribute__((__packed__));
+
+struct pkt_key_ipv6_5tuple {
+	uint16_t payload_length;
+	uint8_t proto;
+	uint8_t hop_limit;
+	uint8_t sa[16];
+	uint8_t da[16];
+	uint16_t sp;
+	uint16_t dp;
+} __attribute__((__packed__));
+
+struct pkt_key_ipv4_addr {
+	uint32_t addr;
+} __attribute__((__packed__));
+
+struct pkt_key_ipv6_addr {
+	uint8_t addr[16];
+} __attribute__((__packed__));
+
+static uint32_t
+parse_match(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size,
+	struct table_rule_match *m)
+{
+	memset(m, 0, sizeof(*m));
+
+	if (n_tokens < 2)
+		return 0;
+
+	if (strcmp(tokens[0], "match") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match");
+		return 0;
+	}
+
+	if (strcmp(tokens[1], "acl") == 0) {
+		if (n_tokens < 14) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+			return 0;
+		}
+
+		m->match_type = TABLE_ACL;
+
+		if (strcmp(tokens[2], "priority") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "priority");
+			return 0;
+		}
+
+		if (parser_read_uint32(&m->match.acl.priority,
+			tokens[3]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "priority");
+			return 0;
+		}
+
+		if (strcmp(tokens[4], "ipv4") == 0) {
+			struct in_addr saddr, daddr;
+
+			m->match.acl.ip_version = 1;
+
+			if (parse_ipv4_addr(tokens[5], &saddr) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID, "sa");
+				return 0;
+			}
+			m->match.acl.ipv4.sa = rte_be_to_cpu_32(saddr.s_addr);
+
+			if (parse_ipv4_addr(tokens[7], &daddr) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID, "da");
+				return 0;
+			}
+			m->match.acl.ipv4.da = rte_be_to_cpu_32(daddr.s_addr);
+		} else if (strcmp(tokens[4], "ipv6") == 0) {
+			struct in6_addr saddr, daddr;
+
+			m->match.acl.ip_version = 0;
+
+			if (parse_ipv6_addr(tokens[5], &saddr) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID, "sa");
+				return 0;
+			}
+			memcpy(m->match.acl.ipv6.sa, saddr.s6_addr, 16);
+
+			if (parse_ipv6_addr(tokens[7], &daddr) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID, "da");
+				return 0;
+			}
+			memcpy(m->match.acl.ipv6.da, daddr.s6_addr, 16);
+		} else {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND,
+				"ipv4 or ipv6");
+			return 0;
+		}
+
+		if (parser_read_uint32(&m->match.acl.sa_depth,
+			tokens[6]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "sa_depth");
+			return 0;
+		}
+
+		if (parser_read_uint32(&m->match.acl.da_depth,
+			tokens[8]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "da_depth");
+			return 0;
+		}
+
+		if (parser_read_uint16(&m->match.acl.sp0, tokens[9]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "sp0");
+			return 0;
+		}
+
+		if (parser_read_uint16(&m->match.acl.sp1, tokens[10]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "sp1");
+			return 0;
+		}
+
+		if (parser_read_uint16(&m->match.acl.dp0, tokens[11]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "dp0");
+			return 0;
+		}
+
+		if (parser_read_uint16(&m->match.acl.dp1, tokens[12]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "dp1");
+			return 0;
+		}
+
+		if (parser_read_uint8(&m->match.acl.proto, tokens[13]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "proto");
+			return 0;
+		}
+
+		m->match.acl.proto_mask = 0xff;
+
+		return 14;
+	} /* acl */
+
+	if (strcmp(tokens[1], "array") == 0) {
+		if (n_tokens < 3) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+			return 0;
+		}
+
+		m->match_type = TABLE_ARRAY;
+
+		if (parser_read_uint32(&m->match.array.pos, tokens[2]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "pos");
+			return 0;
+		}
+
+		return 3;
+	} /* array */
+
+	if (strcmp(tokens[1], "hash") == 0) {
+		if (n_tokens < 3) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+			return 0;
+		}
+
+		m->match_type = TABLE_HASH;
+
+		if (strcmp(tokens[2], "raw") == 0) {
+			uint32_t key_size = TABLE_RULE_MATCH_SIZE_MAX;
+
+			if (n_tokens < 4) {
+				snprintf(out, out_size, MSG_ARG_MISMATCH,
+					tokens[0]);
+				return 0;
+			}
+
+			if (parse_hex_string(tokens[3],
+				m->match.hash.key, &key_size) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID, "key");
+				return 0;
+			}
+
+			return 4;
+		} /* hash raw */
+
+		if (strcmp(tokens[2], "ipv4_5tuple") == 0) {
+			struct pkt_key_ipv4_5tuple *ipv4 =
+				(struct pkt_key_ipv4_5tuple *) m->match.hash.key;
+			struct in_addr saddr, daddr;
+			uint16_t sp, dp;
+			uint8_t proto;
+
+			if (n_tokens < 8) {
+				snprintf(out, out_size, MSG_ARG_MISMATCH,
+					tokens[0]);
+				return 0;
+			}
+
+			if (parse_ipv4_addr(tokens[3], &saddr) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID, "sa");
+				return 0;
+			}
+
+			if (parse_ipv4_addr(tokens[4], &daddr) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID, "da");
+				return 0;
+			}
+
+			if (parser_read_uint16(&sp, tokens[5]) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID, "sp");
+				return 0;
+			}
+
+			if (parser_read_uint16(&dp, tokens[6]) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID, "dp");
+				return 0;
+			}
+
+			if (parser_read_uint8(&proto, tokens[7]) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID,
+					"proto");
+				return 0;
+			}
+
+			ipv4->sa = saddr.s_addr;
+			ipv4->da = daddr.s_addr;
+			ipv4->sp = rte_cpu_to_be_16(sp);
+			ipv4->dp = rte_cpu_to_be_16(dp);
+			ipv4->proto = proto;
+
+			return 8;
+		} /* hash ipv4_5tuple */
+
+		if (strcmp(tokens[2], "ipv6_5tuple") == 0) {
+			struct pkt_key_ipv6_5tuple *ipv6 =
+				(struct pkt_key_ipv6_5tuple *) m->match.hash.key;
+			struct in6_addr saddr, daddr;
+			uint16_t sp, dp;
+			uint8_t proto;
+
+			if (n_tokens < 8) {
+				snprintf(out, out_size, MSG_ARG_MISMATCH,
+					tokens[0]);
+				return 0;
+			}
+
+			if (parse_ipv6_addr(tokens[3], &saddr) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID, "sa");
+				return 0;
+			}
+
+			if (parse_ipv6_addr(tokens[4], &daddr) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID, "da");
+				return 0;
+			}
+
+			if (parser_read_uint16(&sp, tokens[5]) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID, "sp");
+				return 0;
+			}
+
+			if (parser_read_uint16(&dp, tokens[6]) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID, "dp");
+				return 0;
+			}
+
+			if (parser_read_uint8(&proto, tokens[7]) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID,
+					"proto");
+				return 0;
+			}
+
+			memcpy(ipv6->sa, saddr.s6_addr, 16);
+			memcpy(ipv6->da, daddr.s6_addr, 16);
+			ipv6->sp = rte_cpu_to_be_16(sp);
+			ipv6->dp = rte_cpu_to_be_16(dp);
+			ipv6->proto = proto;
+
+			return 8;
+		} /* hash ipv6_5tuple */
+
+		if (strcmp(tokens[2], "ipv4_addr") == 0) {
+			struct pkt_key_ipv4_addr *ipv4_addr =
+				(struct pkt_key_ipv4_addr *) m->match.hash.key;
+			struct in_addr addr;
+
+			if (n_tokens < 4) {
+				snprintf(out, out_size, MSG_ARG_MISMATCH,
+					tokens[0]);
+				return 0;
+			}
+
+			if (parse_ipv4_addr(tokens[3], &addr) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID,
+					"addr");
+				return 0;
+			}
+
+			ipv4_addr->addr = addr.s_addr;
+
+			return 4;
+		} /* hash ipv4_addr */
+
+		if (strcmp(tokens[2], "ipv6_addr") == 0) {
+			struct pkt_key_ipv6_addr *ipv6_addr =
+				(struct pkt_key_ipv6_addr *) m->match.hash.key;
+			struct in6_addr addr;
+
+			if (n_tokens < 4) {
+				snprintf(out, out_size, MSG_ARG_MISMATCH,
+					tokens[0]);
+				return 0;
+			}
+
+			if (parse_ipv6_addr(tokens[3], &addr) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID,
+					"addr");
+				return 0;
+			}
+
+			memcpy(ipv6_addr->addr, addr.s6_addr, 16);
+
+			return 4;
+		} /* hash ipv6_5tuple */
+
+		if (strcmp(tokens[2], "qinq") == 0) {
+			struct pkt_key_qinq *qinq =
+				(struct pkt_key_qinq *) m->match.hash.key;
+			uint16_t svlan, cvlan;
+
+			if (n_tokens < 5) {
+				snprintf(out, out_size, MSG_ARG_MISMATCH,
+					tokens[0]);
+				return 0;
+			}
+
+			if ((parser_read_uint16(&svlan, tokens[3]) != 0) ||
+				(svlan > 0xFFF)) {
+				snprintf(out, out_size, MSG_ARG_INVALID,
+					"svlan");
+				return 0;
+			}
+
+			if ((parser_read_uint16(&cvlan, tokens[4]) != 0) ||
+				(cvlan > 0xFFF)) {
+				snprintf(out, out_size, MSG_ARG_INVALID,
+					"cvlan");
+				return 0;
+			}
+
+			qinq->svlan = rte_cpu_to_be_16(svlan);
+			qinq->cvlan = rte_cpu_to_be_16(cvlan);
+
+			return 5;
+		} /* hash qinq */
+
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return 0;
+	} /* hash */
+
+	if (strcmp(tokens[1], "lpm") == 0) {
+		if (n_tokens < 5) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+			return 0;
+		}
+
+		m->match_type = TABLE_LPM;
+
+		if (strcmp(tokens[2], "ipv4") == 0) {
+			struct in_addr addr;
+
+			m->match.lpm.ip_version = 1;
+
+			if (parse_ipv4_addr(tokens[3], &addr) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID,
+					"addr");
+				return 0;
+			}
+
+			m->match.lpm.ipv4 = rte_be_to_cpu_32(addr.s_addr);
+		} else if (strcmp(tokens[2], "ipv6") == 0) {
+			struct in6_addr addr;
+
+			m->match.lpm.ip_version = 0;
+
+			if (parse_ipv6_addr(tokens[3], &addr) != 0) {
+				snprintf(out, out_size, MSG_ARG_INVALID,
+					"addr");
+				return 0;
+			}
+
+			memcpy(m->match.lpm.ipv6, addr.s6_addr, 16);
+		} else {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"ipv4 or ipv6");
+			return 0;
+		}
+
+		if (parser_read_uint8(&m->match.lpm.depth, tokens[4]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "depth");
+			return 0;
+		}
+
+		return 5;
+	} /* lpm */
+
+	snprintf(out, out_size, MSG_ARG_MISMATCH,
+		"acl or array or hash or lpm");
+	return 0;
+}
+
+/**
+ * table_action ::=
+ *
+ * action
+ *    fwd
+ *       drop
+ *       | port <port_id>
+ *       | meta
+ *       | table <table_id>
+ *    [balance <out0> ... <out7>]
+ *    [meter
+ *       tc0 meter <meter_profile_id> policer g <pa> y <pa> r <pa>
+ *       [tc1 meter <meter_profile_id> policer g <pa> y <pa> r <pa>
+ *       tc2 meter <meter_profile_id> policer g <pa> y <pa> r <pa>
+ *       tc3 meter <meter_profile_id> policer g <pa> y <pa> r <pa>]]
+ *    [tm subport <subport_id> pipe <pipe_id>]
+ *    [encap
+ *       ether <da> <sa>
+ *       | vlan <da> <sa> <pcp> <dei> <vid>
+ *       | qinq <da> <sa> <pcp> <dei> <vid> <pcp> <dei> <vid>
+ *       | mpls unicast | multicast
+ *          <da> <sa>
+ *          label0 <label> <tc> <ttl>
+ *          [label1 <label> <tc> <ttl>
+ *          [label2 <label> <tc> <ttl>
+ *          [label3 <label> <tc> <ttl>]]]
+ *       | pppoe <da> <sa> <session_id>]
+ *    [nat ipv4 | ipv6 <addr> <port>]
+ *    [ttl dec | keep]
+ *    [stats]
+ *    [time]
+ *
+ * where:
+ *    <pa> ::= g | y | r | drop
+ */
+static uint32_t
+parse_table_action_fwd(char **tokens,
+	uint32_t n_tokens,
+	struct table_rule_action *a)
+{
+	if ((n_tokens == 0) || (strcmp(tokens[0], "fwd") != 0))
+		return 0;
+
+	tokens++;
+	n_tokens--;
+
+	if (n_tokens && (strcmp(tokens[0], "drop") == 0)) {
+		a->fwd.action = RTE_PIPELINE_ACTION_DROP;
+		a->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
+		return 1 + 1;
+	}
+
+	if (n_tokens && (strcmp(tokens[0], "port") == 0)) {
+		uint32_t id;
+
+		if ((n_tokens < 2) ||
+			parser_read_uint32(&id, tokens[1]))
+			return 0;
+
+		a->fwd.action = RTE_PIPELINE_ACTION_PORT;
+		a->fwd.id = id;
+		a->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
+		return 1 + 2;
+	}
+
+	if (n_tokens && (strcmp(tokens[0], "meta") == 0)) {
+		a->fwd.action = RTE_PIPELINE_ACTION_PORT_META;
+		a->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
+		return 1 + 1;
+	}
+
+	if (n_tokens && (strcmp(tokens[0], "table") == 0)) {
+		uint32_t id;
+
+		if ((n_tokens < 2) ||
+			parser_read_uint32(&id, tokens[1]))
+			return 0;
+
+		a->fwd.action = RTE_PIPELINE_ACTION_TABLE;
+		a->fwd.id = id;
+		a->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
+		return 1 + 2;
+	}
+
+	return 0;
+}
+
+static int
+parse_policer_action(char *token, enum rte_table_action_policer *a)
+{
+	if (strcmp(token, "g") == 0) {
+		*a = RTE_TABLE_ACTION_POLICER_COLOR_GREEN;
+		return 0;
+	}
+
+	if (strcmp(token, "y") == 0) {
+		*a = RTE_TABLE_ACTION_POLICER_COLOR_YELLOW;
+		return 0;
+	}
+
+	if (strcmp(token, "r") == 0) {
+		*a = RTE_TABLE_ACTION_POLICER_COLOR_RED;
+		return 0;
+	}
+
+	if (strcmp(token, "drop") == 0) {
+		*a = RTE_TABLE_ACTION_POLICER_DROP;
+		return 0;
+	}
+
+	return -1;
+}
+
+static uint32_t
+parse_table_action_meter_tc(char **tokens,
+	uint32_t n_tokens,
+	struct rte_table_action_mtr_tc_params *mtr)
+{
+	if ((n_tokens < 9) ||
+		strcmp(tokens[0], "meter") ||
+		parser_read_uint32(&mtr->meter_profile_id, tokens[1]) ||
+		strcmp(tokens[2], "policer") ||
+		strcmp(tokens[3], "g") ||
+		parse_policer_action(tokens[4], &mtr->policer[e_RTE_METER_GREEN]) ||
+		strcmp(tokens[5], "y") ||
+		parse_policer_action(tokens[6], &mtr->policer[e_RTE_METER_YELLOW]) ||
+		strcmp(tokens[7], "r") ||
+		parse_policer_action(tokens[8], &mtr->policer[e_RTE_METER_RED]))
+		return 0;
+
+	return 9;
+}
+
+static uint32_t
+parse_table_action_meter(char **tokens,
+	uint32_t n_tokens,
+	struct table_rule_action *a)
+{
+	if ((n_tokens == 0) || strcmp(tokens[0], "meter"))
+		return 0;
+
+	tokens++;
+	n_tokens--;
+
+	if ((n_tokens < 10) ||
+		strcmp(tokens[0], "tc0") ||
+		(parse_table_action_meter_tc(tokens + 1,
+			n_tokens - 1,
+			&a->mtr.mtr[0]) == 0))
+		return 0;
+
+	tokens += 10;
+	n_tokens -= 10;
+
+	if ((n_tokens == 0) || strcmp(tokens[0], "tc1")) {
+		a->mtr.tc_mask = 1;
+		a->action_mask |= 1 << RTE_TABLE_ACTION_MTR;
+		return 1 + 10;
+	}
+
+	if ((n_tokens < 30) ||
+		(parse_table_action_meter_tc(tokens + 1,
+			n_tokens - 1, &a->mtr.mtr[1]) == 0) ||
+		strcmp(tokens[10], "tc2") ||
+		(parse_table_action_meter_tc(tokens + 11,
+			n_tokens - 11, &a->mtr.mtr[2]) == 0) ||
+		strcmp(tokens[20], "tc3") ||
+		(parse_table_action_meter_tc(tokens + 21,
+			n_tokens - 21, &a->mtr.mtr[3]) == 0))
+		return 0;
+
+	a->mtr.tc_mask = 0xF;
+	a->action_mask |= 1 << RTE_TABLE_ACTION_MTR;
+	return 1 + 10 + 3 * 10;
+}
+
+static uint32_t
+parse_table_action_tm(char **tokens,
+	uint32_t n_tokens,
+	struct table_rule_action *a)
+{
+	uint32_t subport_id, pipe_id;
+
+	if ((n_tokens < 5) ||
+		strcmp(tokens[0], "tm") ||
+		strcmp(tokens[1], "subport") ||
+		parser_read_uint32(&subport_id, tokens[2]) ||
+		strcmp(tokens[3], "pipe") ||
+		parser_read_uint32(&pipe_id, tokens[4]))
+		return 0;
+
+	a->tm.subport_id = subport_id;
+	a->tm.pipe_id = pipe_id;
+	a->action_mask |= 1 << RTE_TABLE_ACTION_TM;
+	return 5;
+}
+
+static uint32_t
+parse_table_action_encap(char **tokens,
+	uint32_t n_tokens,
+	struct table_rule_action *a)
+{
+	if ((n_tokens == 0) || strcmp(tokens[0], "encap"))
+		return 0;
+
+	tokens++;
+	n_tokens--;
+
+	/* ether */
+	if (n_tokens && (strcmp(tokens[0], "ether") == 0)) {
+		if ((n_tokens < 3) ||
+			parse_mac_addr(tokens[1], &a->encap.ether.ether.da) ||
+			parse_mac_addr(tokens[2], &a->encap.ether.ether.sa))
+			return 0;
+
+		a->encap.type = RTE_TABLE_ACTION_ENCAP_ETHER;
+		a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
+		return 1 + 3;
+	}
+
+	/* vlan */
+	if (n_tokens && (strcmp(tokens[0], "vlan") == 0)) {
+		uint32_t pcp, dei, vid;
+
+		if ((n_tokens < 6) ||
+			parse_mac_addr(tokens[1], &a->encap.vlan.ether.da) ||
+			parse_mac_addr(tokens[2], &a->encap.vlan.ether.sa) ||
+			parser_read_uint32(&pcp, tokens[3]) ||
+			(pcp > 0x7) ||
+			parser_read_uint32(&dei, tokens[4]) ||
+			(dei > 0x1) ||
+			parser_read_uint32(&vid, tokens[5]) ||
+			(vid > 0xFFF))
+			return 0;
+
+		a->encap.vlan.vlan.pcp = pcp & 0x7;
+		a->encap.vlan.vlan.dei = dei & 0x1;
+		a->encap.vlan.vlan.vid = vid & 0xFFF;
+		a->encap.type = RTE_TABLE_ACTION_ENCAP_VLAN;
+		a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
+		return 1 + 6;
+	}
+
+	/* qinq */
+	if (n_tokens && (strcmp(tokens[0], "qinq") == 0)) {
+		uint32_t svlan_pcp, svlan_dei, svlan_vid;
+		uint32_t cvlan_pcp, cvlan_dei, cvlan_vid;
+
+		if ((n_tokens < 9) ||
+			parse_mac_addr(tokens[1], &a->encap.qinq.ether.da) ||
+			parse_mac_addr(tokens[2], &a->encap.qinq.ether.sa) ||
+			parser_read_uint32(&svlan_pcp, tokens[3]) ||
+			(svlan_pcp > 0x7) ||
+			parser_read_uint32(&svlan_dei, tokens[4]) ||
+			(svlan_dei > 0x1) ||
+			parser_read_uint32(&svlan_vid, tokens[5]) ||
+			(svlan_vid > 0xFFF) ||
+			parser_read_uint32(&cvlan_pcp, tokens[6]) ||
+			(cvlan_pcp > 0x7) ||
+			parser_read_uint32(&cvlan_dei, tokens[7]) ||
+			(cvlan_dei > 0x1) ||
+			parser_read_uint32(&cvlan_vid, tokens[8]) ||
+			(cvlan_vid > 0xFFF))
+			return 0;
+
+		a->encap.qinq.svlan.pcp = svlan_pcp & 0x7;
+		a->encap.qinq.svlan.dei = svlan_dei & 0x1;
+		a->encap.qinq.svlan.vid = svlan_vid & 0xFFF;
+		a->encap.qinq.cvlan.pcp = cvlan_pcp & 0x7;
+		a->encap.qinq.cvlan.dei = cvlan_dei & 0x1;
+		a->encap.qinq.cvlan.vid = cvlan_vid & 0xFFF;
+		a->encap.type = RTE_TABLE_ACTION_ENCAP_QINQ;
+		a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
+		return 1 + 9;
+	}
+
+	/* mpls */
+	if (n_tokens && (strcmp(tokens[0], "mpls") == 0)) {
+		uint32_t label, tc, ttl;
+
+		if (n_tokens < 8)
+			return 0;
+
+		if (strcmp(tokens[1], "unicast") == 0)
+			a->encap.mpls.unicast = 1;
+		else if (strcmp(tokens[1], "multicast") == 0)
+			a->encap.mpls.unicast = 0;
+		else
+			return 0;
+
+		if (parse_mac_addr(tokens[2], &a->encap.mpls.ether.da) ||
+			parse_mac_addr(tokens[3], &a->encap.mpls.ether.sa) ||
+			strcmp(tokens[4], "label0") ||
+			parser_read_uint32(&label, tokens[5]) ||
+			(label > 0xFFFFF) ||
+			parser_read_uint32(&tc, tokens[6]) ||
+			(tc > 0x7) ||
+			parser_read_uint32(&ttl, tokens[7]) ||
+			(ttl > 0x3F))
+			return 0;
+
+		a->encap.mpls.mpls[0].label = label;
+		a->encap.mpls.mpls[0].tc = tc;
+		a->encap.mpls.mpls[0].ttl = ttl;
+
+		tokens += 8;
+		n_tokens -= 8;
+
+		if ((n_tokens == 0) || strcmp(tokens[0], "label1")) {
+			a->encap.mpls.mpls_count = 1;
+			a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS;
+			a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
+			return 1 + 8;
+		}
+
+		if ((n_tokens < 4) ||
+			parser_read_uint32(&label, tokens[1]) ||
+			(label > 0xFFFFF) ||
+			parser_read_uint32(&tc, tokens[2]) ||
+			(tc > 0x7) ||
+			parser_read_uint32(&ttl, tokens[3]) ||
+			(ttl > 0x3F))
+			return 0;
+
+		a->encap.mpls.mpls[1].label = label;
+		a->encap.mpls.mpls[1].tc = tc;
+		a->encap.mpls.mpls[1].ttl = ttl;
+
+		tokens += 4;
+		n_tokens -= 4;
+
+		if ((n_tokens == 0) || strcmp(tokens[0], "label2")) {
+			a->encap.mpls.mpls_count = 2;
+			a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS;
+			a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
+			return 1 + 8 + 4;
+		}
+
+		if ((n_tokens < 4) ||
+			parser_read_uint32(&label, tokens[1]) ||
+			(label > 0xFFFFF) ||
+			parser_read_uint32(&tc, tokens[2]) ||
+			(tc > 0x7) ||
+			parser_read_uint32(&ttl, tokens[3]) ||
+			(ttl > 0x3F))
+			return 0;
+
+		a->encap.mpls.mpls[2].label = label;
+		a->encap.mpls.mpls[2].tc = tc;
+		a->encap.mpls.mpls[2].ttl = ttl;
+
+		tokens += 4;
+		n_tokens -= 4;
+
+		if ((n_tokens == 0) || strcmp(tokens[0], "label3")) {
+			a->encap.mpls.mpls_count = 3;
+			a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS;
+			a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
+			return 1 + 8 + 4 + 4;
+		}
+
+		if ((n_tokens < 4) ||
+			parser_read_uint32(&label, tokens[1]) ||
+			(label > 0xFFFFF) ||
+			parser_read_uint32(&tc, tokens[2]) ||
+			(tc > 0x7) ||
+			parser_read_uint32(&ttl, tokens[3]) ||
+			(ttl > 0x3F))
+			return 0;
+
+		a->encap.mpls.mpls[3].label = label;
+		a->encap.mpls.mpls[3].tc = tc;
+		a->encap.mpls.mpls[3].ttl = ttl;
+
+		a->encap.mpls.mpls_count = 4;
+		a->encap.type = RTE_TABLE_ACTION_ENCAP_MPLS;
+		a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
+		return 1 + 8 + 4 + 4 + 4;
+	}
+
+	/* pppoe */
+	if (n_tokens && (strcmp(tokens[0], "pppoe") == 0)) {
+		if ((n_tokens < 4) ||
+			parse_mac_addr(tokens[1], &a->encap.pppoe.ether.da) ||
+			parse_mac_addr(tokens[2], &a->encap.pppoe.ether.sa) ||
+			parser_read_uint16(&a->encap.pppoe.pppoe.session_id,
+				tokens[3]))
+			return 0;
+
+		a->encap.type = RTE_TABLE_ACTION_ENCAP_PPPOE;
+		a->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
+		return 1 + 4;
+	}
+
+	return 0;
+}
+
+static uint32_t
+parse_table_action_nat(char **tokens,
+	uint32_t n_tokens,
+	struct table_rule_action *a)
+{
+	if ((n_tokens < 4) ||
+		strcmp(tokens[0], "nat"))
+		return 0;
+
+	if (strcmp(tokens[1], "ipv4") == 0) {
+		struct in_addr addr;
+		uint16_t port;
+
+		if (parse_ipv4_addr(tokens[2], &addr) ||
+			parser_read_uint16(&port, tokens[3]))
+			return 0;
+
+		a->nat.ip_version = 1;
+		a->nat.addr.ipv4 = rte_be_to_cpu_32(addr.s_addr);
+		a->nat.port = port;
+		a->action_mask |= 1 << RTE_TABLE_ACTION_NAT;
+		return 4;
+	}
+
+	if (strcmp(tokens[1], "ipv6") == 0) {
+		struct in6_addr addr;
+		uint16_t port;
+
+		if (parse_ipv6_addr(tokens[2], &addr) ||
+			parser_read_uint16(&port, tokens[3]))
+			return 0;
+
+		a->nat.ip_version = 0;
+		memcpy(a->nat.addr.ipv6, addr.s6_addr, 16);
+		a->nat.port = port;
+		a->action_mask |= 1 << RTE_TABLE_ACTION_NAT;
+		return 4;
+	}
+
+	return 0;
+}
+
+static uint32_t
+parse_table_action_ttl(char **tokens,
+	uint32_t n_tokens,
+	struct table_rule_action *a)
+{
+	if ((n_tokens < 2) ||
+		strcmp(tokens[0], "ttl"))
+		return 0;
+
+	if (strcmp(tokens[1], "dec") == 0)
+		a->ttl.decrement = 1;
+	else if (strcmp(tokens[1], "keep") == 0)
+		a->ttl.decrement = 0;
+	else
+		return 0;
+
+	a->action_mask |= 1 << RTE_TABLE_ACTION_TTL;
+	return 2;
+}
+
+static uint32_t
+parse_table_action_stats(char **tokens,
+	uint32_t n_tokens,
+	struct table_rule_action *a)
+{
+	if ((n_tokens < 1) ||
+		strcmp(tokens[0], "stats"))
+		return 0;
+
+	a->stats.n_packets = 0;
+	a->stats.n_bytes = 0;
+	a->action_mask |= 1 << RTE_TABLE_ACTION_STATS;
+	return 1;
+}
+
+static uint32_t
+parse_table_action_time(char **tokens,
+	uint32_t n_tokens,
+	struct table_rule_action *a)
+{
+	if ((n_tokens < 1) ||
+		strcmp(tokens[0], "time"))
+		return 0;
+
+	a->time.time = rte_rdtsc();
+	a->action_mask |= 1 << RTE_TABLE_ACTION_TIME;
+	return 1;
+}
+
+static uint32_t
+parse_table_action(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size,
+	struct table_rule_action *a)
+{
+	uint32_t n_tokens0 = n_tokens;
+
+	memset(a, 0, sizeof(*a));
+
+	if ((n_tokens < 2) ||
+		strcmp(tokens[0], "action"))
+		return 0;
+
+	tokens++;
+	n_tokens--;
+
+	if (n_tokens && (strcmp(tokens[0], "fwd") == 0)) {
+		uint32_t n;
+
+		n = parse_table_action_fwd(tokens, n_tokens, a);
+		if (n == 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID,
+				"action fwd");
+			return 0;
+		}
+
+		tokens += n;
+		n_tokens -= n;
+	}
+
+	if (n_tokens && (strcmp(tokens[0], "meter") == 0)) {
+		uint32_t n;
+
+		n = parse_table_action_meter(tokens, n_tokens, a);
+		if (n == 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID,
+				"action meter");
+			return 0;
+		}
+
+		tokens += n;
+		n_tokens -= n;
+	}
+
+	if (n_tokens && (strcmp(tokens[0], "tm") == 0)) {
+		uint32_t n;
+
+		n = parse_table_action_tm(tokens, n_tokens, a);
+		if (n == 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID,
+				"action tm");
+			return 0;
+		}
+
+		tokens += n;
+		n_tokens -= n;
+	}
+
+	if (n_tokens && (strcmp(tokens[0], "encap") == 0)) {
+		uint32_t n;
+
+		n = parse_table_action_encap(tokens, n_tokens, a);
+		if (n == 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID,
+				"action encap");
+			return 0;
+		}
+
+		tokens += n;
+		n_tokens -= n;
+	}
+
+	if (n_tokens && (strcmp(tokens[0], "nat") == 0)) {
+		uint32_t n;
+
+		n = parse_table_action_nat(tokens, n_tokens, a);
+		if (n == 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID,
+				"action nat");
+			return 0;
+		}
+
+		tokens += n;
+		n_tokens -= n;
+	}
+
+	if (n_tokens && (strcmp(tokens[0], "ttl") == 0)) {
+		uint32_t n;
+
+		n = parse_table_action_ttl(tokens, n_tokens, a);
+		if (n == 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID,
+				"action ttl");
+			return 0;
+		}
+
+		tokens += n;
+		n_tokens -= n;
+	}
+
+	if (n_tokens && (strcmp(tokens[0], "stats") == 0)) {
+		uint32_t n;
+
+		n = parse_table_action_stats(tokens, n_tokens, a);
+		if (n == 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID,
+				"action stats");
+			return 0;
+		}
+
+		tokens += n;
+		n_tokens -= n;
+	}
+
+	if (n_tokens && (strcmp(tokens[0], "time") == 0)) {
+		uint32_t n;
+
+		n = parse_table_action_time(tokens, n_tokens, a);
+		if (n == 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID,
+				"action time");
+			return 0;
+		}
+
+		tokens += n;
+		n_tokens -= n;
+	}
+
+	if (n_tokens0 - n_tokens == 1) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "action");
+		return 0;
+	}
+
+	return n_tokens0 - n_tokens;
+}
+
+/**
+ * pipeline <pipeline_name> table <table_id> rule add
+ *    match <match>
+ *    action <table_action>
+ */
+static void
+cmd_pipeline_table_rule_add(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct table_rule_match m;
+	struct table_rule_action a;
+	char *pipeline_name;
+	void *data;
+	uint32_t table_id, t0, n_tokens_parsed;
+	int status;
+
+	if (n_tokens < 8) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "table") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
+		return;
+	}
+
+	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
+		return;
+	}
+
+	if (strcmp(tokens[4], "rule") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
+		return;
+	}
+
+	if (strcmp(tokens[5], "add") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
+		return;
+	}
+
+	t0 = 6;
+
+	/* match */
+	n_tokens_parsed = parse_match(tokens + t0,
+		n_tokens - t0,
+		out,
+		out_size,
+		&m);
+	if (n_tokens_parsed == 0)
+		return;
+	t0 += n_tokens_parsed;
+
+	/* action */
+	n_tokens_parsed = parse_table_action(tokens + t0,
+		n_tokens - t0,
+		out,
+		out_size,
+		&a);
+	if (n_tokens_parsed == 0)
+		return;
+	t0 += n_tokens_parsed;
+
+	if (t0 != n_tokens) {
+		snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]);
+		return;
+	}
+
+	status = pipeline_table_rule_add(pipeline_name, table_id,
+		&m, &a, &data);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
+ * pipeline <pipeline_name> table <table_id> rule add
+ *    match
+ *       default
+ *    action
+ *       fwd
+ *          drop
+ *          | port <port_id>
+ *          | meta
+ *          | table <table_id>
+ */
+static void
+cmd_pipeline_table_rule_add_default(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct table_rule_action action;
+	void *data;
+	char *pipeline_name;
+	uint32_t table_id;
+	int status;
+
+	if ((n_tokens != 11) && (n_tokens != 12)) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "table") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
+		return;
+	}
+
+	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
+		return;
+	}
+
+	if (strcmp(tokens[4], "rule") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
+		return;
+	}
+
+	if (strcmp(tokens[5], "add") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
+		return;
+	}
+
+	if (strcmp(tokens[6], "match") != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "match");
+		return;
+	}
+
+	if (strcmp(tokens[7], "default") != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "default");
+		return;
+	}
+
+	if (strcmp(tokens[8], "action") != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "action");
+		return;
+	}
+
+	if (strcmp(tokens[9], "fwd") != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "fwd");
+		return;
+	}
+
+	action.action_mask = 1 << RTE_TABLE_ACTION_FWD;
+
+	if (strcmp(tokens[10], "drop") == 0) {
+		if (n_tokens != 11) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+			return;
+		}
+
+		action.fwd.action = RTE_PIPELINE_ACTION_DROP;
+	} else if (strcmp(tokens[10], "port") == 0) {
+		uint32_t id;
+
+		if (n_tokens != 12) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+			return;
+		}
+
+		if (parser_read_uint32(&id, tokens[11]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "port_id");
+			return;
+		}
+
+		action.fwd.action = RTE_PIPELINE_ACTION_PORT;
+		action.fwd.id = id;
+	} else if (strcmp(tokens[10], "meta") == 0) {
+		if (n_tokens != 11) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+			return;
+		}
+
+		action.fwd.action = RTE_PIPELINE_ACTION_PORT_META;
+	} else if (strcmp(tokens[10], "table") == 0) {
+		uint32_t id;
+
+		if (n_tokens != 12) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+			return;
+		}
+
+		if (parser_read_uint32(&id, tokens[11]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
+			return;
+		}
+
+		action.fwd.action = RTE_PIPELINE_ACTION_TABLE;
+		action.fwd.id = id;
+	} else {
+		snprintf(out, out_size, MSG_ARG_INVALID,
+			"drop or port or meta or table");
+		return;
+	}
+
+	status = pipeline_table_rule_add_default(pipeline_name,
+		table_id,
+		&action,
+		&data);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
  * thread <thread_id> pipeline <pipeline_name> enable
  */
 static void
@@ -2516,6 +3794,23 @@ cli_process(char *in, char *out, size_t out_size)
 				out, out_size);
 			return;
 		}
+
+		if ((n_tokens >= 7) &&
+			(strcmp(tokens[2], "table") == 0) &&
+			(strcmp(tokens[4], "rule") == 0) &&
+			(strcmp(tokens[5], "add") == 0) &&
+			(strcmp(tokens[6], "match") == 0)) {
+			if ((n_tokens >= 8) &&
+				(strcmp(tokens[7], "default") == 0)) {
+				cmd_pipeline_table_rule_add_default(tokens,
+					n_tokens, out, out_size);
+				return;
+			}
+
+			cmd_pipeline_table_rule_add(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
 	}
 
 	if (strcmp(tokens[0], "thread") == 0) {
diff --git a/examples/ip_pipeline/pipeline.h b/examples/ip_pipeline/pipeline.h
index 5757eb5..64efbed 100644
--- a/examples/ip_pipeline/pipeline.h
+++ b/examples/ip_pipeline/pipeline.h
@@ -295,4 +295,17 @@ pipeline_table_stats_read(const char *pipeline_name,
 	struct rte_pipeline_table_stats *stats,
 	int clear);
 
+int
+pipeline_table_rule_add(const char *pipeline_name,
+	uint32_t table_id,
+	struct table_rule_match *match,
+	struct table_rule_action *action,
+	void **data);
+
+int
+pipeline_table_rule_add_default(const char *pipeline_name,
+	uint32_t table_id,
+	struct table_rule_action *action,
+	void **data);
+
 #endif /* _INCLUDE_PIPELINE_H_ */
diff --git a/examples/ip_pipeline/thread.c b/examples/ip_pipeline/thread.c
index b1a2926..0291883 100644
--- a/examples/ip_pipeline/thread.c
+++ b/examples/ip_pipeline/thread.c
@@ -488,6 +488,8 @@ enum pipeline_req_type {
 
 	/* Table */
 	PIPELINE_REQ_TABLE_STATS_READ,
+	PIPELINE_REQ_TABLE_RULE_ADD,
+	PIPELINE_REQ_TABLE_RULE_ADD_DEFAULT,
 
 	PIPELINE_REQ_MAX
 };
@@ -504,6 +506,15 @@ struct pipeline_msg_req_table_stats_read {
 	int clear;
 };
 
+struct pipeline_msg_req_table_rule_add {
+	struct table_rule_match match;
+	struct table_rule_action action;
+};
+
+struct pipeline_msg_req_table_rule_add_default {
+	struct table_rule_action action;
+};
+
 struct pipeline_msg_req {
 	enum pipeline_req_type type;
 	uint32_t id; /* Port IN, port OUT or table ID */
@@ -513,6 +524,8 @@ struct pipeline_msg_req {
 		struct pipeline_msg_req_port_in_stats_read port_in_stats_read;
 		struct pipeline_msg_req_port_out_stats_read port_out_stats_read;
 		struct pipeline_msg_req_table_stats_read table_stats_read;
+		struct pipeline_msg_req_table_rule_add table_rule_add;
+		struct pipeline_msg_req_table_rule_add_default table_rule_add_default;
 	};
 };
 
@@ -528,6 +541,14 @@ struct pipeline_msg_rsp_table_stats_read {
 	struct rte_pipeline_table_stats stats;
 };
 
+struct pipeline_msg_rsp_table_rule_add {
+	void *data;
+};
+
+struct pipeline_msg_rsp_table_rule_add_default {
+	void *data;
+};
+
 struct pipeline_msg_rsp {
 	int status;
 
@@ -536,6 +557,8 @@ struct pipeline_msg_rsp {
 		struct pipeline_msg_rsp_port_in_stats_read port_in_stats_read;
 		struct pipeline_msg_rsp_port_out_stats_read port_out_stats_read;
 		struct pipeline_msg_rsp_table_stats_read table_stats_read;
+		struct pipeline_msg_rsp_table_rule_add table_rule_add;
+		struct pipeline_msg_rsp_table_rule_add_default table_rule_add_default;
 	};
 };
 
@@ -807,6 +830,272 @@ pipeline_table_stats_read(const char *pipeline_name,
 	return status;
 }
 
+static int
+match_check(struct table_rule_match *match,
+	struct pipeline *p,
+	uint32_t table_id)
+{
+	struct table *table;
+
+	if ((match == NULL) ||
+		(p == NULL) ||
+		(table_id >= p->n_tables))
+		return -1;
+
+	table = &p->table[table_id];
+	if (match->match_type != table->params.match_type)
+		return -1;
+
+	switch (match->match_type) {
+	case TABLE_ACL:
+	{
+		struct table_acl_params *t = &table->params.match.acl;
+		struct table_rule_match_acl *r = &match->match.acl;
+
+		if ((r->ip_version && (t->ip_version == 0)) ||
+			((r->ip_version == 0) && t->ip_version))
+			return -1;
+
+		if (r->ip_version) {
+			if ((r->sa_depth > 32) ||
+				(r->da_depth > 32))
+				return -1;
+		} else {
+			if ((r->sa_depth > 128) ||
+				(r->da_depth > 128))
+				return -1;
+		}
+		return 0;
+	}
+
+	case TABLE_ARRAY:
+		return 0;
+
+	case TABLE_HASH:
+		return 0;
+
+	case TABLE_LPM:
+	{
+		struct table_lpm_params *t = &table->params.match.lpm;
+		struct table_rule_match_lpm *r = &match->match.lpm;
+
+		if ((r->ip_version && (t->key_size != 4)) ||
+			((r->ip_version == 0) && (t->key_size != 16)))
+			return -1;
+
+		if (r->ip_version) {
+			if (r->depth > 32)
+				return -1;
+		} else {
+			if (r->depth > 128)
+				return -1;
+		}
+		return 0;
+	}
+
+	case TABLE_STUB:
+		return -1;
+
+	default:
+		return -1;
+	}
+}
+
+static int
+action_check(struct table_rule_action *action,
+	struct pipeline *p,
+	uint32_t table_id)
+{
+	struct table_action_profile *ap;
+
+	if ((action == NULL) ||
+		(p == NULL) ||
+		(table_id >= p->n_tables))
+		return -1;
+
+	ap = p->table[table_id].ap;
+	if (action->action_mask != ap->params.action_mask)
+		return -1;
+
+	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_FWD)) {
+		if ((action->fwd.action == RTE_PIPELINE_ACTION_PORT) &&
+			(action->fwd.id >= p->n_ports_out))
+			return -1;
+
+		if ((action->fwd.action == RTE_PIPELINE_ACTION_TABLE) &&
+			(action->fwd.id >= p->n_tables))
+			return -1;
+	}
+
+	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) {
+		uint32_t tc_mask0 = (1 << ap->params.mtr.n_tc) - 1;
+		uint32_t tc_mask1 = action->mtr.tc_mask;
+
+		if (tc_mask1 != tc_mask0)
+			return -1;
+	}
+
+	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_TM)) {
+		uint32_t n_subports_per_port =
+			ap->params.tm.n_subports_per_port;
+		uint32_t n_pipes_per_subport =
+			ap->params.tm.n_pipes_per_subport;
+		uint32_t subport_id = action->tm.subport_id;
+		uint32_t pipe_id = action->tm.pipe_id;
+
+		if ((subport_id >= n_subports_per_port) ||
+			(pipe_id >= n_pipes_per_subport))
+			return -1;
+	}
+
+	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_ENCAP)) {
+		uint64_t encap_mask = ap->params.encap.encap_mask;
+		enum rte_table_action_encap_type type = action->encap.type;
+
+		if ((encap_mask & (1LLU << type)) == 0)
+			return -1;
+	}
+
+	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_NAT)) {
+		int ip_version0 = ap->params.common.ip_version;
+		int ip_version1 = action->nat.ip_version;
+
+		if ((ip_version1 && (ip_version0 == 0)) ||
+			((ip_version1 == 0) && ip_version0))
+			return -1;
+	}
+
+	return 0;
+}
+
+static int
+action_default_check(struct table_rule_action *action,
+	struct pipeline *p,
+	uint32_t table_id)
+{
+	if ((action == NULL) ||
+		(action->action_mask != (1LLU << RTE_TABLE_ACTION_FWD)) ||
+		(p == NULL) ||
+		(table_id >= p->n_tables))
+		return -1;
+
+	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_FWD)) {
+		if ((action->fwd.action == RTE_PIPELINE_ACTION_PORT) &&
+			(action->fwd.id >= p->n_ports_out))
+			return -1;
+
+		if ((action->fwd.action == RTE_PIPELINE_ACTION_TABLE) &&
+			(action->fwd.id >= p->n_tables))
+			return -1;
+	}
+
+	return 0;
+}
+
+int
+pipeline_table_rule_add(const char *pipeline_name,
+	uint32_t table_id,
+	struct table_rule_match *match,
+	struct table_rule_action *action,
+	void **data)
+{
+	struct pipeline *p;
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if ((pipeline_name == NULL) ||
+		(match == NULL) ||
+		(action == NULL) ||
+		(data == NULL))
+		return -1;
+
+	p = pipeline_find(pipeline_name);
+	if ((p == NULL) ||
+		(p->enabled == 0) ||
+		(table_id >= p->n_tables) ||
+		match_check(match, p, table_id) ||
+		action_check(action, p, table_id))
+		return -1;
+
+	/* Allocate request */
+	req = pipeline_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = PIPELINE_REQ_TABLE_RULE_ADD;
+	req->id = table_id;
+	memcpy(&req->table_rule_add.match, match, sizeof(*match));
+	memcpy(&req->table_rule_add.action, action, sizeof(*action));
+
+	/* Send request and wait for response */
+	rsp = pipeline_msg_send_recv(p, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+	if (status == 0)
+		*data = rsp->table_rule_add.data;
+
+	/* Free response */
+	pipeline_msg_free(rsp);
+
+	return status;
+}
+
+int
+pipeline_table_rule_add_default(const char *pipeline_name,
+	uint32_t table_id,
+	struct table_rule_action *action,
+	void **data)
+{
+	struct pipeline *p;
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if ((pipeline_name == NULL) ||
+		(action == NULL) ||
+		(data == NULL))
+		return -1;
+
+	p = pipeline_find(pipeline_name);
+	if ((p == NULL) ||
+		(p->enabled == 0) ||
+		(table_id >= p->n_tables) ||
+		action_default_check(action, p, table_id))
+		return -1;
+
+	/* Allocate request */
+	req = pipeline_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = PIPELINE_REQ_TABLE_RULE_ADD_DEFAULT;
+	req->id = table_id;
+	memcpy(&req->table_rule_add_default.action, action, sizeof(*action));
+
+	/* Send request and wait for response */
+	rsp = pipeline_msg_send_recv(p, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+	if (status == 0)
+		*data = rsp->table_rule_add_default.data;
+
+	/* Free response */
+	pipeline_msg_free(rsp);
+
+	return status;
+}
+
 /**
  * Data plane threads: message handling
  */
@@ -908,6 +1197,461 @@ pipeline_msg_handle_table_stats_read(struct pipeline_data *p,
 	return rsp;
 }
 
+union table_rule_match_low_level {
+	struct rte_table_acl_rule_add_params acl_add;
+	struct rte_table_acl_rule_delete_params acl_delete;
+	struct rte_table_array_key array;
+	uint8_t hash[TABLE_RULE_MATCH_SIZE_MAX];
+	struct rte_table_lpm_key lpm_ipv4;
+	struct rte_table_lpm_ipv6_key lpm_ipv6;
+};
+
+static int
+match_convert_ipv6_depth(uint32_t depth, uint32_t *depth32)
+{
+	if (depth > 128)
+		return -1;
+
+	switch (depth / 32) {
+	case 0:
+		depth32[0] = depth;
+		depth32[1] = 0;
+		depth32[2] = 0;
+		depth32[3] = 0;
+		return 0;
+
+	case 1:
+		depth32[0] = 32;
+		depth32[1] = depth - 32;
+		depth32[2] = 0;
+		depth32[3] = 0;
+		return 0;
+
+	case 2:
+		depth32[0] = 32;
+		depth32[1] = 32;
+		depth32[2] = depth - 64;
+		depth32[3] = 0;
+		return 0;
+
+	case 3:
+		depth32[0] = 32;
+		depth32[1] = 32;
+		depth32[2] = 32;
+		depth32[3] = depth - 96;
+		return 0;
+
+	case 4:
+		depth32[0] = 32;
+		depth32[1] = 32;
+		depth32[2] = 32;
+		depth32[3] = 32;
+		return 0;
+
+	default:
+		return -1;
+	}
+}
+
+static int
+match_convert(struct table_rule_match *mh,
+	union table_rule_match_low_level *ml,
+	int add)
+{
+	memset(ml, 0, sizeof(*ml));
+
+	switch (mh->match_type) {
+	case TABLE_ACL:
+		if (mh->match.acl.ip_version)
+			if (add) {
+				ml->acl_add.field_value[0].value.u8 =
+					mh->match.acl.proto;
+				ml->acl_add.field_value[0].mask_range.u8 =
+					mh->match.acl.proto_mask;
+
+				ml->acl_add.field_value[1].value.u32 =
+					mh->match.acl.ipv4.sa;
+				ml->acl_add.field_value[1].mask_range.u32 =
+					mh->match.acl.sa_depth;
+
+				ml->acl_add.field_value[2].value.u32 =
+					mh->match.acl.ipv4.da;
+				ml->acl_add.field_value[2].mask_range.u32 =
+					mh->match.acl.da_depth;
+
+				ml->acl_add.field_value[3].value.u16 =
+					mh->match.acl.sp0;
+				ml->acl_add.field_value[3].mask_range.u16 =
+					mh->match.acl.sp1;
+
+				ml->acl_add.field_value[4].value.u16 =
+					mh->match.acl.dp0;
+				ml->acl_add.field_value[4].mask_range.u16 =
+					mh->match.acl.dp1;
+
+				ml->acl_add.priority =
+					(int32_t) mh->match.acl.priority;
+			} else {
+				ml->acl_delete.field_value[0].value.u8 =
+					mh->match.acl.proto;
+				ml->acl_delete.field_value[0].mask_range.u8 =
+					mh->match.acl.proto_mask;
+
+				ml->acl_delete.field_value[1].value.u32 =
+					mh->match.acl.ipv4.sa;
+				ml->acl_delete.field_value[1].mask_range.u32 =
+					mh->match.acl.sa_depth;
+
+				ml->acl_delete.field_value[2].value.u32 =
+					mh->match.acl.ipv4.da;
+				ml->acl_delete.field_value[2].mask_range.u32 =
+					mh->match.acl.da_depth;
+
+				ml->acl_delete.field_value[3].value.u16 =
+					mh->match.acl.sp0;
+				ml->acl_delete.field_value[3].mask_range.u16 =
+					mh->match.acl.sp1;
+
+				ml->acl_delete.field_value[4].value.u16 =
+					mh->match.acl.dp0;
+				ml->acl_delete.field_value[4].mask_range.u16 =
+					mh->match.acl.dp1;
+			}
+		else
+			if (add) {
+				uint32_t *sa32 =
+					(uint32_t *) mh->match.acl.ipv6.sa;
+				uint32_t *da32 =
+					(uint32_t *) mh->match.acl.ipv6.da;
+				uint32_t sa32_depth[4], da32_depth[4];
+				int status;
+
+				status = match_convert_ipv6_depth(
+					mh->match.acl.sa_depth,
+					sa32_depth);
+				if (status)
+					return status;
+
+				status = match_convert_ipv6_depth(
+					mh->match.acl.da_depth,
+					da32_depth);
+				if (status)
+					return status;
+
+				ml->acl_add.field_value[0].value.u8 =
+					mh->match.acl.proto;
+				ml->acl_add.field_value[0].mask_range.u8 =
+					mh->match.acl.proto_mask;
+
+				ml->acl_add.field_value[1].value.u32 = sa32[0];
+				ml->acl_add.field_value[1].mask_range.u32 =
+					sa32_depth[0];
+				ml->acl_add.field_value[2].value.u32 = sa32[1];
+				ml->acl_add.field_value[2].mask_range.u32 =
+					sa32_depth[1];
+				ml->acl_add.field_value[3].value.u32 = sa32[2];
+				ml->acl_add.field_value[3].mask_range.u32 =
+					sa32_depth[2];
+				ml->acl_add.field_value[4].value.u32 = sa32[3];
+				ml->acl_add.field_value[4].mask_range.u32 =
+					sa32_depth[3];
+
+				ml->acl_add.field_value[5].value.u32 = da32[0];
+				ml->acl_add.field_value[5].mask_range.u32 =
+					da32_depth[0];
+				ml->acl_add.field_value[6].value.u32 = da32[1];
+				ml->acl_add.field_value[6].mask_range.u32 =
+					da32_depth[1];
+				ml->acl_add.field_value[7].value.u32 = da32[2];
+				ml->acl_add.field_value[7].mask_range.u32 =
+					da32_depth[2];
+				ml->acl_add.field_value[8].value.u32 = da32[3];
+				ml->acl_add.field_value[8].mask_range.u32 =
+					da32_depth[3];
+
+				ml->acl_add.field_value[9].value.u16 =
+					mh->match.acl.sp0;
+				ml->acl_add.field_value[9].mask_range.u16 =
+					mh->match.acl.sp1;
+
+				ml->acl_add.field_value[10].value.u16 =
+					mh->match.acl.dp0;
+				ml->acl_add.field_value[10].mask_range.u16 =
+					mh->match.acl.dp1;
+
+				ml->acl_add.priority =
+					(int32_t) mh->match.acl.priority;
+			} else {
+				uint32_t *sa32 =
+					(uint32_t *) mh->match.acl.ipv6.sa;
+				uint32_t *da32 =
+					(uint32_t *) mh->match.acl.ipv6.da;
+				uint32_t sa32_depth[4], da32_depth[4];
+				int status;
+
+				status = match_convert_ipv6_depth(
+					mh->match.acl.sa_depth,
+					sa32_depth);
+				if (status)
+					return status;
+
+				status = match_convert_ipv6_depth(
+					mh->match.acl.da_depth,
+					da32_depth);
+				if (status)
+					return status;
+
+				ml->acl_delete.field_value[0].value.u8 =
+					mh->match.acl.proto;
+				ml->acl_delete.field_value[0].mask_range.u8 =
+					mh->match.acl.proto_mask;
+
+				ml->acl_delete.field_value[1].value.u32 =
+					sa32[0];
+				ml->acl_delete.field_value[1].mask_range.u32 =
+					sa32_depth[0];
+				ml->acl_delete.field_value[2].value.u32 =
+					sa32[1];
+				ml->acl_delete.field_value[2].mask_range.u32 =
+					sa32_depth[1];
+				ml->acl_delete.field_value[3].value.u32 =
+					sa32[2];
+				ml->acl_delete.field_value[3].mask_range.u32 =
+					sa32_depth[2];
+				ml->acl_delete.field_value[4].value.u32 =
+					sa32[3];
+				ml->acl_delete.field_value[4].mask_range.u32 =
+					sa32_depth[3];
+
+				ml->acl_delete.field_value[5].value.u32 =
+					da32[0];
+				ml->acl_delete.field_value[5].mask_range.u32 =
+					da32_depth[0];
+				ml->acl_delete.field_value[6].value.u32 =
+					da32[1];
+				ml->acl_delete.field_value[6].mask_range.u32 =
+					da32_depth[1];
+				ml->acl_delete.field_value[7].value.u32 =
+					da32[2];
+				ml->acl_delete.field_value[7].mask_range.u32 =
+					da32_depth[2];
+				ml->acl_delete.field_value[8].value.u32 =
+					da32[3];
+				ml->acl_delete.field_value[8].mask_range.u32 =
+					da32_depth[3];
+
+				ml->acl_delete.field_value[9].value.u16 =
+					mh->match.acl.sp0;
+				ml->acl_delete.field_value[9].mask_range.u16 =
+					mh->match.acl.sp1;
+
+				ml->acl_delete.field_value[10].value.u16 =
+					mh->match.acl.dp0;
+				ml->acl_delete.field_value[10].mask_range.u16 =
+					mh->match.acl.dp1;
+			}
+		return 0;
+
+	case TABLE_ARRAY:
+		ml->array.pos = mh->match.array.pos;
+		return 0;
+
+	case TABLE_HASH:
+		memcpy(ml->hash, mh->match.hash.key, sizeof(ml->hash));
+		return 0;
+
+	case TABLE_LPM:
+		if (mh->match.lpm.ip_version) {
+			ml->lpm_ipv4.ip = mh->match.lpm.ipv4;
+			ml->lpm_ipv4.depth = mh->match.lpm.depth;
+		} else {
+			memcpy(ml->lpm_ipv6.ip,
+				mh->match.lpm.ipv6, sizeof(ml->lpm_ipv6.ip));
+			ml->lpm_ipv6.depth = mh->match.lpm.depth;
+		}
+
+		return 0;
+
+	default:
+		return -1;
+	}
+}
+
+static struct pipeline_msg_rsp *
+pipeline_msg_handle_table_rule_add(struct pipeline_data *p,
+	struct pipeline_msg_req *req)
+{
+	union table_rule_match_low_level match_ll;
+	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+	struct table_rule_match *match = &req->table_rule_add.match;
+	struct table_rule_action *action = &req->table_rule_add.action;
+	struct rte_pipeline_table_entry *data_in, *data_out;
+	uint32_t table_id = req->id;
+	int key_found, status;
+	struct rte_table_action *a = p->table_data[table_id].a;
+
+	/* Apply actions */
+	memset(p->buffer, 0, sizeof(p->buffer));
+	data_in = (struct rte_pipeline_table_entry *) p->buffer;
+
+	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_FWD)) {
+		status = rte_table_action_apply(a,
+			data_in,
+			RTE_TABLE_ACTION_FWD,
+			&action->fwd);
+
+		if (status) {
+			rsp->status = -1;
+			return rsp;
+		}
+	}
+
+	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) {
+		status = rte_table_action_apply(a,
+			data_in,
+			RTE_TABLE_ACTION_MTR,
+			&action->mtr);
+
+		if (status) {
+			rsp->status = -1;
+			return rsp;
+		}
+	}
+
+	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_TM)) {
+		status = rte_table_action_apply(a,
+			data_in,
+			RTE_TABLE_ACTION_TM,
+			&action->tm);
+
+		if (status) {
+			rsp->status = -1;
+			return rsp;
+		}
+	}
+
+	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_ENCAP)) {
+		status = rte_table_action_apply(a,
+			data_in,
+			RTE_TABLE_ACTION_ENCAP,
+			&action->encap);
+
+		if (status) {
+			rsp->status = -1;
+			return rsp;
+		}
+	}
+
+	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_NAT)) {
+		status = rte_table_action_apply(a,
+			data_in,
+			RTE_TABLE_ACTION_NAT,
+			&action->nat);
+
+		if (status) {
+			rsp->status = -1;
+			return rsp;
+		}
+	}
+
+	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_TTL)) {
+		status = rte_table_action_apply(a,
+			data_in,
+			RTE_TABLE_ACTION_TTL,
+			&action->ttl);
+
+		if (status) {
+			rsp->status = -1;
+			return rsp;
+		}
+	}
+
+	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_STATS)) {
+		status = rte_table_action_apply(a,
+			data_in,
+			RTE_TABLE_ACTION_STATS,
+			&action->stats);
+
+		if (status) {
+			rsp->status = -1;
+			return rsp;
+		}
+	}
+
+	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_TIME)) {
+		status = rte_table_action_apply(a,
+			data_in,
+			RTE_TABLE_ACTION_TIME,
+			&action->time);
+
+		if (status) {
+			rsp->status = -1;
+			return rsp;
+		}
+	}
+
+	/* Add rule (match, action) to table */
+	status = match_convert(match, &match_ll, 1);
+	if (status) {
+		rsp->status = -1;
+		return rsp;
+	}
+
+	status = rte_pipeline_table_entry_add(p->p,
+		table_id,
+		&match_ll,
+		data_in,
+		&key_found,
+		&data_out);
+	if (status) {
+		rsp->status = -1;
+		return rsp;
+	}
+
+	/* Write response */
+	rsp->status = 0;
+	rsp->table_rule_add.data = data_out;
+
+	return rsp;
+}
+
+static struct pipeline_msg_rsp *
+pipeline_msg_handle_table_rule_add_default(struct pipeline_data *p,
+	struct pipeline_msg_req *req)
+{
+	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+	struct table_rule_action *action = &req->table_rule_add_default.action;
+	struct rte_pipeline_table_entry *data_in, *data_out;
+	uint32_t table_id = req->id;
+	int status;
+
+	/* Apply actions */
+	memset(p->buffer, 0, sizeof(p->buffer));
+	data_in = (struct rte_pipeline_table_entry *) p->buffer;
+
+	data_in->action = action->fwd.action;
+	if (action->fwd.action == RTE_PIPELINE_ACTION_PORT)
+		data_in->port_id = action->fwd.id;
+	if (action->fwd.action == RTE_PIPELINE_ACTION_TABLE)
+		data_in->table_id = action->fwd.id;
+
+	/* Add default rule to table */
+	status = rte_pipeline_table_default_entry_add(p->p,
+		table_id,
+		data_in,
+		&data_out);
+	if (status) {
+		rsp->status = -1;
+		return rsp;
+	}
+
+	/* Write response */
+	rsp->status = 0;
+	rsp->table_rule_add_default.data = data_out;
+
+	return rsp;
+}
+
 static void
 pipeline_msg_handle(struct pipeline_data *p)
 {
@@ -940,6 +1684,13 @@ pipeline_msg_handle(struct pipeline_data *p)
 			rsp = pipeline_msg_handle_table_stats_read(p, req);
 			break;
 
+		case PIPELINE_REQ_TABLE_RULE_ADD:
+			rsp = pipeline_msg_handle_table_rule_add(p, req);
+			break;
+
+		case PIPELINE_REQ_TABLE_RULE_ADD_DEFAULT:
+			rsp = pipeline_msg_handle_table_rule_add_default(p,	req);
+			break;
 
 		default:
 			rsp = (struct pipeline_msg_rsp *) req;
-- 
2.9.3

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

* [dpdk-dev] [PATCH v4 36/49] ip_pipeline: add cli to delete pipeline table entry
  2018-03-29 18:31           ` [dpdk-dev] [PATCH v4 00/49] ip_pipeline: refactoring Jasvinder Singh
                               ` (34 preceding siblings ...)
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 35/49] ip_pipeline: add cli for pipeline table entry Jasvinder Singh
@ 2018-03-29 18:31             ` Jasvinder Singh
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 37/49] ip_pipeline: add cli for bulk entries to pipeline table Jasvinder Singh
                               ` (13 subsequent siblings)
  49 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-29 18:31 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add command to delete the pipeline table entry.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/cli.c      | 145 ++++++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/pipeline.h |   9 +++
 examples/ip_pipeline/thread.c   | 142 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 296 insertions(+)

diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index b6a2177..13c7392 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -3540,6 +3540,134 @@ cmd_pipeline_table_rule_add_default(char **tokens,
 }
 
 /**
+ * pipeline <pipeline_name> table <table_id> rule delete
+ *    match <match>
+ */
+static void
+cmd_pipeline_table_rule_delete(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct table_rule_match m;
+	char *pipeline_name;
+	uint32_t table_id, n_tokens_parsed, t0;
+	int status;
+
+	if (n_tokens < 8) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "table") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
+		return;
+	}
+
+	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
+		return;
+	}
+
+	if (strcmp(tokens[4], "rule") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
+		return;
+	}
+
+	if (strcmp(tokens[5], "delete") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete");
+		return;
+	}
+
+	t0 = 6;
+
+	/* match */
+	n_tokens_parsed = parse_match(tokens + t0,
+		n_tokens - t0,
+		out,
+		out_size,
+		&m);
+	if (n_tokens_parsed == 0)
+		return;
+	t0 += n_tokens_parsed;
+
+	if (n_tokens != t0) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	status = pipeline_table_rule_delete(pipeline_name,
+		table_id,
+		&m);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
+ * pipeline <pipeline_name> table <table_id> rule delete
+ *    match
+ *       default
+ */
+static void
+cmd_pipeline_table_rule_delete_default(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	char *pipeline_name;
+	uint32_t table_id;
+	int status;
+
+	if (n_tokens != 8) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "table") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
+		return;
+	}
+
+	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
+		return;
+	}
+
+	if (strcmp(tokens[4], "rule") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
+		return;
+	}
+
+	if (strcmp(tokens[5], "delete") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete");
+		return;
+	}
+
+	if (strcmp(tokens[6], "match") != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "match");
+		return;
+	}
+
+	if (strcmp(tokens[7], "default") != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "default");
+		return;
+	}
+
+	status = pipeline_table_rule_delete_default(pipeline_name,
+		table_id);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
  * thread <thread_id> pipeline <pipeline_name> enable
  */
 static void
@@ -3811,6 +3939,23 @@ cli_process(char *in, char *out, size_t out_size)
 				out, out_size);
 			return;
 		}
+
+		if ((n_tokens >= 7) &&
+			(strcmp(tokens[2], "table") == 0) &&
+			(strcmp(tokens[4], "rule") == 0) &&
+			(strcmp(tokens[5], "delete") == 0) &&
+			(strcmp(tokens[6], "match") == 0)) {
+			if ((n_tokens >= 8) &&
+				(strcmp(tokens[7], "default") == 0)) {
+				cmd_pipeline_table_rule_delete_default(tokens,
+					n_tokens, out, out_size);
+				return;
+				}
+
+			cmd_pipeline_table_rule_delete(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
 	}
 
 	if (strcmp(tokens[0], "thread") == 0) {
diff --git a/examples/ip_pipeline/pipeline.h b/examples/ip_pipeline/pipeline.h
index 64efbed..4fc7b27 100644
--- a/examples/ip_pipeline/pipeline.h
+++ b/examples/ip_pipeline/pipeline.h
@@ -308,4 +308,13 @@ pipeline_table_rule_add_default(const char *pipeline_name,
 	struct table_rule_action *action,
 	void **data);
 
+int
+pipeline_table_rule_delete(const char *pipeline_name,
+	uint32_t table_id,
+	struct table_rule_match *match);
+
+int
+pipeline_table_rule_delete_default(const char *pipeline_name,
+	uint32_t table_id);
+
 #endif /* _INCLUDE_PIPELINE_H_ */
diff --git a/examples/ip_pipeline/thread.c b/examples/ip_pipeline/thread.c
index 0291883..2532e09 100644
--- a/examples/ip_pipeline/thread.c
+++ b/examples/ip_pipeline/thread.c
@@ -490,6 +490,8 @@ enum pipeline_req_type {
 	PIPELINE_REQ_TABLE_STATS_READ,
 	PIPELINE_REQ_TABLE_RULE_ADD,
 	PIPELINE_REQ_TABLE_RULE_ADD_DEFAULT,
+	PIPELINE_REQ_TABLE_RULE_DELETE,
+	PIPELINE_REQ_TABLE_RULE_DELETE_DEFAULT,
 
 	PIPELINE_REQ_MAX
 };
@@ -515,6 +517,10 @@ struct pipeline_msg_req_table_rule_add_default {
 	struct table_rule_action action;
 };
 
+struct pipeline_msg_req_table_rule_delete {
+	struct table_rule_match match;
+};
+
 struct pipeline_msg_req {
 	enum pipeline_req_type type;
 	uint32_t id; /* Port IN, port OUT or table ID */
@@ -526,6 +532,7 @@ struct pipeline_msg_req {
 		struct pipeline_msg_req_table_stats_read table_stats_read;
 		struct pipeline_msg_req_table_rule_add table_rule_add;
 		struct pipeline_msg_req_table_rule_add_default table_rule_add_default;
+		struct pipeline_msg_req_table_rule_delete table_rule_delete;
 	};
 };
 
@@ -1096,6 +1103,94 @@ pipeline_table_rule_add_default(const char *pipeline_name,
 	return status;
 }
 
+int
+pipeline_table_rule_delete(const char *pipeline_name,
+	uint32_t table_id,
+	struct table_rule_match *match)
+{
+	struct pipeline *p;
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if ((pipeline_name == NULL) ||
+		(match == NULL))
+		return -1;
+
+	p = pipeline_find(pipeline_name);
+	if ((p == NULL) ||
+		(p->enabled == 0) ||
+		(table_id >= p->n_tables) ||
+		match_check(match, p, table_id))
+		return -1;
+
+	/* Allocate request */
+	req = pipeline_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = PIPELINE_REQ_TABLE_RULE_DELETE;
+	req->id = table_id;
+	memcpy(&req->table_rule_delete.match, match, sizeof(*match));
+
+	/* Send request and wait for response */
+	rsp = pipeline_msg_send_recv(p, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+
+	/* Free response */
+	pipeline_msg_free(rsp);
+
+	return status;
+}
+
+int
+pipeline_table_rule_delete_default(const char *pipeline_name,
+	uint32_t table_id)
+{
+	struct pipeline *p;
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if (pipeline_name == NULL)
+		return -1;
+
+	p = pipeline_find(pipeline_name);
+	if ((p == NULL) ||
+		(p->enabled == 0) ||
+		(table_id >= p->n_tables))
+		return -1;
+
+	/* Allocate request */
+	req = pipeline_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = PIPELINE_REQ_TABLE_RULE_DELETE_DEFAULT;
+	req->id = table_id;
+
+	/* Send request and wait for response */
+	rsp = pipeline_msg_send_recv(p, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+
+	/* Free response */
+	pipeline_msg_free(rsp);
+
+	return status;
+}
+
 /**
  * Data plane threads: message handling
  */
@@ -1652,6 +1747,45 @@ pipeline_msg_handle_table_rule_add_default(struct pipeline_data *p,
 	return rsp;
 }
 
+static struct pipeline_msg_rsp *
+pipeline_msg_handle_table_rule_delete(struct pipeline_data *p,
+	struct pipeline_msg_req *req)
+{
+	union table_rule_match_low_level match_ll;
+	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+	struct table_rule_match *match = &req->table_rule_delete.match;
+	uint32_t table_id = req->id;
+	int key_found, status;
+
+	status = match_convert(match, &match_ll, 0);
+	if (status) {
+		rsp->status = -1;
+		return rsp;
+	}
+
+	rsp->status = rte_pipeline_table_entry_delete(p->p,
+		table_id,
+		&match_ll,
+		&key_found,
+		NULL);
+
+	return rsp;
+}
+
+static struct pipeline_msg_rsp *
+pipeline_msg_handle_table_rule_delete_default(struct pipeline_data *p,
+	struct pipeline_msg_req *req)
+{
+	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+	uint32_t table_id = req->id;
+
+	rsp->status = rte_pipeline_table_default_entry_delete(p->p,
+		table_id,
+		NULL);
+
+	return rsp;
+}
+
 static void
 pipeline_msg_handle(struct pipeline_data *p)
 {
@@ -1692,6 +1826,14 @@ pipeline_msg_handle(struct pipeline_data *p)
 			rsp = pipeline_msg_handle_table_rule_add_default(p,	req);
 			break;
 
+		case PIPELINE_REQ_TABLE_RULE_DELETE:
+			rsp = pipeline_msg_handle_table_rule_delete(p, req);
+			break;
+
+		case PIPELINE_REQ_TABLE_RULE_DELETE_DEFAULT:
+			rsp = pipeline_msg_handle_table_rule_delete_default(p, req);
+			break;
+
 		default:
 			rsp = (struct pipeline_msg_rsp *) req;
 			rsp->status = -1;
-- 
2.9.3

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

* [dpdk-dev] [PATCH v4 37/49] ip_pipeline: add cli for bulk entries to pipeline table
  2018-03-29 18:31           ` [dpdk-dev] [PATCH v4 00/49] ip_pipeline: refactoring Jasvinder Singh
                               ` (35 preceding siblings ...)
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 36/49] ip_pipeline: add cli to delete " Jasvinder Singh
@ 2018-03-29 18:31             ` Jasvinder Singh
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 38/49] ip_pipeline: add cli to read pipeline table entry stats Jasvinder Singh
                               ` (12 subsequent siblings)
  49 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-29 18:31 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Kevin Laatz

Add cli for adding bulk entries to pipeline table.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
---
 examples/ip_pipeline/cli.c      | 267 +++++++++++++++++++++++++++++++++++++--
 examples/ip_pipeline/pipeline.h |   8 ++
 examples/ip_pipeline/thread.c   | 272 +++++++++++++++++++++++++++++++++++++++-
 3 files changed, 536 insertions(+), 11 deletions(-)

diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index 13c7392..c85d3b3 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -25,16 +25,17 @@
 #define CMD_MAX_TOKENS     256
 #endif
 
-#define MSG_OUT_OF_MEMORY  "Not enough memory.\n"
-#define MSG_CMD_UNKNOWN    "Unknown command \"%s\".\n"
-#define MSG_CMD_UNIMPLEM   "Command \"%s\" not implemented.\n"
-#define MSG_ARG_NOT_ENOUGH "Not enough arguments for command \"%s\".\n"
-#define MSG_ARG_TOO_MANY   "Too many arguments for command \"%s\".\n"
-#define MSG_ARG_MISMATCH   "Wrong number of arguments for command \"%s\".\n"
-#define MSG_ARG_NOT_FOUND  "Argument \"%s\" not found.\n"
-#define MSG_ARG_INVALID    "Invalid value for argument \"%s\".\n"
-#define MSG_FILE_ERR       "Error in file \"%s\" at line %u.\n"
-#define MSG_CMD_FAIL       "Command \"%s\" failed.\n"
+#define MSG_OUT_OF_MEMORY   "Not enough memory.\n"
+#define MSG_CMD_UNKNOWN     "Unknown command \"%s\".\n"
+#define MSG_CMD_UNIMPLEM    "Command \"%s\" not implemented.\n"
+#define MSG_ARG_NOT_ENOUGH  "Not enough arguments for command \"%s\".\n"
+#define MSG_ARG_TOO_MANY    "Too many arguments for command \"%s\".\n"
+#define MSG_ARG_MISMATCH    "Wrong number of arguments for command \"%s\".\n"
+#define MSG_ARG_NOT_FOUND   "Argument \"%s\" not found.\n"
+#define MSG_ARG_INVALID     "Invalid value for argument \"%s\".\n"
+#define MSG_FILE_ERR        "Error in file \"%s\" at line %u.\n"
+#define MSG_FILE_NOT_ENOUGH "Not enough rules in file \"%s\".\n"
+#define MSG_CMD_FAIL        "Command \"%s\" failed.\n"
 
 static int
 is_comment(char *in)
@@ -3540,6 +3541,133 @@ cmd_pipeline_table_rule_add_default(char **tokens,
 }
 
 /**
+ * pipeline <pipeline_name> table <table_id> rule add bulk <file_name> <n_rules>
+ *
+ * File <file_name>:
+ * - line format: match <match> action <action>
+ */
+static int
+cli_rule_file_process(const char *file_name,
+	size_t line_len_max,
+	struct table_rule_match *m,
+	struct table_rule_action *a,
+	uint32_t *n_rules,
+	uint32_t *line_number,
+	char *out,
+	size_t out_size);
+
+static void
+cmd_pipeline_table_rule_add_bulk(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct table_rule_match *match;
+	struct table_rule_action *action;
+	void **data;
+	char *pipeline_name, *file_name;
+	uint32_t table_id, n_rules, n_rules_parsed, line_number;
+	int status;
+
+	if (n_tokens != 9) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "table") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table");
+		return;
+	}
+
+	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
+		return;
+	}
+
+	if (strcmp(tokens[4], "rule") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rule");
+		return;
+	}
+
+	if (strcmp(tokens[5], "add") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
+		return;
+	}
+
+	if (strcmp(tokens[6], "bulk") != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "bulk");
+		return;
+	}
+
+	file_name = tokens[7];
+
+	if ((parser_read_uint32(&n_rules, tokens[8]) != 0) ||
+		(n_rules == 0)) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "n_rules");
+		return;
+	}
+
+	/* Memory allocation. */
+	match = calloc(n_rules, sizeof(struct table_rule_match));
+	action = calloc(n_rules, sizeof(struct table_rule_action));
+	data = calloc(n_rules, sizeof(void *));
+	if ((match == NULL) || (action == NULL) || (data == NULL)) {
+		snprintf(out, out_size, MSG_OUT_OF_MEMORY);
+		free(data);
+		free(action);
+		free(match);
+		return;
+	}
+
+	/* Load rule file */
+	n_rules_parsed = n_rules;
+	status = cli_rule_file_process(file_name,
+		1024,
+		match,
+		action,
+		&n_rules_parsed,
+		&line_number,
+		out,
+		out_size);
+	if (status) {
+		snprintf(out, out_size, MSG_FILE_ERR, file_name, line_number);
+		free(data);
+		free(action);
+		free(match);
+		return;
+	}
+	if (n_rules_parsed != n_rules) {
+		snprintf(out, out_size, MSG_FILE_NOT_ENOUGH, file_name);
+		free(data);
+		free(action);
+		free(match);
+		return;
+	}
+
+	/* Rule bulk add */
+	status = pipeline_table_rule_add_bulk(pipeline_name,
+		table_id,
+		match,
+		action,
+		data,
+		&n_rules);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		free(data);
+		free(action);
+		free(match);
+		return;
+	}
+
+	/* Memory free */
+	free(data);
+	free(action);
+	free(match);
+}
+
+/**
  * pipeline <pipeline_name> table <table_id> rule delete
  *    match <match>
  */
@@ -3943,6 +4071,16 @@ cli_process(char *in, char *out, size_t out_size)
 		if ((n_tokens >= 7) &&
 			(strcmp(tokens[2], "table") == 0) &&
 			(strcmp(tokens[4], "rule") == 0) &&
+			(strcmp(tokens[5], "add") == 0) &&
+			(strcmp(tokens[6], "bulk") == 0)) {
+				cmd_pipeline_table_rule_add_bulk(tokens,
+					n_tokens, out, out_size);
+				return;
+		}
+
+		if ((n_tokens >= 7) &&
+			(strcmp(tokens[2], "table") == 0) &&
+			(strcmp(tokens[4], "rule") == 0) &&
 			(strcmp(tokens[5], "delete") == 0) &&
 			(strcmp(tokens[6], "match") == 0)) {
 			if ((n_tokens >= 8) &&
@@ -4031,3 +4169,112 @@ cli_script_process(const char *file_name,
 	free(msg_in);
 	return 0;
 }
+
+static int
+cli_rule_file_process(const char *file_name,
+	size_t line_len_max,
+	struct table_rule_match *m,
+	struct table_rule_action *a,
+	uint32_t *n_rules,
+	uint32_t *line_number,
+	char *out,
+	size_t out_size)
+{
+	FILE *f = NULL;
+	char *line = NULL;
+	uint32_t rule_id, line_id;
+	int status = 0;
+
+	/* Check input arguments */
+	if ((file_name == NULL) ||
+		(strlen(file_name) == 0) ||
+		(line_len_max == 0)) {
+		*line_number = 0;
+		return -EINVAL;
+	}
+
+	/* Memory allocation */
+	line = malloc(line_len_max + 1);
+	if (line == NULL) {
+		*line_number = 0;
+		return -ENOMEM;
+	}
+
+	/* Open file */
+	f = fopen(file_name, "r");
+	if (f == NULL) {
+		*line_number = 0;
+		free(line);
+		return -EIO;
+	}
+
+	/* Read file */
+	for (line_id = 1, rule_id = 0; rule_id < *n_rules; line_id++) {
+		char *tokens[CMD_MAX_TOKENS];
+		uint32_t n_tokens, n_tokens_parsed, t0;
+
+		/* Read next line from file. */
+		if (fgets(line, line_len_max + 1, f) == NULL)
+			break;
+
+		/* Comment. */
+		if (is_comment(line))
+			continue;
+
+		/* Parse line. */
+		n_tokens = RTE_DIM(tokens);
+		status = parse_tokenize_string(line, tokens, &n_tokens);
+		if (status) {
+			status = -EINVAL;
+			break;
+		}
+
+		/* Empty line. */
+		if (n_tokens == 0)
+			continue;
+		t0 = 0;
+
+		/* Rule match. */
+		n_tokens_parsed = parse_match(tokens + t0,
+			n_tokens - t0,
+			out,
+			out_size,
+			&m[rule_id]);
+		if (n_tokens_parsed == 0) {
+			status = -EINVAL;
+			break;
+		}
+		t0 += n_tokens_parsed;
+
+		/* Rule action. */
+		n_tokens_parsed = parse_table_action(tokens + t0,
+			n_tokens - t0,
+			out,
+			out_size,
+			&a[rule_id]);
+		if (n_tokens_parsed == 0) {
+			status = -EINVAL;
+			break;
+		}
+		t0 += n_tokens_parsed;
+
+		/* Line completed. */
+		if (t0 < n_tokens) {
+			status = -EINVAL;
+			break;
+		}
+
+		/* Increment rule count */
+		rule_id++;
+	}
+
+	/* Close file */
+	fclose(f);
+
+	/* Memory free */
+	free(line);
+
+	*n_rules = rule_id;
+	*line_number = line_id;
+	return status;
+}
diff --git a/examples/ip_pipeline/pipeline.h b/examples/ip_pipeline/pipeline.h
index 4fc7b27..37d1c7a 100644
--- a/examples/ip_pipeline/pipeline.h
+++ b/examples/ip_pipeline/pipeline.h
@@ -303,6 +303,14 @@ pipeline_table_rule_add(const char *pipeline_name,
 	void **data);
 
 int
+pipeline_table_rule_add_bulk(const char *pipeline_name,
+	uint32_t table_id,
+	struct table_rule_match *match,
+	struct table_rule_action *action,
+	void **data,
+	uint32_t *n_rules);
+
+int
 pipeline_table_rule_add_default(const char *pipeline_name,
 	uint32_t table_id,
 	struct table_rule_action *action,
diff --git a/examples/ip_pipeline/thread.c b/examples/ip_pipeline/thread.c
index 2532e09..3f5e15e 100644
--- a/examples/ip_pipeline/thread.c
+++ b/examples/ip_pipeline/thread.c
@@ -490,9 +490,9 @@ enum pipeline_req_type {
 	PIPELINE_REQ_TABLE_STATS_READ,
 	PIPELINE_REQ_TABLE_RULE_ADD,
 	PIPELINE_REQ_TABLE_RULE_ADD_DEFAULT,
+	PIPELINE_REQ_TABLE_RULE_ADD_BULK,
 	PIPELINE_REQ_TABLE_RULE_DELETE,
 	PIPELINE_REQ_TABLE_RULE_DELETE_DEFAULT,
-
 	PIPELINE_REQ_MAX
 };
 
@@ -517,6 +517,14 @@ struct pipeline_msg_req_table_rule_add_default {
 	struct table_rule_action action;
 };
 
+struct pipeline_msg_req_table_rule_add_bulk {
+	struct table_rule_match *match;
+	struct table_rule_action *action;
+	void **data;
+	uint32_t n_rules;
+	int bulk;
+};
+
 struct pipeline_msg_req_table_rule_delete {
 	struct table_rule_match match;
 };
@@ -532,6 +540,7 @@ struct pipeline_msg_req {
 		struct pipeline_msg_req_table_stats_read table_stats_read;
 		struct pipeline_msg_req_table_rule_add table_rule_add;
 		struct pipeline_msg_req_table_rule_add_default table_rule_add_default;
+		struct pipeline_msg_req_table_rule_add_bulk table_rule_add_bulk;
 		struct pipeline_msg_req_table_rule_delete table_rule_delete;
 	};
 };
@@ -556,6 +565,10 @@ struct pipeline_msg_rsp_table_rule_add_default {
 	void *data;
 };
 
+struct pipeline_msg_rsp_table_rule_add_bulk {
+	uint32_t n_rules;
+};
+
 struct pipeline_msg_rsp {
 	int status;
 
@@ -566,6 +579,7 @@ struct pipeline_msg_rsp {
 		struct pipeline_msg_rsp_table_stats_read table_stats_read;
 		struct pipeline_msg_rsp_table_rule_add table_rule_add;
 		struct pipeline_msg_rsp_table_rule_add_default table_rule_add_default;
+		struct pipeline_msg_rsp_table_rule_add_bulk table_rule_add_bulk;
 	};
 };
 
@@ -1104,6 +1118,71 @@ pipeline_table_rule_add_default(const char *pipeline_name,
 }
 
 int
+pipeline_table_rule_add_bulk(const char *pipeline_name,
+	uint32_t table_id,
+	struct table_rule_match *match,
+	struct table_rule_action *action,
+	void **data,
+	uint32_t *n_rules)
+{
+	struct pipeline *p;
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	uint32_t i;
+	int status;
+
+	/* Check input params */
+	if ((pipeline_name == NULL) ||
+		(match == NULL) ||
+		(action == NULL) ||
+		(data == NULL) ||
+		(n_rules == NULL) ||
+		(*n_rules == 0))
+		return -1;
+
+	p = pipeline_find(pipeline_name);
+	if ((p == NULL) ||
+		(p->enabled == 0) ||
+		(table_id >= p->n_tables))
+		return -1;
+
+	for (i = 0; i < *n_rules; i++)
+		if (match_check(match, p, table_id) ||
+			action_check(action, p, table_id))
+			return -1;
+
+	/* Allocate request */
+	req = pipeline_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = PIPELINE_REQ_TABLE_RULE_ADD_BULK;
+	req->id = table_id;
+	req->table_rule_add_bulk.match = match;
+	req->table_rule_add_bulk.action = action;
+	req->table_rule_add_bulk.data = data;
+	req->table_rule_add_bulk.n_rules = *n_rules;
+	req->table_rule_add_bulk.bulk =
+		(p->table[table_id].params.match_type == TABLE_ACL) ? 1 : 0;
+
+	/* Send request and wait for response */
+	rsp = pipeline_msg_send_recv(p, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+	if (status == 0)
+		*n_rules = rsp->table_rule_add_bulk.n_rules;
+
+	/* Free response */
+	pipeline_msg_free(rsp);
+
+	return status;
+}
+
+int
 pipeline_table_rule_delete(const char *pipeline_name,
 	uint32_t table_id,
 	struct table_rule_match *match)
@@ -1748,6 +1827,193 @@ pipeline_msg_handle_table_rule_add_default(struct pipeline_data *p,
 }
 
 static struct pipeline_msg_rsp *
+pipeline_msg_handle_table_rule_add_bulk(struct pipeline_data *p,
+	struct pipeline_msg_req *req)
+{
+
+	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+
+	uint32_t table_id = req->id;
+	struct table_rule_match *match = req->table_rule_add_bulk.match;
+	struct table_rule_action *action = req->table_rule_add_bulk.action;
+	struct rte_pipeline_table_entry **data =
+		(struct rte_pipeline_table_entry **)req->table_rule_add_bulk.data;
+	uint32_t n_rules = req->table_rule_add_bulk.n_rules;
+	uint32_t bulk = req->table_rule_add_bulk.bulk;
+
+	struct rte_table_action *a = p->table_data[table_id].a;
+	union table_rule_match_low_level *match_ll;
+	uint8_t *action_ll;
+	void **match_ll_ptr;
+	struct rte_pipeline_table_entry **action_ll_ptr;
+	int *found, status;
+	uint32_t i;
+
+	/* Memory allocation */
+	match_ll = calloc(n_rules, sizeof(union table_rule_match_low_level));
+	action_ll = calloc(n_rules, TABLE_RULE_ACTION_SIZE_MAX);
+	match_ll_ptr = calloc(n_rules, sizeof(void *));
+	action_ll_ptr =
+		calloc(n_rules, sizeof(struct rte_pipeline_table_entry *));
+	found = calloc(n_rules, sizeof(int));
+
+	if ((match_ll == NULL) ||
+		(action_ll == NULL) ||
+		(match_ll_ptr == NULL) ||
+		(action_ll_ptr == NULL) ||
+		(found == NULL))
+		goto fail;
+
+	for (i = 0; i < n_rules; i++) {
+		match_ll_ptr[i] = (void *)&match_ll[i];
+		action_ll_ptr[i] =
+			(struct rte_pipeline_table_entry *)&action_ll[i * TABLE_RULE_ACTION_SIZE_MAX];
+	}
+
+	/* Rule match conversion */
+	for (i = 0; i < n_rules; i++) {
+		status = match_convert(&match[i], match_ll_ptr[i], 1);
+		if (status)
+			goto fail;
+	}
+
+	/* Rule action conversion */
+	for (i = 0; i < n_rules; i++) {
+		void *data_in = action_ll_ptr[i];
+		struct table_rule_action *act = &action[i];
+
+		if (act->action_mask & (1LLU << RTE_TABLE_ACTION_FWD)) {
+			status = rte_table_action_apply(a,
+				data_in,
+				RTE_TABLE_ACTION_FWD,
+				&act->fwd);
+
+			if (status)
+				goto fail;
+		}
+
+		if (act->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) {
+			status = rte_table_action_apply(a,
+				data_in,
+				RTE_TABLE_ACTION_MTR,
+				&act->mtr);
+
+			if (status)
+				goto fail;
+		}
+
+		if (act->action_mask & (1LLU << RTE_TABLE_ACTION_TM)) {
+			status = rte_table_action_apply(a,
+				data_in,
+				RTE_TABLE_ACTION_TM,
+				&act->tm);
+
+			if (status)
+				goto fail;
+		}
+
+		if (act->action_mask & (1LLU << RTE_TABLE_ACTION_ENCAP)) {
+			status = rte_table_action_apply(a,
+				data_in,
+				RTE_TABLE_ACTION_ENCAP,
+				&act->encap);
+
+			if (status)
+				goto fail;
+		}
+
+		if (act->action_mask & (1LLU << RTE_TABLE_ACTION_NAT)) {
+			status = rte_table_action_apply(a,
+				data_in,
+				RTE_TABLE_ACTION_NAT,
+				&act->nat);
+
+			if (status)
+				goto fail;
+		}
+
+		if (act->action_mask & (1LLU << RTE_TABLE_ACTION_TTL)) {
+			status = rte_table_action_apply(a,
+				data_in,
+				RTE_TABLE_ACTION_TTL,
+				&act->ttl);
+
+			if (status)
+				goto fail;
+		}
+
+		if (act->action_mask & (1LLU << RTE_TABLE_ACTION_STATS)) {
+			status = rte_table_action_apply(a,
+				data_in,
+				RTE_TABLE_ACTION_STATS,
+				&act->stats);
+
+			if (status)
+				goto fail;
+		}
+
+		if (act->action_mask & (1LLU << RTE_TABLE_ACTION_TIME)) {
+			status = rte_table_action_apply(a,
+				data_in,
+				RTE_TABLE_ACTION_TIME,
+				&act->time);
+
+			if (status)
+				goto fail;
+		}
+	}
+
+	/* Add rule (match, action) to table */
+	if (bulk) {
+		status = rte_pipeline_table_entry_add_bulk(p->p,
+			table_id,
+			match_ll_ptr,
+			action_ll_ptr,
+			n_rules,
+			found,
+			data);
+		if (status)
+			n_rules = 0;
+	} else
+		for (i = 0; i < n_rules; i++) {
+			status = rte_pipeline_table_entry_add(p->p,
+				table_id,
+				match_ll_ptr[i],
+				action_ll_ptr[i],
+				&found[i],
+				&data[i]);
+			if (status) {
+				n_rules = i;
+				break;
+			}
+		}
+
+	/* Write response */
+	rsp->status = 0;
+	rsp->table_rule_add_bulk.n_rules = n_rules;
+
+	/* Free */
+	free(found);
+	free(action_ll_ptr);
+	free(match_ll_ptr);
+	free(action_ll);
+	free(match_ll);
+
+	return rsp;
+
+fail:
+	free(found);
+	free(action_ll_ptr);
+	free(match_ll_ptr);
+	free(action_ll);
+	free(match_ll);
+
+	rsp->status = -1;
+	rsp->table_rule_add_bulk.n_rules = 0;
+	return rsp;
+}
+
+static struct pipeline_msg_rsp *
 pipeline_msg_handle_table_rule_delete(struct pipeline_data *p,
 	struct pipeline_msg_req *req)
 {
@@ -1826,6 +2092,10 @@ pipeline_msg_handle(struct pipeline_data *p)
 			rsp = pipeline_msg_handle_table_rule_add_default(p,	req);
 			break;
 
+		case PIPELINE_REQ_TABLE_RULE_ADD_BULK:
+			rsp = pipeline_msg_handle_table_rule_add_bulk(p, req);
+			break;
+
 		case PIPELINE_REQ_TABLE_RULE_DELETE:
 			rsp = pipeline_msg_handle_table_rule_delete(p, req);
 			break;
-- 
2.9.3

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

* [dpdk-dev] [PATCH v4 38/49] ip_pipeline: add cli to read pipeline table entry stats
  2018-03-29 18:31           ` [dpdk-dev] [PATCH v4 00/49] ip_pipeline: refactoring Jasvinder Singh
                               ` (36 preceding siblings ...)
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 37/49] ip_pipeline: add cli for bulk entries to pipeline table Jasvinder Singh
@ 2018-03-29 18:31             ` Jasvinder Singh
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 39/49] ip_pipeline: add cli to configure meter profile Jasvinder Singh
                               ` (11 subsequent siblings)
  49 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-29 18:31 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Fan Zhang

Add command to read the pipeline table entry stats.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Fan Zhang <roy.fan.zhang@intel.com>
---
 examples/ip_pipeline/cli.c      | 22 +++++++++++
 examples/ip_pipeline/pipeline.h |  7 ++++
 examples/ip_pipeline/thread.c   | 85 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 114 insertions(+)

diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index c85d3b3..b9a4c39 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -3796,6 +3796,18 @@ cmd_pipeline_table_rule_delete_default(char **tokens,
 }
 
 /**
+ * pipeline <pipeline_name> table <table_id> rule read stats [clear]
+ */
+static void
+cmd_pipeline_table_rule_stats_read(char **tokens,
+	uint32_t n_tokens __rte_unused,
+	char *out,
+	size_t out_size)
+{
+	snprintf(out, out_size, MSG_CMD_UNIMPLEM, tokens[0]);
+}
+
+/**
  * thread <thread_id> pipeline <pipeline_name> enable
  */
 static void
@@ -4094,6 +4106,16 @@ cli_process(char *in, char *out, size_t out_size)
 				out, out_size);
 			return;
 		}
+
+		if ((n_tokens >= 7) &&
+			(strcmp(tokens[2], "table") == 0) &&
+			(strcmp(tokens[4], "rule") == 0) &&
+			(strcmp(tokens[5], "read") == 0) &&
+			(strcmp(tokens[6], "stats") == 0)) {
+			cmd_pipeline_table_rule_stats_read(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
 	}
 
 	if (strcmp(tokens[0], "thread") == 0) {
diff --git a/examples/ip_pipeline/pipeline.h b/examples/ip_pipeline/pipeline.h
index 37d1c7a..e609538 100644
--- a/examples/ip_pipeline/pipeline.h
+++ b/examples/ip_pipeline/pipeline.h
@@ -325,4 +325,11 @@ int
 pipeline_table_rule_delete_default(const char *pipeline_name,
 	uint32_t table_id);
 
+int
+pipeline_table_rule_stats_read(const char *pipeline_name,
+	uint32_t table_id,
+	void *data,
+	struct rte_table_action_stats_counters *stats,
+	int clear);
+
 #endif /* _INCLUDE_PIPELINE_H_ */
diff --git a/examples/ip_pipeline/thread.c b/examples/ip_pipeline/thread.c
index 3f5e15e..1cc44ce 100644
--- a/examples/ip_pipeline/thread.c
+++ b/examples/ip_pipeline/thread.c
@@ -493,6 +493,7 @@ enum pipeline_req_type {
 	PIPELINE_REQ_TABLE_RULE_ADD_BULK,
 	PIPELINE_REQ_TABLE_RULE_DELETE,
 	PIPELINE_REQ_TABLE_RULE_DELETE_DEFAULT,
+	PIPELINE_REQ_TABLE_RULE_STATS_READ,
 	PIPELINE_REQ_MAX
 };
 
@@ -529,6 +530,11 @@ struct pipeline_msg_req_table_rule_delete {
 	struct table_rule_match match;
 };
 
+struct pipeline_msg_req_table_rule_stats_read {
+	void *data;
+	int clear;
+};
+
 struct pipeline_msg_req {
 	enum pipeline_req_type type;
 	uint32_t id; /* Port IN, port OUT or table ID */
@@ -542,6 +548,7 @@ struct pipeline_msg_req {
 		struct pipeline_msg_req_table_rule_add_default table_rule_add_default;
 		struct pipeline_msg_req_table_rule_add_bulk table_rule_add_bulk;
 		struct pipeline_msg_req_table_rule_delete table_rule_delete;
+		struct pipeline_msg_req_table_rule_stats_read table_rule_stats_read;
 	};
 };
 
@@ -569,6 +576,10 @@ struct pipeline_msg_rsp_table_rule_add_bulk {
 	uint32_t n_rules;
 };
 
+struct pipeline_msg_rsp_table_rule_stats_read {
+	struct rte_table_action_stats_counters stats;
+};
+
 struct pipeline_msg_rsp {
 	int status;
 
@@ -580,6 +591,7 @@ struct pipeline_msg_rsp {
 		struct pipeline_msg_rsp_table_rule_add table_rule_add;
 		struct pipeline_msg_rsp_table_rule_add_default table_rule_add_default;
 		struct pipeline_msg_rsp_table_rule_add_bulk table_rule_add_bulk;
+		struct pipeline_msg_rsp_table_rule_stats_read table_rule_stats_read;
 	};
 };
 
@@ -1270,6 +1282,57 @@ pipeline_table_rule_delete_default(const char *pipeline_name,
 	return status;
 }
 
+int
+pipeline_table_rule_stats_read(const char *pipeline_name,
+	uint32_t table_id,
+	void *data,
+	struct rte_table_action_stats_counters *stats,
+	int clear)
+{
+	struct pipeline *p;
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if ((pipeline_name == NULL) ||
+		(data == NULL) ||
+		(stats == NULL))
+		return -1;
+
+	p = pipeline_find(pipeline_name);
+	if ((p == NULL) ||
+		(p->enabled == 0) ||
+		(table_id >= p->n_tables))
+		return -1;
+
+	/* Allocate request */
+	req = pipeline_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = PIPELINE_REQ_TABLE_RULE_STATS_READ;
+	req->id = table_id;
+	req->table_rule_stats_read.data = data;
+	req->table_rule_stats_read.clear = clear;
+
+	/* Send request and wait for response */
+	rsp = pipeline_msg_send_recv(p, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+	if (status)
+		memcpy(stats, &rsp->table_rule_stats_read.stats, sizeof(*stats));
+
+	/* Free response */
+	pipeline_msg_free(rsp);
+
+	return status;
+}
+
 /**
  * Data plane threads: message handling
  */
@@ -2052,6 +2115,24 @@ pipeline_msg_handle_table_rule_delete_default(struct pipeline_data *p,
 	return rsp;
 }
 
+static struct pipeline_msg_rsp *
+pipeline_msg_handle_table_rule_stats_read(struct pipeline_data *p,
+	struct pipeline_msg_req *req)
+{
+	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+	uint32_t table_id = req->id;
+	void *data = req->table_rule_stats_read.data;
+	int clear = req->table_rule_stats_read.clear;
+	struct rte_table_action *a = p->table_data[table_id].a;
+
+	rsp->status = rte_table_action_stats_read(a,
+		data,
+		&rsp->table_rule_stats_read.stats,
+		clear);
+
+	return rsp;
+}
+
 static void
 pipeline_msg_handle(struct pipeline_data *p)
 {
@@ -2104,6 +2185,10 @@ pipeline_msg_handle(struct pipeline_data *p)
 			rsp = pipeline_msg_handle_table_rule_delete_default(p, req);
 			break;
 
+		case PIPELINE_REQ_TABLE_RULE_STATS_READ:
+			rsp = pipeline_msg_handle_table_rule_stats_read(p, req);
+			break;
+
 		default:
 			rsp = (struct pipeline_msg_rsp *) req;
 			rsp->status = -1;
-- 
2.9.3

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

* [dpdk-dev] [PATCH v4 39/49] ip_pipeline: add cli to configure meter profile
  2018-03-29 18:31           ` [dpdk-dev] [PATCH v4 00/49] ip_pipeline: refactoring Jasvinder Singh
                               ` (37 preceding siblings ...)
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 38/49] ip_pipeline: add cli to read pipeline table entry stats Jasvinder Singh
@ 2018-03-29 18:31             ` Jasvinder Singh
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 40/49] ip_pipeline: add cli to read meter stats Jasvinder Singh
                               ` (10 subsequent siblings)
  49 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-29 18:31 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add commands to configure the traffic meter profile.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/cli.c      | 232 ++++++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/pipeline.h |  11 ++
 examples/ip_pipeline/thread.c   | 146 +++++++++++++++++++++++++
 3 files changed, 389 insertions(+)

diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index b9a4c39..8aab6fb 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -3808,6 +3808,218 @@ cmd_pipeline_table_rule_stats_read(char **tokens,
 }
 
 /**
+ * pipeline <pipeline_name> table <table_id> meter profile <meter_profile_id>
+ *  add srtcm cir <cir> cbs <cbs> ebs <ebs>
+ *  | trtcm cir <cir> pir <pir> cbs <cbs> pbs <pbs>
+ */
+static void
+cmd_pipeline_table_meter_profile_add(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct rte_table_action_meter_profile p;
+	char *pipeline_name;
+	uint32_t table_id, meter_profile_id;
+	int status;
+
+	if (n_tokens < 9) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "table") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
+		return;
+	}
+
+	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
+		return;
+	}
+
+	if (strcmp(tokens[4], "meter") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
+		return;
+	}
+
+	if (strcmp(tokens[5], "profile") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
+		return;
+	}
+
+	if (parser_read_uint32(&meter_profile_id, tokens[6]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "meter_profile_id");
+		return;
+	}
+
+	if (strcmp(tokens[7], "add") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "add");
+		return;
+	}
+
+	if (strcmp(tokens[8], "srtcm") == 0) {
+		if (n_tokens != 15) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				tokens[0]);
+			return;
+		}
+
+		p.alg = RTE_TABLE_ACTION_METER_SRTCM;
+
+		if (strcmp(tokens[9], "cir") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cir");
+			return;
+		}
+
+		if (parser_read_uint64(&p.srtcm.cir, tokens[10]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "cir");
+			return;
+		}
+
+		if (strcmp(tokens[11], "cbs") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cbs");
+			return;
+		}
+
+		if (parser_read_uint64(&p.srtcm.cbs, tokens[12]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "cbs");
+			return;
+		}
+
+		if (strcmp(tokens[13], "ebs") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "ebs");
+			return;
+		}
+
+		if (parser_read_uint64(&p.srtcm.ebs, tokens[14]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "ebs");
+			return;
+		}
+	} else if (strcmp(tokens[8], "trtcm") == 0) {
+		if (n_tokens != 17) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+			return;
+		}
+
+		p.alg = RTE_TABLE_ACTION_METER_TRTCM;
+
+		if (strcmp(tokens[9], "cir") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cir");
+			return;
+		}
+
+		if (parser_read_uint64(&p.trtcm.cir, tokens[10]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "cir");
+			return;
+		}
+
+		if (strcmp(tokens[11], "pir") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pir");
+			return;
+		}
+
+		if (parser_read_uint64(&p.trtcm.pir, tokens[12]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "pir");
+			return;
+		}
+		if (strcmp(tokens[13], "cbs") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cbs");
+			return;
+		}
+
+		if (parser_read_uint64(&p.trtcm.cbs, tokens[14]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "cbs");
+			return;
+		}
+
+		if (strcmp(tokens[15], "pbs") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pbs");
+			return;
+		}
+
+		if (parser_read_uint64(&p.trtcm.pbs, tokens[16]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "pbs");
+			return;
+		}
+	} else {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	status = pipeline_table_mtr_profile_add(pipeline_name,
+		table_id,
+		meter_profile_id,
+		&p);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
+ * pipeline <pipeline_name> table <table_id>
+ *  meter profile <meter_profile_id> delete
+ */
+static void
+cmd_pipeline_table_meter_profile_delete(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	char *pipeline_name;
+	uint32_t table_id, meter_profile_id;
+	int status;
+
+	if (n_tokens != 8) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "table") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
+		return;
+	}
+
+	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
+		return;
+	}
+
+	if (strcmp(tokens[4], "meter") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "meter");
+		return;
+	}
+
+	if (strcmp(tokens[5], "profile") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile");
+		return;
+	}
+
+	if (parser_read_uint32(&meter_profile_id, tokens[6]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "meter_profile_id");
+		return;
+	}
+
+	if (strcmp(tokens[7], "delete") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "delete");
+		return;
+	}
+
+	status = pipeline_table_mtr_profile_delete(pipeline_name,
+		table_id,
+		meter_profile_id);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
  * thread <thread_id> pipeline <pipeline_name> enable
  */
 static void
@@ -4116,6 +4328,26 @@ cli_process(char *in, char *out, size_t out_size)
 				out, out_size);
 			return;
 		}
+
+		if ((n_tokens >= 8) &&
+			(strcmp(tokens[2], "table") == 0) &&
+			(strcmp(tokens[4], "meter") == 0) &&
+			(strcmp(tokens[5], "profile") == 0) &&
+			(strcmp(tokens[7], "add") == 0)) {
+			cmd_pipeline_table_meter_profile_add(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
+
+		if ((n_tokens >= 8) &&
+			(strcmp(tokens[2], "table") == 0) &&
+			(strcmp(tokens[4], "meter") == 0) &&
+			(strcmp(tokens[5], "profile") == 0) &&
+			(strcmp(tokens[7], "delete") == 0)) {
+			cmd_pipeline_table_meter_profile_delete(tokens,
+				n_tokens, out, out_size);
+			return;
+		}
 	}
 
 	if (strcmp(tokens[0], "thread") == 0) {
diff --git a/examples/ip_pipeline/pipeline.h b/examples/ip_pipeline/pipeline.h
index e609538..b8ab1ae 100644
--- a/examples/ip_pipeline/pipeline.h
+++ b/examples/ip_pipeline/pipeline.h
@@ -332,4 +332,15 @@ pipeline_table_rule_stats_read(const char *pipeline_name,
 	struct rte_table_action_stats_counters *stats,
 	int clear);
 
+int
+pipeline_table_mtr_profile_add(const char *pipeline_name,
+	uint32_t table_id,
+	uint32_t meter_profile_id,
+	struct rte_table_action_meter_profile *profile);
+
+int
+pipeline_table_mtr_profile_delete(const char *pipeline_name,
+	uint32_t table_id,
+	uint32_t meter_profile_id);
+
 #endif /* _INCLUDE_PIPELINE_H_ */
diff --git a/examples/ip_pipeline/thread.c b/examples/ip_pipeline/thread.c
index 1cc44ce..41837d5 100644
--- a/examples/ip_pipeline/thread.c
+++ b/examples/ip_pipeline/thread.c
@@ -494,6 +494,8 @@ enum pipeline_req_type {
 	PIPELINE_REQ_TABLE_RULE_DELETE,
 	PIPELINE_REQ_TABLE_RULE_DELETE_DEFAULT,
 	PIPELINE_REQ_TABLE_RULE_STATS_READ,
+	PIPELINE_REQ_TABLE_MTR_PROFILE_ADD,
+	PIPELINE_REQ_TABLE_MTR_PROFILE_DELETE,
 	PIPELINE_REQ_MAX
 };
 
@@ -535,6 +537,15 @@ struct pipeline_msg_req_table_rule_stats_read {
 	int clear;
 };
 
+struct pipeline_msg_req_table_mtr_profile_add {
+	uint32_t meter_profile_id;
+	struct rte_table_action_meter_profile profile;
+};
+
+struct pipeline_msg_req_table_mtr_profile_delete {
+	uint32_t meter_profile_id;
+};
+
 struct pipeline_msg_req {
 	enum pipeline_req_type type;
 	uint32_t id; /* Port IN, port OUT or table ID */
@@ -549,6 +560,8 @@ struct pipeline_msg_req {
 		struct pipeline_msg_req_table_rule_add_bulk table_rule_add_bulk;
 		struct pipeline_msg_req_table_rule_delete table_rule_delete;
 		struct pipeline_msg_req_table_rule_stats_read table_rule_stats_read;
+		struct pipeline_msg_req_table_mtr_profile_add table_mtr_profile_add;
+		struct pipeline_msg_req_table_mtr_profile_delete table_mtr_profile_delete;
 	};
 };
 
@@ -1333,6 +1346,97 @@ pipeline_table_rule_stats_read(const char *pipeline_name,
 	return status;
 }
 
+int
+pipeline_table_mtr_profile_add(const char *pipeline_name,
+	uint32_t table_id,
+	uint32_t meter_profile_id,
+	struct rte_table_action_meter_profile *profile)
+{
+	struct pipeline *p;
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if ((pipeline_name == NULL) ||
+		(profile == NULL))
+		return -1;
+
+	p = pipeline_find(pipeline_name);
+	if ((p == NULL) ||
+		(p->enabled == 0) ||
+		(table_id >= p->n_tables))
+		return -1;
+
+	/* Allocate request */
+	req = pipeline_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = PIPELINE_REQ_TABLE_MTR_PROFILE_ADD;
+	req->id = table_id;
+	req->table_mtr_profile_add.meter_profile_id = meter_profile_id;
+	memcpy(&req->table_mtr_profile_add.profile, profile, sizeof(*profile));
+
+	/* Send request and wait for response */
+	rsp = pipeline_msg_send_recv(p, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+
+	/* Free response */
+	pipeline_msg_free(rsp);
+
+	return status;
+}
+
+int
+pipeline_table_mtr_profile_delete(const char *pipeline_name,
+	uint32_t table_id,
+	uint32_t meter_profile_id)
+{
+	struct pipeline *p;
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if (pipeline_name == NULL)
+		return -1;
+
+	p = pipeline_find(pipeline_name);
+	if ((p == NULL) ||
+		(p->enabled == 0) ||
+		(table_id >= p->n_tables))
+		return -1;
+
+	/* Allocate request */
+	req = pipeline_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = PIPELINE_REQ_TABLE_MTR_PROFILE_DELETE;
+	req->id = table_id;
+	req->table_mtr_profile_delete.meter_profile_id = meter_profile_id;
+
+	/* Send request and wait for response */
+	rsp = pipeline_msg_send_recv(p, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+
+	/* Free response */
+	pipeline_msg_free(rsp);
+
+	return status;
+}
+
 /**
  * Data plane threads: message handling
  */
@@ -2133,6 +2237,40 @@ pipeline_msg_handle_table_rule_stats_read(struct pipeline_data *p,
 	return rsp;
 }
 
+static struct pipeline_msg_rsp *
+pipeline_msg_handle_table_mtr_profile_add(struct pipeline_data *p,
+	struct pipeline_msg_req *req)
+{
+	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+	uint32_t table_id = req->id;
+	uint32_t meter_profile_id = req->table_mtr_profile_add.meter_profile_id;
+	struct rte_table_action_meter_profile *profile =
+		&req->table_mtr_profile_add.profile;
+	struct rte_table_action *a = p->table_data[table_id].a;
+
+	rsp->status = rte_table_action_meter_profile_add(a,
+		meter_profile_id,
+		profile);
+
+	return rsp;
+}
+
+static struct pipeline_msg_rsp *
+pipeline_msg_handle_table_mtr_profile_delete(struct pipeline_data *p,
+	struct pipeline_msg_req *req)
+{
+	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+	uint32_t table_id = req->id;
+	uint32_t meter_profile_id =
+		req->table_mtr_profile_delete.meter_profile_id;
+	struct rte_table_action *a = p->table_data[table_id].a;
+
+	rsp->status = rte_table_action_meter_profile_delete(a,
+		meter_profile_id);
+
+	return rsp;
+}
+
 static void
 pipeline_msg_handle(struct pipeline_data *p)
 {
@@ -2189,6 +2327,14 @@ pipeline_msg_handle(struct pipeline_data *p)
 			rsp = pipeline_msg_handle_table_rule_stats_read(p, req);
 			break;
 
+		case PIPELINE_REQ_TABLE_MTR_PROFILE_ADD:
+			rsp = pipeline_msg_handle_table_mtr_profile_add(p, req);
+			break;
+
+		case PIPELINE_REQ_TABLE_MTR_PROFILE_DELETE:
+			rsp = pipeline_msg_handle_table_mtr_profile_delete(p, req);
+			break;
+
 		default:
 			rsp = (struct pipeline_msg_rsp *) req;
 			rsp->status = -1;
-- 
2.9.3

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

* [dpdk-dev] [PATCH v4 40/49] ip_pipeline: add cli to read meter stats
  2018-03-29 18:31           ` [dpdk-dev] [PATCH v4 00/49] ip_pipeline: refactoring Jasvinder Singh
                               ` (38 preceding siblings ...)
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 39/49] ip_pipeline: add cli to configure meter profile Jasvinder Singh
@ 2018-03-29 18:31             ` Jasvinder Singh
  2018-03-29 18:32             ` [dpdk-dev] [PATCH v4 41/49] ip_pipeline: add cli to update dscp table Jasvinder Singh
                               ` (9 subsequent siblings)
  49 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-29 18:31 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add command to read traffic meter stats.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/cli.c      | 22 ++++++++++
 examples/ip_pipeline/pipeline.h |  8 ++++
 examples/ip_pipeline/thread.c   | 89 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 119 insertions(+)

diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index 8aab6fb..34de526 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -4020,6 +4020,18 @@ cmd_pipeline_table_meter_profile_delete(char **tokens,
 }
 
 /**
+ * pipeline <pipeline_name> table <table_id> rule read meter [clear]
+ */
+static void
+cmd_pipeline_table_rule_meter_read(char **tokens,
+	uint32_t n_tokens __rte_unused,
+	char *out,
+	size_t out_size)
+{
+	snprintf(out, out_size, MSG_CMD_UNIMPLEM, tokens[0]);
+}
+
+/**
  * thread <thread_id> pipeline <pipeline_name> enable
  */
 static void
@@ -4348,6 +4360,16 @@ cli_process(char *in, char *out, size_t out_size)
 				n_tokens, out, out_size);
 			return;
 		}
+
+		if ((n_tokens >= 7) &&
+			(strcmp(tokens[2], "table") == 0) &&
+			(strcmp(tokens[4], "rule") == 0) &&
+			(strcmp(tokens[5], "read") == 0) &&
+			(strcmp(tokens[6], "meter") == 0)) {
+			cmd_pipeline_table_rule_meter_read(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
 	}
 
 	if (strcmp(tokens[0], "thread") == 0) {
diff --git a/examples/ip_pipeline/pipeline.h b/examples/ip_pipeline/pipeline.h
index b8ab1ae..c6439ab 100644
--- a/examples/ip_pipeline/pipeline.h
+++ b/examples/ip_pipeline/pipeline.h
@@ -343,4 +343,12 @@ pipeline_table_mtr_profile_delete(const char *pipeline_name,
 	uint32_t table_id,
 	uint32_t meter_profile_id);
 
+int
+pipeline_table_rule_mtr_read(const char *pipeline_name,
+	uint32_t table_id,
+	void *data,
+	uint32_t tc_mask,
+	struct rte_table_action_mtr_counters *stats,
+	int clear);
+
 #endif /* _INCLUDE_PIPELINE_H_ */
diff --git a/examples/ip_pipeline/thread.c b/examples/ip_pipeline/thread.c
index 41837d5..94f4aea 100644
--- a/examples/ip_pipeline/thread.c
+++ b/examples/ip_pipeline/thread.c
@@ -496,6 +496,7 @@ enum pipeline_req_type {
 	PIPELINE_REQ_TABLE_RULE_STATS_READ,
 	PIPELINE_REQ_TABLE_MTR_PROFILE_ADD,
 	PIPELINE_REQ_TABLE_MTR_PROFILE_DELETE,
+	PIPELINE_REQ_TABLE_RULE_MTR_READ,
 	PIPELINE_REQ_MAX
 };
 
@@ -546,6 +547,11 @@ struct pipeline_msg_req_table_mtr_profile_delete {
 	uint32_t meter_profile_id;
 };
 
+struct pipeline_msg_req_table_rule_mtr_read {
+	void *data;
+	uint32_t tc_mask;
+	int clear;
+};
 struct pipeline_msg_req {
 	enum pipeline_req_type type;
 	uint32_t id; /* Port IN, port OUT or table ID */
@@ -562,6 +568,7 @@ struct pipeline_msg_req {
 		struct pipeline_msg_req_table_rule_stats_read table_rule_stats_read;
 		struct pipeline_msg_req_table_mtr_profile_add table_mtr_profile_add;
 		struct pipeline_msg_req_table_mtr_profile_delete table_mtr_profile_delete;
+		struct pipeline_msg_req_table_rule_mtr_read table_rule_mtr_read;
 	};
 };
 
@@ -593,6 +600,10 @@ struct pipeline_msg_rsp_table_rule_stats_read {
 	struct rte_table_action_stats_counters stats;
 };
 
+struct pipeline_msg_rsp_table_rule_mtr_read {
+	struct rte_table_action_mtr_counters stats;
+};
+
 struct pipeline_msg_rsp {
 	int status;
 
@@ -605,6 +616,7 @@ struct pipeline_msg_rsp {
 		struct pipeline_msg_rsp_table_rule_add_default table_rule_add_default;
 		struct pipeline_msg_rsp_table_rule_add_bulk table_rule_add_bulk;
 		struct pipeline_msg_rsp_table_rule_stats_read table_rule_stats_read;
+		struct pipeline_msg_rsp_table_rule_mtr_read table_rule_mtr_read;
 	};
 };
 
@@ -1437,6 +1449,59 @@ pipeline_table_mtr_profile_delete(const char *pipeline_name,
 	return status;
 }
 
+int
+pipeline_table_rule_mtr_read(const char *pipeline_name,
+	uint32_t table_id,
+	void *data,
+	uint32_t tc_mask,
+	struct rte_table_action_mtr_counters *stats,
+	int clear)
+{
+	struct pipeline *p;
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if ((pipeline_name == NULL) ||
+		(data == NULL) ||
+		(stats == NULL))
+		return -1;
+
+	p = pipeline_find(pipeline_name);
+	if ((p == NULL) ||
+		(p->enabled == 0) ||
+		(table_id >= p->n_tables))
+		return -1;
+
+	/* Allocate request */
+	req = pipeline_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = PIPELINE_REQ_TABLE_RULE_MTR_READ;
+	req->id = table_id;
+	req->table_rule_mtr_read.data = data;
+	req->table_rule_mtr_read.tc_mask = tc_mask;
+	req->table_rule_mtr_read.clear = clear;
+
+	/* Send request and wait for response */
+	rsp = pipeline_msg_send_recv(p, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+	if (status)
+		memcpy(stats, &rsp->table_rule_mtr_read.stats, sizeof(*stats));
+
+	/* Free response */
+	pipeline_msg_free(rsp);
+
+	return status;
+}
+
 /**
  * Data plane threads: message handling
  */
@@ -2271,6 +2336,26 @@ pipeline_msg_handle_table_mtr_profile_delete(struct pipeline_data *p,
 	return rsp;
 }
 
+static struct pipeline_msg_rsp *
+pipeline_msg_handle_table_rule_mtr_read(struct pipeline_data *p,
+	struct pipeline_msg_req *req)
+{
+	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+	uint32_t table_id = req->id;
+	void *data = req->table_rule_mtr_read.data;
+	uint32_t tc_mask = req->table_rule_mtr_read.tc_mask;
+	int clear = req->table_rule_mtr_read.clear;
+	struct rte_table_action *a = p->table_data[table_id].a;
+
+	rsp->status = rte_table_action_meter_read(a,
+		data,
+		tc_mask,
+		&rsp->table_rule_mtr_read.stats,
+		clear);
+
+	return rsp;
+}
+
 static void
 pipeline_msg_handle(struct pipeline_data *p)
 {
@@ -2335,6 +2420,10 @@ pipeline_msg_handle(struct pipeline_data *p)
 			rsp = pipeline_msg_handle_table_mtr_profile_delete(p, req);
 			break;
 
+		case PIPELINE_REQ_TABLE_RULE_MTR_READ:
+			rsp = pipeline_msg_handle_table_rule_mtr_read(p, req);
+			break;
+
 		default:
 			rsp = (struct pipeline_msg_rsp *) req;
 			rsp->status = -1;
-- 
2.9.3

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

* [dpdk-dev] [PATCH v4 41/49] ip_pipeline: add cli to update dscp table
  2018-03-29 18:31           ` [dpdk-dev] [PATCH v4 00/49] ip_pipeline: refactoring Jasvinder Singh
                               ` (39 preceding siblings ...)
  2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 40/49] ip_pipeline: add cli to read meter stats Jasvinder Singh
@ 2018-03-29 18:32             ` Jasvinder Singh
  2018-03-29 18:32             ` [dpdk-dev] [PATCH v4 42/49] ip_pipeline: add cli to read ttl stats Jasvinder Singh
                               ` (8 subsequent siblings)
  49 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-29 18:32 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add command to update the dscp table for traffic meter and traffic
manager.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/cli.c      | 154 ++++++++++++++++++++++++++++++++++++++++
 examples/ip_pipeline/pipeline.h |   6 ++
 examples/ip_pipeline/thread.c   |  78 ++++++++++++++++++++
 3 files changed, 238 insertions(+)

diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index 34de526..b77f795 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -4032,6 +4032,152 @@ cmd_pipeline_table_rule_meter_read(char **tokens,
 }
 
 /**
+ * pipeline <pipeline_name> table <table_id> dscp <file_name>
+ *
+ * File <file_name>:
+ *  - exactly 64 lines
+ *  - line format: <tc_id> <tc_queue_id> <color>, with <color> as: g | y | r
+ */
+static int
+load_dscp_table(struct rte_table_action_dscp_table *dscp_table,
+	const char *file_name,
+	uint32_t *line_number)
+{
+	FILE *f = NULL;
+	uint32_t dscp, l;
+
+	/* Check input arguments */
+	if ((dscp_table == NULL) ||
+		(file_name == NULL) ||
+		(line_number == NULL)) {
+		if (line_number)
+			*line_number = 0;
+		return -EINVAL;
+	}
+
+	/* Open input file */
+	f = fopen(file_name, "r");
+	if (f == NULL) {
+		*line_number = 0;
+		return -EINVAL;
+	}
+
+	/* Read file */
+	for (dscp = 0, l = 1; ; l++) {
+		char line[64];
+		char *tokens[3];
+		enum rte_meter_color color;
+		uint32_t tc_id, tc_queue_id, n_tokens = RTE_DIM(tokens);
+
+		if (fgets(line, sizeof(line), f) == NULL)
+			break;
+
+		if (is_comment(line))
+			continue;
+
+		if (parse_tokenize_string(line, tokens, &n_tokens)) {
+			*line_number = l;
+			return -EINVAL;
+		}
+
+		if (n_tokens == 0)
+			continue;
+
+		if ((dscp >= RTE_DIM(dscp_table->entry)) ||
+			(n_tokens != RTE_DIM(tokens)) ||
+			parser_read_uint32(&tc_id, tokens[0]) ||
+			(tc_id >= RTE_TABLE_ACTION_TC_MAX) ||
+			parser_read_uint32(&tc_queue_id, tokens[1]) ||
+			(tc_queue_id >= RTE_TABLE_ACTION_TC_QUEUE_MAX) ||
+			(strlen(tokens[2]) != 1)) {
+			*line_number = l;
+			return -EINVAL;
+		}
+
+		switch (tokens[2][0]) {
+		case 'g':
+		case 'G':
+			color = e_RTE_METER_GREEN;
+			break;
+
+		case 'y':
+		case 'Y':
+			color = e_RTE_METER_YELLOW;
+			break;
+
+		case 'r':
+		case 'R':
+			color = e_RTE_METER_RED;
+			break;
+
+		default:
+			*line_number = l;
+			return -EINVAL;
+		}
+
+		dscp_table->entry[dscp].tc_id = tc_id;
+		dscp_table->entry[dscp].tc_queue_id = tc_queue_id;
+		dscp_table->entry[dscp].color = color;
+		dscp++;
+	}
+
+	/* Close file */
+	fclose(f);
+	return 0;
+}
+
+static void
+cmd_pipeline_table_dscp(char **tokens,
+	uint32_t n_tokens,
+	char *out,
+	size_t out_size)
+{
+	struct rte_table_action_dscp_table dscp_table;
+	char *pipeline_name, *file_name;
+	uint32_t table_id, line_number;
+	int status;
+
+	if (n_tokens != 6) {
+		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
+		return;
+	}
+
+	pipeline_name = tokens[1];
+
+	if (strcmp(tokens[2], "table") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port");
+		return;
+	}
+
+	if (parser_read_uint32(&table_id, tokens[3]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "table_id");
+		return;
+	}
+
+	if (strcmp(tokens[4], "dscp") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "dscp");
+		return;
+	}
+
+	file_name = tokens[5];
+
+	status = load_dscp_table(&dscp_table, file_name, &line_number);
+	if (status) {
+		snprintf(out, out_size, MSG_FILE_ERR, file_name, line_number);
+		return;
+	}
+
+	status = pipeline_table_dscp_table_update(pipeline_name,
+		table_id,
+		UINT64_MAX,
+		&dscp_table);
+	if (status) {
+		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
+		return;
+	}
+}
+
+/**
  * thread <thread_id> pipeline <pipeline_name> enable
  */
 static void
@@ -4370,6 +4516,14 @@ cli_process(char *in, char *out, size_t out_size)
 				out, out_size);
 			return;
 		}
+
+		if ((n_tokens >= 5) &&
+			(strcmp(tokens[2], "table") == 0) &&
+			(strcmp(tokens[4], "dscp") == 0)) {
+			cmd_pipeline_table_dscp(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
 	}
 
 	if (strcmp(tokens[0], "thread") == 0) {
diff --git a/examples/ip_pipeline/pipeline.h b/examples/ip_pipeline/pipeline.h
index c6439ab..3b985ba 100644
--- a/examples/ip_pipeline/pipeline.h
+++ b/examples/ip_pipeline/pipeline.h
@@ -351,4 +351,10 @@ pipeline_table_rule_mtr_read(const char *pipeline_name,
 	struct rte_table_action_mtr_counters *stats,
 	int clear);
 
+int
+pipeline_table_dscp_table_update(const char *pipeline_name,
+	uint32_t table_id,
+	uint64_t dscp_mask,
+	struct rte_table_action_dscp_table *dscp_table);
+
 #endif /* _INCLUDE_PIPELINE_H_ */
diff --git a/examples/ip_pipeline/thread.c b/examples/ip_pipeline/thread.c
index 94f4aea..8ce0dd7 100644
--- a/examples/ip_pipeline/thread.c
+++ b/examples/ip_pipeline/thread.c
@@ -497,6 +497,7 @@ enum pipeline_req_type {
 	PIPELINE_REQ_TABLE_MTR_PROFILE_ADD,
 	PIPELINE_REQ_TABLE_MTR_PROFILE_DELETE,
 	PIPELINE_REQ_TABLE_RULE_MTR_READ,
+	PIPELINE_REQ_TABLE_DSCP_TABLE_UPDATE,
 	PIPELINE_REQ_MAX
 };
 
@@ -552,6 +553,12 @@ struct pipeline_msg_req_table_rule_mtr_read {
 	uint32_t tc_mask;
 	int clear;
 };
+
+struct pipeline_msg_req_table_dscp_table_update {
+	uint64_t dscp_mask;
+	struct rte_table_action_dscp_table dscp_table;
+};
+
 struct pipeline_msg_req {
 	enum pipeline_req_type type;
 	uint32_t id; /* Port IN, port OUT or table ID */
@@ -569,6 +576,7 @@ struct pipeline_msg_req {
 		struct pipeline_msg_req_table_mtr_profile_add table_mtr_profile_add;
 		struct pipeline_msg_req_table_mtr_profile_delete table_mtr_profile_delete;
 		struct pipeline_msg_req_table_rule_mtr_read table_rule_mtr_read;
+		struct pipeline_msg_req_table_dscp_table_update table_dscp_table_update;
 	};
 };
 
@@ -1502,6 +1510,54 @@ pipeline_table_rule_mtr_read(const char *pipeline_name,
 	return status;
 }
 
+int
+pipeline_table_dscp_table_update(const char *pipeline_name,
+	uint32_t table_id,
+	uint64_t dscp_mask,
+	struct rte_table_action_dscp_table *dscp_table)
+{
+	struct pipeline *p;
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if ((pipeline_name == NULL) ||
+		(dscp_table == NULL))
+		return -1;
+
+	p = pipeline_find(pipeline_name);
+	if ((p == NULL) ||
+		(p->enabled == 0) ||
+		(table_id >= p->n_tables))
+		return -1;
+
+	/* Allocate request */
+	req = pipeline_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = PIPELINE_REQ_TABLE_DSCP_TABLE_UPDATE;
+	req->id = table_id;
+	req->table_dscp_table_update.dscp_mask = dscp_mask;
+	memcpy(&req->table_dscp_table_update.dscp_table,
+		dscp_table, sizeof(*dscp_table));
+
+	/* Send request and wait for response */
+	rsp = pipeline_msg_send_recv(p, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+
+	/* Free response */
+	pipeline_msg_free(rsp);
+
+	return status;
+}
+
 /**
  * Data plane threads: message handling
  */
@@ -2356,6 +2412,24 @@ pipeline_msg_handle_table_rule_mtr_read(struct pipeline_data *p,
 	return rsp;
 }
 
+static struct pipeline_msg_rsp *
+pipeline_msg_handle_table_dscp_table_update(struct pipeline_data *p,
+	struct pipeline_msg_req *req)
+{
+	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+	uint32_t table_id = req->id;
+	uint64_t dscp_mask = req->table_dscp_table_update.dscp_mask;
+	struct rte_table_action_dscp_table *dscp_table =
+		&req->table_dscp_table_update.dscp_table;
+	struct rte_table_action *a = p->table_data[table_id].a;
+
+	rsp->status = rte_table_action_dscp_table_update(a,
+		dscp_mask,
+		dscp_table);
+
+	return rsp;
+}
+
 static void
 pipeline_msg_handle(struct pipeline_data *p)
 {
@@ -2424,6 +2498,10 @@ pipeline_msg_handle(struct pipeline_data *p)
 			rsp = pipeline_msg_handle_table_rule_mtr_read(p, req);
 			break;
 
+		case PIPELINE_REQ_TABLE_DSCP_TABLE_UPDATE:
+			rsp = pipeline_msg_handle_table_dscp_table_update(p, req);
+			break;
+
 		default:
 			rsp = (struct pipeline_msg_rsp *) req;
 			rsp->status = -1;
-- 
2.9.3

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

* [dpdk-dev] [PATCH v4 42/49] ip_pipeline: add cli to read ttl stats
  2018-03-29 18:31           ` [dpdk-dev] [PATCH v4 00/49] ip_pipeline: refactoring Jasvinder Singh
                               ` (40 preceding siblings ...)
  2018-03-29 18:32             ` [dpdk-dev] [PATCH v4 41/49] ip_pipeline: add cli to update dscp table Jasvinder Singh
@ 2018-03-29 18:32             ` Jasvinder Singh
  2018-03-29 18:32             ` [dpdk-dev] [PATCH v4 43/49] ip_pipeline: add cli for load balance action Jasvinder Singh
                               ` (7 subsequent siblings)
  49 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-29 18:32 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add command to read the ttl stats.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/cli.c      | 22 +++++++++++
 examples/ip_pipeline/pipeline.h |  7 ++++
 examples/ip_pipeline/thread.c   | 85 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 114 insertions(+)

diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index b77f795..6f51d92 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -4178,6 +4178,18 @@ cmd_pipeline_table_dscp(char **tokens,
 }
 
 /**
+ * pipeline <pipeline_name> table <table_id> rule read ttl [clear]
+ */
+static void
+cmd_pipeline_table_rule_ttl_read(char **tokens,
+	uint32_t n_tokens __rte_unused,
+	char *out,
+	size_t out_size)
+{
+	snprintf(out, out_size, MSG_CMD_UNIMPLEM, tokens[0]);
+}
+
+/**
  * thread <thread_id> pipeline <pipeline_name> enable
  */
 static void
@@ -4524,6 +4536,16 @@ cli_process(char *in, char *out, size_t out_size)
 				out, out_size);
 			return;
 		}
+
+		if ((n_tokens >= 7) &&
+			(strcmp(tokens[2], "table") == 0) &&
+			(strcmp(tokens[4], "rule") == 0) &&
+			(strcmp(tokens[5], "read") == 0) &&
+			(strcmp(tokens[6], "ttl") == 0)) {
+			cmd_pipeline_table_rule_ttl_read(tokens, n_tokens,
+				out, out_size);
+			return;
+		}
 	}
 
 	if (strcmp(tokens[0], "thread") == 0) {
diff --git a/examples/ip_pipeline/pipeline.h b/examples/ip_pipeline/pipeline.h
index 3b985ba..50aecab 100644
--- a/examples/ip_pipeline/pipeline.h
+++ b/examples/ip_pipeline/pipeline.h
@@ -357,4 +357,11 @@ pipeline_table_dscp_table_update(const char *pipeline_name,
 	uint64_t dscp_mask,
 	struct rte_table_action_dscp_table *dscp_table);
 
+int
+pipeline_table_rule_ttl_read(const char *pipeline_name,
+	uint32_t table_id,
+	void *data,
+	struct rte_table_action_ttl_counters *stats,
+	int clear);
+
 #endif /* _INCLUDE_PIPELINE_H_ */
diff --git a/examples/ip_pipeline/thread.c b/examples/ip_pipeline/thread.c
index 8ce0dd7..8728db9 100644
--- a/examples/ip_pipeline/thread.c
+++ b/examples/ip_pipeline/thread.c
@@ -498,6 +498,7 @@ enum pipeline_req_type {
 	PIPELINE_REQ_TABLE_MTR_PROFILE_DELETE,
 	PIPELINE_REQ_TABLE_RULE_MTR_READ,
 	PIPELINE_REQ_TABLE_DSCP_TABLE_UPDATE,
+	PIPELINE_REQ_TABLE_RULE_TTL_READ,
 	PIPELINE_REQ_MAX
 };
 
@@ -559,6 +560,11 @@ struct pipeline_msg_req_table_dscp_table_update {
 	struct rte_table_action_dscp_table dscp_table;
 };
 
+struct pipeline_msg_req_table_rule_ttl_read {
+	void *data;
+	int clear;
+};
+
 struct pipeline_msg_req {
 	enum pipeline_req_type type;
 	uint32_t id; /* Port IN, port OUT or table ID */
@@ -577,6 +583,7 @@ struct pipeline_msg_req {
 		struct pipeline_msg_req_table_mtr_profile_delete table_mtr_profile_delete;
 		struct pipeline_msg_req_table_rule_mtr_read table_rule_mtr_read;
 		struct pipeline_msg_req_table_dscp_table_update table_dscp_table_update;
+		struct pipeline_msg_req_table_rule_ttl_read table_rule_ttl_read;
 	};
 };
 
@@ -612,6 +619,10 @@ struct pipeline_msg_rsp_table_rule_mtr_read {
 	struct rte_table_action_mtr_counters stats;
 };
 
+struct pipeline_msg_rsp_table_rule_ttl_read {
+	struct rte_table_action_ttl_counters stats;
+};
+
 struct pipeline_msg_rsp {
 	int status;
 
@@ -625,6 +636,7 @@ struct pipeline_msg_rsp {
 		struct pipeline_msg_rsp_table_rule_add_bulk table_rule_add_bulk;
 		struct pipeline_msg_rsp_table_rule_stats_read table_rule_stats_read;
 		struct pipeline_msg_rsp_table_rule_mtr_read table_rule_mtr_read;
+		struct pipeline_msg_rsp_table_rule_ttl_read table_rule_ttl_read;
 	};
 };
 
@@ -1558,6 +1570,57 @@ pipeline_table_dscp_table_update(const char *pipeline_name,
 	return status;
 }
 
+int
+pipeline_table_rule_ttl_read(const char *pipeline_name,
+	uint32_t table_id,
+	void *data,
+	struct rte_table_action_ttl_counters *stats,
+	int clear)
+{
+	struct pipeline *p;
+	struct pipeline_msg_req *req;
+	struct pipeline_msg_rsp *rsp;
+	int status;
+
+	/* Check input params */
+	if ((pipeline_name == NULL) ||
+		(data == NULL) ||
+		(stats == NULL))
+		return -1;
+
+	p = pipeline_find(pipeline_name);
+	if ((p == NULL) ||
+		(p->enabled == 0) ||
+		(table_id >= p->n_tables))
+		return -1;
+
+	/* Allocate request */
+	req = pipeline_msg_alloc();
+	if (req == NULL)
+		return -1;
+
+	/* Write request */
+	req->type = PIPELINE_REQ_TABLE_RULE_TTL_READ;
+	req->id = table_id;
+	req->table_rule_ttl_read.data = data;
+	req->table_rule_ttl_read.clear = clear;
+
+	/* Send request and wait for response */
+	rsp = pipeline_msg_send_recv(p, req);
+	if (rsp == NULL)
+		return -1;
+
+	/* Read response */
+	status = rsp->status;
+	if (status)
+		memcpy(stats, &rsp->table_rule_ttl_read.stats, sizeof(*stats));
+
+	/* Free response */
+	pipeline_msg_free(rsp);
+
+	return status;
+}
+
 /**
  * Data plane threads: message handling
  */
@@ -2430,6 +2493,24 @@ pipeline_msg_handle_table_dscp_table_update(struct pipeline_data *p,
 	return rsp;
 }
 
+static struct pipeline_msg_rsp *
+pipeline_msg_handle_table_rule_ttl_read(struct pipeline_data *p,
+	struct pipeline_msg_req *req)
+{
+	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *) req;
+	uint32_t table_id = req->id;
+	void *data = req->table_rule_ttl_read.data;
+	int clear = req->table_rule_ttl_read.clear;
+	struct rte_table_action *a = p->table_data[table_id].a;
+
+	rsp->status = rte_table_action_ttl_read(a,
+		data,
+		&rsp->table_rule_ttl_read.stats,
+		clear);
+
+	return rsp;
+}
+
 static void
 pipeline_msg_handle(struct pipeline_data *p)
 {
@@ -2502,6 +2583,10 @@ pipeline_msg_handle(struct pipeline_data *p)
 			rsp = pipeline_msg_handle_table_dscp_table_update(p, req);
 			break;
 
+		case PIPELINE_REQ_TABLE_RULE_TTL_READ:
+			rsp = pipeline_msg_handle_table_rule_ttl_read(p, req);
+			break;
+
 		default:
 			rsp = (struct pipeline_msg_rsp *) req;
 			rsp->status = -1;
-- 
2.9.3

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

* [dpdk-dev] [PATCH v4 43/49] ip_pipeline: add cli for load balance action
  2018-03-29 18:31           ` [dpdk-dev] [PATCH v4 00/49] ip_pipeline: refactoring Jasvinder Singh
                               ` (41 preceding siblings ...)
  2018-03-29 18:32             ` [dpdk-dev] [PATCH v4 42/49] ip_pipeline: add cli to read ttl stats Jasvinder Singh
@ 2018-03-29 18:32             ` Jasvinder Singh
  2018-03-29 18:32             ` [dpdk-dev] [PATCH v4 44/49] ip_pipeline: add l2fwd example Jasvinder Singh
                               ` (6 subsequent siblings)
  49 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-29 18:32 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add command for load balance action.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/action.c   | 11 ++++++
 examples/ip_pipeline/action.h   |  1 +
 examples/ip_pipeline/cli.c      | 84 ++++++++++++++++++++++++++++++++++++++++-
 examples/ip_pipeline/pipeline.h |  1 +
 examples/ip_pipeline/thread.c   | 22 +++++++++++
 5 files changed, 118 insertions(+), 1 deletion(-)

diff --git a/examples/ip_pipeline/action.c b/examples/ip_pipeline/action.c
index 9db6dba..1659876 100644
--- a/examples/ip_pipeline/action.c
+++ b/examples/ip_pipeline/action.c
@@ -177,6 +177,17 @@ table_action_profile_create(const char *name,
 		}
 	}
 
+	if (params->action_mask & (1LLU << RTE_TABLE_ACTION_LB)) {
+		status = rte_table_action_profile_action_register(ap,
+			RTE_TABLE_ACTION_LB,
+			&params->lb);
+
+		if (status) {
+			rte_table_action_profile_free(ap);
+			return NULL;
+		}
+	}
+
 	if (params->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) {
 		status = rte_table_action_profile_action_register(ap,
 			RTE_TABLE_ACTION_MTR,
diff --git a/examples/ip_pipeline/action.h b/examples/ip_pipeline/action.h
index 98b5032..417200e 100644
--- a/examples/ip_pipeline/action.h
+++ b/examples/ip_pipeline/action.h
@@ -46,6 +46,7 @@ port_in_action_profile_create(const char *name,
 struct table_action_profile_params {
 	uint64_t action_mask;
 	struct rte_table_action_common_config common;
+	struct rte_table_action_lb_config lb;
 	struct rte_table_action_mtr_config mtr;
 	struct rte_table_action_tm_config tm;
 	struct rte_table_action_encap_config encap;
diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index 6f51d92..22c7f5a 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -805,7 +805,8 @@ cmd_port_in_action_profile(char **tokens,
 		uint32_t i;
 
 		if (n_tokens < t0 + 22) {
-			snprintf(out, out_size, MSG_ARG_MISMATCH, "port in action profile balance");
+			snprintf(out, out_size, MSG_ARG_MISMATCH,
+				"port in action profile balance");
 			return;
 		}
 
@@ -862,6 +863,7 @@ cmd_port_in_action_profile(char **tokens,
  *  ipv4 | ipv6
  *  offset <ip_offset>
  *  fwd
+ *  [balance offset <key_offset> mask <key_mask> outoffset <out_offset>]
  *  [meter srtcm | trtcm
  *      tc <n_tc>
  *      stats none | pkts | bytes | both]
@@ -931,6 +933,47 @@ cmd_table_action_profile(char **tokens,
 	p.action_mask |= 1LLU << RTE_TABLE_ACTION_FWD;
 
 	t0 = 8;
+	if ((t0 < n_tokens) && (strcmp(tokens[t0], "balance") == 0)) {
+		if (n_tokens < t0 + 7) {
+			snprintf(out, out_size, MSG_ARG_MISMATCH, "table action profile balance");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 1], "offset") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset");
+			return;
+		}
+
+		if (parser_read_uint32(&p.lb.key_offset, tokens[t0 + 2]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "key_offset");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 3], "mask") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask");
+			return;
+		}
+
+		p.lb.key_size = RTE_PORT_IN_ACTION_LB_KEY_SIZE_MAX;
+		if (parse_hex_string(tokens[t0 + 4], p.lb.key_mask, &p.lb.key_size) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "key_mask");
+			return;
+		}
+
+		if (strcmp(tokens[t0 + 5], "outoffset") != 0) {
+			snprintf(out, out_size, MSG_ARG_NOT_FOUND, "outoffset");
+			return;
+		}
+
+		if (parser_read_uint32(&p.lb.out_offset, tokens[t0 + 6]) != 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID, "out_offset");
+			return;
+		}
+
+		p.action_mask |= 1LLU << RTE_TABLE_ACTION_LB;
+		t0 += 7;
+	} /* balance */
+
 	if ((t0 < n_tokens) && (strcmp(tokens[t0], "meter") == 0)) {
 		if (n_tokens < t0 + 6) {
 			snprintf(out, out_size, MSG_ARG_MISMATCH,
@@ -2789,6 +2832,31 @@ parse_table_action_fwd(char **tokens,
 	return 0;
 }
 
+static uint32_t
+parse_table_action_balance(char **tokens,
+	uint32_t n_tokens,
+	struct table_rule_action *a)
+{
+	uint32_t i;
+
+	if ((n_tokens == 0) || (strcmp(tokens[0], "balance") != 0))
+		return 0;
+
+	tokens++;
+	n_tokens--;
+
+	if (n_tokens < RTE_TABLE_ACTION_LB_KEY_SIZE_MAX)
+		return 0;
+
+	for (i = 0; i < RTE_TABLE_ACTION_LB_KEY_SIZE_MAX; i++)
+		if (parser_read_uint32(&a->lb.out[i], tokens[i]) != 0)
+			return 0;
+
+	a->action_mask |= 1 << RTE_TABLE_ACTION_LB;
+	return 1 + RTE_TABLE_ACTION_LB_KEY_SIZE_MAX;
+
+}
+
 static int
 parse_policer_action(char *token, enum rte_table_action_policer *a)
 {
@@ -3222,6 +3290,20 @@ parse_table_action(char **tokens,
 		n_tokens -= n;
 	}
 
+	if (n_tokens && (strcmp(tokens[0], "balance") == 0)) {
+		uint32_t n;
+
+		n = parse_table_action_balance(tokens, n_tokens, a);
+		if (n == 0) {
+			snprintf(out, out_size, MSG_ARG_INVALID,
+				"action balance");
+			return 0;
+		}
+
+		tokens += n;
+		n_tokens -= n;
+	}
+
 	if (n_tokens && (strcmp(tokens[0], "meter") == 0)) {
 		uint32_t n;
 
diff --git a/examples/ip_pipeline/pipeline.h b/examples/ip_pipeline/pipeline.h
index 50aecab..a953a29 100644
--- a/examples/ip_pipeline/pipeline.h
+++ b/examples/ip_pipeline/pipeline.h
@@ -260,6 +260,7 @@ struct table_rule_match {
 struct table_rule_action {
 	uint64_t action_mask;
 	struct rte_table_action_fwd_params fwd;
+	struct rte_table_action_lb_params lb;
 	struct rte_table_action_mtr_params mtr;
 	struct rte_table_action_tm_params tm;
 	struct rte_table_action_encap_params encap;
diff --git a/examples/ip_pipeline/thread.c b/examples/ip_pipeline/thread.c
index 8728db9..fa85cf6 100644
--- a/examples/ip_pipeline/thread.c
+++ b/examples/ip_pipeline/thread.c
@@ -2031,6 +2031,18 @@ pipeline_msg_handle_table_rule_add(struct pipeline_data *p,
 		}
 	}
 
+	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_LB)) {
+		status = rte_table_action_apply(a,
+			data_in,
+			RTE_TABLE_ACTION_LB,
+			&action->lb);
+
+		if (status) {
+			rsp->status = -1;
+			return rsp;
+		}
+	}
+
 	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) {
 		status = rte_table_action_apply(a,
 			data_in,
@@ -2243,6 +2255,16 @@ pipeline_msg_handle_table_rule_add_bulk(struct pipeline_data *p,
 				goto fail;
 		}
 
+		if (act->action_mask & (1LLU << RTE_TABLE_ACTION_LB)) {
+			status = rte_table_action_apply(a,
+				data_in,
+				RTE_TABLE_ACTION_LB,
+				&act->lb);
+
+			if (status)
+				goto fail;
+		}
+
 		if (act->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) {
 			status = rte_table_action_apply(a,
 				data_in,
-- 
2.9.3

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

* [dpdk-dev] [PATCH v4 44/49] ip_pipeline: add l2fwd example
  2018-03-29 18:31           ` [dpdk-dev] [PATCH v4 00/49] ip_pipeline: refactoring Jasvinder Singh
                               ` (42 preceding siblings ...)
  2018-03-29 18:32             ` [dpdk-dev] [PATCH v4 43/49] ip_pipeline: add cli for load balance action Jasvinder Singh
@ 2018-03-29 18:32             ` Jasvinder Singh
  2018-03-29 18:32             ` [dpdk-dev] [PATCH v4 45/49] ip_pipeline: add KNI port example Jasvinder Singh
                               ` (5 subsequent siblings)
  49 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-29 18:32 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Kevin Laatz

This patch add the configuration file for l2fwd example. It
includes commands to build the packet processing stage (pipeline),
defining action, add rules to its table, etc.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
---
 examples/ip_pipeline/examples/l2fwd.cli | 51 +++++++++++++++++++++++++++++++++
 1 file changed, 51 insertions(+)
 create mode 100644 examples/ip_pipeline/examples/l2fwd.cli

diff --git a/examples/ip_pipeline/examples/l2fwd.cli b/examples/ip_pipeline/examples/l2fwd.cli
new file mode 100644
index 0000000..35e77cc
--- /dev/null
+++ b/examples/ip_pipeline/examples/l2fwd.cli
@@ -0,0 +1,51 @@
+; SPDX-License-Identifier: BSD-3-Clause
+; Copyright(c) 2010-2018 Intel Corporation
+
+; The pipeline below implements a simple pass-through connection between the
+; input ports to the output ports, as in this diagram:
+;                 ________________
+; LINK0 RXQ0 --->|................|---> LINK1 TXQ0
+;                |                |
+; LINK1 RXQ0 --->|................|---> LINK0 TXQ0
+;                |    PIPELINE0   |
+; LINK2 RXQ0 --->|................|---> LINK3 TXQ0
+;                |                |
+; LINK3 RXQ0 --->|................|---> LINK2 TXQ0
+;                |________________|
+;
+
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+
+link LINK0 dev 0000:02:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+link LINK1 dev 0000:02:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+link LINK2 dev 0000:06:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+link LINK3 dev 0000:06:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+
+pipeline PIPELINE0 period 10 offset_port_id 0 cpu 0
+
+pipeline PIPELINE0 port in bsz 32 link LINK0 rxq 0
+pipeline PIPELINE0 port in bsz 32 link LINK1 rxq 0
+pipeline PIPELINE0 port in bsz 32 link LINK2 rxq 0
+pipeline PIPELINE0 port in bsz 32 link LINK3 rxq 0
+
+pipeline PIPELINE0 port out bsz 32 link LINK0 txq 0
+pipeline PIPELINE0 port out bsz 32 link LINK1 txq 0
+pipeline PIPELINE0 port out bsz 32 link LINK2 txq 0
+pipeline PIPELINE0 port out bsz 32 link LINK3 txq 0
+
+pipeline PIPELINE0 table match stub
+pipeline PIPELINE0 table match stub
+pipeline PIPELINE0 table match stub
+pipeline PIPELINE0 table match stub
+
+pipeline PIPELINE0 port in 0 table 0
+pipeline PIPELINE0 port in 1 table 1
+pipeline PIPELINE0 port in 2 table 2
+pipeline PIPELINE0 port in 3 table 3
+
+thread 1 pipeline PIPELINE0 enable
+
+pipeline PIPELINE0 table 0 rule add match default action fwd port 1
+pipeline PIPELINE0 table 1 rule add match default action fwd port 0
+pipeline PIPELINE0 table 2 rule add match default action fwd port 3
+pipeline PIPELINE0 table 3 rule add match default action fwd port 2
-- 
2.9.3

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

* [dpdk-dev] [PATCH v4 45/49] ip_pipeline: add KNI port example
  2018-03-29 18:31           ` [dpdk-dev] [PATCH v4 00/49] ip_pipeline: refactoring Jasvinder Singh
                               ` (43 preceding siblings ...)
  2018-03-29 18:32             ` [dpdk-dev] [PATCH v4 44/49] ip_pipeline: add l2fwd example Jasvinder Singh
@ 2018-03-29 18:32             ` Jasvinder Singh
  2018-03-29 18:32             ` [dpdk-dev] [PATCH v4 46/49] ip_pipeline: add TAP " Jasvinder Singh
                               ` (4 subsequent siblings)
  49 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-29 18:32 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Kevin Laatz

Add example to illustrate the pipeline functioning with KNI
interface.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
---
 examples/ip_pipeline/examples/kni.cli | 69 +++++++++++++++++++++++++++++++++++
 1 file changed, 69 insertions(+)
 create mode 100644 examples/ip_pipeline/examples/kni.cli

diff --git a/examples/ip_pipeline/examples/kni.cli b/examples/ip_pipeline/examples/kni.cli
new file mode 100644
index 0000000..1438340
--- /dev/null
+++ b/examples/ip_pipeline/examples/kni.cli
@@ -0,0 +1,69 @@
+; SPDX-License-Identifier: BSD-3-Clause
+; Copyright(c) 2010-2018 Intel Corporation
+
+;                 _______________          ______________________
+;                |               |  KNI0  |                      |
+; LINK0 RXQ0 --->|...............|------->|--+                   |
+;                |               |  KNI1  |  | br0               |
+; LINK1 TXQ0 <---|...............|<-------|<-+                   |
+;                |               |        |     Linux Kernel     |
+;                |   PIPELINE0   |        |     Network Stack    |
+;                |               |  KNI1  |                      |
+; LINK1 RXQ0 --->|...............|------->|--+                   |
+;                |               |  KNI0  |  | br0               |
+; LINK0 TXQ0 <---|...............|<-------|<-+                   |
+;                |_______________|        |______________________|
+;
+; Insert Linux kernel KNI module:
+;    [Linux]$ insmod rte_kni.ko
+;
+; Configure Linux kernel bridge between KNI0 and KNI1 interfaces:
+;    [Linux]$ brctl addbr br0
+;    [Linux]$ brctl addif br0 KNI0
+;    [Linux]$ brctl addif br0 KNI1
+;    [Linux]$ ifconfig br0 up
+;    [Linux]$ ifconfig KNI0 up
+;    [Linux]$ ifconfig KNI1 up
+;
+; Monitor packet forwarding performed by Linux kernel between KNI0 and KNI1:
+;    [Linux]$ tcpdump -i KNI0
+;    [Linux]$ tcpdump -i KNI1
+
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+
+link LINK0 dev 0000:02:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+link LINK1 dev 0000:02:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+
+kni KNI0 link LINK0 mempool MEMPOOL0
+kni KNI1 link LINK1 mempool MEMPOOL0
+
+table action profile AP0 ipv4 offset 270 fwd
+
+pipeline PIPELINE0 period 10 offset_port_id 0 cpu 0
+
+pipeline PIPELINE0 port in bsz 32 link LINK0 rxq 0
+pipeline PIPELINE0 port in bsz 32 kni KNI1
+pipeline PIPELINE0 port in bsz 32 link LINK1 rxq 0
+pipeline PIPELINE0 port in bsz 32 kni KNI0
+
+pipeline PIPELINE0 port out bsz 32 kni KNI0
+pipeline PIPELINE0 port out bsz 32 link LINK1 txq 0
+pipeline PIPELINE0 port out bsz 32 kni KNI1
+pipeline PIPELINE0 port out bsz 32 link LINK0 txq 0
+
+pipeline PIPELINE0 table match stub action AP0
+pipeline PIPELINE0 table match stub action AP0
+pipeline PIPELINE0 table match stub action AP0
+pipeline PIPELINE0 table match stub action AP0
+
+pipeline PIPELINE0 port in 0 table 0
+pipeline PIPELINE0 port in 1 table 1
+pipeline PIPELINE0 port in 2 table 2
+pipeline PIPELINE0 port in 3 table 3
+
+thread 1 pipeline PIPELINE0 enable
+
+pipeline PIPELINE0 table 0 rule add match default action fwd port 0
+pipeline PIPELINE0 table 1 rule add match default action fwd port 1
+pipeline PIPELINE0 table 2 rule add match default action fwd port 2
+pipeline PIPELINE0 table 3 rule add match default action fwd port 3
-- 
2.9.3

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

* [dpdk-dev] [PATCH v4 46/49] ip_pipeline: add TAP port example
  2018-03-29 18:31           ` [dpdk-dev] [PATCH v4 00/49] ip_pipeline: refactoring Jasvinder Singh
                               ` (44 preceding siblings ...)
  2018-03-29 18:32             ` [dpdk-dev] [PATCH v4 45/49] ip_pipeline: add KNI port example Jasvinder Singh
@ 2018-03-29 18:32             ` Jasvinder Singh
  2018-03-29 18:32             ` [dpdk-dev] [PATCH v4 47/49] ip_pipeline: add route example Jasvinder Singh
                               ` (3 subsequent siblings)
  49 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-29 18:32 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Kevin Laatz

Add example to illustrate the pipeline functioning with TAP
interface.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Kevin Laatz <kevin.laatz@intel.com>
---
 examples/ip_pipeline/examples/tap.cli | 66 +++++++++++++++++++++++++++++++++++
 1 file changed, 66 insertions(+)
 create mode 100644 examples/ip_pipeline/examples/tap.cli

diff --git a/examples/ip_pipeline/examples/tap.cli b/examples/ip_pipeline/examples/tap.cli
new file mode 100644
index 0000000..600cea2
--- /dev/null
+++ b/examples/ip_pipeline/examples/tap.cli
@@ -0,0 +1,66 @@
+; SPDX-License-Identifier: BSD-3-Clause
+; Copyright(c) 2010-2018 Intel Corporation
+
+;                 _______________          ______________________
+;                |               |  TAP0  |                      |
+; LINK0 RXQ0 --->|...............|------->|--+                   |
+;                |               |  TAP1  |  | br0               |
+; LINK1 TXQ0 <---|...............|<-------|<-+                   |
+;                |               |        |     Linux Kernel     |
+;                |   PIPELINE0   |        |     Network Stack    |
+;                |               |  TAP1  |                      |
+; LINK1 RXQ0 --->|...............|------->|--+                   |
+;                |               |  TAP0  |  | br0               |
+; LINK0 TXQ0 <---|...............|<-------|<-+                   |
+;                |_______________|        |______________________|
+;
+; Configure Linux kernel bridge between TAP0 and TAP1 interfaces:
+;    [Linux]$ brctl addbr br0
+;    [Linux]$ brctl addif br0 TAP0
+;    [Linux]$ brctl addif br0 TAP1
+;    [Linux]$ ifconfig TAP0 up
+;    [Linux]$ ifconfig TAP1 up
+;    [Linux]$ ifconfig br0 up
+;
+; Monitor packet forwarding performed by Linux kernel between TAP0 and TAP1:
+;    [Linux]$ tcpdump -i TAP0
+;    [Linux]$ tcpdump -i TAP1
+
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+
+link LINK0 dev 0000:02:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+link LINK1 dev 0000:02:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+
+tap TAP0
+tap TAP1
+
+table action profile AP0 ipv4 offset 270 fwd
+
+pipeline PIPELINE0 period 10 offset_port_id 0 cpu 0
+
+pipeline PIPELINE0 port in bsz 32 link LINK0 rxq 0
+pipeline PIPELINE0 port in bsz 32 tap TAP1 mempool MEMPOOL0 mtu 1500
+pipeline PIPELINE0 port in bsz 32 link LINK1 rxq 0
+pipeline PIPELINE0 port in bsz 32 tap TAP0 mempool MEMPOOL0 mtu 1500
+
+pipeline PIPELINE0 port out bsz 32 tap TAP0
+pipeline PIPELINE0 port out bsz 32 link LINK1 txq 0
+pipeline PIPELINE0 port out bsz 32 tap TAP1
+pipeline PIPELINE0 port out bsz 32 link LINK0 txq 0
+
+pipeline PIPELINE0 table match stub action AP0
+pipeline PIPELINE0 table match stub action AP0
+pipeline PIPELINE0 table match stub action AP0
+pipeline PIPELINE0 table match stub action AP0
+
+pipeline PIPELINE0 port in 0 table 0
+pipeline PIPELINE0 port in 1 table 1
+pipeline PIPELINE0 port in 2 table 2
+pipeline PIPELINE0 port in 3 table 3
+
+thread 1 pipeline PIPELINE0 enable
+
+pipeline PIPELINE0 table 0 rule add match default action fwd port 0
+pipeline PIPELINE0 table 1 rule add match default action fwd port 1
+pipeline PIPELINE0 table 2 rule add match default action fwd port 2
+pipeline PIPELINE0 table 3 rule add match default action fwd port 3
-- 
2.9.3

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

* [dpdk-dev] [PATCH v4 47/49] ip_pipeline: add route example
  2018-03-29 18:31           ` [dpdk-dev] [PATCH v4 00/49] ip_pipeline: refactoring Jasvinder Singh
                               ` (45 preceding siblings ...)
  2018-03-29 18:32             ` [dpdk-dev] [PATCH v4 46/49] ip_pipeline: add TAP " Jasvinder Singh
@ 2018-03-29 18:32             ` Jasvinder Singh
  2018-03-29 18:32             ` [dpdk-dev] [PATCH v4 48/49] ip_pipeline: add firewall example Jasvinder Singh
                               ` (2 subsequent siblings)
  49 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-29 18:32 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Reshma Pattan

Add example to built pipeline with LPM table to demonstrate layer 3
routing.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Reshma Pattan <reshma.pattan@intel.com>
---
 examples/ip_pipeline/examples/route.cli | 60 +++++++++++++++++++++++++++++++++
 1 file changed, 60 insertions(+)
 create mode 100644 examples/ip_pipeline/examples/route.cli

diff --git a/examples/ip_pipeline/examples/route.cli b/examples/ip_pipeline/examples/route.cli
new file mode 100644
index 0000000..579b36a
--- /dev/null
+++ b/examples/ip_pipeline/examples/route.cli
@@ -0,0 +1,60 @@
+; SPDX-License-Identifier: BSD-3-Clause
+; Copyright(c) 2010-2018 Intel Corporation
+
+;                 _______________
+; LINK0 RXQ0 --->|               |---> LINK0 TXQ0
+;                |               |
+; LINK1 RXQ0 --->|               |---> LINK1 TXQ0
+;                |    Routing    |
+; LINK2 RXQ0 --->|               |---> LINK2 TXQ0
+;                |               |
+; LINK3 RXQ0 --->|               |---> LINK3 TXQ0
+;                |_______________|
+;                        |
+;                        +-----------> SINK0 (route miss)
+;
+; Input packet: Ethernet/IPv4
+;
+; Packet buffer layout:
+; #   Field Name       Offset (Bytes)   Size (Bytes)
+; 0   Mbuf             0                128
+; 1   Headroom         128              128
+; 2   Ethernet header  256              14
+; 3   IPv4 header      270              20
+
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+
+link LINK0 dev 0000:02:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+link LINK1 dev 0000:02:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+link LINK2 dev 0000:06:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+link LINK3 dev 0000:06:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+
+table action profile AP0 ipv4 offset 270 fwd encap ether
+
+pipeline PIPELINE0 period 10 offset_port_id 0 cpu 0
+
+pipeline PIPELINE0 port in bsz 32 link LINK0 rxq 0
+pipeline PIPELINE0 port in bsz 32 link LINK1 rxq 0
+pipeline PIPELINE0 port in bsz 32 link LINK2 rxq 0
+pipeline PIPELINE0 port in bsz 32 link LINK3 rxq 0
+
+pipeline PIPELINE0 port out bsz 32 link LINK0 txq 0
+pipeline PIPELINE0 port out bsz 32 link LINK1 txq 0
+pipeline PIPELINE0 port out bsz 32 link LINK2 txq 0
+pipeline PIPELINE0 port out bsz 32 link LINK3 txq 0
+pipeline PIPELINE0 port out bsz 32 sink
+
+pipeline PIPELINE0 table match lpm ipv4 offset 286 size 4K action AP0
+
+pipeline PIPELINE0 port in 0 table 0
+pipeline PIPELINE0 port in 1 table 0
+pipeline PIPELINE0 port in 2 table 0
+pipeline PIPELINE0 port in 3 table 0
+
+thread 1 pipeline PIPELINE0 enable
+
+pipeline PIPELINE0 table 0 rule add match default action fwd port 4
+pipeline PIPELINE0 table 0 rule add match lpm ipv4 100.0.0.0 10 action fwd port 0 encap ether a0:a1:a2:a3:a4:a5 00:01:02:03:04:05
+pipeline PIPELINE0 table 0 rule add match lpm ipv4 100.64.0.0 10 action fwd port 1 encap ether b0:b1:b2:b3:b4:b5 10:11:12:13:14:15
+pipeline PIPELINE0 table 0 rule add match lpm ipv4 100.128.0.0 10 action fwd port 2 encap ether c0:c1:c2:c3:c4:c5 20:21:22:23:24:25
+pipeline PIPELINE0 table 0 rule add match lpm ipv4 100.192.0.0 10 action fwd port 3 encap ether d0:d1:d2:d3:d4:d5 30:31:32:33:34:35
-- 
2.9.3

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

* [dpdk-dev] [PATCH v4 48/49] ip_pipeline: add firewall example
  2018-03-29 18:31           ` [dpdk-dev] [PATCH v4 00/49] ip_pipeline: refactoring Jasvinder Singh
                               ` (46 preceding siblings ...)
  2018-03-29 18:32             ` [dpdk-dev] [PATCH v4 47/49] ip_pipeline: add route example Jasvinder Singh
@ 2018-03-29 18:32             ` Jasvinder Singh
  2018-03-29 18:32             ` [dpdk-dev] [PATCH v4 49/49] ip_pipeline: add flow classification example Jasvinder Singh
  2018-03-30 12:44             ` [dpdk-dev] [PATCH v4 00/49] ip_pipeline: refactoring Dumitrescu, Cristian
  49 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-29 18:32 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu

Add example to built pipeline with ACL table to demonstrate
the firewall operation.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/examples/firewall.cli | 59 ++++++++++++++++++++++++++++++
 1 file changed, 59 insertions(+)
 create mode 100644 examples/ip_pipeline/examples/firewall.cli

diff --git a/examples/ip_pipeline/examples/firewall.cli b/examples/ip_pipeline/examples/firewall.cli
new file mode 100644
index 0000000..269256c
--- /dev/null
+++ b/examples/ip_pipeline/examples/firewall.cli
@@ -0,0 +1,59 @@
+; SPDX-License-Identifier: BSD-3-Clause
+; Copyright(c) 2010-2018 Intel Corporation
+
+;                 _______________
+; LINK0 RXQ0 --->|               |---> LINK0 TXQ0
+;                |               |
+; LINK1 RXQ0 --->|               |---> LINK1 TXQ0
+;                |   Firewall    |
+; LINK2 RXQ0 --->|               |---> LINK2 TXQ0
+;                |               |
+; LINK3 RXQ0 --->|               |---> LINK3 TXQ0
+;                |_______________|
+;                        |
+;                       -+-
+;
+; Input packet: Ethernet/IPv4
+;
+; Packet buffer layout:
+; #   Field Name            Offset (Bytes)      Size (Bytes)
+; 0   Mbuf                  0                   128
+; 1   Headroom              128                 128
+; 2   Ethernet header       256                 14
+; 3   IPv4 header           270                 20
+
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+
+link LINK0 dev 0000:02:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+link LINK1 dev 0000:02:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+link LINK2 dev 0000:06:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+link LINK3 dev 0000:06:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+
+table action profile AP0 ipv4 offset 270 fwd
+
+pipeline PIPELINE0 period 10 offset_port_id 0 cpu 0
+
+pipeline PIPELINE0 port in bsz 32 link LINK0 rxq 0
+pipeline PIPELINE0 port in bsz 32 link LINK1 rxq 0
+pipeline PIPELINE0 port in bsz 32 link LINK2 rxq 0
+pipeline PIPELINE0 port in bsz 32 link LINK3 rxq 0
+
+pipeline PIPELINE0 port out bsz 32 link LINK0 txq 0
+pipeline PIPELINE0 port out bsz 32 link LINK1 txq 0
+pipeline PIPELINE0 port out bsz 32 link LINK2 txq 0
+pipeline PIPELINE0 port out bsz 32 link LINK3 txq 0
+
+pipeline PIPELINE0 table match acl ipv4 offset 270 size 4K action AP0
+
+pipeline PIPELINE0 port in 0 table 0
+pipeline PIPELINE0 port in 1 table 0
+pipeline PIPELINE0 port in 2 table 0
+pipeline PIPELINE0 port in 3 table 0
+
+thread 1 pipeline PIPELINE0 enable
+
+pipeline PIPELINE0 table 0 rule add match default action fwd drop
+pipeline PIPELINE0 table 0 rule add match acl priority 0 ipv4 0.0.0.0 0 100.0.0.0 10 0 65535 0 65535 6 action fwd port 0
+pipeline PIPELINE0 table 0 rule add match acl priority 0 ipv4 0.0.0.0 0 100.64.0.0 10 0 65535 0 65535 6 action fwd port 1
+pipeline PIPELINE0 table 0 rule add match acl priority 0 ipv4 0.0.0.0 0 100.128.0.0 10 0 65535 0 65535 6 action fwd port 2
+pipeline PIPELINE0 table 0 rule add match acl priority 0 ipv4 0.0.0.0 0 100.192.0.0 10 0 65535 0 65535 6 action fwd port 3
-- 
2.9.3

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

* [dpdk-dev] [PATCH v4 49/49] ip_pipeline: add flow classification example
  2018-03-29 18:31           ` [dpdk-dev] [PATCH v4 00/49] ip_pipeline: refactoring Jasvinder Singh
                               ` (47 preceding siblings ...)
  2018-03-29 18:32             ` [dpdk-dev] [PATCH v4 48/49] ip_pipeline: add firewall example Jasvinder Singh
@ 2018-03-29 18:32             ` Jasvinder Singh
  2018-03-30 12:44             ` [dpdk-dev] [PATCH v4 00/49] ip_pipeline: refactoring Dumitrescu, Cristian
  49 siblings, 0 replies; 181+ messages in thread
From: Jasvinder Singh @ 2018-03-29 18:32 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, Fan Zhang

Add example to build pipeline with hash table to classify the
ingress traffic.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Signed-off-by: Fan Zhang <roy.fan.zhang@intel.com>
---
 examples/ip_pipeline/examples/flow.cli | 60 ++++++++++++++++++++++++++++++++++
 1 file changed, 60 insertions(+)
 create mode 100644 examples/ip_pipeline/examples/flow.cli

diff --git a/examples/ip_pipeline/examples/flow.cli b/examples/ip_pipeline/examples/flow.cli
new file mode 100644
index 0000000..426ff90
--- /dev/null
+++ b/examples/ip_pipeline/examples/flow.cli
@@ -0,0 +1,60 @@
+; SPDX-License-Identifier: BSD-3-Clause
+; Copyright(c) 2010-2018 Intel Corporation
+
+;                 ________________
+; LINK0 RXQ0 --->|                |---> LINK0 TXQ0
+;                |                |
+; LINK1 RXQ0 --->|                |---> LINK1 TXQ0
+;                |      Flow      |
+; LINK2 RXQ0 --->| Classification |---> LINK2 TXQ0
+;                |                |
+; LINK3 RXQ0 --->|                |---> LINK3 TXQ0
+;                |________________|
+;                        |
+;                        +-----------> SINK0 (flow lookup miss)
+;
+; Input packet: Ethernet/IPv4
+;
+; Packet buffer layout:
+; #   Field Name       Offset (Bytes)   Size (Bytes)
+; 0   Mbuf             0                128
+; 1   Headroom         128              128
+; 2   Ethernet header  256              14
+; 3   IPv4 header      270              20
+
+mempool MEMPOOL0 buffer 2304 pool 32K cache 256 cpu 0
+
+link LINK0 dev 0000:02:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+link LINK1 dev 0000:02:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+link LINK2 dev 0000:06:00.0 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+link LINK3 dev 0000:06:00.1 rxq 1 128 MEMPOOL0 txq 1 512 promiscuous on
+
+table action profile AP0 ipv4 offset 270 fwd
+
+pipeline PIPELINE0 period 10 offset_port_id 0 cpu 0
+
+pipeline PIPELINE0 port in bsz 32 link LINK0 rxq 0
+pipeline PIPELINE0 port in bsz 32 link LINK1 rxq 0
+pipeline PIPELINE0 port in bsz 32 link LINK2 rxq 0
+pipeline PIPELINE0 port in bsz 32 link LINK3 rxq 0
+
+pipeline PIPELINE0 port out bsz 32 link LINK0 txq 0
+pipeline PIPELINE0 port out bsz 32 link LINK1 txq 0
+pipeline PIPELINE0 port out bsz 32 link LINK2 txq 0
+pipeline PIPELINE0 port out bsz 32 link LINK3 txq 0
+pipeline PIPELINE0 port out bsz 32 sink
+
+pipeline PIPELINE0 table match hash ext key 16 mask 00FF0000FFFFFFFFFFFFFFFFFFFFFFFF offset 278 buckets 16K size 65K action AP0
+
+pipeline PIPELINE0 port in 0 table 0
+pipeline PIPELINE0 port in 1 table 0
+pipeline PIPELINE0 port in 2 table 0
+pipeline PIPELINE0 port in 3 table 0
+
+thread 1 pipeline PIPELINE0 enable
+
+pipeline PIPELINE0 table 0 rule add match default action fwd port 4
+pipeline PIPELINE0 table 0 rule add match hash ipv4_5tuple 100.0.0.10 200.0.0.10 100 200 6 action fwd port 0
+pipeline PIPELINE0 table 0 rule add match hash ipv4_5tuple 100.0.0.11 200.0.0.11 101 201 6 action fwd port 1
+pipeline PIPELINE0 table 0 rule add match hash ipv4_5tuple 100.0.0.12 200.0.0.12 102 202 6 action fwd port 2
+pipeline PIPELINE0 table 0 rule add match hash ipv4_5tuple 100.0.0.13 200.0.0.13 103 203 6 action fwd port 3
-- 
2.9.3

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

* Re: [dpdk-dev] [PATCH v4 00/49] ip_pipeline: refactoring
  2018-03-29 18:31           ` [dpdk-dev] [PATCH v4 00/49] ip_pipeline: refactoring Jasvinder Singh
                               ` (48 preceding siblings ...)
  2018-03-29 18:32             ` [dpdk-dev] [PATCH v4 49/49] ip_pipeline: add flow classification example Jasvinder Singh
@ 2018-03-30 12:44             ` Dumitrescu, Cristian
  49 siblings, 0 replies; 181+ messages in thread
From: Dumitrescu, Cristian @ 2018-03-30 12:44 UTC (permalink / raw)
  To: Singh, Jasvinder, dev; +Cc: Zhang, Roy Fan, Laatz, Kevin, Pattan, Reshma



> -----Original Message-----
> From: Singh, Jasvinder
> Sent: Thursday, March 29, 2018 7:31 PM
> To: dev@dpdk.org
> Cc: Dumitrescu, Cristian <cristian.dumitrescu@intel.com>
> Subject: [PATCH v4 00/49] ip_pipeline: refactoring
> 
> Refactored the IP pipeline application. As result, the code base
> size (lines of code) reduces by ~60%.
> 
> v4:

Applied to next-pipeline tree, thanks!

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

end of thread, other threads:[~2018-03-30 12:44 UTC | newest]

Thread overview: 181+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-03-09 18:23 [dpdk-dev] [PATCH 00/37] ip_pipeline: refactoring Jasvinder Singh
2018-03-09 18:23 ` [dpdk-dev] [PATCH 01/37] pipeline: add pipeline table action APIs Jasvinder Singh
2018-03-12 17:25   ` [dpdk-dev] [PATCH v2 00/44] ip_pipeline: refactoring Jasvinder Singh
2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 01/44] pipeline: add pipeline table action APIs Jasvinder Singh
2018-03-16 17:56       ` [dpdk-dev] [PATCH v3 00/44] ip_pipeline: refactoring Jasvinder Singh
2018-03-16 17:56         ` [dpdk-dev] [PATCH v3 01/44] pipeline: add pipeline table action APIs Jasvinder Singh
2018-03-16 17:58       ` [dpdk-dev] [PATCH v3 00/44] ip_pipeline: refactoring Jasvinder Singh
2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 01/44] pipeline: add pipeline table action APIs Jasvinder Singh
2018-03-29 18:31           ` [dpdk-dev] [PATCH v4 00/49] ip_pipeline: refactoring Jasvinder Singh
2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 01/49] pipeline: add pipeline table action APIs Jasvinder Singh
2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 02/49] pipeline: get pipeline table action params Jasvinder Singh
2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 03/49] pipeline: add traffic metering action Jasvinder Singh
2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 04/49] pipeline: add traffic manager action Jasvinder Singh
2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 05/49] pipeline: add packet encapsulation action Jasvinder Singh
2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 06/49] pipeline: add nat action Jasvinder Singh
2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 07/49] pipeline: add ttl update action Jasvinder Singh
2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 08/49] pipeline: add statistics read action Jasvinder Singh
2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 09/49] pipeline: add timestamp action Jasvinder Singh
2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 10/49] pipeline: add load balance action Jasvinder Singh
2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 11/49] pipeline: add pipeline port in action APIs Jasvinder Singh
2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 12/49] librte_table/acl: remove incorrect check Jasvinder Singh
2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 13/49] ip_pipeline: remove passthrough pipeline Jasvinder Singh
2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 14/49] ip_pipeline: remove routing pipeline Jasvinder Singh
2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 15/49] ip_pipeline: remove flow classification pipeline Jasvinder Singh
2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 16/49] ip_pipeline: remove flow actions pipeline Jasvinder Singh
2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 17/49] ip_pipeline: remove firewall pipeline Jasvinder Singh
2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 18/49] ip_pipeline: remove master pipeline Jasvinder Singh
2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 19/49] ip_pipeline: remove config Jasvinder Singh
2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 20/49] ip_pipeline: rework and improvements Jasvinder Singh
2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 21/49] ip_pipeline: add cli interface Jasvinder Singh
2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 22/49] ip_pipeline: add mempool object for pipeline Jasvinder Singh
2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 23/49] ip_pipeline: add link object Jasvinder Singh
2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 24/49] ip_pipeline: add software queue object Jasvinder Singh
2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 25/49] ip_pipeline: add traffic manager object Jasvinder Singh
2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 26/49] ip_pipeline: add tap object Jasvinder Singh
2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 27/49] ip_pipeline: add kni object Jasvinder Singh
2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 28/49] ip_pipeline: add action profile object Jasvinder Singh
2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 29/49] ip_pipeline: add pipeline object Jasvinder Singh
2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 30/49] ip_pipeline: add threads Jasvinder Singh
2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 31/49] ip_pipeline: add thread runtime Jasvinder Singh
2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 32/49] ip_pipeline: add cli to enable and disable pipeline Jasvinder Singh
2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 33/49] ip_pipeline: add cli to enable and disable pipeline port Jasvinder Singh
2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 34/49] ip_pipeline: add cli to read pipeline port and table stats Jasvinder Singh
2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 35/49] ip_pipeline: add cli for pipeline table entry Jasvinder Singh
2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 36/49] ip_pipeline: add cli to delete " Jasvinder Singh
2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 37/49] ip_pipeline: add cli for bulk entries to pipeline table Jasvinder Singh
2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 38/49] ip_pipeline: add cli to read pipeline table entry stats Jasvinder Singh
2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 39/49] ip_pipeline: add cli to configure meter profile Jasvinder Singh
2018-03-29 18:31             ` [dpdk-dev] [PATCH v4 40/49] ip_pipeline: add cli to read meter stats Jasvinder Singh
2018-03-29 18:32             ` [dpdk-dev] [PATCH v4 41/49] ip_pipeline: add cli to update dscp table Jasvinder Singh
2018-03-29 18:32             ` [dpdk-dev] [PATCH v4 42/49] ip_pipeline: add cli to read ttl stats Jasvinder Singh
2018-03-29 18:32             ` [dpdk-dev] [PATCH v4 43/49] ip_pipeline: add cli for load balance action Jasvinder Singh
2018-03-29 18:32             ` [dpdk-dev] [PATCH v4 44/49] ip_pipeline: add l2fwd example Jasvinder Singh
2018-03-29 18:32             ` [dpdk-dev] [PATCH v4 45/49] ip_pipeline: add KNI port example Jasvinder Singh
2018-03-29 18:32             ` [dpdk-dev] [PATCH v4 46/49] ip_pipeline: add TAP " Jasvinder Singh
2018-03-29 18:32             ` [dpdk-dev] [PATCH v4 47/49] ip_pipeline: add route example Jasvinder Singh
2018-03-29 18:32             ` [dpdk-dev] [PATCH v4 48/49] ip_pipeline: add firewall example Jasvinder Singh
2018-03-29 18:32             ` [dpdk-dev] [PATCH v4 49/49] ip_pipeline: add flow classification example Jasvinder Singh
2018-03-30 12:44             ` [dpdk-dev] [PATCH v4 00/49] ip_pipeline: refactoring Dumitrescu, Cristian
2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 02/44] pipeline: get pipeline table action params Jasvinder Singh
2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 03/44] pipeline: add traffic metering action Jasvinder Singh
2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 04/44] pipeline: add traffic manager action Jasvinder Singh
2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 05/44] pipeline: add packet encapsulation action Jasvinder Singh
2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 06/44] pipeline: add nat action Jasvinder Singh
2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 07/44] pipeline: add ttl update action Jasvinder Singh
2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 08/44] pipeline: add statistics read action Jasvinder Singh
2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 09/44] pipeline: add timestamp action Jasvinder Singh
2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 10/44] ip_pipeline: remove passthrough pipeline Jasvinder Singh
2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 11/44] ip_pipeline: remove routing pipeline Jasvinder Singh
2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 12/44] ip_pipeline: remove flow classification pipeline Jasvinder Singh
2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 13/44] ip_pipeline: remove flow actions pipeline Jasvinder Singh
2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 14/44] ip_pipeline: remove firewall pipeline Jasvinder Singh
2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 15/44] ip_pipeline: remove master pipeline Jasvinder Singh
2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 16/44] ip_pipeline: remove config Jasvinder Singh
2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 17/44] ip_pipeline: rework and improvements Jasvinder Singh
2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 18/44] ip_pipeline: add cli interface Jasvinder Singh
2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 19/44] ip_pipeline: add mempool object for pipeline Jasvinder Singh
2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 20/44] ip_pipeline: add link object Jasvinder Singh
2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 21/44] ip_pipeline: add software queue object Jasvinder Singh
2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 22/44] ip_pipeline: add traffic manager object Jasvinder Singh
2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 23/44] ip_pipeline: add tap object Jasvinder Singh
2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 24/44] ip_pipeline: add kni object Jasvinder Singh
2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 25/44] ip_pipeline: add action profile object Jasvinder Singh
2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 26/44] ip_pipeline: add pipeline object Jasvinder Singh
2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 27/44] ip_pipeline: add threads Jasvinder Singh
2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 28/44] ip_pipeline: add thread runtime Jasvinder Singh
2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 29/44] ip_pipeline: add cli to enable and disable pipeline Jasvinder Singh
2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 30/44] ip_pipeline: add cli to enable and disable pipeline port Jasvinder Singh
2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 31/44] ip_pipeline: add cli to read pipeline port and table stats Jasvinder Singh
2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 32/44] ip_pipeline: add cli for pipeline table entries Jasvinder Singh
2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 33/44] ip_pipeline: add cli to delete pipeline table entry Jasvinder Singh
2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 34/44] ip_pipeline: add cli to read pipeline table entry stats Jasvinder Singh
2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 35/44] ip_pipeline: add cli to configure meter profile Jasvinder Singh
2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 36/44] ip_pipeline: add cli to read meter stats Jasvinder Singh
2018-03-16 17:58         ` [dpdk-dev] [PATCH v3 37/44] ip_pipeline: add cli to update dscp table Jasvinder Singh
2018-03-16 17:59         ` [dpdk-dev] [PATCH v3 38/44] ip_pipeline: add cli to read ttl stats Jasvinder Singh
2018-03-16 17:59         ` [dpdk-dev] [PATCH v3 39/44] ip_pipeline: add l2fwd example Jasvinder Singh
2018-03-16 17:59         ` [dpdk-dev] [PATCH v3 40/44] ip_pipeline: add KNI port example Jasvinder Singh
2018-03-16 17:59         ` [dpdk-dev] [PATCH v3 41/44] ip_pipeline: add TAP " Jasvinder Singh
2018-03-16 17:59         ` [dpdk-dev] [PATCH v3 42/44] ip_pipeline: add route example Jasvinder Singh
2018-03-16 17:59         ` [dpdk-dev] [PATCH v3 43/44] ip_pipeline: add firewall example Jasvinder Singh
2018-03-16 17:59         ` [dpdk-dev] [PATCH v3 44/44] ip_pipeline: add flow classification example Jasvinder Singh
2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 02/44] pipeline: get pipeline table action params Jasvinder Singh
2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 03/44] pipeline: add traffic metering action Jasvinder Singh
2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 04/44] pipeline: add traffic manager action Jasvinder Singh
2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 05/44] pipeline: add packet encapsulation action Jasvinder Singh
2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 06/44] pipeline: add nat action Jasvinder Singh
2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 07/44] pipeline: add ttl update action Jasvinder Singh
2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 08/44] pipeline: add statistics read action Jasvinder Singh
2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 09/44] pipeline: add timestamp action Jasvinder Singh
2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 10/44] ip_pipeline: remove passthrough pipeline Jasvinder Singh
2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 11/44] ip_pipeline: remove routing pipeline Jasvinder Singh
2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 12/44] ip_pipeline: remove flow classification pipeline Jasvinder Singh
2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 13/44] ip_pipeline: remove flow actions pipeline Jasvinder Singh
2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 14/44] ip_pipeline: remove firewall pipeline Jasvinder Singh
2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 15/44] ip_pipeline: remove master pipeline Jasvinder Singh
2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 16/44] ip_pipeline: remove config Jasvinder Singh
2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 17/44] ip_pipeline: rework and improvements Jasvinder Singh
2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 18/44] ip_pipeline: add cli interface Jasvinder Singh
2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 19/44] ip_pipeline: add mempool object for pipeline Jasvinder Singh
2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 20/44] ip_pipeline: add link object Jasvinder Singh
2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 21/44] ip_pipeline: add software queue object Jasvinder Singh
2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 22/44] ip_pipeline: add traffic manager object Jasvinder Singh
2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 23/44] ip_pipeline: add tap object Jasvinder Singh
2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 24/44] ip_pipeline: add kni object Jasvinder Singh
2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 25/44] ip_pipeline: add action profile object Jasvinder Singh
2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 26/44] ip_pipeline: add pipeline object Jasvinder Singh
2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 27/44] ip_pipeline: add threads Jasvinder Singh
2018-03-12 17:25     ` [dpdk-dev] [PATCH v2 28/44] ip_pipeline: add thread runtime Jasvinder Singh
2018-03-12 17:26     ` [dpdk-dev] [PATCH v2 29/44] ip_pipeline: add cli to enable and disable pipeline Jasvinder Singh
2018-03-12 17:26     ` [dpdk-dev] [PATCH v2 30/44] ip_pipeline: add cli to enable and disable pipeline port Jasvinder Singh
2018-03-12 17:26     ` [dpdk-dev] [PATCH v2 31/44] ip_pipeline: add cli to read pipeline port and table stats Jasvinder Singh
2018-03-12 17:26     ` [dpdk-dev] [PATCH v2 32/44] ip_pipeline: add cli for pipeline table entries Jasvinder Singh
2018-03-12 17:26     ` [dpdk-dev] [PATCH v2 33/44] ip_pipeline: add cli to delete pipeline table entry Jasvinder Singh
2018-03-12 17:26     ` [dpdk-dev] [PATCH v2 34/44] ip_pipeline: add cli to read pipeline table entry stats Jasvinder Singh
2018-03-12 17:26     ` [dpdk-dev] [PATCH v2 35/44] ip_pipeline: add cli to configure meter profile Jasvinder Singh
2018-03-12 17:26     ` [dpdk-dev] [PATCH v2 36/44] ip_pipeline: add cli to read meter stats Jasvinder Singh
2018-03-12 17:26     ` [dpdk-dev] [PATCH v2 37/44] ip_pipeline: add cli to update dscp table Jasvinder Singh
2018-03-12 17:26     ` [dpdk-dev] [PATCH v2 38/44] ip_pipeline: add cli to read ttl stats Jasvinder Singh
2018-03-12 17:26     ` [dpdk-dev] [PATCH v2 39/44] ip_pipeline: add l2fwd example Jasvinder Singh
2018-03-12 17:26     ` [dpdk-dev] [PATCH v2 40/44] ip_pipeline: add KNI port example Jasvinder Singh
2018-03-12 17:26     ` [dpdk-dev] [PATCH v2 41/44] ip_pipeline: add TAP " Jasvinder Singh
2018-03-12 17:26     ` [dpdk-dev] [PATCH v2 42/44] ip_pipeline: add route example Jasvinder Singh
2018-03-12 17:26     ` [dpdk-dev] [PATCH v2 43/44] ip_pipeline: add firewall example Jasvinder Singh
2018-03-12 17:26     ` [dpdk-dev] [PATCH v2 44/44] ip_pipeline: add flow classification example Jasvinder Singh
2018-03-09 18:23 ` [dpdk-dev] [PATCH 02/37] pipeline: get pipeline table action params Jasvinder Singh
2018-03-09 18:23 ` [dpdk-dev] [PATCH 03/37] pipeline: add traffic metering action Jasvinder Singh
2018-03-09 18:23 ` [dpdk-dev] [PATCH 04/37] pipeline: add traffic manager action Jasvinder Singh
2018-03-09 18:23 ` [dpdk-dev] [PATCH 05/37] pipeline: add packet encapsulation action Jasvinder Singh
2018-03-09 18:23 ` [dpdk-dev] [PATCH 06/37] pipeline: add nat action Jasvinder Singh
2018-03-09 18:23 ` [dpdk-dev] [PATCH 07/37] pipeline: add ttl update action Jasvinder Singh
2018-03-09 18:23 ` [dpdk-dev] [PATCH 08/37] pipeline: add statistics read action Jasvinder Singh
2018-03-09 18:23 ` [dpdk-dev] [PATCH 09/37] pipeline: add timestamp action Jasvinder Singh
2018-03-09 18:23 ` [dpdk-dev] [PATCH 10/37] ip_pipeline: rework and improvements Jasvinder Singh
2018-03-09 18:24 ` [dpdk-dev] [PATCH 11/37] ip_pipeline: add cli interface Jasvinder Singh
2018-03-09 18:24 ` [dpdk-dev] [PATCH 12/37] ip_pipeline: add mempool object for pipeline Jasvinder Singh
2018-03-09 18:24 ` [dpdk-dev] [PATCH 13/37] ip_pipeline: add link object Jasvinder Singh
2018-03-09 18:24 ` [dpdk-dev] [PATCH 14/37] ip_pipeline: add software queue object Jasvinder Singh
2018-03-09 18:24 ` [dpdk-dev] [PATCH 15/37] ip_pipeline: add traffic manager object Jasvinder Singh
2018-03-09 18:24 ` [dpdk-dev] [PATCH 16/37] ip_pipeline: add tap object Jasvinder Singh
2018-03-09 18:24 ` [dpdk-dev] [PATCH 17/37] ip_pipeline: add kni object Jasvinder Singh
2018-03-09 18:24 ` [dpdk-dev] [PATCH 18/37] ip_pipeline: add action profile object Jasvinder Singh
2018-03-09 18:24 ` [dpdk-dev] [PATCH 19/37] ip_pipeline: add pipeline object Jasvinder Singh
2018-03-09 18:24 ` [dpdk-dev] [PATCH 20/37] ip_pipeline: add threads Jasvinder Singh
2018-03-09 18:24 ` [dpdk-dev] [PATCH 21/37] ip_pipeline: add thread runtime Jasvinder Singh
2018-03-09 18:24 ` [dpdk-dev] [PATCH 22/37] ip_pipeline: add cli to enable and disable pipeline Jasvinder Singh
2018-03-09 18:24 ` [dpdk-dev] [PATCH 23/37] ip_pipeline: add cli to enable and disable pipeline port Jasvinder Singh
2018-03-09 18:24 ` [dpdk-dev] [PATCH 24/37] ip_pipeline: add cli to read pipeline port and table stats Jasvinder Singh
2018-03-09 18:24 ` [dpdk-dev] [PATCH 25/37] ip_pipeline: add cli for pipeline table entries Jasvinder Singh
2018-03-09 18:24 ` [dpdk-dev] [PATCH 26/37] ip_pipeline: add cli to delete pipeline table entry Jasvinder Singh
2018-03-09 18:24 ` [dpdk-dev] [PATCH 27/37] ip_pipeline: add cli to read pipeline table entry stats Jasvinder Singh
2018-03-09 18:24 ` [dpdk-dev] [PATCH 28/37] ip_pipeline: add cli to configure meter profile Jasvinder Singh
2018-03-09 18:24 ` [dpdk-dev] [PATCH 29/37] ip_pipeline: add cli to read meter stats Jasvinder Singh
2018-03-09 18:24 ` [dpdk-dev] [PATCH 30/37] ip_pipeline: add cli to update dscp table Jasvinder Singh
2018-03-09 18:24 ` [dpdk-dev] [PATCH 31/37] ip_pipeline: add cli to read ttl stats Jasvinder Singh
2018-03-09 18:24 ` [dpdk-dev] [PATCH 32/37] ip_pipeline: add l2fwd example Jasvinder Singh
2018-03-09 18:24 ` [dpdk-dev] [PATCH 33/37] ip_pipeline: add KNI port example Jasvinder Singh
2018-03-09 18:24 ` [dpdk-dev] [PATCH 34/37] ip_pipeline: add TAP " Jasvinder Singh
2018-03-09 18:24 ` [dpdk-dev] [PATCH 35/37] ip_pipeline: add route example Jasvinder Singh
2018-03-09 18:24 ` [dpdk-dev] [PATCH 36/37] ip_pipeline: add firewall example Jasvinder Singh
2018-03-09 18:24 ` [dpdk-dev] [PATCH 37/37] ip_pipeline: add flow classification example Jasvinder Singh

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).