[07/21] net/softnic: replace the legacy pipeline with the SWX pipeline

Message ID 20220804165839.1074817-8-cristian.dumitrescu@intel.com (mailing list archive)
State Superseded, archived
Delegated to: Andrew Rybchenko
Headers
Series net/softnic: replace the legacy pipeline with SWX pipeline |

Checks

Context Check Description
ci/checkpatch success coding style OK

Commit Message

Cristian Dumitrescu Aug. 4, 2022, 4:58 p.m. UTC
  Replace the legacy pipeline support with support for the SWX pipeline.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
Signed-off-by: Yogesh Jangra <yogesh.jangra@intel.com>
---
 drivers/net/softnic/meson.build               |    1 -
 drivers/net/softnic/rte_eth_softnic.c         |    6 -
 drivers/net/softnic/rte_eth_softnic_action.c  |  423 ---
 drivers/net/softnic/rte_eth_softnic_cli.c     |   16 +-
 .../net/softnic/rte_eth_softnic_internals.h   |  502 +---
 .../net/softnic/rte_eth_softnic_pipeline.c    |  988 +------
 drivers/net/softnic/rte_eth_softnic_thread.c  | 2594 +----------------
 7 files changed, 216 insertions(+), 4314 deletions(-)
 delete mode 100644 drivers/net/softnic/rte_eth_softnic_action.c
  

Patch

diff --git a/drivers/net/softnic/meson.build b/drivers/net/softnic/meson.build
index 91f1f3220f..f0cfc6dc17 100644
--- a/drivers/net/softnic/meson.build
+++ b/drivers/net/softnic/meson.build
@@ -10,7 +10,6 @@  sources = files(
         'conn.c',
         'parser.c',
         'rte_eth_softnic.c',
-        'rte_eth_softnic_action.c',
         'rte_eth_softnic_cli.c',
         'rte_eth_softnic_link.c',
         'rte_eth_softnic_mempool.c',
diff --git a/drivers/net/softnic/rte_eth_softnic.c b/drivers/net/softnic/rte_eth_softnic.c
index eb97ae7185..a940952c7a 100644
--- a/drivers/net/softnic/rte_eth_softnic.c
+++ b/drivers/net/softnic/rte_eth_softnic.c
@@ -160,8 +160,6 @@  pmd_dev_stop(struct rte_eth_dev *dev)
 	/* Firmware */
 	softnic_pipeline_disable_all(p);
 	softnic_pipeline_free(p);
-	softnic_table_action_profile_free(p);
-	softnic_port_in_action_profile_free(p);
 	softnic_link_free(p);
 	softnic_softnic_swq_free_keep_rxq_txq(p);
 	softnic_mempool_free(p);
@@ -180,8 +178,6 @@  pmd_free(struct pmd_internals *p)
 
 	softnic_thread_free(p);
 	softnic_pipeline_free(p);
-	softnic_table_action_profile_free(p);
-	softnic_port_in_action_profile_free(p);
 	softnic_link_free(p);
 	softnic_swq_free(p);
 	softnic_mempool_free(p);
@@ -261,8 +257,6 @@  pmd_init(struct pmd_params *params)
 	softnic_mempool_init(p);
 	softnic_swq_init(p);
 	softnic_link_init(p);
-	softnic_port_in_action_profile_init(p);
-	softnic_table_action_profile_init(p);
 	softnic_pipeline_init(p);
 
 	status = softnic_thread_init(p);
diff --git a/drivers/net/softnic/rte_eth_softnic_action.c b/drivers/net/softnic/rte_eth_softnic_action.c
deleted file mode 100644
index 33be9552a6..0000000000
--- a/drivers/net/softnic/rte_eth_softnic_action.c
+++ /dev/null
@@ -1,423 +0,0 @@ 
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2018 Intel Corporation
- */
-
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <rte_string_fns.h>
-#include <rte_table_hash_func.h>
-
-#include "rte_eth_softnic_internals.h"
-
-/**
- * Input port
- */
-int
-softnic_port_in_action_profile_init(struct pmd_internals *p)
-{
-	TAILQ_INIT(&p->port_in_action_profile_list);
-
-	return 0;
-}
-
-void
-softnic_port_in_action_profile_free(struct pmd_internals *p)
-{
-	for ( ; ; ) {
-		struct softnic_port_in_action_profile *profile;
-
-		profile = TAILQ_FIRST(&p->port_in_action_profile_list);
-		if (profile == NULL)
-			break;
-
-		TAILQ_REMOVE(&p->port_in_action_profile_list, profile, node);
-		free(profile);
-	}
-}
-
-struct softnic_port_in_action_profile *
-softnic_port_in_action_profile_find(struct pmd_internals *p,
-	const char *name)
-{
-	struct softnic_port_in_action_profile *profile;
-
-	if (name == NULL)
-		return NULL;
-
-	TAILQ_FOREACH(profile, &p->port_in_action_profile_list, node)
-		if (strcmp(profile->name, name) == 0)
-			return profile;
-
-	return NULL;
-}
-
-struct softnic_port_in_action_profile *
-softnic_port_in_action_profile_create(struct pmd_internals *p,
-	const char *name,
-	struct softnic_port_in_action_profile_params *params)
-{
-	struct softnic_port_in_action_profile *profile;
-	struct rte_port_in_action_profile *ap;
-	int status;
-
-	/* Check input params */
-	if (name == NULL ||
-		softnic_port_in_action_profile_find(p, 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 = rte_table_hash_crc_key8;
-			break;
-
-		case 16:
-			params->lb.f_hash = rte_table_hash_crc_key16;
-			break;
-
-		case 24:
-			params->lb.f_hash = rte_table_hash_crc_key24;
-			break;
-
-		case 32:
-			params->lb.f_hash = rte_table_hash_crc_key32;
-			break;
-
-		case 40:
-			params->lb.f_hash = rte_table_hash_crc_key40;
-			break;
-
-		case 48:
-			params->lb.f_hash = rte_table_hash_crc_key48;
-			break;
-
-		case 56:
-			params->lb.f_hash = rte_table_hash_crc_key56;
-			break;
-
-		case 64:
-			params->lb.f_hash = rte_table_hash_crc_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 softnic_port_in_action_profile));
-	if (profile == NULL) {
-		rte_port_in_action_profile_free(ap);
-		return NULL;
-	}
-
-	/* Node fill in */
-	strlcpy(profile->name, name, sizeof(profile->name));
-	memcpy(&profile->params, params, sizeof(*params));
-	profile->ap = ap;
-
-	/* Node add to list */
-	TAILQ_INSERT_TAIL(&p->port_in_action_profile_list, profile, node);
-
-	return profile;
-}
-
-/**
- * Table
- */
-int
-softnic_table_action_profile_init(struct pmd_internals *p)
-{
-	TAILQ_INIT(&p->table_action_profile_list);
-
-	return 0;
-}
-
-void
-softnic_table_action_profile_free(struct pmd_internals *p)
-{
-	for ( ; ; ) {
-		struct softnic_table_action_profile *profile;
-
-		profile = TAILQ_FIRST(&p->table_action_profile_list);
-		if (profile == NULL)
-			break;
-
-		TAILQ_REMOVE(&p->table_action_profile_list, profile, node);
-		rte_table_action_profile_free(profile->ap);
-		free(profile);
-	}
-}
-
-struct softnic_table_action_profile *
-softnic_table_action_profile_find(struct pmd_internals *p,
-	const char *name)
-{
-	struct softnic_table_action_profile *profile;
-
-	if (name == NULL)
-		return NULL;
-
-	TAILQ_FOREACH(profile, &p->table_action_profile_list, node)
-		if (strcmp(profile->name, name) == 0)
-			return profile;
-
-	return NULL;
-}
-
-struct softnic_table_action_profile *
-softnic_table_action_profile_create(struct pmd_internals *p,
-	const char *name,
-	struct softnic_table_action_profile_params *params)
-{
-	struct softnic_table_action_profile *profile;
-	struct rte_table_action_profile *ap;
-	int status;
-
-	/* Check input params */
-	if (name == NULL ||
-		softnic_table_action_profile_find(p, name) ||
-		params == NULL ||
-		((params->action_mask & (1LLU << RTE_TABLE_ACTION_FWD)) == 0))
-		return NULL;
-
-	if ((params->action_mask & (1LLU << RTE_TABLE_ACTION_LB)) &&
-		params->lb.f_hash == NULL) {
-		switch (params->lb.key_size) {
-		case 8:
-			params->lb.f_hash = rte_table_hash_crc_key8;
-			break;
-
-		case 16:
-			params->lb.f_hash = rte_table_hash_crc_key16;
-			break;
-
-		case 24:
-			params->lb.f_hash = rte_table_hash_crc_key24;
-			break;
-
-		case 32:
-			params->lb.f_hash = rte_table_hash_crc_key32;
-			break;
-
-		case 40:
-			params->lb.f_hash = rte_table_hash_crc_key40;
-			break;
-
-		case 48:
-			params->lb.f_hash = rte_table_hash_crc_key48;
-			break;
-
-		case 56:
-			params->lb.f_hash = rte_table_hash_crc_key56;
-			break;
-
-		case 64:
-			params->lb.f_hash = rte_table_hash_crc_key64;
-			break;
-
-		default:
-			return NULL;
-		}
-
-		params->lb.seed = 0;
-	}
-
-	/* 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_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,
-			&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;
-		}
-	}
-
-	if (params->action_mask & (1LLU << RTE_TABLE_ACTION_TAG)) {
-		status = rte_table_action_profile_action_register(ap,
-			RTE_TABLE_ACTION_TAG,
-			NULL);
-
-		if (status) {
-			rte_table_action_profile_free(ap);
-			return NULL;
-		}
-	}
-
-	if (params->action_mask & (1LLU << RTE_TABLE_ACTION_DECAP)) {
-		status = rte_table_action_profile_action_register(ap,
-			RTE_TABLE_ACTION_DECAP,
-			NULL);
-
-		if (status) {
-			rte_table_action_profile_free(ap);
-			return NULL;
-		}
-	}
-
-	if (params->action_mask & (1LLU << RTE_TABLE_ACTION_SYM_CRYPTO)) {
-		status = rte_table_action_profile_action_register(ap,
-			RTE_TABLE_ACTION_SYM_CRYPTO,
-			&params->sym_crypto);
-
-		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 softnic_table_action_profile));
-	if (profile == NULL) {
-		rte_table_action_profile_free(ap);
-		return NULL;
-	}
-
-	/* Node fill in */
-	strlcpy(profile->name, name, sizeof(profile->name));
-	memcpy(&profile->params, params, sizeof(*params));
-	profile->ap = ap;
-
-	/* Node add to list */
-	TAILQ_INSERT_TAIL(&p->table_action_profile_list, profile, node);
-
-	return profile;
-}
diff --git a/drivers/net/softnic/rte_eth_softnic_cli.c b/drivers/net/softnic/rte_eth_softnic_cli.c
index abe275ec83..2b00b65c6c 100644
--- a/drivers/net/softnic/rte_eth_softnic_cli.c
+++ b/drivers/net/softnic/rte_eth_softnic_cli.c
@@ -196,6 +196,7 @@  cmd_softnic_thread_pipeline_enable(struct pmd_internals *softnic,
 	size_t out_size)
 {
 	char *pipeline_name;
+	struct pipeline *p;
 	uint32_t thread_id;
 	int status;
 
@@ -215,13 +216,18 @@  cmd_softnic_thread_pipeline_enable(struct pmd_internals *softnic,
 	}
 
 	pipeline_name = tokens[3];
+	p = softnic_pipeline_find(softnic, pipeline_name);
+	if (!p) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
+		return;
+	}
 
 	if (strcmp(tokens[4], "enable") != 0) {
 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable");
 		return;
 	}
 
-	status = softnic_thread_pipeline_enable(softnic, thread_id, pipeline_name);
+	status = softnic_thread_pipeline_enable(softnic, thread_id, p);
 	if (status) {
 		snprintf(out, out_size, MSG_CMD_FAIL, "thread pipeline enable");
 		return;
@@ -239,6 +245,7 @@  cmd_softnic_thread_pipeline_disable(struct pmd_internals *softnic,
 	size_t out_size)
 {
 	char *pipeline_name;
+	struct pipeline *p;
 	uint32_t thread_id;
 	int status;
 
@@ -258,13 +265,18 @@  cmd_softnic_thread_pipeline_disable(struct pmd_internals *softnic,
 	}
 
 	pipeline_name = tokens[3];
+	p = softnic_pipeline_find(softnic, pipeline_name);
+	if (!p) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name");
+		return;
+	}
 
 	if (strcmp(tokens[4], "disable") != 0) {
 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable");
 		return;
 	}
 
-	status = softnic_thread_pipeline_disable(softnic, thread_id, pipeline_name);
+	status = softnic_thread_pipeline_disable(softnic, thread_id, p);
 	if (status) {
 		snprintf(out, out_size, MSG_CMD_FAIL,
 			"thread pipeline disable");
diff --git a/drivers/net/softnic/rte_eth_softnic_internals.h b/drivers/net/softnic/rte_eth_softnic_internals.h
index df74c1fbdc..d817883a39 100644
--- a/drivers/net/softnic/rte_eth_softnic_internals.h
+++ b/drivers/net/softnic/rte_eth_softnic_internals.h
@@ -13,9 +13,8 @@ 
 #include <rte_mbuf.h>
 #include <rte_ring.h>
 #include <rte_ethdev.h>
-#include <rte_port_in_action.h>
-#include <rte_table_action.h>
-#include <rte_pipeline.h>
+#include <rte_swx_pipeline.h>
+#include <rte_swx_ctl.h>
 
 #include <rte_ethdev_core.h>
 #include <ethdev_driver.h>
@@ -89,207 +88,18 @@  struct softnic_link {
 
 TAILQ_HEAD(softnic_link_list, softnic_link);
 
-/**
- * Input port action
- */
-struct softnic_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 softnic_port_in_action_profile {
-	TAILQ_ENTRY(softnic_port_in_action_profile) node;
-	char name[NAME_SIZE];
-	struct softnic_port_in_action_profile_params params;
-	struct rte_port_in_action_profile *ap;
-};
-
-TAILQ_HEAD(softnic_port_in_action_profile_list, softnic_port_in_action_profile);
-
-/**
- * Table action
- */
-struct softnic_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;
-	struct rte_table_action_nat_config nat;
-	struct rte_table_action_ttl_config ttl;
-	struct rte_table_action_stats_config stats;
-	struct rte_table_action_sym_crypto_config sym_crypto;
-};
-
-struct softnic_table_action_profile {
-	TAILQ_ENTRY(softnic_table_action_profile) node;
-	char name[NAME_SIZE];
-	struct softnic_table_action_profile_params params;
-	struct rte_table_action_profile *ap;
-};
-
-TAILQ_HEAD(softnic_table_action_profile_list, softnic_table_action_profile);
-
-struct softnic_table_meter_profile {
-	TAILQ_ENTRY(softnic_table_meter_profile) node;
-	uint32_t meter_profile_id;
-	struct rte_table_action_meter_profile profile;
-};
-
-TAILQ_HEAD(softnic_table_meter_profile_list,
-	softnic_table_meter_profile);
-
 /**
  * Pipeline
  */
-struct pipeline_params {
-	uint32_t timer_period_ms;
-	uint32_t offset_port_id;
-};
-
-enum softnic_port_in_type {
-	PORT_IN_RXQ,
-	PORT_IN_SWQ,
-	PORT_IN_SOURCE,
-};
-
-struct softnic_port_in_params {
-	/* Read */
-	enum softnic_port_in_type type;
-	char dev_name[NAME_SIZE];
-	union {
-		struct {
-			uint16_t queue_id;
-		} rxq;
-
-		struct {
-			const char *mempool_name;
-			const char *file_name;
-			uint32_t n_bytes_per_pkt;
-		} source;
-	};
-	uint32_t burst_size;
-
-	/* Action */
-	char action_profile_name[NAME_SIZE];
-};
-
-enum softnic_port_out_type {
-	PORT_OUT_TXQ,
-	PORT_OUT_SWQ,
-	PORT_OUT_SINK,
-};
-
-struct softnic_port_out_params {
-	enum softnic_port_out_type type;
-	char dev_name[NAME_SIZE];
-	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 softnic_table_type {
-	TABLE_ACL,
-	TABLE_ARRAY,
-	TABLE_HASH,
-	TABLE_LPM,
-	TABLE_STUB,
-};
-
-struct softnic_table_acl_params {
-	uint32_t n_rules;
-	uint32_t ip_header_offset;
-	int ip_version;
-};
-
-struct softnic_table_array_params {
-	uint32_t n_keys;
-	uint32_t key_offset;
-};
-
-#ifndef TABLE_RULE_MATCH_SIZE_MAX
-#define TABLE_RULE_MATCH_SIZE_MAX                          256
-#endif
-
-struct softnic_table_hash_params {
-	uint32_t n_keys;
-	uint32_t key_offset;
-	uint32_t key_size;
-	uint8_t key_mask[TABLE_RULE_MATCH_SIZE_MAX];
-	uint32_t n_buckets;
-	int extendable_bucket;
-};
-
-struct softnic_table_lpm_params {
-	uint32_t n_rules;
-	uint32_t key_offset;
-	uint32_t key_size;
-};
-
-struct softnic_table_params {
-	/* Match */
-	enum softnic_table_type match_type;
-	union {
-		struct softnic_table_acl_params acl;
-		struct softnic_table_array_params array;
-		struct softnic_table_hash_params hash;
-		struct softnic_table_lpm_params lpm;
-	} match;
-
-	/* Action */
-	char action_profile_name[NAME_SIZE];
-};
-
-struct softnic_port_in {
-	struct softnic_port_in_params params;
-	struct softnic_port_in_action_profile *ap;
-	struct rte_port_in_action *a;
-};
-
-struct softnic_port_out {
-	struct softnic_port_out_params params;
-};
-
-struct softnic_table {
-	struct softnic_table_params params;
-	struct softnic_table_action_profile *ap;
-	struct rte_table_action *a;
-	struct rte_table_action_dscp_table dscp_table;
-	struct softnic_table_meter_profile_list meter_profiles;
-};
-
 struct pipeline {
 	TAILQ_ENTRY(pipeline) node;
 	char name[NAME_SIZE];
 
-	struct rte_pipeline *p;
-	struct pipeline_params params;
-	struct softnic_port_in port_in[RTE_PIPELINE_PORT_IN_MAX];
-	struct softnic_port_out port_out[RTE_PIPELINE_PORT_OUT_MAX];
-	struct softnic_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;
+	struct rte_swx_pipeline *p;
+	struct rte_swx_ctl_pipeline *ctl;
 
 	int enabled;
 	uint32_t thread_id;
-	uint32_t cpu_id;
 };
 
 TAILQ_HEAD(pipeline_list, pipeline);
@@ -309,6 +119,15 @@  TAILQ_HEAD(pipeline_list, pipeline);
 #define THREAD_TIMER_PERIOD_MS                             100
 #endif
 
+/* Pipeline instruction quanta: Needs to be big enough to do some meaningful
+ * work, but not too big to avoid starving any other pipelines mapped to the
+ * same thread. For a pipeline that executes 10 instructions per packet, a
+ * quanta of 1000 instructions equates to processing 100 packets.
+ */
+#ifndef PIPELINE_INSTR_QUANTA
+#define PIPELINE_INSTR_QUANTA                              1000
+#endif
+
 /**
  * Main thread: data plane thread context
  */
@@ -322,37 +141,14 @@  struct softnic_thread {
 /**
  * Data plane threads: context
  */
-#ifndef TABLE_RULE_ACTION_SIZE_MAX
-#define TABLE_RULE_ACTION_SIZE_MAX                         2048
-#endif
-
-struct softnic_table_data {
-	struct rte_table_action *a;
-};
-
-struct pipeline_data {
-	struct rte_pipeline *p;
-	struct softnic_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 softnic_thread_data {
-	struct rte_pipeline *p[THREAD_PIPELINES_MAX];
+	struct rte_swx_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;
 	uint64_t iter;
 } __rte_cache_aligned;
 
@@ -367,8 +163,6 @@  struct pmd_internals {
 	struct softnic_mempool_list mempool_list;
 	struct softnic_swq_list swq_list;
 	struct softnic_link_list link_list;
-	struct softnic_port_in_action_profile_list port_in_action_profile_list;
-	struct softnic_table_action_profile_list table_action_profile_list;
 	struct pipeline_list pipeline_list;
 	struct softnic_thread thread[RTE_MAX_LCORE];
 	struct softnic_thread_data thread_data[RTE_MAX_LCORE];
@@ -447,42 +241,6 @@  softnic_link_create(struct pmd_internals *p,
 	const char *name,
 	struct softnic_link_params *params);
 
-/**
- * Input port action
- */
-int
-softnic_port_in_action_profile_init(struct pmd_internals *p);
-
-void
-softnic_port_in_action_profile_free(struct pmd_internals *p);
-
-struct softnic_port_in_action_profile *
-softnic_port_in_action_profile_find(struct pmd_internals *p,
-	const char *name);
-
-struct softnic_port_in_action_profile *
-softnic_port_in_action_profile_create(struct pmd_internals *p,
-	const char *name,
-	struct softnic_port_in_action_profile_params *params);
-
-/**
- * Table action
- */
-int
-softnic_table_action_profile_init(struct pmd_internals *p);
-
-void
-softnic_table_action_profile_free(struct pmd_internals *p);
-
-struct softnic_table_action_profile *
-softnic_table_action_profile_find(struct pmd_internals *p,
-	const char *name);
-
-struct softnic_table_action_profile *
-softnic_table_action_profile_create(struct pmd_internals *p,
-	const char *name,
-	struct softnic_table_action_profile_params *params);
-
 /**
  * Pipeline
  */
@@ -504,228 +262,9 @@  softnic_pipeline_find(struct pmd_internals *p, const char *name);
 struct pipeline *
 softnic_pipeline_create(struct pmd_internals *p,
 	const char *name,
-	struct pipeline_params *params);
-
-int
-softnic_pipeline_port_in_create(struct pmd_internals *p,
-	const char *pipeline_name,
-	struct softnic_port_in_params *params,
-	int enabled);
-
-int
-softnic_pipeline_port_in_connect_to_table(struct pmd_internals *p,
-	const char *pipeline_name,
-	uint32_t port_id,
-	uint32_t table_id);
-
-int
-softnic_pipeline_port_out_create(struct pmd_internals *p,
-	const char *pipeline_name,
-	struct softnic_port_out_params *params);
-
-int
-softnic_pipeline_port_out_find(struct pmd_internals *softnic,
-		const char *pipeline_name,
-		const char *name,
-		uint32_t *port_id);
-
-int
-softnic_pipeline_table_create(struct pmd_internals *p,
-	const char *pipeline_name,
-	struct softnic_table_params *params);
-
-struct softnic_table_meter_profile *
-softnic_pipeline_table_meter_profile_find(struct softnic_table *table,
-	uint32_t meter_profile_id);
-
-struct softnic_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 softnic_table_rule_match_array {
-	uint32_t pos;
-};
-
-struct softnic_table_rule_match_hash {
-	uint8_t key[TABLE_RULE_MATCH_SIZE_MAX];
-};
-
-struct softnic_table_rule_match_lpm {
-	int ip_version;
-
-	RTE_STD_C11
-	union {
-		uint32_t ipv4;
-		uint8_t ipv6[16];
-	};
-
-	uint8_t depth;
-};
-
-struct softnic_table_rule_match {
-	enum softnic_table_type match_type;
-
-	union {
-		struct softnic_table_rule_match_acl acl;
-		struct softnic_table_rule_match_array array;
-		struct softnic_table_rule_match_hash hash;
-		struct softnic_table_rule_match_lpm lpm;
-	} match;
-};
-
-#ifndef SYM_CRYPTO_MAX_KEY_SIZE
-#define SYM_CRYPTO_MAX_KEY_SIZE		(256)
-#endif
-struct softnic_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;
-	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;
-	struct rte_table_action_tag_params tag;
-	struct rte_table_action_decap_params decap;
-	struct rte_table_action_sym_crypto_params sym_crypto;
-	uint8_t sym_crypto_key[SYM_CRYPTO_MAX_KEY_SIZE];
-};
-
-int
-softnic_pipeline_port_in_stats_read(struct pmd_internals *p,
-	const char *pipeline_name,
-	uint32_t port_id,
-	struct rte_pipeline_port_in_stats *stats,
-	int clear);
-
-int
-softnic_pipeline_port_in_enable(struct pmd_internals *p,
-	const char *pipeline_name,
-	uint32_t port_id);
-
-int
-softnic_pipeline_port_in_disable(struct pmd_internals *p,
-	const char *pipeline_name,
-	uint32_t port_id);
-
-int
-softnic_pipeline_port_out_stats_read(struct pmd_internals *p,
-	const char *pipeline_name,
-	uint32_t port_id,
-	struct rte_pipeline_port_out_stats *stats,
-	int clear);
-
-int
-softnic_pipeline_table_stats_read(struct pmd_internals *p,
-	const char *pipeline_name,
-	uint32_t table_id,
-	struct rte_pipeline_table_stats *stats,
-	int clear);
-
-int
-softnic_pipeline_table_rule_add(struct pmd_internals *p,
-	const char *pipeline_name,
-	uint32_t table_id,
-	struct softnic_table_rule_match *match,
-	struct softnic_table_rule_action *action,
-	void **data);
-
-int
-softnic_pipeline_table_rule_add_bulk(struct pmd_internals *p,
-	const char *pipeline_name,
-	uint32_t table_id,
-	struct softnic_table_rule_match *match,
-	struct softnic_table_rule_action *action,
-	void **data,
-	uint32_t *n_rules);
-
-int
-softnic_pipeline_table_rule_add_default(struct pmd_internals *p,
-	const char *pipeline_name,
-	uint32_t table_id,
-	struct softnic_table_rule_action *action,
-	void **data);
-
-int
-softnic_pipeline_table_rule_delete(struct pmd_internals *p,
-	const char *pipeline_name,
-	uint32_t table_id,
-	struct softnic_table_rule_match *match);
-
-int
-softnic_pipeline_table_rule_delete_default(struct pmd_internals *p,
-	const char *pipeline_name,
-	uint32_t table_id);
-
-int
-softnic_pipeline_table_rule_stats_read(struct pmd_internals *p,
-	const char *pipeline_name,
-	uint32_t table_id,
-	void *data,
-	struct rte_table_action_stats_counters *stats,
-	int clear);
-
-int
-softnic_pipeline_table_mtr_profile_add(struct pmd_internals *p,
-	const char *pipeline_name,
-	uint32_t table_id,
-	uint32_t meter_profile_id,
-	struct rte_table_action_meter_profile *profile);
-
-int
-softnic_pipeline_table_mtr_profile_delete(struct pmd_internals *p,
-	const char *pipeline_name,
-	uint32_t table_id,
-	uint32_t meter_profile_id);
-
-int
-softnic_pipeline_table_rule_mtr_read(struct pmd_internals *p,
-	const char *pipeline_name,
-	uint32_t table_id,
-	void *data,
-	uint32_t tc_mask,
-	struct rte_table_action_mtr_counters *stats,
-	int clear);
-
-int
-softnic_pipeline_table_dscp_table_update(struct pmd_internals *p,
-	const char *pipeline_name,
-	uint32_t table_id,
-	uint64_t dscp_mask,
-	struct rte_table_action_dscp_table *dscp_table);
-
-int
-softnic_pipeline_table_rule_ttl_read(struct pmd_internals *p,
-	const char *pipeline_name,
-	uint32_t table_id,
-	void *data,
-	struct rte_table_action_ttl_counters *stats,
-	int clear);
+	const char *lib_file_name,
+	const char *iospec_file_name,
+	int numa_node);
 
 /**
  * Thread
@@ -739,12 +278,15 @@  softnic_thread_free(struct pmd_internals *p);
 int
 softnic_thread_pipeline_enable(struct pmd_internals *p,
 	uint32_t thread_id,
-	const char *pipeline_name);
+	struct pipeline *pipeline);
 
 int
 softnic_thread_pipeline_disable(struct pmd_internals *p,
 	uint32_t thread_id,
-	const char *pipeline_name);
+	struct pipeline *pipeline);
+
+void
+softnic_thread_pipeline_disable_all(struct pmd_internals *p);
 
 /**
  * CLI
diff --git a/drivers/net/softnic/rte_eth_softnic_pipeline.c b/drivers/net/softnic/rte_eth_softnic_pipeline.c
index 7a2828b785..76570b2cb3 100644
--- a/drivers/net/softnic/rte_eth_softnic_pipeline.c
+++ b/drivers/net/softnic/rte_eth_softnic_pipeline.c
@@ -6,35 +6,10 @@ 
 #include <string.h>
 
 #include <rte_common.h>
-#include <rte_ip.h>
-#include <rte_tcp.h>
-
 #include <rte_string_fns.h>
-#include <rte_port_ethdev.h>
-#include <rte_port_ring.h>
-#include <rte_port_source_sink.h>
-#include <rte_port_fd.h>
-#include <rte_port_sched.h>
-#include <rte_port_sym_crypto.h>
-
-#include <rte_table_acl.h>
-#include <rte_table_array.h>
-#include <rte_table_hash.h>
-#include <rte_table_hash_func.h>
-#include <rte_table_lpm.h>
-#include <rte_table_lpm_ipv6.h>
-#include <rte_table_stub.h>
 
 #include "rte_eth_softnic_internals.h"
 
-#ifndef PIPELINE_MSGQ_SIZE
-#define PIPELINE_MSGQ_SIZE                                 64
-#endif
-
-#ifndef TABLE_LPM_NUMBER_TBL8
-#define TABLE_LPM_NUMBER_TBL8                              256
-#endif
-
 int
 softnic_pipeline_init(struct pmd_internals *p)
 {
@@ -43,44 +18,19 @@  softnic_pipeline_init(struct pmd_internals *p)
 	return 0;
 }
 
-static void
-softnic_pipeline_table_free(struct softnic_table *table)
-{
-	for ( ; ; ) {
-		struct softnic_table_meter_profile *mp;
-
-		mp = TAILQ_FIRST(&table->meter_profiles);
-		if (mp == NULL)
-			break;
-
-		TAILQ_REMOVE(&table->meter_profiles, mp, node);
-		free(mp);
-	}
-}
-
 void
 softnic_pipeline_free(struct pmd_internals *p)
 {
 	for ( ; ; ) {
 		struct pipeline *pipeline;
-		uint32_t table_id;
 
 		pipeline = TAILQ_FIRST(&p->pipeline_list);
 		if (pipeline == NULL)
 			break;
 
 		TAILQ_REMOVE(&p->pipeline_list, pipeline, node);
-
-		for (table_id = 0; table_id < pipeline->n_tables; table_id++) {
-			struct softnic_table *table =
-				&pipeline->table[table_id];
-
-			softnic_pipeline_table_free(table);
-		}
-
-		rte_ring_free(pipeline->msgq_req);
-		rte_ring_free(pipeline->msgq_rsp);
-		rte_pipeline_free(pipeline->p);
+		rte_swx_ctl_pipeline_free(pipeline->ctl);
+		rte_swx_pipeline_free(pipeline->p);
 		free(pipeline);
 	}
 }
@@ -94,7 +44,7 @@  softnic_pipeline_disable_all(struct pmd_internals *p)
 		if (pipeline->enabled)
 			softnic_thread_pipeline_disable(p,
 				pipeline->thread_id,
-				pipeline->name);
+				pipeline);
 }
 
 uint32_t
@@ -126,850 +76,170 @@  softnic_pipeline_find(struct pmd_internals *p,
 	return NULL;
 }
 
-struct pipeline *
-softnic_pipeline_create(struct pmd_internals *softnic,
-	const char *name,
-	struct pipeline_params *params)
-{
-	char resource_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 ||
-		softnic_pipeline_find(softnic, name) ||
-		params == NULL ||
-		params->timer_period_ms == 0)
-		return NULL;
-
-	/* Resource create */
-	snprintf(resource_name, sizeof(resource_name), "%s-%s-REQ",
-		softnic->params.name,
-		name);
-
-	msgq_req = rte_ring_create(resource_name,
-		PIPELINE_MSGQ_SIZE,
-		softnic->params.cpu_id,
-		RING_F_SP_ENQ | RING_F_SC_DEQ);
-	if (msgq_req == NULL)
-		return NULL;
-
-	snprintf(resource_name, sizeof(resource_name), "%s-%s-RSP",
-		softnic->params.name,
-		name);
-
-	msgq_rsp = rte_ring_create(resource_name,
-		PIPELINE_MSGQ_SIZE,
-		softnic->params.cpu_id,
-		RING_F_SP_ENQ | RING_F_SC_DEQ);
-	if (msgq_rsp == NULL) {
-		rte_ring_free(msgq_req);
-		return NULL;
-	}
-
-	snprintf(resource_name, sizeof(resource_name), "%s_%s",
-		softnic->params.name,
-		name);
-
-	pp.name = resource_name;
-	pp.socket_id = (int)softnic->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 */
-	strlcpy(pipeline->name, name, sizeof(pipeline->name));
-	pipeline->p = p;
-	memcpy(&pipeline->params, params, sizeof(*params));
-	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 = softnic->params.cpu_id;
-
-	/* Node add to list */
-	TAILQ_INSERT_TAIL(&softnic->pipeline_list, pipeline, node);
-
-	return pipeline;
-}
+#ifndef MAX_LINE_LENGTH
+#define MAX_LINE_LENGTH 2048
+#endif
 
-int
-softnic_pipeline_port_in_create(struct pmd_internals *softnic,
-	const char *pipeline_name,
-	struct softnic_port_in_params *params,
-	int enabled)
+/* The Soft NIC device internal resources such as mempools, rings or pipelines are globally visible,
+ * hence they need to have globally unique names. In order to apply the same configuration scripts
+ * unmodified to all the Soft NIC devices that instantiate the same program, the pipeline I/O
+ * configuration files are silently translated internally to prefix the name of the above resources
+ * with the Soft NIC device name, thus making the resource names globally unique.
+ */
+static int
+iospec_translate(struct pmd_internals *softnic __rte_unused,
+		 const char *file_in_name,
+		 const char *file_out_name)
 {
-	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_source_params source;
-	} pp;
+	FILE *fi = NULL, *fo = NULL;
+	char *line = NULL;
+	int status = 0;
 
-	struct pipeline *pipeline;
-	struct softnic_port_in *port_in;
-	struct softnic_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 = softnic_pipeline_find(softnic, pipeline_name);
-	if (pipeline == NULL)
-		return -1;
-
-	ap = NULL;
-	if (strlen(params->action_profile_name)) {
-		ap = softnic_port_in_action_profile_find(softnic,
-			params->action_profile_name);
-		if (ap == NULL)
-			return -1;
+	/* File open. */
+	fi = fopen(file_in_name, "r");
+	fo = fopen(file_out_name, "w");
+	if (!fi || !fo) {
+		status = -EIO;
+		goto free;
 	}
 
-	switch (params->type) {
-	case PORT_IN_RXQ:
-	{
-		struct softnic_link *link;
-
-		link = softnic_link_find(softnic, 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;
+	/* Memory allocation. */
+	line = malloc(MAX_LINE_LENGTH);
+	if (!line) {
+		status = -ENOMEM;
+		goto free;
 	}
 
-	case PORT_IN_SWQ:
-	{
-		struct softnic_swq *swq;
-
-		swq = softnic_swq_find(softnic, 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;
-	}
+	/* Read from the input file and write to the output file. */
+	for ( ; ; ) {
+		char *ptr = line;
+		uint32_t n_tokens;
+		int flag = 0;
 
-	case PORT_IN_SOURCE:
-	{
-		struct softnic_mempool *mempool;
+		/* Read next line. */
+		if (!fgets(line, MAX_LINE_LENGTH, fi))
+			break;
 
-		mempool = softnic_mempool_find(softnic, params->source.mempool_name);
-		if (mempool == NULL)
-			return -1;
+		/* Parse the line into tokens. */
+		for (n_tokens = 0; ; n_tokens++) {
+			char *token;
 
-		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;
+			/* Read token. */
+			token = strtok_r(ptr, " \f\n\r\t\v", &ptr);
+			if (!token)
+				break;
 
-		p.ops = &rte_port_source_ops;
-		p.arg_create = &pp.source;
-		break;
-	}
+			/* Handle comments. */
+			if (!n_tokens &&
+			    ((token[0] == '#') ||
+			     (token[0] == ';') ||
+			     ((token[0] == '/') && (token[1] == '/'))))
+				break;
 
-	default:
-		return -1;
-	}
+			/* Process token. */
+			if (flag) {
+				fprintf(fo, "%s_%s ", softnic->params.name, token);
+				flag = 0;
+				continue;
+			}
 
-	p.burst_size = params->burst_size;
+			if (!strcmp(token, "mempool") ||
+			    !strcmp(token, "ring")) {
+				flag = 1;
+				fprintf(fo, "%s ", token);
+				continue;
+			}
 
-	/* Resource create */
-	action = NULL;
-	p.f_action = NULL;
-	p.arg_ah = NULL;
-
-	if (ap) {
-		action = rte_port_in_action_create(ap->ap,
-			softnic->params.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;
+			/* Default action: write token. */
+			fprintf(fo, "%s ", token);
 		}
-	}
-
-	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
-softnic_pipeline_port_in_connect_to_table(struct pmd_internals *softnic,
-	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;
+		/* Handle empty or comment lines. */
+		if (!n_tokens)
+			continue;
 
-	pipeline = softnic_pipeline_find(softnic, pipeline_name);
-	if (pipeline == NULL ||
-		port_id >= pipeline->n_ports_in ||
-		table_id >= pipeline->n_tables)
-		return -1;
+		/* Write newline. */
+		fprintf(fo, "\n");
+	}
 
-	/* Resource */
-	status = rte_pipeline_port_in_connect_to_table(pipeline->p,
-		port_id,
-		table_id);
+free:
+	/* Memory free. */
+	free(line);
 
+	/* File close. */
+	if (fi)
+		fclose(fi);
+	if (fo)
+		fclose(fo);
 	return status;
 }
 
-int
-softnic_pipeline_port_out_create(struct pmd_internals *softnic,
-	const char *pipeline_name,
-	struct softnic_port_out_params *params)
+struct pipeline *
+softnic_pipeline_create(struct pmd_internals *softnic,
+	const char *name,
+	const char *lib_file_name,
+	const char *iospec_file_name,
+	int numa_node)
 {
-	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_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;
-	} pp_nodrop;
-
-	struct pipeline *pipeline;
-	struct softnic_port_out *port_out;
-	uint32_t port_id;
-	int status;
-
-	memset(&p, 0, sizeof(p));
-	memset(&pp, 0, sizeof(pp));
-	memset(&pp_nodrop, 0, sizeof(pp_nodrop));
+	char global_name[NAME_MAX];
+	FILE *iospec_file = NULL;
+	struct pipeline *pipeline = NULL;
+	struct rte_swx_pipeline *p = NULL;
+	struct rte_swx_ctl_pipeline *ctl = NULL;
+	int status = 0;
 
 	/* 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 = softnic_pipeline_find(softnic, pipeline_name);
-	if (pipeline == NULL)
-		return -1;
-
-	switch (params->type) {
-	case PORT_OUT_TXQ:
-	{
-		struct softnic_link *link;
-
-		link = softnic_link_find(softnic, 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 softnic_swq *swq;
-
-		swq = softnic_swq_find(softnic, 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_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;
+	if (!name || !name[0] || softnic_pipeline_find(softnic, name))
+		goto error;
 
 	/* Resource create */
-	status = rte_pipeline_port_out_create(pipeline->p,
-		&p,
-		&port_id);
+	snprintf(global_name, sizeof(global_name), "/tmp/%s_%s.io", softnic->params.name, name);
 
+	status = iospec_translate(softnic, iospec_file_name, global_name);
 	if (status)
-		return -1;
-
-	/* Pipeline */
-	port_out = &pipeline->port_out[pipeline->n_ports_out];
-	memcpy(&port_out->params, params, sizeof(*params));
-	pipeline->n_ports_out++;
-
-	return 0;
-}
+		goto error;
 
-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 rte_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 rte_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 rte_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 rte_ipv4_hdr) +
-			offsetof(struct rte_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 rte_ipv4_hdr) +
-			offsetof(struct rte_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 rte_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 rte_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 rte_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 rte_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 rte_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 rte_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 rte_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 rte_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 rte_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 rte_ipv6_hdr) +
-			offsetof(struct rte_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 rte_ipv6_hdr) +
-			offsetof(struct rte_tcp_hdr, dst_port),
-	},
-};
-
-int
-softnic_pipeline_table_create(struct pmd_internals *softnic,
-	const char *pipeline_name,
-	struct softnic_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 softnic_table *table;
-	struct softnic_table_action_profile *ap;
-	struct rte_table_action *action;
-	uint32_t table_id;
-	int status;
+	iospec_file = fopen(global_name, "r");
+	if (!iospec_file)
+		goto error;
 
-	memset(&p, 0, sizeof(p));
-	memset(&pp, 0, sizeof(pp));
-
-	/* Check input params */
-	if (pipeline_name == NULL ||
-		params == NULL)
-		return -1;
-
-	pipeline = softnic_pipeline_find(softnic, pipeline_name);
-	if (pipeline == NULL ||
-		pipeline->n_tables >= RTE_PIPELINE_TABLE_MAX)
-		return -1;
-
-	ap = NULL;
-	if (strlen(params->action_profile_name)) {
-		ap = softnic_table_action_profile_find(softnic,
-			params->action_profile_name);
-		if (ap == NULL)
-			return -1;
-	}
-
-	snprintf(name, NAME_MAX, "%s_%s_table%u",
-		softnic->params.name, 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 = rte_table_hash_crc_key8;
-			break;
-		case 16:
-			f_hash = rte_table_hash_crc_key16;
-			break;
-		case 24:
-			f_hash = rte_table_hash_crc_key24;
-			break;
-		case 32:
-			f_hash = rte_table_hash_crc_key32;
-			break;
-		case 40:
-			f_hash = rte_table_hash_crc_key40;
-			break;
-		case 48:
-			f_hash = rte_table_hash_crc_key48;
-			break;
-		case 56:
-			f_hash = rte_table_hash_crc_key56;
-			break;
-		case 64:
-			f_hash = rte_table_hash_crc_key64;
-			break;
-		default:
-			return -1;
-		}
+	snprintf(global_name, sizeof(global_name), "%s_%s", softnic->params.name, name);
 
-		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,
-			softnic->params.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;
-	}
+	status = rte_swx_pipeline_build_from_lib(&p,
+						 global_name,
+						 lib_file_name,
+						 iospec_file,
+						 numa_node);
+	if (status)
+		goto error;
 
-	/* Pipeline */
-	table = &pipeline->table[pipeline->n_tables];
-	memcpy(&table->params, params, sizeof(*params));
-	table->ap = ap;
-	table->a = action;
-	TAILQ_INIT(&table->meter_profiles);
-	memset(&table->dscp_table, 0, sizeof(table->dscp_table));
-	pipeline->n_tables++;
+	fclose(iospec_file);
+	iospec_file = NULL;
 
-	return 0;
-}
+	ctl = rte_swx_ctl_pipeline_create(p);
+	if (!ctl)
+		goto error;
 
-int
-softnic_pipeline_port_out_find(struct pmd_internals *softnic,
-		const char *pipeline_name,
-		const char *name,
-		uint32_t *port_id)
-{
-	struct pipeline *pipeline;
-	uint32_t i;
-
-	if (softnic == NULL ||
-			pipeline_name == NULL ||
-			name == NULL ||
-			port_id == NULL)
-		return -1;
-
-	pipeline = softnic_pipeline_find(softnic, pipeline_name);
-	if (pipeline == NULL)
-		return -1;
-
-	for (i = 0; i < pipeline->n_ports_out; i++)
-		if (strcmp(pipeline->port_out[i].params.dev_name, name) == 0) {
-			*port_id = i;
-			return 0;
-		}
+	/* Node allocation */
+	pipeline = calloc(1, sizeof(struct pipeline));
+	if (!pipeline)
+		goto error;
 
-	return -1;
-}
+	/* Node fill in */
+	strlcpy(pipeline->name, name, sizeof(pipeline->name));
+	pipeline->p = p;
+	pipeline->ctl = ctl;
 
-struct softnic_table_meter_profile *
-softnic_pipeline_table_meter_profile_find(struct softnic_table *table,
-	uint32_t meter_profile_id)
-{
-	struct softnic_table_meter_profile *mp;
+	/* Node add to list */
+	TAILQ_INSERT_TAIL(&softnic->pipeline_list, pipeline, node);
 
-	TAILQ_FOREACH(mp, &table->meter_profiles, node)
-		if (mp->meter_profile_id == meter_profile_id)
-			return mp;
+	return pipeline;
 
+error:
+	free(pipeline);
+	rte_swx_ctl_pipeline_free(ctl);
+	rte_swx_pipeline_free(p);
+	if (iospec_file)
+		fclose(iospec_file);
 	return NULL;
 }
diff --git a/drivers/net/softnic/rte_eth_softnic_thread.c b/drivers/net/softnic/rte_eth_softnic_thread.c
index ec8bef4694..888af6caf4 100644
--- a/drivers/net/softnic/rte_eth_softnic_thread.c
+++ b/drivers/net/softnic/rte_eth_softnic_thread.c
@@ -10,11 +10,6 @@ 
 #include <rte_service_component.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 "rte_eth_softnic_internals.h"
 
 /**
@@ -88,7 +83,6 @@  softnic_thread_init(struct pmd_internals *softnic)
 		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;
@@ -97,6 +91,9 @@  softnic_thread_init(struct pmd_internals *softnic)
 static inline int
 thread_is_valid(struct pmd_internals *softnic, uint32_t thread_id)
 {
+	if (thread_id >= RTE_MAX_LCORE)
+		return 0; /* FALSE */
+
 	if (thread_id == rte_get_main_lcore())
 		return 0; /* FALSE */
 
@@ -190,18 +187,22 @@  thread_sc_service_down(struct pmd_internals *softnic, uint32_t thread_id)
 	t->service_id = UINT32_MAX;
 }
 
-/**
- * Pipeline is running when:
- *    (A) Pipeline is mapped to a data plane thread AND
- *    (B) Its data plane thread is in RUNNING state.
- */
-static inline int
-pipeline_is_running(struct pipeline *p)
+void
+softnic_thread_pipeline_disable_all(struct pmd_internals *softnic)
 {
-	if (p->enabled == 0)
-		return 0;
+	uint32_t thread_id;
 
-	return thread_is_running(p->thread_id);
+	for (thread_id = 0; thread_id < RTE_MAX_LCORE; thread_id++) {
+		struct softnic_thread_data *td = &softnic->thread_data[thread_id];
+
+		if (!thread_is_valid(softnic, thread_id))
+			continue;
+
+		if (softnic->params.sc && td->n_pipelines)
+			thread_sc_service_down(softnic, thread_id);
+
+		td->n_pipelines = 0;
+	}
 }
 
 /**
@@ -218,18 +219,11 @@  struct thread_msg_req {
 
 	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;
+			struct rte_swx_pipeline *p;
 		} pipeline_enable;
 
 		struct {
-			struct rte_pipeline *p;
+			struct rte_swx_pipeline *p;
 		} pipeline_disable;
 	};
 };
@@ -283,20 +277,16 @@  thread_msg_send_recv(struct pmd_internals *softnic,
 int
 softnic_thread_pipeline_enable(struct pmd_internals *softnic,
 	uint32_t thread_id,
-	const char *pipeline_name)
+	struct pipeline *p)
 {
-	struct pipeline *p = softnic_pipeline_find(softnic, pipeline_name);
 	struct thread_msg_req *req;
 	struct thread_msg_rsp *rsp;
-	uint32_t n_pipelines, i;
+	uint32_t n_pipelines;
 	int status;
 
 	/* Check input params */
 	if (!thread_is_valid(softnic, thread_id) ||
 		(p == NULL) ||
-		(p->n_ports_in == 0) ||
-		(p->n_ports_out == 0) ||
-		(p->n_tables == 0) ||
 		p->enabled)
 		return -1;
 
@@ -312,22 +302,9 @@  softnic_thread_pipeline_enable(struct pmd_internals *softnic,
 
 	if (!thread_is_running(thread_id)) {
 		struct softnic_thread_data *td = &softnic->thread_data[thread_id];
-		struct pipeline_data *tdp = &td->pipeline_data[td->n_pipelines];
 
 		/* Data plane thread */
 		td->p[td->n_pipelines] = p->p;
-
-		tdp->p = p->p;
-		for (i = 0; i < p->n_tables; i++)
-			tdp->table_data[i].a =
-				p->table[i].a;
-		tdp->n_tables = p->n_tables;
-
-		tdp->msgq_req = p->msgq_req;
-		tdp->msgq_rsp = p->msgq_rsp;
-		tdp->timer_period = (rte_get_tsc_hz() * p->timer_period_ms) / 1000;
-		tdp->time_next = rte_get_tsc_cycles() + tdp->timer_period;
-
 		td->n_pipelines++;
 
 		/* Pipeline */
@@ -345,13 +322,6 @@  softnic_thread_pipeline_enable(struct pmd_internals *softnic,
 	/* 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(softnic, thread_id, req);
@@ -375,9 +345,8 @@  softnic_thread_pipeline_enable(struct pmd_internals *softnic,
 int
 softnic_thread_pipeline_disable(struct pmd_internals *softnic,
 	uint32_t thread_id,
-	const char *pipeline_name)
+	struct pipeline *p)
 {
-	struct pipeline *p = softnic_pipeline_find(softnic, pipeline_name);
 	struct thread_msg_req *req;
 	struct thread_msg_rsp *rsp;
 	uint32_t n_pipelines;
@@ -397,21 +366,12 @@  softnic_thread_pipeline_disable(struct pmd_internals *softnic,
 		uint32_t i;
 
 		for (i = 0; i < td->n_pipelines; i++) {
-			struct pipeline_data *tdp = &td->pipeline_data[i];
-
-			if (tdp->p != p->p)
+			if (td->p[i] != p->p)
 				continue;
 
 			/* Data plane thread */
-			if (i < td->n_pipelines - 1) {
-				struct rte_pipeline *pipeline_last =
-					td->p[td->n_pipelines - 1];
-				struct pipeline_data *tdp_last =
-					&td->pipeline_data[td->n_pipelines - 1];
-
-				td->p[i] = pipeline_last;
-				memcpy(tdp, tdp_last, sizeof(*tdp));
-			}
+			if (i < td->n_pipelines - 1)
+				td->p[i] = td->p[td->n_pipelines - 1];
 
 			td->n_pipelines--;
 
@@ -490,25 +450,9 @@  thread_msg_handle_pipeline_enable(struct softnic_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 */
 	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 */
@@ -522,25 +466,16 @@  thread_msg_handle_pipeline_disable(struct softnic_thread_data *t,
 {
 	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;
+	struct rte_swx_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)
+		if (t->p[i] != 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));
-		}
+		if (i < n_pipelines - 1)
+			t->p[i] = t->p[n_pipelines - 1];
 
 		t->n_pipelines--;
 
@@ -583,2464 +518,37 @@  thread_msg_handle(struct softnic_thread_data *t)
 }
 
 /**
- * Main thread & data plane threads: message passing
- */
-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_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_TABLE_RULE_STATS_READ,
-	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_TABLE_RULE_TTL_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_table_rule_add {
-	struct softnic_table_rule_match match;
-	struct softnic_table_rule_action action;
-};
-
-struct pipeline_msg_req_table_rule_add_default {
-	struct softnic_table_rule_action action;
-};
-
-struct pipeline_msg_req_table_rule_add_bulk {
-	struct softnic_table_rule_match *match;
-	struct softnic_table_rule_action *action;
-	void **data;
-	uint32_t n_rules;
-	int bulk;
-};
-
-struct pipeline_msg_req_table_rule_delete {
-	struct softnic_table_rule_match match;
-};
-
-struct pipeline_msg_req_table_rule_stats_read {
-	void *data;
-	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_table_rule_mtr_read {
-	void *data;
-	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_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 */
-
-	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_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;
-		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;
-		struct pipeline_msg_req_table_dscp_table_update table_dscp_table_update;
-		struct pipeline_msg_req_table_rule_ttl_read table_rule_ttl_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_table_rule_add {
-	void *data;
-};
-
-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_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_table_rule_ttl_read {
-	struct rte_table_action_ttl_counters 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;
-		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;
-		struct pipeline_msg_rsp_table_rule_mtr_read table_rule_mtr_read;
-		struct pipeline_msg_rsp_table_rule_ttl_read table_rule_ttl_read;
-	};
-};
-
-/**
- * Main thread
+ * Data plane threads: main
  */
-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
-softnic_pipeline_port_in_stats_read(struct pmd_internals *softnic,
-	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 = softnic_pipeline_find(softnic, pipeline_name);
-	if (p == NULL ||
-		port_id >= p->n_ports_in)
-		return -1;
-
-	if (!pipeline_is_running(p)) {
-		status = rte_pipeline_port_in_stats_read(p->p,
-			port_id,
-			stats,
-			clear);
-
-		return status;
-	}
-
-	/* 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);
-
-	/* 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
-softnic_pipeline_port_in_enable(struct pmd_internals *softnic,
-	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 = softnic_pipeline_find(softnic, pipeline_name);
-	if (p == NULL ||
-		port_id >= p->n_ports_in)
-		return -1;
-
-	if (!pipeline_is_running(p)) {
-		status = rte_pipeline_port_in_enable(p->p, port_id);
-		return status;
-	}
-
-	/* 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);
-
-	/* Read response */
-	status = rsp->status;
-
-	/* Free response */
-	pipeline_msg_free(rsp);
-
-	return status;
-}
-
-int
-softnic_pipeline_port_in_disable(struct pmd_internals *softnic,
-	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 = softnic_pipeline_find(softnic, pipeline_name);
-	if (p == NULL ||
-		port_id >= p->n_ports_in)
-		return -1;
-
-	if (!pipeline_is_running(p)) {
-		status = rte_pipeline_port_in_disable(p->p, port_id);
-		return status;
-	}
-
-	/* 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);
-
-	/* Read response */
-	status = rsp->status;
-
-	/* Free response */
-	pipeline_msg_free(rsp);
-
-	return status;
-}
-
-int
-softnic_pipeline_port_out_stats_read(struct pmd_internals *softnic,
-	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 = softnic_pipeline_find(softnic, pipeline_name);
-	if (p == NULL ||
-		port_id >= p->n_ports_out)
-		return -1;
-
-	if (!pipeline_is_running(p)) {
-		status = rte_pipeline_port_out_stats_read(p->p,
-			port_id,
-			stats,
-			clear);
-
-		return status;
-	}
-
-	/* 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);
-
-	/* 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
-softnic_pipeline_table_stats_read(struct pmd_internals *softnic,
-	const char *pipeline_name,
-	uint32_t table_id,
-	struct rte_pipeline_table_stats *stats,
-	int clear)
+static int32_t
+rte_pmd_softnic_run_internal(void *arg)
 {
-	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;
+	struct rte_eth_dev *dev = arg;
+	struct pmd_internals *softnic;
+	struct softnic_thread_data *t;
+	uint32_t thread_id, j;
 
-	p = softnic_pipeline_find(softnic, pipeline_name);
-	if (p == NULL ||
-		table_id >= p->n_tables)
-		return -1;
+	softnic = dev->data->dev_private;
+	thread_id = rte_lcore_id();
+	t = &softnic->thread_data[thread_id];
+	t->iter++;
 
-	if (!pipeline_is_running(p)) {
-		status = rte_pipeline_table_stats_read(p->p,
-			table_id,
-			stats,
-			clear);
+	/* Data Plane */
+	for (j = 0; j < t->n_pipelines; j++)
+		rte_swx_pipeline_run(t->p[j], PIPELINE_INSTR_QUANTA);
 
-		return status;
-	}
+	/* Control Plane */
+	if ((t->iter & 0xFLLU) == 0) {
+		uint64_t time = rte_get_tsc_cycles();
+		uint64_t time_next = t->time_next;
 
-	/* 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);
-
-	/* Read response */
-	status = rsp->status;
-	if (status)
-		memcpy(stats, &rsp->table_stats_read.stats, sizeof(*stats));
-
-	/* Free response */
-	pipeline_msg_free(rsp);
-
-	return status;
-}
-
-static int
-match_check(struct softnic_table_rule_match *match,
-	struct pipeline *p,
-	uint32_t table_id)
-{
-	struct softnic_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 softnic_table_acl_params *t = &table->params.match.acl;
-		struct softnic_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 softnic_table_lpm_params *t = &table->params.match.lpm;
-		struct softnic_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 softnic_table_rule_action *action,
-	struct pipeline *p,
-	uint32_t table_id)
-{
-	struct softnic_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 softnic_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;
-}
-
-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(struct softnic_table_rule_match *mh,
-	union table_rule_match_low_level *ml,
-	int add);
-
-static int
-action_convert(struct rte_table_action *a,
-	struct softnic_table_rule_action *action,
-	struct rte_pipeline_table_entry *data);
-
-int
-softnic_pipeline_table_rule_add(struct pmd_internals *softnic,
-	const char *pipeline_name,
-	uint32_t table_id,
-	struct softnic_table_rule_match *match,
-	struct softnic_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 = softnic_pipeline_find(softnic, pipeline_name);
-	if (p == NULL ||
-		table_id >= p->n_tables ||
-		match_check(match, p, table_id) ||
-		action_check(action, p, table_id))
-		return -1;
-
-	if (!pipeline_is_running(p)) {
-		struct rte_table_action *a = p->table[table_id].a;
-		union table_rule_match_low_level match_ll;
-		struct rte_pipeline_table_entry *data_in, *data_out;
-		int key_found;
-		uint8_t *buffer;
-
-		buffer = calloc(TABLE_RULE_ACTION_SIZE_MAX, sizeof(uint8_t));
-		if (buffer == NULL)
-			return -1;
-
-		/* Table match-action rule conversion */
-		data_in = (struct rte_pipeline_table_entry *)buffer;
-
-		status = match_convert(match, &match_ll, 1);
-		if (status) {
-			free(buffer);
-			return -1;
-		}
-
-		status = action_convert(a, action, data_in);
-		if (status) {
-			free(buffer);
-			return -1;
-		}
-
-		/* Add rule (match, action) to table */
-		status = rte_pipeline_table_entry_add(p->p,
-				table_id,
-				&match_ll,
-				data_in,
-				&key_found,
-				&data_out);
-		if (status) {
-			free(buffer);
-			return -1;
-		}
-
-		/* Write Response */
-		*data = data_out;
-
-		free(buffer);
-		return 0;
-	}
-
-	/* 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);
-
-	/* Read response */
-	status = rsp->status;
-	if (status == 0)
-		*data = rsp->table_rule_add.data;
-
-	/* Free response */
-	pipeline_msg_free(rsp);
-
-	return status;
-}
-
-int
-softnic_pipeline_table_rule_add_default(struct pmd_internals *softnic,
-	const char *pipeline_name,
-	uint32_t table_id,
-	struct softnic_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 = softnic_pipeline_find(softnic, pipeline_name);
-	if (p == NULL ||
-		table_id >= p->n_tables ||
-		action_default_check(action, p, table_id))
-		return -1;
-
-	if (!pipeline_is_running(p)) {
-		struct rte_pipeline_table_entry *data_in, *data_out;
-		uint8_t *buffer;
-
-		buffer = calloc(TABLE_RULE_ACTION_SIZE_MAX, sizeof(uint8_t));
-		if (buffer == NULL)
-			return -1;
-
-		/* Apply actions */
-		data_in = (struct rte_pipeline_table_entry *)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) {
-			free(buffer);
-			return -1;
-		}
-
-		/* Write Response */
-		*data = data_out;
-
-		free(buffer);
-		return 0;
-	}
-
-	/* 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);
-
-	/* Read response */
-	status = rsp->status;
-	if (status == 0)
-		*data = rsp->table_rule_add_default.data;
-
-	/* Free response */
-	pipeline_msg_free(rsp);
-
-	return status;
-}
-
-int
-softnic_pipeline_table_rule_add_bulk(struct pmd_internals *softnic,
-	const char *pipeline_name,
-	uint32_t table_id,
-	struct softnic_table_rule_match *match,
-	struct softnic_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 = softnic_pipeline_find(softnic, pipeline_name);
-	if (p == NULL ||
-		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;
-
-	if (!pipeline_is_running(p)) {
-		struct rte_table_action *a = p->table[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;
-		struct rte_pipeline_table_entry **entries_ptr =
-			(struct rte_pipeline_table_entry **)data;
-		uint32_t bulk =
-			(p->table[table_id].params.match_type == TABLE_ACL) ? 1 : 0;
-		int *found;
-
-		/* 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++) {
-			status = action_convert(a, &action[i], action_ll_ptr[i]);
-			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,
-				entries_ptr);
-			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],
-					&entries_ptr[i]);
-				if (status) {
-					*n_rules = i;
-					break;
-				}
-			}
-		}
-
-		/* Free */
-		free(found);
-		free(action_ll_ptr);
-		free(match_ll_ptr);
-		free(action_ll);
-		free(match_ll);
-
-		return status;
-
-fail:
-		free(found);
-		free(action_ll_ptr);
-		free(match_ll_ptr);
-		free(action_ll);
-		free(match_ll);
-
-		*n_rules = 0;
-		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);
-
-	/* 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
-softnic_pipeline_table_rule_delete(struct pmd_internals *softnic,
-	const char *pipeline_name,
-	uint32_t table_id,
-	struct softnic_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 = softnic_pipeline_find(softnic, pipeline_name);
-	if (p == NULL ||
-		table_id >= p->n_tables ||
-		match_check(match, p, table_id))
-		return -1;
-
-	if (!pipeline_is_running(p)) {
-		union table_rule_match_low_level match_ll;
-		int key_found;
-
-		status = match_convert(match, &match_ll, 0);
-		if (status)
-			return -1;
-
-		status = rte_pipeline_table_entry_delete(p->p,
-				table_id,
-				&match_ll,
-				&key_found,
-				NULL);
-
-		return status;
-	}
-
-	/* 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);
-
-	/* Read response */
-	status = rsp->status;
-
-	/* Free response */
-	pipeline_msg_free(rsp);
-
-	return status;
-}
-
-int
-softnic_pipeline_table_rule_delete_default(struct pmd_internals *softnic,
-	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 = softnic_pipeline_find(softnic, pipeline_name);
-	if (p == NULL ||
-		table_id >= p->n_tables)
-		return -1;
-
-	if (!pipeline_is_running(p)) {
-		status = rte_pipeline_table_default_entry_delete(p->p,
-			table_id,
-			NULL);
-
-		return status;
-	}
-
-	/* 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);
-
-	/* Read response */
-	status = rsp->status;
-
-	/* Free response */
-	pipeline_msg_free(rsp);
-
-	return status;
-}
-
-int
-softnic_pipeline_table_rule_stats_read(struct pmd_internals *softnic,
-	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 = softnic_pipeline_find(softnic, pipeline_name);
-	if (p == NULL ||
-		table_id >= p->n_tables)
-		return -1;
-
-	if (!pipeline_is_running(p)) {
-		struct rte_table_action *a = p->table[table_id].a;
-
-		status = rte_table_action_stats_read(a,
-			data,
-			stats,
-			clear);
-
-		return status;
-	}
-
-	/* 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);
-
-	/* 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;
-}
-
-int
-softnic_pipeline_table_mtr_profile_add(struct pmd_internals *softnic,
-	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;
-	struct softnic_table *table;
-	struct softnic_table_meter_profile *mp;
-	int status;
-
-	/* Check input params */
-	if (pipeline_name == NULL ||
-		profile == NULL)
-		return -1;
-
-	p = softnic_pipeline_find(softnic, pipeline_name);
-	if (p == NULL ||
-		table_id >= p->n_tables)
-		return -1;
-
-	table = &p->table[table_id];
-	mp = softnic_pipeline_table_meter_profile_find(table, meter_profile_id);
-	if (mp)
-		return -1;
-
-	/* Resource Allocation */
-	mp = calloc(1, sizeof(struct softnic_table_meter_profile));
-	if (mp == NULL)
-		return -1;
-
-	mp->meter_profile_id = meter_profile_id;
-	memcpy(&mp->profile, profile, sizeof(mp->profile));
-
-	if (!pipeline_is_running(p)) {
-		status = rte_table_action_meter_profile_add(table->a,
-			meter_profile_id,
-			profile);
-		if (status) {
-			free(mp);
-			return status;
-		}
-
-		/* Add profile to the table. */
-		TAILQ_INSERT_TAIL(&table->meter_profiles, mp, node);
-
-		return status;
-	}
-
-	/* Allocate request */
-	req = pipeline_msg_alloc();
-	if (req == NULL) {
-		free(mp);
-		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);
-
-	/* Read response */
-	status = rsp->status;
-	if (status == 0)
-		TAILQ_INSERT_TAIL(&table->meter_profiles, mp, node);
-	else
-		free(mp);
-
-	/* Free response */
-	pipeline_msg_free(rsp);
-
-	return status;
-}
-
-int
-softnic_pipeline_table_mtr_profile_delete(struct pmd_internals *softnic,
-	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 = softnic_pipeline_find(softnic, pipeline_name);
-	if (p == NULL ||
-		table_id >= p->n_tables)
-		return -1;
-
-	if (!pipeline_is_running(p)) {
-		struct rte_table_action *a = p->table[table_id].a;
-
-		status = rte_table_action_meter_profile_delete(a,
-				meter_profile_id);
-
-		return status;
-	}
-
-	/* 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);
-
-	/* Read response */
-	status = rsp->status;
-
-	/* Free response */
-	pipeline_msg_free(rsp);
-
-	return status;
-}
-
-int
-softnic_pipeline_table_rule_mtr_read(struct pmd_internals *softnic,
-	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 = softnic_pipeline_find(softnic, pipeline_name);
-	if (p == NULL ||
-		table_id >= p->n_tables)
-		return -1;
-
-	if (!pipeline_is_running(p)) {
-		struct rte_table_action *a = p->table[table_id].a;
-
-		status = rte_table_action_meter_read(a,
-				data,
-				tc_mask,
-				stats,
-				clear);
-
-		return status;
-	}
-
-	/* 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);
-
-	/* 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;
-}
-
-int
-softnic_pipeline_table_dscp_table_update(struct pmd_internals *softnic,
-	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 = softnic_pipeline_find(softnic, pipeline_name);
-	if (p == NULL ||
-		table_id >= p->n_tables)
-		return -1;
-
-	if (!pipeline_is_running(p)) {
-		struct rte_table_action *a = p->table[table_id].a;
-
-		status = rte_table_action_dscp_table_update(a,
-				dscp_mask,
-				dscp_table);
-
-		/* Update table dscp table */
-		if (!status)
-			memcpy(&p->table[table_id].dscp_table, dscp_table,
-				sizeof(p->table[table_id].dscp_table));
-
-		return status;
-	}
-
-	/* 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);
-
-	/* Read response */
-	status = rsp->status;
-
-	/* Update table dscp table */
-	if (!status)
-		memcpy(&p->table[table_id].dscp_table, dscp_table,
-			sizeof(p->table[table_id].dscp_table));
-
-	/* Free response */
-	pipeline_msg_free(rsp);
-
-	return status;
-}
-
-int
-softnic_pipeline_table_rule_ttl_read(struct pmd_internals *softnic,
-	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 = softnic_pipeline_find(softnic, pipeline_name);
-	if (p == NULL ||
-		table_id >= p->n_tables)
-		return -1;
-
-	if (!pipeline_is_running(p)) {
-		struct rte_table_action *a = p->table[table_id].a;
-
-		status = rte_table_action_ttl_read(a,
-				data,
-				stats,
-				clear);
-
-		return status;
-	}
-
-	/* 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);
-
-	/* 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
- */
-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 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)
-{
-	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 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 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 softnic_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 =
-					rte_be_to_cpu_32(sa32[0]);
-				ml->acl_add.field_value[1].mask_range.u32 =
-					sa32_depth[0];
-				ml->acl_add.field_value[2].value.u32 =
-					rte_be_to_cpu_32(sa32[1]);
-				ml->acl_add.field_value[2].mask_range.u32 =
-					sa32_depth[1];
-				ml->acl_add.field_value[3].value.u32 =
-					rte_be_to_cpu_32(sa32[2]);
-				ml->acl_add.field_value[3].mask_range.u32 =
-					sa32_depth[2];
-				ml->acl_add.field_value[4].value.u32 =
-					rte_be_to_cpu_32(sa32[3]);
-				ml->acl_add.field_value[4].mask_range.u32 =
-					sa32_depth[3];
-
-				ml->acl_add.field_value[5].value.u32 =
-					rte_be_to_cpu_32(da32[0]);
-				ml->acl_add.field_value[5].mask_range.u32 =
-					da32_depth[0];
-				ml->acl_add.field_value[6].value.u32 =
-					rte_be_to_cpu_32(da32[1]);
-				ml->acl_add.field_value[6].mask_range.u32 =
-					da32_depth[1];
-				ml->acl_add.field_value[7].value.u32 =
-					rte_be_to_cpu_32(da32[2]);
-				ml->acl_add.field_value[7].mask_range.u32 =
-					da32_depth[2];
-				ml->acl_add.field_value[8].value.u32 =
-					rte_be_to_cpu_32(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 =
-					rte_be_to_cpu_32(sa32[0]);
-				ml->acl_delete.field_value[1].mask_range.u32 =
-					sa32_depth[0];
-				ml->acl_delete.field_value[2].value.u32 =
-					rte_be_to_cpu_32(sa32[1]);
-				ml->acl_delete.field_value[2].mask_range.u32 =
-					sa32_depth[1];
-				ml->acl_delete.field_value[3].value.u32 =
-					rte_be_to_cpu_32(sa32[2]);
-				ml->acl_delete.field_value[3].mask_range.u32 =
-					sa32_depth[2];
-				ml->acl_delete.field_value[4].value.u32 =
-					rte_be_to_cpu_32(sa32[3]);
-				ml->acl_delete.field_value[4].mask_range.u32 =
-					sa32_depth[3];
-
-				ml->acl_delete.field_value[5].value.u32 =
-					rte_be_to_cpu_32(da32[0]);
-				ml->acl_delete.field_value[5].mask_range.u32 =
-					da32_depth[0];
-				ml->acl_delete.field_value[6].value.u32 =
-					rte_be_to_cpu_32(da32[1]);
-				ml->acl_delete.field_value[6].mask_range.u32 =
-					da32_depth[1];
-				ml->acl_delete.field_value[7].value.u32 =
-					rte_be_to_cpu_32(da32[2]);
-				ml->acl_delete.field_value[7].mask_range.u32 =
-					da32_depth[2];
-				ml->acl_delete.field_value[8].value.u32 =
-					rte_be_to_cpu_32(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 int
-action_convert(struct rte_table_action *a,
-	struct softnic_table_rule_action *action,
-	struct rte_pipeline_table_entry *data)
-{
-	int status;
-
-	/* Apply actions */
-	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_FWD)) {
-		status = rte_table_action_apply(a,
-			data,
-			RTE_TABLE_ACTION_FWD,
-			&action->fwd);
-
-		if (status)
-			return status;
-	}
-
-	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_LB)) {
-		status = rte_table_action_apply(a,
-			data,
-			RTE_TABLE_ACTION_LB,
-			&action->lb);
-
-		if (status)
-			return status;
-	}
-
-	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) {
-		status = rte_table_action_apply(a,
-			data,
-			RTE_TABLE_ACTION_MTR,
-			&action->mtr);
-
-		if (status)
-			return status;
-	}
-
-	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_TM)) {
-		status = rte_table_action_apply(a,
-			data,
-			RTE_TABLE_ACTION_TM,
-			&action->tm);
-
-		if (status)
-			return status;
-	}
-
-	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_ENCAP)) {
-		status = rte_table_action_apply(a,
-			data,
-			RTE_TABLE_ACTION_ENCAP,
-			&action->encap);
-
-		if (status)
-			return status;
-	}
-
-	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_NAT)) {
-		status = rte_table_action_apply(a,
-			data,
-			RTE_TABLE_ACTION_NAT,
-			&action->nat);
-
-		if (status)
-			return status;
-	}
-
-	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_TTL)) {
-		status = rte_table_action_apply(a,
-			data,
-			RTE_TABLE_ACTION_TTL,
-			&action->ttl);
-
-		if (status)
-			return status;
-	}
-
-	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_STATS)) {
-		status = rte_table_action_apply(a,
-			data,
-			RTE_TABLE_ACTION_STATS,
-			&action->stats);
-
-		if (status)
-			return status;
-	}
-
-	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_TIME)) {
-		status = rte_table_action_apply(a,
-			data,
-			RTE_TABLE_ACTION_TIME,
-			&action->time);
-
-		if (status)
-			return status;
-	}
-
-	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_TAG)) {
-		status = rte_table_action_apply(a,
-			data,
-			RTE_TABLE_ACTION_TAG,
-			&action->tag);
-
-		if (status)
-			return status;
-	}
-
-	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_DECAP)) {
-		status = rte_table_action_apply(a,
-			data,
-			RTE_TABLE_ACTION_DECAP,
-			&action->decap);
-
-		if (status)
-			return status;
-	}
-
-	if (action->action_mask & (1LLU << RTE_TABLE_ACTION_SYM_CRYPTO)) {
-		status = rte_table_action_apply(a,
-			data,
-			RTE_TABLE_ACTION_SYM_CRYPTO,
-			&action->sym_crypto);
-
-		if (status)
-			return status;
-	}
-
-	return 0;
-}
-
-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 softnic_table_rule_match *match = &req->table_rule_add.match;
-	struct softnic_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;
-
-	status = match_convert(match, &match_ll, 1);
-	if (status) {
-		rsp->status = -1;
-		return rsp;
-	}
-
-	status = action_convert(a, action, data_in);
-	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 softnic_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 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 softnic_table_rule_match *match = req->table_rule_add_bulk.match;
-	struct softnic_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++) {
-		status = action_convert(a, &action[i], action_ll_ptr[i]);
-		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)
-{
-	union table_rule_match_low_level match_ll;
-	struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req;
-	struct softnic_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 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 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 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 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 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)
-{
-	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) {
-		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;
-
-		case PIPELINE_REQ_PORT_IN_DISABLE:
-			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;
-
-		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;
-
-		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;
-
-		case PIPELINE_REQ_TABLE_RULE_DELETE_DEFAULT:
-			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;
-
-		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;
-
-		case PIPELINE_REQ_TABLE_RULE_MTR_READ:
-			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;
-
-		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;
-		}
-
-		pipeline_msg_send(p->msgq_rsp, rsp);
-	}
-}
-
-/**
- * Data plane threads: main
- */
-static int32_t
-rte_pmd_softnic_run_internal(void *arg)
-{
-	struct rte_eth_dev *dev = arg;
-	struct pmd_internals *softnic;
-	struct softnic_thread_data *t;
-	uint32_t thread_id, j;
-
-	softnic = dev->data->dev_private;
-	thread_id = rte_lcore_id();
-	t = &softnic->thread_data[thread_id];
-	t->iter++;
-
-	/* Data Plane */
-	for (j = 0; j < t->n_pipelines; j++)
-		rte_pipeline_run(t->p[j]);
-
-	/* Control Plane */
-	if ((t->iter & 0xFLLU) == 0) {
-		uint64_t time = rte_get_tsc_cycles();
-		uint64_t time_next_min = UINT64_MAX;
-
-		if (time < t->time_next_min)
-			return 0;
-
-		/* 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;
-		}
+		if (time < time_next)
+			return 0;
 
 		/* 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;
-		}
+		thread_msg_handle(t);
 
-		t->time_next_min = time_next_min;
+		t->time_next = time_next + t->timer_period;
 	}
 
 	return 0;