[dpdk-dev] ip_pipeline: modify action handler in passthrough pipeline

Message ID 1443871212-12919-1-git-send-email-jasvinder.singh@intel.com (mailing list archive)
State Accepted, archived
Headers

Commit Message

Jasvinder Singh Oct. 3, 2015, 11:20 a.m. UTC
  This patch implements a generic approach to
extract fields from the packet's header and
copying them to packet metadata. The fields
are selected at the desired offset on the basis
of the mask specified in application configuration
file. The extracted fields, for instance, can be
used to compute hash for the lookup table. This
feature exposes more flexibility to the users as
they will be able to employ new protocol headers
and specify the required fields to be extracted.

The above feature has been implemented as port_in
action handler of the passthrough pipeline. The
example of the configuration file for passthrough
pipeline is as below;

[PIPELINE1]
type = PASS-THROUGH
core = 1
pktq_in = RXQ0.0 RXQ1.0 RXQ2.0 RXQ3.0
pktq_out = TXQ0.0 TXQ1.0 TXQ2.0 TXQ3.0
dma_size = 16
dma_dst_offset = 64
dma_src_offset = 150
dma_src_mask = 00FF0000FFFFFFFFFFFFFFFFFFFFFFFF
dma_hash_offset = 80

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/ip_pipeline/config_parse.c                |  52 ++
 .../ip_pipeline/pipeline/pipeline_passthrough_be.c | 660 ++++++++-------------
 .../ip_pipeline/pipeline/pipeline_passthrough_be.h |  17 +
 examples/ip_pipeline/pipeline_be.h                 |   3 +
 4 files changed, 319 insertions(+), 413 deletions(-)
  

Comments

Cristian Dumitrescu Oct. 5, 2015, 9:38 a.m. UTC | #1
> -----Original Message-----
> From: Singh, Jasvinder
> Sent: Saturday, October 3, 2015 12:20 PM
> To: dev@dpdk.org
> Cc: Dumitrescu, Cristian
> Subject: [PATCH] ip_pipeline: modify action handler in passthrough pipeline
> 
> 
> Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
> ---

Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
  
Thomas Monjalon Dec. 7, 2015, 12:43 a.m. UTC | #2
> > Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
> 
> Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>

Applied, thanks
  

Patch

diff --git a/examples/ip_pipeline/config_parse.c b/examples/ip_pipeline/config_parse.c
index c9b78f9..f4e2b1d 100644
--- a/examples/ip_pipeline/config_parse.c
+++ b/examples/ip_pipeline/config_parse.c
@@ -362,6 +362,58 @@  parser_read_uint32(uint32_t *value, const char *p)
 	return 0;
 }
 
+static uint32_t
+get_hex_val(char c)
+{
+	switch (c) {
+	case '0': case '1': case '2': case '3': case '4': case '5':
+	case '6': case '7': case '8': case '9':
+		return c - '0';
+	case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+		return c - 'A' + 10;
+	case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+		return c - 'a' + 10;
+	default:
+		return 0;
+	}
+}
+
+int
+parse_hex_string(char *src, uint8_t *dst, uint32_t *size)
+{
+	char *c;
+	uint32_t len, i;
+
+	/* Check input parameters */
+	if ((src == NULL) ||
+		(dst == NULL) ||
+		(size == NULL) ||
+		(*size == 0))
+		return -1;
+
+	len = strlen(src);
+	if (((len & 3) != 0) ||
+		(len > (*size) * 2))
+		return -1;
+	*size = len / 2;
+
+	for (c = src; *c != 0; c++) {
+		if ((((*c) >= '0') && ((*c) <= '9')) ||
+			(((*c) >= 'A') && ((*c) <= 'F')) ||
+			(((*c) >= 'a') && ((*c) <= 'f')))
+			continue;
+
+		return -1;
+	}
+
+	/* Convert chars to bytes */
+	for (i = 0; i < *size; i++)
+		dst[i] = get_hex_val(src[2 * i]) * 16 +
+			get_hex_val(src[2 * i + 1]);
+
+	return 0;
+}
+
 static int
 parse_pipeline_core(uint32_t *socket,
 	uint32_t *core,
diff --git a/examples/ip_pipeline/pipeline/pipeline_passthrough_be.c b/examples/ip_pipeline/pipeline/pipeline_passthrough_be.c
index 83a16c2..a898f7d 100644
--- a/examples/ip_pipeline/pipeline/pipeline_passthrough_be.c
+++ b/examples/ip_pipeline/pipeline/pipeline_passthrough_be.c
@@ -44,23 +44,10 @@ 
 #include "pipeline_actions_common.h"
 #include "hash_func.h"
 
-enum flow_key_type {
-	FLOW_KEY_QINQ,
-	FLOW_KEY_IPV4_5TUPLE,
-	FLOW_KEY_IPV6_5TUPLE,
-};
-
 struct pipeline_passthrough {
 	struct pipeline p;
-
-	uint32_t key_type_valid;
-	enum flow_key_type key_type;
-	uint32_t key_offset_rd;
-	uint32_t key_offset_wr;
-	uint32_t hash_offset;
-
+	struct pipeline_passthrough_params params;
 	rte_table_hash_op_hash f_hash;
-	rte_pipeline_port_in_action_handler f_port_in_ah;
 } __rte_cache_aligned;
 
 static pipeline_msg_req_handler handlers[] = {
@@ -80,421 +67,272 @@  static pipeline_msg_req_handler handlers[] = {
 		pipeline_msg_req_invalid_handler,
 };
 
-static inline void
-pkt_work_key_qinq(
+static inline __attribute__((always_inline)) void
+pkt_work(
 	struct rte_mbuf *pkt,
-	void *arg)
+	void *arg,
+	uint32_t dma_size,
+	uint32_t hash_enabled)
 {
-	struct pipeline_passthrough *p_pt = arg;
-	uint32_t key_offset_rd = p_pt->key_offset_rd;
-	uint32_t key_offset_wr = p_pt->key_offset_wr;
-	uint32_t hash_offset = p_pt->hash_offset;
-
-	uint64_t *key_rd = RTE_MBUF_METADATA_UINT64_PTR(pkt, key_offset_rd);
-	uint64_t *key_wr = RTE_MBUF_METADATA_UINT64_PTR(pkt, key_offset_wr);
-	uint32_t *hash = RTE_MBUF_METADATA_UINT32_PTR(pkt, hash_offset);
-
-	/* Read */
-	uint64_t key_qinq = *key_rd & rte_bswap64(0x00000FFF00000FFFLLU);
+	struct pipeline_passthrough *p = arg;
+
+	uint64_t *dma_dst = RTE_MBUF_METADATA_UINT64_PTR(pkt,
+		p->params.dma_dst_offset);
+	uint64_t *dma_src = RTE_MBUF_METADATA_UINT64_PTR(pkt,
+		p->params.dma_src_offset);
+	uint64_t *dma_mask = (uint64_t *) p->params.dma_src_mask;
+	uint32_t *dma_hash = RTE_MBUF_METADATA_UINT32_PTR(pkt,
+		p->params.dma_hash_offset);
+	uint32_t i;
 
-	/* Compute */
-	uint32_t hash_qinq = p_pt->f_hash(&key_qinq, 8, 0);
+	/* Read (dma_src), compute (dma_dst), write (dma_dst) */
+	for (i = 0; i < (dma_size / 8); i++)
+		dma_dst[i] = dma_src[i] & dma_mask[i];
 
-	/* Write */
-	*key_wr = key_qinq;
-	*hash = hash_qinq;
+	/* Read (dma_dst), compute (hash), write (hash) */
+	if (hash_enabled)
+		*dma_hash = p->f_hash(dma_dst, dma_size, 0);
 }
 
-static inline void
-pkt4_work_key_qinq(
-	struct rte_mbuf **pkt,
-	void *arg)
+static inline __attribute__((always_inline)) void
+pkt4_work(
+	struct rte_mbuf **pkts,
+	void *arg,
+	uint32_t dma_size,
+	uint32_t hash_enabled)
 {
-	struct pipeline_passthrough *p_pt = arg;
-	uint32_t key_offset_rd = p_pt->key_offset_rd;
-	uint32_t key_offset_wr = p_pt->key_offset_wr;
-	uint32_t hash_offset = p_pt->hash_offset;
-
-	uint64_t *key_rd0 = RTE_MBUF_METADATA_UINT64_PTR(pkt[0], key_offset_rd);
-	uint64_t *key_wr0 = RTE_MBUF_METADATA_UINT64_PTR(pkt[0], key_offset_wr);
-	uint32_t *hash0 = RTE_MBUF_METADATA_UINT32_PTR(pkt[0], hash_offset);
-
-	uint64_t *key_rd1 = RTE_MBUF_METADATA_UINT64_PTR(pkt[1], key_offset_rd);
-	uint64_t *key_wr1 = RTE_MBUF_METADATA_UINT64_PTR(pkt[1], key_offset_wr);
-	uint32_t *hash1 = RTE_MBUF_METADATA_UINT32_PTR(pkt[1], hash_offset);
-
-	uint64_t *key_rd2 = RTE_MBUF_METADATA_UINT64_PTR(pkt[2], key_offset_rd);
-	uint64_t *key_wr2 = RTE_MBUF_METADATA_UINT64_PTR(pkt[2], key_offset_wr);
-	uint32_t *hash2 = RTE_MBUF_METADATA_UINT32_PTR(pkt[2], hash_offset);
-
-	uint64_t *key_rd3 = RTE_MBUF_METADATA_UINT64_PTR(pkt[3], key_offset_rd);
-	uint64_t *key_wr3 = RTE_MBUF_METADATA_UINT64_PTR(pkt[3], key_offset_wr);
-	uint32_t *hash3 = RTE_MBUF_METADATA_UINT32_PTR(pkt[3], hash_offset);
-
-	/* Read */
-	uint64_t key_qinq0 = *key_rd0 & rte_bswap64(0x00000FFF00000FFFLLU);
-	uint64_t key_qinq1 = *key_rd1 & rte_bswap64(0x00000FFF00000FFFLLU);
-	uint64_t key_qinq2 = *key_rd2 & rte_bswap64(0x00000FFF00000FFFLLU);
-	uint64_t key_qinq3 = *key_rd3 & rte_bswap64(0x00000FFF00000FFFLLU);
-
-	/* Compute */
-	uint32_t hash_qinq0 = p_pt->f_hash(&key_qinq0, 8, 0);
-	uint32_t hash_qinq1 = p_pt->f_hash(&key_qinq1, 8, 0);
-	uint32_t hash_qinq2 = p_pt->f_hash(&key_qinq2, 8, 0);
-	uint32_t hash_qinq3 = p_pt->f_hash(&key_qinq3, 8, 0);
-
-	/* Write */
-	*key_wr0 = key_qinq0;
-	*key_wr1 = key_qinq1;
-	*key_wr2 = key_qinq2;
-	*key_wr3 = key_qinq3;
-
-	*hash0 = hash_qinq0;
-	*hash1 = hash_qinq1;
-	*hash2 = hash_qinq2;
-	*hash3 = hash_qinq3;
-}
+	struct pipeline_passthrough *p = arg;
+
+	uint64_t *dma_dst0 = RTE_MBUF_METADATA_UINT64_PTR(pkts[0],
+		p->params.dma_dst_offset);
+	uint64_t *dma_dst1 = RTE_MBUF_METADATA_UINT64_PTR(pkts[1],
+		p->params.dma_dst_offset);
+	uint64_t *dma_dst2 = RTE_MBUF_METADATA_UINT64_PTR(pkts[2],
+		p->params.dma_dst_offset);
+	uint64_t *dma_dst3 = RTE_MBUF_METADATA_UINT64_PTR(pkts[3],
+		p->params.dma_dst_offset);
+
+	uint64_t *dma_src0 = RTE_MBUF_METADATA_UINT64_PTR(pkts[0],
+		p->params.dma_src_offset);
+	uint64_t *dma_src1 = RTE_MBUF_METADATA_UINT64_PTR(pkts[1],
+		p->params.dma_src_offset);
+	uint64_t *dma_src2 = RTE_MBUF_METADATA_UINT64_PTR(pkts[2],
+		p->params.dma_src_offset);
+	uint64_t *dma_src3 = RTE_MBUF_METADATA_UINT64_PTR(pkts[3],
+		p->params.dma_src_offset);
+
+	uint64_t *dma_mask = (uint64_t *) p->params.dma_src_mask;
+
+	uint32_t *dma_hash0 = RTE_MBUF_METADATA_UINT32_PTR(pkts[0],
+		p->params.dma_hash_offset);
+	uint32_t *dma_hash1 = RTE_MBUF_METADATA_UINT32_PTR(pkts[1],
+		p->params.dma_hash_offset);
+	uint32_t *dma_hash2 = RTE_MBUF_METADATA_UINT32_PTR(pkts[2],
+		p->params.dma_hash_offset);
+	uint32_t *dma_hash3 = RTE_MBUF_METADATA_UINT32_PTR(pkts[3],
+		p->params.dma_hash_offset);
 
-PIPELINE_PORT_IN_AH(port_in_ah_key_qinq, pkt_work_key_qinq, pkt4_work_key_qinq);
+	uint32_t i;
 
-static inline void
-pkt_work_key_ipv4(
-	struct rte_mbuf *pkt,
-	void *arg)
-{
-	struct pipeline_passthrough *p_pt = arg;
-	uint32_t key_offset_rd = p_pt->key_offset_rd;
-	uint32_t key_offset_wr = p_pt->key_offset_wr;
-	uint32_t hash_offset = p_pt->hash_offset;
-
-	uint64_t *key_rd = RTE_MBUF_METADATA_UINT64_PTR(pkt, key_offset_rd);
-	uint64_t *key_wr = RTE_MBUF_METADATA_UINT64_PTR(pkt, key_offset_wr);
-	uint32_t *hash = RTE_MBUF_METADATA_UINT32_PTR(pkt, hash_offset);
-	uint64_t key_ipv4[2];
-	uint32_t hash_ipv4;
-
-	/* Read */
-	key_ipv4[0] = key_rd[0] & rte_bswap64(0x00FF0000FFFFFFFFLLU);
-	key_ipv4[1] = key_rd[1];
-
-	/* Compute */
-	hash_ipv4 = p_pt->f_hash(key_ipv4, 16, 0);
-
-	/* Write */
-	key_wr[0] = key_ipv4[0];
-	key_wr[1] = key_ipv4[1];
-	*hash = hash_ipv4;
-}
+	/* Read (dma_src), compute (dma_dst), write (dma_dst) */
+	for (i = 0; i < (dma_size / 8); i++) {
+		dma_dst0[i] = dma_src0[i] & dma_mask[i];
+		dma_dst1[i] = dma_src1[i] & dma_mask[i];
+		dma_dst2[i] = dma_src2[i] & dma_mask[i];
+		dma_dst3[i] = dma_src3[i] & dma_mask[i];
+	}
 
-static inline void
-pkt4_work_key_ipv4(
-	struct rte_mbuf **pkt,
-	void *arg)
-{
-	struct pipeline_passthrough *p_pt = arg;
-	uint32_t key_offset_rd = p_pt->key_offset_rd;
-	uint32_t key_offset_wr = p_pt->key_offset_wr;
-	uint32_t hash_offset = p_pt->hash_offset;
-
-	uint64_t *key_rd0 = RTE_MBUF_METADATA_UINT64_PTR(pkt[0], key_offset_rd);
-	uint64_t *key_wr0 = RTE_MBUF_METADATA_UINT64_PTR(pkt[0], key_offset_wr);
-	uint32_t *hash0 = RTE_MBUF_METADATA_UINT32_PTR(pkt[0], hash_offset);
-
-	uint64_t *key_rd1 = RTE_MBUF_METADATA_UINT64_PTR(pkt[1], key_offset_rd);
-	uint64_t *key_wr1 = RTE_MBUF_METADATA_UINT64_PTR(pkt[1], key_offset_wr);
-	uint32_t *hash1 = RTE_MBUF_METADATA_UINT32_PTR(pkt[1], hash_offset);
-
-	uint64_t *key_rd2 = RTE_MBUF_METADATA_UINT64_PTR(pkt[2], key_offset_rd);
-	uint64_t *key_wr2 = RTE_MBUF_METADATA_UINT64_PTR(pkt[2], key_offset_wr);
-	uint32_t *hash2 = RTE_MBUF_METADATA_UINT32_PTR(pkt[2], hash_offset);
-
-	uint64_t *key_rd3 = RTE_MBUF_METADATA_UINT64_PTR(pkt[3], key_offset_rd);
-	uint64_t *key_wr3 = RTE_MBUF_METADATA_UINT64_PTR(pkt[3], key_offset_wr);
-	uint32_t *hash3 = RTE_MBUF_METADATA_UINT32_PTR(pkt[3], hash_offset);
-
-	uint64_t key_ipv4_0[2];
-	uint64_t key_ipv4_1[2];
-	uint64_t key_ipv4_2[2];
-	uint64_t key_ipv4_3[2];
-
-	uint32_t hash_ipv4_0;
-	uint32_t hash_ipv4_1;
-	uint32_t hash_ipv4_2;
-	uint32_t hash_ipv4_3;
-
-	/* Read */
-	key_ipv4_0[0] = key_rd0[0] & rte_bswap64(0x00FF0000FFFFFFFFLLU);
-	key_ipv4_1[0] = key_rd1[0] & rte_bswap64(0x00FF0000FFFFFFFFLLU);
-	key_ipv4_2[0] = key_rd2[0] & rte_bswap64(0x00FF0000FFFFFFFFLLU);
-	key_ipv4_3[0] = key_rd3[0] & rte_bswap64(0x00FF0000FFFFFFFFLLU);
-
-	key_ipv4_0[1] = key_rd0[1];
-	key_ipv4_1[1] = key_rd1[1];
-	key_ipv4_2[1] = key_rd2[1];
-	key_ipv4_3[1] = key_rd3[1];
-
-	/* Compute */
-	hash_ipv4_0 = p_pt->f_hash(key_ipv4_0, 16, 0);
-	hash_ipv4_1 = p_pt->f_hash(key_ipv4_1, 16, 0);
-	hash_ipv4_2 = p_pt->f_hash(key_ipv4_2, 16, 0);
-	hash_ipv4_3 = p_pt->f_hash(key_ipv4_3, 16, 0);
-
-	/* Write */
-	key_wr0[0] = key_ipv4_0[0];
-	key_wr1[0] = key_ipv4_1[0];
-	key_wr2[0] = key_ipv4_2[0];
-	key_wr3[0] = key_ipv4_3[0];
-
-	key_wr0[1] = key_ipv4_0[1];
-	key_wr1[1] = key_ipv4_1[1];
-	key_wr2[1] = key_ipv4_2[1];
-	key_wr3[1] = key_ipv4_3[1];
-
-	*hash0 = hash_ipv4_0;
-	*hash1 = hash_ipv4_1;
-	*hash2 = hash_ipv4_2;
-	*hash3 = hash_ipv4_3;
+	/* Read (dma_dst), compute (hash), write (hash) */
+	if (hash_enabled) {
+		*dma_hash0 = p->f_hash(dma_dst0, dma_size, 0);
+		*dma_hash1 = p->f_hash(dma_dst1, dma_size, 0);
+		*dma_hash2 = p->f_hash(dma_dst2, dma_size, 0);
+		*dma_hash3 = p->f_hash(dma_dst3, dma_size, 0);
+	}
 }
 
-PIPELINE_PORT_IN_AH(port_in_ah_key_ipv4, pkt_work_key_ipv4, pkt4_work_key_ipv4);
+#define PKT_WORK(dma_size, hash_enabled)			\
+static inline void						\
+pkt_work_size##dma_size##_hash##hash_enabled(			\
+	struct rte_mbuf *pkt,					\
+	void *arg)						\
+{								\
+	pkt_work(pkt, arg, dma_size, hash_enabled);		\
+}
 
-static inline void
-pkt_work_key_ipv6(
-	struct rte_mbuf *pkt,
-	void *arg)
-{
-	struct pipeline_passthrough *p_pt = arg;
-	uint32_t key_offset_rd = p_pt->key_offset_rd;
-	uint32_t key_offset_wr = p_pt->key_offset_wr;
-	uint32_t hash_offset = p_pt->hash_offset;
-
-	uint64_t *key_rd = RTE_MBUF_METADATA_UINT64_PTR(pkt, key_offset_rd);
-	uint64_t *key_wr = RTE_MBUF_METADATA_UINT64_PTR(pkt, key_offset_wr);
-	uint32_t *hash = RTE_MBUF_METADATA_UINT32_PTR(pkt, hash_offset);
-	uint64_t key_ipv6[8];
-	uint32_t hash_ipv6;
-
-	/* Read */
-	key_ipv6[0] = key_rd[0] & rte_bswap64(0x0000FF00FFFFFFFFLLU);
-	key_ipv6[1] = key_rd[1];
-	key_ipv6[2] = key_rd[2];
-	key_ipv6[3] = key_rd[3];
-	key_ipv6[4] = key_rd[4];
-	key_ipv6[5] = 0;
-	key_ipv6[6] = 0;
-	key_ipv6[7] = 0;
-
-	/* Compute */
-	hash_ipv6 = p_pt->f_hash(key_ipv6, 64, 0);
-
-	/* Write */
-	key_wr[0] = key_ipv6[0];
-	key_wr[1] = key_ipv6[1];
-	key_wr[2] = key_ipv6[2];
-	key_wr[3] = key_ipv6[3];
-	key_wr[4] = key_ipv6[4];
-	key_wr[5] = 0;
-	key_wr[6] = 0;
-	key_wr[7] = 0;
-	*hash = hash_ipv6;
+#define PKT4_WORK(dma_size, hash_enabled)			\
+static inline void						\
+pkt4_work_size##dma_size##_hash##hash_enabled(			\
+	struct rte_mbuf **pkts,					\
+	void *arg)						\
+{								\
+	pkt4_work(pkts, arg, dma_size, hash_enabled);		\
 }
 
-static inline void
-pkt4_work_key_ipv6(
-	struct rte_mbuf **pkt,
-	void *arg)
+#define port_in_ah(dma_size, hash_enabled)			\
+PKT_WORK(dma_size, hash_enabled)				\
+PKT4_WORK(dma_size, hash_enabled)				\
+PIPELINE_PORT_IN_AH(port_in_ah_size##dma_size##_hash##hash_enabled,\
+	pkt_work_size##dma_size##_hash##hash_enabled,		\
+	pkt4_work_size##dma_size##_hash##hash_enabled)
+
+
+port_in_ah(8, 0)
+port_in_ah(8, 1)
+port_in_ah(16, 0)
+port_in_ah(16, 1)
+port_in_ah(24, 0)
+port_in_ah(24, 1)
+port_in_ah(32, 0)
+port_in_ah(32, 1)
+port_in_ah(40, 0)
+port_in_ah(40, 1)
+port_in_ah(48, 0)
+port_in_ah(48, 1)
+port_in_ah(56, 0)
+port_in_ah(56, 1)
+port_in_ah(64, 0)
+port_in_ah(64, 1)
+
+static rte_pipeline_port_in_action_handler
+get_port_in_ah(struct pipeline_passthrough *p)
 {
-	struct pipeline_passthrough *p_pt = arg;
-	uint32_t key_offset_rd = p_pt->key_offset_rd;
-	uint32_t key_offset_wr = p_pt->key_offset_wr;
-	uint32_t hash_offset = p_pt->hash_offset;
-
-	uint64_t *key_rd0 = RTE_MBUF_METADATA_UINT64_PTR(pkt[0], key_offset_rd);
-	uint64_t *key_wr0 = RTE_MBUF_METADATA_UINT64_PTR(pkt[0], key_offset_wr);
-	uint32_t *hash0 = RTE_MBUF_METADATA_UINT32_PTR(pkt[0], hash_offset);
-
-	uint64_t *key_rd1 = RTE_MBUF_METADATA_UINT64_PTR(pkt[1], key_offset_rd);
-	uint64_t *key_wr1 = RTE_MBUF_METADATA_UINT64_PTR(pkt[1], key_offset_wr);
-	uint32_t *hash1 = RTE_MBUF_METADATA_UINT32_PTR(pkt[1], hash_offset);
-
-	uint64_t *key_rd2 = RTE_MBUF_METADATA_UINT64_PTR(pkt[2], key_offset_rd);
-	uint64_t *key_wr2 = RTE_MBUF_METADATA_UINT64_PTR(pkt[2], key_offset_wr);
-	uint32_t *hash2 = RTE_MBUF_METADATA_UINT32_PTR(pkt[2], hash_offset);
-
-	uint64_t *key_rd3 = RTE_MBUF_METADATA_UINT64_PTR(pkt[3], key_offset_rd);
-	uint64_t *key_wr3 = RTE_MBUF_METADATA_UINT64_PTR(pkt[3], key_offset_wr);
-	uint32_t *hash3 = RTE_MBUF_METADATA_UINT32_PTR(pkt[3], hash_offset);
-
-	uint64_t key_ipv6_0[8];
-	uint64_t key_ipv6_1[8];
-	uint64_t key_ipv6_2[8];
-	uint64_t key_ipv6_3[8];
-
-	uint32_t hash_ipv6_0;
-	uint32_t hash_ipv6_1;
-	uint32_t hash_ipv6_2;
-	uint32_t hash_ipv6_3;
-
-	/* Read */
-	key_ipv6_0[0] = key_rd0[0] & rte_bswap64(0x0000FF00FFFFFFFFLLU);
-	key_ipv6_1[0] = key_rd1[0] & rte_bswap64(0x0000FF00FFFFFFFFLLU);
-	key_ipv6_2[0] = key_rd2[0] & rte_bswap64(0x0000FF00FFFFFFFFLLU);
-	key_ipv6_3[0] = key_rd3[0] & rte_bswap64(0x0000FF00FFFFFFFFLLU);
-
-	key_ipv6_0[1] = key_rd0[1];
-	key_ipv6_1[1] = key_rd1[1];
-	key_ipv6_2[1] = key_rd2[1];
-	key_ipv6_3[1] = key_rd3[1];
-
-	key_ipv6_0[2] = key_rd0[2];
-	key_ipv6_1[2] = key_rd1[2];
-	key_ipv6_2[2] = key_rd2[2];
-	key_ipv6_3[2] = key_rd3[2];
-
-	key_ipv6_0[3] = key_rd0[3];
-	key_ipv6_1[3] = key_rd1[3];
-	key_ipv6_2[3] = key_rd2[3];
-	key_ipv6_3[3] = key_rd3[3];
-
-	key_ipv6_0[4] = key_rd0[4];
-	key_ipv6_1[4] = key_rd1[4];
-	key_ipv6_2[4] = key_rd2[4];
-	key_ipv6_3[4] = key_rd3[4];
-
-	key_ipv6_0[5] = 0;
-	key_ipv6_1[5] = 0;
-	key_ipv6_2[5] = 0;
-	key_ipv6_3[5] = 0;
-
-	key_ipv6_0[6] = 0;
-	key_ipv6_1[6] = 0;
-	key_ipv6_2[6] = 0;
-	key_ipv6_3[6] = 0;
-
-	key_ipv6_0[7] = 0;
-	key_ipv6_1[7] = 0;
-	key_ipv6_2[7] = 0;
-	key_ipv6_3[7] = 0;
-
-	/* Compute */
-	hash_ipv6_0 = p_pt->f_hash(key_ipv6_0, 64, 0);
-	hash_ipv6_1 = p_pt->f_hash(key_ipv6_1, 64, 0);
-	hash_ipv6_2 = p_pt->f_hash(key_ipv6_2, 64, 0);
-	hash_ipv6_3 = p_pt->f_hash(key_ipv6_3, 64, 0);
-
-	/* Write */
-	key_wr0[0] = key_ipv6_0[0];
-	key_wr1[0] = key_ipv6_1[0];
-	key_wr2[0] = key_ipv6_2[0];
-	key_wr3[0] = key_ipv6_3[0];
-
-	key_wr0[1] = key_ipv6_0[1];
-	key_wr1[1] = key_ipv6_1[1];
-	key_wr2[1] = key_ipv6_2[1];
-	key_wr3[1] = key_ipv6_3[1];
-
-	key_wr0[2] = key_ipv6_0[2];
-	key_wr1[2] = key_ipv6_1[2];
-	key_wr2[2] = key_ipv6_2[2];
-	key_wr3[2] = key_ipv6_3[2];
-
-	key_wr0[3] = key_ipv6_0[3];
-	key_wr1[3] = key_ipv6_1[3];
-	key_wr2[3] = key_ipv6_2[3];
-	key_wr3[3] = key_ipv6_3[3];
-
-	key_wr0[4] = key_ipv6_0[4];
-	key_wr1[4] = key_ipv6_1[4];
-	key_wr2[4] = key_ipv6_2[4];
-	key_wr3[4] = key_ipv6_3[4];
-
-	key_wr0[5] = 0;
-	key_wr0[5] = 0;
-	key_wr0[5] = 0;
-	key_wr0[5] = 0;
-
-	key_wr0[6] = 0;
-	key_wr0[6] = 0;
-	key_wr0[6] = 0;
-	key_wr0[6] = 0;
-
-	key_wr0[7] = 0;
-	key_wr0[7] = 0;
-	key_wr0[7] = 0;
-	key_wr0[7] = 0;
-
-	*hash0 = hash_ipv6_0;
-	*hash1 = hash_ipv6_1;
-	*hash2 = hash_ipv6_2;
-	*hash3 = hash_ipv6_3;
-}
+	if (p->params.dma_enabled == 0)
+		return NULL;
 
-PIPELINE_PORT_IN_AH(port_in_ah_key_ipv6, pkt_work_key_ipv6, pkt4_work_key_ipv6);
+	if (p->params.dma_hash_enabled)
+		switch (p->params.dma_size) {
+
+		case 8: return port_in_ah_size8_hash1;
+		case 16: return port_in_ah_size16_hash1;
+		case 24: return port_in_ah_size24_hash1;
+		case 32: return port_in_ah_size32_hash1;
+		case 40: return port_in_ah_size40_hash1;
+		case 48: return port_in_ah_size48_hash1;
+		case 56: return port_in_ah_size56_hash1;
+		case 64: return port_in_ah_size64_hash1;
+		default: return NULL;
+		}
+	else
+		switch (p->params.dma_size) {
+
+		case 8: return port_in_ah_size8_hash0;
+		case 16: return port_in_ah_size16_hash0;
+		case 24: return port_in_ah_size24_hash0;
+		case 32: return port_in_ah_size32_hash0;
+		case 40: return port_in_ah_size40_hash0;
+		case 48: return port_in_ah_size48_hash0;
+		case 56: return port_in_ah_size56_hash0;
+		case 64: return port_in_ah_size64_hash0;
+		default: return NULL;
+		}
+}
 
-static int
-pipeline_passthrough_parse_args(struct pipeline_passthrough *p,
+int
+pipeline_passthrough_parse_args(struct pipeline_passthrough_params *p,
 	struct pipeline_params *params)
 {
-	uint32_t key_type_present = 0;
-	uint32_t key_offset_rd_present = 0;
-	uint32_t key_offset_wr_present = 0;
-	uint32_t hash_offset_present = 0;
+	uint32_t dma_dst_offset_present = 0;
+	uint32_t dma_src_offset_present = 0;
+	uint32_t dma_src_mask_present = 0;
+	uint32_t dma_size_present = 0;
+	uint32_t dma_hash_offset_present = 0;
 	uint32_t i;
 
+	/* default values */
+	p->dma_enabled = 0;
+	p->dma_hash_enabled = 0;
+	memset(p->dma_src_mask, 0xFF, sizeof(p->dma_src_mask));
+
 	for (i = 0; i < params->n_args; i++) {
 		char *arg_name = params->args_name[i];
 		char *arg_value = params->args_value[i];
 
-		/* key_type */
-		if (strcmp(arg_name, "key_type") == 0) {
-			if (key_type_present)
+		/* dma_dst_offset */
+		if (strcmp(arg_name, "dma_dst_offset") == 0) {
+			if (dma_dst_offset_present)
 				return -1;
-			key_type_present = 1;
-
-			if ((strcmp(arg_value, "q-in-q") == 0) ||
-				(strcmp(arg_value, "qinq") == 0))
-				p->key_type = FLOW_KEY_QINQ;
-			else if (strcmp(arg_value, "ipv4_5tuple") == 0)
-				p->key_type = FLOW_KEY_IPV4_5TUPLE;
-			else if (strcmp(arg_value, "ipv6_5tuple") == 0)
-				p->key_type = FLOW_KEY_IPV6_5TUPLE;
-			else
+			dma_dst_offset_present = 1;
+
+			p->dma_dst_offset = atoi(arg_value);
+			p->dma_enabled = 1;
+
+			continue;
+		}
+
+		/* dma_src_offset */
+		if (strcmp(arg_name, "dma_src_offset") == 0) {
+			if (dma_src_offset_present)
 				return -1;
+			dma_src_offset_present = 1;
 
-			p->key_type_valid = 1;
+			p->dma_src_offset = atoi(arg_value);
+			p->dma_enabled = 1;
 
 			continue;
 		}
 
-		/* key_offset_rd */
-		if (strcmp(arg_name, "key_offset_rd") == 0) {
-			if (key_offset_rd_present)
+		/* dma_size */
+		if (strcmp(arg_name, "dma_size") == 0) {
+			if (dma_size_present)
 				return -1;
-			key_offset_rd_present = 1;
+			dma_size_present = 1;
 
-			p->key_offset_rd = atoi(arg_value);
+			p->dma_size = atoi(arg_value);
+			if ((p->dma_size == 0) ||
+				(p->dma_size > PIPELINE_PASSTHROUGH_DMA_SIZE_MAX) ||
+				((p->dma_size % 8) != 0))
+				return -1;
+
+			p->dma_enabled = 1;
 
 			continue;
 		}
 
-		/* key_offset_wr */
-		if (strcmp(arg_name, "key_offset_wr") == 0) {
-			if (key_offset_wr_present)
+		/* dma_src_mask */
+		if (strcmp(arg_name, "dma_src_mask") == 0) {
+			uint32_t dma_size;
+			int status;
+
+			if (dma_src_mask_present ||
+				(dma_size_present == 0))
+				return -1;
+			dma_src_mask_present = 1;
+
+			dma_size = p->dma_size;
+			status = parse_hex_string(arg_value,
+				p->dma_src_mask,
+				&dma_size);
+			if (status ||
+				(dma_size != p->dma_size))
 				return -1;
-			key_offset_wr_present = 1;
 
-			p->key_offset_wr = atoi(arg_value);
+			p->dma_enabled = 1;
 
 			continue;
 		}
 
-		/* hash_offset */
-		if (strcmp(arg_name, "hash_offset") == 0) {
-			if (hash_offset_present)
+		/* dma_dst_offset */
+		if (strcmp(arg_name, "dma_dst_offset") == 0) {
+			if (dma_dst_offset_present)
 				return -1;
-			hash_offset_present = 1;
+			dma_dst_offset_present = 1;
 
-			p->hash_offset = atoi(arg_value);
+			p->dma_dst_offset = atoi(arg_value);
+			p->dma_enabled = 1;
+
+			continue;
+		}
+
+		/* dma_hash_offset */
+		if (strcmp(arg_name, "dma_hash_offset") == 0) {
+			if (dma_hash_offset_present)
+				return -1;
+			dma_hash_offset_present = 1;
+
+			p->dma_hash_offset = atoi(arg_value);
+			p->dma_hash_enabled = 1;
+			p->dma_enabled = 1;
 
 			continue;
 		}
@@ -503,15 +341,35 @@  pipeline_passthrough_parse_args(struct pipeline_passthrough *p,
 		return -1;
 	}
 
-	/* Check that mandatory arguments are present */
-	if ((key_offset_rd_present != key_type_present) ||
-		(key_offset_wr_present != key_type_present) ||
-		(hash_offset_present != key_type_present))
+	/* Check correlations between arguments */
+	if ((dma_dst_offset_present != p->dma_enabled) ||
+		(dma_src_offset_present != p->dma_enabled) ||
+		(dma_size_present != p->dma_enabled) ||
+		(dma_hash_offset_present != p->dma_hash_enabled) ||
+		(p->dma_hash_enabled > p->dma_enabled))
 		return -1;
 
 	return 0;
 }
 
+
+static rte_table_hash_op_hash
+get_hash_function(struct pipeline_passthrough *p)
+{
+	switch (p->params.dma_size) {
+
+	case 8: return hash_default_key8;
+	case 16: return hash_default_key16;
+	case 24: return hash_default_key24;
+	case 32: return hash_default_key32;
+	case 40: return hash_default_key40;
+	case 48: return hash_default_key48;
+	case 56: return hash_default_key56;
+	case 64: return hash_default_key64;
+	default: return NULL;
+	}
+}
+
 static void*
 pipeline_passthrough_init(struct pipeline_params *params,
 	__rte_unused void *arg)
@@ -541,33 +399,9 @@  pipeline_passthrough_init(struct pipeline_params *params,
 	PLOG(p, HIGH, "Pass-through");
 
 	/* Parse arguments */
-	if (pipeline_passthrough_parse_args(p_pt, params))
+	if (pipeline_passthrough_parse_args(&p_pt->params, params))
 		return NULL;
-
-	if (p_pt->key_type_valid == 0) {
-		p_pt->f_hash = NULL;
-		p_pt->f_port_in_ah = NULL;
-	} else
-		switch (p_pt->key_type) {
-		case FLOW_KEY_QINQ:
-			p_pt->f_hash = hash_default_key8;
-			p_pt->f_port_in_ah = port_in_ah_key_qinq;
-			break;
-
-		case FLOW_KEY_IPV4_5TUPLE:
-			p_pt->f_hash = hash_default_key16;
-			p_pt->f_port_in_ah = port_in_ah_key_ipv4;
-			break;
-
-		case FLOW_KEY_IPV6_5TUPLE:
-			p_pt->f_hash = hash_default_key64;
-			p_pt->f_port_in_ah = port_in_ah_key_ipv6;
-			break;
-
-		default:
-			p_pt->f_hash = NULL;
-			p_pt->f_port_in_ah = NULL;
-		}
+	p_pt->f_hash = get_hash_function(p_pt);
 
 	/* Pipeline */
 	{
@@ -592,7 +426,7 @@  pipeline_passthrough_init(struct pipeline_params *params,
 				&params->port_in[i]),
 			.arg_create = pipeline_port_in_params_convert(
 				&params->port_in[i]),
-			.f_action = p_pt->f_port_in_ah,
+			.f_action = get_port_in_ah(p_pt),
 			.arg_ah = p_pt,
 			.burst_size = params->port_in[i].burst_size,
 		};
diff --git a/examples/ip_pipeline/pipeline/pipeline_passthrough_be.h b/examples/ip_pipeline/pipeline/pipeline_passthrough_be.h
index 9d5e3db..03756a1 100644
--- a/examples/ip_pipeline/pipeline/pipeline_passthrough_be.h
+++ b/examples/ip_pipeline/pipeline/pipeline_passthrough_be.h
@@ -36,6 +36,23 @@ 
 
 #include "pipeline_common_be.h"
 
+#define PIPELINE_PASSTHROUGH_DMA_SIZE_MAX                             64
+
+struct pipeline_passthrough_params {
+	uint32_t dma_enabled;
+	uint32_t dma_dst_offset;
+	uint32_t dma_src_offset;
+	uint8_t dma_src_mask[PIPELINE_PASSTHROUGH_DMA_SIZE_MAX];
+	uint32_t dma_size;
+
+	uint32_t dma_hash_enabled;
+	uint32_t dma_hash_offset;
+};
+
+int
+pipeline_passthrough_parse_args(struct pipeline_passthrough_params *p,
+	struct pipeline_params *params);
+
 extern struct pipeline_be_ops pipeline_passthrough_be_ops;
 
 #endif
diff --git a/examples/ip_pipeline/pipeline_be.h b/examples/ip_pipeline/pipeline_be.h
index 51f1e4f..25869fb 100644
--- a/examples/ip_pipeline/pipeline_be.h
+++ b/examples/ip_pipeline/pipeline_be.h
@@ -253,4 +253,7 @@  struct pipeline_be_ops {
 	pipeline_be_op_track f_track;
 };
 
+int
+parse_hex_string(char *src, uint8_t *dst, uint32_t *size);
+
 #endif