[dpdk-dev] [PATCH v1] examples/ipsec-secgw: support flow director feature

Subsystems: the rest

23 messages, 3 authors, 2020-04-17 · open the first message on its own page

[dpdk-dev] [PATCH v1] examples/ipsec-secgw: support flow director feature

From: Praveen Shetty <hidden>
Date: 2020-03-11 14:55:39

Modified Secuirty gateway application to support configuration of
flow director rule to direct inbound IPsec SA to a specified queue.

Signed-off-by: Praveen Shetty <redacted>
---
 examples/ipsec-secgw/ep0.cfg       | 11 +++++
 examples/ipsec-secgw/ipsec-secgw.c | 56 ++++++++++++++++++++++++-
 examples/ipsec-secgw/ipsec.c       | 67 ++++++++++++++++++++++++++++++
 examples/ipsec-secgw/ipsec.h       | 11 +++++
 examples/ipsec-secgw/sa.c          | 50 +++++++++++++++++++++-
 5 files changed, 192 insertions(+), 3 deletions(-)
diff --git a/examples/ipsec-secgw/ep0.cfg b/examples/ipsec-secgw/ep0.cfg
index dfd4aca7d..c9f80e81b 100644
--- a/examples/ipsec-secgw/ep0.cfg
+++ b/examples/ipsec-secgw/ep0.cfg
@@ -29,6 +29,7 @@ sp ipv4 in esp protect 111 pri 1 dst 192.168.186.0/24 sport 0:65535 dport 0:6553
 sp ipv4 in esp protect 115 pri 1 dst 192.168.210.0/24 sport 0:65535 dport 0:65535
 sp ipv4 in esp protect 116 pri 1 dst 192.168.211.0/24 sport 0:65535 dport 0:65535
 sp ipv4 in esp protect 115 pri 1 dst 192.168.210.0/24 sport 0:65535 dport 0:65535
+sp ipv4 in esp protect 117 pri 1 dst 192.168.212.0/24 sport 0:65535 dport 0:65535
 sp ipv4 in esp protect 125 pri 1 dst 192.168.65.0/24 sport 0:65535 dport 0:65535
 sp ipv4 in esp protect 125 pri 1 dst 192.168.65.0/24 sport 0:65535 dport 0:65535
 sp ipv4 in esp protect 126 pri 1 dst 192.168.66.0/24 sport 0:65535 dport 0:65535
@@ -61,6 +62,8 @@ sp ipv6 in esp protect 125 pri 1 dst ffff:0000:0000:0000:aaaa:aaaa:0000:0000/96
 sport 0:65535 dport 0:65535
 sp ipv6 in esp protect 126 pri 1 dst ffff:0000:0000:0000:bbbb:bbbb:0000:0000/96 \
 sport 0:65535 dport 0:65535
+sp ipv6 in esp protect 127 pri 1 dst ffff:0000:0000:0000:cccc:dddd:0000:0000/96 \
+sport 0:65535 dport 0:65535
 
 #SA rules
 sa out 5 cipher_algo aes-128-cbc cipher_key 0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0 \
@@ -118,6 +121,9 @@ dst 172.16.1.5
 
 sa in 116 cipher_algo null auth_algo null mode ipv4-tunnel src 172.16.2.6 dst 172.16.1.6
 
+sa in 117 cipher_algo null auth_algo null mode ipv4-tunnel src 172.16.2.7 \
+dst 172.16.1.7 flow-direction 0 2 port_id 0 type lookaside-protocol-offload
+
 sa in 125 cipher_algo aes-128-cbc cipher_key c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:\
 c3:c3:c3:c3:c3 auth_algo sha1-hmac auth_key c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:\
 c3:c3:c3:c3:c3:c3:c3:c3:c3 mode ipv6-tunnel \
@@ -130,6 +136,11 @@ sa in 126 cipher_algo aes-128-cbc cipher_key 4d:4d:4d:4d:4d:4d:4d:4d:4d:4d:4d:\
 src 2222:2222:2222:2222:2222:2222:2222:6666 \
 dst 1111:1111:1111:1111:1111:1111:1111:6666
 
+sa in 127 cipher_algo null auth_algo null mode ipv6-tunnel \
+src 2222:2222:2222:2222:2222:2222:2222:7777 \
+dst 1111:1111:1111:1111:1111:1111:1111:7777 \
+flow-direction 0 3 port_id 0 type lookaside-protocol-offload
+
 #Routing rules
 rt ipv4 dst 172.16.2.5/32 port 0
 rt ipv4 dst 172.16.2.6/32 port 1
diff --git a/examples/ipsec-secgw/ipsec-secgw.c b/examples/ipsec-secgw/ipsec-secgw.c
index 4799bc90c..132484422 100644
--- a/examples/ipsec-secgw/ipsec-secgw.c
+++ b/examples/ipsec-secgw/ipsec-secgw.c
@@ -166,7 +166,6 @@ static const struct option lgopts[] = {
 	{CMD_LINE_OPT_FRAG_TTL, 1, 0, CMD_LINE_OPT_FRAG_TTL_NUM},
 	{NULL, 0, 0, 0}
 };
-
 /* mask of enabled ports */
 static uint32_t enabled_port_mask;
 static uint64_t enabled_cryptodev_mask = UINT64_MAX;
@@ -259,6 +258,30 @@ static struct rte_eth_conf port_conf = {
 	.txmode = {
 		.mq_mode = ETH_MQ_TX_NONE,
 	},
+	.fdir_conf = {
+	.mode = RTE_FDIR_MODE_NONE,
+	.pballoc = RTE_FDIR_PBALLOC_64K,
+	.status = RTE_FDIR_REPORT_STATUS,
+	.mask = {
+		.vlan_tci_mask = 0xFFEF,
+		.ipv4_mask     = {
+			.src_ip = 0xFFFFFFFF,
+			.dst_ip = 0xFFFFFFFF,
+		},
+		.ipv6_mask     = {
+			.src_ip = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+						0xFFFFFFFF},
+			.dst_ip = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+						0xFFFFFFFF},
+		},
+		.src_port_mask = 0xFFFF,
+		.dst_port_mask = 0xFFFF,
+		.mac_addr_byte_mask = 0xFF,
+		.tunnel_type_mask = 1,
+		.tunnel_id_mask = 0xFFFFFFFF,
+	},
+	.drop_queue = 127,
+	}
 };
 
 static struct socket_ctx socket_ctx[NB_SOCKETS];
@@ -1184,7 +1207,6 @@ main_loop(__attribute__((unused)) void *dummy)
 
 			if (nb_rx > 0)
 				process_pkts(qconf, pkts, nb_rx, portid);
-
 			/* dequeue and process completed crypto-ops */
 			if (UNPROTECTED_PORT(portid))
 				drain_inbound_crypto_queues(qconf,
@@ -1196,6 +1218,27 @@ main_loop(__attribute__((unused)) void *dummy)
 	}
 }
 
+int check_flow_params(uint16_t fdir_portid, uint8_t fdir_qid)
+{
+	uint16_t i;
+	uint16_t portid;
+	uint8_t queueid;
+
+	for (i = 0; i < nb_lcore_params; ++i) {
+		portid = lcore_params_array[i].port_id;
+		if (portid == fdir_portid) {
+			queueid = lcore_params_array[i].queue_id;
+			if (queueid == fdir_qid)
+				break;
+		}
+
+		if (i == nb_lcore_params - 1)
+			return -1;
+	}
+
+	return 1;
+}
+
 static int32_t
 check_params(void)
 {
@@ -2503,6 +2546,15 @@ main(int32_t argc, char **argv)
 			continue;
 
 		sa_check_offloads(portid, &req_rx_offloads, &req_tx_offloads);
+		/* check if FDIR is configured on the port */
+		if (check_fdir_configured(portid)) {
+			/* Enable FDIR */
+			port_conf.fdir_conf.mode = RTE_FDIR_MODE_PERFECT;
+			/* Disable RSS */
+			port_conf.rxmode.mq_mode = ETH_MQ_RX_NONE;
+			port_conf.rx_adv_conf.rss_conf.rss_hf = 0;
+			port_conf.rx_adv_conf.rss_conf.rss_key = NULL;
+		}
 		port_init(portid, req_rx_offloads, req_tx_offloads);
 	}
 
diff --git a/examples/ipsec-secgw/ipsec.c b/examples/ipsec-secgw/ipsec.c
index 6e8120702..363809cfd 100644
--- a/examples/ipsec-secgw/ipsec.c
+++ b/examples/ipsec-secgw/ipsec.c
@@ -415,6 +415,73 @@ create_inline_session(struct socket_ctx *skt_ctx, struct ipsec_sa *sa,
 	return 0;
 }
 
+int
+create_ipsec_esp_flow(struct ipsec_sa *sa)
+{
+	int ret = 0;
+	struct rte_flow_error err;
+	if (sa->direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS)
+		return 0; /* No Flow director rules for Egress traffic */
+	if (sa->flags == TRANSPORT) {
+		RTE_LOG(ERR, IPSEC,
+			"No Flow director rule for transport mode:");
+			return -1;
+	}
+	sa->action[0].type = RTE_FLOW_ACTION_TYPE_QUEUE;
+	sa->pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
+	sa->action[0].conf =
+			&(struct rte_flow_action_queue){
+				.index = sa->fdir_qid,
+	};
+	sa->attr.egress = 0;
+	sa->attr.ingress = 1;
+	if (IS_IP6(sa->flags)) {
+		sa->pattern[1].mask = &rte_flow_item_ipv6_mask;
+		sa->pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV6;
+		sa->pattern[1].spec = &sa->ipv6_spec;
+		memcpy(sa->ipv6_spec.hdr.dst_addr,
+				sa->dst.ip.ip6.ip6_b, IPV6_ADDR_LEN);
+		memcpy(sa->ipv6_spec.hdr.src_addr,
+				sa->src.ip.ip6.ip6_b, IPV6_ADDR_LEN);
+		sa->pattern[2].type = RTE_FLOW_ITEM_TYPE_ESP;
+		sa->pattern[2].spec = &sa->esp_spec;
+		sa->pattern[2].mask = &rte_flow_item_esp_mask;
+		sa->esp_spec.hdr.spi = rte_cpu_to_be_32(sa->spi);
+		sa->pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
+	} else if (IS_IP4(sa->flags)) {
+		sa->pattern[1].mask = &rte_flow_item_ipv4_mask;
+		sa->pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV4;
+		sa->pattern[1].spec = &sa->ipv4_spec;
+		sa->ipv4_spec.hdr.dst_addr = sa->dst.ip.ip4;
+		sa->ipv4_spec.hdr.src_addr = sa->src.ip.ip4;
+		sa->pattern[2].type = RTE_FLOW_ITEM_TYPE_ESP;
+		sa->pattern[2].spec = &sa->esp_spec;
+		sa->pattern[2].mask = &rte_flow_item_esp_mask;
+		sa->esp_spec.hdr.spi = rte_cpu_to_be_32(sa->spi);
+		sa->pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
+	}
+	sa->action[1].type = RTE_FLOW_ACTION_TYPE_END;
+
+	ret = rte_flow_validate(sa->fdir_portid, &sa->attr,
+				sa->pattern, sa->action,
+				&err);
+	if (ret < 0) {
+		RTE_LOG(ERR, IPSEC,
+			"Flow Validation failed\n");
+		return ret;
+	}
+	sa->flow = rte_flow_create(sa->fdir_portid,
+				&sa->attr, sa->pattern, sa->action,
+				&err);
+	if (!sa->flow) {
+		RTE_LOG(ERR, IPSEC,
+			"Flow Creation failed\n");
+		return -1;
+	}
+
+	return 0;
+}
+
 /*
  * queue crypto-ops into PMD queue.
  */
diff --git a/examples/ipsec-secgw/ipsec.h b/examples/ipsec-secgw/ipsec.h
index 4f2fd6184..00147895a 100644
--- a/examples/ipsec-secgw/ipsec.h
+++ b/examples/ipsec-secgw/ipsec.h
@@ -46,6 +46,8 @@
 
 #define IP6_VERSION (6)
 
+#define IPV6_ADDR_LEN   16
+
 struct rte_crypto_xform;
 struct ipsec_xform;
 struct rte_mbuf;
@@ -138,6 +140,9 @@ struct ipsec_sa {
 	};
 	enum rte_security_ipsec_sa_direction direction;
 	uint16_t portid;
+	uint16_t fdir_portid;
+	uint8_t fdir_qid;
+	uint8_t fdir_flag;
 
 #define MAX_RTE_FLOW_PATTERN (4)
 #define MAX_RTE_FLOW_ACTIONS (3)
@@ -383,5 +388,11 @@ create_lookaside_session(struct ipsec_ctx *ipsec_ctx, struct ipsec_sa *sa,
 int
 create_inline_session(struct socket_ctx *skt_ctx, struct ipsec_sa *sa,
 		struct rte_ipsec_session *ips);
+int
+check_flow_params(uint16_t fdir_portid, uint8_t fdir_qid);
+
+int
+create_ipsec_esp_flow(struct ipsec_sa *sa);
 
+int check_fdir_configured(uint16_t portid);
 #endif /* __IPSEC_H__ */
diff --git a/examples/ipsec-secgw/sa.c b/examples/ipsec-secgw/sa.c
index 4822d6bda..9955dfcbe 100644
--- a/examples/ipsec-secgw/sa.c
+++ b/examples/ipsec-secgw/sa.c
@@ -20,6 +20,9 @@
 #include <rte_random.h>
 #include <rte_ethdev.h>
 #include <rte_malloc.h>
+#include <rte_common.h>
+#include <rte_string_fns.h>
+#include <rte_ethdev_driver.h>
 
 #include "ipsec.h"
 #include "esp.h"
@@ -271,6 +274,7 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	uint32_t type_p = 0;
 	uint32_t portid_p = 0;
 	uint32_t fallback_p = 0;
+	int16_t status_p = 0;
 
 	if (strcmp(tokens[0], "in") == 0) {
 		ri = &nb_sa_in;
@@ -681,6 +685,25 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 			fallback_p = 1;
 			continue;
 		}
+		if (strcmp(tokens[ti], "flow-direction") == 0) {
+			rule->fdir_flag = 1;
+			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
+			if (status->status < 0)
+				return;
+			rule->fdir_portid = atoi(tokens[ti]);
+			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
+			if (status->status < 0)
+				return;
+			rule->fdir_qid = atoi(tokens[ti]);
+			/* validating portid and queueid */
+			status_p = check_flow_params(rule->fdir_portid,
+					rule->fdir_qid);
+			if (status_p < 0) {
+				printf("port id %u / queue id %u is not valid\n",
+					rule->fdir_portid, rule->fdir_qid);
+			}
+			continue;
+		}
 
 		/* unrecognizeable input */
 		APP_CHECK(0, status, "unrecognized input \"%s\"",
@@ -823,6 +846,9 @@ print_one_sa_rule(const struct ipsec_sa *sa, int inbound)
 			break;
 		}
 	}
+	if (sa->fdir_flag == 1)
+		printf("flow-direction %d %d", sa->fdir_portid, sa->fdir_qid);
+
 	printf("\n");
 }
 
@@ -1153,7 +1179,15 @@ sa_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
 				return -EINVAL;
 			}
 		}
-
+		if (sa->fdir_flag &&
+			ips->type ==
+			RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL &&
+			inbound) {
+			rc = create_ipsec_esp_flow(sa);
+			if (rc != 0)
+				RTE_LOG(ERR, IPSEC_ESP,
+					"create_ipsec_esp flow failed\n");
+			}
 		print_one_sa_rule(sa, inbound);
 	}
 
@@ -1256,6 +1290,20 @@ fill_ipsec_session(struct rte_ipsec_session *ss, struct rte_ipsec_sa *sa)
 	return rc;
 }
 
+int
+check_fdir_configured(uint16_t portid)
+{
+	struct ipsec_sa *sa = NULL;
+	uint32_t idx_sa = 0;
+
+	for (idx_sa = 0; idx_sa < nb_sa_in; idx_sa++) {
+		sa = &sa_in[idx_sa];
+		if (sa->fdir_portid == portid)
+			return sa->fdir_flag;
+	}
+	return 0;
+}
+
 /*
  * Initialise related rte_ipsec_sa object.
  */
-- 
2.17.1

Re: [dpdk-dev] [PATCH v1] examples/ipsec-secgw: support flow director feature

From: Anoob Joseph <hidden>
Date: 2020-03-12 11:01:01

Hi Praveen,

I do have some review comments on the code. Before that, can you give a brief overview of what is being targeted? My understanding is that the primary objective is to use rte_flow (or flow director) to redirect a specific flow(/SA) to a specific queue. Can you confirm?

Couple of questions,
1. I would assume the new option of "flow-direction" is optional and is determined per SA. In that case, can I assume that RSS would be active for the other flows (or SAs). Let's say, I just want to add a SA for which I would like to enable "flow-direction" but leave the rest as is. How is that handled?
2. I see that the changes are only applicable for LOOKASIDE_PROTOCOL. The same feature would be useful for other modes as well, right?
3. I'm not sure "flow-direction" is the right wording for the option. This is just specifying the "rx-queue" per SA. @Akhil, Konstantin, comments?

Thanks,
Anoob
quoted hunk
-----Original Message-----
From: dev <redacted> On Behalf Of Praveen Shetty
Sent: Wednesday, March 11, 2020 8:25 PM
To: dev@dpdk.org; declan.doherty@intel.com; bernard.iremonger@intel.com;
konstantin.ananyev@intel.com
Subject: [dpdk-dev] [PATCH v1] examples/ipsec-secgw: support flow director
feature

Modified Secuirty gateway application to support configuration of flow director
rule to direct inbound IPsec SA to a specified queue.

Signed-off-by: Praveen Shetty <redacted>
---
 examples/ipsec-secgw/ep0.cfg       | 11 +++++
 examples/ipsec-secgw/ipsec-secgw.c | 56 ++++++++++++++++++++++++-
 examples/ipsec-secgw/ipsec.c       | 67 ++++++++++++++++++++++++++++++
 examples/ipsec-secgw/ipsec.h       | 11 +++++
 examples/ipsec-secgw/sa.c          | 50 +++++++++++++++++++++-
 5 files changed, 192 insertions(+), 3 deletions(-)
diff --git a/examples/ipsec-secgw/ep0.cfg b/examples/ipsec-secgw/ep0.cfg
index dfd4aca7d..c9f80e81b 100644
--- a/examples/ipsec-secgw/ep0.cfg
+++ b/examples/ipsec-secgw/ep0.cfg
@@ -29,6 +29,7 @@ sp ipv4 in esp protect 111 pri 1 dst 192.168.186.0/24 sport
0:65535 dport 0:6553  sp ipv4 in esp protect 115 pri 1 dst 192.168.210.0/24 sport
0:65535 dport 0:65535  sp ipv4 in esp protect 116 pri 1 dst 192.168.211.0/24
sport 0:65535 dport 0:65535  sp ipv4 in esp protect 115 pri 1 dst
192.168.210.0/24 sport 0:65535 dport 0:65535
+sp ipv4 in esp protect 117 pri 1 dst 192.168.212.0/24 sport 0:65535
+dport 0:65535
 sp ipv4 in esp protect 125 pri 1 dst 192.168.65.0/24 sport 0:65535 dport 0:65535
sp ipv4 in esp protect 125 pri 1 dst 192.168.65.0/24 sport 0:65535 dport 0:65535
sp ipv4 in esp protect 126 pri 1 dst 192.168.66.0/24 sport 0:65535 dport 0:65535
@@ -61,6 +62,8 @@ sp ipv6 in esp protect 125 pri 1 dst
ffff:0000:0000:0000:aaaa:aaaa:0000:0000/96
 sport 0:65535 dport 0:65535
 sp ipv6 in esp protect 126 pri 1 dst
ffff:0000:0000:0000:bbbb:bbbb:0000:0000/96 \  sport 0:65535 dport 0:65535
+sp ipv6 in esp protect 127 pri 1 dst
+ffff:0000:0000:0000:cccc:dddd:0000:0000/96 \ sport 0:65535 dport
+0:65535

 #SA rules
 sa out 5 cipher_algo aes-128-cbc cipher_key 0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0 \
@@ -118,6 +121,9 @@ dst 172.16.1.5

 sa in 116 cipher_algo null auth_algo null mode ipv4-tunnel src 172.16.2.6 dst
172.16.1.6

+sa in 117 cipher_algo null auth_algo null mode ipv4-tunnel src
+172.16.2.7 \ dst 172.16.1.7 flow-direction 0 2 port_id 0 type
+lookaside-protocol-offload
+
 sa in 125 cipher_algo aes-128-cbc cipher_key c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:\
 c3:c3:c3:c3:c3 auth_algo sha1-hmac auth_key
c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:\
 c3:c3:c3:c3:c3:c3:c3:c3:c3 mode ipv6-tunnel \ @@ -130,6 +136,11 @@ sa in
126 cipher_algo aes-128-cbc cipher_key 4d:4d:4d:4d:4d:4d:4d:4d:4d:4d:4d:\
 src 2222:2222:2222:2222:2222:2222:2222:6666 \  dst
1111:1111:1111:1111:1111:1111:1111:6666

+sa in 127 cipher_algo null auth_algo null mode ipv6-tunnel \ src
+2222:2222:2222:2222:2222:2222:2222:7777 \ dst
+1111:1111:1111:1111:1111:1111:1111:7777 \ flow-direction 0 3 port_id 0
+type lookaside-protocol-offload
+
 #Routing rules
 rt ipv4 dst 172.16.2.5/32 port 0
 rt ipv4 dst 172.16.2.6/32 port 1
diff --git a/examples/ipsec-secgw/ipsec-secgw.c b/examples/ipsec-
secgw/ipsec-secgw.c
index 4799bc90c..132484422 100644
--- a/examples/ipsec-secgw/ipsec-secgw.c
+++ b/examples/ipsec-secgw/ipsec-secgw.c
@@ -166,7 +166,6 @@ static const struct option lgopts[] = {
 	{CMD_LINE_OPT_FRAG_TTL, 1, 0, CMD_LINE_OPT_FRAG_TTL_NUM},
 	{NULL, 0, 0, 0}
 };
-
 /* mask of enabled ports */
 static uint32_t enabled_port_mask;
 static uint64_t enabled_cryptodev_mask = UINT64_MAX; @@ -259,6 +258,30
@@ static struct rte_eth_conf port_conf = {
 	.txmode = {
 		.mq_mode = ETH_MQ_TX_NONE,
 	},
+	.fdir_conf = {
+	.mode = RTE_FDIR_MODE_NONE,
+	.pballoc = RTE_FDIR_PBALLOC_64K,
+	.status = RTE_FDIR_REPORT_STATUS,
+	.mask = {
+		.vlan_tci_mask = 0xFFEF,
+		.ipv4_mask     = {
+			.src_ip = 0xFFFFFFFF,
+			.dst_ip = 0xFFFFFFFF,
+		},
+		.ipv6_mask     = {
+			.src_ip = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+						0xFFFFFFFF},
+			.dst_ip = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+						0xFFFFFFFF},
+		},
+		.src_port_mask = 0xFFFF,
+		.dst_port_mask = 0xFFFF,
+		.mac_addr_byte_mask = 0xFF,
+		.tunnel_type_mask = 1,
+		.tunnel_id_mask = 0xFFFFFFFF,
+	},
+	.drop_queue = 127,
+	}
 };

 static struct socket_ctx socket_ctx[NB_SOCKETS]; @@ -1184,7 +1207,6 @@
main_loop(__attribute__((unused)) void *dummy)

 			if (nb_rx > 0)
 				process_pkts(qconf, pkts, nb_rx, portid);
-
 			/* dequeue and process completed crypto-ops */
 			if (UNPROTECTED_PORT(portid))
 				drain_inbound_crypto_queues(qconf,
@@ -1196,6 +1218,27 @@ main_loop(__attribute__((unused)) void *dummy)
 	}
 }

+int check_flow_params(uint16_t fdir_portid, uint8_t fdir_qid) {
+	uint16_t i;
+	uint16_t portid;
+	uint8_t queueid;
+
+	for (i = 0; i < nb_lcore_params; ++i) {
+		portid = lcore_params_array[i].port_id;
+		if (portid == fdir_portid) {
+			queueid = lcore_params_array[i].queue_id;
+			if (queueid == fdir_qid)
+				break;
+		}
+
+		if (i == nb_lcore_params - 1)
+			return -1;
+	}
+
+	return 1;
+}
+
 static int32_t
 check_params(void)
 {
@@ -2503,6 +2546,15 @@ main(int32_t argc, char **argv)
 			continue;

 		sa_check_offloads(portid, &req_rx_offloads,
&req_tx_offloads);
+		/* check if FDIR is configured on the port */
+		if (check_fdir_configured(portid)) {
+			/* Enable FDIR */
+			port_conf.fdir_conf.mode =
RTE_FDIR_MODE_PERFECT;
+			/* Disable RSS */
+			port_conf.rxmode.mq_mode = ETH_MQ_RX_NONE;
+			port_conf.rx_adv_conf.rss_conf.rss_hf = 0;
+			port_conf.rx_adv_conf.rss_conf.rss_key = NULL;
+		}
 		port_init(portid, req_rx_offloads, req_tx_offloads);
 	}
diff --git a/examples/ipsec-secgw/ipsec.c b/examples/ipsec-secgw/ipsec.c index
6e8120702..363809cfd 100644
--- a/examples/ipsec-secgw/ipsec.c
+++ b/examples/ipsec-secgw/ipsec.c
@@ -415,6 +415,73 @@ create_inline_session(struct socket_ctx *skt_ctx,
struct ipsec_sa *sa,
 	return 0;
 }

+int
+create_ipsec_esp_flow(struct ipsec_sa *sa) {
+	int ret = 0;
+	struct rte_flow_error err;
+	if (sa->direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS)
+		return 0; /* No Flow director rules for Egress traffic */
+	if (sa->flags == TRANSPORT) {
+		RTE_LOG(ERR, IPSEC,
+			"No Flow director rule for transport mode:");
+			return -1;
+	}
+	sa->action[0].type = RTE_FLOW_ACTION_TYPE_QUEUE;
+	sa->pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
+	sa->action[0].conf =
+			&(struct rte_flow_action_queue){
+				.index = sa->fdir_qid,
+	};
+	sa->attr.egress = 0;
+	sa->attr.ingress = 1;
+	if (IS_IP6(sa->flags)) {
+		sa->pattern[1].mask = &rte_flow_item_ipv6_mask;
+		sa->pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV6;
+		sa->pattern[1].spec = &sa->ipv6_spec;
+		memcpy(sa->ipv6_spec.hdr.dst_addr,
+				sa->dst.ip.ip6.ip6_b, IPV6_ADDR_LEN);
+		memcpy(sa->ipv6_spec.hdr.src_addr,
+				sa->src.ip.ip6.ip6_b, IPV6_ADDR_LEN);
+		sa->pattern[2].type = RTE_FLOW_ITEM_TYPE_ESP;
+		sa->pattern[2].spec = &sa->esp_spec;
+		sa->pattern[2].mask = &rte_flow_item_esp_mask;
+		sa->esp_spec.hdr.spi = rte_cpu_to_be_32(sa->spi);
+		sa->pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
+	} else if (IS_IP4(sa->flags)) {
+		sa->pattern[1].mask = &rte_flow_item_ipv4_mask;
+		sa->pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV4;
+		sa->pattern[1].spec = &sa->ipv4_spec;
+		sa->ipv4_spec.hdr.dst_addr = sa->dst.ip.ip4;
+		sa->ipv4_spec.hdr.src_addr = sa->src.ip.ip4;
+		sa->pattern[2].type = RTE_FLOW_ITEM_TYPE_ESP;
+		sa->pattern[2].spec = &sa->esp_spec;
+		sa->pattern[2].mask = &rte_flow_item_esp_mask;
+		sa->esp_spec.hdr.spi = rte_cpu_to_be_32(sa->spi);
+		sa->pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
+	}
+	sa->action[1].type = RTE_FLOW_ACTION_TYPE_END;
+
+	ret = rte_flow_validate(sa->fdir_portid, &sa->attr,
+				sa->pattern, sa->action,
+				&err);
+	if (ret < 0) {
+		RTE_LOG(ERR, IPSEC,
+			"Flow Validation failed\n");
+		return ret;
+	}
+	sa->flow = rte_flow_create(sa->fdir_portid,
+				&sa->attr, sa->pattern, sa->action,
+				&err);
+	if (!sa->flow) {
+		RTE_LOG(ERR, IPSEC,
+			"Flow Creation failed\n");
+		return -1;
+	}
+
+	return 0;
+}
+
 /*
  * queue crypto-ops into PMD queue.
  */
diff --git a/examples/ipsec-secgw/ipsec.h b/examples/ipsec-secgw/ipsec.h
index 4f2fd6184..00147895a 100644
--- a/examples/ipsec-secgw/ipsec.h
+++ b/examples/ipsec-secgw/ipsec.h
@@ -46,6 +46,8 @@

 #define IP6_VERSION (6)

+#define IPV6_ADDR_LEN   16
+
 struct rte_crypto_xform;
 struct ipsec_xform;
 struct rte_mbuf;
@@ -138,6 +140,9 @@ struct ipsec_sa {
 	};
 	enum rte_security_ipsec_sa_direction direction;
 	uint16_t portid;
+	uint16_t fdir_portid;
+	uint8_t fdir_qid;
+	uint8_t fdir_flag;

 #define MAX_RTE_FLOW_PATTERN (4)
 #define MAX_RTE_FLOW_ACTIONS (3)
@@ -383,5 +388,11 @@ create_lookaside_session(struct ipsec_ctx *ipsec_ctx,
struct ipsec_sa *sa,  int  create_inline_session(struct socket_ctx *skt_ctx, struct
ipsec_sa *sa,
 		struct rte_ipsec_session *ips);
+int
+check_flow_params(uint16_t fdir_portid, uint8_t fdir_qid);
+
+int
+create_ipsec_esp_flow(struct ipsec_sa *sa);

+int check_fdir_configured(uint16_t portid);
 #endif /* __IPSEC_H__ */
diff --git a/examples/ipsec-secgw/sa.c b/examples/ipsec-secgw/sa.c index
4822d6bda..9955dfcbe 100644
--- a/examples/ipsec-secgw/sa.c
+++ b/examples/ipsec-secgw/sa.c
@@ -20,6 +20,9 @@
 #include <rte_random.h>
 #include <rte_ethdev.h>
 #include <rte_malloc.h>
+#include <rte_common.h>
+#include <rte_string_fns.h>
+#include <rte_ethdev_driver.h>

 #include "ipsec.h"
 #include "esp.h"
@@ -271,6 +274,7 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	uint32_t type_p = 0;
 	uint32_t portid_p = 0;
 	uint32_t fallback_p = 0;
+	int16_t status_p = 0;

 	if (strcmp(tokens[0], "in") == 0) {
 		ri = &nb_sa_in;
@@ -681,6 +685,25 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 			fallback_p = 1;
 			continue;
 		}
+		if (strcmp(tokens[ti], "flow-direction") == 0) {
+			rule->fdir_flag = 1;
+			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
+			if (status->status < 0)
+				return;
+			rule->fdir_portid = atoi(tokens[ti]);
+			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
+			if (status->status < 0)
+				return;
+			rule->fdir_qid = atoi(tokens[ti]);
+			/* validating portid and queueid */
+			status_p = check_flow_params(rule->fdir_portid,
+					rule->fdir_qid);
+			if (status_p < 0) {
+				printf("port id %u / queue id %u is not valid\n",
+					rule->fdir_portid, rule->fdir_qid);
+			}
+			continue;
+		}

 		/* unrecognizeable input */
 		APP_CHECK(0, status, "unrecognized input \"%s\"", @@ -823,6
+846,9 @@ print_one_sa_rule(const struct ipsec_sa *sa, int inbound)
 			break;
 		}
 	}
+	if (sa->fdir_flag == 1)
+		printf("flow-direction %d %d", sa->fdir_portid, sa->fdir_qid);
+
 	printf("\n");
 }
@@ -1153,7 +1179,15 @@ sa_add_rules(struct sa_ctx *sa_ctx, const struct
ipsec_sa entries[],
 				return -EINVAL;
 			}
 		}
-
+		if (sa->fdir_flag &&
+			ips->type ==
+			RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL
&&
+			inbound) {
+			rc = create_ipsec_esp_flow(sa);
+			if (rc != 0)
+				RTE_LOG(ERR, IPSEC_ESP,
+					"create_ipsec_esp flow failed\n");
+			}
 		print_one_sa_rule(sa, inbound);
 	}
@@ -1256,6 +1290,20 @@ fill_ipsec_session(struct rte_ipsec_session *ss, struct
rte_ipsec_sa *sa)
 	return rc;
 }

+int
+check_fdir_configured(uint16_t portid)
+{
+	struct ipsec_sa *sa = NULL;
+	uint32_t idx_sa = 0;
+
+	for (idx_sa = 0; idx_sa < nb_sa_in; idx_sa++) {
+		sa = &sa_in[idx_sa];
+		if (sa->fdir_portid == portid)
+			return sa->fdir_flag;
+	}
+	return 0;
+}
+
 /*
  * Initialise related rte_ipsec_sa object.
  */
--
2.17.1

[dpdk-dev] [PATCH v2] examples/ipsec-secgw: support flow director feature

From: Praveen Shetty <hidden>
Date: 2020-03-19 16:22:02

Support load distribution in security gateway application using
NIC load distribution feature(Flow Director).
Flow Director is used to redirect the specified inbound ipsec flow
to a specified queue.This is achieved by extending the SA rule syntax
to support specification by adding new action_type of <flow-direction>
to a specified <port_id> <queue_id>.

Signed-off-by: Praveen Shetty <redacted>
---
v2 changes:
added more details in commit message.
added a check to throw an error if the security session type is other than LOOKASIDE_NONE

 examples/ipsec-secgw/ep0.cfg       | 11 +++++
 examples/ipsec-secgw/ipsec-secgw.c | 56 ++++++++++++++++++++++++-
 examples/ipsec-secgw/ipsec.c       | 67 ++++++++++++++++++++++++++++++
 examples/ipsec-secgw/ipsec.h       | 11 +++++
 examples/ipsec-secgw/sa.c          | 60 +++++++++++++++++++++++++-
 5 files changed, 202 insertions(+), 3 deletions(-)
diff --git a/examples/ipsec-secgw/ep0.cfg b/examples/ipsec-secgw/ep0.cfg
index dfd4aca7d..6f8d5aa53 100644
--- a/examples/ipsec-secgw/ep0.cfg
+++ b/examples/ipsec-secgw/ep0.cfg
@@ -29,6 +29,7 @@ sp ipv4 in esp protect 111 pri 1 dst 192.168.186.0/24 sport 0:65535 dport 0:6553
 sp ipv4 in esp protect 115 pri 1 dst 192.168.210.0/24 sport 0:65535 dport 0:65535
 sp ipv4 in esp protect 116 pri 1 dst 192.168.211.0/24 sport 0:65535 dport 0:65535
 sp ipv4 in esp protect 115 pri 1 dst 192.168.210.0/24 sport 0:65535 dport 0:65535
+sp ipv4 in esp protect 117 pri 1 dst 192.168.212.0/24 sport 0:65535 dport 0:65535
 sp ipv4 in esp protect 125 pri 1 dst 192.168.65.0/24 sport 0:65535 dport 0:65535
 sp ipv4 in esp protect 125 pri 1 dst 192.168.65.0/24 sport 0:65535 dport 0:65535
 sp ipv4 in esp protect 126 pri 1 dst 192.168.66.0/24 sport 0:65535 dport 0:65535
@@ -61,6 +62,8 @@ sp ipv6 in esp protect 125 pri 1 dst ffff:0000:0000:0000:aaaa:aaaa:0000:0000/96
 sport 0:65535 dport 0:65535
 sp ipv6 in esp protect 126 pri 1 dst ffff:0000:0000:0000:bbbb:bbbb:0000:0000/96 \
 sport 0:65535 dport 0:65535
+sp ipv6 in esp protect 127 pri 1 dst ffff:0000:0000:0000:cccc:dddd:0000:0000/96 \
+sport 0:65535 dport 0:65535
 
 #SA rules
 sa out 5 cipher_algo aes-128-cbc cipher_key 0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0 \
@@ -118,6 +121,9 @@ dst 172.16.1.5
 
 sa in 116 cipher_algo null auth_algo null mode ipv4-tunnel src 172.16.2.6 dst 172.16.1.6
 
+sa in 117 cipher_algo null auth_algo null mode ipv4-tunnel src 172.16.2.7 \
+dst 172.16.1.7 flow-direction 0 2
+
 sa in 125 cipher_algo aes-128-cbc cipher_key c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:\
 c3:c3:c3:c3:c3 auth_algo sha1-hmac auth_key c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:\
 c3:c3:c3:c3:c3:c3:c3:c3:c3 mode ipv6-tunnel \
@@ -130,6 +136,11 @@ sa in 126 cipher_algo aes-128-cbc cipher_key 4d:4d:4d:4d:4d:4d:4d:4d:4d:4d:4d:\
 src 2222:2222:2222:2222:2222:2222:2222:6666 \
 dst 1111:1111:1111:1111:1111:1111:1111:6666
 
+sa in 127 cipher_algo null auth_algo null mode ipv6-tunnel \
+src 2222:2222:2222:2222:2222:2222:2222:7777 \
+dst 1111:1111:1111:1111:1111:1111:1111:7777 \
+flow-direction 0 3
+
 #Routing rules
 rt ipv4 dst 172.16.2.5/32 port 0
 rt ipv4 dst 172.16.2.6/32 port 1
diff --git a/examples/ipsec-secgw/ipsec-secgw.c b/examples/ipsec-secgw/ipsec-secgw.c
index 4799bc90c..132484422 100644
--- a/examples/ipsec-secgw/ipsec-secgw.c
+++ b/examples/ipsec-secgw/ipsec-secgw.c
@@ -166,7 +166,6 @@ static const struct option lgopts[] = {
 	{CMD_LINE_OPT_FRAG_TTL, 1, 0, CMD_LINE_OPT_FRAG_TTL_NUM},
 	{NULL, 0, 0, 0}
 };
-
 /* mask of enabled ports */
 static uint32_t enabled_port_mask;
 static uint64_t enabled_cryptodev_mask = UINT64_MAX;
@@ -259,6 +258,30 @@ static struct rte_eth_conf port_conf = {
 	.txmode = {
 		.mq_mode = ETH_MQ_TX_NONE,
 	},
+	.fdir_conf = {
+	.mode = RTE_FDIR_MODE_NONE,
+	.pballoc = RTE_FDIR_PBALLOC_64K,
+	.status = RTE_FDIR_REPORT_STATUS,
+	.mask = {
+		.vlan_tci_mask = 0xFFEF,
+		.ipv4_mask     = {
+			.src_ip = 0xFFFFFFFF,
+			.dst_ip = 0xFFFFFFFF,
+		},
+		.ipv6_mask     = {
+			.src_ip = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+						0xFFFFFFFF},
+			.dst_ip = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+						0xFFFFFFFF},
+		},
+		.src_port_mask = 0xFFFF,
+		.dst_port_mask = 0xFFFF,
+		.mac_addr_byte_mask = 0xFF,
+		.tunnel_type_mask = 1,
+		.tunnel_id_mask = 0xFFFFFFFF,
+	},
+	.drop_queue = 127,
+	}
 };
 
 static struct socket_ctx socket_ctx[NB_SOCKETS];
@@ -1184,7 +1207,6 @@ main_loop(__attribute__((unused)) void *dummy)
 
 			if (nb_rx > 0)
 				process_pkts(qconf, pkts, nb_rx, portid);
-
 			/* dequeue and process completed crypto-ops */
 			if (UNPROTECTED_PORT(portid))
 				drain_inbound_crypto_queues(qconf,
@@ -1196,6 +1218,27 @@ main_loop(__attribute__((unused)) void *dummy)
 	}
 }
 
+int check_flow_params(uint16_t fdir_portid, uint8_t fdir_qid)
+{
+	uint16_t i;
+	uint16_t portid;
+	uint8_t queueid;
+
+	for (i = 0; i < nb_lcore_params; ++i) {
+		portid = lcore_params_array[i].port_id;
+		if (portid == fdir_portid) {
+			queueid = lcore_params_array[i].queue_id;
+			if (queueid == fdir_qid)
+				break;
+		}
+
+		if (i == nb_lcore_params - 1)
+			return -1;
+	}
+
+	return 1;
+}
+
 static int32_t
 check_params(void)
 {
@@ -2503,6 +2546,15 @@ main(int32_t argc, char **argv)
 			continue;
 
 		sa_check_offloads(portid, &req_rx_offloads, &req_tx_offloads);
+		/* check if FDIR is configured on the port */
+		if (check_fdir_configured(portid)) {
+			/* Enable FDIR */
+			port_conf.fdir_conf.mode = RTE_FDIR_MODE_PERFECT;
+			/* Disable RSS */
+			port_conf.rxmode.mq_mode = ETH_MQ_RX_NONE;
+			port_conf.rx_adv_conf.rss_conf.rss_hf = 0;
+			port_conf.rx_adv_conf.rss_conf.rss_key = NULL;
+		}
 		port_init(portid, req_rx_offloads, req_tx_offloads);
 	}
 
diff --git a/examples/ipsec-secgw/ipsec.c b/examples/ipsec-secgw/ipsec.c
index 6e8120702..363809cfd 100644
--- a/examples/ipsec-secgw/ipsec.c
+++ b/examples/ipsec-secgw/ipsec.c
@@ -415,6 +415,73 @@ create_inline_session(struct socket_ctx *skt_ctx, struct ipsec_sa *sa,
 	return 0;
 }
 
+int
+create_ipsec_esp_flow(struct ipsec_sa *sa)
+{
+	int ret = 0;
+	struct rte_flow_error err;
+	if (sa->direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS)
+		return 0; /* No Flow director rules for Egress traffic */
+	if (sa->flags == TRANSPORT) {
+		RTE_LOG(ERR, IPSEC,
+			"No Flow director rule for transport mode:");
+			return -1;
+	}
+	sa->action[0].type = RTE_FLOW_ACTION_TYPE_QUEUE;
+	sa->pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
+	sa->action[0].conf =
+			&(struct rte_flow_action_queue){
+				.index = sa->fdir_qid,
+	};
+	sa->attr.egress = 0;
+	sa->attr.ingress = 1;
+	if (IS_IP6(sa->flags)) {
+		sa->pattern[1].mask = &rte_flow_item_ipv6_mask;
+		sa->pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV6;
+		sa->pattern[1].spec = &sa->ipv6_spec;
+		memcpy(sa->ipv6_spec.hdr.dst_addr,
+				sa->dst.ip.ip6.ip6_b, IPV6_ADDR_LEN);
+		memcpy(sa->ipv6_spec.hdr.src_addr,
+				sa->src.ip.ip6.ip6_b, IPV6_ADDR_LEN);
+		sa->pattern[2].type = RTE_FLOW_ITEM_TYPE_ESP;
+		sa->pattern[2].spec = &sa->esp_spec;
+		sa->pattern[2].mask = &rte_flow_item_esp_mask;
+		sa->esp_spec.hdr.spi = rte_cpu_to_be_32(sa->spi);
+		sa->pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
+	} else if (IS_IP4(sa->flags)) {
+		sa->pattern[1].mask = &rte_flow_item_ipv4_mask;
+		sa->pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV4;
+		sa->pattern[1].spec = &sa->ipv4_spec;
+		sa->ipv4_spec.hdr.dst_addr = sa->dst.ip.ip4;
+		sa->ipv4_spec.hdr.src_addr = sa->src.ip.ip4;
+		sa->pattern[2].type = RTE_FLOW_ITEM_TYPE_ESP;
+		sa->pattern[2].spec = &sa->esp_spec;
+		sa->pattern[2].mask = &rte_flow_item_esp_mask;
+		sa->esp_spec.hdr.spi = rte_cpu_to_be_32(sa->spi);
+		sa->pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
+	}
+	sa->action[1].type = RTE_FLOW_ACTION_TYPE_END;
+
+	ret = rte_flow_validate(sa->fdir_portid, &sa->attr,
+				sa->pattern, sa->action,
+				&err);
+	if (ret < 0) {
+		RTE_LOG(ERR, IPSEC,
+			"Flow Validation failed\n");
+		return ret;
+	}
+	sa->flow = rte_flow_create(sa->fdir_portid,
+				&sa->attr, sa->pattern, sa->action,
+				&err);
+	if (!sa->flow) {
+		RTE_LOG(ERR, IPSEC,
+			"Flow Creation failed\n");
+		return -1;
+	}
+
+	return 0;
+}
+
 /*
  * queue crypto-ops into PMD queue.
  */
diff --git a/examples/ipsec-secgw/ipsec.h b/examples/ipsec-secgw/ipsec.h
index 4f2fd6184..00147895a 100644
--- a/examples/ipsec-secgw/ipsec.h
+++ b/examples/ipsec-secgw/ipsec.h
@@ -46,6 +46,8 @@
 
 #define IP6_VERSION (6)
 
+#define IPV6_ADDR_LEN   16
+
 struct rte_crypto_xform;
 struct ipsec_xform;
 struct rte_mbuf;
@@ -138,6 +140,9 @@ struct ipsec_sa {
 	};
 	enum rte_security_ipsec_sa_direction direction;
 	uint16_t portid;
+	uint16_t fdir_portid;
+	uint8_t fdir_qid;
+	uint8_t fdir_flag;
 
 #define MAX_RTE_FLOW_PATTERN (4)
 #define MAX_RTE_FLOW_ACTIONS (3)
@@ -383,5 +388,11 @@ create_lookaside_session(struct ipsec_ctx *ipsec_ctx, struct ipsec_sa *sa,
 int
 create_inline_session(struct socket_ctx *skt_ctx, struct ipsec_sa *sa,
 		struct rte_ipsec_session *ips);
+int
+check_flow_params(uint16_t fdir_portid, uint8_t fdir_qid);
+
+int
+create_ipsec_esp_flow(struct ipsec_sa *sa);
 
+int check_fdir_configured(uint16_t portid);
 #endif /* __IPSEC_H__ */
diff --git a/examples/ipsec-secgw/sa.c b/examples/ipsec-secgw/sa.c
index 4822d6bda..204a685fb 100644
--- a/examples/ipsec-secgw/sa.c
+++ b/examples/ipsec-secgw/sa.c
@@ -20,6 +20,9 @@
 #include <rte_random.h>
 #include <rte_ethdev.h>
 #include <rte_malloc.h>
+#include <rte_common.h>
+#include <rte_string_fns.h>
+#include <rte_ethdev_driver.h>
 
 #include "ipsec.h"
 #include "esp.h"
@@ -271,6 +274,7 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	uint32_t type_p = 0;
 	uint32_t portid_p = 0;
 	uint32_t fallback_p = 0;
+	int16_t status_p = 0;
 
 	if (strcmp(tokens[0], "in") == 0) {
 		ri = &nb_sa_in;
@@ -681,6 +685,38 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 			fallback_p = 1;
 			continue;
 		}
+		if (strcmp(tokens[ti], "flow-direction") == 0) {
+			if (ips->type ==
+				RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL ||
+				ips->type ==
+				RTE_SECURITY_ACTION_TYPE_CPU_CRYPTO ||
+				ips->type ==
+				RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL ||
+				ips->type ==
+				RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO) {
+				APP_CHECK(0, status, "Flow Director not "
+					"supported for security session "
+					"type:%d", ips->type);
+					return;
+			}
+			rule->fdir_flag = 1;
+			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
+			if (status->status < 0)
+				return;
+			rule->fdir_portid = atoi(tokens[ti]);
+			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
+			if (status->status < 0)
+				return;
+			rule->fdir_qid = atoi(tokens[ti]);
+			/* validating portid and queueid */
+			status_p = check_flow_params(rule->fdir_portid,
+					rule->fdir_qid);
+			if (status_p < 0) {
+				printf("port id %u / queue id %u is not valid\n",
+					rule->fdir_portid, rule->fdir_qid);
+			}
+			continue;
+		}
 
 		/* unrecognizeable input */
 		APP_CHECK(0, status, "unrecognized input \"%s\"",
@@ -823,6 +859,9 @@ print_one_sa_rule(const struct ipsec_sa *sa, int inbound)
 			break;
 		}
 	}
+	if (sa->fdir_flag == 1)
+		printf("flow-direction %d %d", sa->fdir_portid, sa->fdir_qid);
+
 	printf("\n");
 }
 
@@ -1153,7 +1192,12 @@ sa_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
 				return -EINVAL;
 			}
 		}
-
+		if (sa->fdir_flag && inbound) {
+			rc = create_ipsec_esp_flow(sa);
+			if (rc != 0)
+				RTE_LOG(ERR, IPSEC_ESP,
+					"create_ipsec_esp flow failed\n");
+			}
 		print_one_sa_rule(sa, inbound);
 	}
 
@@ -1256,6 +1300,20 @@ fill_ipsec_session(struct rte_ipsec_session *ss, struct rte_ipsec_sa *sa)
 	return rc;
 }
 
+int
+check_fdir_configured(uint16_t portid)
+{
+	struct ipsec_sa *sa = NULL;
+	uint32_t idx_sa = 0;
+
+	for (idx_sa = 0; idx_sa < nb_sa_in; idx_sa++) {
+		sa = &sa_in[idx_sa];
+		if (sa->fdir_portid == portid)
+			return sa->fdir_flag;
+	}
+	return 0;
+}
+
 /*
  * Initialise related rte_ipsec_sa object.
  */
-- 
2.17.1

Re: [dpdk-dev] [PATCH v2] examples/ipsec-secgw: support flow director feature

From: Anoob Joseph <hidden>
Date: 2020-03-20 08:15:14

Hi Praveen,

You need to rebase to the latest dpdk-next-crypto code base. This patch is not applying cleanly.

There were few patches from Intel removing the existing FDIR and adding some new implementation. Hope this patch takes that also into account. Also, why do we need to call the feature flow director. I would assume rte_flow per SA is what is being attempted here.

Few comments. See inline.

Thanks,
Anoob
quoted hunk
-----Original Message-----
From: dev <redacted> On Behalf Of Praveen Shetty
Sent: Thursday, March 19, 2020 9:52 PM
To: dev@dpdk.org; declan.doherty@intel.com; bernard.iremonger@intel.co;
konstantin.ananyev@intel.com
Subject: [dpdk-dev] [PATCH v2] examples/ipsec-secgw: support flow director
feature

Support load distribution in security gateway application using NIC load
distribution feature(Flow Director).
Flow Director is used to redirect the specified inbound ipsec flow to a specified
queue.This is achieved by extending the SA rule syntax to support specification
by adding new action_type of <flow-direction> to a specified <port_id>
<queue_id>.

Signed-off-by: Praveen Shetty <redacted>
---
v2 changes:
added more details in commit message.
added a check to throw an error if the security session type is other than
LOOKASIDE_NONE

 examples/ipsec-secgw/ep0.cfg       | 11 +++++
 examples/ipsec-secgw/ipsec-secgw.c | 56 ++++++++++++++++++++++++-
 examples/ipsec-secgw/ipsec.c       | 67 ++++++++++++++++++++++++++++++
 examples/ipsec-secgw/ipsec.h       | 11 +++++
 examples/ipsec-secgw/sa.c          | 60 +++++++++++++++++++++++++-
 5 files changed, 202 insertions(+), 3 deletions(-)
diff --git a/examples/ipsec-secgw/ep0.cfg b/examples/ipsec-secgw/ep0.cfg
index dfd4aca7d..6f8d5aa53 100644
--- a/examples/ipsec-secgw/ep0.cfg
+++ b/examples/ipsec-secgw/ep0.cfg
@@ -29,6 +29,7 @@ sp ipv4 in esp protect 111 pri 1 dst 192.168.186.0/24 sport
0:65535 dport 0:6553  sp ipv4 in esp protect 115 pri 1 dst 192.168.210.0/24 sport
0:65535 dport 0:65535  sp ipv4 in esp protect 116 pri 1 dst 192.168.211.0/24
sport 0:65535 dport 0:65535  sp ipv4 in esp protect 115 pri 1 dst
192.168.210.0/24 sport 0:65535 dport 0:65535
+sp ipv4 in esp protect 117 pri 1 dst 192.168.212.0/24 sport 0:65535
+dport 0:65535
 sp ipv4 in esp protect 125 pri 1 dst 192.168.65.0/24 sport 0:65535 dport 0:65535
sp ipv4 in esp protect 125 pri 1 dst 192.168.65.0/24 sport 0:65535 dport 0:65535
sp ipv4 in esp protect 126 pri 1 dst 192.168.66.0/24 sport 0:65535 dport 0:65535
@@ -61,6 +62,8 @@ sp ipv6 in esp protect 125 pri 1 dst
ffff:0000:0000:0000:aaaa:aaaa:0000:0000/96
 sport 0:65535 dport 0:65535
 sp ipv6 in esp protect 126 pri 1 dst
ffff:0000:0000:0000:bbbb:bbbb:0000:0000/96 \  sport 0:65535 dport 0:65535
+sp ipv6 in esp protect 127 pri 1 dst
+ffff:0000:0000:0000:cccc:dddd:0000:0000/96 \ sport 0:65535 dport
+0:65535

 #SA rules
 sa out 5 cipher_algo aes-128-cbc cipher_key 0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0 \
@@ -118,6 +121,9 @@ dst 172.16.1.5

 sa in 116 cipher_algo null auth_algo null mode ipv4-tunnel src 172.16.2.6 dst
172.16.1.6

+sa in 117 cipher_algo null auth_algo null mode ipv4-tunnel src
+172.16.2.7 \ dst 172.16.1.7 flow-direction 0 2
+
 sa in 125 cipher_algo aes-128-cbc cipher_key c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:\
 c3:c3:c3:c3:c3 auth_algo sha1-hmac auth_key
c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:\
 c3:c3:c3:c3:c3:c3:c3:c3:c3 mode ipv6-tunnel \ @@ -130,6 +136,11 @@ sa in
126 cipher_algo aes-128-cbc cipher_key 4d:4d:4d:4d:4d:4d:4d:4d:4d:4d:4d:\
 src 2222:2222:2222:2222:2222:2222:2222:6666 \  dst
1111:1111:1111:1111:1111:1111:1111:6666

+sa in 127 cipher_algo null auth_algo null mode ipv6-tunnel \ src
+2222:2222:2222:2222:2222:2222:2222:7777 \ dst
+1111:1111:1111:1111:1111:1111:1111:7777 \ flow-direction 0 3
+
 #Routing rules
 rt ipv4 dst 172.16.2.5/32 port 0
 rt ipv4 dst 172.16.2.6/32 port 1
diff --git a/examples/ipsec-secgw/ipsec-secgw.c b/examples/ipsec-
secgw/ipsec-secgw.c
index 4799bc90c..132484422 100644
--- a/examples/ipsec-secgw/ipsec-secgw.c
+++ b/examples/ipsec-secgw/ipsec-secgw.c
@@ -166,7 +166,6 @@ static const struct option lgopts[] = {
 	{CMD_LINE_OPT_FRAG_TTL, 1, 0, CMD_LINE_OPT_FRAG_TTL_NUM},
 	{NULL, 0, 0, 0}
 };
-
[Anoob] I would assume the above change is not intentional.
 
quoted hunk
 /* mask of enabled ports */
 static uint32_t enabled_port_mask;
 static uint64_t enabled_cryptodev_mask = UINT64_MAX; @@ -259,6 +258,30
@@ static struct rte_eth_conf port_conf = {
 	.txmode = {
 		.mq_mode = ETH_MQ_TX_NONE,
 	},
+	.fdir_conf = {
+	.mode = RTE_FDIR_MODE_NONE,
+	.pballoc = RTE_FDIR_PBALLOC_64K,
+	.status = RTE_FDIR_REPORT_STATUS,
+	.mask = {
+		.vlan_tci_mask = 0xFFEF,
+		.ipv4_mask     = {
+			.src_ip = 0xFFFFFFFF,
+			.dst_ip = 0xFFFFFFFF,
+		},
+		.ipv6_mask     = {
+			.src_ip = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+						0xFFFFFFFF},
+			.dst_ip = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+						0xFFFFFFFF},
+		},
+		.src_port_mask = 0xFFFF,
+		.dst_port_mask = 0xFFFF,
+		.mac_addr_byte_mask = 0xFF,
+		.tunnel_type_mask = 1,
+		.tunnel_id_mask = 0xFFFFFFFF,
+	},
+	.drop_queue = 127,
+	}
 };

 static struct socket_ctx socket_ctx[NB_SOCKETS]; @@ -1184,7 +1207,6 @@
main_loop(__attribute__((unused)) void *dummy)

 			if (nb_rx > 0)
 				process_pkts(qconf, pkts, nb_rx, portid);
-
[Anoob] I would assume the above change is not intentional.
 
quoted hunk
 			/* dequeue and process completed crypto-ops */
 			if (UNPROTECTED_PORT(portid))
 				drain_inbound_crypto_queues(qconf,
@@ -1196,6 +1218,27 @@ main_loop(__attribute__((unused)) void *dummy)
 	}
 }

+int check_flow_params(uint16_t fdir_portid, uint8_t fdir_qid) {
+	uint16_t i;
+	uint16_t portid;
+	uint8_t queueid;
+
+	for (i = 0; i < nb_lcore_params; ++i) {
+		portid = lcore_params_array[i].port_id;
+		if (portid == fdir_portid) {
+			queueid = lcore_params_array[i].queue_id;
+			if (queueid == fdir_qid)
+				break;
+		}
+
+		if (i == nb_lcore_params - 1)
+			return -1;
+	}
+
+	return 1;
+}
+
 static int32_t
 check_params(void)
 {
@@ -2503,6 +2546,15 @@ main(int32_t argc, char **argv)
 			continue;

 		sa_check_offloads(portid, &req_rx_offloads,
&req_tx_offloads);
+		/* check if FDIR is configured on the port */
+		if (check_fdir_configured(portid)) {
+			/* Enable FDIR */
+			port_conf.fdir_conf.mode =
RTE_FDIR_MODE_PERFECT;
+			/* Disable RSS */
+			port_conf.rxmode.mq_mode = ETH_MQ_RX_NONE;
+			port_conf.rx_adv_conf.rss_conf.rss_hf = 0;
+			port_conf.rx_adv_conf.rss_conf.rss_key = NULL;
+		}
[Anoob] This would mean, once FDIR is enabled for one SA, then the port init is changed. RSS is disabled and FDIR gets enabled. Can you confirm if I understood the code correctly?
 
quoted hunk
 		port_init(portid, req_rx_offloads, req_tx_offloads);
 	}
diff --git a/examples/ipsec-secgw/ipsec.c b/examples/ipsec-secgw/ipsec.c index
6e8120702..363809cfd 100644
--- a/examples/ipsec-secgw/ipsec.c
+++ b/examples/ipsec-secgw/ipsec.c
@@ -415,6 +415,73 @@ create_inline_session(struct socket_ctx *skt_ctx,
struct ipsec_sa *sa,
 	return 0;
 }

+int
+create_ipsec_esp_flow(struct ipsec_sa *sa) {
[Anoob] Why just ESP? Can't the same rte_flow rules be used for doing BYPASS/TRANSPORT?
 
quoted hunk
+	int ret = 0;
+	struct rte_flow_error err;
+	if (sa->direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS)
+		return 0; /* No Flow director rules for Egress traffic */
+	if (sa->flags == TRANSPORT) {
+		RTE_LOG(ERR, IPSEC,
+			"No Flow director rule for transport mode:");
+			return -1;
+	}
+	sa->action[0].type = RTE_FLOW_ACTION_TYPE_QUEUE;
+	sa->pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
+	sa->action[0].conf =
+			&(struct rte_flow_action_queue){
+				.index = sa->fdir_qid,
+	};
+	sa->attr.egress = 0;
+	sa->attr.ingress = 1;
+	if (IS_IP6(sa->flags)) {
+		sa->pattern[1].mask = &rte_flow_item_ipv6_mask;
+		sa->pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV6;
+		sa->pattern[1].spec = &sa->ipv6_spec;
+		memcpy(sa->ipv6_spec.hdr.dst_addr,
+				sa->dst.ip.ip6.ip6_b, IPV6_ADDR_LEN);
+		memcpy(sa->ipv6_spec.hdr.src_addr,
+				sa->src.ip.ip6.ip6_b, IPV6_ADDR_LEN);
+		sa->pattern[2].type = RTE_FLOW_ITEM_TYPE_ESP;
+		sa->pattern[2].spec = &sa->esp_spec;
+		sa->pattern[2].mask = &rte_flow_item_esp_mask;
+		sa->esp_spec.hdr.spi = rte_cpu_to_be_32(sa->spi);
+		sa->pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
+	} else if (IS_IP4(sa->flags)) {
+		sa->pattern[1].mask = &rte_flow_item_ipv4_mask;
+		sa->pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV4;
+		sa->pattern[1].spec = &sa->ipv4_spec;
+		sa->ipv4_spec.hdr.dst_addr = sa->dst.ip.ip4;
+		sa->ipv4_spec.hdr.src_addr = sa->src.ip.ip4;
+		sa->pattern[2].type = RTE_FLOW_ITEM_TYPE_ESP;
+		sa->pattern[2].spec = &sa->esp_spec;
+		sa->pattern[2].mask = &rte_flow_item_esp_mask;
+		sa->esp_spec.hdr.spi = rte_cpu_to_be_32(sa->spi);
+		sa->pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
+	}
+	sa->action[1].type = RTE_FLOW_ACTION_TYPE_END;
+
+	ret = rte_flow_validate(sa->fdir_portid, &sa->attr,
+				sa->pattern, sa->action,
+				&err);
+	if (ret < 0) {
+		RTE_LOG(ERR, IPSEC,
+			"Flow Validation failed\n");
+		return ret;
+	}
+	sa->flow = rte_flow_create(sa->fdir_portid,
+				&sa->attr, sa->pattern, sa->action,
+				&err);
+	if (!sa->flow) {
+		RTE_LOG(ERR, IPSEC,
+			"Flow Creation failed\n");
+		return -1;
+	}
+
+	return 0;
+}
+
 /*
  * queue crypto-ops into PMD queue.
  */
diff --git a/examples/ipsec-secgw/ipsec.h b/examples/ipsec-secgw/ipsec.h
index 4f2fd6184..00147895a 100644
--- a/examples/ipsec-secgw/ipsec.h
+++ b/examples/ipsec-secgw/ipsec.h
@@ -46,6 +46,8 @@

 #define IP6_VERSION (6)

+#define IPV6_ADDR_LEN   16
[Anoob] Can't we do a sizeof of some structure to get the same? Having an application specific macro may not be the right approach.
 
quoted hunk
+
 struct rte_crypto_xform;
 struct ipsec_xform;
 struct rte_mbuf;
@@ -138,6 +140,9 @@ struct ipsec_sa {
 	};
 	enum rte_security_ipsec_sa_direction direction;
 	uint16_t portid;
+	uint16_t fdir_portid;
[Anoob] The existing member 'portid' above 'fdir_portid' is used for a similar rte_flow creation for inline IPsec. Can't we use the same here also?
 
quoted hunk
+	uint8_t fdir_qid;
+	uint8_t fdir_flag;

 #define MAX_RTE_FLOW_PATTERN (4)
 #define MAX_RTE_FLOW_ACTIONS (3)
@@ -383,5 +388,11 @@ create_lookaside_session(struct ipsec_ctx *ipsec_ctx,
struct ipsec_sa *sa,  int  create_inline_session(struct socket_ctx *skt_ctx, struct
ipsec_sa *sa,
 		struct rte_ipsec_session *ips);
+int
+check_flow_params(uint16_t fdir_portid, uint8_t fdir_qid);
+
+int
+create_ipsec_esp_flow(struct ipsec_sa *sa);

+int check_fdir_configured(uint16_t portid);
[Anoob] Better to stick to the convention followed.
 
quoted hunk
 #endif /* __IPSEC_H__ */
diff --git a/examples/ipsec-secgw/sa.c b/examples/ipsec-secgw/sa.c index
4822d6bda..204a685fb 100644
--- a/examples/ipsec-secgw/sa.c
+++ b/examples/ipsec-secgw/sa.c
@@ -20,6 +20,9 @@
 #include <rte_random.h>
 #include <rte_ethdev.h>
 #include <rte_malloc.h>
+#include <rte_common.h>
+#include <rte_string_fns.h>
+#include <rte_ethdev_driver.h>

 #include "ipsec.h"
 #include "esp.h"
@@ -271,6 +274,7 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	uint32_t type_p = 0;
 	uint32_t portid_p = 0;
 	uint32_t fallback_p = 0;
+	int16_t status_p = 0;

 	if (strcmp(tokens[0], "in") == 0) {
 		ri = &nb_sa_in;
@@ -681,6 +685,38 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 			fallback_p = 1;
 			continue;
 		}
+		if (strcmp(tokens[ti], "flow-direction") == 0) {
+			if (ips->type ==
+
	RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL ||
+				ips->type ==
+				RTE_SECURITY_ACTION_TYPE_CPU_CRYPTO
||
+				ips->type ==
+
	RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL ||
+				ips->type ==
+
	RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO) {
+				APP_CHECK(0, status, "Flow Director not "
+					"supported for security session "
+					"type:%d", ips->type);
+					return;
+			}
+			rule->fdir_flag = 1;
+			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
+			if (status->status < 0)
+				return;
+			rule->fdir_portid = atoi(tokens[ti]);
+			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
+			if (status->status < 0)
+				return;
+			rule->fdir_qid = atoi(tokens[ti]);
+			/* validating portid and queueid */
+			status_p = check_flow_params(rule->fdir_portid,
+					rule->fdir_qid);
+			if (status_p < 0) {
+				printf("port id %u / queue id %u is not valid\n",
+					rule->fdir_portid, rule->fdir_qid);
+			}
+			continue;
+		}

 		/* unrecognizeable input */
 		APP_CHECK(0, status, "unrecognized input \"%s\"", @@ -823,6
+859,9 @@ print_one_sa_rule(const struct ipsec_sa *sa, int inbound)
 			break;
 		}
 	}
+	if (sa->fdir_flag == 1)
+		printf("flow-direction %d %d", sa->fdir_portid, sa->fdir_qid);
+
 	printf("\n");
 }
@@ -1153,7 +1192,12 @@ sa_add_rules(struct sa_ctx *sa_ctx, const struct
ipsec_sa entries[],
 				return -EINVAL;
 			}
 		}
-
+		if (sa->fdir_flag && inbound) {
+			rc = create_ipsec_esp_flow(sa);
+			if (rc != 0)
+				RTE_LOG(ERR, IPSEC_ESP,
+					"create_ipsec_esp flow failed\n");
+			}
 		print_one_sa_rule(sa, inbound);
 	}
@@ -1256,6 +1300,20 @@ fill_ipsec_session(struct rte_ipsec_session *ss, struct
rte_ipsec_sa *sa)
 	return rc;
 }

+int
+check_fdir_configured(uint16_t portid)
+{
+	struct ipsec_sa *sa = NULL;
+	uint32_t idx_sa = 0;
+
+	for (idx_sa = 0; idx_sa < nb_sa_in; idx_sa++) {
+		sa = &sa_in[idx_sa];
+		if (sa->fdir_portid == portid)
+			return sa->fdir_flag;
+	}
+	return 0;
+}
+
 /*
  * Initialise related rte_ipsec_sa object.
  */
--
2.17.1

Re: [dpdk-dev] [PATCH v2] examples/ipsec-secgw: support flow director feature

From: Shetty, Praveen <hidden>
Date: 2020-03-23 11:24:41

Hi Anoob,

Thank you.

Please see my response inline.

Regards,
Praveen

-----Original Message-----
From: Anoob Joseph <redacted> 
Sent: Friday, March 20, 2020 1:45 PM
To: Shetty, Praveen <redacted>; dev@dpdk.org; Doherty, Declan <redacted>; bernard.iremonger@intel.co; Ananyev, Konstantin <redacted>
Cc: Narayana Prasad Raju Athreya <redacted>
Subject: RE: [dpdk-dev] [PATCH v2] examples/ipsec-secgw: support flow director feature

Hi Praveen,

You need to rebase to the latest dpdk-next-crypto code base. This patch is not applying cleanly.

[Praveen] Will fix this in V3.

There were few patches from Intel removing the existing FDIR and adding some new implementation. Hope this patch takes that also into account. Also, why do we need to call the feature flow director. I would assume rte_flow per SA is what is being attempted here.

[Praveen] In regards the action name, it wasn't trying to be flow director specific, but the name was trying to capture the action which was flow direction to a specific queue. We're open to change this to whatever is deemed appropriate ...

perhaps just
"flow-queue-action <port_id> <queue-id>" or
"distrubte <port_id> <queue-id>?


Few comments. See inline.

Thanks,
Anoob
quoted hunk
-----Original Message-----
From: dev <redacted> On Behalf Of Praveen Shetty
Sent: Thursday, March 19, 2020 9:52 PM
To: dev@dpdk.org; declan.doherty@intel.com; 
bernard.iremonger@intel.co; konstantin.ananyev@intel.com
Subject: [dpdk-dev] [PATCH v2] examples/ipsec-secgw: support flow 
director feature

Support load distribution in security gateway application using NIC 
load distribution feature(Flow Director).
Flow Director is used to redirect the specified inbound ipsec flow to 
a specified queue.This is achieved by extending the SA rule syntax to 
support specification by adding new action_type of <flow-direction> to 
a specified <port_id> <queue_id>.

Signed-off-by: Praveen Shetty <redacted>
---
v2 changes:
added more details in commit message.
added a check to throw an error if the security session type is other 
than LOOKASIDE_NONE

 examples/ipsec-secgw/ep0.cfg       | 11 +++++
 examples/ipsec-secgw/ipsec-secgw.c | 56 ++++++++++++++++++++++++-
 examples/ipsec-secgw/ipsec.c       | 67 ++++++++++++++++++++++++++++++
 examples/ipsec-secgw/ipsec.h       | 11 +++++
 examples/ipsec-secgw/sa.c          | 60 +++++++++++++++++++++++++-
 5 files changed, 202 insertions(+), 3 deletions(-)
diff --git a/examples/ipsec-secgw/ep0.cfg 
b/examples/ipsec-secgw/ep0.cfg index dfd4aca7d..6f8d5aa53 100644
--- a/examples/ipsec-secgw/ep0.cfg
+++ b/examples/ipsec-secgw/ep0.cfg
@@ -29,6 +29,7 @@ sp ipv4 in esp protect 111 pri 1 dst 
192.168.186.0/24 sport
0:65535 dport 0:6553  sp ipv4 in esp protect 115 pri 1 dst 
192.168.210.0/24 sport
0:65535 dport 0:65535  sp ipv4 in esp protect 116 pri 1 dst 
192.168.211.0/24 sport 0:65535 dport 0:65535  sp ipv4 in esp protect 
115 pri 1 dst
192.168.210.0/24 sport 0:65535 dport 0:65535
+sp ipv4 in esp protect 117 pri 1 dst 192.168.212.0/24 sport 0:65535 
+dport 0:65535
 sp ipv4 in esp protect 125 pri 1 dst 192.168.65.0/24 sport 0:65535 
dport 0:65535 sp ipv4 in esp protect 125 pri 1 dst 192.168.65.0/24 
sport 0:65535 dport 0:65535 sp ipv4 in esp protect 126 pri 1 dst 
192.168.66.0/24 sport 0:65535 dport 0:65535 @@ -61,6 +62,8 @@ sp ipv6 
in esp protect 125 pri 1 dst
ffff:0000:0000:0000:aaaa:aaaa:0000:0000/96
 sport 0:65535 dport 0:65535
 sp ipv6 in esp protect 126 pri 1 dst
ffff:0000:0000:0000:bbbb:bbbb:0000:0000/96 \  sport 0:65535 dport 
0:65535
+sp ipv6 in esp protect 127 pri 1 dst
+ffff:0000:0000:0000:cccc:dddd:0000:0000/96 \ sport 0:65535 dport
+0:65535

 #SA rules
 sa out 5 cipher_algo aes-128-cbc cipher_key 
0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0 \ @@ -118,6 +121,9 @@ dst 172.16.1.5

 sa in 116 cipher_algo null auth_algo null mode ipv4-tunnel src 
172.16.2.6 dst
172.16.1.6

+sa in 117 cipher_algo null auth_algo null mode ipv4-tunnel src
+172.16.2.7 \ dst 172.16.1.7 flow-direction 0 2
+
 sa in 125 cipher_algo aes-128-cbc cipher_key 
c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:\
 c3:c3:c3:c3:c3 auth_algo sha1-hmac auth_key 
c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:\
 c3:c3:c3:c3:c3:c3:c3:c3:c3 mode ipv6-tunnel \ @@ -130,6 +136,11 @@ sa 
in
126 cipher_algo aes-128-cbc cipher_key 
4d:4d:4d:4d:4d:4d:4d:4d:4d:4d:4d:\
 src 2222:2222:2222:2222:2222:2222:2222:6666 \  dst
1111:1111:1111:1111:1111:1111:1111:6666

+sa in 127 cipher_algo null auth_algo null mode ipv6-tunnel \ src
+2222:2222:2222:2222:2222:2222:2222:7777 \ dst
+1111:1111:1111:1111:1111:1111:1111:7777 \ flow-direction 0 3
+
 #Routing rules
 rt ipv4 dst 172.16.2.5/32 port 0
 rt ipv4 dst 172.16.2.6/32 port 1
diff --git a/examples/ipsec-secgw/ipsec-secgw.c b/examples/ipsec- 
secgw/ipsec-secgw.c index 4799bc90c..132484422 100644
--- a/examples/ipsec-secgw/ipsec-secgw.c
+++ b/examples/ipsec-secgw/ipsec-secgw.c
@@ -166,7 +166,6 @@ static const struct option lgopts[] = {
 	{CMD_LINE_OPT_FRAG_TTL, 1, 0, CMD_LINE_OPT_FRAG_TTL_NUM},
 	{NULL, 0, 0, 0}
 };
-
[Anoob] I would assume the above change is not intentional.

[Praveen] it was not intentional. Will fix this in V3.
 
 /* mask of enabled ports */
 static uint32_t enabled_port_mask;
 static uint64_t enabled_cryptodev_mask = UINT64_MAX; @@ -259,6 
+258,30 @@ static struct rte_eth_conf port_conf = {
 	.txmode = {
 		.mq_mode = ETH_MQ_TX_NONE,
 	},
+	.fdir_conf = {
+	.mode = RTE_FDIR_MODE_NONE,
+	.pballoc = RTE_FDIR_PBALLOC_64K,
+	.status = RTE_FDIR_REPORT_STATUS,
+	.mask = {
+		.vlan_tci_mask = 0xFFEF,
+		.ipv4_mask     = {
+			.src_ip = 0xFFFFFFFF,
+			.dst_ip = 0xFFFFFFFF,
+		},
+		.ipv6_mask     = {
+			.src_ip = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+						0xFFFFFFFF},
+			.dst_ip = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+						0xFFFFFFFF},
+		},
+		.src_port_mask = 0xFFFF,
+		.dst_port_mask = 0xFFFF,
+		.mac_addr_byte_mask = 0xFF,
+		.tunnel_type_mask = 1,
+		.tunnel_id_mask = 0xFFFFFFFF,
+	},
+	.drop_queue = 127,
+	}
 };

 static struct socket_ctx socket_ctx[NB_SOCKETS]; @@ -1184,7 +1207,6 
@@
main_loop(__attribute__((unused)) void *dummy)

 			if (nb_rx > 0)
 				process_pkts(qconf, pkts, nb_rx, portid);
-
[Anoob] I would assume the above change is not intentional.

[Praveen ] it was not intentional. Will fix this in V3.
 
quoted hunk
 			/* dequeue and process completed crypto-ops */
 			if (UNPROTECTED_PORT(portid))
 				drain_inbound_crypto_queues(qconf,
@@ -1196,6 +1218,27 @@ main_loop(__attribute__((unused)) void *dummy)
 	}
 }

+int check_flow_params(uint16_t fdir_portid, uint8_t fdir_qid) {
+	uint16_t i;
+	uint16_t portid;
+	uint8_t queueid;
+
+	for (i = 0; i < nb_lcore_params; ++i) {
+		portid = lcore_params_array[i].port_id;
+		if (portid == fdir_portid) {
+			queueid = lcore_params_array[i].queue_id;
+			if (queueid == fdir_qid)
+				break;
+		}
+
+		if (i == nb_lcore_params - 1)
+			return -1;
+	}
+
+	return 1;
+}
+
 static int32_t
 check_params(void)
 {
@@ -2503,6 +2546,15 @@ main(int32_t argc, char **argv)
 			continue;

 		sa_check_offloads(portid, &req_rx_offloads, &req_tx_offloads);
+		/* check if FDIR is configured on the port */
+		if (check_fdir_configured(portid)) {
+			/* Enable FDIR */
+			port_conf.fdir_conf.mode =
RTE_FDIR_MODE_PERFECT;
+			/* Disable RSS */
+			port_conf.rxmode.mq_mode = ETH_MQ_RX_NONE;
+			port_conf.rx_adv_conf.rss_conf.rss_hf = 0;
+			port_conf.rx_adv_conf.rss_conf.rss_key = NULL;
+		}
[Anoob] This would mean, once FDIR is enabled for one SA, then the port init is changed. RSS is disabled and FDIR gets enabled. Can you confirm if I understood the code correctly?

[Praveen]  Currently this is correct but in the future the idea would be only to disable the queue which the SA is associated with.
 
quoted hunk
 		port_init(portid, req_rx_offloads, req_tx_offloads);
 	}
diff --git a/examples/ipsec-secgw/ipsec.c 
b/examples/ipsec-secgw/ipsec.c index 6e8120702..363809cfd 100644
--- a/examples/ipsec-secgw/ipsec.c
+++ b/examples/ipsec-secgw/ipsec.c
@@ -415,6 +415,73 @@ create_inline_session(struct socket_ctx *skt_ctx, 
struct ipsec_sa *sa,
 	return 0;
 }

+int
+create_ipsec_esp_flow(struct ipsec_sa *sa) {
[Anoob] Why just ESP? Can't the same rte_flow rules be used for doing BYPASS/TRANSPORT?

[Praveen]  So yes but this is all we have validated at the moment, transport is trickier as it requires a reverse lookup of the SPD to get the SIP/DIP, which we may do in the future. In terms of BYPASS is not SA specified so we haven't looked at offloading the SPD yet. Finally AH isn't supported in the GW so we haven't looked at it.
 
quoted hunk
+	int ret = 0;
+	struct rte_flow_error err;
+	if (sa->direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS)
+		return 0; /* No Flow director rules for Egress traffic */
+	if (sa->flags == TRANSPORT) {
+		RTE_LOG(ERR, IPSEC,
+			"No Flow director rule for transport mode:");
+			return -1;
+	}
+	sa->action[0].type = RTE_FLOW_ACTION_TYPE_QUEUE;
+	sa->pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
+	sa->action[0].conf =
+			&(struct rte_flow_action_queue){
+				.index = sa->fdir_qid,
+	};
+	sa->attr.egress = 0;
+	sa->attr.ingress = 1;
+	if (IS_IP6(sa->flags)) {
+		sa->pattern[1].mask = &rte_flow_item_ipv6_mask;
+		sa->pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV6;
+		sa->pattern[1].spec = &sa->ipv6_spec;
+		memcpy(sa->ipv6_spec.hdr.dst_addr,
+				sa->dst.ip.ip6.ip6_b, IPV6_ADDR_LEN);
+		memcpy(sa->ipv6_spec.hdr.src_addr,
+				sa->src.ip.ip6.ip6_b, IPV6_ADDR_LEN);
+		sa->pattern[2].type = RTE_FLOW_ITEM_TYPE_ESP;
+		sa->pattern[2].spec = &sa->esp_spec;
+		sa->pattern[2].mask = &rte_flow_item_esp_mask;
+		sa->esp_spec.hdr.spi = rte_cpu_to_be_32(sa->spi);
+		sa->pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
+	} else if (IS_IP4(sa->flags)) {
+		sa->pattern[1].mask = &rte_flow_item_ipv4_mask;
+		sa->pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV4;
+		sa->pattern[1].spec = &sa->ipv4_spec;
+		sa->ipv4_spec.hdr.dst_addr = sa->dst.ip.ip4;
+		sa->ipv4_spec.hdr.src_addr = sa->src.ip.ip4;
+		sa->pattern[2].type = RTE_FLOW_ITEM_TYPE_ESP;
+		sa->pattern[2].spec = &sa->esp_spec;
+		sa->pattern[2].mask = &rte_flow_item_esp_mask;
+		sa->esp_spec.hdr.spi = rte_cpu_to_be_32(sa->spi);
+		sa->pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
+	}
+	sa->action[1].type = RTE_FLOW_ACTION_TYPE_END;
+
+	ret = rte_flow_validate(sa->fdir_portid, &sa->attr,
+				sa->pattern, sa->action,
+				&err);
+	if (ret < 0) {
+		RTE_LOG(ERR, IPSEC,
+			"Flow Validation failed\n");
+		return ret;
+	}
+	sa->flow = rte_flow_create(sa->fdir_portid,
+				&sa->attr, sa->pattern, sa->action,
+				&err);
+	if (!sa->flow) {
+		RTE_LOG(ERR, IPSEC,
+			"Flow Creation failed\n");
+		return -1;
+	}
+
+	return 0;
+}
+
 /*
  * queue crypto-ops into PMD queue.
  */
diff --git a/examples/ipsec-secgw/ipsec.h 
b/examples/ipsec-secgw/ipsec.h index 4f2fd6184..00147895a 100644
--- a/examples/ipsec-secgw/ipsec.h
+++ b/examples/ipsec-secgw/ipsec.h
@@ -46,6 +46,8 @@

 #define IP6_VERSION (6)

+#define IPV6_ADDR_LEN   16
[Anoob] Can't we do a sizeof of some structure to get the same? Having an application specific macro may not be the right approach.

[Praveen] okay. Wil fix this in V3.
 
quoted hunk
+
 struct rte_crypto_xform;
 struct ipsec_xform;
 struct rte_mbuf;
@@ -138,6 +140,9 @@ struct ipsec_sa {
 	};
 	enum rte_security_ipsec_sa_direction direction;
 	uint16_t portid;
+	uint16_t fdir_portid;
[Anoob] The existing member 'portid' above 'fdir_portid' is used for a similar rte_flow creation for inline IPsec. Can't we use the same here also?

[Praveen] Will check if we can use the existing member.
quoted hunk
+	uint8_t fdir_qid;
+	uint8_t fdir_flag;

 #define MAX_RTE_FLOW_PATTERN (4)
 #define MAX_RTE_FLOW_ACTIONS (3)
@@ -383,5 +388,11 @@ create_lookaside_session(struct ipsec_ctx 
*ipsec_ctx, struct ipsec_sa *sa,  int  create_inline_session(struct 
socket_ctx *skt_ctx, struct ipsec_sa *sa,
 		struct rte_ipsec_session *ips);
+int
+check_flow_params(uint16_t fdir_portid, uint8_t fdir_qid);
+
+int
+create_ipsec_esp_flow(struct ipsec_sa *sa);

+int check_fdir_configured(uint16_t portid);
[Anoob] Better to stick to the convention followed.

[Praveen] Will fix this in V3.

 
quoted hunk
 #endif /* __IPSEC_H__ */
diff --git a/examples/ipsec-secgw/sa.c b/examples/ipsec-secgw/sa.c 
index 4822d6bda..204a685fb 100644
--- a/examples/ipsec-secgw/sa.c
+++ b/examples/ipsec-secgw/sa.c
@@ -20,6 +20,9 @@
 #include <rte_random.h>
 #include <rte_ethdev.h>
 #include <rte_malloc.h>
+#include <rte_common.h>
+#include <rte_string_fns.h>
+#include <rte_ethdev_driver.h>

 #include "ipsec.h"
 #include "esp.h"
@@ -271,6 +274,7 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	uint32_t type_p = 0;
 	uint32_t portid_p = 0;
 	uint32_t fallback_p = 0;
+	int16_t status_p = 0;

 	if (strcmp(tokens[0], "in") == 0) {
 		ri = &nb_sa_in;
@@ -681,6 +685,38 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 			fallback_p = 1;
 			continue;
 		}
+		if (strcmp(tokens[ti], "flow-direction") == 0) {
+			if (ips->type ==
+
	RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL ||
+				ips->type ==
+				RTE_SECURITY_ACTION_TYPE_CPU_CRYPTO
||
+				ips->type ==
+
	RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL ||
+				ips->type ==
+
	RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO) {
+				APP_CHECK(0, status, "Flow Director not "
+					"supported for security session "
+					"type:%d", ips->type);
+					return;
+			}
+			rule->fdir_flag = 1;
+			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
+			if (status->status < 0)
+				return;
+			rule->fdir_portid = atoi(tokens[ti]);
+			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
+			if (status->status < 0)
+				return;
+			rule->fdir_qid = atoi(tokens[ti]);
+			/* validating portid and queueid */
+			status_p = check_flow_params(rule->fdir_portid,
+					rule->fdir_qid);
+			if (status_p < 0) {
+				printf("port id %u / queue id %u is not valid\n",
+					rule->fdir_portid, rule->fdir_qid);
+			}
+			continue;
+		}

 		/* unrecognizeable input */
 		APP_CHECK(0, status, "unrecognized input \"%s\"", @@ -823,6
+859,9 @@ print_one_sa_rule(const struct ipsec_sa *sa, int inbound)
 			break;
 		}
 	}
+	if (sa->fdir_flag == 1)
+		printf("flow-direction %d %d", sa->fdir_portid, sa->fdir_qid);
+
 	printf("\n");
 }
@@ -1153,7 +1192,12 @@ sa_add_rules(struct sa_ctx *sa_ctx, const 
struct ipsec_sa entries[],
 				return -EINVAL;
 			}
 		}
-
+		if (sa->fdir_flag && inbound) {
+			rc = create_ipsec_esp_flow(sa);
+			if (rc != 0)
+				RTE_LOG(ERR, IPSEC_ESP,
+					"create_ipsec_esp flow failed\n");
+			}
 		print_one_sa_rule(sa, inbound);
 	}
@@ -1256,6 +1300,20 @@ fill_ipsec_session(struct rte_ipsec_session 
*ss, struct rte_ipsec_sa *sa)
 	return rc;
 }

+int
+check_fdir_configured(uint16_t portid) {
+	struct ipsec_sa *sa = NULL;
+	uint32_t idx_sa = 0;
+
+	for (idx_sa = 0; idx_sa < nb_sa_in; idx_sa++) {
+		sa = &sa_in[idx_sa];
+		if (sa->fdir_portid == portid)
+			return sa->fdir_flag;
+	}
+	return 0;
+}
+
 /*
  * Initialise related rte_ipsec_sa object.
  */
--
2.17.1

[dpdk-dev] [PATCH v3] examples/ipsec-secgw: support flow director feature

From: Praveen Shetty <hidden>
Date: 2020-03-31 13:02:22

Support load distribution in security gateway application using
NIC load distribution feature(Flow Director).
Flow Director is used to redirect the specified inbound ipsec flow
to a specified queue.This is achieved by extending the SA rule syntax
to support specification by adding new action_type of <flow-direction>
to a specified <port_id> <queue_id>.

Signed-off-by: Praveen Shetty <redacted>
---
v3 changes:
Incorporated Anoob review comments on v2.

 examples/ipsec-secgw/ep0.cfg       | 11 +++++
 examples/ipsec-secgw/ipsec-secgw.c | 55 +++++++++++++++++++++++
 examples/ipsec-secgw/ipsec.c       | 67 +++++++++++++++++++++++++++
 examples/ipsec-secgw/ipsec.h       |  9 ++++
 examples/ipsec-secgw/sa.c          | 72 ++++++++++++++++++++++++++++--
 5 files changed, 211 insertions(+), 3 deletions(-)
diff --git a/examples/ipsec-secgw/ep0.cfg b/examples/ipsec-secgw/ep0.cfg
index dfd4aca7d..6f8d5aa53 100644
--- a/examples/ipsec-secgw/ep0.cfg
+++ b/examples/ipsec-secgw/ep0.cfg
@@ -29,6 +29,7 @@ sp ipv4 in esp protect 111 pri 1 dst 192.168.186.0/24 sport 0:65535 dport 0:6553
 sp ipv4 in esp protect 115 pri 1 dst 192.168.210.0/24 sport 0:65535 dport 0:65535
 sp ipv4 in esp protect 116 pri 1 dst 192.168.211.0/24 sport 0:65535 dport 0:65535
 sp ipv4 in esp protect 115 pri 1 dst 192.168.210.0/24 sport 0:65535 dport 0:65535
+sp ipv4 in esp protect 117 pri 1 dst 192.168.212.0/24 sport 0:65535 dport 0:65535
 sp ipv4 in esp protect 125 pri 1 dst 192.168.65.0/24 sport 0:65535 dport 0:65535
 sp ipv4 in esp protect 125 pri 1 dst 192.168.65.0/24 sport 0:65535 dport 0:65535
 sp ipv4 in esp protect 126 pri 1 dst 192.168.66.0/24 sport 0:65535 dport 0:65535
@@ -61,6 +62,8 @@ sp ipv6 in esp protect 125 pri 1 dst ffff:0000:0000:0000:aaaa:aaaa:0000:0000/96
 sport 0:65535 dport 0:65535
 sp ipv6 in esp protect 126 pri 1 dst ffff:0000:0000:0000:bbbb:bbbb:0000:0000/96 \
 sport 0:65535 dport 0:65535
+sp ipv6 in esp protect 127 pri 1 dst ffff:0000:0000:0000:cccc:dddd:0000:0000/96 \
+sport 0:65535 dport 0:65535
 
 #SA rules
 sa out 5 cipher_algo aes-128-cbc cipher_key 0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0 \
@@ -118,6 +121,9 @@ dst 172.16.1.5
 
 sa in 116 cipher_algo null auth_algo null mode ipv4-tunnel src 172.16.2.6 dst 172.16.1.6
 
+sa in 117 cipher_algo null auth_algo null mode ipv4-tunnel src 172.16.2.7 \
+dst 172.16.1.7 flow-direction 0 2
+
 sa in 125 cipher_algo aes-128-cbc cipher_key c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:\
 c3:c3:c3:c3:c3 auth_algo sha1-hmac auth_key c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:\
 c3:c3:c3:c3:c3:c3:c3:c3:c3 mode ipv6-tunnel \
@@ -130,6 +136,11 @@ sa in 126 cipher_algo aes-128-cbc cipher_key 4d:4d:4d:4d:4d:4d:4d:4d:4d:4d:4d:\
 src 2222:2222:2222:2222:2222:2222:2222:6666 \
 dst 1111:1111:1111:1111:1111:1111:1111:6666
 
+sa in 127 cipher_algo null auth_algo null mode ipv6-tunnel \
+src 2222:2222:2222:2222:2222:2222:2222:7777 \
+dst 1111:1111:1111:1111:1111:1111:1111:7777 \
+flow-direction 0 3
+
 #Routing rules
 rt ipv4 dst 172.16.2.5/32 port 0
 rt ipv4 dst 172.16.2.6/32 port 1
diff --git a/examples/ipsec-secgw/ipsec-secgw.c b/examples/ipsec-secgw/ipsec-secgw.c
index ce36e6d9c..4400b075c 100644
--- a/examples/ipsec-secgw/ipsec-secgw.c
+++ b/examples/ipsec-secgw/ipsec-secgw.c
@@ -246,6 +246,30 @@ static struct rte_eth_conf port_conf = {
 	.txmode = {
 		.mq_mode = ETH_MQ_TX_NONE,
 	},
+	.fdir_conf = {
+	.mode = RTE_FDIR_MODE_NONE,
+	.pballoc = RTE_FDIR_PBALLOC_64K,
+	.status = RTE_FDIR_REPORT_STATUS,
+	.mask = {
+		.vlan_tci_mask = 0xFFEF,
+		.ipv4_mask     = {
+			.src_ip = 0xFFFFFFFF,
+			.dst_ip = 0xFFFFFFFF,
+		},
+		.ipv6_mask     = {
+			.src_ip = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+						0xFFFFFFFF},
+			.dst_ip = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+						0xFFFFFFFF},
+		},
+		.src_port_mask = 0xFFFF,
+		.dst_port_mask = 0xFFFF,
+		.mac_addr_byte_mask = 0xFF,
+		.tunnel_type_mask = 1,
+		.tunnel_id_mask = 0xFFFFFFFF,
+	},
+	.drop_queue = 127,
+	}
 };
 
 struct socket_ctx socket_ctx[NB_SOCKETS];
@@ -1183,6 +1207,28 @@ ipsec_poll_mode_worker(void)
 	}
 }
 
+int
+check_flow_params(uint16_t fdir_portid, uint8_t fdir_qid)
+{
+	uint16_t i;
+	uint16_t portid;
+	uint8_t queueid;
+
+	for (i = 0; i < nb_lcore_params; ++i) {
+		portid = lcore_params_array[i].port_id;
+		if (portid == fdir_portid) {
+			queueid = lcore_params_array[i].queue_id;
+			if (queueid == fdir_qid)
+				break;
+		}
+
+		if (i == nb_lcore_params - 1)
+			return -1;
+	}
+
+	return 1;
+}
+
 static int32_t
 check_poll_mode_params(struct eh_conf *eh_conf)
 {
@@ -2813,6 +2859,15 @@ main(int32_t argc, char **argv)
 
 		sa_check_offloads(portid, &req_rx_offloads[portid],
 				&req_tx_offloads[portid]);
+		 /* check if FDIR is configured on the port */
+		if (check_fdir_configured(portid)) {
+			/* Enable FDIR */
+			port_conf.fdir_conf.mode = RTE_FDIR_MODE_PERFECT;
+			/* Disable RSS */
+			port_conf.rxmode.mq_mode = ETH_MQ_RX_NONE;
+			port_conf.rx_adv_conf.rss_conf.rss_hf = 0;
+			port_conf.rx_adv_conf.rss_conf.rss_key = NULL;
+		}
 		port_init(portid, req_rx_offloads[portid],
 				req_tx_offloads[portid]);
 	}
diff --git a/examples/ipsec-secgw/ipsec.c b/examples/ipsec-secgw/ipsec.c
index d40657102..76ee9dbcf 100644
--- a/examples/ipsec-secgw/ipsec.c
+++ b/examples/ipsec-secgw/ipsec.c
@@ -418,6 +418,73 @@ create_inline_session(struct socket_ctx *skt_ctx, struct ipsec_sa *sa,
 	return 0;
 }
 
+int
+create_ipsec_esp_flow(struct ipsec_sa *sa)
+{
+	int ret = 0;
+	struct rte_flow_error err;
+	if (sa->direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS)
+		return 0; /* No Flow director rules for Egress traffic */
+	if (sa->flags == TRANSPORT) {
+		RTE_LOG(ERR, IPSEC,
+			"No Flow director rule for transport mode:");
+			return -1;
+	}
+	sa->action[0].type = RTE_FLOW_ACTION_TYPE_QUEUE;
+	sa->pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
+	sa->action[0].conf =
+			&(struct rte_flow_action_queue){
+				.index = sa->fdir_qid,
+	};
+	sa->attr.egress = 0;
+	sa->attr.ingress = 1;
+	if (IS_IP6(sa->flags)) {
+		sa->pattern[1].mask = &rte_flow_item_ipv6_mask;
+		sa->pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV6;
+		sa->pattern[1].spec = &sa->ipv6_spec;
+		memcpy(sa->ipv6_spec.hdr.dst_addr,
+			sa->dst.ip.ip6.ip6_b, sizeof(sa->dst.ip.ip6.ip6_b));
+		memcpy(sa->ipv6_spec.hdr.src_addr,
+			sa->src.ip.ip6.ip6_b, sizeof(sa->src.ip.ip6.ip6_b));
+		sa->pattern[2].type = RTE_FLOW_ITEM_TYPE_ESP;
+		sa->pattern[2].spec = &sa->esp_spec;
+		sa->pattern[2].mask = &rte_flow_item_esp_mask;
+		sa->esp_spec.hdr.spi = rte_cpu_to_be_32(sa->spi);
+		sa->pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
+	} else if (IS_IP4(sa->flags)) {
+		sa->pattern[1].mask = &rte_flow_item_ipv4_mask;
+		sa->pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV4;
+		sa->pattern[1].spec = &sa->ipv4_spec;
+		sa->ipv4_spec.hdr.dst_addr = sa->dst.ip.ip4;
+		sa->ipv4_spec.hdr.src_addr = sa->src.ip.ip4;
+		sa->pattern[2].type = RTE_FLOW_ITEM_TYPE_ESP;
+		sa->pattern[2].spec = &sa->esp_spec;
+		sa->pattern[2].mask = &rte_flow_item_esp_mask;
+		sa->esp_spec.hdr.spi = rte_cpu_to_be_32(sa->spi);
+		sa->pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
+	}
+	sa->action[1].type = RTE_FLOW_ACTION_TYPE_END;
+
+	ret = rte_flow_validate(sa->portid, &sa->attr,
+				sa->pattern, sa->action,
+				&err);
+	if (ret < 0) {
+		RTE_LOG(ERR, IPSEC,
+			"Flow Validation failed\n");
+		return ret;
+	}
+	sa->flow = rte_flow_create(sa->portid,
+				&sa->attr, sa->pattern, sa->action,
+				&err);
+	if (!sa->flow) {
+		RTE_LOG(ERR, IPSEC,
+			"Flow Creation failed\n");
+		return -1;
+	}
+
+	return 0;
+}
+
 /*
  * queue crypto-ops into PMD queue.
  */
diff --git a/examples/ipsec-secgw/ipsec.h b/examples/ipsec-secgw/ipsec.h
index f8f29f9b1..b0e9f45cb 100644
--- a/examples/ipsec-secgw/ipsec.h
+++ b/examples/ipsec-secgw/ipsec.h
@@ -144,6 +144,8 @@ struct ipsec_sa {
 	};
 	enum rte_security_ipsec_sa_direction direction;
 	uint16_t portid;
+	uint8_t fdir_qid;
+	uint8_t fdir_flag;
 
 #define MAX_RTE_FLOW_PATTERN (4)
 #define MAX_RTE_FLOW_ACTIONS (3)
@@ -408,5 +410,12 @@ create_lookaside_session(struct ipsec_ctx *ipsec_ctx, struct ipsec_sa *sa,
 int
 create_inline_session(struct socket_ctx *skt_ctx, struct ipsec_sa *sa,
 		struct rte_ipsec_session *ips);
+int
+check_flow_params(uint16_t fdir_portid, uint8_t fdir_qid);
+
+int
+create_ipsec_esp_flow(struct ipsec_sa *sa);
 
+int
+check_fdir_configured(uint16_t portid);
 #endif /* __IPSEC_H__ */
diff --git a/examples/ipsec-secgw/sa.c b/examples/ipsec-secgw/sa.c
index 0eb52d141..ddd275142 100644
--- a/examples/ipsec-secgw/sa.c
+++ b/examples/ipsec-secgw/sa.c
@@ -271,6 +271,7 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	uint32_t type_p = 0;
 	uint32_t portid_p = 0;
 	uint32_t fallback_p = 0;
+	int16_t status_p = 0;
 
 	if (strcmp(tokens[0], "in") == 0) {
 		ri = &nb_sa_in;
@@ -295,6 +296,7 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	if (atoi(tokens[1]) == INVALID_SPI)
 		return;
 	rule->spi = atoi(tokens[1]);
+	rule->portid = UINT16_MAX;
 	ips = ipsec_get_primary_session(rule);
 
 	for (ti = 2; ti < n_tokens; ti++) {
@@ -636,9 +638,14 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
 			if (status->status < 0)
 				return;
-			rule->portid = atoi(tokens[ti]);
-			if (status->status < 0)
+			if (rule->portid == UINT16_MAX)
+				rule->portid = atoi(tokens[ti]);
+			else if (rule->portid != atoi(tokens[ti])) {
+				APP_CHECK(0, status, "portid %s "
+				"not matching with already assigned portid %u",
+				tokens[ti], rule->portid);
 				return;
+			}
 			portid_p = 1;
 			continue;
 		}
@@ -681,6 +688,43 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 			fallback_p = 1;
 			continue;
 		}
+		if (strcmp(tokens[ti], "flow-direction") == 0) {
+			if (ips->type ==
+				RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL ||
+				ips->type ==
+				RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL ||
+				ips->type ==
+				RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO) {
+				APP_CHECK(0, status, "Flow Director not "
+					"supported for security session "
+					"type:%d", ips->type);
+					return;
+			}
+			rule->fdir_flag = 1;
+			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
+			if (status->status < 0)
+				return;
+			if (rule->portid == UINT16_MAX)
+				rule->portid = atoi(tokens[ti]);
+			else if (rule->portid != atoi(tokens[ti])) {
+				APP_CHECK(0, status, "portid %s "
+				"not matching with already assigned portid %u",
+				tokens[ti], rule->portid);
+				return;
+			}
+			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
+			if (status->status < 0)
+				return;
+			rule->fdir_qid = atoi(tokens[ti]);
+			/* validating portid and queueid */
+			status_p = check_flow_params(rule->portid,
+					rule->fdir_qid);
+			if (status_p < 0) {
+				printf("port id %u / queue id %u is not valid\n",
+					rule->portid, rule->fdir_qid);
+			}
+			continue;
+		}
 
 		/* unrecognizeable input */
 		APP_CHECK(0, status, "unrecognized input \"%s\"",
@@ -719,7 +763,6 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	if (!type_p || (!portid_p && ips->type !=
 			RTE_SECURITY_ACTION_TYPE_CPU_CRYPTO)) {
 		ips->type = RTE_SECURITY_ACTION_TYPE_NONE;
-		rule->portid = -1;
 	}
 
 	*ri = *ri + 1;
@@ -823,6 +866,9 @@ print_one_sa_rule(const struct ipsec_sa *sa, int inbound)
 			break;
 		}
 	}
+	if (sa->fdir_flag == 1)
+		printf("flow-direction %d %d", sa->portid, sa->fdir_qid);
+
 	printf("\n");
 }
 
@@ -1141,6 +1187,12 @@ sa_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
 			}
 		}
 
+		if (sa->fdir_flag && inbound) {
+			rc = create_ipsec_esp_flow(sa);
+			if (rc != 0)
+				RTE_LOG(ERR, IPSEC_ESP,
+					"create_ipsec_esp flow failed\n");
+			}
 		print_one_sa_rule(sa, inbound);
 	}
 
@@ -1243,6 +1295,20 @@ fill_ipsec_session(struct rte_ipsec_session *ss, struct rte_ipsec_sa *sa)
 	return rc;
 }
 
+int
+check_fdir_configured(uint16_t portid)
+{
+	struct ipsec_sa *sa = NULL;
+	uint32_t idx_sa = 0;
+
+	for (idx_sa = 0; idx_sa < nb_sa_in; idx_sa++) {
+		sa = &sa_in[idx_sa];
+		if (sa->portid == portid)
+			return sa->fdir_flag;
+	}
+	return 0;
+}
+
 /*
  * Initialise related rte_ipsec_sa object.
  */
-- 
2.17.1

Re: [dpdk-dev] [PATCH v3] examples/ipsec-secgw: support flow director feature

From: Akhil Goyal <hidden>
Date: 2020-04-01 13:19:54

Hi Praveen,

Sorry for being late to reply on this, Please delegate the patches properly from next time in patchworks.
This patch was neither delegated to me, nor I was in to/cc. So it got missed.
Support load distribution in security gateway application using
NIC load distribution feature(Flow Director).
Flow Director is used to redirect the specified inbound ipsec flow
to a specified queue.This is achieved by extending the SA rule syntax
to support specification by adding new action_type of <flow-direction>
to a specified <port_id> <queue_id>.
Please add documentation (doc/guides/sample_app_ug/ipsec_secgw.rst) changes
to explain the new parameter.
Signed-off-by: Praveen Shetty <redacted>
---
v3 changes:
Incorporated Anoob review comments on v2.

quoted hunk
diff --git a/examples/ipsec-secgw/ipsec-secgw.c b/examples/ipsec-
secgw/ipsec-secgw.c
index ce36e6d9c..4400b075c 100644
--- a/examples/ipsec-secgw/ipsec-secgw.c
+++ b/examples/ipsec-secgw/ipsec-secgw.c
@@ -246,6 +246,30 @@ static struct rte_eth_conf port_conf = {
 	.txmode = {
 		.mq_mode = ETH_MQ_TX_NONE,
 	},
+	.fdir_conf = {
Fdir_conf is a deprecated parameter. It is not good to introduce 
Something new in the application with a deprecated parameter.
Please use the recommended way to configure flows.
quoted hunk
+	.mode = RTE_FDIR_MODE_NONE,
+	.pballoc = RTE_FDIR_PBALLOC_64K,
+	.status = RTE_FDIR_REPORT_STATUS,
+	.mask = {
+		.vlan_tci_mask = 0xFFEF,
+		.ipv4_mask     = {
+			.src_ip = 0xFFFFFFFF,
+			.dst_ip = 0xFFFFFFFF,
+		},
+		.ipv6_mask     = {
+			.src_ip = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+						0xFFFFFFFF},
+			.dst_ip = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+						0xFFFFFFFF},
+		},
+		.src_port_mask = 0xFFFF,
+		.dst_port_mask = 0xFFFF,
+		.mac_addr_byte_mask = 0xFF,
+		.tunnel_type_mask = 1,
+		.tunnel_id_mask = 0xFFFFFFFF,
+	},
+	.drop_queue = 127,
+	}
 };

 struct socket_ctx socket_ctx[NB_SOCKETS];
@@ -1183,6 +1207,28 @@ ipsec_poll_mode_worker(void)
 	}
 }

+int
+check_flow_params(uint16_t fdir_portid, uint8_t fdir_qid)
+{
+	uint16_t i;
+	uint16_t portid;
+	uint8_t queueid;
+
+	for (i = 0; i < nb_lcore_params; ++i) {
+		portid = lcore_params_array[i].port_id;
+		if (portid == fdir_portid) {
+			queueid = lcore_params_array[i].queue_id;
+			if (queueid == fdir_qid)
+				break;
+		}
+
+		if (i == nb_lcore_params - 1)
+			return -1;
+	}
+
+	return 1;
+}
+
 static int32_t
 check_poll_mode_params(struct eh_conf *eh_conf)
 {
@@ -2813,6 +2859,15 @@ main(int32_t argc, char **argv)

 		sa_check_offloads(portid, &req_rx_offloads[portid],
 				&req_tx_offloads[portid]);
+		 /* check if FDIR is configured on the port */
+		if (check_fdir_configured(portid)) {
+			/* Enable FDIR */
+			port_conf.fdir_conf.mode =
RTE_FDIR_MODE_PERFECT;
+			/* Disable RSS */
+			port_conf.rxmode.mq_mode = ETH_MQ_RX_NONE;
+			port_conf.rx_adv_conf.rss_conf.rss_hf = 0;
+			port_conf.rx_adv_conf.rss_conf.rss_key = NULL;
+		}
 		port_init(portid, req_rx_offloads[portid],
 				req_tx_offloads[portid]);
 	}
diff --git a/examples/ipsec-secgw/ipsec.c b/examples/ipsec-secgw/ipsec.c
index d40657102..76ee9dbcf 100644
--- a/examples/ipsec-secgw/ipsec.c
+++ b/examples/ipsec-secgw/ipsec.c
@@ -418,6 +418,73 @@ create_inline_session(struct socket_ctx *skt_ctx,
struct ipsec_sa *sa,
 	return 0;
 }

+int
+create_ipsec_esp_flow(struct ipsec_sa *sa)
+{
+	int ret = 0;
+	struct rte_flow_error err;
+	if (sa->direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS)
+		return 0; /* No Flow director rules for Egress traffic */
+	if (sa->flags == TRANSPORT) {
+		RTE_LOG(ERR, IPSEC,
+			"No Flow director rule for transport mode:");
+			return -1;
+	}
+	sa->action[0].type = RTE_FLOW_ACTION_TYPE_QUEUE;
+	sa->pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
+	sa->action[0].conf =
+			&(struct rte_flow_action_queue){
+				.index = sa->fdir_qid,
+	};
+	sa->attr.egress = 0;
+	sa->attr.ingress = 1;
+	if (IS_IP6(sa->flags)) {
+		sa->pattern[1].mask = &rte_flow_item_ipv6_mask;
+		sa->pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV6;
+		sa->pattern[1].spec = &sa->ipv6_spec;
+		memcpy(sa->ipv6_spec.hdr.dst_addr,
+			sa->dst.ip.ip6.ip6_b, sizeof(sa->dst.ip.ip6.ip6_b));
+		memcpy(sa->ipv6_spec.hdr.src_addr,
+			sa->src.ip.ip6.ip6_b, sizeof(sa->src.ip.ip6.ip6_b));
+		sa->pattern[2].type = RTE_FLOW_ITEM_TYPE_ESP;
+		sa->pattern[2].spec = &sa->esp_spec;
+		sa->pattern[2].mask = &rte_flow_item_esp_mask;
+		sa->esp_spec.hdr.spi = rte_cpu_to_be_32(sa->spi);
+		sa->pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
+	} else if (IS_IP4(sa->flags)) {
+		sa->pattern[1].mask = &rte_flow_item_ipv4_mask;
+		sa->pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV4;
+		sa->pattern[1].spec = &sa->ipv4_spec;
+		sa->ipv4_spec.hdr.dst_addr = sa->dst.ip.ip4;
+		sa->ipv4_spec.hdr.src_addr = sa->src.ip.ip4;
+		sa->pattern[2].type = RTE_FLOW_ITEM_TYPE_ESP;
+		sa->pattern[2].spec = &sa->esp_spec;
+		sa->pattern[2].mask = &rte_flow_item_esp_mask;
+		sa->esp_spec.hdr.spi = rte_cpu_to_be_32(sa->spi);
+		sa->pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
+	}
+	sa->action[1].type = RTE_FLOW_ACTION_TYPE_END;
+
+	ret = rte_flow_validate(sa->portid, &sa->attr,
+				sa->pattern, sa->action,
+				&err);
+	if (ret < 0) {
+		RTE_LOG(ERR, IPSEC,
+			"Flow Validation failed\n");
+		return ret;
+	}
+	sa->flow = rte_flow_create(sa->portid,
+				&sa->attr, sa->pattern, sa->action,
+				&err);
+	if (!sa->flow) {
+		RTE_LOG(ERR, IPSEC,
+			"Flow Creation failed\n");
+		return -1;
+	}
+
+	return 0;
+}
+
 /*
  * queue crypto-ops into PMD queue.
  */
diff --git a/examples/ipsec-secgw/ipsec.h b/examples/ipsec-secgw/ipsec.h
index f8f29f9b1..b0e9f45cb 100644
--- a/examples/ipsec-secgw/ipsec.h
+++ b/examples/ipsec-secgw/ipsec.h
@@ -144,6 +144,8 @@ struct ipsec_sa {
 	};
 	enum rte_security_ipsec_sa_direction direction;
 	uint16_t portid;
+	uint8_t fdir_qid;
+	uint8_t fdir_flag;

 #define MAX_RTE_FLOW_PATTERN (4)
 #define MAX_RTE_FLOW_ACTIONS (3)
@@ -408,5 +410,12 @@ create_lookaside_session(struct ipsec_ctx *ipsec_ctx,
struct ipsec_sa *sa,
 int
 create_inline_session(struct socket_ctx *skt_ctx, struct ipsec_sa *sa,
 		struct rte_ipsec_session *ips);
+int
+check_flow_params(uint16_t fdir_portid, uint8_t fdir_qid);
+
+int
+create_ipsec_esp_flow(struct ipsec_sa *sa);

+int
+check_fdir_configured(uint16_t portid);
 #endif /* __IPSEC_H__ */
diff --git a/examples/ipsec-secgw/sa.c b/examples/ipsec-secgw/sa.c
index 0eb52d141..ddd275142 100644
--- a/examples/ipsec-secgw/sa.c
+++ b/examples/ipsec-secgw/sa.c
@@ -271,6 +271,7 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	uint32_t type_p = 0;
 	uint32_t portid_p = 0;
 	uint32_t fallback_p = 0;
+	int16_t status_p = 0;

 	if (strcmp(tokens[0], "in") == 0) {
 		ri = &nb_sa_in;
@@ -295,6 +296,7 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	if (atoi(tokens[1]) == INVALID_SPI)
 		return;
 	rule->spi = atoi(tokens[1]);
+	rule->portid = UINT16_MAX;
 	ips = ipsec_get_primary_session(rule);

 	for (ti = 2; ti < n_tokens; ti++) {
@@ -636,9 +638,14 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
 			if (status->status < 0)
 				return;
-			rule->portid = atoi(tokens[ti]);
-			if (status->status < 0)
+			if (rule->portid == UINT16_MAX)
+				rule->portid = atoi(tokens[ti]);
+			else if (rule->portid != atoi(tokens[ti])) {
+				APP_CHECK(0, status, "portid %s "
+				"not matching with already assigned portid %u",
+				tokens[ti], rule->portid);
 				return;
+			}
 			portid_p = 1;
 			continue;
 		}
@@ -681,6 +688,43 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 			fallback_p = 1;
 			continue;
 		}
+		if (strcmp(tokens[ti], "flow-direction") == 0) {
+			if (ips->type ==
+
	RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL ||
+				ips->type ==
+
	RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL ||
+				ips->type ==
+
	RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO) {
+				APP_CHECK(0, status, "Flow Director not "
+					"supported for security session "
+					"type:%d", ips->type);
+					return;
+			}
It means it is supported in cpu crypto as well? Better to have a check for the supported
Action types, as in the future there may be some other action types.
quoted hunk
+			rule->fdir_flag = 1;
+			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
+			if (status->status < 0)
+				return;
+			if (rule->portid == UINT16_MAX)
+				rule->portid = atoi(tokens[ti]);
+			else if (rule->portid != atoi(tokens[ti])) {
+				APP_CHECK(0, status, "portid %s "
+				"not matching with already assigned portid %u",
+				tokens[ti], rule->portid);
+				return;
+			}
+			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
+			if (status->status < 0)
+				return;
+			rule->fdir_qid = atoi(tokens[ti]);
+			/* validating portid and queueid */
+			status_p = check_flow_params(rule->portid,
+					rule->fdir_qid);
+			if (status_p < 0) {
+				printf("port id %u / queue id %u is not valid\n",
+					rule->portid, rule->fdir_qid);
+			}
+			continue;
+		}

 		/* unrecognizeable input */
 		APP_CHECK(0, status, "unrecognized input \"%s\"",
@@ -719,7 +763,6 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	if (!type_p || (!portid_p && ips->type !=
 			RTE_SECURITY_ACTION_TYPE_CPU_CRYPTO)) {
 		ips->type = RTE_SECURITY_ACTION_TYPE_NONE;
-		rule->portid = -1;
 	}

 	*ri = *ri + 1;
@@ -823,6 +866,9 @@ print_one_sa_rule(const struct ipsec_sa *sa, int inbound)
 			break;
 		}
 	}
+	if (sa->fdir_flag == 1)
+		printf("flow-direction %d %d", sa->portid, sa->fdir_qid);
Better to print like below.
printf("flow-direction port %d queue %d ", sa->portid, sa->fdir_qid)
+
 	printf("\n");
 }

Re: [dpdk-dev] [PATCH v3] examples/ipsec-secgw: support flow director feature

From: Anoob Joseph <hidden>
Date: 2020-04-01 13:27:03

Hi Akhil, Praveen,

Can't rte_flow and RSS co-exist? In rte_flow there is an ACTION type RSS in addition to QUEUE. With this patch, if rte_flow is enabled on any SA, then RSS would be disabled for the entire port. Is that the right behavior? And if we have to address this later, what would be the course of action?

Also, is flow director the right name we should use? Internally it is rte_flow, right? 

Thanks,
Anoob
-----Original Message-----
From: Akhil Goyal <redacted>
Sent: Wednesday, April 1, 2020 6:50 PM
To: Praveen Shetty <redacted>; dev@dpdk.org;
declan.doherty@intel.com; Anoob Joseph [off-list ref]
Cc: bernard.iremonger@intel.com; konstantin.ananyev@intel.com
Subject: [EXT] RE: [dpdk-dev] [PATCH v3] examples/ipsec-secgw: support flow
director feature

External Email

----------------------------------------------------------------------
Hi Praveen,

Sorry for being late to reply on this, Please delegate the patches properly from
next time in patchworks.
This patch was neither delegated to me, nor I was in to/cc. So it got missed.
quoted
Support load distribution in security gateway application using NIC
load distribution feature(Flow Director).
Flow Director is used to redirect the specified inbound ipsec flow to
a specified queue.This is achieved by extending the SA rule syntax to
support specification by adding new action_type of <flow-direction> to
a specified <port_id> <queue_id>.
Please add documentation (doc/guides/sample_app_ug/ipsec_secgw.rst)
changes to explain the new parameter.
quoted
Signed-off-by: Praveen Shetty <redacted>
---
v3 changes:
Incorporated Anoob review comments on v2.

quoted
diff --git a/examples/ipsec-secgw/ipsec-secgw.c b/examples/ipsec-
secgw/ipsec-secgw.c index ce36e6d9c..4400b075c 100644
--- a/examples/ipsec-secgw/ipsec-secgw.c
+++ b/examples/ipsec-secgw/ipsec-secgw.c
@@ -246,6 +246,30 @@ static struct rte_eth_conf port_conf = {
 	.txmode = {
 		.mq_mode = ETH_MQ_TX_NONE,
 	},
+	.fdir_conf = {
Fdir_conf is a deprecated parameter. It is not good to introduce Something new
in the application with a deprecated parameter.
Please use the recommended way to configure flows.
quoted
+	.mode = RTE_FDIR_MODE_NONE,
+	.pballoc = RTE_FDIR_PBALLOC_64K,
+	.status = RTE_FDIR_REPORT_STATUS,
+	.mask = {
+		.vlan_tci_mask = 0xFFEF,
+		.ipv4_mask     = {
+			.src_ip = 0xFFFFFFFF,
+			.dst_ip = 0xFFFFFFFF,
+		},
+		.ipv6_mask     = {
+			.src_ip = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+						0xFFFFFFFF},
+			.dst_ip = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+						0xFFFFFFFF},
+		},
+		.src_port_mask = 0xFFFF,
+		.dst_port_mask = 0xFFFF,
+		.mac_addr_byte_mask = 0xFF,
+		.tunnel_type_mask = 1,
+		.tunnel_id_mask = 0xFFFFFFFF,
+	},
+	.drop_queue = 127,
+	}
 };

 struct socket_ctx socket_ctx[NB_SOCKETS]; @@ -1183,6 +1207,28 @@
ipsec_poll_mode_worker(void)
 	}
 }

+int
+check_flow_params(uint16_t fdir_portid, uint8_t fdir_qid) {
+	uint16_t i;
+	uint16_t portid;
+	uint8_t queueid;
+
+	for (i = 0; i < nb_lcore_params; ++i) {
+		portid = lcore_params_array[i].port_id;
+		if (portid == fdir_portid) {
+			queueid = lcore_params_array[i].queue_id;
+			if (queueid == fdir_qid)
+				break;
+		}
+
+		if (i == nb_lcore_params - 1)
+			return -1;
+	}
+
+	return 1;
+}
+
 static int32_t
 check_poll_mode_params(struct eh_conf *eh_conf)  { @@ -2813,6
+2859,15 @@ main(int32_t argc, char **argv)

 		sa_check_offloads(portid, &req_rx_offloads[portid],
 				&req_tx_offloads[portid]);
+		 /* check if FDIR is configured on the port */
+		if (check_fdir_configured(portid)) {
+			/* Enable FDIR */
+			port_conf.fdir_conf.mode =
RTE_FDIR_MODE_PERFECT;
+			/* Disable RSS */
+			port_conf.rxmode.mq_mode = ETH_MQ_RX_NONE;
+			port_conf.rx_adv_conf.rss_conf.rss_hf = 0;
+			port_conf.rx_adv_conf.rss_conf.rss_key = NULL;
+		}
 		port_init(portid, req_rx_offloads[portid],
 				req_tx_offloads[portid]);
 	}
diff --git a/examples/ipsec-secgw/ipsec.c
b/examples/ipsec-secgw/ipsec.c index d40657102..76ee9dbcf 100644
--- a/examples/ipsec-secgw/ipsec.c
+++ b/examples/ipsec-secgw/ipsec.c
@@ -418,6 +418,73 @@ create_inline_session(struct socket_ctx *skt_ctx,
struct ipsec_sa *sa,
 	return 0;
 }

+int
+create_ipsec_esp_flow(struct ipsec_sa *sa) {
+	int ret = 0;
+	struct rte_flow_error err;
+	if (sa->direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS)
+		return 0; /* No Flow director rules for Egress traffic */
+	if (sa->flags == TRANSPORT) {
+		RTE_LOG(ERR, IPSEC,
+			"No Flow director rule for transport mode:");
+			return -1;
+	}
+	sa->action[0].type = RTE_FLOW_ACTION_TYPE_QUEUE;
+	sa->pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
+	sa->action[0].conf =
+			&(struct rte_flow_action_queue){
+				.index = sa->fdir_qid,
+	};
+	sa->attr.egress = 0;
+	sa->attr.ingress = 1;
+	if (IS_IP6(sa->flags)) {
+		sa->pattern[1].mask = &rte_flow_item_ipv6_mask;
+		sa->pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV6;
+		sa->pattern[1].spec = &sa->ipv6_spec;
+		memcpy(sa->ipv6_spec.hdr.dst_addr,
+			sa->dst.ip.ip6.ip6_b, sizeof(sa->dst.ip.ip6.ip6_b));
+		memcpy(sa->ipv6_spec.hdr.src_addr,
+			sa->src.ip.ip6.ip6_b, sizeof(sa->src.ip.ip6.ip6_b));
+		sa->pattern[2].type = RTE_FLOW_ITEM_TYPE_ESP;
+		sa->pattern[2].spec = &sa->esp_spec;
+		sa->pattern[2].mask = &rte_flow_item_esp_mask;
+		sa->esp_spec.hdr.spi = rte_cpu_to_be_32(sa->spi);
+		sa->pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
+	} else if (IS_IP4(sa->flags)) {
+		sa->pattern[1].mask = &rte_flow_item_ipv4_mask;
+		sa->pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV4;
+		sa->pattern[1].spec = &sa->ipv4_spec;
+		sa->ipv4_spec.hdr.dst_addr = sa->dst.ip.ip4;
+		sa->ipv4_spec.hdr.src_addr = sa->src.ip.ip4;
+		sa->pattern[2].type = RTE_FLOW_ITEM_TYPE_ESP;
+		sa->pattern[2].spec = &sa->esp_spec;
+		sa->pattern[2].mask = &rte_flow_item_esp_mask;
+		sa->esp_spec.hdr.spi = rte_cpu_to_be_32(sa->spi);
+		sa->pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
+	}
+	sa->action[1].type = RTE_FLOW_ACTION_TYPE_END;
+
+	ret = rte_flow_validate(sa->portid, &sa->attr,
+				sa->pattern, sa->action,
+				&err);
+	if (ret < 0) {
+		RTE_LOG(ERR, IPSEC,
+			"Flow Validation failed\n");
+		return ret;
+	}
+	sa->flow = rte_flow_create(sa->portid,
+				&sa->attr, sa->pattern, sa->action,
+				&err);
+	if (!sa->flow) {
+		RTE_LOG(ERR, IPSEC,
+			"Flow Creation failed\n");
+		return -1;
+	}
+
+	return 0;
+}
+
 /*
  * queue crypto-ops into PMD queue.
  */
diff --git a/examples/ipsec-secgw/ipsec.h
b/examples/ipsec-secgw/ipsec.h index f8f29f9b1..b0e9f45cb 100644
--- a/examples/ipsec-secgw/ipsec.h
+++ b/examples/ipsec-secgw/ipsec.h
@@ -144,6 +144,8 @@ struct ipsec_sa {
 	};
 	enum rte_security_ipsec_sa_direction direction;
 	uint16_t portid;
+	uint8_t fdir_qid;
+	uint8_t fdir_flag;

 #define MAX_RTE_FLOW_PATTERN (4)
 #define MAX_RTE_FLOW_ACTIONS (3)
@@ -408,5 +410,12 @@ create_lookaside_session(struct ipsec_ctx
*ipsec_ctx, struct ipsec_sa *sa,  int  create_inline_session(struct
socket_ctx *skt_ctx, struct ipsec_sa *sa,
 		struct rte_ipsec_session *ips);
+int
+check_flow_params(uint16_t fdir_portid, uint8_t fdir_qid);
+
+int
+create_ipsec_esp_flow(struct ipsec_sa *sa);

+int
+check_fdir_configured(uint16_t portid);
 #endif /* __IPSEC_H__ */
diff --git a/examples/ipsec-secgw/sa.c b/examples/ipsec-secgw/sa.c
index 0eb52d141..ddd275142 100644
--- a/examples/ipsec-secgw/sa.c
+++ b/examples/ipsec-secgw/sa.c
@@ -271,6 +271,7 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	uint32_t type_p = 0;
 	uint32_t portid_p = 0;
 	uint32_t fallback_p = 0;
+	int16_t status_p = 0;

 	if (strcmp(tokens[0], "in") == 0) {
 		ri = &nb_sa_in;
@@ -295,6 +296,7 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	if (atoi(tokens[1]) == INVALID_SPI)
 		return;
 	rule->spi = atoi(tokens[1]);
+	rule->portid = UINT16_MAX;
 	ips = ipsec_get_primary_session(rule);

 	for (ti = 2; ti < n_tokens; ti++) {
@@ -636,9 +638,14 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
 			if (status->status < 0)
 				return;
-			rule->portid = atoi(tokens[ti]);
-			if (status->status < 0)
+			if (rule->portid == UINT16_MAX)
+				rule->portid = atoi(tokens[ti]);
+			else if (rule->portid != atoi(tokens[ti])) {
+				APP_CHECK(0, status, "portid %s "
+				"not matching with already assigned portid
%u",
quoted
+				tokens[ti], rule->portid);
 				return;
+			}
 			portid_p = 1;
 			continue;
 		}
@@ -681,6 +688,43 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 			fallback_p = 1;
 			continue;
 		}
+		if (strcmp(tokens[ti], "flow-direction") == 0) {
+			if (ips->type ==
+
	RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL ||
+				ips->type ==
+
	RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL ||
+				ips->type ==
+
	RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO) {
+				APP_CHECK(0, status, "Flow Director not "
+					"supported for security session "
+					"type:%d", ips->type);
+					return;
+			}
It means it is supported in cpu crypto as well? Better to have a check for the
supported Action types, as in the future there may be some other action types.
quoted
+			rule->fdir_flag = 1;
+			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
+			if (status->status < 0)
+				return;
+			if (rule->portid == UINT16_MAX)
+				rule->portid = atoi(tokens[ti]);
+			else if (rule->portid != atoi(tokens[ti])) {
+				APP_CHECK(0, status, "portid %s "
+				"not matching with already assigned portid
%u",
quoted
+				tokens[ti], rule->portid);
+				return;
+			}
+			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
+			if (status->status < 0)
+				return;
+			rule->fdir_qid = atoi(tokens[ti]);
+			/* validating portid and queueid */
+			status_p = check_flow_params(rule->portid,
+					rule->fdir_qid);
+			if (status_p < 0) {
+				printf("port id %u / queue id %u is not valid\n",
+					rule->portid, rule->fdir_qid);
+			}
+			continue;
+		}

 		/* unrecognizeable input */
 		APP_CHECK(0, status, "unrecognized input \"%s\"", @@ -719,7
+763,6
quoted
@@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	if (!type_p || (!portid_p && ips->type !=
 			RTE_SECURITY_ACTION_TYPE_CPU_CRYPTO)) {
 		ips->type = RTE_SECURITY_ACTION_TYPE_NONE;
-		rule->portid = -1;
 	}

 	*ri = *ri + 1;
@@ -823,6 +866,9 @@ print_one_sa_rule(const struct ipsec_sa *sa, int
inbound)
quoted
 			break;
 		}
 	}
+	if (sa->fdir_flag == 1)
+		printf("flow-direction %d %d", sa->portid, sa->fdir_qid);
Better to print like below.
printf("flow-direction port %d queue %d ", sa->portid, sa->fdir_qid)
quoted
+
 	printf("\n");
 }

Re: [dpdk-dev] [PATCH v3] examples/ipsec-secgw: support flow director feature

From: Akhil Goyal <hidden>
Date: 2020-04-01 13:53:58

-----Original Message-----
From: Anoob Joseph <redacted>
Sent: Wednesday, April 1, 2020 6:57 PM
To: Akhil Goyal <redacted>; Praveen Shetty
[off-list ref]; dev@dpdk.org; declan.doherty@intel.com
Cc: bernard.iremonger@intel.com; konstantin.ananyev@intel.com
Subject: RE: [dpdk-dev] [PATCH v3] examples/ipsec-secgw: support flow director
feature

Hi Akhil, Praveen,

Can't rte_flow and RSS co-exist? In rte_flow there is an ACTION type RSS in
addition to QUEUE. With this patch, if rte_flow is enabled on any SA, then RSS
would be disabled for the entire port. Is that the right behavior? And if we have
to address this later, what would be the course of action?
Yes they can co-exist I believe. What this patch is doing is assigning a fixed queue to
A flow which user can control for an SA. RSS is based on hash and user doesnot have
Control on it.
Removing RSS on entire port is not desirable and it should not be done. Probably there
Should be a mechanism to disable RSS on that particular flow.
Also, is flow director the right name we should use? Internally it is rte_flow, right?
Name can be anything, I don't feel issue in either flow director or rte_flow.
Thanks,
Anoob
quoted
-----Original Message-----
From: Akhil Goyal <redacted>
Sent: Wednesday, April 1, 2020 6:50 PM
To: Praveen Shetty <redacted>; dev@dpdk.org;
declan.doherty@intel.com; Anoob Joseph [off-list ref]
Cc: bernard.iremonger@intel.com; konstantin.ananyev@intel.com
Subject: [EXT] RE: [dpdk-dev] [PATCH v3] examples/ipsec-secgw: support flow
director feature

External Email

----------------------------------------------------------------------
Hi Praveen,

Sorry for being late to reply on this, Please delegate the patches properly from
next time in patchworks.
This patch was neither delegated to me, nor I was in to/cc. So it got missed.
quoted
Support load distribution in security gateway application using NIC
load distribution feature(Flow Director).
Flow Director is used to redirect the specified inbound ipsec flow to
a specified queue.This is achieved by extending the SA rule syntax to
support specification by adding new action_type of <flow-direction> to
a specified <port_id> <queue_id>.
Please add documentation (doc/guides/sample_app_ug/ipsec_secgw.rst)
changes to explain the new parameter.
quoted
Signed-off-by: Praveen Shetty <redacted>
---
v3 changes:
Incorporated Anoob review comments on v2.

quoted
diff --git a/examples/ipsec-secgw/ipsec-secgw.c b/examples/ipsec-
secgw/ipsec-secgw.c index ce36e6d9c..4400b075c 100644
--- a/examples/ipsec-secgw/ipsec-secgw.c
+++ b/examples/ipsec-secgw/ipsec-secgw.c
@@ -246,6 +246,30 @@ static struct rte_eth_conf port_conf = {
 	.txmode = {
 		.mq_mode = ETH_MQ_TX_NONE,
 	},
+	.fdir_conf = {
Fdir_conf is a deprecated parameter. It is not good to introduce Something
new
quoted
in the application with a deprecated parameter.
Please use the recommended way to configure flows.
quoted
+	.mode = RTE_FDIR_MODE_NONE,
+	.pballoc = RTE_FDIR_PBALLOC_64K,
+	.status = RTE_FDIR_REPORT_STATUS,
+	.mask = {
+		.vlan_tci_mask = 0xFFEF,
+		.ipv4_mask     = {
+			.src_ip = 0xFFFFFFFF,
+			.dst_ip = 0xFFFFFFFF,
+		},
+		.ipv6_mask     = {
+			.src_ip = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+						0xFFFFFFFF},
+			.dst_ip = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+						0xFFFFFFFF},
+		},
+		.src_port_mask = 0xFFFF,
+		.dst_port_mask = 0xFFFF,
+		.mac_addr_byte_mask = 0xFF,
+		.tunnel_type_mask = 1,
+		.tunnel_id_mask = 0xFFFFFFFF,
+	},
+	.drop_queue = 127,
+	}
 };

 struct socket_ctx socket_ctx[NB_SOCKETS]; @@ -1183,6 +1207,28 @@
ipsec_poll_mode_worker(void)
 	}
 }

+int
+check_flow_params(uint16_t fdir_portid, uint8_t fdir_qid) {
+	uint16_t i;
+	uint16_t portid;
+	uint8_t queueid;
+
+	for (i = 0; i < nb_lcore_params; ++i) {
+		portid = lcore_params_array[i].port_id;
+		if (portid == fdir_portid) {
+			queueid = lcore_params_array[i].queue_id;
+			if (queueid == fdir_qid)
+				break;
+		}
+
+		if (i == nb_lcore_params - 1)
+			return -1;
+	}
+
+	return 1;
+}
+
 static int32_t
 check_poll_mode_params(struct eh_conf *eh_conf)  { @@ -2813,6
+2859,15 @@ main(int32_t argc, char **argv)

 		sa_check_offloads(portid, &req_rx_offloads[portid],
 				&req_tx_offloads[portid]);
+		 /* check if FDIR is configured on the port */
+		if (check_fdir_configured(portid)) {
+			/* Enable FDIR */
+			port_conf.fdir_conf.mode =
RTE_FDIR_MODE_PERFECT;
+			/* Disable RSS */
+			port_conf.rxmode.mq_mode = ETH_MQ_RX_NONE;
+			port_conf.rx_adv_conf.rss_conf.rss_hf = 0;
+			port_conf.rx_adv_conf.rss_conf.rss_key = NULL;
+		}
 		port_init(portid, req_rx_offloads[portid],
 				req_tx_offloads[portid]);
 	}
diff --git a/examples/ipsec-secgw/ipsec.c
b/examples/ipsec-secgw/ipsec.c index d40657102..76ee9dbcf 100644
--- a/examples/ipsec-secgw/ipsec.c
+++ b/examples/ipsec-secgw/ipsec.c
@@ -418,6 +418,73 @@ create_inline_session(struct socket_ctx *skt_ctx,
struct ipsec_sa *sa,
 	return 0;
 }

+int
+create_ipsec_esp_flow(struct ipsec_sa *sa) {
+	int ret = 0;
+	struct rte_flow_error err;
+	if (sa->direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS)
+		return 0; /* No Flow director rules for Egress traffic */
+	if (sa->flags == TRANSPORT) {
+		RTE_LOG(ERR, IPSEC,
+			"No Flow director rule for transport mode:");
+			return -1;
+	}
+	sa->action[0].type = RTE_FLOW_ACTION_TYPE_QUEUE;
+	sa->pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
+	sa->action[0].conf =
+			&(struct rte_flow_action_queue){
+				.index = sa->fdir_qid,
+	};
+	sa->attr.egress = 0;
+	sa->attr.ingress = 1;
+	if (IS_IP6(sa->flags)) {
+		sa->pattern[1].mask = &rte_flow_item_ipv6_mask;
+		sa->pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV6;
+		sa->pattern[1].spec = &sa->ipv6_spec;
+		memcpy(sa->ipv6_spec.hdr.dst_addr,
+			sa->dst.ip.ip6.ip6_b, sizeof(sa->dst.ip.ip6.ip6_b));
+		memcpy(sa->ipv6_spec.hdr.src_addr,
+			sa->src.ip.ip6.ip6_b, sizeof(sa->src.ip.ip6.ip6_b));
+		sa->pattern[2].type = RTE_FLOW_ITEM_TYPE_ESP;
+		sa->pattern[2].spec = &sa->esp_spec;
+		sa->pattern[2].mask = &rte_flow_item_esp_mask;
+		sa->esp_spec.hdr.spi = rte_cpu_to_be_32(sa->spi);
+		sa->pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
+	} else if (IS_IP4(sa->flags)) {
+		sa->pattern[1].mask = &rte_flow_item_ipv4_mask;
+		sa->pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV4;
+		sa->pattern[1].spec = &sa->ipv4_spec;
+		sa->ipv4_spec.hdr.dst_addr = sa->dst.ip.ip4;
+		sa->ipv4_spec.hdr.src_addr = sa->src.ip.ip4;
+		sa->pattern[2].type = RTE_FLOW_ITEM_TYPE_ESP;
+		sa->pattern[2].spec = &sa->esp_spec;
+		sa->pattern[2].mask = &rte_flow_item_esp_mask;
+		sa->esp_spec.hdr.spi = rte_cpu_to_be_32(sa->spi);
+		sa->pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
+	}
+	sa->action[1].type = RTE_FLOW_ACTION_TYPE_END;
+
+	ret = rte_flow_validate(sa->portid, &sa->attr,
+				sa->pattern, sa->action,
+				&err);
+	if (ret < 0) {
+		RTE_LOG(ERR, IPSEC,
+			"Flow Validation failed\n");
+		return ret;
+	}
+	sa->flow = rte_flow_create(sa->portid,
+				&sa->attr, sa->pattern, sa->action,
+				&err);
+	if (!sa->flow) {
+		RTE_LOG(ERR, IPSEC,
+			"Flow Creation failed\n");
+		return -1;
+	}
+
+	return 0;
+}
+
 /*
  * queue crypto-ops into PMD queue.
  */
diff --git a/examples/ipsec-secgw/ipsec.h
b/examples/ipsec-secgw/ipsec.h index f8f29f9b1..b0e9f45cb 100644
--- a/examples/ipsec-secgw/ipsec.h
+++ b/examples/ipsec-secgw/ipsec.h
@@ -144,6 +144,8 @@ struct ipsec_sa {
 	};
 	enum rte_security_ipsec_sa_direction direction;
 	uint16_t portid;
+	uint8_t fdir_qid;
+	uint8_t fdir_flag;

 #define MAX_RTE_FLOW_PATTERN (4)
 #define MAX_RTE_FLOW_ACTIONS (3)
@@ -408,5 +410,12 @@ create_lookaside_session(struct ipsec_ctx
*ipsec_ctx, struct ipsec_sa *sa,  int  create_inline_session(struct
socket_ctx *skt_ctx, struct ipsec_sa *sa,
 		struct rte_ipsec_session *ips);
+int
+check_flow_params(uint16_t fdir_portid, uint8_t fdir_qid);
+
+int
+create_ipsec_esp_flow(struct ipsec_sa *sa);

+int
+check_fdir_configured(uint16_t portid);
 #endif /* __IPSEC_H__ */
diff --git a/examples/ipsec-secgw/sa.c b/examples/ipsec-secgw/sa.c
index 0eb52d141..ddd275142 100644
--- a/examples/ipsec-secgw/sa.c
+++ b/examples/ipsec-secgw/sa.c
@@ -271,6 +271,7 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	uint32_t type_p = 0;
 	uint32_t portid_p = 0;
 	uint32_t fallback_p = 0;
+	int16_t status_p = 0;

 	if (strcmp(tokens[0], "in") == 0) {
 		ri = &nb_sa_in;
@@ -295,6 +296,7 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	if (atoi(tokens[1]) == INVALID_SPI)
 		return;
 	rule->spi = atoi(tokens[1]);
+	rule->portid = UINT16_MAX;
 	ips = ipsec_get_primary_session(rule);

 	for (ti = 2; ti < n_tokens; ti++) {
@@ -636,9 +638,14 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
 			if (status->status < 0)
 				return;
-			rule->portid = atoi(tokens[ti]);
-			if (status->status < 0)
+			if (rule->portid == UINT16_MAX)
+				rule->portid = atoi(tokens[ti]);
+			else if (rule->portid != atoi(tokens[ti])) {
+				APP_CHECK(0, status, "portid %s "
+				"not matching with already assigned portid
%u",
quoted
+				tokens[ti], rule->portid);
 				return;
+			}
 			portid_p = 1;
 			continue;
 		}
@@ -681,6 +688,43 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 			fallback_p = 1;
 			continue;
 		}
+		if (strcmp(tokens[ti], "flow-direction") == 0) {
+			if (ips->type ==
+
	RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL ||
+				ips->type ==
+
	RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL ||
+				ips->type ==
+
	RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO) {
+				APP_CHECK(0, status, "Flow Director not "
+					"supported for security session "
+					"type:%d", ips->type);
+					return;
+			}
It means it is supported in cpu crypto as well? Better to have a check for the
supported Action types, as in the future there may be some other action types.
quoted
+			rule->fdir_flag = 1;
+			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
+			if (status->status < 0)
+				return;
+			if (rule->portid == UINT16_MAX)
+				rule->portid = atoi(tokens[ti]);
+			else if (rule->portid != atoi(tokens[ti])) {
+				APP_CHECK(0, status, "portid %s "
+				"not matching with already assigned portid
%u",
quoted
+				tokens[ti], rule->portid);
+				return;
+			}
+			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
+			if (status->status < 0)
+				return;
+			rule->fdir_qid = atoi(tokens[ti]);
+			/* validating portid and queueid */
+			status_p = check_flow_params(rule->portid,
+					rule->fdir_qid);
+			if (status_p < 0) {
+				printf("port id %u / queue id %u is not valid\n",
+					rule->portid, rule->fdir_qid);
+			}
+			continue;
+		}

 		/* unrecognizeable input */
 		APP_CHECK(0, status, "unrecognized input \"%s\"", @@ -719,7
+763,6
quoted
@@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	if (!type_p || (!portid_p && ips->type !=
 			RTE_SECURITY_ACTION_TYPE_CPU_CRYPTO)) {
 		ips->type = RTE_SECURITY_ACTION_TYPE_NONE;
-		rule->portid = -1;
 	}

 	*ri = *ri + 1;
@@ -823,6 +866,9 @@ print_one_sa_rule(const struct ipsec_sa *sa, int
inbound)
quoted
 			break;
 		}
 	}
+	if (sa->fdir_flag == 1)
+		printf("flow-direction %d %d", sa->portid, sa->fdir_qid);
Better to print like below.
printf("flow-direction port %d queue %d ", sa->portid, sa->fdir_qid)
quoted
+
 	printf("\n");
 }

Re: [dpdk-dev] [PATCH v3] examples/ipsec-secgw: support flow director feature

From: Shetty, Praveen <hidden>
Date: 2020-04-02 11:15:45


-----Original Message-----
From: Akhil Goyal <redacted> 
Sent: Wednesday, April 1, 2020 7:24 PM
To: Anoob Joseph <redacted>; Shetty, Praveen <redacted>; dev@dpdk.org; Doherty, Declan <redacted>
Cc: Iremonger, Bernard <redacted>; Ananyev, Konstantin <redacted>
Subject: RE: [dpdk-dev] [PATCH v3] examples/ipsec-secgw: support flow director feature


-----Original Message-----
From: Anoob Joseph <redacted>
Sent: Wednesday, April 1, 2020 6:57 PM
To: Akhil Goyal <redacted>; Praveen Shetty 
[off-list ref]; dev@dpdk.org; declan.doherty@intel.com
Cc: bernard.iremonger@intel.com; konstantin.ananyev@intel.com
Subject: RE: [dpdk-dev] [PATCH v3] examples/ipsec-secgw: support flow 
director feature

Hi Akhil, Praveen,

Can't rte_flow and RSS co-exist? In rte_flow there is an ACTION type 
RSS in addition to QUEUE. With this patch, if rte_flow is enabled on 
any SA, then RSS would be disabled for the entire port. Is that the 
right behavior? And if we have to address this later, what would be the course of action?
Yes they can co-exist I believe. What this patch is doing is assigning a fixed queue to A flow which user can control for an SA. RSS is based on hash and user doesnot have Control on it.
Removing RSS on entire port is not desirable and it should not be done. Probably there Should be a mechanism to disable RSS on that particular flow.

[Praveen]  We will remove the code which disables RSS on entire port in V4. 
meanwhile we will also explore a way to disable the RSS on the queue which the SA is associated with. 

future the idea would be only to disable the queue which the SA is associated with
Also, is flow director the right name we should use? Internally it is rte_flow, right?
Name can be anything, I don't feel issue in either flow director or rte_flow.
Thanks,
Anoob
quoted
-----Original Message-----
From: Akhil Goyal <redacted>
Sent: Wednesday, April 1, 2020 6:50 PM
To: Praveen Shetty <redacted>; dev@dpdk.org; 
declan.doherty@intel.com; Anoob Joseph [off-list ref]
Cc: bernard.iremonger@intel.com; konstantin.ananyev@intel.com
Subject: [EXT] RE: [dpdk-dev] [PATCH v3] examples/ipsec-secgw: 
support flow director feature

External Email

--------------------------------------------------------------------
--
Hi Praveen,

Sorry for being late to reply on this, Please delegate the patches 
properly from next time in patchworks.
This patch was neither delegated to me, nor I was in to/cc. So it got missed.
[Praveen] sorry , I forgot to include you. Will do it from next time.
quoted
quoted
Support load distribution in security gateway application using 
NIC load distribution feature(Flow Director).
Flow Director is used to redirect the specified inbound ipsec flow 
to a specified queue.This is achieved by extending the SA rule 
syntax to support specification by adding new action_type of 
<flow-direction> to a specified <port_id> <queue_id>.
Please add documentation (doc/guides/sample_app_ug/ipsec_secgw.rst)
changes to explain the new parameter.
[Praveen] Will do it in v4.
quoted
quoted
Signed-off-by: Praveen Shetty <redacted>
---
v3 changes:
Incorporated Anoob review comments on v2.

quoted
diff --git a/examples/ipsec-secgw/ipsec-secgw.c b/examples/ipsec- 
secgw/ipsec-secgw.c index ce36e6d9c..4400b075c 100644
--- a/examples/ipsec-secgw/ipsec-secgw.c
+++ b/examples/ipsec-secgw/ipsec-secgw.c
@@ -246,6 +246,30 @@ static struct rte_eth_conf port_conf = {
 	.txmode = {
 		.mq_mode = ETH_MQ_TX_NONE,
 	},
+	.fdir_conf = {
Fdir_conf is a deprecated parameter. It is not good to introduce 
Something
new
quoted
in the application with a deprecated parameter.
Please use the recommended way to configure flows.
[Praveen] We will check and do it in v4.
quoted
quoted
+	.mode = RTE_FDIR_MODE_NONE,
+	.pballoc = RTE_FDIR_PBALLOC_64K,
+	.status = RTE_FDIR_REPORT_STATUS,
+	.mask = {
+		.vlan_tci_mask = 0xFFEF,
+		.ipv4_mask     = {
+			.src_ip = 0xFFFFFFFF,
+			.dst_ip = 0xFFFFFFFF,
+		},
+		.ipv6_mask     = {
+			.src_ip = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+						0xFFFFFFFF},
+			.dst_ip = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+						0xFFFFFFFF},
+		},
+		.src_port_mask = 0xFFFF,
+		.dst_port_mask = 0xFFFF,
+		.mac_addr_byte_mask = 0xFF,
+		.tunnel_type_mask = 1,
+		.tunnel_id_mask = 0xFFFFFFFF,
+	},
+	.drop_queue = 127,
+	}
 };

 struct socket_ctx socket_ctx[NB_SOCKETS]; @@ -1183,6 +1207,28 @@
ipsec_poll_mode_worker(void)
 	}
 }

+int
+check_flow_params(uint16_t fdir_portid, uint8_t fdir_qid) {
+	uint16_t i;
+	uint16_t portid;
+	uint8_t queueid;
+
+	for (i = 0; i < nb_lcore_params; ++i) {
+		portid = lcore_params_array[i].port_id;
+		if (portid == fdir_portid) {
+			queueid = lcore_params_array[i].queue_id;
+			if (queueid == fdir_qid)
+				break;
+		}
+
+		if (i == nb_lcore_params - 1)
+			return -1;
+	}
+
+	return 1;
+}
+
 static int32_t
 check_poll_mode_params(struct eh_conf *eh_conf)  { @@ -2813,6
+2859,15 @@ main(int32_t argc, char **argv)

 		sa_check_offloads(portid, &req_rx_offloads[portid],
 				&req_tx_offloads[portid]);
+		 /* check if FDIR is configured on the port */
+		if (check_fdir_configured(portid)) {
+			/* Enable FDIR */
+			port_conf.fdir_conf.mode =
RTE_FDIR_MODE_PERFECT;
+			/* Disable RSS */
+			port_conf.rxmode.mq_mode = ETH_MQ_RX_NONE;
+			port_conf.rx_adv_conf.rss_conf.rss_hf = 0;
+			port_conf.rx_adv_conf.rss_conf.rss_key = NULL;
+		}
 		port_init(portid, req_rx_offloads[portid],
 				req_tx_offloads[portid]);
 	}
diff --git a/examples/ipsec-secgw/ipsec.c 
b/examples/ipsec-secgw/ipsec.c index d40657102..76ee9dbcf 100644
--- a/examples/ipsec-secgw/ipsec.c
+++ b/examples/ipsec-secgw/ipsec.c
@@ -418,6 +418,73 @@ create_inline_session(struct socket_ctx 
*skt_ctx, struct ipsec_sa *sa,
 	return 0;
 }

+int
+create_ipsec_esp_flow(struct ipsec_sa *sa) {
+	int ret = 0;
+	struct rte_flow_error err;
+	if (sa->direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS)
+		return 0; /* No Flow director rules for Egress traffic */
+	if (sa->flags == TRANSPORT) {
+		RTE_LOG(ERR, IPSEC,
+			"No Flow director rule for transport mode:");
+			return -1;
+	}
+	sa->action[0].type = RTE_FLOW_ACTION_TYPE_QUEUE;
+	sa->pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
+	sa->action[0].conf =
+			&(struct rte_flow_action_queue){
+				.index = sa->fdir_qid,
+	};
+	sa->attr.egress = 0;
+	sa->attr.ingress = 1;
+	if (IS_IP6(sa->flags)) {
+		sa->pattern[1].mask = &rte_flow_item_ipv6_mask;
+		sa->pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV6;
+		sa->pattern[1].spec = &sa->ipv6_spec;
+		memcpy(sa->ipv6_spec.hdr.dst_addr,
+			sa->dst.ip.ip6.ip6_b, sizeof(sa->dst.ip.ip6.ip6_b));
+		memcpy(sa->ipv6_spec.hdr.src_addr,
+			sa->src.ip.ip6.ip6_b, sizeof(sa->src.ip.ip6.ip6_b));
+		sa->pattern[2].type = RTE_FLOW_ITEM_TYPE_ESP;
+		sa->pattern[2].spec = &sa->esp_spec;
+		sa->pattern[2].mask = &rte_flow_item_esp_mask;
+		sa->esp_spec.hdr.spi = rte_cpu_to_be_32(sa->spi);
+		sa->pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
+	} else if (IS_IP4(sa->flags)) {
+		sa->pattern[1].mask = &rte_flow_item_ipv4_mask;
+		sa->pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV4;
+		sa->pattern[1].spec = &sa->ipv4_spec;
+		sa->ipv4_spec.hdr.dst_addr = sa->dst.ip.ip4;
+		sa->ipv4_spec.hdr.src_addr = sa->src.ip.ip4;
+		sa->pattern[2].type = RTE_FLOW_ITEM_TYPE_ESP;
+		sa->pattern[2].spec = &sa->esp_spec;
+		sa->pattern[2].mask = &rte_flow_item_esp_mask;
+		sa->esp_spec.hdr.spi = rte_cpu_to_be_32(sa->spi);
+		sa->pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
+	}
+	sa->action[1].type = RTE_FLOW_ACTION_TYPE_END;
+
+	ret = rte_flow_validate(sa->portid, &sa->attr,
+				sa->pattern, sa->action,
+				&err);
+	if (ret < 0) {
+		RTE_LOG(ERR, IPSEC,
+			"Flow Validation failed\n");
+		return ret;
+	}
+	sa->flow = rte_flow_create(sa->portid,
+				&sa->attr, sa->pattern, sa->action,
+				&err);
+	if (!sa->flow) {
+		RTE_LOG(ERR, IPSEC,
+			"Flow Creation failed\n");
+		return -1;
+	}
+
+	return 0;
+}
+
 /*
  * queue crypto-ops into PMD queue.
  */
diff --git a/examples/ipsec-secgw/ipsec.h 
b/examples/ipsec-secgw/ipsec.h index f8f29f9b1..b0e9f45cb 100644
--- a/examples/ipsec-secgw/ipsec.h
+++ b/examples/ipsec-secgw/ipsec.h
@@ -144,6 +144,8 @@ struct ipsec_sa {
 	};
 	enum rte_security_ipsec_sa_direction direction;
 	uint16_t portid;
+	uint8_t fdir_qid;
+	uint8_t fdir_flag;

 #define MAX_RTE_FLOW_PATTERN (4)
 #define MAX_RTE_FLOW_ACTIONS (3)
@@ -408,5 +410,12 @@ create_lookaside_session(struct ipsec_ctx 
*ipsec_ctx, struct ipsec_sa *sa,  int  
create_inline_session(struct socket_ctx *skt_ctx, struct ipsec_sa *sa,
 		struct rte_ipsec_session *ips);
+int
+check_flow_params(uint16_t fdir_portid, uint8_t fdir_qid);
+
+int
+create_ipsec_esp_flow(struct ipsec_sa *sa);

+int
+check_fdir_configured(uint16_t portid);
 #endif /* __IPSEC_H__ */
diff --git a/examples/ipsec-secgw/sa.c b/examples/ipsec-secgw/sa.c 
index 0eb52d141..ddd275142 100644
--- a/examples/ipsec-secgw/sa.c
+++ b/examples/ipsec-secgw/sa.c
@@ -271,6 +271,7 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	uint32_t type_p = 0;
 	uint32_t portid_p = 0;
 	uint32_t fallback_p = 0;
+	int16_t status_p = 0;

 	if (strcmp(tokens[0], "in") == 0) {
 		ri = &nb_sa_in;
@@ -295,6 +296,7 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	if (atoi(tokens[1]) == INVALID_SPI)
 		return;
 	rule->spi = atoi(tokens[1]);
+	rule->portid = UINT16_MAX;
 	ips = ipsec_get_primary_session(rule);

 	for (ti = 2; ti < n_tokens; ti++) { @@ -636,9 +638,14 @@ 
parse_sa_tokens(char **tokens, uint32_t n_tokens,
 			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
 			if (status->status < 0)
 				return;
-			rule->portid = atoi(tokens[ti]);
-			if (status->status < 0)
+			if (rule->portid == UINT16_MAX)
+				rule->portid = atoi(tokens[ti]);
+			else if (rule->portid != atoi(tokens[ti])) {
+				APP_CHECK(0, status, "portid %s "
+				"not matching with already assigned portid
%u",
quoted
+				tokens[ti], rule->portid);
 				return;
+			}
 			portid_p = 1;
 			continue;
 		}
@@ -681,6 +688,43 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 			fallback_p = 1;
 			continue;
 		}
+		if (strcmp(tokens[ti], "flow-direction") == 0) {
+			if (ips->type ==
+
	RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL ||
+				ips->type ==
+
	RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL ||
+				ips->type ==
+
	RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO) {
+				APP_CHECK(0, status, "Flow Director not "
+					"supported for security session "
+					"type:%d", ips->type);
+					return;
+			}
It means it is supported in cpu crypto as well? 
[Praveen] As of now we have validated only on "RTE_SECURITY_ACTION_TYPE_NONE" and CPU crypto is independent of the IO device similar to action type NONE.
And also it should be supported in other crypto devices as well but we have not included them here because we have not validated.
quoted
Better to have a check for the supported Action types, as in the future there may be some other action types.
[Praveen] We will fix this in V4.
quoted
quoted
+			rule->fdir_flag = 1;
+			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
+			if (status->status < 0)
+				return;
+			if (rule->portid == UINT16_MAX)
+				rule->portid = atoi(tokens[ti]);
+			else if (rule->portid != atoi(tokens[ti])) {
+				APP_CHECK(0, status, "portid %s "
+				"not matching with already assigned portid
%u",
quoted
+				tokens[ti], rule->portid);
+				return;
+			}
+			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
+			if (status->status < 0)
+				return;
+			rule->fdir_qid = atoi(tokens[ti]);
+			/* validating portid and queueid */
+			status_p = check_flow_params(rule->portid,
+					rule->fdir_qid);
+			if (status_p < 0) {
+				printf("port id %u / queue id %u is not valid\n",
+					rule->portid, rule->fdir_qid);
+			}
+			continue;
+		}

 		/* unrecognizeable input */
 		APP_CHECK(0, status, "unrecognized input \"%s\"", @@ -719,7
+763,6
quoted
@@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	if (!type_p || (!portid_p && ips->type !=
 			RTE_SECURITY_ACTION_TYPE_CPU_CRYPTO)) {
 		ips->type = RTE_SECURITY_ACTION_TYPE_NONE;
-		rule->portid = -1;
 	}

 	*ri = *ri + 1;
@@ -823,6 +866,9 @@ print_one_sa_rule(const struct ipsec_sa *sa, 
int
inbound)
quoted
 			break;
 		}
 	}
+	if (sa->fdir_flag == 1)
+		printf("flow-direction %d %d", sa->portid, sa->fdir_qid);
Better to print like below.
printf("flow-direction port %d queue %d ", sa->portid, sa->fdir_qid)
[Praveen] Will do it in V4.
quoted
quoted
+
 	printf("\n");
 }

Re: [dpdk-dev] [EXT] [PATCH v3] examples/ipsec-secgw: support flow director feature

From: Anoob Joseph <hidden>
Date: 2020-04-02 13:39:11

Hi Praveen,

I've few minor comments. Please see inline.

Thanks,
Anoob
quoted hunk
-----Original Message-----
From: Praveen Shetty <redacted>
Sent: Tuesday, March 31, 2020 6:32 PM
To: dev@dpdk.org; declan.doherty@intel.com; Anoob Joseph
[off-list ref]
Cc: bernard.iremonger@intel.com; konstantin.ananyev@intel.com
Subject: [EXT] [PATCH v3] examples/ipsec-secgw: support flow director feature

External Email

----------------------------------------------------------------------
Support load distribution in security gateway application using NIC load
distribution feature(Flow Director).
Flow Director is used to redirect the specified inbound ipsec flow to a specified
queue.This is achieved by extending the SA rule syntax to support specification
by adding new action_type of <flow-direction> to a specified <port_id>
<queue_id>.

Signed-off-by: Praveen Shetty <redacted>
---
v3 changes:
Incorporated Anoob review comments on v2.

 examples/ipsec-secgw/ep0.cfg       | 11 +++++
 examples/ipsec-secgw/ipsec-secgw.c | 55 +++++++++++++++++++++++
 examples/ipsec-secgw/ipsec.c       | 67 +++++++++++++++++++++++++++
 examples/ipsec-secgw/ipsec.h       |  9 ++++
 examples/ipsec-secgw/sa.c          | 72 ++++++++++++++++++++++++++++--
 5 files changed, 211 insertions(+), 3 deletions(-)
diff --git a/examples/ipsec-secgw/ep0.cfg b/examples/ipsec-secgw/ep0.cfg
index dfd4aca7d..6f8d5aa53 100644
--- a/examples/ipsec-secgw/ep0.cfg
+++ b/examples/ipsec-secgw/ep0.cfg
@@ -29,6 +29,7 @@ sp ipv4 in esp protect 111 pri 1 dst 192.168.186.0/24 sport
0:65535 dport 0:6553  sp ipv4 in esp protect 115 pri 1 dst 192.168.210.0/24 sport
0:65535 dport 0:65535  sp ipv4 in esp protect 116 pri 1 dst 192.168.211.0/24
sport 0:65535 dport 0:65535  sp ipv4 in esp protect 115 pri 1 dst
192.168.210.0/24 sport 0:65535 dport 0:65535
+sp ipv4 in esp protect 117 pri 1 dst 192.168.212.0/24 sport 0:65535
+dport 0:65535
 sp ipv4 in esp protect 125 pri 1 dst 192.168.65.0/24 sport 0:65535 dport 0:65535
sp ipv4 in esp protect 125 pri 1 dst 192.168.65.0/24 sport 0:65535 dport 0:65535
sp ipv4 in esp protect 126 pri 1 dst 192.168.66.0/24 sport 0:65535 dport 0:65535
@@ -61,6 +62,8 @@ sp ipv6 in esp protect 125 pri 1 dst
ffff:0000:0000:0000:aaaa:aaaa:0000:0000/96
 sport 0:65535 dport 0:65535
 sp ipv6 in esp protect 126 pri 1 dst
ffff:0000:0000:0000:bbbb:bbbb:0000:0000/96 \  sport 0:65535 dport 0:65535
+sp ipv6 in esp protect 127 pri 1 dst
+ffff:0000:0000:0000:cccc:dddd:0000:0000/96 \ sport 0:65535 dport
+0:65535

 #SA rules
 sa out 5 cipher_algo aes-128-cbc cipher_key 0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0 \
@@ -118,6 +121,9 @@ dst 172.16.1.5

 sa in 116 cipher_algo null auth_algo null mode ipv4-tunnel src 172.16.2.6 dst
172.16.1.6

+sa in 117 cipher_algo null auth_algo null mode ipv4-tunnel src
+172.16.2.7 \ dst 172.16.1.7 flow-direction 0 2
+
 sa in 125 cipher_algo aes-128-cbc cipher_key c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:\
 c3:c3:c3:c3:c3 auth_algo sha1-hmac auth_key
c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:\
 c3:c3:c3:c3:c3:c3:c3:c3:c3 mode ipv6-tunnel \ @@ -130,6 +136,11 @@ sa in
126 cipher_algo aes-128-cbc cipher_key 4d:4d:4d:4d:4d:4d:4d:4d:4d:4d:4d:\
 src 2222:2222:2222:2222:2222:2222:2222:6666 \  dst
1111:1111:1111:1111:1111:1111:1111:6666

+sa in 127 cipher_algo null auth_algo null mode ipv6-tunnel \ src
+2222:2222:2222:2222:2222:2222:2222:7777 \ dst
+1111:1111:1111:1111:1111:1111:1111:7777 \ flow-direction 0 3
+
 #Routing rules
 rt ipv4 dst 172.16.2.5/32 port 0
 rt ipv4 dst 172.16.2.6/32 port 1
diff --git a/examples/ipsec-secgw/ipsec-secgw.c b/examples/ipsec-
secgw/ipsec-secgw.c
index ce36e6d9c..4400b075c 100644
--- a/examples/ipsec-secgw/ipsec-secgw.c
+++ b/examples/ipsec-secgw/ipsec-secgw.c
@@ -246,6 +246,30 @@ static struct rte_eth_conf port_conf = {
 	.txmode = {
 		.mq_mode = ETH_MQ_TX_NONE,
 	},
+	.fdir_conf = {
+	.mode = RTE_FDIR_MODE_NONE,
+	.pballoc = RTE_FDIR_PBALLOC_64K,
+	.status = RTE_FDIR_REPORT_STATUS,
+	.mask = {
+		.vlan_tci_mask = 0xFFEF,
+		.ipv4_mask     = {
+			.src_ip = 0xFFFFFFFF,
+			.dst_ip = 0xFFFFFFFF,
+		},
+		.ipv6_mask     = {
+			.src_ip = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+						0xFFFFFFFF},
+			.dst_ip = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+						0xFFFFFFFF},
+		},
+		.src_port_mask = 0xFFFF,
+		.dst_port_mask = 0xFFFF,
+		.mac_addr_byte_mask = 0xFF,
+		.tunnel_type_mask = 1,
+		.tunnel_id_mask = 0xFFFFFFFF,
+	},
+	.drop_queue = 127,
+	}
 };

 struct socket_ctx socket_ctx[NB_SOCKETS]; @@ -1183,6 +1207,28 @@
ipsec_poll_mode_worker(void)
 	}
 }

+int
+check_flow_params(uint16_t fdir_portid, uint8_t fdir_qid) {
+	uint16_t i;
+	uint16_t portid;
+	uint8_t queueid;
+
+	for (i = 0; i < nb_lcore_params; ++i) {
+		portid = lcore_params_array[i].port_id;
+		if (portid == fdir_portid) {
+			queueid = lcore_params_array[i].queue_id;
+			if (queueid == fdir_qid)
+				break;
+		}
+
+		if (i == nb_lcore_params - 1)
+			return -1;
+	}
+
+	return 1;
+}
+
 static int32_t
 check_poll_mode_params(struct eh_conf *eh_conf)  { @@ -2813,6 +2859,15
@@ main(int32_t argc, char **argv)

 		sa_check_offloads(portid, &req_rx_offloads[portid],
 				&req_tx_offloads[portid]);
+		 /* check if FDIR is configured on the port */
+		if (check_fdir_configured(portid)) {
+			/* Enable FDIR */
+			port_conf.fdir_conf.mode =
RTE_FDIR_MODE_PERFECT;
+			/* Disable RSS */
+			port_conf.rxmode.mq_mode = ETH_MQ_RX_NONE;
+			port_conf.rx_adv_conf.rss_conf.rss_hf = 0;
+			port_conf.rx_adv_conf.rss_conf.rss_key = NULL;
+		}
 		port_init(portid, req_rx_offloads[portid],
 				req_tx_offloads[portid]);
 	}
diff --git a/examples/ipsec-secgw/ipsec.c b/examples/ipsec-secgw/ipsec.c index
d40657102..76ee9dbcf 100644
--- a/examples/ipsec-secgw/ipsec.c
+++ b/examples/ipsec-secgw/ipsec.c
@@ -418,6 +418,73 @@ create_inline_session(struct socket_ctx *skt_ctx,
struct ipsec_sa *sa,
 	return 0;
 }

+int
+create_ipsec_esp_flow(struct ipsec_sa *sa) {
+	int ret = 0;
+	struct rte_flow_error err;
+	if (sa->direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS)
+		return 0; /* No Flow director rules for Egress traffic */
[Anoob] Any reason why this is not relevant for Egress. 

As for the code I would suggest something like,
	/* No flow director rules for Egress traffic */
	if (sa->direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS)
		return 0;

	...
 
+	if (sa->flags == TRANSPORT) {
+		RTE_LOG(ERR, IPSEC,
+			"No Flow director rule for transport mode:");
[Anoob] Is the ending : required in the line above? And do might need a \n?

Also, why is one case returning 0 (EGRESS) and another (TRANSPORT) is returning -1? One is treated as error and other is not?
 
+			return -1;
+	}
+	sa->action[0].type = RTE_FLOW_ACTION_TYPE_QUEUE;
+	sa->pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
+	sa->action[0].conf =
+			&(struct rte_flow_action_queue){
+				.index = sa->fdir_qid,
+	};
+	sa->attr.egress = 0;
+	sa->attr.ingress = 1;
+	if (IS_IP6(sa->flags)) {
+		sa->pattern[1].mask = &rte_flow_item_ipv6_mask;
+		sa->pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV6;
+		sa->pattern[1].spec = &sa->ipv6_spec;
+		memcpy(sa->ipv6_spec.hdr.dst_addr,
+			sa->dst.ip.ip6.ip6_b, sizeof(sa->dst.ip.ip6.ip6_b));
+		memcpy(sa->ipv6_spec.hdr.src_addr,
+			sa->src.ip.ip6.ip6_b, sizeof(sa->src.ip.ip6.ip6_b));
+		sa->pattern[2].type = RTE_FLOW_ITEM_TYPE_ESP;
+		sa->pattern[2].spec = &sa->esp_spec;
+		sa->pattern[2].mask = &rte_flow_item_esp_mask;
+		sa->esp_spec.hdr.spi = rte_cpu_to_be_32(sa->spi);
+		sa->pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
+	} else if (IS_IP4(sa->flags)) {
+		sa->pattern[1].mask = &rte_flow_item_ipv4_mask;
+		sa->pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV4;
+		sa->pattern[1].spec = &sa->ipv4_spec;
+		sa->ipv4_spec.hdr.dst_addr = sa->dst.ip.ip4;
+		sa->ipv4_spec.hdr.src_addr = sa->src.ip.ip4;
+		sa->pattern[2].type = RTE_FLOW_ITEM_TYPE_ESP;
+		sa->pattern[2].spec = &sa->esp_spec;
+		sa->pattern[2].mask = &rte_flow_item_esp_mask;
+		sa->esp_spec.hdr.spi = rte_cpu_to_be_32(sa->spi);
+		sa->pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
+	}
+	sa->action[1].type = RTE_FLOW_ACTION_TYPE_END;
+
+	ret = rte_flow_validate(sa->portid, &sa->attr,
+				sa->pattern, sa->action,
+				&err);
+	if (ret < 0) {
+		RTE_LOG(ERR, IPSEC,
+			"Flow Validation failed\n");
[Anoob] The above should fit into one line. Also V should be small.
 
+		return ret;
+	}
+	sa->flow = rte_flow_create(sa->portid,
+				&sa->attr, sa->pattern, sa->action,
+				&err);
[Anoob] Start breaking into multiple lines when you exceed 80 char limits. In the earlier line, &sa->attr should fit into the line above.

Also, having a blank line above rte_flow_create() line would be good.
 
+	if (!sa->flow) {
+		RTE_LOG(ERR, IPSEC,
+			"Flow Creation failed\n");
[Anoob] Above should fit into one line. Also C should be small.
quoted hunk
+		return -1;
+	}
+
+	return 0;
+}
+
 /*
  * queue crypto-ops into PMD queue.
  */
diff --git a/examples/ipsec-secgw/ipsec.h b/examples/ipsec-secgw/ipsec.h
index f8f29f9b1..b0e9f45cb 100644
--- a/examples/ipsec-secgw/ipsec.h
+++ b/examples/ipsec-secgw/ipsec.h
@@ -144,6 +144,8 @@ struct ipsec_sa {
 	};
 	enum rte_security_ipsec_sa_direction direction;
 	uint16_t portid;
+	uint8_t fdir_qid;
+	uint8_t fdir_flag;

 #define MAX_RTE_FLOW_PATTERN (4)
 #define MAX_RTE_FLOW_ACTIONS (3)
@@ -408,5 +410,12 @@ create_lookaside_session(struct ipsec_ctx *ipsec_ctx,
struct ipsec_sa *sa,  int  create_inline_session(struct socket_ctx *skt_ctx, struct
ipsec_sa *sa,
 		struct rte_ipsec_session *ips);
+int
+check_flow_params(uint16_t fdir_portid, uint8_t fdir_qid);
+
+int
+create_ipsec_esp_flow(struct ipsec_sa *sa);

+int
+check_fdir_configured(uint16_t portid);
 #endif /* __IPSEC_H__ */
diff --git a/examples/ipsec-secgw/sa.c b/examples/ipsec-secgw/sa.c index
0eb52d141..ddd275142 100644
--- a/examples/ipsec-secgw/sa.c
+++ b/examples/ipsec-secgw/sa.c
@@ -271,6 +271,7 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	uint32_t type_p = 0;
 	uint32_t portid_p = 0;
 	uint32_t fallback_p = 0;
+	int16_t status_p = 0;

 	if (strcmp(tokens[0], "in") == 0) {
 		ri = &nb_sa_in;
@@ -295,6 +296,7 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	if (atoi(tokens[1]) == INVALID_SPI)
 		return;
 	rule->spi = atoi(tokens[1]);
+	rule->portid = UINT16_MAX;
 	ips = ipsec_get_primary_session(rule);

 	for (ti = 2; ti < n_tokens; ti++) {
@@ -636,9 +638,14 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
 			if (status->status < 0)
 				return;
-			rule->portid = atoi(tokens[ti]);
-			if (status->status < 0)
+			if (rule->portid == UINT16_MAX)
+				rule->portid = atoi(tokens[ti]);
+			else if (rule->portid != atoi(tokens[ti])) {
+				APP_CHECK(0, status, "portid %s "
+				"not matching with already assigned portid
%u",
+				tokens[ti], rule->portid);
 				return;
[Anoob] Alignment for APP_CHECK's broken up parts are not following the convention.
quoted hunk
+			}
 			portid_p = 1;
 			continue;
 		}
@@ -681,6 +688,43 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 			fallback_p = 1;
 			continue;
 		}
+		if (strcmp(tokens[ti], "flow-direction") == 0) {
+			if (ips->type ==
+
	RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL ||
+				ips->type ==
+
	RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL ||
+				ips->type ==
+
	RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO) {
+				APP_CHECK(0, status, "Flow Director not "
+					"supported for security session "
+					"type:%d", ips->type);
+					return;
+			}
+			rule->fdir_flag = 1;
+			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
+			if (status->status < 0)
+				return;
+			if (rule->portid == UINT16_MAX)
+				rule->portid = atoi(tokens[ti]);
+			else if (rule->portid != atoi(tokens[ti])) {
+				APP_CHECK(0, status, "portid %s "
+				"not matching with already assigned portid
%u",
+				tokens[ti], rule->portid);
+				return;
+			}
+			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
+			if (status->status < 0)
+				return;
+			rule->fdir_qid = atoi(tokens[ti]);
+			/* validating portid and queueid */
+			status_p = check_flow_params(rule->portid,
+					rule->fdir_qid);
+			if (status_p < 0) {
+				printf("port id %u / queue id %u is not valid\n",
+					rule->portid, rule->fdir_qid);
+			}
+			continue;
+		}

 		/* unrecognizeable input */
 		APP_CHECK(0, status, "unrecognized input \"%s\"", @@ -719,7
+763,6 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	if (!type_p || (!portid_p && ips->type !=
 			RTE_SECURITY_ACTION_TYPE_CPU_CRYPTO)) {
 		ips->type = RTE_SECURITY_ACTION_TYPE_NONE;
-		rule->portid = -1;
 	}

 	*ri = *ri + 1;
@@ -823,6 +866,9 @@ print_one_sa_rule(const struct ipsec_sa *sa, int
inbound)
 			break;
 		}
 	}
+	if (sa->fdir_flag == 1)
+		printf("flow-direction %d %d", sa->portid, sa->fdir_qid);
+
 	printf("\n");
 }
@@ -1141,6 +1187,12 @@ sa_add_rules(struct sa_ctx *sa_ctx, const struct
ipsec_sa entries[],
 			}
 		}

+		if (sa->fdir_flag && inbound) {
+			rc = create_ipsec_esp_flow(sa);
+			if (rc != 0)
+				RTE_LOG(ERR, IPSEC_ESP,
+					"create_ipsec_esp flow failed\n");
[Anoob] Instead of function name, can you give the description of what actually failed?
quoted hunk
+			}
 		print_one_sa_rule(sa, inbound);
 	}
@@ -1243,6 +1295,20 @@ fill_ipsec_session(struct rte_ipsec_session *ss, struct
rte_ipsec_sa *sa)
 	return rc;
 }

+int
+check_fdir_configured(uint16_t portid)
+{
+	struct ipsec_sa *sa = NULL;
+	uint32_t idx_sa = 0;
+
+	for (idx_sa = 0; idx_sa < nb_sa_in; idx_sa++) {
+		sa = &sa_in[idx_sa];
+		if (sa->portid == portid)
+			return sa->fdir_flag;
+	}
+	return 0;
+}
+
 /*
  * Initialise related rte_ipsec_sa object.
  */
--
2.17.1

Re: [dpdk-dev] [EXT] [PATCH v3] examples/ipsec-secgw: support flow director feature

From: Shetty, Praveen <hidden>
Date: 2020-04-02 17:57:01

Hi Anoob,

See my response inline.

Regards,
Praveen

-----Original Message-----
From: Anoob Joseph <redacted> 
Sent: Thursday, April 2, 2020 7:09 PM
To: Shetty, Praveen <redacted>; dev@dpdk.org; Doherty, Declan <redacted>
Cc: Iremonger, Bernard <redacted>; Ananyev, Konstantin <redacted>
Subject: RE: [EXT] [PATCH v3] examples/ipsec-secgw: support flow director feature

Hi Praveen,

I've few minor comments. Please see inline.

Thanks,
Anoob
quoted hunk
-----Original Message-----
From: Praveen Shetty <redacted>
Sent: Tuesday, March 31, 2020 6:32 PM
To: dev@dpdk.org; declan.doherty@intel.com; Anoob Joseph 
[off-list ref]
Cc: bernard.iremonger@intel.com; konstantin.ananyev@intel.com
Subject: [EXT] [PATCH v3] examples/ipsec-secgw: support flow director 
feature

External Email

----------------------------------------------------------------------
Support load distribution in security gateway application using NIC 
load distribution feature(Flow Director).
Flow Director is used to redirect the specified inbound ipsec flow to 
a specified queue.This is achieved by extending the SA rule syntax to 
support specification by adding new action_type of <flow-direction> to 
a specified <port_id> <queue_id>.

Signed-off-by: Praveen Shetty <redacted>
---
v3 changes:
Incorporated Anoob review comments on v2.

 examples/ipsec-secgw/ep0.cfg       | 11 +++++
 examples/ipsec-secgw/ipsec-secgw.c | 55 +++++++++++++++++++++++
 examples/ipsec-secgw/ipsec.c       | 67 +++++++++++++++++++++++++++
 examples/ipsec-secgw/ipsec.h       |  9 ++++
 examples/ipsec-secgw/sa.c          | 72 ++++++++++++++++++++++++++++--
 5 files changed, 211 insertions(+), 3 deletions(-)
diff --git a/examples/ipsec-secgw/ep0.cfg 
b/examples/ipsec-secgw/ep0.cfg index dfd4aca7d..6f8d5aa53 100644
--- a/examples/ipsec-secgw/ep0.cfg
+++ b/examples/ipsec-secgw/ep0.cfg
@@ -29,6 +29,7 @@ sp ipv4 in esp protect 111 pri 1 dst 
192.168.186.0/24 sport
0:65535 dport 0:6553  sp ipv4 in esp protect 115 pri 1 dst 
192.168.210.0/24 sport
0:65535 dport 0:65535  sp ipv4 in esp protect 116 pri 1 dst 
192.168.211.0/24 sport 0:65535 dport 0:65535  sp ipv4 in esp protect 
115 pri 1 dst
192.168.210.0/24 sport 0:65535 dport 0:65535
+sp ipv4 in esp protect 117 pri 1 dst 192.168.212.0/24 sport 0:65535 
+dport 0:65535
 sp ipv4 in esp protect 125 pri 1 dst 192.168.65.0/24 sport 0:65535 
dport 0:65535 sp ipv4 in esp protect 125 pri 1 dst 192.168.65.0/24 
sport 0:65535 dport 0:65535 sp ipv4 in esp protect 126 pri 1 dst 
192.168.66.0/24 sport 0:65535 dport 0:65535 @@ -61,6 +62,8 @@ sp ipv6 
in esp protect 125 pri 1 dst
ffff:0000:0000:0000:aaaa:aaaa:0000:0000/96
 sport 0:65535 dport 0:65535
 sp ipv6 in esp protect 126 pri 1 dst
ffff:0000:0000:0000:bbbb:bbbb:0000:0000/96 \  sport 0:65535 dport 
0:65535
+sp ipv6 in esp protect 127 pri 1 dst
+ffff:0000:0000:0000:cccc:dddd:0000:0000/96 \ sport 0:65535 dport
+0:65535

 #SA rules
 sa out 5 cipher_algo aes-128-cbc cipher_key 
0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0 \ @@ -118,6 +121,9 @@ dst 172.16.1.5

 sa in 116 cipher_algo null auth_algo null mode ipv4-tunnel src 
172.16.2.6 dst
172.16.1.6

+sa in 117 cipher_algo null auth_algo null mode ipv4-tunnel src
+172.16.2.7 \ dst 172.16.1.7 flow-direction 0 2
+
 sa in 125 cipher_algo aes-128-cbc cipher_key 
c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:\
 c3:c3:c3:c3:c3 auth_algo sha1-hmac auth_key 
c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:\
 c3:c3:c3:c3:c3:c3:c3:c3:c3 mode ipv6-tunnel \ @@ -130,6 +136,11 @@ sa 
in
126 cipher_algo aes-128-cbc cipher_key 
4d:4d:4d:4d:4d:4d:4d:4d:4d:4d:4d:\
 src 2222:2222:2222:2222:2222:2222:2222:6666 \  dst
1111:1111:1111:1111:1111:1111:1111:6666

+sa in 127 cipher_algo null auth_algo null mode ipv6-tunnel \ src
+2222:2222:2222:2222:2222:2222:2222:7777 \ dst
+1111:1111:1111:1111:1111:1111:1111:7777 \ flow-direction 0 3
+
 #Routing rules
 rt ipv4 dst 172.16.2.5/32 port 0
 rt ipv4 dst 172.16.2.6/32 port 1
diff --git a/examples/ipsec-secgw/ipsec-secgw.c b/examples/ipsec- 
secgw/ipsec-secgw.c index ce36e6d9c..4400b075c 100644
--- a/examples/ipsec-secgw/ipsec-secgw.c
+++ b/examples/ipsec-secgw/ipsec-secgw.c
@@ -246,6 +246,30 @@ static struct rte_eth_conf port_conf = {
 	.txmode = {
 		.mq_mode = ETH_MQ_TX_NONE,
 	},
+	.fdir_conf = {
+	.mode = RTE_FDIR_MODE_NONE,
+	.pballoc = RTE_FDIR_PBALLOC_64K,
+	.status = RTE_FDIR_REPORT_STATUS,
+	.mask = {
+		.vlan_tci_mask = 0xFFEF,
+		.ipv4_mask     = {
+			.src_ip = 0xFFFFFFFF,
+			.dst_ip = 0xFFFFFFFF,
+		},
+		.ipv6_mask     = {
+			.src_ip = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+						0xFFFFFFFF},
+			.dst_ip = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+						0xFFFFFFFF},
+		},
+		.src_port_mask = 0xFFFF,
+		.dst_port_mask = 0xFFFF,
+		.mac_addr_byte_mask = 0xFF,
+		.tunnel_type_mask = 1,
+		.tunnel_id_mask = 0xFFFFFFFF,
+	},
+	.drop_queue = 127,
+	}
 };

 struct socket_ctx socket_ctx[NB_SOCKETS]; @@ -1183,6 +1207,28 @@
ipsec_poll_mode_worker(void)
 	}
 }

+int
+check_flow_params(uint16_t fdir_portid, uint8_t fdir_qid) {
+	uint16_t i;
+	uint16_t portid;
+	uint8_t queueid;
+
+	for (i = 0; i < nb_lcore_params; ++i) {
+		portid = lcore_params_array[i].port_id;
+		if (portid == fdir_portid) {
+			queueid = lcore_params_array[i].queue_id;
+			if (queueid == fdir_qid)
+				break;
+		}
+
+		if (i == nb_lcore_params - 1)
+			return -1;
+	}
+
+	return 1;
+}
+
 static int32_t
 check_poll_mode_params(struct eh_conf *eh_conf)  { @@ -2813,6 
+2859,15 @@ main(int32_t argc, char **argv)

 		sa_check_offloads(portid, &req_rx_offloads[portid],
 				&req_tx_offloads[portid]);
+		 /* check if FDIR is configured on the port */
+		if (check_fdir_configured(portid)) {
+			/* Enable FDIR */
+			port_conf.fdir_conf.mode =
RTE_FDIR_MODE_PERFECT;
+			/* Disable RSS */
+			port_conf.rxmode.mq_mode = ETH_MQ_RX_NONE;
+			port_conf.rx_adv_conf.rss_conf.rss_hf = 0;
+			port_conf.rx_adv_conf.rss_conf.rss_key = NULL;
+		}
 		port_init(portid, req_rx_offloads[portid],
 				req_tx_offloads[portid]);
 	}
diff --git a/examples/ipsec-secgw/ipsec.c 
b/examples/ipsec-secgw/ipsec.c index d40657102..76ee9dbcf 100644
--- a/examples/ipsec-secgw/ipsec.c
+++ b/examples/ipsec-secgw/ipsec.c
@@ -418,6 +418,73 @@ create_inline_session(struct socket_ctx *skt_ctx, 
struct ipsec_sa *sa,
 	return 0;
 }

+int
+create_ipsec_esp_flow(struct ipsec_sa *sa) {
+	int ret = 0;
+	struct rte_flow_error err;
+	if (sa->direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS)
+		return 0; /* No Flow director rules for Egress traffic */
[Anoob] Any reason why this is not relevant for Egress. 

[Praveen] we don't see an use case for load distribution across ingress queues for outbound IPsec traffic therefore we have limited this configuration to inbound IPsec processing, as this is the only use case we can verify.

As for the code I would suggest something like,
	/* No flow director rules for Egress traffic */
	if (sa->direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS)
		return 0;

	...
 
+	if (sa->flags == TRANSPORT) {
+		RTE_LOG(ERR, IPSEC,
+			"No Flow director rule for transport mode:");
[Anoob] Is the ending : required in the line above? And do might need a \n?

[Praveen] Will fix this in v4.

Also, why is one case returning 0 (EGRESS) and another (TRANSPORT) is returning -1? One is treated as error and other is not?

[Praveen] It should be -1(error) for both the cases , will fix this in v4.

 
+			return -1;
+	}
+	sa->action[0].type = RTE_FLOW_ACTION_TYPE_QUEUE;
+	sa->pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
+	sa->action[0].conf =
+			&(struct rte_flow_action_queue){
+				.index = sa->fdir_qid,
+	};
+	sa->attr.egress = 0;
+	sa->attr.ingress = 1;
+	if (IS_IP6(sa->flags)) {
+		sa->pattern[1].mask = &rte_flow_item_ipv6_mask;
+		sa->pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV6;
+		sa->pattern[1].spec = &sa->ipv6_spec;
+		memcpy(sa->ipv6_spec.hdr.dst_addr,
+			sa->dst.ip.ip6.ip6_b, sizeof(sa->dst.ip.ip6.ip6_b));
+		memcpy(sa->ipv6_spec.hdr.src_addr,
+			sa->src.ip.ip6.ip6_b, sizeof(sa->src.ip.ip6.ip6_b));
+		sa->pattern[2].type = RTE_FLOW_ITEM_TYPE_ESP;
+		sa->pattern[2].spec = &sa->esp_spec;
+		sa->pattern[2].mask = &rte_flow_item_esp_mask;
+		sa->esp_spec.hdr.spi = rte_cpu_to_be_32(sa->spi);
+		sa->pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
+	} else if (IS_IP4(sa->flags)) {
+		sa->pattern[1].mask = &rte_flow_item_ipv4_mask;
+		sa->pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV4;
+		sa->pattern[1].spec = &sa->ipv4_spec;
+		sa->ipv4_spec.hdr.dst_addr = sa->dst.ip.ip4;
+		sa->ipv4_spec.hdr.src_addr = sa->src.ip.ip4;
+		sa->pattern[2].type = RTE_FLOW_ITEM_TYPE_ESP;
+		sa->pattern[2].spec = &sa->esp_spec;
+		sa->pattern[2].mask = &rte_flow_item_esp_mask;
+		sa->esp_spec.hdr.spi = rte_cpu_to_be_32(sa->spi);
+		sa->pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
+	}
+	sa->action[1].type = RTE_FLOW_ACTION_TYPE_END;
+
+	ret = rte_flow_validate(sa->portid, &sa->attr,
+				sa->pattern, sa->action,
+				&err);
+	if (ret < 0) {
+		RTE_LOG(ERR, IPSEC,
+			"Flow Validation failed\n");
[Anoob] The above should fit into one line. Also V should be small.

[Praveen] Okay. Will fix this in v4.
 
+		return ret;
+	}
+	sa->flow = rte_flow_create(sa->portid,
+				&sa->attr, sa->pattern, sa->action,
+				&err);
[Anoob] Start breaking into multiple lines when you exceed 80 char limits. In the earlier line, &sa->attr should fit into the line above.

Also, having a blank line above rte_flow_create() line would be good.

[Praveen] Okay. Will fix it in v4
 
+	if (!sa->flow) {
+		RTE_LOG(ERR, IPSEC,
+			"Flow Creation failed\n");
[Anoob] Above should fit into one line. Also C should be small.

[Praveen] okay. Will fix this in v4.
quoted hunk
+		return -1;
+	}
+
+	return 0;
+}
+
 /*
  * queue crypto-ops into PMD queue.
  */
diff --git a/examples/ipsec-secgw/ipsec.h 
b/examples/ipsec-secgw/ipsec.h index f8f29f9b1..b0e9f45cb 100644
--- a/examples/ipsec-secgw/ipsec.h
+++ b/examples/ipsec-secgw/ipsec.h
@@ -144,6 +144,8 @@ struct ipsec_sa {
 	};
 	enum rte_security_ipsec_sa_direction direction;
 	uint16_t portid;
+	uint8_t fdir_qid;
+	uint8_t fdir_flag;

 #define MAX_RTE_FLOW_PATTERN (4)
 #define MAX_RTE_FLOW_ACTIONS (3)
@@ -408,5 +410,12 @@ create_lookaside_session(struct ipsec_ctx 
*ipsec_ctx, struct ipsec_sa *sa,  int  create_inline_session(struct 
socket_ctx *skt_ctx, struct ipsec_sa *sa,
 		struct rte_ipsec_session *ips);
+int
+check_flow_params(uint16_t fdir_portid, uint8_t fdir_qid);
+
+int
+create_ipsec_esp_flow(struct ipsec_sa *sa);

+int
+check_fdir_configured(uint16_t portid);
 #endif /* __IPSEC_H__ */
diff --git a/examples/ipsec-secgw/sa.c b/examples/ipsec-secgw/sa.c 
index
0eb52d141..ddd275142 100644
--- a/examples/ipsec-secgw/sa.c
+++ b/examples/ipsec-secgw/sa.c
@@ -271,6 +271,7 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	uint32_t type_p = 0;
 	uint32_t portid_p = 0;
 	uint32_t fallback_p = 0;
+	int16_t status_p = 0;

 	if (strcmp(tokens[0], "in") == 0) {
 		ri = &nb_sa_in;
@@ -295,6 +296,7 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	if (atoi(tokens[1]) == INVALID_SPI)
 		return;
 	rule->spi = atoi(tokens[1]);
+	rule->portid = UINT16_MAX;
 	ips = ipsec_get_primary_session(rule);

 	for (ti = 2; ti < n_tokens; ti++) {
@@ -636,9 +638,14 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
 			if (status->status < 0)
 				return;
-			rule->portid = atoi(tokens[ti]);
-			if (status->status < 0)
+			if (rule->portid == UINT16_MAX)
+				rule->portid = atoi(tokens[ti]);
+			else if (rule->portid != atoi(tokens[ti])) {
+				APP_CHECK(0, status, "portid %s "
+				"not matching with already assigned portid
%u",
+				tokens[ti], rule->portid);
 				return;
[Anoob] Alignment for APP_CHECK's broken up parts are not following the convention.

[Praveen] Will fix this in v4.
quoted hunk
+			}
 			portid_p = 1;
 			continue;
 		}
@@ -681,6 +688,43 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 			fallback_p = 1;
 			continue;
 		}
+		if (strcmp(tokens[ti], "flow-direction") == 0) {
+			if (ips->type ==
+
	RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL ||
+				ips->type ==
+
	RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL ||
+				ips->type ==
+
	RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO) {
+				APP_CHECK(0, status, "Flow Director not "
+					"supported for security session "
+					"type:%d", ips->type);
+					return;
+			}
+			rule->fdir_flag = 1;
+			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
+			if (status->status < 0)
+				return;
+			if (rule->portid == UINT16_MAX)
+				rule->portid = atoi(tokens[ti]);
+			else if (rule->portid != atoi(tokens[ti])) {
+				APP_CHECK(0, status, "portid %s "
+				"not matching with already assigned portid
%u",
+				tokens[ti], rule->portid);
+				return;
+			}
+			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
+			if (status->status < 0)
+				return;
+			rule->fdir_qid = atoi(tokens[ti]);
+			/* validating portid and queueid */
+			status_p = check_flow_params(rule->portid,
+					rule->fdir_qid);
+			if (status_p < 0) {
+				printf("port id %u / queue id %u is not valid\n",
+					rule->portid, rule->fdir_qid);
+			}
+			continue;
+		}

 		/* unrecognizeable input */
 		APP_CHECK(0, status, "unrecognized input \"%s\"", @@ -719,7
+763,6 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	if (!type_p || (!portid_p && ips->type !=
 			RTE_SECURITY_ACTION_TYPE_CPU_CRYPTO)) {
 		ips->type = RTE_SECURITY_ACTION_TYPE_NONE;
-		rule->portid = -1;
 	}

 	*ri = *ri + 1;
@@ -823,6 +866,9 @@ print_one_sa_rule(const struct ipsec_sa *sa, int
inbound)
 			break;
 		}
 	}
+	if (sa->fdir_flag == 1)
+		printf("flow-direction %d %d", sa->portid, sa->fdir_qid);
+
 	printf("\n");
 }
@@ -1141,6 +1187,12 @@ sa_add_rules(struct sa_ctx *sa_ctx, const 
struct ipsec_sa entries[],
 			}
 		}

+		if (sa->fdir_flag && inbound) {
+			rc = create_ipsec_esp_flow(sa);
+			if (rc != 0)
+				RTE_LOG(ERR, IPSEC_ESP,
+					"create_ipsec_esp flow failed\n");
[Anoob] Instead of function name, can you give the description of what actually failed?

[Praveen] Can be done , will do it in v4.
quoted hunk
+			}
 		print_one_sa_rule(sa, inbound);
 	}
@@ -1243,6 +1295,20 @@ fill_ipsec_session(struct rte_ipsec_session 
*ss, struct rte_ipsec_sa *sa)
 	return rc;
 }

+int
+check_fdir_configured(uint16_t portid) {
+	struct ipsec_sa *sa = NULL;
+	uint32_t idx_sa = 0;
+
+	for (idx_sa = 0; idx_sa < nb_sa_in; idx_sa++) {
+		sa = &sa_in[idx_sa];
+		if (sa->portid == portid)
+			return sa->fdir_flag;
+	}
+	return 0;
+}
+
 /*
  * Initialise related rte_ipsec_sa object.
  */
--
2.17.1

Re: [dpdk-dev] [EXT] [PATCH v3] examples/ipsec-secgw: support flow director feature

From: Anoob Joseph <hidden>
Date: 2020-04-03 05:14:10

Hi Praveen,

Please see inline.

Thanks,
Anoob
-----Original Message-----
From: Shetty, Praveen <redacted>
Sent: Thursday, April 2, 2020 11:27 PM
To: Anoob Joseph <redacted>; dev@dpdk.org; Doherty, Declan
[off-list ref]; Akhil Goyal [off-list ref]
Cc: Iremonger, Bernard <redacted>; Ananyev, Konstantin
[off-list ref]
Subject: RE: [EXT] [PATCH v3] examples/ipsec-secgw: support flow director
feature


Hi Anoob,

See my response inline.

Regards,
Praveen

-----Original Message-----
From: Anoob Joseph <redacted>
Sent: Thursday, April 2, 2020 7:09 PM
To: Shetty, Praveen <redacted>; dev@dpdk.org; Doherty,
Declan [off-list ref]
Cc: Iremonger, Bernard <redacted>; Ananyev, Konstantin
[off-list ref]
Subject: RE: [EXT] [PATCH v3] examples/ipsec-secgw: support flow director
feature

Hi Praveen,

I've few minor comments. Please see inline.

Thanks,
Anoob
quoted
-----Original Message-----
From: Praveen Shetty <redacted>
Sent: Tuesday, March 31, 2020 6:32 PM
To: dev@dpdk.org; declan.doherty@intel.com; Anoob Joseph
[off-list ref]
Cc: bernard.iremonger@intel.com; konstantin.ananyev@intel.com
Subject: [EXT] [PATCH v3] examples/ipsec-secgw: support flow director
feature

External Email

----------------------------------------------------------------------
Support load distribution in security gateway application using NIC
load distribution feature(Flow Director).
Flow Director is used to redirect the specified inbound ipsec flow to
a specified queue.This is achieved by extending the SA rule syntax to
support specification by adding new action_type of <flow-direction> to
a specified <port_id> <queue_id>.

Signed-off-by: Praveen Shetty <redacted>
---
v3 changes:
Incorporated Anoob review comments on v2.

 examples/ipsec-secgw/ep0.cfg       | 11 +++++
 examples/ipsec-secgw/ipsec-secgw.c | 55 +++++++++++++++++++++++
 examples/ipsec-secgw/ipsec.c       | 67 +++++++++++++++++++++++++++
 examples/ipsec-secgw/ipsec.h       |  9 ++++
 examples/ipsec-secgw/sa.c          | 72 ++++++++++++++++++++++++++++--
 5 files changed, 211 insertions(+), 3 deletions(-)
diff --git a/examples/ipsec-secgw/ep0.cfg
b/examples/ipsec-secgw/ep0.cfg index dfd4aca7d..6f8d5aa53 100644
--- a/examples/ipsec-secgw/ep0.cfg
+++ b/examples/ipsec-secgw/ep0.cfg
@@ -29,6 +29,7 @@ sp ipv4 in esp protect 111 pri 1 dst
192.168.186.0/24 sport
0:65535 dport 0:6553  sp ipv4 in esp protect 115 pri 1 dst
192.168.210.0/24 sport
0:65535 dport 0:65535  sp ipv4 in esp protect 116 pri 1 dst
192.168.211.0/24 sport 0:65535 dport 0:65535  sp ipv4 in esp protect
115 pri 1 dst
192.168.210.0/24 sport 0:65535 dport 0:65535
+sp ipv4 in esp protect 117 pri 1 dst 192.168.212.0/24 sport 0:65535
+dport 0:65535
 sp ipv4 in esp protect 125 pri 1 dst 192.168.65.0/24 sport 0:65535
dport 0:65535 sp ipv4 in esp protect 125 pri 1 dst 192.168.65.0/24
sport 0:65535 dport 0:65535 sp ipv4 in esp protect 126 pri 1 dst
192.168.66.0/24 sport 0:65535 dport 0:65535 @@ -61,6 +62,8 @@ sp ipv6
in esp protect 125 pri 1 dst
ffff:0000:0000:0000:aaaa:aaaa:0000:0000/96
 sport 0:65535 dport 0:65535
 sp ipv6 in esp protect 126 pri 1 dst
ffff:0000:0000:0000:bbbb:bbbb:0000:0000/96 \  sport 0:65535 dport
0:65535
+sp ipv6 in esp protect 127 pri 1 dst
+ffff:0000:0000:0000:cccc:dddd:0000:0000/96 \ sport 0:65535 dport
+0:65535

 #SA rules
 sa out 5 cipher_algo aes-128-cbc cipher_key
0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0 \ @@ -118,6 +121,9 @@ dst 172.16.1.5

 sa in 116 cipher_algo null auth_algo null mode ipv4-tunnel src
172.16.2.6 dst
172.16.1.6

+sa in 117 cipher_algo null auth_algo null mode ipv4-tunnel src
+172.16.2.7 \ dst 172.16.1.7 flow-direction 0 2
+
 sa in 125 cipher_algo aes-128-cbc cipher_key
c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:\
 c3:c3:c3:c3:c3 auth_algo sha1-hmac auth_key
c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:\
 c3:c3:c3:c3:c3:c3:c3:c3:c3 mode ipv6-tunnel \ @@ -130,6 +136,11 @@ sa
in
126 cipher_algo aes-128-cbc cipher_key
4d:4d:4d:4d:4d:4d:4d:4d:4d:4d:4d:\
 src 2222:2222:2222:2222:2222:2222:2222:6666 \  dst
1111:1111:1111:1111:1111:1111:1111:6666

+sa in 127 cipher_algo null auth_algo null mode ipv6-tunnel \ src
+2222:2222:2222:2222:2222:2222:2222:7777 \ dst
+1111:1111:1111:1111:1111:1111:1111:7777 \ flow-direction 0 3
+
 #Routing rules
 rt ipv4 dst 172.16.2.5/32 port 0
 rt ipv4 dst 172.16.2.6/32 port 1
diff --git a/examples/ipsec-secgw/ipsec-secgw.c b/examples/ipsec-
secgw/ipsec-secgw.c index ce36e6d9c..4400b075c 100644
--- a/examples/ipsec-secgw/ipsec-secgw.c
+++ b/examples/ipsec-secgw/ipsec-secgw.c
@@ -246,6 +246,30 @@ static struct rte_eth_conf port_conf = {
 	.txmode = {
 		.mq_mode = ETH_MQ_TX_NONE,
 	},
+	.fdir_conf = {
+	.mode = RTE_FDIR_MODE_NONE,
+	.pballoc = RTE_FDIR_PBALLOC_64K,
+	.status = RTE_FDIR_REPORT_STATUS,
+	.mask = {
+		.vlan_tci_mask = 0xFFEF,
+		.ipv4_mask     = {
+			.src_ip = 0xFFFFFFFF,
+			.dst_ip = 0xFFFFFFFF,
+		},
+		.ipv6_mask     = {
+			.src_ip = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+						0xFFFFFFFF},
+			.dst_ip = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+						0xFFFFFFFF},
+		},
+		.src_port_mask = 0xFFFF,
+		.dst_port_mask = 0xFFFF,
+		.mac_addr_byte_mask = 0xFF,
+		.tunnel_type_mask = 1,
+		.tunnel_id_mask = 0xFFFFFFFF,
+	},
+	.drop_queue = 127,
+	}
 };

 struct socket_ctx socket_ctx[NB_SOCKETS]; @@ -1183,6 +1207,28 @@
ipsec_poll_mode_worker(void)
 	}
 }

+int
+check_flow_params(uint16_t fdir_portid, uint8_t fdir_qid) {
+	uint16_t i;
+	uint16_t portid;
+	uint8_t queueid;
+
+	for (i = 0; i < nb_lcore_params; ++i) {
+		portid = lcore_params_array[i].port_id;
+		if (portid == fdir_portid) {
+			queueid = lcore_params_array[i].queue_id;
+			if (queueid == fdir_qid)
+				break;
+		}
+
+		if (i == nb_lcore_params - 1)
+			return -1;
+	}
+
+	return 1;
+}
+
 static int32_t
 check_poll_mode_params(struct eh_conf *eh_conf)  { @@ -2813,6
+2859,15 @@ main(int32_t argc, char **argv)

 		sa_check_offloads(portid, &req_rx_offloads[portid],
 				&req_tx_offloads[portid]);
+		 /* check if FDIR is configured on the port */
+		if (check_fdir_configured(portid)) {
+			/* Enable FDIR */
+			port_conf.fdir_conf.mode =
RTE_FDIR_MODE_PERFECT;
+			/* Disable RSS */
+			port_conf.rxmode.mq_mode = ETH_MQ_RX_NONE;
+			port_conf.rx_adv_conf.rss_conf.rss_hf = 0;
+			port_conf.rx_adv_conf.rss_conf.rss_key = NULL;
+		}
 		port_init(portid, req_rx_offloads[portid],
 				req_tx_offloads[portid]);
 	}
diff --git a/examples/ipsec-secgw/ipsec.c
b/examples/ipsec-secgw/ipsec.c index d40657102..76ee9dbcf 100644
--- a/examples/ipsec-secgw/ipsec.c
+++ b/examples/ipsec-secgw/ipsec.c
@@ -418,6 +418,73 @@ create_inline_session(struct socket_ctx *skt_ctx,
struct ipsec_sa *sa,
 	return 0;
 }

+int
+create_ipsec_esp_flow(struct ipsec_sa *sa) {
+	int ret = 0;
+	struct rte_flow_error err;
+	if (sa->direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS)
+		return 0; /* No Flow director rules for Egress traffic */
[Anoob] Any reason why this is not relevant for Egress.

[Praveen] we don't see an use case for load distribution across ingress queues
for outbound IPsec traffic therefore we have limited this configuration to
inbound IPsec processing, as this is the only use case we can verify.
[Anoob] Why do you say load distribution for ingress queues is not required but is required for egress? I would say the use case is the same in either direction.

Said that, adding just egress should be fine. I leave this to Akhil's judgement.
As for the code I would suggest something like,
	/* No flow director rules for Egress traffic */
	if (sa->direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS)
		return 0;

	...
quoted
+	if (sa->flags == TRANSPORT) {
+		RTE_LOG(ERR, IPSEC,
+			"No Flow director rule for transport mode:");
[Anoob] Is the ending : required in the line above? And do might need a \n?

[Praveen] Will fix this in v4.

Also, why is one case returning 0 (EGRESS) and another (TRANSPORT) is
returning -1? One is treated as error and other is not?

[Praveen] It should be -1(error) for both the cases , will fix this in v4.

quoted
+			return -1;
+	}
+	sa->action[0].type = RTE_FLOW_ACTION_TYPE_QUEUE;
+	sa->pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
+	sa->action[0].conf =
+			&(struct rte_flow_action_queue){
+				.index = sa->fdir_qid,
+	};
+	sa->attr.egress = 0;
+	sa->attr.ingress = 1;
+	if (IS_IP6(sa->flags)) {
+		sa->pattern[1].mask = &rte_flow_item_ipv6_mask;
+		sa->pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV6;
+		sa->pattern[1].spec = &sa->ipv6_spec;
+		memcpy(sa->ipv6_spec.hdr.dst_addr,
+			sa->dst.ip.ip6.ip6_b, sizeof(sa->dst.ip.ip6.ip6_b));
+		memcpy(sa->ipv6_spec.hdr.src_addr,
+			sa->src.ip.ip6.ip6_b, sizeof(sa->src.ip.ip6.ip6_b));
+		sa->pattern[2].type = RTE_FLOW_ITEM_TYPE_ESP;
+		sa->pattern[2].spec = &sa->esp_spec;
+		sa->pattern[2].mask = &rte_flow_item_esp_mask;
+		sa->esp_spec.hdr.spi = rte_cpu_to_be_32(sa->spi);
+		sa->pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
+	} else if (IS_IP4(sa->flags)) {
+		sa->pattern[1].mask = &rte_flow_item_ipv4_mask;
+		sa->pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV4;
+		sa->pattern[1].spec = &sa->ipv4_spec;
+		sa->ipv4_spec.hdr.dst_addr = sa->dst.ip.ip4;
+		sa->ipv4_spec.hdr.src_addr = sa->src.ip.ip4;
+		sa->pattern[2].type = RTE_FLOW_ITEM_TYPE_ESP;
+		sa->pattern[2].spec = &sa->esp_spec;
+		sa->pattern[2].mask = &rte_flow_item_esp_mask;
+		sa->esp_spec.hdr.spi = rte_cpu_to_be_32(sa->spi);
+		sa->pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
+	}
+	sa->action[1].type = RTE_FLOW_ACTION_TYPE_END;
+
+	ret = rte_flow_validate(sa->portid, &sa->attr,
+				sa->pattern, sa->action,
+				&err);
+	if (ret < 0) {
+		RTE_LOG(ERR, IPSEC,
+			"Flow Validation failed\n");
[Anoob] The above should fit into one line. Also V should be small.

[Praveen] Okay. Will fix this in v4.
quoted
+		return ret;
+	}
+	sa->flow = rte_flow_create(sa->portid,
+				&sa->attr, sa->pattern, sa->action,
+				&err);
[Anoob] Start breaking into multiple lines when you exceed 80 char limits. In the
earlier line, &sa->attr should fit into the line above.

Also, having a blank line above rte_flow_create() line would be good.

[Praveen] Okay. Will fix it in v4
quoted
+	if (!sa->flow) {
+		RTE_LOG(ERR, IPSEC,
+			"Flow Creation failed\n");
[Anoob] Above should fit into one line. Also C should be small.

[Praveen] okay. Will fix this in v4.
quoted
+		return -1;
+	}
+
+	return 0;
+}
+
 /*
  * queue crypto-ops into PMD queue.
  */
diff --git a/examples/ipsec-secgw/ipsec.h
b/examples/ipsec-secgw/ipsec.h index f8f29f9b1..b0e9f45cb 100644
--- a/examples/ipsec-secgw/ipsec.h
+++ b/examples/ipsec-secgw/ipsec.h
@@ -144,6 +144,8 @@ struct ipsec_sa {
 	};
 	enum rte_security_ipsec_sa_direction direction;
 	uint16_t portid;
+	uint8_t fdir_qid;
+	uint8_t fdir_flag;

 #define MAX_RTE_FLOW_PATTERN (4)
 #define MAX_RTE_FLOW_ACTIONS (3)
@@ -408,5 +410,12 @@ create_lookaside_session(struct ipsec_ctx
*ipsec_ctx, struct ipsec_sa *sa,  int  create_inline_session(struct
socket_ctx *skt_ctx, struct ipsec_sa *sa,
 		struct rte_ipsec_session *ips);
+int
+check_flow_params(uint16_t fdir_portid, uint8_t fdir_qid);
+
+int
+create_ipsec_esp_flow(struct ipsec_sa *sa);

+int
+check_fdir_configured(uint16_t portid);
 #endif /* __IPSEC_H__ */
diff --git a/examples/ipsec-secgw/sa.c b/examples/ipsec-secgw/sa.c
index
0eb52d141..ddd275142 100644
--- a/examples/ipsec-secgw/sa.c
+++ b/examples/ipsec-secgw/sa.c
@@ -271,6 +271,7 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	uint32_t type_p = 0;
 	uint32_t portid_p = 0;
 	uint32_t fallback_p = 0;
+	int16_t status_p = 0;

 	if (strcmp(tokens[0], "in") == 0) {
 		ri = &nb_sa_in;
@@ -295,6 +296,7 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	if (atoi(tokens[1]) == INVALID_SPI)
 		return;
 	rule->spi = atoi(tokens[1]);
+	rule->portid = UINT16_MAX;
 	ips = ipsec_get_primary_session(rule);

 	for (ti = 2; ti < n_tokens; ti++) {
@@ -636,9 +638,14 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
 			if (status->status < 0)
 				return;
-			rule->portid = atoi(tokens[ti]);
-			if (status->status < 0)
+			if (rule->portid == UINT16_MAX)
+				rule->portid = atoi(tokens[ti]);
+			else if (rule->portid != atoi(tokens[ti])) {
+				APP_CHECK(0, status, "portid %s "
+				"not matching with already assigned portid
%u",
+				tokens[ti], rule->portid);
 				return;
[Anoob] Alignment for APP_CHECK's broken up parts are not following the
convention.

[Praveen] Will fix this in v4.
quoted
+			}
 			portid_p = 1;
 			continue;
 		}
@@ -681,6 +688,43 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 			fallback_p = 1;
 			continue;
 		}
+		if (strcmp(tokens[ti], "flow-direction") == 0) {
+			if (ips->type ==
+
	RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL ||
+				ips->type ==
+
	RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL ||
+				ips->type ==
+
	RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO) {
+				APP_CHECK(0, status, "Flow Director not "
+					"supported for security session "
+					"type:%d", ips->type);
+					return;
+			}
+			rule->fdir_flag = 1;
+			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
+			if (status->status < 0)
+				return;
+			if (rule->portid == UINT16_MAX)
+				rule->portid = atoi(tokens[ti]);
+			else if (rule->portid != atoi(tokens[ti])) {
+				APP_CHECK(0, status, "portid %s "
+				"not matching with already assigned portid
%u",
+				tokens[ti], rule->portid);
+				return;
+			}
+			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
+			if (status->status < 0)
+				return;
+			rule->fdir_qid = atoi(tokens[ti]);
+			/* validating portid and queueid */
+			status_p = check_flow_params(rule->portid,
+					rule->fdir_qid);
+			if (status_p < 0) {
+				printf("port id %u / queue id %u is not valid\n",
+					rule->portid, rule->fdir_qid);
+			}
+			continue;
+		}

 		/* unrecognizeable input */
 		APP_CHECK(0, status, "unrecognized input \"%s\"", @@ -719,7
+763,6 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	if (!type_p || (!portid_p && ips->type !=
 			RTE_SECURITY_ACTION_TYPE_CPU_CRYPTO)) {
 		ips->type = RTE_SECURITY_ACTION_TYPE_NONE;
-		rule->portid = -1;
 	}

 	*ri = *ri + 1;
@@ -823,6 +866,9 @@ print_one_sa_rule(const struct ipsec_sa *sa, int
inbound)
 			break;
 		}
 	}
+	if (sa->fdir_flag == 1)
+		printf("flow-direction %d %d", sa->portid, sa->fdir_qid);
+
 	printf("\n");
 }
@@ -1141,6 +1187,12 @@ sa_add_rules(struct sa_ctx *sa_ctx, const
struct ipsec_sa entries[],
 			}
 		}

+		if (sa->fdir_flag && inbound) {
+			rc = create_ipsec_esp_flow(sa);
+			if (rc != 0)
+				RTE_LOG(ERR, IPSEC_ESP,
+					"create_ipsec_esp flow failed\n");
[Anoob] Instead of function name, can you give the description of what actually
failed?

[Praveen] Can be done , will do it in v4.
quoted
+			}
 		print_one_sa_rule(sa, inbound);
 	}
@@ -1243,6 +1295,20 @@ fill_ipsec_session(struct rte_ipsec_session
*ss, struct rte_ipsec_sa *sa)
 	return rc;
 }

+int
+check_fdir_configured(uint16_t portid) {
+	struct ipsec_sa *sa = NULL;
+	uint32_t idx_sa = 0;
+
+	for (idx_sa = 0; idx_sa < nb_sa_in; idx_sa++) {
+		sa = &sa_in[idx_sa];
+		if (sa->portid == portid)
+			return sa->fdir_flag;
+	}
+	return 0;
+}
+
 /*
  * Initialise related rte_ipsec_sa object.
  */
--
2.17.1

Re: [dpdk-dev] [EXT] [PATCH v3] examples/ipsec-secgw: support flow director feature

From: Akhil Goyal <hidden>
Date: 2020-04-03 05:52:14

quoted
quoted
diff --git a/examples/ipsec-secgw/ipsec.c
b/examples/ipsec-secgw/ipsec.c index d40657102..76ee9dbcf 100644
--- a/examples/ipsec-secgw/ipsec.c
+++ b/examples/ipsec-secgw/ipsec.c
@@ -418,6 +418,73 @@ create_inline_session(struct socket_ctx *skt_ctx,
struct ipsec_sa *sa,
 	return 0;
 }

+int
+create_ipsec_esp_flow(struct ipsec_sa *sa) {
+	int ret = 0;
+	struct rte_flow_error err;
+	if (sa->direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS)
+		return 0; /* No Flow director rules for Egress traffic */
[Anoob] Any reason why this is not relevant for Egress.

[Praveen] we don't see an use case for load distribution across ingress queues
for outbound IPsec traffic therefore we have limited this configuration to
inbound IPsec processing, as this is the only use case we can verify.
[Anoob] Why do you say load distribution for ingress queues is not required but
is required for egress? I would say the use case is the same in either direction.

Said that, adding just egress should be fine. I leave this to Akhil's judgement.
I believe it does not matter for EGRESS in most hardwares,
INGRESS flows should have distribution. I think your comments are just reverse but
The code is inline with my understanding.

Re: [dpdk-dev] [EXT] [PATCH v3] examples/ipsec-secgw: support flow director feature

From: Shetty, Praveen <hidden>
Date: 2020-04-03 10:21:36


-----Original Message-----
From: Akhil Goyal <redacted> 
Sent: Friday, April 3, 2020 11:22 AM
To: Anoob Joseph <redacted>; Shetty, Praveen <redacted>; dev@dpdk.org; Doherty, Declan <redacted>
Cc: Iremonger, Bernard <redacted>; Ananyev, Konstantin <redacted>
Subject: RE: [EXT] [PATCH v3] examples/ipsec-secgw: support flow director feature
quoted
quoted
diff --git a/examples/ipsec-secgw/ipsec.c 
b/examples/ipsec-secgw/ipsec.c index d40657102..76ee9dbcf 100644
--- a/examples/ipsec-secgw/ipsec.c
+++ b/examples/ipsec-secgw/ipsec.c
@@ -418,6 +418,73 @@ create_inline_session(struct socket_ctx 
*skt_ctx, struct ipsec_sa *sa,
 	return 0;
 }

+int
+create_ipsec_esp_flow(struct ipsec_sa *sa) {
+	int ret = 0;
+	struct rte_flow_error err;
+	if (sa->direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS)
+		return 0; /* No Flow director rules for Egress traffic */
[Anoob] Any reason why this is not relevant for Egress.

[Praveen] we don't see an use case for load distribution across 
ingress queues for outbound IPsec traffic therefore we have limited 
this configuration to inbound IPsec processing, as this is the only use case we can verify.
[Anoob] Why do you say load distribution for ingress queues is not 
required but is required for egress? I would say the use case is the same in either direction.

Said that, adding just egress should be fine. I leave this to Akhil's judgement.
I believe it does not matter for EGRESS in most hardwares, INGRESS flows should have distribution. I think your comments are just reverse but The code is inline with my understanding.

[Praveen] 
Current implementation is only for ingress traffic load distribution therefore it is applicable only for inbound IPsec traffic.

Re: [dpdk-dev] [EXT] [PATCH v3] examples/ipsec-secgw: support flow director feature

From: Anoob Joseph <hidden>
Date: 2020-04-03 10:28:33

Hi Akhil, Praveen,

Please see inline.

Thanks,
Anoob
-----Original Message-----
From: Shetty, Praveen <redacted>
Sent: Friday, April 3, 2020 3:51 PM
To: Akhil Goyal <redacted>; Anoob Joseph <redacted>;
dev@dpdk.org; Doherty, Declan [off-list ref]
Cc: Iremonger, Bernard <redacted>; Ananyev, Konstantin
[off-list ref]
Subject: RE: [EXT] [PATCH v3] examples/ipsec-secgw: support flow director
feature



-----Original Message-----
From: Akhil Goyal <redacted>
Sent: Friday, April 3, 2020 11:22 AM
To: Anoob Joseph <redacted>; Shetty, Praveen
[off-list ref]; dev@dpdk.org; Doherty, Declan
[off-list ref]
Cc: Iremonger, Bernard <redacted>; Ananyev, Konstantin
[off-list ref]
Subject: RE: [EXT] [PATCH v3] examples/ipsec-secgw: support flow director
feature
quoted
quoted
quoted
diff --git a/examples/ipsec-secgw/ipsec.c
b/examples/ipsec-secgw/ipsec.c index d40657102..76ee9dbcf 100644
--- a/examples/ipsec-secgw/ipsec.c
+++ b/examples/ipsec-secgw/ipsec.c
@@ -418,6 +418,73 @@ create_inline_session(struct socket_ctx
*skt_ctx, struct ipsec_sa *sa,
 	return 0;
 }

+int
+create_ipsec_esp_flow(struct ipsec_sa *sa) {
+	int ret = 0;
+	struct rte_flow_error err;
+	if (sa->direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS)
+		return 0; /* No Flow director rules for Egress traffic */
[Anoob] Any reason why this is not relevant for Egress.

[Praveen] we don't see an use case for load distribution across
ingress queues for outbound IPsec traffic therefore we have limited
this configuration to inbound IPsec processing, as this is the only use case we
can verify.
quoted
[Anoob] Why do you say load distribution for ingress queues is not
required but is required for egress? I would say the use case is the same in
either direction.
quoted
Said that, adding just egress should be fine. I leave this to Akhil's judgement.
I believe it does not matter for EGRESS in most hardwares, INGRESS flows
should have distribution. I think your comments are just reverse but The code is
inline with my understanding.

[Praveen]
Current implementation is only for ingress traffic load distribution therefore it is
applicable only for inbound IPsec traffic.
[Anoob] Yes. I got it reverse. Meant egress instead of ingress and the other way round as well.

I was asking for the rationale behind limiting the scope. Anyway, that can be taken up separately.

[dpdk-dev] [PATCH v4] examples/ipsec-secgw: support flow director feature

From: Praveen Shetty <hidden>
Date: 2020-04-08 14:13:50

Support load distribution in security gateway application using
NIC load distribution feature(Flow Director).
Flow Director is used to redirect the specified inbound ipsec flow
to a specified queue.This is achieved by extending the SA rule syntax
to support specification by adding new action_type of <flow-direction>
to a specified <port_id> <queue_id>.

Signed-off-by: Praveen Shetty <redacted>
---
v4 changes:
1. Removed flow direction configuration changes as it is not required anymore.
2. Addressed all the review comments from Akhil and Anoob.
3. Included Release doc and Release notes.

 doc/guides/rel_notes/release_20_05.rst   |  4 ++
 doc/guides/sample_app_ug/ipsec_secgw.rst | 16 ++++++
 examples/ipsec-secgw/ep0.cfg             | 11 ++++
 examples/ipsec-secgw/ipsec-secgw.c       | 22 ++++++++
 examples/ipsec-secgw/ipsec.c             | 67 ++++++++++++++++++++++++
 examples/ipsec-secgw/ipsec.h             |  7 +++
 examples/ipsec-secgw/sa.c                | 61 +++++++++++++++++++--
 7 files changed, 185 insertions(+), 3 deletions(-)
diff --git a/doc/guides/rel_notes/release_20_05.rst b/doc/guides/rel_notes/release_20_05.rst
index 6b1a7c58c..a9ec163cf 100644
--- a/doc/guides/rel_notes/release_20_05.rst
+++ b/doc/guides/rel_notes/release_20_05.rst
@@ -81,6 +81,10 @@ New Features
   by making use of the event device capabilities. The event mode currently supports
   only inline IPsec protocol offload.
 
+* **Updated ipsec-secgw application.**
+
+  Added IPsec inbound load-distribution support for ipsec-secgw application using NIC
+  load distribution feature(Flow Director).
 
 Removed Items
 -------------
diff --git a/doc/guides/sample_app_ug/ipsec_secgw.rst b/doc/guides/sample_app_ug/ipsec_secgw.rst
index 038f593f4..12f921d76 100644
--- a/doc/guides/sample_app_ug/ipsec_secgw.rst
+++ b/doc/guides/sample_app_ug/ipsec_secgw.rst
@@ -506,6 +506,7 @@ The SA rule syntax is shown as follows:
 
     sa <dir> <spi> <cipher_algo> <cipher_key> <auth_algo> <auth_key>
     <mode> <src_ip> <dst_ip> <action_type> <port_id> <fallback>
+    <flow-direction> <port_id> <queue_id>
 
 where each options means:
 
@@ -698,6 +699,18 @@ where each options means:
 
    * *fallback lookaside-none*
 
+``<flow-direction>``
+
+ * Action type is for redirecting the specific inbound ipsec-flow to
+   a specified queue.
+
+ * Optional: Yes.
+
+ * Available options:
+
+   * *port_id*: Port ID of the NIC for which the SA is configured.
+   * *queue_id*: Queue ID to which traffic should be redirected.
+
 Example SA rules:
 
 .. code-block:: console
@@ -727,6 +740,9 @@ Example SA rules:
     mode ipv4-tunnel src 172.16.2.5 dst 172.16.1.5 \
     type inline-crypto-offload port_id 0
 
+    sa in 117 cipher_algo null auth_algo null mode ipv4-tunnel src 172.16.2.7 \
+    dst 172.16.1.7 flow-direction 0 2
+
 Routing rule syntax
 ^^^^^^^^^^^^^^^^^^^
 
diff --git a/examples/ipsec-secgw/ep0.cfg b/examples/ipsec-secgw/ep0.cfg
index dfd4aca7d..6f8d5aa53 100644
--- a/examples/ipsec-secgw/ep0.cfg
+++ b/examples/ipsec-secgw/ep0.cfg
@@ -29,6 +29,7 @@ sp ipv4 in esp protect 111 pri 1 dst 192.168.186.0/24 sport 0:65535 dport 0:6553
 sp ipv4 in esp protect 115 pri 1 dst 192.168.210.0/24 sport 0:65535 dport 0:65535
 sp ipv4 in esp protect 116 pri 1 dst 192.168.211.0/24 sport 0:65535 dport 0:65535
 sp ipv4 in esp protect 115 pri 1 dst 192.168.210.0/24 sport 0:65535 dport 0:65535
+sp ipv4 in esp protect 117 pri 1 dst 192.168.212.0/24 sport 0:65535 dport 0:65535
 sp ipv4 in esp protect 125 pri 1 dst 192.168.65.0/24 sport 0:65535 dport 0:65535
 sp ipv4 in esp protect 125 pri 1 dst 192.168.65.0/24 sport 0:65535 dport 0:65535
 sp ipv4 in esp protect 126 pri 1 dst 192.168.66.0/24 sport 0:65535 dport 0:65535
@@ -61,6 +62,8 @@ sp ipv6 in esp protect 125 pri 1 dst ffff:0000:0000:0000:aaaa:aaaa:0000:0000/96
 sport 0:65535 dport 0:65535
 sp ipv6 in esp protect 126 pri 1 dst ffff:0000:0000:0000:bbbb:bbbb:0000:0000/96 \
 sport 0:65535 dport 0:65535
+sp ipv6 in esp protect 127 pri 1 dst ffff:0000:0000:0000:cccc:dddd:0000:0000/96 \
+sport 0:65535 dport 0:65535
 
 #SA rules
 sa out 5 cipher_algo aes-128-cbc cipher_key 0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0 \
@@ -118,6 +121,9 @@ dst 172.16.1.5
 
 sa in 116 cipher_algo null auth_algo null mode ipv4-tunnel src 172.16.2.6 dst 172.16.1.6
 
+sa in 117 cipher_algo null auth_algo null mode ipv4-tunnel src 172.16.2.7 \
+dst 172.16.1.7 flow-direction 0 2
+
 sa in 125 cipher_algo aes-128-cbc cipher_key c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:\
 c3:c3:c3:c3:c3 auth_algo sha1-hmac auth_key c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:\
 c3:c3:c3:c3:c3:c3:c3:c3:c3 mode ipv6-tunnel \
@@ -130,6 +136,11 @@ sa in 126 cipher_algo aes-128-cbc cipher_key 4d:4d:4d:4d:4d:4d:4d:4d:4d:4d:4d:\
 src 2222:2222:2222:2222:2222:2222:2222:6666 \
 dst 1111:1111:1111:1111:1111:1111:1111:6666
 
+sa in 127 cipher_algo null auth_algo null mode ipv6-tunnel \
+src 2222:2222:2222:2222:2222:2222:2222:7777 \
+dst 1111:1111:1111:1111:1111:1111:1111:7777 \
+flow-direction 0 3
+
 #Routing rules
 rt ipv4 dst 172.16.2.5/32 port 0
 rt ipv4 dst 172.16.2.6/32 port 1
diff --git a/examples/ipsec-secgw/ipsec-secgw.c b/examples/ipsec-secgw/ipsec-secgw.c
index 5fde4f728..6d02341de 100644
--- a/examples/ipsec-secgw/ipsec-secgw.c
+++ b/examples/ipsec-secgw/ipsec-secgw.c
@@ -1183,6 +1183,28 @@ ipsec_poll_mode_worker(void)
 	}
 }
 
+int
+check_flow_params(uint16_t fdir_portid, uint8_t fdir_qid)
+{
+	uint16_t i;
+	uint16_t portid;
+	uint8_t queueid;
+
+	for (i = 0; i < nb_lcore_params; ++i) {
+		portid = lcore_params_array[i].port_id;
+		if (portid == fdir_portid) {
+			queueid = lcore_params_array[i].queue_id;
+			if (queueid == fdir_qid)
+				break;
+		}
+
+		if (i == nb_lcore_params - 1)
+			return -1;
+	}
+
+	return 1;
+}
+
 static int32_t
 check_poll_mode_params(struct eh_conf *eh_conf)
 {
diff --git a/examples/ipsec-secgw/ipsec.c b/examples/ipsec-secgw/ipsec.c
index d40657102..461fae461 100644
--- a/examples/ipsec-secgw/ipsec.c
+++ b/examples/ipsec-secgw/ipsec.c
@@ -418,6 +418,73 @@ create_inline_session(struct socket_ctx *skt_ctx, struct ipsec_sa *sa,
 	return 0;
 }
 
+int
+create_ipsec_esp_flow(struct ipsec_sa *sa)
+{
+	int ret = 0;
+	struct rte_flow_error err;
+	if (sa->direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS) {
+		RTE_LOG(ERR, IPSEC,
+			"No Flow director rule for Egress traffic\n");
+		return -1;
+	}
+	if (sa->flags == TRANSPORT) {
+		RTE_LOG(ERR, IPSEC,
+			"No Flow director rule for transport mode\n");
+		return -1;
+	}
+	sa->action[0].type = RTE_FLOW_ACTION_TYPE_QUEUE;
+	sa->pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
+	sa->action[0].conf =
+			&(struct rte_flow_action_queue){
+				.index = sa->fdir_qid,
+	};
+	sa->attr.egress = 0;
+	sa->attr.ingress = 1;
+	if (IS_IP6(sa->flags)) {
+		sa->pattern[1].mask = &rte_flow_item_ipv6_mask;
+		sa->pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV6;
+		sa->pattern[1].spec = &sa->ipv6_spec;
+		memcpy(sa->ipv6_spec.hdr.dst_addr,
+			sa->dst.ip.ip6.ip6_b, sizeof(sa->dst.ip.ip6.ip6_b));
+		memcpy(sa->ipv6_spec.hdr.src_addr,
+			sa->src.ip.ip6.ip6_b, sizeof(sa->src.ip.ip6.ip6_b));
+		sa->pattern[2].type = RTE_FLOW_ITEM_TYPE_ESP;
+		sa->pattern[2].spec = &sa->esp_spec;
+		sa->pattern[2].mask = &rte_flow_item_esp_mask;
+		sa->esp_spec.hdr.spi = rte_cpu_to_be_32(sa->spi);
+		sa->pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
+	} else if (IS_IP4(sa->flags)) {
+		sa->pattern[1].mask = &rte_flow_item_ipv4_mask;
+		sa->pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV4;
+		sa->pattern[1].spec = &sa->ipv4_spec;
+		sa->ipv4_spec.hdr.dst_addr = sa->dst.ip.ip4;
+		sa->ipv4_spec.hdr.src_addr = sa->src.ip.ip4;
+		sa->pattern[2].type = RTE_FLOW_ITEM_TYPE_ESP;
+		sa->pattern[2].spec = &sa->esp_spec;
+		sa->pattern[2].mask = &rte_flow_item_esp_mask;
+		sa->esp_spec.hdr.spi = rte_cpu_to_be_32(sa->spi);
+		sa->pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
+	}
+	sa->action[1].type = RTE_FLOW_ACTION_TYPE_END;
+
+	ret = rte_flow_validate(sa->portid, &sa->attr, sa->pattern, sa->action,
+				&err);
+	if (ret < 0) {
+		RTE_LOG(ERR, IPSEC, "Flow validation failed %s\n", err.message);
+		return ret;
+	}
+
+	sa->flow = rte_flow_create(sa->portid, &sa->attr, sa->pattern,
+					sa->action, &err);
+	if (!sa->flow) {
+		RTE_LOG(ERR, IPSEC, "Flow creation failed %s\n", err.message);
+		return -1;
+	}
+
+	return 0;
+}
+
 /*
  * queue crypto-ops into PMD queue.
  */
diff --git a/examples/ipsec-secgw/ipsec.h b/examples/ipsec-secgw/ipsec.h
index f8f29f9b1..1790a93ca 100644
--- a/examples/ipsec-secgw/ipsec.h
+++ b/examples/ipsec-secgw/ipsec.h
@@ -144,6 +144,8 @@ struct ipsec_sa {
 	};
 	enum rte_security_ipsec_sa_direction direction;
 	uint16_t portid;
+	uint8_t fdir_qid;
+	uint8_t fdir_flag;
 
 #define MAX_RTE_FLOW_PATTERN (4)
 #define MAX_RTE_FLOW_ACTIONS (3)
@@ -408,5 +410,10 @@ create_lookaside_session(struct ipsec_ctx *ipsec_ctx, struct ipsec_sa *sa,
 int
 create_inline_session(struct socket_ctx *skt_ctx, struct ipsec_sa *sa,
 		struct rte_ipsec_session *ips);
+int
+check_flow_params(uint16_t fdir_portid, uint8_t fdir_qid);
+
+int
+create_ipsec_esp_flow(struct ipsec_sa *sa);
 
 #endif /* __IPSEC_H__ */
diff --git a/examples/ipsec-secgw/sa.c b/examples/ipsec-secgw/sa.c
index a6bf5e8b1..7ed68fb93 100644
--- a/examples/ipsec-secgw/sa.c
+++ b/examples/ipsec-secgw/sa.c
@@ -271,6 +271,7 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	uint32_t type_p = 0;
 	uint32_t portid_p = 0;
 	uint32_t fallback_p = 0;
+	int16_t status_p = 0;
 
 	if (strcmp(tokens[0], "in") == 0) {
 		ri = &nb_sa_in;
@@ -295,6 +296,7 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	if (atoi(tokens[1]) == INVALID_SPI)
 		return;
 	rule->spi = atoi(tokens[1]);
+	rule->portid = UINT16_MAX;
 	ips = ipsec_get_primary_session(rule);
 
 	for (ti = 2; ti < n_tokens; ti++) {
@@ -636,9 +638,14 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
 			if (status->status < 0)
 				return;
-			rule->portid = atoi(tokens[ti]);
-			if (status->status < 0)
+			if (rule->portid == UINT16_MAX)
+				rule->portid = atoi(tokens[ti]);
+			else if (rule->portid != atoi(tokens[ti])) {
+				APP_CHECK(0, status, "portid %s not matching "
+					"with already assigned portid %u",
+					tokens[ti], rule->portid);
 				return;
+			}
 			portid_p = 1;
 			continue;
 		}
@@ -683,6 +690,44 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 			fallback_p = 1;
 			continue;
 		}
+		if (strcmp(tokens[ti], "flow-direction") == 0) {
+			if (ips->type ==
+				RTE_SECURITY_ACTION_TYPE_NONE ||
+				ips->type ==
+				RTE_SECURITY_ACTION_TYPE_CPU_CRYPTO) {
+				printf("flow director supported for security "
+					"session type:%d\n", ips->type);
+			} else {
+				APP_CHECK(0, status, "flow director not "
+					"supported for security session "
+					"type:%d", ips->type);
+				return;
+			}
+			rule->fdir_flag = 1;
+			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
+			if (status->status < 0)
+				return;
+			if (rule->portid == UINT16_MAX)
+				rule->portid = atoi(tokens[ti]);
+			else if (rule->portid != atoi(tokens[ti])) {
+				APP_CHECK(0, status, "portid %s "
+					"not matching with already assigned "
+					"portid %u", tokens[ti], rule->portid);
+				return;
+			}
+			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
+			if (status->status < 0)
+				return;
+			rule->fdir_qid = atoi(tokens[ti]);
+			/* validating portid and queueid */
+			status_p = check_flow_params(rule->portid,
+					rule->fdir_qid);
+			if (status_p < 0) {
+				printf("port id %u / queue id %u is not valid\n",
+					rule->portid, rule->fdir_qid);
+			}
+			continue;
+		}
 
 		/* unrecognizeable input */
 		APP_CHECK(0, status, "unrecognized input \"%s\"",
@@ -721,7 +766,6 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	if (!type_p || (!portid_p && ips->type !=
 			RTE_SECURITY_ACTION_TYPE_CPU_CRYPTO)) {
 		ips->type = RTE_SECURITY_ACTION_TYPE_NONE;
-		rule->portid = -1;
 	}
 
 	*ri = *ri + 1;
@@ -825,6 +869,10 @@ print_one_sa_rule(const struct ipsec_sa *sa, int inbound)
 			break;
 		}
 	}
+	if (sa->fdir_flag == 1)
+		printf("flow-direction port %d queue %d", sa->portid,
+				sa->fdir_qid);
+
 	printf("\n");
 }
 
@@ -1143,6 +1191,13 @@ sa_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
 			}
 		}
 
+		if (sa->fdir_flag && inbound) {
+			rc = create_ipsec_esp_flow(sa);
+			if (rc != 0)
+				RTE_LOG(ERR, IPSEC_ESP,
+					"create_ipsec_esp_flow() failed %s\n",
+					strerror(rc));
+		}
 		print_one_sa_rule(sa, inbound);
 	}
 
-- 
2.17.1

[dpdk-dev] [PATCH v5] examples/ipsec-secgw: support flow director feature

From: Praveen Shetty <hidden>
Date: 2020-04-09 10:19:18

Support load distribution in security gateway application using
NIC load distribution feature(Flow Director).
Flow Director is used to redirect the specified inbound ipsec flow
to a specified queue.This is achieved by extending the SA rule syntax
to support specification by adding new action_type of <flow-direction>
to a specified <port_id> <queue_id>.

Signed-off-by: Praveen Shetty <redacted>
---
v5 changes:
Small change in condtional handling in sa.c file.

v4 changes:
1. Removed flow director configuration changes as they are not 
   required anymore.
2. Addressed all the review comments from Akhil and Anoob.
3. Included update to the ipsec-secgw user guide and update to release notes.

 doc/guides/rel_notes/release_20_05.rst   |  4 ++
 doc/guides/sample_app_ug/ipsec_secgw.rst | 16 ++++++
 examples/ipsec-secgw/ep0.cfg             | 11 ++++
 examples/ipsec-secgw/ipsec-secgw.c       | 22 ++++++++
 examples/ipsec-secgw/ipsec.c             | 67 ++++++++++++++++++++++++
 examples/ipsec-secgw/ipsec.h             |  7 +++
 examples/ipsec-secgw/sa.c                | 63 ++++++++++++++++++++--
 7 files changed, 186 insertions(+), 4 deletions(-)
diff --git a/doc/guides/rel_notes/release_20_05.rst b/doc/guides/rel_notes/release_20_05.rst
index 6b1a7c58c..a9ec163cf 100644
--- a/doc/guides/rel_notes/release_20_05.rst
+++ b/doc/guides/rel_notes/release_20_05.rst
@@ -81,6 +81,10 @@ New Features
   by making use of the event device capabilities. The event mode currently supports
   only inline IPsec protocol offload.
 
+* **Updated ipsec-secgw application.**
+
+  Added IPsec inbound load-distribution support for ipsec-secgw application using NIC
+  load distribution feature(Flow Director).
 
 Removed Items
 -------------
diff --git a/doc/guides/sample_app_ug/ipsec_secgw.rst b/doc/guides/sample_app_ug/ipsec_secgw.rst
index 038f593f4..12f921d76 100644
--- a/doc/guides/sample_app_ug/ipsec_secgw.rst
+++ b/doc/guides/sample_app_ug/ipsec_secgw.rst
@@ -506,6 +506,7 @@ The SA rule syntax is shown as follows:
 
     sa <dir> <spi> <cipher_algo> <cipher_key> <auth_algo> <auth_key>
     <mode> <src_ip> <dst_ip> <action_type> <port_id> <fallback>
+    <flow-direction> <port_id> <queue_id>
 
 where each options means:
 
@@ -698,6 +699,18 @@ where each options means:
 
    * *fallback lookaside-none*
 
+``<flow-direction>``
+
+ * Action type is for redirecting the specific inbound ipsec-flow to
+   a specified queue.
+
+ * Optional: Yes.
+
+ * Available options:
+
+   * *port_id*: Port ID of the NIC for which the SA is configured.
+   * *queue_id*: Queue ID to which traffic should be redirected.
+
 Example SA rules:
 
 .. code-block:: console
@@ -727,6 +740,9 @@ Example SA rules:
     mode ipv4-tunnel src 172.16.2.5 dst 172.16.1.5 \
     type inline-crypto-offload port_id 0
 
+    sa in 117 cipher_algo null auth_algo null mode ipv4-tunnel src 172.16.2.7 \
+    dst 172.16.1.7 flow-direction 0 2
+
 Routing rule syntax
 ^^^^^^^^^^^^^^^^^^^
 
diff --git a/examples/ipsec-secgw/ep0.cfg b/examples/ipsec-secgw/ep0.cfg
index dfd4aca7d..6f8d5aa53 100644
--- a/examples/ipsec-secgw/ep0.cfg
+++ b/examples/ipsec-secgw/ep0.cfg
@@ -29,6 +29,7 @@ sp ipv4 in esp protect 111 pri 1 dst 192.168.186.0/24 sport 0:65535 dport 0:6553
 sp ipv4 in esp protect 115 pri 1 dst 192.168.210.0/24 sport 0:65535 dport 0:65535
 sp ipv4 in esp protect 116 pri 1 dst 192.168.211.0/24 sport 0:65535 dport 0:65535
 sp ipv4 in esp protect 115 pri 1 dst 192.168.210.0/24 sport 0:65535 dport 0:65535
+sp ipv4 in esp protect 117 pri 1 dst 192.168.212.0/24 sport 0:65535 dport 0:65535
 sp ipv4 in esp protect 125 pri 1 dst 192.168.65.0/24 sport 0:65535 dport 0:65535
 sp ipv4 in esp protect 125 pri 1 dst 192.168.65.0/24 sport 0:65535 dport 0:65535
 sp ipv4 in esp protect 126 pri 1 dst 192.168.66.0/24 sport 0:65535 dport 0:65535
@@ -61,6 +62,8 @@ sp ipv6 in esp protect 125 pri 1 dst ffff:0000:0000:0000:aaaa:aaaa:0000:0000/96
 sport 0:65535 dport 0:65535
 sp ipv6 in esp protect 126 pri 1 dst ffff:0000:0000:0000:bbbb:bbbb:0000:0000/96 \
 sport 0:65535 dport 0:65535
+sp ipv6 in esp protect 127 pri 1 dst ffff:0000:0000:0000:cccc:dddd:0000:0000/96 \
+sport 0:65535 dport 0:65535
 
 #SA rules
 sa out 5 cipher_algo aes-128-cbc cipher_key 0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0 \
@@ -118,6 +121,9 @@ dst 172.16.1.5
 
 sa in 116 cipher_algo null auth_algo null mode ipv4-tunnel src 172.16.2.6 dst 172.16.1.6
 
+sa in 117 cipher_algo null auth_algo null mode ipv4-tunnel src 172.16.2.7 \
+dst 172.16.1.7 flow-direction 0 2
+
 sa in 125 cipher_algo aes-128-cbc cipher_key c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:\
 c3:c3:c3:c3:c3 auth_algo sha1-hmac auth_key c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:\
 c3:c3:c3:c3:c3:c3:c3:c3:c3 mode ipv6-tunnel \
@@ -130,6 +136,11 @@ sa in 126 cipher_algo aes-128-cbc cipher_key 4d:4d:4d:4d:4d:4d:4d:4d:4d:4d:4d:\
 src 2222:2222:2222:2222:2222:2222:2222:6666 \
 dst 1111:1111:1111:1111:1111:1111:1111:6666
 
+sa in 127 cipher_algo null auth_algo null mode ipv6-tunnel \
+src 2222:2222:2222:2222:2222:2222:2222:7777 \
+dst 1111:1111:1111:1111:1111:1111:1111:7777 \
+flow-direction 0 3
+
 #Routing rules
 rt ipv4 dst 172.16.2.5/32 port 0
 rt ipv4 dst 172.16.2.6/32 port 1
diff --git a/examples/ipsec-secgw/ipsec-secgw.c b/examples/ipsec-secgw/ipsec-secgw.c
index 5fde4f728..6d02341de 100644
--- a/examples/ipsec-secgw/ipsec-secgw.c
+++ b/examples/ipsec-secgw/ipsec-secgw.c
@@ -1183,6 +1183,28 @@ ipsec_poll_mode_worker(void)
 	}
 }
 
+int
+check_flow_params(uint16_t fdir_portid, uint8_t fdir_qid)
+{
+	uint16_t i;
+	uint16_t portid;
+	uint8_t queueid;
+
+	for (i = 0; i < nb_lcore_params; ++i) {
+		portid = lcore_params_array[i].port_id;
+		if (portid == fdir_portid) {
+			queueid = lcore_params_array[i].queue_id;
+			if (queueid == fdir_qid)
+				break;
+		}
+
+		if (i == nb_lcore_params - 1)
+			return -1;
+	}
+
+	return 1;
+}
+
 static int32_t
 check_poll_mode_params(struct eh_conf *eh_conf)
 {
diff --git a/examples/ipsec-secgw/ipsec.c b/examples/ipsec-secgw/ipsec.c
index d40657102..461fae461 100644
--- a/examples/ipsec-secgw/ipsec.c
+++ b/examples/ipsec-secgw/ipsec.c
@@ -418,6 +418,73 @@ create_inline_session(struct socket_ctx *skt_ctx, struct ipsec_sa *sa,
 	return 0;
 }
 
+int
+create_ipsec_esp_flow(struct ipsec_sa *sa)
+{
+	int ret = 0;
+	struct rte_flow_error err;
+	if (sa->direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS) {
+		RTE_LOG(ERR, IPSEC,
+			"No Flow director rule for Egress traffic\n");
+		return -1;
+	}
+	if (sa->flags == TRANSPORT) {
+		RTE_LOG(ERR, IPSEC,
+			"No Flow director rule for transport mode\n");
+		return -1;
+	}
+	sa->action[0].type = RTE_FLOW_ACTION_TYPE_QUEUE;
+	sa->pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
+	sa->action[0].conf =
+			&(struct rte_flow_action_queue){
+				.index = sa->fdir_qid,
+	};
+	sa->attr.egress = 0;
+	sa->attr.ingress = 1;
+	if (IS_IP6(sa->flags)) {
+		sa->pattern[1].mask = &rte_flow_item_ipv6_mask;
+		sa->pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV6;
+		sa->pattern[1].spec = &sa->ipv6_spec;
+		memcpy(sa->ipv6_spec.hdr.dst_addr,
+			sa->dst.ip.ip6.ip6_b, sizeof(sa->dst.ip.ip6.ip6_b));
+		memcpy(sa->ipv6_spec.hdr.src_addr,
+			sa->src.ip.ip6.ip6_b, sizeof(sa->src.ip.ip6.ip6_b));
+		sa->pattern[2].type = RTE_FLOW_ITEM_TYPE_ESP;
+		sa->pattern[2].spec = &sa->esp_spec;
+		sa->pattern[2].mask = &rte_flow_item_esp_mask;
+		sa->esp_spec.hdr.spi = rte_cpu_to_be_32(sa->spi);
+		sa->pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
+	} else if (IS_IP4(sa->flags)) {
+		sa->pattern[1].mask = &rte_flow_item_ipv4_mask;
+		sa->pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV4;
+		sa->pattern[1].spec = &sa->ipv4_spec;
+		sa->ipv4_spec.hdr.dst_addr = sa->dst.ip.ip4;
+		sa->ipv4_spec.hdr.src_addr = sa->src.ip.ip4;
+		sa->pattern[2].type = RTE_FLOW_ITEM_TYPE_ESP;
+		sa->pattern[2].spec = &sa->esp_spec;
+		sa->pattern[2].mask = &rte_flow_item_esp_mask;
+		sa->esp_spec.hdr.spi = rte_cpu_to_be_32(sa->spi);
+		sa->pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
+	}
+	sa->action[1].type = RTE_FLOW_ACTION_TYPE_END;
+
+	ret = rte_flow_validate(sa->portid, &sa->attr, sa->pattern, sa->action,
+				&err);
+	if (ret < 0) {
+		RTE_LOG(ERR, IPSEC, "Flow validation failed %s\n", err.message);
+		return ret;
+	}
+
+	sa->flow = rte_flow_create(sa->portid, &sa->attr, sa->pattern,
+					sa->action, &err);
+	if (!sa->flow) {
+		RTE_LOG(ERR, IPSEC, "Flow creation failed %s\n", err.message);
+		return -1;
+	}
+
+	return 0;
+}
+
 /*
  * queue crypto-ops into PMD queue.
  */
diff --git a/examples/ipsec-secgw/ipsec.h b/examples/ipsec-secgw/ipsec.h
index f8f29f9b1..1790a93ca 100644
--- a/examples/ipsec-secgw/ipsec.h
+++ b/examples/ipsec-secgw/ipsec.h
@@ -144,6 +144,8 @@ struct ipsec_sa {
 	};
 	enum rte_security_ipsec_sa_direction direction;
 	uint16_t portid;
+	uint8_t fdir_qid;
+	uint8_t fdir_flag;
 
 #define MAX_RTE_FLOW_PATTERN (4)
 #define MAX_RTE_FLOW_ACTIONS (3)
@@ -408,5 +410,10 @@ create_lookaside_session(struct ipsec_ctx *ipsec_ctx, struct ipsec_sa *sa,
 int
 create_inline_session(struct socket_ctx *skt_ctx, struct ipsec_sa *sa,
 		struct rte_ipsec_session *ips);
+int
+check_flow_params(uint16_t fdir_portid, uint8_t fdir_qid);
+
+int
+create_ipsec_esp_flow(struct ipsec_sa *sa);
 
 #endif /* __IPSEC_H__ */
diff --git a/examples/ipsec-secgw/sa.c b/examples/ipsec-secgw/sa.c
index a6bf5e8b1..06bb25b3e 100644
--- a/examples/ipsec-secgw/sa.c
+++ b/examples/ipsec-secgw/sa.c
@@ -271,6 +271,7 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	uint32_t type_p = 0;
 	uint32_t portid_p = 0;
 	uint32_t fallback_p = 0;
+	int16_t status_p = 0;
 
 	if (strcmp(tokens[0], "in") == 0) {
 		ri = &nb_sa_in;
@@ -295,6 +296,7 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	if (atoi(tokens[1]) == INVALID_SPI)
 		return;
 	rule->spi = atoi(tokens[1]);
+	rule->portid = UINT16_MAX;
 	ips = ipsec_get_primary_session(rule);
 
 	for (ti = 2; ti < n_tokens; ti++) {
@@ -636,9 +638,14 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
 			if (status->status < 0)
 				return;
-			rule->portid = atoi(tokens[ti]);
-			if (status->status < 0)
+			if (rule->portid == UINT16_MAX)
+				rule->portid = atoi(tokens[ti]);
+			else if (rule->portid != atoi(tokens[ti])) {
+				APP_CHECK(0, status, "portid %s not matching "
+					"with already assigned portid %u",
+					tokens[ti], rule->portid);
 				return;
+			}
 			portid_p = 1;
 			continue;
 		}
@@ -683,6 +690,44 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 			fallback_p = 1;
 			continue;
 		}
+		if (strcmp(tokens[ti], "flow-direction") == 0) {
+			if (ips->type ==
+				RTE_SECURITY_ACTION_TYPE_NONE ||
+				ips->type ==
+				RTE_SECURITY_ACTION_TYPE_CPU_CRYPTO) {
+				rule->fdir_flag = 1;
+				INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
+				if (status->status < 0)
+					return;
+				if (rule->portid == UINT16_MAX)
+					rule->portid = atoi(tokens[ti]);
+				else if (rule->portid != atoi(tokens[ti])) {
+					APP_CHECK(0, status, "portid %s "
+						"not matching with already "
+						"assigned portid %u",
+						tokens[ti], rule->portid);
+					return;
+				}
+				INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
+				if (status->status < 0)
+					return;
+				rule->fdir_qid = atoi(tokens[ti]);
+				/* validating portid and queueid */
+				status_p = check_flow_params(rule->portid,
+						rule->fdir_qid);
+				if (status_p < 0) {
+					printf("port id %u / queue id %u is "
+						"not valid\n", rule->portid,
+						 rule->fdir_qid);
+				}
+			} else {
+				APP_CHECK(0, status, "flow director not "
+					"supported for security session "
+					"type:%d", ips->type);
+				return;
+			}
+			continue;
+		}
 
 		/* unrecognizeable input */
 		APP_CHECK(0, status, "unrecognized input \"%s\"",
@@ -721,7 +766,6 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	if (!type_p || (!portid_p && ips->type !=
 			RTE_SECURITY_ACTION_TYPE_CPU_CRYPTO)) {
 		ips->type = RTE_SECURITY_ACTION_TYPE_NONE;
-		rule->portid = -1;
 	}
 
 	*ri = *ri + 1;
@@ -806,7 +850,7 @@ print_one_sa_rule(const struct ipsec_sa *sa, int inbound)
 		printf("lookaside-protocol-offload ");
 		break;
 	case RTE_SECURITY_ACTION_TYPE_CPU_CRYPTO:
-		printf("cpu-crypto-accelerated");
+		printf("cpu-crypto-accelerated ");
 		break;
 	}
 
@@ -825,6 +869,10 @@ print_one_sa_rule(const struct ipsec_sa *sa, int inbound)
 			break;
 		}
 	}
+	if (sa->fdir_flag == 1)
+		printf("flow-direction port %d queue %d", sa->portid,
+				sa->fdir_qid);
+
 	printf("\n");
 }
 
@@ -1143,6 +1191,13 @@ sa_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
 			}
 		}
 
+		if (sa->fdir_flag && inbound) {
+			rc = create_ipsec_esp_flow(sa);
+			if (rc != 0)
+				RTE_LOG(ERR, IPSEC_ESP,
+					"create_ipsec_esp_flow() failed %s\n",
+					strerror(rc));
+		}
 		print_one_sa_rule(sa, inbound);
 	}
 
-- 
2.17.1

Re: [dpdk-dev] [PATCH v5] examples/ipsec-secgw: support flow director feature

From: Shetty, Praveen <hidden>
Date: 2020-04-14 07:33:54

Hi Akhil/Anoob

Do you have any further review comments ?

Regards,
Praveen

-----Original Message-----
From: dev <redacted> On Behalf Of Praveen Shetty
Sent: Thursday, April 9, 2020 3:40 PM
To: dev@dpdk.org; Doherty, Declan <redacted>; akhil.goyal@nxp.com; anoobj@marvell.com
Cc: Iremonger, Bernard <redacted>; Ananyev, Konstantin <redacted>
Subject: [dpdk-dev] [PATCH v5] examples/ipsec-secgw: support flow director feature

Support load distribution in security gateway application using NIC load distribution feature(Flow Director).
Flow Director is used to redirect the specified inbound ipsec flow to a specified queue.This is achieved by extending the SA rule syntax to support specification by adding new action_type of <flow-direction> to a specified <port_id> <queue_id>.

Signed-off-by: Praveen Shetty <redacted>
---
v5 changes:
Small change in condtional handling in sa.c file.

v4 changes:
1. Removed flow director configuration changes as they are not 
   required anymore.
2. Addressed all the review comments from Akhil and Anoob.
3. Included update to the ipsec-secgw user guide and update to release notes.

 doc/guides/rel_notes/release_20_05.rst   |  4 ++
 doc/guides/sample_app_ug/ipsec_secgw.rst | 16 ++++++
 examples/ipsec-secgw/ep0.cfg             | 11 ++++
 examples/ipsec-secgw/ipsec-secgw.c       | 22 ++++++++
 examples/ipsec-secgw/ipsec.c             | 67 ++++++++++++++++++++++++
 examples/ipsec-secgw/ipsec.h             |  7 +++
 examples/ipsec-secgw/sa.c                | 63 ++++++++++++++++++++--
 7 files changed, 186 insertions(+), 4 deletions(-)
diff --git a/doc/guides/rel_notes/release_20_05.rst b/doc/guides/rel_notes/release_20_05.rst
index 6b1a7c58c..a9ec163cf 100644
--- a/doc/guides/rel_notes/release_20_05.rst
+++ b/doc/guides/rel_notes/release_20_05.rst
@@ -81,6 +81,10 @@ New Features
   by making use of the event device capabilities. The event mode currently supports
   only inline IPsec protocol offload.
 
+* **Updated ipsec-secgw application.**
+
+  Added IPsec inbound load-distribution support for ipsec-secgw 
+ application using NIC  load distribution feature(Flow Director).
 
 Removed Items
 -------------
diff --git a/doc/guides/sample_app_ug/ipsec_secgw.rst b/doc/guides/sample_app_ug/ipsec_secgw.rst
index 038f593f4..12f921d76 100644
--- a/doc/guides/sample_app_ug/ipsec_secgw.rst
+++ b/doc/guides/sample_app_ug/ipsec_secgw.rst
@@ -506,6 +506,7 @@ The SA rule syntax is shown as follows:
 
     sa <dir> <spi> <cipher_algo> <cipher_key> <auth_algo> <auth_key>
     <mode> <src_ip> <dst_ip> <action_type> <port_id> <fallback>
+    <flow-direction> <port_id> <queue_id>
 
 where each options means:
 
@@ -698,6 +699,18 @@ where each options means:
 
    * *fallback lookaside-none*
 
+``<flow-direction>``
+
+ * Action type is for redirecting the specific inbound ipsec-flow to
+   a specified queue.
+
+ * Optional: Yes.
+
+ * Available options:
+
+   * *port_id*: Port ID of the NIC for which the SA is configured.
+   * *queue_id*: Queue ID to which traffic should be redirected.
+
 Example SA rules:
 
 .. code-block:: console
@@ -727,6 +740,9 @@ Example SA rules:
     mode ipv4-tunnel src 172.16.2.5 dst 172.16.1.5 \
     type inline-crypto-offload port_id 0
 
+    sa in 117 cipher_algo null auth_algo null mode ipv4-tunnel src 172.16.2.7 \
+    dst 172.16.1.7 flow-direction 0 2
+
 Routing rule syntax
 ^^^^^^^^^^^^^^^^^^^
 
diff --git a/examples/ipsec-secgw/ep0.cfg b/examples/ipsec-secgw/ep0.cfg index dfd4aca7d..6f8d5aa53 100644
--- a/examples/ipsec-secgw/ep0.cfg
+++ b/examples/ipsec-secgw/ep0.cfg
@@ -29,6 +29,7 @@ sp ipv4 in esp protect 111 pri 1 dst 192.168.186.0/24 sport 0:65535 dport 0:6553  sp ipv4 in esp protect 115 pri 1 dst 192.168.210.0/24 sport 0:65535 dport 0:65535  sp ipv4 in esp protect 116 pri 1 dst 192.168.211.0/24 sport 0:65535 dport 0:65535  sp ipv4 in esp protect 115 pri 1 dst 192.168.210.0/24 sport 0:65535 dport 0:65535
+sp ipv4 in esp protect 117 pri 1 dst 192.168.212.0/24 sport 0:65535 
+dport 0:65535
 sp ipv4 in esp protect 125 pri 1 dst 192.168.65.0/24 sport 0:65535 dport 0:65535  sp ipv4 in esp protect 125 pri 1 dst 192.168.65.0/24 sport 0:65535 dport 0:65535  sp ipv4 in esp protect 126 pri 1 dst 192.168.66.0/24 sport 0:65535 dport 0:65535 @@ -61,6 +62,8 @@ sp ipv6 in esp protect 125 pri 1 dst ffff:0000:0000:0000:aaaa:aaaa:0000:0000/96
 sport 0:65535 dport 0:65535
 sp ipv6 in esp protect 126 pri 1 dst ffff:0000:0000:0000:bbbb:bbbb:0000:0000/96 \  sport 0:65535 dport 0:65535
+sp ipv6 in esp protect 127 pri 1 dst 
+ffff:0000:0000:0000:cccc:dddd:0000:0000/96 \ sport 0:65535 dport 
+0:65535
 
 #SA rules
 sa out 5 cipher_algo aes-128-cbc cipher_key 0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0 \ @@ -118,6 +121,9 @@ dst 172.16.1.5
 
 sa in 116 cipher_algo null auth_algo null mode ipv4-tunnel src 172.16.2.6 dst 172.16.1.6
 
+sa in 117 cipher_algo null auth_algo null mode ipv4-tunnel src 
+172.16.2.7 \ dst 172.16.1.7 flow-direction 0 2
+
 sa in 125 cipher_algo aes-128-cbc cipher_key c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:\
 c3:c3:c3:c3:c3 auth_algo sha1-hmac auth_key c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:\
 c3:c3:c3:c3:c3:c3:c3:c3:c3 mode ipv6-tunnel \ @@ -130,6 +136,11 @@ sa in 126 cipher_algo aes-128-cbc cipher_key 4d:4d:4d:4d:4d:4d:4d:4d:4d:4d:4d:\
 src 2222:2222:2222:2222:2222:2222:2222:6666 \  dst 1111:1111:1111:1111:1111:1111:1111:6666
 
+sa in 127 cipher_algo null auth_algo null mode ipv6-tunnel \ src 
+2222:2222:2222:2222:2222:2222:2222:7777 \ dst 
+1111:1111:1111:1111:1111:1111:1111:7777 \ flow-direction 0 3
+
 #Routing rules
 rt ipv4 dst 172.16.2.5/32 port 0
 rt ipv4 dst 172.16.2.6/32 port 1
diff --git a/examples/ipsec-secgw/ipsec-secgw.c b/examples/ipsec-secgw/ipsec-secgw.c
index 5fde4f728..6d02341de 100644
--- a/examples/ipsec-secgw/ipsec-secgw.c
+++ b/examples/ipsec-secgw/ipsec-secgw.c
@@ -1183,6 +1183,28 @@ ipsec_poll_mode_worker(void)
 	}
 }
 
+int
+check_flow_params(uint16_t fdir_portid, uint8_t fdir_qid) {
+	uint16_t i;
+	uint16_t portid;
+	uint8_t queueid;
+
+	for (i = 0; i < nb_lcore_params; ++i) {
+		portid = lcore_params_array[i].port_id;
+		if (portid == fdir_portid) {
+			queueid = lcore_params_array[i].queue_id;
+			if (queueid == fdir_qid)
+				break;
+		}
+
+		if (i == nb_lcore_params - 1)
+			return -1;
+	}
+
+	return 1;
+}
+
 static int32_t
 check_poll_mode_params(struct eh_conf *eh_conf)  { diff --git a/examples/ipsec-secgw/ipsec.c b/examples/ipsec-secgw/ipsec.c index d40657102..461fae461 100644
--- a/examples/ipsec-secgw/ipsec.c
+++ b/examples/ipsec-secgw/ipsec.c
@@ -418,6 +418,73 @@ create_inline_session(struct socket_ctx *skt_ctx, struct ipsec_sa *sa,
 	return 0;
 }
 
+int
+create_ipsec_esp_flow(struct ipsec_sa *sa) {
+	int ret = 0;
+	struct rte_flow_error err;
+	if (sa->direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS) {
+		RTE_LOG(ERR, IPSEC,
+			"No Flow director rule for Egress traffic\n");
+		return -1;
+	}
+	if (sa->flags == TRANSPORT) {
+		RTE_LOG(ERR, IPSEC,
+			"No Flow director rule for transport mode\n");
+		return -1;
+	}
+	sa->action[0].type = RTE_FLOW_ACTION_TYPE_QUEUE;
+	sa->pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
+	sa->action[0].conf =
+			&(struct rte_flow_action_queue){
+				.index = sa->fdir_qid,
+	};
+	sa->attr.egress = 0;
+	sa->attr.ingress = 1;
+	if (IS_IP6(sa->flags)) {
+		sa->pattern[1].mask = &rte_flow_item_ipv6_mask;
+		sa->pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV6;
+		sa->pattern[1].spec = &sa->ipv6_spec;
+		memcpy(sa->ipv6_spec.hdr.dst_addr,
+			sa->dst.ip.ip6.ip6_b, sizeof(sa->dst.ip.ip6.ip6_b));
+		memcpy(sa->ipv6_spec.hdr.src_addr,
+			sa->src.ip.ip6.ip6_b, sizeof(sa->src.ip.ip6.ip6_b));
+		sa->pattern[2].type = RTE_FLOW_ITEM_TYPE_ESP;
+		sa->pattern[2].spec = &sa->esp_spec;
+		sa->pattern[2].mask = &rte_flow_item_esp_mask;
+		sa->esp_spec.hdr.spi = rte_cpu_to_be_32(sa->spi);
+		sa->pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
+	} else if (IS_IP4(sa->flags)) {
+		sa->pattern[1].mask = &rte_flow_item_ipv4_mask;
+		sa->pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV4;
+		sa->pattern[1].spec = &sa->ipv4_spec;
+		sa->ipv4_spec.hdr.dst_addr = sa->dst.ip.ip4;
+		sa->ipv4_spec.hdr.src_addr = sa->src.ip.ip4;
+		sa->pattern[2].type = RTE_FLOW_ITEM_TYPE_ESP;
+		sa->pattern[2].spec = &sa->esp_spec;
+		sa->pattern[2].mask = &rte_flow_item_esp_mask;
+		sa->esp_spec.hdr.spi = rte_cpu_to_be_32(sa->spi);
+		sa->pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
+	}
+	sa->action[1].type = RTE_FLOW_ACTION_TYPE_END;
+
+	ret = rte_flow_validate(sa->portid, &sa->attr, sa->pattern, sa->action,
+				&err);
+	if (ret < 0) {
+		RTE_LOG(ERR, IPSEC, "Flow validation failed %s\n", err.message);
+		return ret;
+	}
+
+	sa->flow = rte_flow_create(sa->portid, &sa->attr, sa->pattern,
+					sa->action, &err);
+	if (!sa->flow) {
+		RTE_LOG(ERR, IPSEC, "Flow creation failed %s\n", err.message);
+		return -1;
+	}
+
+	return 0;
+}
+
 /*
  * queue crypto-ops into PMD queue.
  */
diff --git a/examples/ipsec-secgw/ipsec.h b/examples/ipsec-secgw/ipsec.h index f8f29f9b1..1790a93ca 100644
--- a/examples/ipsec-secgw/ipsec.h
+++ b/examples/ipsec-secgw/ipsec.h
@@ -144,6 +144,8 @@ struct ipsec_sa {
 	};
 	enum rte_security_ipsec_sa_direction direction;
 	uint16_t portid;
+	uint8_t fdir_qid;
+	uint8_t fdir_flag;
 
 #define MAX_RTE_FLOW_PATTERN (4)
 #define MAX_RTE_FLOW_ACTIONS (3)
@@ -408,5 +410,10 @@ create_lookaside_session(struct ipsec_ctx *ipsec_ctx, struct ipsec_sa *sa,  int  create_inline_session(struct socket_ctx *skt_ctx, struct ipsec_sa *sa,
 		struct rte_ipsec_session *ips);
+int
+check_flow_params(uint16_t fdir_portid, uint8_t fdir_qid);
+
+int
+create_ipsec_esp_flow(struct ipsec_sa *sa);
 
 #endif /* __IPSEC_H__ */
diff --git a/examples/ipsec-secgw/sa.c b/examples/ipsec-secgw/sa.c index a6bf5e8b1..06bb25b3e 100644
--- a/examples/ipsec-secgw/sa.c
+++ b/examples/ipsec-secgw/sa.c
@@ -271,6 +271,7 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	uint32_t type_p = 0;
 	uint32_t portid_p = 0;
 	uint32_t fallback_p = 0;
+	int16_t status_p = 0;
 
 	if (strcmp(tokens[0], "in") == 0) {
 		ri = &nb_sa_in;
@@ -295,6 +296,7 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	if (atoi(tokens[1]) == INVALID_SPI)
 		return;
 	rule->spi = atoi(tokens[1]);
+	rule->portid = UINT16_MAX;
 	ips = ipsec_get_primary_session(rule);
 
 	for (ti = 2; ti < n_tokens; ti++) {
@@ -636,9 +638,14 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
 			if (status->status < 0)
 				return;
-			rule->portid = atoi(tokens[ti]);
-			if (status->status < 0)
+			if (rule->portid == UINT16_MAX)
+				rule->portid = atoi(tokens[ti]);
+			else if (rule->portid != atoi(tokens[ti])) {
+				APP_CHECK(0, status, "portid %s not matching "
+					"with already assigned portid %u",
+					tokens[ti], rule->portid);
 				return;
+			}
 			portid_p = 1;
 			continue;
 		}
@@ -683,6 +690,44 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 			fallback_p = 1;
 			continue;
 		}
+		if (strcmp(tokens[ti], "flow-direction") == 0) {
+			if (ips->type ==
+				RTE_SECURITY_ACTION_TYPE_NONE ||
+				ips->type ==
+				RTE_SECURITY_ACTION_TYPE_CPU_CRYPTO) {
+				rule->fdir_flag = 1;
+				INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
+				if (status->status < 0)
+					return;
+				if (rule->portid == UINT16_MAX)
+					rule->portid = atoi(tokens[ti]);
+				else if (rule->portid != atoi(tokens[ti])) {
+					APP_CHECK(0, status, "portid %s "
+						"not matching with already "
+						"assigned portid %u",
+						tokens[ti], rule->portid);
+					return;
+				}
+				INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
+				if (status->status < 0)
+					return;
+				rule->fdir_qid = atoi(tokens[ti]);
+				/* validating portid and queueid */
+				status_p = check_flow_params(rule->portid,
+						rule->fdir_qid);
+				if (status_p < 0) {
+					printf("port id %u / queue id %u is "
+						"not valid\n", rule->portid,
+						 rule->fdir_qid);
+				}
+			} else {
+				APP_CHECK(0, status, "flow director not "
+					"supported for security session "
+					"type:%d", ips->type);
+				return;
+			}
+			continue;
+		}
 
 		/* unrecognizeable input */
 		APP_CHECK(0, status, "unrecognized input \"%s\"", @@ -721,7 +766,6 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	if (!type_p || (!portid_p && ips->type !=
 			RTE_SECURITY_ACTION_TYPE_CPU_CRYPTO)) {
 		ips->type = RTE_SECURITY_ACTION_TYPE_NONE;
-		rule->portid = -1;
 	}
 
 	*ri = *ri + 1;
@@ -806,7 +850,7 @@ print_one_sa_rule(const struct ipsec_sa *sa, int inbound)
 		printf("lookaside-protocol-offload ");
 		break;
 	case RTE_SECURITY_ACTION_TYPE_CPU_CRYPTO:
-		printf("cpu-crypto-accelerated");
+		printf("cpu-crypto-accelerated ");
 		break;
 	}
 
@@ -825,6 +869,10 @@ print_one_sa_rule(const struct ipsec_sa *sa, int inbound)
 			break;
 		}
 	}
+	if (sa->fdir_flag == 1)
+		printf("flow-direction port %d queue %d", sa->portid,
+				sa->fdir_qid);
+
 	printf("\n");
 }
 
@@ -1143,6 +1191,13 @@ sa_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
 			}
 		}
 
+		if (sa->fdir_flag && inbound) {
+			rc = create_ipsec_esp_flow(sa);
+			if (rc != 0)
+				RTE_LOG(ERR, IPSEC_ESP,
+					"create_ipsec_esp_flow() failed %s\n",
+					strerror(rc));
+		}
 		print_one_sa_rule(sa, inbound);
 	}
 
--
2.17.1

Re: [dpdk-dev] [PATCH v5] examples/ipsec-secgw: support flow director feature

From: Akhil Goyal <hidden>
Date: 2020-04-15 19:00:00

Hi Praveen,
Support load distribution in security gateway application using
NIC load distribution feature(Flow Director).
Flow Director is used to redirect the specified inbound ipsec flow
to a specified queue.This is achieved by extending the SA rule syntax
to support specification by adding new action_type of <flow-direction>
to a specified <port_id> <queue_id>.

Signed-off-by: Praveen Shetty <redacted>
Please fix a few minor comments below.

Apart from that,
Acked-by: Akhil Goyal <redacted>
quoted hunk
---
v5 changes:
Small change in condtional handling in sa.c file.

v4 changes:
1. Removed flow director configuration changes as they are not
   required anymore.
2. Addressed all the review comments from Akhil and Anoob.
3. Included update to the ipsec-secgw user guide and update to release notes.

 doc/guides/rel_notes/release_20_05.rst   |  4 ++
 doc/guides/sample_app_ug/ipsec_secgw.rst | 16 ++++++
 examples/ipsec-secgw/ep0.cfg             | 11 ++++
 examples/ipsec-secgw/ipsec-secgw.c       | 22 ++++++++
 examples/ipsec-secgw/ipsec.c             | 67 ++++++++++++++++++++++++
 examples/ipsec-secgw/ipsec.h             |  7 +++
 examples/ipsec-secgw/sa.c                | 63 ++++++++++++++++++++--
 7 files changed, 186 insertions(+), 4 deletions(-)
diff --git a/doc/guides/rel_notes/release_20_05.rst
b/doc/guides/rel_notes/release_20_05.rst
index 6b1a7c58c..a9ec163cf 100644
--- a/doc/guides/rel_notes/release_20_05.rst
+++ b/doc/guides/rel_notes/release_20_05.rst
@@ -81,6 +81,10 @@ New Features
   by making use of the event device capabilities. The event mode currently
supports
   only inline IPsec protocol offload.

+* **Updated ipsec-secgw application.**
+
+  Added IPsec inbound load-distribution support for ipsec-secgw application
using NIC
+  load distribution feature(Flow Director).
There is one more item in release notes for ipsec-secgw for event mode.
You should add a bullet in that for this feature.
quoted hunk
 Removed Items
 -------------
diff --git a/doc/guides/sample_app_ug/ipsec_secgw.rst
b/doc/guides/sample_app_ug/ipsec_secgw.rst
index 038f593f4..12f921d76 100644
--- a/doc/guides/sample_app_ug/ipsec_secgw.rst
+++ b/doc/guides/sample_app_ug/ipsec_secgw.rst
@@ -506,6 +506,7 @@ The SA rule syntax is shown as follows:

     sa <dir> <spi> <cipher_algo> <cipher_key> <auth_algo> <auth_key>
     <mode> <src_ip> <dst_ip> <action_type> <port_id> <fallback>
+    <flow-direction> <port_id> <queue_id>

 where each options means:
@@ -698,6 +699,18 @@ where each options means:

    * *fallback lookaside-none*

+``<flow-direction>``
+
+ * Action type is for redirecting the specific inbound ipsec-flow to
+   a specified queue.
Flow direction is not an action type. You can re-phrase it as
Option for redirecting a specific inbound ipsec flow of a port to a specific queue of that port. 
quoted hunk
+
+ * Optional: Yes.
+
+ * Available options:
+
+   * *port_id*: Port ID of the NIC for which the SA is configured.
+   * *queue_id*: Queue ID to which traffic should be redirected.
+
 Example SA rules:

 .. code-block:: console
@@ -727,6 +740,9 @@ Example SA rules:
     mode ipv4-tunnel src 172.16.2.5 dst 172.16.1.5 \
     type inline-crypto-offload port_id 0

+    sa in 117 cipher_algo null auth_algo null mode ipv4-tunnel src 172.16.2.7 \
+    dst 172.16.1.7 flow-direction 0 2
+
 Routing rule syntax
 ^^^^^^^^^^^^^^^^^^^
diff --git a/examples/ipsec-secgw/ep0.cfg b/examples/ipsec-secgw/ep0.cfg
index dfd4aca7d..6f8d5aa53 100644
--- a/examples/ipsec-secgw/ep0.cfg
+++ b/examples/ipsec-secgw/ep0.cfg
@@ -29,6 +29,7 @@ sp ipv4 in esp protect 111 pri 1 dst 192.168.186.0/24 sport
0:65535 dport 0:6553
 sp ipv4 in esp protect 115 pri 1 dst 192.168.210.0/24 sport 0:65535 dport
0:65535
 sp ipv4 in esp protect 116 pri 1 dst 192.168.211.0/24 sport 0:65535 dport
0:65535
 sp ipv4 in esp protect 115 pri 1 dst 192.168.210.0/24 sport 0:65535 dport
0:65535
+sp ipv4 in esp protect 117 pri 1 dst 192.168.212.0/24 sport 0:65535 dport
0:65535
 sp ipv4 in esp protect 125 pri 1 dst 192.168.65.0/24 sport 0:65535 dport 0:65535
 sp ipv4 in esp protect 125 pri 1 dst 192.168.65.0/24 sport 0:65535 dport 0:65535
 sp ipv4 in esp protect 126 pri 1 dst 192.168.66.0/24 sport 0:65535 dport 0:65535
@@ -61,6 +62,8 @@ sp ipv6 in esp protect 125 pri 1 dst
ffff:0000:0000:0000:aaaa:aaaa:0000:0000/96
 sport 0:65535 dport 0:65535
 sp ipv6 in esp protect 126 pri 1 dst
ffff:0000:0000:0000:bbbb:bbbb:0000:0000/96 \
 sport 0:65535 dport 0:65535
+sp ipv6 in esp protect 127 pri 1 dst
ffff:0000:0000:0000:cccc:dddd:0000:0000/96 \
+sport 0:65535 dport 0:65535

 #SA rules
 sa out 5 cipher_algo aes-128-cbc cipher_key 0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0 \
@@ -118,6 +121,9 @@ dst 172.16.1.5

 sa in 116 cipher_algo null auth_algo null mode ipv4-tunnel src 172.16.2.6 dst
172.16.1.6

+sa in 117 cipher_algo null auth_algo null mode ipv4-tunnel src 172.16.2.7 \
+dst 172.16.1.7 flow-direction 0 2
+
 sa in 125 cipher_algo aes-128-cbc cipher_key c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:\
 c3:c3:c3:c3:c3 auth_algo sha1-hmac auth_key
c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:\
 c3:c3:c3:c3:c3:c3:c3:c3:c3 mode ipv6-tunnel \
@@ -130,6 +136,11 @@ sa in 126 cipher_algo aes-128-cbc cipher_key
4d:4d:4d:4d:4d:4d:4d:4d:4d:4d:4d:\
 src 2222:2222:2222:2222:2222:2222:2222:6666 \
 dst 1111:1111:1111:1111:1111:1111:1111:6666

+sa in 127 cipher_algo null auth_algo null mode ipv6-tunnel \
+src 2222:2222:2222:2222:2222:2222:2222:7777 \
+dst 1111:1111:1111:1111:1111:1111:1111:7777 \
+flow-direction 0 3
+
 #Routing rules
 rt ipv4 dst 172.16.2.5/32 port 0
 rt ipv4 dst 172.16.2.6/32 port 1
diff --git a/examples/ipsec-secgw/ipsec-secgw.c b/examples/ipsec-
secgw/ipsec-secgw.c
index 5fde4f728..6d02341de 100644
--- a/examples/ipsec-secgw/ipsec-secgw.c
+++ b/examples/ipsec-secgw/ipsec-secgw.c
@@ -1183,6 +1183,28 @@ ipsec_poll_mode_worker(void)
 	}
 }

+int
+check_flow_params(uint16_t fdir_portid, uint8_t fdir_qid)
+{
+	uint16_t i;
+	uint16_t portid;
+	uint8_t queueid;
+
+	for (i = 0; i < nb_lcore_params; ++i) {
+		portid = lcore_params_array[i].port_id;
+		if (portid == fdir_portid) {
+			queueid = lcore_params_array[i].queue_id;
+			if (queueid == fdir_qid)
+				break;
+		}
+
+		if (i == nb_lcore_params - 1)
+			return -1;
+	}
+
+	return 1;
+}
+
 static int32_t
 check_poll_mode_params(struct eh_conf *eh_conf)
 {
diff --git a/examples/ipsec-secgw/ipsec.c b/examples/ipsec-secgw/ipsec.c
index d40657102..461fae461 100644
--- a/examples/ipsec-secgw/ipsec.c
+++ b/examples/ipsec-secgw/ipsec.c
@@ -418,6 +418,73 @@ create_inline_session(struct socket_ctx *skt_ctx,
struct ipsec_sa *sa,
 	return 0;
 }

+int
+create_ipsec_esp_flow(struct ipsec_sa *sa)
+{
+	int ret = 0;
+	struct rte_flow_error err;
+	if (sa->direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS) {
+		RTE_LOG(ERR, IPSEC,
+			"No Flow director rule for Egress traffic\n");
+		return -1;
+	}
+	if (sa->flags == TRANSPORT) {
+		RTE_LOG(ERR, IPSEC,
+			"No Flow director rule for transport mode\n");
+		return -1;
+	}
+	sa->action[0].type = RTE_FLOW_ACTION_TYPE_QUEUE;
+	sa->pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
+	sa->action[0].conf =
+			&(struct rte_flow_action_queue){
+				.index = sa->fdir_qid,
+	};
Unnecessary line break, spacing before '{'

quoted hunk
+	sa->attr.egress = 0;
+	sa->attr.ingress = 1;
+	if (IS_IP6(sa->flags)) {
+		sa->pattern[1].mask = &rte_flow_item_ipv6_mask;
+		sa->pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV6;
+		sa->pattern[1].spec = &sa->ipv6_spec;
+		memcpy(sa->ipv6_spec.hdr.dst_addr,
+			sa->dst.ip.ip6.ip6_b, sizeof(sa->dst.ip.ip6.ip6_b));
+		memcpy(sa->ipv6_spec.hdr.src_addr,
+			sa->src.ip.ip6.ip6_b, sizeof(sa->src.ip.ip6.ip6_b));
+		sa->pattern[2].type = RTE_FLOW_ITEM_TYPE_ESP;
+		sa->pattern[2].spec = &sa->esp_spec;
+		sa->pattern[2].mask = &rte_flow_item_esp_mask;
+		sa->esp_spec.hdr.spi = rte_cpu_to_be_32(sa->spi);
+		sa->pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
+	} else if (IS_IP4(sa->flags)) {
+		sa->pattern[1].mask = &rte_flow_item_ipv4_mask;
+		sa->pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV4;
+		sa->pattern[1].spec = &sa->ipv4_spec;
+		sa->ipv4_spec.hdr.dst_addr = sa->dst.ip.ip4;
+		sa->ipv4_spec.hdr.src_addr = sa->src.ip.ip4;
+		sa->pattern[2].type = RTE_FLOW_ITEM_TYPE_ESP;
+		sa->pattern[2].spec = &sa->esp_spec;
+		sa->pattern[2].mask = &rte_flow_item_esp_mask;
+		sa->esp_spec.hdr.spi = rte_cpu_to_be_32(sa->spi);
+		sa->pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
+	}
+	sa->action[1].type = RTE_FLOW_ACTION_TYPE_END;
+
+	ret = rte_flow_validate(sa->portid, &sa->attr, sa->pattern, sa->action,
+				&err);
+	if (ret < 0) {
+		RTE_LOG(ERR, IPSEC, "Flow validation failed %s\n",
err.message);
+		return ret;
+	}
+
+	sa->flow = rte_flow_create(sa->portid, &sa->attr, sa->pattern,
+					sa->action, &err);
+	if (!sa->flow) {
+		RTE_LOG(ERR, IPSEC, "Flow creation failed %s\n", err.message);
+		return -1;
+	}
+
+	return 0;
+}
+
 /*
  * queue crypto-ops into PMD queue.
  */
diff --git a/examples/ipsec-secgw/ipsec.h b/examples/ipsec-secgw/ipsec.h
index f8f29f9b1..1790a93ca 100644
--- a/examples/ipsec-secgw/ipsec.h
+++ b/examples/ipsec-secgw/ipsec.h
@@ -144,6 +144,8 @@ struct ipsec_sa {
 	};
 	enum rte_security_ipsec_sa_direction direction;
 	uint16_t portid;
+	uint8_t fdir_qid;
+	uint8_t fdir_flag;

 #define MAX_RTE_FLOW_PATTERN (4)
 #define MAX_RTE_FLOW_ACTIONS (3)
@@ -408,5 +410,10 @@ create_lookaside_session(struct ipsec_ctx *ipsec_ctx,
struct ipsec_sa *sa,
 int
 create_inline_session(struct socket_ctx *skt_ctx, struct ipsec_sa *sa,
 		struct rte_ipsec_session *ips);
+int
+check_flow_params(uint16_t fdir_portid, uint8_t fdir_qid);
+
+int
+create_ipsec_esp_flow(struct ipsec_sa *sa);

 #endif /* __IPSEC_H__ */
diff --git a/examples/ipsec-secgw/sa.c b/examples/ipsec-secgw/sa.c
index a6bf5e8b1..06bb25b3e 100644
--- a/examples/ipsec-secgw/sa.c
+++ b/examples/ipsec-secgw/sa.c
@@ -271,6 +271,7 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	uint32_t type_p = 0;
 	uint32_t portid_p = 0;
 	uint32_t fallback_p = 0;
+	int16_t status_p = 0;

 	if (strcmp(tokens[0], "in") == 0) {
 		ri = &nb_sa_in;
@@ -295,6 +296,7 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	if (atoi(tokens[1]) == INVALID_SPI)
 		return;
 	rule->spi = atoi(tokens[1]);
+	rule->portid = UINT16_MAX;
 	ips = ipsec_get_primary_session(rule);

 	for (ti = 2; ti < n_tokens; ti++) {
@@ -636,9 +638,14 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
 			if (status->status < 0)
 				return;
-			rule->portid = atoi(tokens[ti]);
-			if (status->status < 0)
+			if (rule->portid == UINT16_MAX)
+				rule->portid = atoi(tokens[ti]);
+			else if (rule->portid != atoi(tokens[ti])) {
+				APP_CHECK(0, status, "portid %s not matching
"
+					"with already assigned portid %u",
+					tokens[ti], rule->portid);
Please do not split strings which are printed as the output on console.
It will make it difficult to grep while debugging.
quoted hunk
 				return;
+			}
 			portid_p = 1;
 			continue;
 		}
@@ -683,6 +690,44 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 			fallback_p = 1;
 			continue;
 		}
+		if (strcmp(tokens[ti], "flow-direction") == 0) {
+			if (ips->type ==
+				RTE_SECURITY_ACTION_TYPE_NONE ||
+				ips->type ==
+				RTE_SECURITY_ACTION_TYPE_CPU_CRYPTO) {
The code is not readable here.
Either a switch case or a separate function if the indentation it going beyond.
+				rule->fdir_flag = 1;
+				INCREMENT_TOKEN_INDEX(ti, n_tokens,
status);
+				if (status->status < 0)
+					return;
+				if (rule->portid == UINT16_MAX)
+					rule->portid = atoi(tokens[ti]);
+				else if (rule->portid != atoi(tokens[ti])) {
+					APP_CHECK(0, status, "portid %s "
+						"not matching with already "
+						"assigned portid %u",
+						tokens[ti], rule->portid);
Same here, do not split strings which are printed.
You should have the complete string on a separate line. Checkpatch will not trouble for more than 80.
quoted hunk
+					return;
+				}
+				INCREMENT_TOKEN_INDEX(ti, n_tokens,
status);
+				if (status->status < 0)
+					return;
+				rule->fdir_qid = atoi(tokens[ti]);
+				/* validating portid and queueid */
+				status_p = check_flow_params(rule->portid,
+						rule->fdir_qid);
+				if (status_p < 0) {
+					printf("port id %u / queue id %u is "
+						"not valid\n", rule->portid,
+						 rule->fdir_qid);
+				}
+			} else {
+				APP_CHECK(0, status, "flow director not "
+					"supported for security session "
+					"type:%d", ips->type);
+				return;
+			}
+			continue;
+		}

 		/* unrecognizeable input */
 		APP_CHECK(0, status, "unrecognized input \"%s\"",
@@ -721,7 +766,6 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	if (!type_p || (!portid_p && ips->type !=
 			RTE_SECURITY_ACTION_TYPE_CPU_CRYPTO)) {
 		ips->type = RTE_SECURITY_ACTION_TYPE_NONE;
-		rule->portid = -1;
 	}

 	*ri = *ri + 1;
@@ -806,7 +850,7 @@ print_one_sa_rule(const struct ipsec_sa *sa, int inbound)
 		printf("lookaside-protocol-offload ");
 		break;
 	case RTE_SECURITY_ACTION_TYPE_CPU_CRYPTO:
-		printf("cpu-crypto-accelerated");
+		printf("cpu-crypto-accelerated ");
 		break;
 	}
@@ -825,6 +869,10 @@ print_one_sa_rule(const struct ipsec_sa *sa, int
inbound)
 			break;
 		}
 	}
+	if (sa->fdir_flag == 1)
+		printf("flow-direction port %d queue %d", sa->portid,
+				sa->fdir_qid);
+
 	printf("\n");
 }
@@ -1143,6 +1191,13 @@ sa_add_rules(struct sa_ctx *sa_ctx, const struct
ipsec_sa entries[],
 			}
 		}

+		if (sa->fdir_flag && inbound) {
+			rc = create_ipsec_esp_flow(sa);
+			if (rc != 0)
+				RTE_LOG(ERR, IPSEC_ESP,
+					"create_ipsec_esp_flow() failed %s\n",
+					strerror(rc));
+		}
 		print_one_sa_rule(sa, inbound);
 	}

--
2.17.1

Re: [dpdk-dev] [PATCH v5] examples/ipsec-secgw: support flow director feature

From: Shetty, Praveen <hidden>
Date: 2020-04-16 11:49:30

Hi Akhil,

Thank you.

Please see my response inline.


-----Original Message-----
From: Akhil Goyal <redacted> 
Sent: Thursday, April 16, 2020 12:30 AM
To: Shetty, Praveen <redacted>; dev@dpdk.org; Doherty, Declan <redacted>; anoobj@marvell.com
Cc: Iremonger, Bernard <redacted>; Ananyev, Konstantin <redacted>
Subject: RE: [PATCH v5] examples/ipsec-secgw: support flow director feature

Hi Praveen,
Support load distribution in security gateway application using NIC 
load distribution feature(Flow Director).
Flow Director is used to redirect the specified inbound ipsec flow to 
a specified queue.This is achieved by extending the SA rule syntax to 
support specification by adding new action_type of <flow-direction> to 
a specified <port_id> <queue_id>.

Signed-off-by: Praveen Shetty <redacted>
Please fix a few minor comments below.

Apart from that,
Acked-by: Akhil Goyal <redacted>
quoted hunk
---
v5 changes:
Small change in condtional handling in sa.c file.

v4 changes:
1. Removed flow director configuration changes as they are not
   required anymore.
2. Addressed all the review comments from Akhil and Anoob.
3. Included update to the ipsec-secgw user guide and update to release notes.

 doc/guides/rel_notes/release_20_05.rst   |  4 ++
 doc/guides/sample_app_ug/ipsec_secgw.rst | 16 ++++++
 examples/ipsec-secgw/ep0.cfg             | 11 ++++
 examples/ipsec-secgw/ipsec-secgw.c       | 22 ++++++++
 examples/ipsec-secgw/ipsec.c             | 67 ++++++++++++++++++++++++
 examples/ipsec-secgw/ipsec.h             |  7 +++
 examples/ipsec-secgw/sa.c                | 63 ++++++++++++++++++++--
 7 files changed, 186 insertions(+), 4 deletions(-)
diff --git a/doc/guides/rel_notes/release_20_05.rst
b/doc/guides/rel_notes/release_20_05.rst
index 6b1a7c58c..a9ec163cf 100644
--- a/doc/guides/rel_notes/release_20_05.rst
+++ b/doc/guides/rel_notes/release_20_05.rst
@@ -81,6 +81,10 @@ New Features
   by making use of the event device capabilities. The event mode 
currently supports
   only inline IPsec protocol offload.

+* **Updated ipsec-secgw application.**
+
+  Added IPsec inbound load-distribution support for ipsec-secgw 
+ application
using NIC
+  load distribution feature(Flow Director).
There is one more item in release notes for ipsec-secgw for event mode.
You should add a bullet in that for this feature.

[Praveen] okay. Will do it in v6.
quoted hunk
 Removed Items
 -------------
diff --git a/doc/guides/sample_app_ug/ipsec_secgw.rst
b/doc/guides/sample_app_ug/ipsec_secgw.rst
index 038f593f4..12f921d76 100644
--- a/doc/guides/sample_app_ug/ipsec_secgw.rst
+++ b/doc/guides/sample_app_ug/ipsec_secgw.rst
@@ -506,6 +506,7 @@ The SA rule syntax is shown as follows:

     sa <dir> <spi> <cipher_algo> <cipher_key> <auth_algo> <auth_key>
     <mode> <src_ip> <dst_ip> <action_type> <port_id> <fallback>
+    <flow-direction> <port_id> <queue_id>

 where each options means:
@@ -698,6 +699,18 @@ where each options means:

    * *fallback lookaside-none*

+``<flow-direction>``
+
+ * Action type is for redirecting the specific inbound ipsec-flow to
+   a specified queue.
Flow direction is not an action type. You can re-phrase it as Option for redirecting a specific inbound ipsec flow of a port to a specific queue of that port. 

[Praveen] okay. Will update this in v6.
quoted hunk
+
+ * Optional: Yes.
+
+ * Available options:
+
+   * *port_id*: Port ID of the NIC for which the SA is configured.
+   * *queue_id*: Queue ID to which traffic should be redirected.
+
 Example SA rules:

 .. code-block:: console
@@ -727,6 +740,9 @@ Example SA rules:
     mode ipv4-tunnel src 172.16.2.5 dst 172.16.1.5 \
     type inline-crypto-offload port_id 0

+    sa in 117 cipher_algo null auth_algo null mode ipv4-tunnel src 172.16.2.7 \
+    dst 172.16.1.7 flow-direction 0 2
+
 Routing rule syntax
 ^^^^^^^^^^^^^^^^^^^
diff --git a/examples/ipsec-secgw/ep0.cfg 
b/examples/ipsec-secgw/ep0.cfg index dfd4aca7d..6f8d5aa53 100644
--- a/examples/ipsec-secgw/ep0.cfg
+++ b/examples/ipsec-secgw/ep0.cfg
@@ -29,6 +29,7 @@ sp ipv4 in esp protect 111 pri 1 dst 
192.168.186.0/24 sport
0:65535 dport 0:6553
 sp ipv4 in esp protect 115 pri 1 dst 192.168.210.0/24 sport 0:65535 
dport
0:65535
 sp ipv4 in esp protect 116 pri 1 dst 192.168.211.0/24 sport 0:65535 
dport
0:65535
 sp ipv4 in esp protect 115 pri 1 dst 192.168.210.0/24 sport 0:65535 
dport
0:65535
+sp ipv4 in esp protect 117 pri 1 dst 192.168.212.0/24 sport 0:65535 
+dport
0:65535
 sp ipv4 in esp protect 125 pri 1 dst 192.168.65.0/24 sport 0:65535 
dport 0:65535  sp ipv4 in esp protect 125 pri 1 dst 192.168.65.0/24 
sport 0:65535 dport 0:65535  sp ipv4 in esp protect 126 pri 1 dst 
192.168.66.0/24 sport 0:65535 dport 0:65535 @@ -61,6 +62,8 @@ sp ipv6 
in esp protect 125 pri 1 dst
ffff:0000:0000:0000:aaaa:aaaa:0000:0000/96
 sport 0:65535 dport 0:65535
 sp ipv6 in esp protect 126 pri 1 dst
ffff:0000:0000:0000:bbbb:bbbb:0000:0000/96 \  sport 0:65535 dport 
0:65535
+sp ipv6 in esp protect 127 pri 1 dst
ffff:0000:0000:0000:cccc:dddd:0000:0000/96 \
+sport 0:65535 dport 0:65535

 #SA rules
 sa out 5 cipher_algo aes-128-cbc cipher_key 
0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0 \ @@ -118,6 +121,9 @@ dst 172.16.1.5

 sa in 116 cipher_algo null auth_algo null mode ipv4-tunnel src 
172.16.2.6 dst
172.16.1.6

+sa in 117 cipher_algo null auth_algo null mode ipv4-tunnel src 
+172.16.2.7 \ dst 172.16.1.7 flow-direction 0 2
+
 sa in 125 cipher_algo aes-128-cbc cipher_key 
c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:\
 c3:c3:c3:c3:c3 auth_algo sha1-hmac auth_key 
c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:\
 c3:c3:c3:c3:c3:c3:c3:c3:c3 mode ipv6-tunnel \ @@ -130,6 +136,11 @@ sa 
in 126 cipher_algo aes-128-cbc cipher_key 
4d:4d:4d:4d:4d:4d:4d:4d:4d:4d:4d:\
 src 2222:2222:2222:2222:2222:2222:2222:6666 \  dst 
1111:1111:1111:1111:1111:1111:1111:6666

+sa in 127 cipher_algo null auth_algo null mode ipv6-tunnel \ src 
+2222:2222:2222:2222:2222:2222:2222:7777 \ dst 
+1111:1111:1111:1111:1111:1111:1111:7777 \ flow-direction 0 3
+
 #Routing rules
 rt ipv4 dst 172.16.2.5/32 port 0
 rt ipv4 dst 172.16.2.6/32 port 1
diff --git a/examples/ipsec-secgw/ipsec-secgw.c b/examples/ipsec- 
secgw/ipsec-secgw.c index 5fde4f728..6d02341de 100644
--- a/examples/ipsec-secgw/ipsec-secgw.c
+++ b/examples/ipsec-secgw/ipsec-secgw.c
@@ -1183,6 +1183,28 @@ ipsec_poll_mode_worker(void)
 	}
 }

+int
+check_flow_params(uint16_t fdir_portid, uint8_t fdir_qid) {
+	uint16_t i;
+	uint16_t portid;
+	uint8_t queueid;
+
+	for (i = 0; i < nb_lcore_params; ++i) {
+		portid = lcore_params_array[i].port_id;
+		if (portid == fdir_portid) {
+			queueid = lcore_params_array[i].queue_id;
+			if (queueid == fdir_qid)
+				break;
+		}
+
+		if (i == nb_lcore_params - 1)
+			return -1;
+	}
+
+	return 1;
+}
+
 static int32_t
 check_poll_mode_params(struct eh_conf *eh_conf)  { diff --git 
a/examples/ipsec-secgw/ipsec.c b/examples/ipsec-secgw/ipsec.c index 
d40657102..461fae461 100644
--- a/examples/ipsec-secgw/ipsec.c
+++ b/examples/ipsec-secgw/ipsec.c
@@ -418,6 +418,73 @@ create_inline_session(struct socket_ctx *skt_ctx, 
struct ipsec_sa *sa,
 	return 0;
 }

+int
+create_ipsec_esp_flow(struct ipsec_sa *sa) {
+	int ret = 0;
+	struct rte_flow_error err;
+	if (sa->direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS) {
+		RTE_LOG(ERR, IPSEC,
+			"No Flow director rule for Egress traffic\n");
+		return -1;
+	}
+	if (sa->flags == TRANSPORT) {
+		RTE_LOG(ERR, IPSEC,
+			"No Flow director rule for transport mode\n");
+		return -1;
+	}
+	sa->action[0].type = RTE_FLOW_ACTION_TYPE_QUEUE;
+	sa->pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
+	sa->action[0].conf =
+			&(struct rte_flow_action_queue){
+				.index = sa->fdir_qid,
+	};
Unnecessary line break, spacing before '{'

[Praveen] will fix this in v6.

quoted hunk
+	sa->attr.egress = 0;
+	sa->attr.ingress = 1;
+	if (IS_IP6(sa->flags)) {
+		sa->pattern[1].mask = &rte_flow_item_ipv6_mask;
+		sa->pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV6;
+		sa->pattern[1].spec = &sa->ipv6_spec;
+		memcpy(sa->ipv6_spec.hdr.dst_addr,
+			sa->dst.ip.ip6.ip6_b, sizeof(sa->dst.ip.ip6.ip6_b));
+		memcpy(sa->ipv6_spec.hdr.src_addr,
+			sa->src.ip.ip6.ip6_b, sizeof(sa->src.ip.ip6.ip6_b));
+		sa->pattern[2].type = RTE_FLOW_ITEM_TYPE_ESP;
+		sa->pattern[2].spec = &sa->esp_spec;
+		sa->pattern[2].mask = &rte_flow_item_esp_mask;
+		sa->esp_spec.hdr.spi = rte_cpu_to_be_32(sa->spi);
+		sa->pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
+	} else if (IS_IP4(sa->flags)) {
+		sa->pattern[1].mask = &rte_flow_item_ipv4_mask;
+		sa->pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV4;
+		sa->pattern[1].spec = &sa->ipv4_spec;
+		sa->ipv4_spec.hdr.dst_addr = sa->dst.ip.ip4;
+		sa->ipv4_spec.hdr.src_addr = sa->src.ip.ip4;
+		sa->pattern[2].type = RTE_FLOW_ITEM_TYPE_ESP;
+		sa->pattern[2].spec = &sa->esp_spec;
+		sa->pattern[2].mask = &rte_flow_item_esp_mask;
+		sa->esp_spec.hdr.spi = rte_cpu_to_be_32(sa->spi);
+		sa->pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
+	}
+	sa->action[1].type = RTE_FLOW_ACTION_TYPE_END;
+
+	ret = rte_flow_validate(sa->portid, &sa->attr, sa->pattern, sa->action,
+				&err);
+	if (ret < 0) {
+		RTE_LOG(ERR, IPSEC, "Flow validation failed %s\n",
err.message);
+		return ret;
+	}
+
+	sa->flow = rte_flow_create(sa->portid, &sa->attr, sa->pattern,
+					sa->action, &err);
+	if (!sa->flow) {
+		RTE_LOG(ERR, IPSEC, "Flow creation failed %s\n", err.message);
+		return -1;
+	}
+
+	return 0;
+}
+
 /*
  * queue crypto-ops into PMD queue.
  */
diff --git a/examples/ipsec-secgw/ipsec.h 
b/examples/ipsec-secgw/ipsec.h index f8f29f9b1..1790a93ca 100644
--- a/examples/ipsec-secgw/ipsec.h
+++ b/examples/ipsec-secgw/ipsec.h
@@ -144,6 +144,8 @@ struct ipsec_sa {
 	};
 	enum rte_security_ipsec_sa_direction direction;
 	uint16_t portid;
+	uint8_t fdir_qid;
+	uint8_t fdir_flag;

 #define MAX_RTE_FLOW_PATTERN (4)
 #define MAX_RTE_FLOW_ACTIONS (3)
@@ -408,5 +410,10 @@ create_lookaside_session(struct ipsec_ctx 
*ipsec_ctx, struct ipsec_sa *sa,  int  create_inline_session(struct 
socket_ctx *skt_ctx, struct ipsec_sa *sa,
 		struct rte_ipsec_session *ips);
+int
+check_flow_params(uint16_t fdir_portid, uint8_t fdir_qid);
+
+int
+create_ipsec_esp_flow(struct ipsec_sa *sa);

 #endif /* __IPSEC_H__ */
diff --git a/examples/ipsec-secgw/sa.c b/examples/ipsec-secgw/sa.c 
index a6bf5e8b1..06bb25b3e 100644
--- a/examples/ipsec-secgw/sa.c
+++ b/examples/ipsec-secgw/sa.c
@@ -271,6 +271,7 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	uint32_t type_p = 0;
 	uint32_t portid_p = 0;
 	uint32_t fallback_p = 0;
+	int16_t status_p = 0;

 	if (strcmp(tokens[0], "in") == 0) {
 		ri = &nb_sa_in;
@@ -295,6 +296,7 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	if (atoi(tokens[1]) == INVALID_SPI)
 		return;
 	rule->spi = atoi(tokens[1]);
+	rule->portid = UINT16_MAX;
 	ips = ipsec_get_primary_session(rule);

 	for (ti = 2; ti < n_tokens; ti++) {
@@ -636,9 +638,14 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
 			if (status->status < 0)
 				return;
-			rule->portid = atoi(tokens[ti]);
-			if (status->status < 0)
+			if (rule->portid == UINT16_MAX)
+				rule->portid = atoi(tokens[ti]);
+			else if (rule->portid != atoi(tokens[ti])) {
+				APP_CHECK(0, status, "portid %s not matching
"
+					"with already assigned portid %u",
+					tokens[ti], rule->portid);
Please do not split strings which are printed as the output on console.
It will make it difficult to grep while debugging.

[Praveen] okay. Will fix this in v6.
quoted hunk
 				return;
+			}
 			portid_p = 1;
 			continue;
 		}
@@ -683,6 +690,44 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 			fallback_p = 1;
 			continue;
 		}
+		if (strcmp(tokens[ti], "flow-direction") == 0) {
+			if (ips->type ==
+				RTE_SECURITY_ACTION_TYPE_NONE ||
+				ips->type ==
+				RTE_SECURITY_ACTION_TYPE_CPU_CRYPTO) {
The code is not readable here.
Either a switch case or a separate function if the indentation it going beyond.

[Praveen] okay. Will do this in v6.
+				rule->fdir_flag = 1;
+				INCREMENT_TOKEN_INDEX(ti, n_tokens,
status);
+				if (status->status < 0)
+					return;
+				if (rule->portid == UINT16_MAX)
+					rule->portid = atoi(tokens[ti]);
+				else if (rule->portid != atoi(tokens[ti])) {
+					APP_CHECK(0, status, "portid %s "
+						"not matching with already "
+						"assigned portid %u",
+						tokens[ti], rule->portid);
Same here, do not split strings which are printed.
You should have the complete string on a separate line. Checkpatch will not trouble for more than 80.

[Praveen] Okay. Will do this in v6.
quoted hunk
+					return;
+				}
+				INCREMENT_TOKEN_INDEX(ti, n_tokens,
status);
+				if (status->status < 0)
+					return;
+				rule->fdir_qid = atoi(tokens[ti]);
+				/* validating portid and queueid */
+				status_p = check_flow_params(rule->portid,
+						rule->fdir_qid);
+				if (status_p < 0) {
+					printf("port id %u / queue id %u is "
+						"not valid\n", rule->portid,
+						 rule->fdir_qid);
+				}
+			} else {
+				APP_CHECK(0, status, "flow director not "
+					"supported for security session "
+					"type:%d", ips->type);
+				return;
+			}
+			continue;
+		}

 		/* unrecognizeable input */
 		APP_CHECK(0, status, "unrecognized input \"%s\"", @@ -721,7 +766,6 
@@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	if (!type_p || (!portid_p && ips->type !=
 			RTE_SECURITY_ACTION_TYPE_CPU_CRYPTO)) {
 		ips->type = RTE_SECURITY_ACTION_TYPE_NONE;
-		rule->portid = -1;
 	}

 	*ri = *ri + 1;
@@ -806,7 +850,7 @@ print_one_sa_rule(const struct ipsec_sa *sa, int inbound)
 		printf("lookaside-protocol-offload ");
 		break;
 	case RTE_SECURITY_ACTION_TYPE_CPU_CRYPTO:
-		printf("cpu-crypto-accelerated");
+		printf("cpu-crypto-accelerated ");
 		break;
 	}
@@ -825,6 +869,10 @@ print_one_sa_rule(const struct ipsec_sa *sa, int
inbound)
 			break;
 		}
 	}
+	if (sa->fdir_flag == 1)
+		printf("flow-direction port %d queue %d", sa->portid,
+				sa->fdir_qid);
+
 	printf("\n");
 }
@@ -1143,6 +1191,13 @@ sa_add_rules(struct sa_ctx *sa_ctx, const 
struct ipsec_sa entries[],
 			}
 		}

+		if (sa->fdir_flag && inbound) {
+			rc = create_ipsec_esp_flow(sa);
+			if (rc != 0)
+				RTE_LOG(ERR, IPSEC_ESP,
+					"create_ipsec_esp_flow() failed %s\n",
+					strerror(rc));
+		}
 		print_one_sa_rule(sa, inbound);
 	}

--
2.17.1
Regards,
Praveen

[dpdk-dev] [PATCH v6] examples/ipsec-secgw: support flow director feature

From: Praveen Shetty <hidden>
Date: 2020-04-16 16:47:37

Support load distribution in security gateway application using
NIC load distribution feature(Flow Director).
Flow Director is used to redirect the specified inbound ipsec flow
to a specified queue.This is achieved by extending the SA rule syntax
to support specification by adding new action_type of <flow-direction>
to a specified <port_id> <queue_id>.

Signed-off-by: Praveen Shetty <redacted>
Acked-by: Akhil Goyal <redacted>
---
v6 changes:
Incorporated all the review comments from Akhil on v5.

 doc/guides/rel_notes/release_20_05.rst   |  4 +-
 doc/guides/sample_app_ug/ipsec_secgw.rst | 16 ++++++
 examples/ipsec-secgw/ep0.cfg             | 11 ++++
 examples/ipsec-secgw/ipsec-secgw.c       | 22 ++++++++
 examples/ipsec-secgw/ipsec.c             | 66 ++++++++++++++++++++++++
 examples/ipsec-secgw/ipsec.h             |  7 +++
 examples/ipsec-secgw/sa.c                | 65 +++++++++++++++++++++--
 7 files changed, 186 insertions(+), 5 deletions(-)
diff --git a/doc/guides/rel_notes/release_20_05.rst b/doc/guides/rel_notes/release_20_05.rst
index 184967844..bcb11a45b 100644
--- a/doc/guides/rel_notes/release_20_05.rst
+++ b/doc/guides/rel_notes/release_20_05.rst
@@ -73,7 +73,7 @@ New Features
 
   Supported large size code blocks which does not fit in one mbuf segment.
 
-* **Added event mode to ipsec-secgw application.**
+* **Updated ipsec-secgw application.**
 
   Updated ipsec-secgw application to add event based packet processing. The worker
   thread(s) would receive events and submit them back to the event device after
@@ -81,6 +81,8 @@ New Features
   by making use of the event device capabilities. The event mode currently supports
   only inline IPsec protocol offload.
 
+  Added IPsec inbound load-distribution support for ipsec-secgw application using NIC
+  load distribution feature(Flow Director).
 
 Removed Items
 -------------
diff --git a/doc/guides/sample_app_ug/ipsec_secgw.rst b/doc/guides/sample_app_ug/ipsec_secgw.rst
index 038f593f4..5cc29c414 100644
--- a/doc/guides/sample_app_ug/ipsec_secgw.rst
+++ b/doc/guides/sample_app_ug/ipsec_secgw.rst
@@ -506,6 +506,7 @@ The SA rule syntax is shown as follows:
 
     sa <dir> <spi> <cipher_algo> <cipher_key> <auth_algo> <auth_key>
     <mode> <src_ip> <dst_ip> <action_type> <port_id> <fallback>
+    <flow-direction> <port_id> <queue_id>
 
 where each options means:
 
@@ -698,6 +699,18 @@ where each options means:
 
    * *fallback lookaside-none*
 
+``<flow-direction>``
+
+ * Option for redirecting a specific inbound ipsec flow of a port to a specific
+   queue of that port.
+
+ * Optional: Yes.
+
+ * Available options:
+
+   * *port_id*: Port ID of the NIC for which the SA is configured.
+   * *queue_id*: Queue ID to which traffic should be redirected.
+
 Example SA rules:
 
 .. code-block:: console
@@ -727,6 +740,9 @@ Example SA rules:
     mode ipv4-tunnel src 172.16.2.5 dst 172.16.1.5 \
     type inline-crypto-offload port_id 0
 
+    sa in 117 cipher_algo null auth_algo null mode ipv4-tunnel src 172.16.2.7 \
+    dst 172.16.1.7 flow-direction 0 2
+
 Routing rule syntax
 ^^^^^^^^^^^^^^^^^^^
 
diff --git a/examples/ipsec-secgw/ep0.cfg b/examples/ipsec-secgw/ep0.cfg
index dfd4aca7d..6f8d5aa53 100644
--- a/examples/ipsec-secgw/ep0.cfg
+++ b/examples/ipsec-secgw/ep0.cfg
@@ -29,6 +29,7 @@ sp ipv4 in esp protect 111 pri 1 dst 192.168.186.0/24 sport 0:65535 dport 0:6553
 sp ipv4 in esp protect 115 pri 1 dst 192.168.210.0/24 sport 0:65535 dport 0:65535
 sp ipv4 in esp protect 116 pri 1 dst 192.168.211.0/24 sport 0:65535 dport 0:65535
 sp ipv4 in esp protect 115 pri 1 dst 192.168.210.0/24 sport 0:65535 dport 0:65535
+sp ipv4 in esp protect 117 pri 1 dst 192.168.212.0/24 sport 0:65535 dport 0:65535
 sp ipv4 in esp protect 125 pri 1 dst 192.168.65.0/24 sport 0:65535 dport 0:65535
 sp ipv4 in esp protect 125 pri 1 dst 192.168.65.0/24 sport 0:65535 dport 0:65535
 sp ipv4 in esp protect 126 pri 1 dst 192.168.66.0/24 sport 0:65535 dport 0:65535
@@ -61,6 +62,8 @@ sp ipv6 in esp protect 125 pri 1 dst ffff:0000:0000:0000:aaaa:aaaa:0000:0000/96
 sport 0:65535 dport 0:65535
 sp ipv6 in esp protect 126 pri 1 dst ffff:0000:0000:0000:bbbb:bbbb:0000:0000/96 \
 sport 0:65535 dport 0:65535
+sp ipv6 in esp protect 127 pri 1 dst ffff:0000:0000:0000:cccc:dddd:0000:0000/96 \
+sport 0:65535 dport 0:65535
 
 #SA rules
 sa out 5 cipher_algo aes-128-cbc cipher_key 0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0 \
@@ -118,6 +121,9 @@ dst 172.16.1.5
 
 sa in 116 cipher_algo null auth_algo null mode ipv4-tunnel src 172.16.2.6 dst 172.16.1.6
 
+sa in 117 cipher_algo null auth_algo null mode ipv4-tunnel src 172.16.2.7 \
+dst 172.16.1.7 flow-direction 0 2
+
 sa in 125 cipher_algo aes-128-cbc cipher_key c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:\
 c3:c3:c3:c3:c3 auth_algo sha1-hmac auth_key c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:\
 c3:c3:c3:c3:c3:c3:c3:c3:c3 mode ipv6-tunnel \
@@ -130,6 +136,11 @@ sa in 126 cipher_algo aes-128-cbc cipher_key 4d:4d:4d:4d:4d:4d:4d:4d:4d:4d:4d:\
 src 2222:2222:2222:2222:2222:2222:2222:6666 \
 dst 1111:1111:1111:1111:1111:1111:1111:6666
 
+sa in 127 cipher_algo null auth_algo null mode ipv6-tunnel \
+src 2222:2222:2222:2222:2222:2222:2222:7777 \
+dst 1111:1111:1111:1111:1111:1111:1111:7777 \
+flow-direction 0 3
+
 #Routing rules
 rt ipv4 dst 172.16.2.5/32 port 0
 rt ipv4 dst 172.16.2.6/32 port 1
diff --git a/examples/ipsec-secgw/ipsec-secgw.c b/examples/ipsec-secgw/ipsec-secgw.c
index 5fde4f728..6d02341de 100644
--- a/examples/ipsec-secgw/ipsec-secgw.c
+++ b/examples/ipsec-secgw/ipsec-secgw.c
@@ -1183,6 +1183,28 @@ ipsec_poll_mode_worker(void)
 	}
 }
 
+int
+check_flow_params(uint16_t fdir_portid, uint8_t fdir_qid)
+{
+	uint16_t i;
+	uint16_t portid;
+	uint8_t queueid;
+
+	for (i = 0; i < nb_lcore_params; ++i) {
+		portid = lcore_params_array[i].port_id;
+		if (portid == fdir_portid) {
+			queueid = lcore_params_array[i].queue_id;
+			if (queueid == fdir_qid)
+				break;
+		}
+
+		if (i == nb_lcore_params - 1)
+			return -1;
+	}
+
+	return 1;
+}
+
 static int32_t
 check_poll_mode_params(struct eh_conf *eh_conf)
 {
diff --git a/examples/ipsec-secgw/ipsec.c b/examples/ipsec-secgw/ipsec.c
index d40657102..bf88d80d6 100644
--- a/examples/ipsec-secgw/ipsec.c
+++ b/examples/ipsec-secgw/ipsec.c
@@ -418,6 +418,72 @@ create_inline_session(struct socket_ctx *skt_ctx, struct ipsec_sa *sa,
 	return 0;
 }
 
+int
+create_ipsec_esp_flow(struct ipsec_sa *sa)
+{
+	int ret = 0;
+	struct rte_flow_error err;
+	if (sa->direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS) {
+		RTE_LOG(ERR, IPSEC,
+			"No Flow director rule for Egress traffic\n");
+		return -1;
+	}
+	if (sa->flags == TRANSPORT) {
+		RTE_LOG(ERR, IPSEC,
+			"No Flow director rule for transport mode\n");
+		return -1;
+	}
+	sa->action[0].type = RTE_FLOW_ACTION_TYPE_QUEUE;
+	sa->pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
+	sa->action[0].conf = &(struct rte_flow_action_queue) {
+				.index = sa->fdir_qid,
+	};
+	sa->attr.egress = 0;
+	sa->attr.ingress = 1;
+	if (IS_IP6(sa->flags)) {
+		sa->pattern[1].mask = &rte_flow_item_ipv6_mask;
+		sa->pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV6;
+		sa->pattern[1].spec = &sa->ipv6_spec;
+		memcpy(sa->ipv6_spec.hdr.dst_addr,
+			sa->dst.ip.ip6.ip6_b, sizeof(sa->dst.ip.ip6.ip6_b));
+		memcpy(sa->ipv6_spec.hdr.src_addr,
+			sa->src.ip.ip6.ip6_b, sizeof(sa->src.ip.ip6.ip6_b));
+		sa->pattern[2].type = RTE_FLOW_ITEM_TYPE_ESP;
+		sa->pattern[2].spec = &sa->esp_spec;
+		sa->pattern[2].mask = &rte_flow_item_esp_mask;
+		sa->esp_spec.hdr.spi = rte_cpu_to_be_32(sa->spi);
+		sa->pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
+	} else if (IS_IP4(sa->flags)) {
+		sa->pattern[1].mask = &rte_flow_item_ipv4_mask;
+		sa->pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV4;
+		sa->pattern[1].spec = &sa->ipv4_spec;
+		sa->ipv4_spec.hdr.dst_addr = sa->dst.ip.ip4;
+		sa->ipv4_spec.hdr.src_addr = sa->src.ip.ip4;
+		sa->pattern[2].type = RTE_FLOW_ITEM_TYPE_ESP;
+		sa->pattern[2].spec = &sa->esp_spec;
+		sa->pattern[2].mask = &rte_flow_item_esp_mask;
+		sa->esp_spec.hdr.spi = rte_cpu_to_be_32(sa->spi);
+		sa->pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
+	}
+	sa->action[1].type = RTE_FLOW_ACTION_TYPE_END;
+
+	ret = rte_flow_validate(sa->portid, &sa->attr, sa->pattern, sa->action,
+				&err);
+	if (ret < 0) {
+		RTE_LOG(ERR, IPSEC, "Flow validation failed %s\n", err.message);
+		return ret;
+	}
+
+	sa->flow = rte_flow_create(sa->portid, &sa->attr, sa->pattern,
+					sa->action, &err);
+	if (!sa->flow) {
+		RTE_LOG(ERR, IPSEC, "Flow creation failed %s\n", err.message);
+		return -1;
+	}
+
+	return 0;
+}
+
 /*
  * queue crypto-ops into PMD queue.
  */
diff --git a/examples/ipsec-secgw/ipsec.h b/examples/ipsec-secgw/ipsec.h
index f8f29f9b1..1790a93ca 100644
--- a/examples/ipsec-secgw/ipsec.h
+++ b/examples/ipsec-secgw/ipsec.h
@@ -144,6 +144,8 @@ struct ipsec_sa {
 	};
 	enum rte_security_ipsec_sa_direction direction;
 	uint16_t portid;
+	uint8_t fdir_qid;
+	uint8_t fdir_flag;
 
 #define MAX_RTE_FLOW_PATTERN (4)
 #define MAX_RTE_FLOW_ACTIONS (3)
@@ -408,5 +410,10 @@ create_lookaside_session(struct ipsec_ctx *ipsec_ctx, struct ipsec_sa *sa,
 int
 create_inline_session(struct socket_ctx *skt_ctx, struct ipsec_sa *sa,
 		struct rte_ipsec_session *ips);
+int
+check_flow_params(uint16_t fdir_portid, uint8_t fdir_qid);
+
+int
+create_ipsec_esp_flow(struct ipsec_sa *sa);
 
 #endif /* __IPSEC_H__ */
diff --git a/examples/ipsec-secgw/sa.c b/examples/ipsec-secgw/sa.c
index a6bf5e8b1..4783bdccd 100644
--- a/examples/ipsec-secgw/sa.c
+++ b/examples/ipsec-secgw/sa.c
@@ -271,6 +271,7 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	uint32_t type_p = 0;
 	uint32_t portid_p = 0;
 	uint32_t fallback_p = 0;
+	int16_t status_p = 0;
 
 	if (strcmp(tokens[0], "in") == 0) {
 		ri = &nb_sa_in;
@@ -295,6 +296,7 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	if (atoi(tokens[1]) == INVALID_SPI)
 		return;
 	rule->spi = atoi(tokens[1]);
+	rule->portid = UINT16_MAX;
 	ips = ipsec_get_primary_session(rule);
 
 	for (ti = 2; ti < n_tokens; ti++) {
@@ -636,9 +638,14 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
 			if (status->status < 0)
 				return;
-			rule->portid = atoi(tokens[ti]);
-			if (status->status < 0)
+			if (rule->portid == UINT16_MAX)
+				rule->portid = atoi(tokens[ti]);
+			else if (rule->portid != atoi(tokens[ti])) {
+				APP_CHECK(0, status,
+					"portid %s not matching with already assigned portid %u",
+					tokens[ti], rule->portid);
 				return;
+			}
 			portid_p = 1;
 			continue;
 		}
@@ -683,6 +690,46 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 			fallback_p = 1;
 			continue;
 		}
+		if (strcmp(tokens[ti], "flow-direction") == 0) {
+			switch (ips->type) {
+			case RTE_SECURITY_ACTION_TYPE_NONE:
+			case RTE_SECURITY_ACTION_TYPE_CPU_CRYPTO:
+				rule->fdir_flag = 1;
+				INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
+				if (status->status < 0)
+					return;
+				if (rule->portid == UINT16_MAX)
+					rule->portid = atoi(tokens[ti]);
+				else if (rule->portid != atoi(tokens[ti])) {
+					APP_CHECK(0, status,
+						"portid %s not matching with already assigned portid %u",
+						tokens[ti], rule->portid);
+					return;
+				}
+				INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
+				if (status->status < 0)
+					return;
+				rule->fdir_qid = atoi(tokens[ti]);
+				/* validating portid and queueid */
+				status_p = check_flow_params(rule->portid,
+						rule->fdir_qid);
+				if (status_p < 0) {
+					printf("port id %u / queue id %u is "
+						"not valid\n", rule->portid,
+						 rule->fdir_qid);
+				}
+				break;
+			case RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO:
+			case RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL:
+			case RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL:
+			default:
+				APP_CHECK(0, status,
+					"flow director not supported for security session type %d",
+					ips->type);
+				return;
+			}
+			continue;
+		}
 
 		/* unrecognizeable input */
 		APP_CHECK(0, status, "unrecognized input \"%s\"",
@@ -721,7 +768,6 @@ parse_sa_tokens(char **tokens, uint32_t n_tokens,
 	if (!type_p || (!portid_p && ips->type !=
 			RTE_SECURITY_ACTION_TYPE_CPU_CRYPTO)) {
 		ips->type = RTE_SECURITY_ACTION_TYPE_NONE;
-		rule->portid = -1;
 	}
 
 	*ri = *ri + 1;
@@ -806,7 +852,7 @@ print_one_sa_rule(const struct ipsec_sa *sa, int inbound)
 		printf("lookaside-protocol-offload ");
 		break;
 	case RTE_SECURITY_ACTION_TYPE_CPU_CRYPTO:
-		printf("cpu-crypto-accelerated");
+		printf("cpu-crypto-accelerated ");
 		break;
 	}
 
@@ -825,6 +871,10 @@ print_one_sa_rule(const struct ipsec_sa *sa, int inbound)
 			break;
 		}
 	}
+	if (sa->fdir_flag == 1)
+		printf("flow-direction port %d queue %d", sa->portid,
+				sa->fdir_qid);
+
 	printf("\n");
 }
 
@@ -1143,6 +1193,13 @@ sa_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
 			}
 		}
 
+		if (sa->fdir_flag && inbound) {
+			rc = create_ipsec_esp_flow(sa);
+			if (rc != 0)
+				RTE_LOG(ERR, IPSEC_ESP,
+					"create_ipsec_esp_flow() failed %s\n",
+					strerror(rc));
+		}
 		print_one_sa_rule(sa, inbound);
 	}
 
-- 
2.17.1

Re: [dpdk-dev] [PATCH v6] examples/ipsec-secgw: support flow director feature

From: Akhil Goyal <hidden>
Date: 2020-04-17 20:58:08

Support load distribution in security gateway application using
NIC load distribution feature(Flow Director).
Flow Director is used to redirect the specified inbound ipsec flow
to a specified queue.This is achieved by extending the SA rule syntax
to support specification by adding new action_type of <flow-direction>
to a specified <port_id> <queue_id>.

Signed-off-by: Praveen Shetty <redacted>
Acked-by: Akhil Goyal <redacted>
---
v6 changes:
Incorporated all the review comments from Akhil on v5.

 doc/guides/rel_notes/release_20_05.rst   |  4 +-
 doc/guides/sample_app_ug/ipsec_secgw.rst | 16 ++++++
 examples/ipsec-secgw/ep0.cfg             | 11 ++++
 examples/ipsec-secgw/ipsec-secgw.c       | 22 ++++++++
 examples/ipsec-secgw/ipsec.c             | 66 ++++++++++++++++++++++++
 examples/ipsec-secgw/ipsec.h             |  7 +++
 examples/ipsec-secgw/sa.c                | 65 +++++++++++++++++++++--
 7 files changed, 186 insertions(+), 5 deletions(-)
Applied to dpdk-next-crypto

Thanks.
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help