[dpdk-dev,v2,2/6] ip_pipeline: linking routing pipeline output ports with NIC ports

Message ID 1464789663-173318-3-git-send-email-jasvinder.singh@intel.com (mailing list archive)
State Accepted, archived
Delegated to: Thomas Monjalon
Headers

Commit Message

Jasvinder Singh June 1, 2016, 2 p.m. UTC
  This commit implements tracking mechanism for linking routing pipeline
output ports to physical NIC ports.

Once all the pipelines of the application are initialised, mechanism is
invoked during post initialisation phase for relating routing pipeline
output with NIC ports by navigating through the intermediate pipelines,
if present.

The tracking functions of the pipelines which help in navigating through
the intermediate pipelines are moved from pipeline_<pipeline_name>_be.c
to pipeline_<pipeline_name>.c. All pipelines except passthrough pipelines
use default tracking function (pipeline/pipeline_common_fe.c).

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 examples/ip_pipeline/app.h                         | 151 ++++++++++++++++++++-
 examples/ip_pipeline/init.c                        |  32 ++++-
 examples/ip_pipeline/pipeline.h                    |  11 +-
 examples/ip_pipeline/pipeline/pipeline_common_fe.c | 109 +++++++++++++++
 examples/ip_pipeline/pipeline/pipeline_common_fe.h |  10 ++
 examples/ip_pipeline/pipeline/pipeline_firewall.c  |   2 +
 .../ip_pipeline/pipeline/pipeline_firewall_be.c    |  22 ---
 .../ip_pipeline/pipeline/pipeline_flow_actions.c   |   2 +
 .../pipeline/pipeline_flow_actions_be.c            |  22 ---
 .../pipeline/pipeline_flow_classification.c        |   2 +
 .../pipeline/pipeline_flow_classification_be.c     |  22 ---
 examples/ip_pipeline/pipeline/pipeline_master.c    |   2 +
 examples/ip_pipeline/pipeline/pipeline_master_be.c |  13 +-
 .../ip_pipeline/pipeline/pipeline_passthrough.c    |  27 ++++
 .../ip_pipeline/pipeline/pipeline_passthrough_be.c |  39 +++---
 examples/ip_pipeline/pipeline/pipeline_routing.c   |   6 +-
 .../ip_pipeline/pipeline/pipeline_routing_be.c     |  22 ---
 examples/ip_pipeline/pipeline_be.h                 |  10 +-
 18 files changed, 380 insertions(+), 124 deletions(-)
  

Patch

diff --git a/examples/ip_pipeline/app.h b/examples/ip_pipeline/app.h
index dfdfb51..93e96d0 100644
--- a/examples/ip_pipeline/app.h
+++ b/examples/ip_pipeline/app.h
@@ -205,9 +205,7 @@  struct app_pktq_out_params {
 	uint32_t id; /* Position in the appropriate app array */
 };
 
-#ifndef APP_PIPELINE_TYPE_SIZE
-#define APP_PIPELINE_TYPE_SIZE                   64
-#endif
+#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
@@ -651,6 +649,41 @@  app_swq_get_readers(struct app_params *app, struct app_pktq_swq_params *swq)
 	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;
+	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, 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)
 {
@@ -676,6 +709,41 @@  app_tm_get_readers(struct app_params *app, struct app_pktq_tm_params *tm)
 	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;
+	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, 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_source_get_readers(struct app_params *app,
 struct app_pktq_source_params *source)
@@ -775,6 +843,42 @@  app_swq_get_writers(struct app_params *app, struct app_pktq_swq_params *swq)
 	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;
+	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, 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)
 {
@@ -801,6 +905,41 @@  app_tm_get_writers(struct app_params *app, struct app_pktq_tm_params *tm)
 	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;
+	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, 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_sink_get_writers(struct app_params *app, struct app_pktq_sink_params *sink)
 {
@@ -899,6 +1038,10 @@  app_get_link_for_tm(struct app_params *app, struct app_pktq_tm_params *p_tm)
 	return &app->link_params[link_param_idx];
 }
 
+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,
@@ -918,6 +1061,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,
diff --git a/examples/ip_pipeline/init.c b/examples/ip_pipeline/init.c
index b2eafe3..7120bab 100644
--- a/examples/ip_pipeline/init.c
+++ b/examples/ip_pipeline/init.c
@@ -1196,7 +1196,7 @@  app_init_msgq(struct app_params *app)
 	}
 }
 
-static void app_pipeline_params_get(struct app_params *app,
+void app_pipeline_params_get(struct app_params *app,
 	struct app_pipeline_params *p_in,
 	struct pipeline_params *p_out)
 {
@@ -1204,6 +1204,8 @@  static void app_pipeline_params_get(struct app_params *app,
 
 	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;
@@ -1499,6 +1501,27 @@  app_init_pipelines(struct app_params *app)
 }
 
 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();
@@ -1601,6 +1624,13 @@  int app_init(struct app_params *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)
diff --git a/examples/ip_pipeline/pipeline.h b/examples/ip_pipeline/pipeline.h
index dab9c36..14a551d 100644
--- a/examples/ip_pipeline/pipeline.h
+++ b/examples/ip_pipeline/pipeline.h
@@ -42,13 +42,22 @@ 
  * Pipeline type front-end operations
  */
 
-typedef void* (*pipeline_fe_op_init)(struct pipeline_params *params, void *arg);
+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;
 };
 
diff --git a/examples/ip_pipeline/pipeline/pipeline_common_fe.c b/examples/ip_pipeline/pipeline/pipeline_common_fe.c
index dc37a5f..fa0a482 100644
--- a/examples/ip_pipeline/pipeline/pipeline_common_fe.c
+++ b/examples/ip_pipeline/pipeline/pipeline_common_fe.c
@@ -47,6 +47,115 @@ 
 #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_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)
diff --git a/examples/ip_pipeline/pipeline/pipeline_common_fe.h b/examples/ip_pipeline/pipeline/pipeline_common_fe.h
index f93ff74..8abee4a 100644
--- a/examples/ip_pipeline/pipeline/pipeline_common_fe.h
+++ b/examples/ip_pipeline/pipeline/pipeline_common_fe.h
@@ -182,6 +182,16 @@  app_msg_send_recv(struct app_params *app,
 	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);
diff --git a/examples/ip_pipeline/pipeline/pipeline_firewall.c b/examples/ip_pipeline/pipeline/pipeline_firewall.c
index 30b22a1..a82e552 100644
--- a/examples/ip_pipeline/pipeline/pipeline_firewall.c
+++ b/examples/ip_pipeline/pipeline/pipeline_firewall.c
@@ -1437,7 +1437,9 @@  static cmdline_parse_ctx_t pipeline_cmds[] = {
 
 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,
 };
 
diff --git a/examples/ip_pipeline/pipeline/pipeline_firewall_be.c b/examples/ip_pipeline/pipeline/pipeline_firewall_be.c
index 4edca66..b61f303 100644
--- a/examples/ip_pipeline/pipeline/pipeline_firewall_be.c
+++ b/examples/ip_pipeline/pipeline/pipeline_firewall_be.c
@@ -565,27 +565,6 @@  pipeline_firewall_free(void *pipeline)
 }
 
 static int
-pipeline_firewall_track(void *pipeline,
-	__rte_unused uint32_t port_in,
-	uint32_t *port_out)
-{
-	struct pipeline *p = (struct pipeline *) pipeline;
-
-	/* Check input arguments */
-	if ((p == NULL) ||
-		(port_in >= p->n_ports_in) ||
-		(port_out == NULL))
-		return -1;
-
-	if (p->n_ports_in == 1) {
-		*port_out = 0;
-		return 0;
-	}
-
-	return -1;
-}
-
-static int
 pipeline_firewall_timer(void *pipeline)
 {
 	struct pipeline *p = (struct pipeline *) pipeline;
@@ -903,5 +882,4 @@  struct pipeline_be_ops pipeline_firewall_be_ops = {
 	.f_free = pipeline_firewall_free,
 	.f_run = NULL,
 	.f_timer = pipeline_firewall_timer,
-	.f_track = pipeline_firewall_track,
 };
diff --git a/examples/ip_pipeline/pipeline/pipeline_flow_actions.c b/examples/ip_pipeline/pipeline/pipeline_flow_actions.c
index 7560051..bf12fd7 100644
--- a/examples/ip_pipeline/pipeline/pipeline_flow_actions.c
+++ b/examples/ip_pipeline/pipeline/pipeline_flow_actions.c
@@ -1300,7 +1300,9 @@  static cmdline_parse_ctx_t pipeline_cmds[] = {
 
 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,
 };
 
diff --git a/examples/ip_pipeline/pipeline/pipeline_flow_actions_be.c b/examples/ip_pipeline/pipeline/pipeline_flow_actions_be.c
index 3ad3ee6..11fcbb7 100644
--- a/examples/ip_pipeline/pipeline/pipeline_flow_actions_be.c
+++ b/examples/ip_pipeline/pipeline/pipeline_flow_actions_be.c
@@ -760,27 +760,6 @@  pipeline_fa_free(void *pipeline)
 }
 
 static int
-pipeline_fa_track(void *pipeline,
-	__rte_unused uint32_t port_in,
-	uint32_t *port_out)
-{
-	struct pipeline *p = (struct pipeline *) pipeline;
-
-	/* Check input arguments */
-	if ((p == NULL) ||
-		(port_in >= p->n_ports_in) ||
-		(port_out == NULL))
-		return -1;
-
-	if (p->n_ports_in == 1) {
-		*port_out = 0;
-		return 0;
-	}
-
-	return -1;
-}
-
-static int
 pipeline_fa_timer(void *pipeline)
 {
 	struct pipeline *p = (struct pipeline *) pipeline;
@@ -1007,5 +986,4 @@  struct pipeline_be_ops pipeline_flow_actions_be_ops = {
 	.f_free = pipeline_fa_free,
 	.f_run = NULL,
 	.f_timer = pipeline_fa_timer,
-	.f_track = pipeline_fa_track,
 };
diff --git a/examples/ip_pipeline/pipeline/pipeline_flow_classification.c b/examples/ip_pipeline/pipeline/pipeline_flow_classification.c
index e49c881..9ef50cc 100644
--- a/examples/ip_pipeline/pipeline/pipeline_flow_classification.c
+++ b/examples/ip_pipeline/pipeline/pipeline_flow_classification.c
@@ -1892,7 +1892,9 @@  static cmdline_parse_ctx_t pipeline_cmds[] = {
 
 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,
 };
 
diff --git a/examples/ip_pipeline/pipeline/pipeline_flow_classification_be.c b/examples/ip_pipeline/pipeline/pipeline_flow_classification_be.c
index 70d976d..8a762bc 100644
--- a/examples/ip_pipeline/pipeline/pipeline_flow_classification_be.c
+++ b/examples/ip_pipeline/pipeline/pipeline_flow_classification_be.c
@@ -643,27 +643,6 @@  pipeline_fc_free(void *pipeline)
 }
 
 static int
-pipeline_fc_track(void *pipeline,
-	__rte_unused uint32_t port_in,
-	uint32_t *port_out)
-{
-	struct pipeline *p = (struct pipeline *) pipeline;
-
-	/* Check input arguments */
-	if ((p == NULL) ||
-		(port_in >= p->n_ports_in) ||
-		(port_out == NULL))
-		return -1;
-
-	if (p->n_ports_in == 1) {
-		*port_out = 0;
-		return 0;
-	}
-
-	return -1;
-}
-
-static int
 pipeline_fc_timer(void *pipeline)
 {
 	struct pipeline *p = (struct pipeline *) pipeline;
@@ -807,5 +786,4 @@  struct pipeline_be_ops pipeline_flow_classification_be_ops = {
 	.f_free = pipeline_fc_free,
 	.f_run = NULL,
 	.f_timer = pipeline_fc_timer,
-	.f_track = pipeline_fc_track,
 };
diff --git a/examples/ip_pipeline/pipeline/pipeline_master.c b/examples/ip_pipeline/pipeline/pipeline_master.c
index 1ccdad1..aab58a2 100644
--- a/examples/ip_pipeline/pipeline/pipeline_master.c
+++ b/examples/ip_pipeline/pipeline/pipeline_master.c
@@ -36,7 +36,9 @@ 
 
 static struct pipeline_fe_ops pipeline_master_fe_ops = {
 	.f_init = NULL,
+	.f_post_init = NULL,
 	.f_free = NULL,
+	.f_track = NULL,
 	.cmds = NULL,
 };
 
diff --git a/examples/ip_pipeline/pipeline/pipeline_master_be.c b/examples/ip_pipeline/pipeline/pipeline_master_be.c
index ac0cbbc..79869a4 100644
--- a/examples/ip_pipeline/pipeline/pipeline_master_be.c
+++ b/examples/ip_pipeline/pipeline/pipeline_master_be.c
@@ -48,6 +48,7 @@ 
 struct pipeline_master {
 	struct app_params *app;
 	struct cmdline *cl;
+	int post_init_done;
 	int script_file_done;
 } __rte_cache_aligned;
 
@@ -77,6 +78,7 @@  pipeline_init(__rte_unused struct pipeline_params *params, void *arg)
 		return NULL;
 	}
 
+	p->post_init_done = 0;
 	p->script_file_done = 0;
 	if (app->script_file == NULL)
 		p->script_file_done = 1;
@@ -102,8 +104,17 @@  static int
 pipeline_run(void *pipeline)
 {
 	struct pipeline_master *p = (struct pipeline_master *) pipeline;
+	struct app_params *app = p->app;
 	int status;
 
+	/* 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);
@@ -124,6 +135,7 @@  pipeline_run(void *pipeline)
 		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);
@@ -146,5 +158,4 @@  struct pipeline_be_ops pipeline_master_be_ops = {
 		.f_free = pipeline_free,
 		.f_run = pipeline_run,
 		.f_timer = pipeline_timer,
-		.f_track = NULL,
 };
diff --git a/examples/ip_pipeline/pipeline/pipeline_passthrough.c b/examples/ip_pipeline/pipeline/pipeline_passthrough.c
index fc2cae5..63ce147 100644
--- a/examples/ip_pipeline/pipeline/pipeline_passthrough.c
+++ b/examples/ip_pipeline/pipeline/pipeline_passthrough.c
@@ -34,9 +34,36 @@ 
 #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.lb_hash_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,
 };
 
diff --git a/examples/ip_pipeline/pipeline/pipeline_passthrough_be.c b/examples/ip_pipeline/pipeline/pipeline_passthrough_be.c
index a0d11ae..6146a28 100644
--- a/examples/ip_pipeline/pipeline/pipeline_passthrough_be.c
+++ b/examples/ip_pipeline/pipeline/pipeline_passthrough_be.c
@@ -547,6 +547,18 @@  pipeline_passthrough_parse_args(struct pipeline_passthrough_params *p,
 			"dma_src_mask", dma_mask_str);
 	}
 
+	if (p->lb_hash_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;
 }
 
@@ -579,9 +591,7 @@  pipeline_passthrough_init(struct pipeline_params *params,
 	/* Check input arguments */
 	if ((params == NULL) ||
 		(params->n_ports_in == 0) ||
-		(params->n_ports_out == 0) ||
-		(params->n_ports_in < params->n_ports_out) ||
-		(params->n_ports_in % params->n_ports_out))
+		(params->n_ports_out == 0))
 		return NULL;
 
 	/* Memory allocation */
@@ -702,10 +712,13 @@  pipeline_passthrough_init(struct pipeline_params *params,
 
 	/* Add entries to tables */
 	for (i = 0; i < p->n_ports_in; i++) {
+		uint32_t port_out_id = (p_pt->params.lb_hash_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[
-				i / (p->n_ports_in / p->n_ports_out)]},
+			{.port_id = p->port_out_id[port_out_id]},
 		};
 
 		struct rte_pipeline_table_entry *default_entry_ptr;
@@ -780,25 +793,9 @@  pipeline_passthrough_timer(void *pipeline)
 	return 0;
 }
 
-static int
-pipeline_passthrough_track(void *pipeline, uint32_t port_in, uint32_t *port_out)
-{
-	struct pipeline *p = (struct pipeline *) pipeline;
-
-	/* Check input arguments */
-	if ((p == NULL) ||
-		(port_in >= p->n_ports_in) ||
-		(port_out == NULL))
-		return -1;
-
-	*port_out = port_in / p->n_ports_in;
-	return 0;
-}
-
 struct pipeline_be_ops pipeline_passthrough_be_ops = {
 	.f_init = pipeline_passthrough_init,
 	.f_free = pipeline_passthrough_free,
 	.f_run = NULL,
 	.f_timer = pipeline_passthrough_timer,
-	.f_track = pipeline_passthrough_track,
 };
diff --git a/examples/ip_pipeline/pipeline/pipeline_routing.c b/examples/ip_pipeline/pipeline/pipeline_routing.c
index c68e470..4d074c1 100644
--- a/examples/ip_pipeline/pipeline/pipeline_routing.c
+++ b/examples/ip_pipeline/pipeline/pipeline_routing.c
@@ -382,8 +382,6 @@  app_pipeline_routing_add_route(struct app_params *app,
 		p->n_routes++;
 	}
 
-	print_route(entry);
-
 	/* Message buffer free */
 	app_msg_free(app, rsp);
 	return 0;
@@ -676,8 +674,6 @@  app_pipeline_routing_add_arp_entry(struct app_params *app, uint32_t pipeline_id,
 		p->n_arp_entries++;
 	}
 
-	print_arp_entry(entry);
-
 	/* Message buffer free */
 	app_msg_free(app, rsp);
 	return 0;
@@ -1390,7 +1386,9 @@  static cmdline_parse_ctx_t pipeline_cmds[] = {
 
 static struct pipeline_fe_ops pipeline_routing_fe_ops = {
 	.f_init = pipeline_routing_init,
+	.f_post_init = NULL,
 	.f_free = app_pipeline_routing_free,
+	.f_track = app_pipeline_track_default,
 	.cmds = pipeline_cmds,
 };
 
diff --git a/examples/ip_pipeline/pipeline/pipeline_routing_be.c b/examples/ip_pipeline/pipeline/pipeline_routing_be.c
index bc5bf7a..e7542a8 100644
--- a/examples/ip_pipeline/pipeline/pipeline_routing_be.c
+++ b/examples/ip_pipeline/pipeline/pipeline_routing_be.c
@@ -1419,27 +1419,6 @@  pipeline_routing_free(void *pipeline)
 }
 
 static int
-pipeline_routing_track(void *pipeline,
-	__rte_unused uint32_t port_in,
-	uint32_t *port_out)
-{
-	struct pipeline *p = (struct pipeline *) pipeline;
-
-	/* Check input arguments */
-	if ((p == NULL) ||
-		(port_in >= p->n_ports_in) ||
-		(port_out == NULL))
-		return -1;
-
-	if (p->n_ports_in == 1) {
-		*port_out = 0;
-		return 0;
-	}
-
-	return -1;
-}
-
-static int
 pipeline_routing_timer(void *pipeline)
 {
 	struct pipeline *p = (struct pipeline *) pipeline;
@@ -1966,5 +1945,4 @@  struct pipeline_be_ops pipeline_routing_be_ops = {
 	.f_free = pipeline_routing_free,
 	.f_run = NULL,
 	.f_timer = pipeline_routing_timer,
-	.f_track = pipeline_routing_track,
 };
diff --git a/examples/ip_pipeline/pipeline_be.h b/examples/ip_pipeline/pipeline_be.h
index 8f858ed..5501ab7 100644
--- a/examples/ip_pipeline/pipeline_be.h
+++ b/examples/ip_pipeline/pipeline_be.h
@@ -203,6 +203,10 @@  pipeline_port_out_params_get_ops(struct pipeline_port_out_params  *p)
 #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
@@ -229,6 +233,7 @@  pipeline_port_out_params_get_ops(struct pipeline_port_out_params  *p)
 
 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];
@@ -261,16 +266,11 @@  typedef int (*pipeline_be_op_run)(void *pipeline);
 
 typedef int (*pipeline_be_op_timer)(void *pipeline);
 
-typedef int (*pipeline_be_op_track)(void *pipeline,
-	uint32_t port_in,
-	uint32_t *port_out);
-
 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_be_op_track f_track;
 };
 
 /* Pipeline specific config parse error messages */