DPDK patches and discussions
 help / color / mirror / Atom feed
* [dpdk-dev] [PATCH] ip_pipeline: add load balancing function to pass-through pipeline
@ 2016-01-27 10:15 Jasvinder Singh
  2016-02-04 17:16 ` [dpdk-dev] [PATCH v2] " Jasvinder Singh
  2016-03-10 15:29 ` [dpdk-dev] [PATCH v3] " Jasvinder Singh
  0 siblings, 2 replies; 5+ messages in thread
From: Jasvinder Singh @ 2016-01-27 10:15 UTC (permalink / raw)
  To: dev

The passthrough pipeline implementation is extended with load balancing
function. This function allows uniform distribution of the packets among
its output ports. For packets distribution, any application level logic
can be applied. For instance, in this implementation, hash value
computed over specific header fields of the incoming packets has been
used to spread traffic uniformly among the output ports. The following
passthrough configuration can be used for implementing load balancing
function over ipv4 traffic;

[PIPELINE0]
type = PASS-THROUGH
core = 0
pktq_in = RXQ0.0 RXQ1.0 RXQ2.0 RXQ3.0
pktq_out = TXQ0.0 TXQ1.0 TXQ2.0 TXQ3.0
dma_src_offset = 278; mbuf (128) + headroom (128) + 1st ethertype offset (14) + ttl offset within ip header = 278 (ipv4)
dma_dst_offset = 128; mbuf (128)
dma_size = 16
dma_src_mask = 00FF0000FFFFFFFFFFFFFFFFFFFFFFFF
dma_hash_offset = 144; (dma_dst_offset+dma_size)
lb = hash

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 .../ip_pipeline/pipeline/pipeline_actions_common.h |  22 ++
 .../ip_pipeline/pipeline/pipeline_passthrough_be.c | 281 ++++++++++++++++-----
 .../ip_pipeline/pipeline/pipeline_passthrough_be.h |   2 +
 3 files changed, 245 insertions(+), 60 deletions(-)

diff --git a/examples/ip_pipeline/pipeline/pipeline_actions_common.h b/examples/ip_pipeline/pipeline/pipeline_actions_common.h
index 9958758..2c08db2 100644
--- a/examples/ip_pipeline/pipeline/pipeline_actions_common.h
+++ b/examples/ip_pipeline/pipeline/pipeline_actions_common.h
@@ -59,6 +59,28 @@ f_ah(									\
 	return 0;							\
 }
 
+#define PIPELINE_PORT_IN_AH_LB(f_ah, f_pkt_work, f_pkt4_work) \
+static int								\
+f_ah(									\
+	struct rte_pipeline *p,				\
+	struct rte_mbuf **pkts,					\
+	uint32_t n_pkts,						\
+	void *arg)						\
+{									\
+	uint32_t i;							\
+									\
+	uint64_t pkt_mask = RTE_LEN2MASK(n_pkts, uint64_t);	\
+									\
+	rte_pipeline_ah_packet_hijack(p, pkt_mask);	\
+	for (i = 0; i < (n_pkts & (~0x3LLU)); i += 4)	\
+		f_pkt4_work(&pkts[i], arg);				\
+									\
+	for ( ; i < n_pkts; i++)				\
+		f_pkt_work(pkts[i], arg);			\
+									\
+	return 0;							\
+}
+
 #define PIPELINE_TABLE_AH_HIT(f_ah, f_pkt_work, f_pkt4_work)		\
 static int								\
 f_ah(									\
diff --git a/examples/ip_pipeline/pipeline/pipeline_passthrough_be.c b/examples/ip_pipeline/pipeline/pipeline_passthrough_be.c
index 7642462..75b6fd8 100644
--- a/examples/ip_pipeline/pipeline/pipeline_passthrough_be.c
+++ b/examples/ip_pipeline/pipeline/pipeline_passthrough_be.c
@@ -72,7 +72,9 @@ pkt_work(
 	struct rte_mbuf *pkt,
 	void *arg,
 	uint32_t dma_size,
-	uint32_t hash_enabled)
+	uint32_t hash_enabled,
+	uint32_t lb_hash,
+	uint32_t port_out_pw2)
 {
 	struct pipeline_passthrough *p = arg;
 
@@ -90,8 +92,24 @@ pkt_work(
 		dma_dst[i] = dma_src[i] & dma_mask[i];
 
 	/* Read (dma_dst), compute (hash), write (hash) */
-	if (hash_enabled)
-		*dma_hash = p->f_hash(dma_dst, dma_size, 0);
+	if (hash_enabled) {
+		uint32_t hash = p->f_hash(dma_dst, dma_size, 0);
+		*dma_hash = hash;
+
+		if (lb_hash) {
+			uint32_t port_out;
+
+			if (port_out_pw2)
+				port_out
+					= hash & (p->p.n_ports_out - 1);
+			else
+				port_out
+					= hash % p->p.n_ports_out;
+
+			rte_pipeline_port_out_packet_insert(p->p.p,
+				port_out, pkt);
+		}
+	}
 }
 
 static inline __attribute__((always_inline)) void
@@ -99,7 +117,9 @@ pkt4_work(
 	struct rte_mbuf **pkts,
 	void *arg,
 	uint32_t dma_size,
-	uint32_t hash_enabled)
+	uint32_t hash_enabled,
+	uint32_t lb_hash,
+	uint32_t port_out_pw2)
 {
 	struct pipeline_passthrough *p = arg;
 
@@ -144,55 +164,144 @@ pkt4_work(
 
 	/* 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);
+		uint32_t hash0 = p->f_hash(dma_dst0, dma_size, 0);
+		uint32_t hash1 = p->f_hash(dma_dst1, dma_size, 0);
+		uint32_t hash2 = p->f_hash(dma_dst2, dma_size, 0);
+		uint32_t hash3 = p->f_hash(dma_dst3, dma_size, 0);
+
+		*dma_hash0 = hash0;
+		*dma_hash1 = hash1;
+		*dma_hash2 = hash2;
+		*dma_hash3 = hash3;
+
+		if (lb_hash) {
+			uint32_t port_out0, port_out1, port_out2, port_out3;
+
+			if (port_out_pw2) {
+				port_out0
+					= hash0 & (p->p.n_ports_out - 1);
+				port_out1
+					= hash1 & (p->p.n_ports_out - 1);
+				port_out2
+					= hash2 & (p->p.n_ports_out - 1);
+				port_out3
+					= hash3 & (p->p.n_ports_out - 1);
+			} else {
+				port_out0
+					= hash0 % p->p.n_ports_out;
+				port_out1
+					= hash1 % p->p.n_ports_out;
+				port_out2
+					= hash2 % p->p.n_ports_out;
+				port_out3
+					= hash3 % p->p.n_ports_out;
+			}
+			rte_pipeline_port_out_packet_insert(p->p.p,
+				port_out0, pkts[0]);
+			rte_pipeline_port_out_packet_insert(p->p.p,
+				port_out1, pkts[1]);
+			rte_pipeline_port_out_packet_insert(p->p.p,
+				port_out2, pkts[2]);
+			rte_pipeline_port_out_packet_insert(p->p.p,
+				port_out3, pkts[3]);
+		}
 	}
 }
 
-#define PKT_WORK(dma_size, hash_enabled)			\
+#define PKT_WORK(dma_size, hash_enabled, lb_hash, port_pw2)	\
 static inline void						\
-pkt_work_size##dma_size##_hash##hash_enabled(			\
+pkt_work_size##dma_size##_hash##hash_enabled		\
+	##_lb##lb_hash##_pw##port_pw2(			\
 	struct rte_mbuf *pkt,					\
 	void *arg)						\
 {								\
-	pkt_work(pkt, arg, dma_size, hash_enabled);		\
+	pkt_work(pkt, arg, dma_size, hash_enabled, lb_hash, port_pw2);	\
 }
 
-#define PKT4_WORK(dma_size, hash_enabled)			\
+#define PKT4_WORK(dma_size, hash_enabled, lb_hash, port_pw2)	\
 static inline void						\
-pkt4_work_size##dma_size##_hash##hash_enabled(			\
+pkt4_work_size##dma_size##_hash##hash_enabled			\
+	##_lb##lb_hash##_pw##port_pw2(			\
+	struct rte_mbuf **pkts,						\
+	void *arg)							\
+{									\
+	pkt4_work(pkts, arg, dma_size, hash_enabled, lb_hash, port_pw2); \
+}
+
+#define port_in_ah(dma_size, hash_enabled, lb_hash, port_pow2)	\
+PKT_WORK(dma_size, hash_enabled, lb_hash, port_pow2)			\
+PKT4_WORK(dma_size, hash_enabled, lb_hash, port_pow2)			\
+PIPELINE_PORT_IN_AH(port_in_ah_size##dma_size##_hash	\
+	##hash_enabled##_lb##lb_hash##_pw##port_pow2,		\
+	pkt_work_size##dma_size##_hash##hash_enabled		\
+	##_lb##lb_hash##_pw##port_pow2,			\
+	pkt4_work_size##dma_size##_hash##hash_enabled		\
+	##_lb##lb_hash##_pw##port_pow2)
+
+
+#define PKT_WORK_LB(dma_size, hash_enabled, lb_hash, port_pw2)	\
+static inline void						\
+pkt_work_size##dma_size##_hash##hash_enabled	\
+	##_lb##lb_hash##_pw##port_pw2(		\
+	struct rte_mbuf *pkt,					\
+	void *arg)						\
+{								\
+	pkt_work(pkt, arg, dma_size, hash_enabled, lb_hash, port_pw2);	\
+}
+
+#define PKT4_WORK_LB(dma_size, hash_enabled, lb_hash, port_pw2)	\
+static inline void						\
+pkt4_work_size##dma_size##_hash##hash_enabled		\
+	##_lb##lb_hash##_pw##port_pw2(		\
 	struct rte_mbuf **pkts,					\
 	void *arg)						\
 {								\
-	pkt4_work(pkts, arg, dma_size, hash_enabled);		\
+	pkt4_work(pkts, arg, dma_size, hash_enabled, lb_hash, port_pw2); \
 }
 
-#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)
+#define port_in_ah_lb(dma_size, hash_enabled, lb_hash, port_pw2)	\
+PKT_WORK_LB(dma_size, hash_enabled, lb_hash, port_pw2)			\
+PKT4_WORK_LB(dma_size, hash_enabled, lb_hash, port_pw2)		\
+PIPELINE_PORT_IN_AH_LB(						\
+	port_in_ah_size##dma_size##_hash##hash_enabled		\
+	##_lb##lb_hash##_pw##port_pw2,			\
+	pkt_work_size##dma_size##_hash##hash_enabled		\
+	##_lb##lb_hash##_pw##port_pw2,	\
+	pkt4_work_size##dma_size##_hash##hash_enabled		\
+	##_lb##lb_hash##_pw##port_pw2)
+
+port_in_ah(8, 0, 0, 0)
+port_in_ah(8, 1, 0, 0)
+port_in_ah_lb(8, 1, 1, 0)
+port_in_ah_lb(8, 1, 1, 1)
+port_in_ah(16, 0, 0, 0)
+port_in_ah(16, 1, 0, 0)
+port_in_ah_lb(16, 1, 1, 0)
+port_in_ah_lb(16, 1, 1, 1)
+port_in_ah(24, 0, 0, 0)
+port_in_ah(24, 1, 0, 0)
+port_in_ah_lb(24, 1, 1, 0)
+port_in_ah_lb(24, 1, 1, 1)
+port_in_ah(32, 0, 0, 0)
+port_in_ah(32, 1, 0, 0)
+port_in_ah_lb(32, 1, 1, 0)
+port_in_ah_lb(32, 1, 1, 1)
+port_in_ah(40, 0, 0, 0)
+port_in_ah(40, 1, 0, 0)
+port_in_ah_lb(40, 1, 1, 0)
+port_in_ah_lb(40, 1, 1, 1)
+port_in_ah(48, 0, 0, 0)
+port_in_ah(48, 1, 0, 0)
+port_in_ah_lb(48, 1, 1, 0)
+port_in_ah_lb(48, 1, 1, 1)
+port_in_ah(56, 0, 0, 0)
+port_in_ah(56, 1, 0, 0)
+port_in_ah_lb(56, 1, 1, 0)
+port_in_ah_lb(56, 1, 1, 1)
+port_in_ah(64, 0, 0, 0)
+port_in_ah(64, 1, 0, 0)
+port_in_ah_lb(64, 1, 1, 0)
+port_in_ah_lb(64, 1, 1, 1)
 
 static rte_pipeline_port_in_action_handler
 get_port_in_ah(struct pipeline_passthrough *p)
@@ -200,34 +309,63 @@ get_port_in_ah(struct pipeline_passthrough *p)
 	if (p->params.dma_enabled == 0)
 		return NULL;
 
-	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;
+	if (p->params.dma_hash_enabled) {
+		if (p->params.lb_hash_enabled) {
+			if (p->params.n_ports_out_pow_of_2)
+				switch (p->params.dma_size) {
+
+				case 8: return port_in_ah_size8_hash1_lb1_pw1;
+				case 16: return port_in_ah_size16_hash1_lb1_pw1;
+				case 24: return port_in_ah_size24_hash1_lb1_pw1;
+				case 32: return port_in_ah_size32_hash1_lb1_pw1;
+				case 40: return port_in_ah_size40_hash1_lb1_pw1;
+				case 48: return port_in_ah_size48_hash1_lb1_pw1;
+				case 56: return port_in_ah_size56_hash1_lb1_pw1;
+				case 64: return port_in_ah_size64_hash1_lb1_pw1;
+				default: return NULL;
+				}
+			else
+				switch (p->params.dma_size) {
+
+				case 8: return port_in_ah_size8_hash1_lb1_pw0;
+				case 16: return port_in_ah_size16_hash1_lb1_pw0;
+				case 24: return port_in_ah_size24_hash1_lb1_pw0;
+				case 32: return port_in_ah_size32_hash1_lb1_pw0;
+				case 40: return port_in_ah_size40_hash1_lb1_pw0;
+				case 48: return port_in_ah_size48_hash1_lb1_pw0;
+				case 56: return port_in_ah_size56_hash1_lb1_pw0;
+				case 64: return port_in_ah_size64_hash1_lb1_pw0;
+				default: return NULL;
+			}
+		} else
+			switch (p->params.dma_size) {
+
+			case 8: return port_in_ah_size8_hash1_lb0_pw0;
+			case 16: return port_in_ah_size16_hash1_lb0_pw0;
+			case 24: return port_in_ah_size24_hash1_lb0_pw0;
+			case 32: return port_in_ah_size32_hash1_lb0_pw0;
+			case 40: return port_in_ah_size40_hash1_lb0_pw0;
+			case 48: return port_in_ah_size48_hash1_lb0_pw0;
+			case 56: return port_in_ah_size56_hash1_lb0_pw0;
+			case 64: return port_in_ah_size64_hash1_lb0_pw0;
+			default: return NULL;
 		}
-	else
+	} 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;
+		case 8: return port_in_ah_size8_hash0_lb0_pw0;
+		case 16: return port_in_ah_size16_hash0_lb0_pw0;
+		case 24: return port_in_ah_size24_hash0_lb0_pw0;
+		case 32: return port_in_ah_size32_hash0_lb0_pw0;
+		case 40: return port_in_ah_size40_hash0_lb0_pw0;
+		case 48: return port_in_ah_size48_hash0_lb0_pw0;
+		case 56: return port_in_ah_size56_hash0_lb0_pw0;
+		case 64: return port_in_ah_size64_hash0_lb0_pw0;
 		default: return NULL;
 		}
 }
 
+
 int
 pipeline_passthrough_parse_args(struct pipeline_passthrough_params *p,
 	struct pipeline_params *params)
@@ -237,11 +375,14 @@ pipeline_passthrough_parse_args(struct pipeline_passthrough_params *p,
 	uint32_t dma_src_mask_present = 0;
 	uint32_t dma_size_present = 0;
 	uint32_t dma_hash_offset_present = 0;
+	uint32_t lb_present = 0;
+
 	uint32_t i;
 
 	/* default values */
 	p->dma_enabled = 0;
 	p->dma_hash_enabled = 0;
+	p->lb_hash_enabled = 0;
 	memset(p->dma_src_mask, 0xFF, sizeof(p->dma_src_mask));
 
 	for (i = 0; i < params->n_args; i++) {
@@ -337,6 +478,20 @@ pipeline_passthrough_parse_args(struct pipeline_passthrough_params *p,
 			continue;
 		}
 
+		/* load_balance mode */
+		if (strcmp(arg_name, "lb") == 0) {
+			if (lb_present)
+				return -1;
+			lb_present = 1;
+		if ((strcmp(arg_value, "hash") == 0) ||
+				(strcmp(arg_value, "HASH") == 0))
+			p->lb_hash_enabled = 1;
+		else
+			return -1;
+
+			continue;
+		}
+
 		/* any other */
 		return -1;
 	}
@@ -346,7 +501,8 @@ pipeline_passthrough_parse_args(struct pipeline_passthrough_params *p,
 		(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))
+		(p->dma_hash_enabled > p->dma_enabled) ||
+		(p->lb_hash_enabled && (p->dma_hash_enabled == 0)))
 		return -1;
 
 	return 0;
@@ -418,6 +574,11 @@ pipeline_passthrough_init(struct pipeline_params *params,
 		}
 	}
 
+	p_pt->params.n_ports_out_pow_of_2 = 0;
+	if (rte_is_power_of_2(params->n_ports_out) &&
+		p_pt->params.lb_hash_enabled)
+		p_pt->params.n_ports_out_pow_of_2 = 1;
+
 	/* Input ports */
 	p->n_ports_in = params->n_ports_in;
 	for (i = 0; i < p->n_ports_in; i++) {
diff --git a/examples/ip_pipeline/pipeline/pipeline_passthrough_be.h b/examples/ip_pipeline/pipeline/pipeline_passthrough_be.h
index 03756a1..5c8fa8d 100644
--- a/examples/ip_pipeline/pipeline/pipeline_passthrough_be.h
+++ b/examples/ip_pipeline/pipeline/pipeline_passthrough_be.h
@@ -47,6 +47,8 @@ struct pipeline_passthrough_params {
 
 	uint32_t dma_hash_enabled;
 	uint32_t dma_hash_offset;
+	uint32_t lb_hash_enabled;
+	uint32_t n_ports_out_pow_of_2;
 };
 
 int
-- 
2.5.0

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

* [dpdk-dev] [PATCH v2] ip_pipeline: add load balancing function to pass-through pipeline
  2016-01-27 10:15 [dpdk-dev] [PATCH] ip_pipeline: add load balancing function to pass-through pipeline Jasvinder Singh
@ 2016-02-04 17:16 ` Jasvinder Singh
  2016-03-10  0:26   ` Thomas Monjalon
  2016-03-10 15:29 ` [dpdk-dev] [PATCH v3] " Jasvinder Singh
  1 sibling, 1 reply; 5+ messages in thread
From: Jasvinder Singh @ 2016-02-04 17:16 UTC (permalink / raw)
  To: dev

The pass-through pipeline implementation is extended with load balancing
function. This function allows uniform distribution of the packets among
its output ports. For packets distribution, any application level logic
can be applied. For instance, in this implementation, hash value
computed over specific header fields of the incoming packets has been
used to spread traffic uniformly among the output ports. The following
pass-through configuration can be used for implementing load balancing
function over ipv4 traffic;

[PIPELINE0]
type = PASS-THROUGH
core = 0
pktq_in = RXQ0.0 RXQ1.0 RXQ2.0 RXQ3.0
pktq_out = TXQ0.0 TXQ1.0 TXQ2.0 TXQ3.0
dma_src_offset = 278; mbuf (128) + headroom (128) + 1st ethertype offset (14) + ttl offset within ip header = 278 (ipv4)
dma_dst_offset = 128; mbuf (128)
dma_size = 16
dma_src_mask = 00FF0000FFFFFFFFFFFFFFFFFFFFFFFF
dma_hash_offset = 144; (dma_dst_offset+dma_size)
lb = hash

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
v2
* modify the action handler implementation

 .../ip_pipeline/pipeline/pipeline_actions_common.h |  22 ++
 .../ip_pipeline/pipeline/pipeline_passthrough_be.c | 279 ++++++++++++++++-----
 .../ip_pipeline/pipeline/pipeline_passthrough_be.h |   1 +
 3 files changed, 236 insertions(+), 66 deletions(-)

diff --git a/examples/ip_pipeline/pipeline/pipeline_actions_common.h b/examples/ip_pipeline/pipeline/pipeline_actions_common.h
index 9958758..ab08612 100644
--- a/examples/ip_pipeline/pipeline/pipeline_actions_common.h
+++ b/examples/ip_pipeline/pipeline/pipeline_actions_common.h
@@ -59,6 +59,28 @@ f_ah(									\
 	return 0;							\
 }
 
+#define PIPELINE_PORT_IN_AH_HIJACK_ALL(f_ah, f_pkt_work, f_pkt4_work) \
+static int								\
+f_ah(									\
+	struct rte_pipeline *p,				\
+	struct rte_mbuf **pkts,					\
+	uint32_t n_pkts,						\
+	void *arg)						\
+{									\
+	uint64_t pkt_mask = RTE_LEN2MASK(n_pkts, uint64_t);	\
+	uint32_t i;							\
+									\
+	rte_pipeline_ah_packet_hijack(p, pkt_mask);	\
+									\
+	for (i = 0; i < (n_pkts & (~0x3LLU)); i += 4)	\
+		f_pkt4_work(&pkts[i], arg);				\
+									\
+	for ( ; i < n_pkts; i++)				\
+		f_pkt_work(pkts[i], arg);			\
+									\
+	return 0;							\
+}
+
 #define PIPELINE_TABLE_AH_HIT(f_ah, f_pkt_work, f_pkt4_work)		\
 static int								\
 f_ah(									\
diff --git a/examples/ip_pipeline/pipeline/pipeline_passthrough_be.c b/examples/ip_pipeline/pipeline/pipeline_passthrough_be.c
index 7642462..d2b1aa2 100644
--- a/examples/ip_pipeline/pipeline/pipeline_passthrough_be.c
+++ b/examples/ip_pipeline/pipeline/pipeline_passthrough_be.c
@@ -72,7 +72,9 @@ pkt_work(
 	struct rte_mbuf *pkt,
 	void *arg,
 	uint32_t dma_size,
-	uint32_t hash_enabled)
+	uint32_t hash_enabled,
+	uint32_t lb_hash,
+	uint32_t port_out_pow2)
 {
 	struct pipeline_passthrough *p = arg;
 
@@ -90,8 +92,24 @@ pkt_work(
 		dma_dst[i] = dma_src[i] & dma_mask[i];
 
 	/* Read (dma_dst), compute (hash), write (hash) */
-	if (hash_enabled)
-		*dma_hash = p->f_hash(dma_dst, dma_size, 0);
+	if (hash_enabled) {
+		uint32_t hash = p->f_hash(dma_dst, dma_size, 0);
+		*dma_hash = hash;
+
+		if (lb_hash) {
+			uint32_t port_out;
+
+			if (port_out_pow2)
+				port_out
+					= hash & (p->p.n_ports_out - 1);
+			else
+				port_out
+					= hash % p->p.n_ports_out;
+
+			rte_pipeline_port_out_packet_insert(p->p.p,
+				port_out, pkt);
+		}
+	}
 }
 
 static inline __attribute__((always_inline)) void
@@ -99,7 +117,9 @@ pkt4_work(
 	struct rte_mbuf **pkts,
 	void *arg,
 	uint32_t dma_size,
-	uint32_t hash_enabled)
+	uint32_t hash_enabled,
+	uint32_t lb_hash,
+	uint32_t port_out_pow2)
 {
 	struct pipeline_passthrough *p = arg;
 
@@ -144,55 +164,133 @@ pkt4_work(
 
 	/* 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);
+		uint32_t hash0 = p->f_hash(dma_dst0, dma_size, 0);
+		uint32_t hash1 = p->f_hash(dma_dst1, dma_size, 0);
+		uint32_t hash2 = p->f_hash(dma_dst2, dma_size, 0);
+		uint32_t hash3 = p->f_hash(dma_dst3, dma_size, 0);
+
+		*dma_hash0 = hash0;
+		*dma_hash1 = hash1;
+		*dma_hash2 = hash2;
+		*dma_hash3 = hash3;
+
+		if (lb_hash) {
+			uint32_t port_out0, port_out1, port_out2, port_out3;
+
+			if (port_out_pow2) {
+				port_out0
+					= hash0 & (p->p.n_ports_out - 1);
+				port_out1
+					= hash1 & (p->p.n_ports_out - 1);
+				port_out2
+					= hash2 & (p->p.n_ports_out - 1);
+				port_out3
+					= hash3 & (p->p.n_ports_out - 1);
+			} else {
+				port_out0
+					= hash0 % p->p.n_ports_out;
+				port_out1
+					= hash1 % p->p.n_ports_out;
+				port_out2
+					= hash2 % p->p.n_ports_out;
+				port_out3
+					= hash3 % p->p.n_ports_out;
+			}
+			rte_pipeline_port_out_packet_insert(p->p.p,
+				port_out0, pkts[0]);
+			rte_pipeline_port_out_packet_insert(p->p.p,
+				port_out1, pkts[1]);
+			rte_pipeline_port_out_packet_insert(p->p.p,
+				port_out2, pkts[2]);
+			rte_pipeline_port_out_packet_insert(p->p.p,
+				port_out3, pkts[3]);
+		}
 	}
 }
 
-#define PKT_WORK(dma_size, hash_enabled)			\
+#define PKT_WORK(dma_size, hash_enabled, lb_hash, port_pow2)	\
 static inline void						\
-pkt_work_size##dma_size##_hash##hash_enabled(			\
+pkt_work_size##dma_size##_hash##hash_enabled		\
+	##_lb##lb_hash##_pw##port_pow2(			\
 	struct rte_mbuf *pkt,					\
 	void *arg)						\
 {								\
-	pkt_work(pkt, arg, dma_size, hash_enabled);		\
+	pkt_work(pkt, arg, dma_size, hash_enabled, lb_hash, port_pow2);	\
 }
 
-#define PKT4_WORK(dma_size, hash_enabled)			\
+#define PKT4_WORK(dma_size, hash_enabled, lb_hash, port_pow2)	\
 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);		\
+pkt4_work_size##dma_size##_hash##hash_enabled			\
+	##_lb##lb_hash##_pw##port_pow2(			\
+	struct rte_mbuf **pkts,						\
+	void *arg)							\
+{									\
+	pkt4_work(pkts, arg, dma_size, hash_enabled, lb_hash, port_pow2); \
 }
 
-#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)
+#define port_in_ah(dma_size, hash_enabled, lb_hash, port_pow2)	\
+PKT_WORK(dma_size, hash_enabled, lb_hash, port_pow2)			\
+PKT4_WORK(dma_size, hash_enabled, lb_hash, port_pow2)			\
+PIPELINE_PORT_IN_AH(port_in_ah_size##dma_size##_hash	\
+	##hash_enabled##_lb##lb_hash##_pw##port_pow2,		\
+	pkt_work_size##dma_size##_hash##hash_enabled		\
+	##_lb##lb_hash##_pw##port_pow2,			\
+	pkt4_work_size##dma_size##_hash##hash_enabled		\
+	##_lb##lb_hash##_pw##port_pow2)
+
+
+#define port_in_ah_lb(dma_size, hash_enabled, lb_hash, port_pow2) \
+PKT_WORK(dma_size, hash_enabled, lb_hash, port_pow2)		\
+PKT4_WORK(dma_size, hash_enabled, lb_hash, port_pow2)	\
+PIPELINE_PORT_IN_AH_HIJACK_ALL(						\
+	port_in_ah_size##dma_size##_hash##hash_enabled		\
+	##_lb##lb_hash##_pw##port_pow2,			\
+	pkt_work_size##dma_size##_hash##hash_enabled		\
+	##_lb##lb_hash##_pw##port_pow2,	\
+	pkt4_work_size##dma_size##_hash##hash_enabled		\
+	##_lb##lb_hash##_pw##port_pow2)
+
+/* Port in AH (dma_size, hash_enabled, lb_hash, port_pow2) */
+
+port_in_ah(8, 0, 0, 0)
+port_in_ah(8, 1, 0, 0)
+port_in_ah_lb(8, 1, 1, 0)
+port_in_ah_lb(8, 1, 1, 1)
+
+port_in_ah(16, 0, 0, 0)
+port_in_ah(16, 1, 0, 0)
+port_in_ah_lb(16, 1, 1, 0)
+port_in_ah_lb(16, 1, 1, 1)
+
+port_in_ah(24, 0, 0, 0)
+port_in_ah(24, 1, 0, 0)
+port_in_ah_lb(24, 1, 1, 0)
+port_in_ah_lb(24, 1, 1, 1)
+
+port_in_ah(32, 0, 0, 0)
+port_in_ah(32, 1, 0, 0)
+port_in_ah_lb(32, 1, 1, 0)
+port_in_ah_lb(32, 1, 1, 1)
+
+port_in_ah(40, 0, 0, 0)
+port_in_ah(40, 1, 0, 0)
+port_in_ah_lb(40, 1, 1, 0)
+port_in_ah_lb(40, 1, 1, 1)
+
+port_in_ah(48, 0, 0, 0)
+port_in_ah(48, 1, 0, 0)
+port_in_ah_lb(48, 1, 1, 0)
+port_in_ah_lb(48, 1, 1, 1)
+
+port_in_ah(56, 0, 0, 0)
+port_in_ah(56, 1, 0, 0)
+port_in_ah_lb(56, 1, 1, 0)
+port_in_ah_lb(56, 1, 1, 1)
+
+port_in_ah(64, 0, 0, 0)
+port_in_ah(64, 1, 0, 0)
+port_in_ah_lb(64, 1, 1, 0)
+port_in_ah_lb(64, 1, 1, 1)
 
 static rte_pipeline_port_in_action_handler
 get_port_in_ah(struct pipeline_passthrough *p)
@@ -200,34 +298,63 @@ get_port_in_ah(struct pipeline_passthrough *p)
 	if (p->params.dma_enabled == 0)
 		return NULL;
 
-	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;
+	if (p->params.dma_hash_enabled) {
+		if (p->params.lb_hash_enabled) {
+			if (rte_is_power_of_2(p->p.n_ports_out))
+				switch (p->params.dma_size) {
+
+				case 8: return port_in_ah_size8_hash1_lb1_pw1;
+				case 16: return port_in_ah_size16_hash1_lb1_pw1;
+				case 24: return port_in_ah_size24_hash1_lb1_pw1;
+				case 32: return port_in_ah_size32_hash1_lb1_pw1;
+				case 40: return port_in_ah_size40_hash1_lb1_pw1;
+				case 48: return port_in_ah_size48_hash1_lb1_pw1;
+				case 56: return port_in_ah_size56_hash1_lb1_pw1;
+				case 64: return port_in_ah_size64_hash1_lb1_pw1;
+				default: return NULL;
+				}
+			else
+				switch (p->params.dma_size) {
+
+				case 8: return port_in_ah_size8_hash1_lb1_pw0;
+				case 16: return port_in_ah_size16_hash1_lb1_pw0;
+				case 24: return port_in_ah_size24_hash1_lb1_pw0;
+				case 32: return port_in_ah_size32_hash1_lb1_pw0;
+				case 40: return port_in_ah_size40_hash1_lb1_pw0;
+				case 48: return port_in_ah_size48_hash1_lb1_pw0;
+				case 56: return port_in_ah_size56_hash1_lb1_pw0;
+				case 64: return port_in_ah_size64_hash1_lb1_pw0;
+				default: return NULL;
+			}
+		} else
+			switch (p->params.dma_size) {
+
+			case 8: return port_in_ah_size8_hash1_lb0_pw0;
+			case 16: return port_in_ah_size16_hash1_lb0_pw0;
+			case 24: return port_in_ah_size24_hash1_lb0_pw0;
+			case 32: return port_in_ah_size32_hash1_lb0_pw0;
+			case 40: return port_in_ah_size40_hash1_lb0_pw0;
+			case 48: return port_in_ah_size48_hash1_lb0_pw0;
+			case 56: return port_in_ah_size56_hash1_lb0_pw0;
+			case 64: return port_in_ah_size64_hash1_lb0_pw0;
+			default: return NULL;
 		}
-	else
+	} 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;
+		case 8: return port_in_ah_size8_hash0_lb0_pw0;
+		case 16: return port_in_ah_size16_hash0_lb0_pw0;
+		case 24: return port_in_ah_size24_hash0_lb0_pw0;
+		case 32: return port_in_ah_size32_hash0_lb0_pw0;
+		case 40: return port_in_ah_size40_hash0_lb0_pw0;
+		case 48: return port_in_ah_size48_hash0_lb0_pw0;
+		case 56: return port_in_ah_size56_hash0_lb0_pw0;
+		case 64: return port_in_ah_size64_hash0_lb0_pw0;
 		default: return NULL;
 		}
 }
 
+
 int
 pipeline_passthrough_parse_args(struct pipeline_passthrough_params *p,
 	struct pipeline_params *params)
@@ -237,11 +364,14 @@ pipeline_passthrough_parse_args(struct pipeline_passthrough_params *p,
 	uint32_t dma_src_mask_present = 0;
 	uint32_t dma_size_present = 0;
 	uint32_t dma_hash_offset_present = 0;
+	uint32_t lb_present = 0;
+
 	uint32_t i;
 
 	/* default values */
 	p->dma_enabled = 0;
 	p->dma_hash_enabled = 0;
+	p->lb_hash_enabled = 0;
 	memset(p->dma_src_mask, 0xFF, sizeof(p->dma_src_mask));
 
 	for (i = 0; i < params->n_args; i++) {
@@ -337,6 +467,21 @@ pipeline_passthrough_parse_args(struct pipeline_passthrough_params *p,
 			continue;
 		}
 
+		/* load_balance mode */
+		if (strcmp(arg_name, "lb") == 0) {
+			if (lb_present)
+				return -1;
+			lb_present = 1;
+
+			if ((strcmp(arg_value, "hash") == 0) ||
+				(strcmp(arg_value, "HASH") == 0))
+				p->lb_hash_enabled = 1;
+			else
+				return -1;
+
+			continue;
+		}
+
 		/* any other */
 		return -1;
 	}
@@ -346,7 +491,8 @@ pipeline_passthrough_parse_args(struct pipeline_passthrough_params *p,
 		(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))
+		(p->dma_hash_enabled > p->dma_enabled) ||
+		(p->lb_hash_enabled > p->dma_hash_enabled))
 		return -1;
 
 	return 0;
@@ -418,8 +564,11 @@ pipeline_passthrough_init(struct pipeline_params *params,
 		}
 	}
 
-	/* Input ports */
 	p->n_ports_in = params->n_ports_in;
+	p->n_ports_out = params->n_ports_out;
+	p->n_tables = p->n_ports_in;
+
+	/*Input ports*/
 	for (i = 0; i < p->n_ports_in; i++) {
 		struct rte_pipeline_port_in_params port_params = {
 			.ops = pipeline_port_in_params_get_ops(
@@ -443,7 +592,6 @@ pipeline_passthrough_init(struct pipeline_params *params,
 	}
 
 	/* Output ports */
-	p->n_ports_out = params->n_ports_out;
 	for (i = 0; i < p->n_ports_out; i++) {
 		struct rte_pipeline_port_out_params port_params = {
 			.ops = pipeline_port_out_params_get_ops(
@@ -466,7 +614,6 @@ pipeline_passthrough_init(struct pipeline_params *params,
 	}
 
 	/* Tables */
-	p->n_tables = p->n_ports_in;
 	for (i = 0; i < p->n_ports_in; i++) {
 		struct rte_pipeline_table_params table_params = {
 			.ops = &rte_table_stub_ops,
diff --git a/examples/ip_pipeline/pipeline/pipeline_passthrough_be.h b/examples/ip_pipeline/pipeline/pipeline_passthrough_be.h
index 03756a1..9368cec 100644
--- a/examples/ip_pipeline/pipeline/pipeline_passthrough_be.h
+++ b/examples/ip_pipeline/pipeline/pipeline_passthrough_be.h
@@ -47,6 +47,7 @@ struct pipeline_passthrough_params {
 
 	uint32_t dma_hash_enabled;
 	uint32_t dma_hash_offset;
+	uint32_t lb_hash_enabled;
 };
 
 int
-- 
2.5.0

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

* Re: [dpdk-dev] [PATCH v2] ip_pipeline: add load balancing function to pass-through pipeline
  2016-02-04 17:16 ` [dpdk-dev] [PATCH v2] " Jasvinder Singh
@ 2016-03-10  0:26   ` Thomas Monjalon
  0 siblings, 0 replies; 5+ messages in thread
From: Thomas Monjalon @ 2016-03-10  0:26 UTC (permalink / raw)
  To: Jasvinder Singh; +Cc: dev

2016-02-04 17:16, Jasvinder Singh:
> The pass-through pipeline implementation is extended with load balancing
> function. This function allows uniform distribution of the packets among
> its output ports. For packets distribution, any application level logic
> can be applied. For instance, in this implementation, hash value
> computed over specific header fields of the incoming packets has been
> used to spread traffic uniformly among the output ports. The following
> pass-through configuration can be used for implementing load balancing
> function over ipv4 traffic;

Please rebase, thanks

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

* [dpdk-dev] [PATCH v3] ip_pipeline: add load balancing function to pass-through pipeline
  2016-01-27 10:15 [dpdk-dev] [PATCH] ip_pipeline: add load balancing function to pass-through pipeline Jasvinder Singh
  2016-02-04 17:16 ` [dpdk-dev] [PATCH v2] " Jasvinder Singh
@ 2016-03-10 15:29 ` Jasvinder Singh
  2016-03-13 15:09   ` Thomas Monjalon
  1 sibling, 1 reply; 5+ messages in thread
From: Jasvinder Singh @ 2016-03-10 15:29 UTC (permalink / raw)
  To: dev

The pass-through pipeline implementation is extended with load balancing
function. This function allows uniform distribution of the packets among
its output ports. For packets distribution, any application level logic
can be applied. For instance, in this implementation, hash value
computed over specific header fields of the incoming packets has been
used to spread traffic uniformly among the output ports.

The following pass-through configuration can be used for implementing
load balancing function over ipv4 traffic;

[PIPELINE0]
type = PASS-THROUGH
core = 0
pktq_in = RXQ0.0 RXQ1.0 RXQ2.0 RXQ3.0
pktq_out = TXQ0.0 TXQ1.0 TXQ2.0 TXQ3.0
dma_src_offset = 278; mbuf (128) + headroom (128) + 1st ethertype offset (14) + ttl offset within ip header = 278 (ipv4)
dma_dst_offset = 128; mbuf (128)
dma_size = 16
dma_src_mask = 00FF0000FFFFFFFFFFFFFFFFFFFFFFFF
dma_hash_offset = 144; (dma_dst_offset+dma_size)
lb = hash

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
v3
* rebased on master

v2
* modify the action handler implementation

 .../ip_pipeline/pipeline/pipeline_actions_common.h |  22 ++
 .../ip_pipeline/pipeline/pipeline_passthrough_be.c | 275 ++++++++++++++++-----
 .../ip_pipeline/pipeline/pipeline_passthrough_be.h |   1 +
 3 files changed, 236 insertions(+), 62 deletions(-)

diff --git a/examples/ip_pipeline/pipeline/pipeline_actions_common.h b/examples/ip_pipeline/pipeline/pipeline_actions_common.h
index 9958758..ab08612 100644
--- a/examples/ip_pipeline/pipeline/pipeline_actions_common.h
+++ b/examples/ip_pipeline/pipeline/pipeline_actions_common.h
@@ -59,6 +59,28 @@ f_ah(									\
 	return 0;							\
 }
 
+#define PIPELINE_PORT_IN_AH_HIJACK_ALL(f_ah, f_pkt_work, f_pkt4_work) \
+static int								\
+f_ah(									\
+	struct rte_pipeline *p,				\
+	struct rte_mbuf **pkts,					\
+	uint32_t n_pkts,						\
+	void *arg)						\
+{									\
+	uint64_t pkt_mask = RTE_LEN2MASK(n_pkts, uint64_t);	\
+	uint32_t i;							\
+									\
+	rte_pipeline_ah_packet_hijack(p, pkt_mask);	\
+									\
+	for (i = 0; i < (n_pkts & (~0x3LLU)); i += 4)	\
+		f_pkt4_work(&pkts[i], arg);				\
+									\
+	for ( ; i < n_pkts; i++)				\
+		f_pkt_work(pkts[i], arg);			\
+									\
+	return 0;							\
+}
+
 #define PIPELINE_TABLE_AH_HIT(f_ah, f_pkt_work, f_pkt4_work)		\
 static int								\
 f_ah(									\
diff --git a/examples/ip_pipeline/pipeline/pipeline_passthrough_be.c b/examples/ip_pipeline/pipeline/pipeline_passthrough_be.c
index 3e3fdd0..a0d11ae 100644
--- a/examples/ip_pipeline/pipeline/pipeline_passthrough_be.c
+++ b/examples/ip_pipeline/pipeline/pipeline_passthrough_be.c
@@ -73,7 +73,9 @@ pkt_work(
 	struct rte_mbuf *pkt,
 	void *arg,
 	uint32_t dma_size,
-	uint32_t hash_enabled)
+	uint32_t hash_enabled,
+	uint32_t lb_hash,
+	uint32_t port_out_pow2)
 {
 	struct pipeline_passthrough *p = arg;
 
@@ -91,8 +93,24 @@ pkt_work(
 		dma_dst[i] = dma_src[i] & dma_mask[i];
 
 	/* Read (dma_dst), compute (hash), write (hash) */
-	if (hash_enabled)
-		*dma_hash = p->f_hash(dma_dst, dma_size, 0);
+	if (hash_enabled) {
+		uint32_t hash = p->f_hash(dma_dst, dma_size, 0);
+		*dma_hash = hash;
+
+		if (lb_hash) {
+			uint32_t port_out;
+
+			if (port_out_pow2)
+				port_out
+					= hash & (p->p.n_ports_out - 1);
+			else
+				port_out
+					= hash % p->p.n_ports_out;
+
+			rte_pipeline_port_out_packet_insert(p->p.p,
+				port_out, pkt);
+		}
+	}
 }
 
 static inline __attribute__((always_inline)) void
@@ -100,7 +118,9 @@ pkt4_work(
 	struct rte_mbuf **pkts,
 	void *arg,
 	uint32_t dma_size,
-	uint32_t hash_enabled)
+	uint32_t hash_enabled,
+	uint32_t lb_hash,
+	uint32_t port_out_pow2)
 {
 	struct pipeline_passthrough *p = arg;
 
@@ -145,55 +165,133 @@ pkt4_work(
 
 	/* 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);
+		uint32_t hash0 = p->f_hash(dma_dst0, dma_size, 0);
+		uint32_t hash1 = p->f_hash(dma_dst1, dma_size, 0);
+		uint32_t hash2 = p->f_hash(dma_dst2, dma_size, 0);
+		uint32_t hash3 = p->f_hash(dma_dst3, dma_size, 0);
+
+		*dma_hash0 = hash0;
+		*dma_hash1 = hash1;
+		*dma_hash2 = hash2;
+		*dma_hash3 = hash3;
+
+		if (lb_hash) {
+			uint32_t port_out0, port_out1, port_out2, port_out3;
+
+			if (port_out_pow2) {
+				port_out0
+					= hash0 & (p->p.n_ports_out - 1);
+				port_out1
+					= hash1 & (p->p.n_ports_out - 1);
+				port_out2
+					= hash2 & (p->p.n_ports_out - 1);
+				port_out3
+					= hash3 & (p->p.n_ports_out - 1);
+			} else {
+				port_out0
+					= hash0 % p->p.n_ports_out;
+				port_out1
+					= hash1 % p->p.n_ports_out;
+				port_out2
+					= hash2 % p->p.n_ports_out;
+				port_out3
+					= hash3 % p->p.n_ports_out;
+			}
+			rte_pipeline_port_out_packet_insert(p->p.p,
+				port_out0, pkts[0]);
+			rte_pipeline_port_out_packet_insert(p->p.p,
+				port_out1, pkts[1]);
+			rte_pipeline_port_out_packet_insert(p->p.p,
+				port_out2, pkts[2]);
+			rte_pipeline_port_out_packet_insert(p->p.p,
+				port_out3, pkts[3]);
+		}
 	}
 }
 
-#define PKT_WORK(dma_size, hash_enabled)			\
+#define PKT_WORK(dma_size, hash_enabled, lb_hash, port_pow2)	\
 static inline void						\
-pkt_work_size##dma_size##_hash##hash_enabled(			\
+pkt_work_size##dma_size##_hash##hash_enabled		\
+	##_lb##lb_hash##_pw##port_pow2(			\
 	struct rte_mbuf *pkt,					\
 	void *arg)						\
 {								\
-	pkt_work(pkt, arg, dma_size, hash_enabled);		\
+	pkt_work(pkt, arg, dma_size, hash_enabled, lb_hash, port_pow2);	\
 }
 
-#define PKT4_WORK(dma_size, hash_enabled)			\
+#define PKT4_WORK(dma_size, hash_enabled, lb_hash, port_pow2)	\
 static inline void						\
-pkt4_work_size##dma_size##_hash##hash_enabled(			\
+pkt4_work_size##dma_size##_hash##hash_enabled			\
+	##_lb##lb_hash##_pw##port_pow2(			\
 	struct rte_mbuf **pkts,					\
 	void *arg)						\
 {								\
-	pkt4_work(pkts, arg, dma_size, hash_enabled);		\
+	pkt4_work(pkts, arg, dma_size, hash_enabled, lb_hash, port_pow2); \
 }
 
-#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)
+#define port_in_ah(dma_size, hash_enabled, lb_hash, port_pow2)	\
+PKT_WORK(dma_size, hash_enabled, lb_hash, port_pow2)			\
+PKT4_WORK(dma_size, hash_enabled, lb_hash, port_pow2)			\
+PIPELINE_PORT_IN_AH(port_in_ah_size##dma_size##_hash	\
+	##hash_enabled##_lb##lb_hash##_pw##port_pow2,		\
+	pkt_work_size##dma_size##_hash##hash_enabled		\
+	##_lb##lb_hash##_pw##port_pow2,			\
+	pkt4_work_size##dma_size##_hash##hash_enabled		\
+	##_lb##lb_hash##_pw##port_pow2)
+
+
+#define port_in_ah_lb(dma_size, hash_enabled, lb_hash, port_pow2) \
+PKT_WORK(dma_size, hash_enabled, lb_hash, port_pow2)		\
+PKT4_WORK(dma_size, hash_enabled, lb_hash, port_pow2)	\
+PIPELINE_PORT_IN_AH_HIJACK_ALL(						\
+	port_in_ah_size##dma_size##_hash##hash_enabled		\
+	##_lb##lb_hash##_pw##port_pow2,			\
+	pkt_work_size##dma_size##_hash##hash_enabled		\
+	##_lb##lb_hash##_pw##port_pow2,	\
+	pkt4_work_size##dma_size##_hash##hash_enabled		\
+	##_lb##lb_hash##_pw##port_pow2)
+
+/* Port in AH (dma_size, hash_enabled, lb_hash, port_pow2) */
+
+port_in_ah(8, 0, 0, 0)
+port_in_ah(8, 1, 0, 0)
+port_in_ah_lb(8, 1, 1, 0)
+port_in_ah_lb(8, 1, 1, 1)
+
+port_in_ah(16, 0, 0, 0)
+port_in_ah(16, 1, 0, 0)
+port_in_ah_lb(16, 1, 1, 0)
+port_in_ah_lb(16, 1, 1, 1)
+
+port_in_ah(24, 0, 0, 0)
+port_in_ah(24, 1, 0, 0)
+port_in_ah_lb(24, 1, 1, 0)
+port_in_ah_lb(24, 1, 1, 1)
+
+port_in_ah(32, 0, 0, 0)
+port_in_ah(32, 1, 0, 0)
+port_in_ah_lb(32, 1, 1, 0)
+port_in_ah_lb(32, 1, 1, 1)
+
+port_in_ah(40, 0, 0, 0)
+port_in_ah(40, 1, 0, 0)
+port_in_ah_lb(40, 1, 1, 0)
+port_in_ah_lb(40, 1, 1, 1)
+
+port_in_ah(48, 0, 0, 0)
+port_in_ah(48, 1, 0, 0)
+port_in_ah_lb(48, 1, 1, 0)
+port_in_ah_lb(48, 1, 1, 1)
+
+port_in_ah(56, 0, 0, 0)
+port_in_ah(56, 1, 0, 0)
+port_in_ah_lb(56, 1, 1, 0)
+port_in_ah_lb(56, 1, 1, 1)
+
+port_in_ah(64, 0, 0, 0)
+port_in_ah(64, 1, 0, 0)
+port_in_ah_lb(64, 1, 1, 0)
+port_in_ah_lb(64, 1, 1, 1)
 
 static rte_pipeline_port_in_action_handler
 get_port_in_ah(struct pipeline_passthrough *p)
@@ -201,30 +299,58 @@ get_port_in_ah(struct pipeline_passthrough *p)
 	if (p->params.dma_enabled == 0)
 		return NULL;
 
-	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;
+	if (p->params.dma_hash_enabled) {
+		if (p->params.lb_hash_enabled) {
+			if (rte_is_power_of_2(p->p.n_ports_out))
+				switch (p->params.dma_size) {
+
+				case 8: return port_in_ah_size8_hash1_lb1_pw1;
+				case 16: return port_in_ah_size16_hash1_lb1_pw1;
+				case 24: return port_in_ah_size24_hash1_lb1_pw1;
+				case 32: return port_in_ah_size32_hash1_lb1_pw1;
+				case 40: return port_in_ah_size40_hash1_lb1_pw1;
+				case 48: return port_in_ah_size48_hash1_lb1_pw1;
+				case 56: return port_in_ah_size56_hash1_lb1_pw1;
+				case 64: return port_in_ah_size64_hash1_lb1_pw1;
+				default: return NULL;
+				}
+			else
+				switch (p->params.dma_size) {
+
+				case 8: return port_in_ah_size8_hash1_lb1_pw0;
+				case 16: return port_in_ah_size16_hash1_lb1_pw0;
+				case 24: return port_in_ah_size24_hash1_lb1_pw0;
+				case 32: return port_in_ah_size32_hash1_lb1_pw0;
+				case 40: return port_in_ah_size40_hash1_lb1_pw0;
+				case 48: return port_in_ah_size48_hash1_lb1_pw0;
+				case 56: return port_in_ah_size56_hash1_lb1_pw0;
+				case 64: return port_in_ah_size64_hash1_lb1_pw0;
+				default: return NULL;
+			}
+		} else
+			switch (p->params.dma_size) {
+
+			case 8: return port_in_ah_size8_hash1_lb0_pw0;
+			case 16: return port_in_ah_size16_hash1_lb0_pw0;
+			case 24: return port_in_ah_size24_hash1_lb0_pw0;
+			case 32: return port_in_ah_size32_hash1_lb0_pw0;
+			case 40: return port_in_ah_size40_hash1_lb0_pw0;
+			case 48: return port_in_ah_size48_hash1_lb0_pw0;
+			case 56: return port_in_ah_size56_hash1_lb0_pw0;
+			case 64: return port_in_ah_size64_hash1_lb0_pw0;
+			default: return NULL;
 		}
-	else
+	} 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;
+		case 8: return port_in_ah_size8_hash0_lb0_pw0;
+		case 16: return port_in_ah_size16_hash0_lb0_pw0;
+		case 24: return port_in_ah_size24_hash0_lb0_pw0;
+		case 32: return port_in_ah_size32_hash0_lb0_pw0;
+		case 40: return port_in_ah_size40_hash0_lb0_pw0;
+		case 48: return port_in_ah_size48_hash0_lb0_pw0;
+		case 56: return port_in_ah_size56_hash0_lb0_pw0;
+		case 64: return port_in_ah_size64_hash0_lb0_pw0;
 		default: return NULL;
 		}
 }
@@ -238,12 +364,14 @@ pipeline_passthrough_parse_args(struct pipeline_passthrough_params *p,
 	uint32_t dma_src_mask_present = 0;
 	uint32_t dma_size_present = 0;
 	uint32_t dma_hash_offset_present = 0;
+	uint32_t lb_present = 0;
 	uint32_t i;
 	char dma_mask_str[PIPELINE_PASSTHROUGH_DMA_SIZE_MAX * 2];
 
 	/* default values */
 	p->dma_enabled = 0;
 	p->dma_hash_enabled = 0;
+	p->lb_hash_enabled = 0;
 	memset(p->dma_src_mask, 0xFF, sizeof(p->dma_src_mask));
 
 	for (i = 0; i < params->n_args; i++) {
@@ -362,6 +490,25 @@ pipeline_passthrough_parse_args(struct pipeline_passthrough_params *p,
 			continue;
 		}
 
+		/* load_balance mode */
+		if (strcmp(arg_name, "lb") == 0) {
+			PIPELINE_PARSE_ERR_DUPLICATE(
+				lb_present == 0,
+				params->name, arg_name);
+			lb_present = 1;
+
+			if ((strcmp(arg_value, "hash") == 0) ||
+				(strcmp(arg_value, "HASH") == 0))
+				p->lb_hash_enabled = 1;
+			else
+				PIPELINE_PARSE_ERR_INV_VAL(0,
+					params->name,
+					arg_name,
+					arg_value);
+
+			continue;
+		}
+
 		/* any other */
 		PIPELINE_PARSE_ERR_INV_ENT(0, params->name, arg_name);
 	}
@@ -379,6 +526,9 @@ pipeline_passthrough_parse_args(struct pipeline_passthrough_params *p,
 	PIPELINE_ARG_CHECK((dma_hash_offset_present == p->dma_enabled),
 		"Parse error in section \"%s\": missing entry "
 		"\"dma_hash_offset\"", params->name);
+	PIPELINE_ARG_CHECK((p->lb_hash_enabled <= p->dma_hash_enabled),
+		"Parse error in section \"%s\": missing entry "
+		"\"dma_hash_offset\"", params->name);
 
 	if (dma_src_mask_present) {
 		uint32_t dma_size = p->dma_size;
@@ -466,8 +616,11 @@ pipeline_passthrough_init(struct pipeline_params *params,
 		}
 	}
 
-	/* Input ports */
 	p->n_ports_in = params->n_ports_in;
+	p->n_ports_out = params->n_ports_out;
+	p->n_tables = p->n_ports_in;
+
+	/*Input ports*/
 	for (i = 0; i < p->n_ports_in; i++) {
 		struct rte_pipeline_port_in_params port_params = {
 			.ops = pipeline_port_in_params_get_ops(
@@ -491,7 +644,6 @@ pipeline_passthrough_init(struct pipeline_params *params,
 	}
 
 	/* Output ports */
-	p->n_ports_out = params->n_ports_out;
 	for (i = 0; i < p->n_ports_out; i++) {
 		struct rte_pipeline_port_out_params port_params = {
 			.ops = pipeline_port_out_params_get_ops(
@@ -514,7 +666,6 @@ pipeline_passthrough_init(struct pipeline_params *params,
 	}
 
 	/* Tables */
-	p->n_tables = p->n_ports_in;
 	for (i = 0; i < p->n_ports_in; i++) {
 		struct rte_pipeline_table_params table_params = {
 			.ops = &rte_table_stub_ops,
diff --git a/examples/ip_pipeline/pipeline/pipeline_passthrough_be.h b/examples/ip_pipeline/pipeline/pipeline_passthrough_be.h
index 03756a1..9368cec 100644
--- a/examples/ip_pipeline/pipeline/pipeline_passthrough_be.h
+++ b/examples/ip_pipeline/pipeline/pipeline_passthrough_be.h
@@ -47,6 +47,7 @@ struct pipeline_passthrough_params {
 
 	uint32_t dma_hash_enabled;
 	uint32_t dma_hash_offset;
+	uint32_t lb_hash_enabled;
 };
 
 int
-- 
2.5.0

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

* Re: [dpdk-dev] [PATCH v3] ip_pipeline: add load balancing function to pass-through pipeline
  2016-03-10 15:29 ` [dpdk-dev] [PATCH v3] " Jasvinder Singh
@ 2016-03-13 15:09   ` Thomas Monjalon
  0 siblings, 0 replies; 5+ messages in thread
From: Thomas Monjalon @ 2016-03-13 15:09 UTC (permalink / raw)
  To: Jasvinder Singh; +Cc: dev

2016-03-10 15:29, Jasvinder Singh:
> The pass-through pipeline implementation is extended with load balancing
> function. This function allows uniform distribution of the packets among
> its output ports. For packets distribution, any application level logic
> can be applied. For instance, in this implementation, hash value
> computed over specific header fields of the incoming packets has been
> used to spread traffic uniformly among the output ports.

Applied, thanks

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

end of thread, other threads:[~2016-03-13 15:10 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-01-27 10:15 [dpdk-dev] [PATCH] ip_pipeline: add load balancing function to pass-through pipeline Jasvinder Singh
2016-02-04 17:16 ` [dpdk-dev] [PATCH v2] " Jasvinder Singh
2016-03-10  0:26   ` Thomas Monjalon
2016-03-10 15:29 ` [dpdk-dev] [PATCH v3] " Jasvinder Singh
2016-03-13 15:09   ` Thomas Monjalon

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).